Link with C++ linker
[oweals/cde.git] / cde / programs / ttsnoop / DtTt.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 //%%  (c) Copyright 1993, 1994 Hewlett-Packard Company
24 //%%  (c) Copyright 1993, 1994 International Business Machines Corp.
25 //%%  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
26 //%%  (c) Copyright 1993, 1994 Novell, Inc.
27 //%%  $XConsortium: DtTt.C /main/4 1996/03/19 10:47:59 barstow $
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <sys/wait.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <strstream.h>
37 #include <Xm/TextF.h>
38 #include <Dt/SpinBox.h>
39 #include <Dt/HelpDialog.h>
40 #include "tt_c++.h"
41 #include "DtTt.h"
42 #include "messageProps_ui.h"
43 #include "patternProps_ui.h"
44
45 static const char **    dtTtProcids             = 0;
46 static const void **    dtTtProcidClientDatums  = 0;
47 static unsigned int     dtTtProcidsCount        = 0;
48 static Tt_pattern *     dtTtPatterns            = 0;
49 static unsigned int     dtTtPatternsCount       = 0;
50 static Tt_message *     dtTtMessages            = 0;
51 static unsigned int     dtTtMessagesCount       = 0;
52 static Tt_pattern **    dtTtDtSessions          = 0;
53 static unsigned int     dtTtDtSessionsCount     = 0;
54 static Tt_pattern **    dtTtDtFiles             = 0;
55 static unsigned int     dtTtDtFilesCount        = 0;
56
57 int             _DtTtPatsNameKey        = (int)DtTtNth;
58 extern Tt_pattern       snoopPat;
59
60 int
61 listGrow(
62         void **         pList,
63         unsigned int &  listCount,
64         size_t          elemSize
65 )
66 {
67         void *newList;
68         newList = realloc( *pList, (1 + listCount) * elemSize );
69         if (newList == 0) {
70                 return 0;
71         }
72         *pList = newList;
73         listCount++;
74         return 1;
75 }
76
77 XmString
78 DtTtStatusString(
79         Tt_status       status
80 )
81 {
82         char *s = tt_status_string( status );
83         XmString s2 = XmStringCreateLocalized( s );
84         tt_free( s );
85         return s2;
86 }
87
88 Tt_status
89 DtTtCreated(
90         DtTtType        type,
91         const void *    entity,
92         const void *    clientData
93 )
94 {
95         Tt_status status = tt_ptr_error( entity );
96         if ((tt_is_err( status )) || (entity == 0)) {
97                 return TT_OK;
98         }
99         switch (type) {
100                 char *proc;
101             case DTTT_PROCID:
102                 proc = strdup( (const char *)entity );
103                 if (proc == 0) {
104                         return TT_ERR_NOMEM;
105                 }
106                 if (! listAppend( dtTtProcids, dtTtProcidsCount, const char *,
107                                   proc ))
108                 {
109                         return TT_ERR_NOMEM;
110                 }
111                 dtTtProcidsCount--; // shared by both lists
112                 if (! listAppend( dtTtProcidClientDatums, dtTtProcidsCount,
113                                   const void *, clientData ))
114                 {
115                         return TT_ERR_NOMEM;
116                 }
117                 break;
118             case DTTT_MESSAGE:
119                 if (DtTtIndex( type, entity ) >= 0) {
120                         return TT_OK;
121                 }
122                 if (! listAppend( dtTtMessages, dtTtMessagesCount, Tt_message,
123                                   (const Tt_message)entity ))
124                 {
125                         return TT_ERR_NOMEM;
126                 }
127                 break;
128             case DTTT_PATTERN:
129                 if (DtTtIndex( type, entity ) >= 0) {
130                         return TT_OK;
131                 }
132                 if (! listAppend( dtTtPatterns, dtTtPatternsCount, Tt_pattern,
133                                   (const Tt_pattern)entity ))
134                 {
135                         return TT_ERR_NOMEM;
136                 }
137                 break;
138             case DTTT_PTYPE:
139             case DTTT_OTYPE:
140             case DTTT_OBJECT:
141             case DTTT_SESSION:
142             case DTTT_DTSESSION:
143             case DTTT_DTFILE:
144             case DTTT_OP:
145                 abort();
146                 break;
147         }
148         return TT_OK;
149 }
150
151 Tt_status
152 DtTtCreated(
153         DtTtType        type,
154         Tt_pattern *    entity,
155         const char *    name
156 )
157 {
158         if ((tt_is_err( tt_ptr_error( entity ) )) || (entity == 0)) {
159                 return TT_OK;
160         }
161         if ((tt_is_err( tt_ptr_error( name ) )) || (name == 0)) {
162                 return TT_OK;
163         }
164         switch (type) {
165             case DTTT_PROCID:
166             case DTTT_MESSAGE:
167             case DTTT_PATTERN:
168             case DTTT_PTYPE:
169             case DTTT_OTYPE:
170             case DTTT_OBJECT:
171             case DTTT_SESSION:
172             case DTTT_OP:
173                 abort();
174                 break;
175             case DTTT_DTSESSION:
176                 tt_pattern_user_set( *entity, _DtTtPatsNameKey,
177                                      strdup( name ));
178                 if (DtTtIndex( type, entity ) >= 0) {
179                         return TT_OK;
180                 }
181                 if (! listAppend( dtTtDtSessions, dtTtDtSessionsCount,
182                                   Tt_pattern *, (Tt_pattern *)entity ))
183                 {
184                         return TT_ERR_NOMEM;
185                 }
186                 break;
187             case DTTT_DTFILE:
188                 tt_pattern_user_set( *entity, _DtTtPatsNameKey,
189                                      strdup( name ));
190                 if (DtTtIndex( type, entity ) >= 0) {
191                         return TT_OK;
192                 }
193                 if (! listAppend( dtTtDtFiles, dtTtDtFilesCount,
194                                   Tt_pattern *, (Tt_pattern *)entity ))
195                 {
196                         return TT_ERR_NOMEM;
197                 }
198                 break;
199         }
200         while (*entity != 0) {
201                 DtTtCreated( DTTT_PATTERN, *entity );
202                 entity++;
203         }
204         return TT_OK;
205 }
206
207 void *
208 DtTtNth(
209         DtTtType        type,
210         int             n
211 )
212 {
213         switch (type) {
214             case DTTT_PROCID:
215                 if ((n < 0) || (n >= dtTtProcidsCount)) {
216                         return 0;
217                 }
218                 return (void *)dtTtProcids[ n ];
219             case DTTT_MESSAGE:
220                 if ((n < 0) || (n >= dtTtMessagesCount)) {
221                         return 0;
222                 }
223                 return dtTtMessages[ n ];
224             case DTTT_PATTERN:
225                 if ((n < 0) || (n >= dtTtPatternsCount)) {
226                         return 0;
227                 }
228                 return dtTtPatterns[ n ];
229             case DTTT_DTSESSION:
230                 if ((n < 0) || (n >= dtTtDtSessionsCount)) {
231                         return 0;
232                 }
233                 return dtTtDtSessions[ n ];
234             case DTTT_DTFILE:
235                 if ((n < 0) || (n >= dtTtDtFilesCount)) {
236                         return 0;
237                 }
238                 return dtTtDtFiles[ n ];
239             case DTTT_OP:
240                 return tttk_op_string( (Tttk_op)(n+1) );
241         }
242 }
243
244 void *
245 DtTtNthClientDatum(
246         DtTtType        type,
247         int             n
248 )
249 {
250         switch (type) {
251             case DTTT_PROCID:
252                 if ((n < 0) || (n >= dtTtProcidsCount)) {
253                         return 0;
254                 }
255                 return (void *)dtTtProcidClientDatums[ n ];
256             default:
257                 abort();
258                 return 0;
259         }
260 }
261
262 void
263 DtTtNthClientDatumSet(
264         DtTtType        type,
265         int             n,
266         const void *    clientData
267 )
268 {
269         switch (type) {
270             case DTTT_PROCID:
271                 if ((n < 0) || (n >= dtTtProcidsCount)) {
272                         return;
273                 }
274                 dtTtProcidClientDatums[ n ] = clientData;
275                 return;
276             default:
277                 abort();
278         }
279 }
280
281 int
282 DtTtIndex(
283         DtTtType        type,
284         const void *    entity
285 )
286 {
287         Tt_status status = tt_ptr_error( entity );
288         if ((tt_is_err( status )) || (entity == 0)) {
289                 return -1;
290         }
291         switch (type) {
292                 int i;
293             case DTTT_PROCID:
294                 for (i = dtTtProcidsCount - 1; i >= 0; i--) {
295                         if (strcmp( dtTtProcids[i], (char *)entity) == 0) {
296                                 return i;
297                         }
298                 }
299                 return -1;
300             case DTTT_MESSAGE:
301                 for (i = dtTtMessagesCount - 1; i >= 0; i--) {
302                         if (dtTtMessages[i] == entity) {
303                                 return i;
304                         }
305                 }
306                 return -1;
307             case DTTT_PATTERN:
308                 for (i = dtTtPatternsCount - 1; i >= 0; i--) {
309                         if (dtTtPatterns[i] == entity) {
310                                 return i;
311                         }
312                 }
313                 return -1;
314             case DTTT_DTSESSION:
315                 for (i = dtTtDtSessionsCount - 1; i >= 0; i--) {
316                         if (dtTtDtSessions[i] == entity) {
317                                 return i;
318                         }
319                 }
320                 return -1;
321             case DTTT_DTFILE:
322                 for (i = dtTtDtFilesCount - 1; i >= 0; i--) {
323                         if (dtTtDtFiles[i] == entity) {
324                                 return i;
325                         }
326                 }
327                 return -1;
328             case DTTT_OP:
329                 for (i = 1; i < TTDT_OP_LAST; i++) {
330                         if (0 == strcmp( tttk_op_string( (Tttk_op)i ),
331                                          (char *)entity ))
332                         {
333                                 return i;
334                         }
335                 }
336                 return -1;
337         }
338 }
339
340 Tt_status
341 DtTtDestroyed(
342         DtTtType        type,
343         const void *    entity
344 )
345 {
346         Tt_status status = tt_ptr_error( entity );
347         if ((tt_is_err( status )) || (entity == 0)) {
348                 return TT_OK;
349         }
350         switch (type) {
351                 int i, j;
352                 Tt_pattern *pats;
353             case DTTT_PROCID:
354                 for (i = dtTtProcidsCount - 1; i >= 0; i--) {
355                         if (strcmp( dtTtProcids[i], (char *)entity) == 0) {
356                                 break;
357                         }
358                 }
359                 if (i < 0) {
360                         return TT_WRN_NOTFOUND;
361                 }
362                 for (j = i; j < dtTtProcidsCount - 1; j++) {
363                         dtTtProcids[j] = dtTtProcids[j+1];
364                 }
365                 for (j = i; j < dtTtProcidsCount - 1; j++) {
366                         dtTtProcidClientDatums[j] =
367                                 dtTtProcidClientDatums[j+1];
368                 }
369                 dtTtProcidsCount--;
370                 break;
371             case DTTT_MESSAGE:
372                 for (i = dtTtMessagesCount - 1; i >= 0; i--) {
373                         if (dtTtMessages[i] == entity) {
374                                 break;
375                         }
376                 }
377                 if (i < 0) {
378                         return TT_WRN_NOTFOUND;
379                 }
380                 for (j = i; j < dtTtMessagesCount - 1; j++) {
381                         dtTtMessages[j] = dtTtMessages[j+1];
382                 }
383                 dtTtMessagesCount--;
384                 break;
385             case DTTT_PATTERN:
386                 if (snoopPat == entity) snoopPat = 0;
387                 for (i = dtTtPatternsCount - 1; i >= 0; i--) {
388                         if (dtTtPatterns[i] == entity) {
389                                 break;
390                         }
391                 }
392                 if (i < 0) {
393                         return TT_WRN_NOTFOUND;
394                 }
395                 for (j = i; j < dtTtPatternsCount - 1; j++) {
396                         dtTtPatterns[j] = dtTtPatterns[j+1];
397                 }
398                 dtTtPatternsCount--;
399                 break;
400             case DTTT_DTSESSION:
401                 for (i = dtTtDtSessionsCount - 1; i >= 0; i--) {
402                         if (dtTtDtSessions[i] == entity) {
403                                 break;
404                         }
405                 }
406                 if (i < 0) {
407                         return TT_WRN_NOTFOUND;
408                 }
409                 pats = (Tt_pattern *)entity;
410                 while (*pats != 0) {
411                         DtTtDestroyed( DTTT_PATTERN, *pats );
412                         pats++;
413                 }
414                 for (j = i; j < dtTtDtSessionsCount - 1; j++) {
415                         dtTtDtSessions[j] = dtTtDtSessions[j+1];
416                 }
417                 dtTtDtSessionsCount--;
418                 break;
419             case DTTT_DTFILE:
420                 for (i = dtTtDtFilesCount - 1; i >= 0; i--) {
421                         if (dtTtDtFiles[i] == entity) {
422                                 break;
423                         }
424                 }
425                 if (i < 0) {
426                         return TT_WRN_NOTFOUND;
427                 }
428                 pats = (Tt_pattern *)entity;
429                 while (*pats != 0) {
430                         DtTtDestroyed( DTTT_PATTERN, *pats );
431                         pats++;
432                 }
433                 for (j = i; j < dtTtDtFilesCount - 1; j++) {
434                         dtTtDtFiles[j] = dtTtDtFiles[j+1];
435                 }
436                 dtTtDtFilesCount--;
437                 break;
438         }
439         return TT_OK;
440 }
441
442 Tt_status
443 DtTtSetLabel(
444         Widget labelWidget,
445         const char *string
446 )
447 {
448     if (labelWidget == 0) {
449             return TT_OK;
450     }
451     XmString labelXmString = XmStringCreateLocalized( (String)string );
452     XtVaSetValues( labelWidget, XmNlabelString, labelXmString, 0 );
453     XmStringFree( labelXmString );
454     return TT_OK;
455 }
456
457 Tt_status
458 DtTtSetLabel(
459         Widget labelWidget,
460         const char *func,
461         void *val
462 )
463 {
464     Tt_status status = tt_ptr_error( val );
465     ostrstream errStream;
466     errStream << func << " = " << val << " (" << status << ")" << ends;
467     char *label = errStream.str();
468     DtTtSetLabel( labelWidget, label );
469     delete label;
470     return status;
471 }
472
473 Tt_status
474 DtTtSetLabel(
475         Widget labelWidget,
476         const char *func,
477         Tt_status status
478 )
479 {
480     ostrstream errStream;
481     errStream << func << " = " << status << ends;
482     char *label = errStream.str();
483     DtTtSetLabel( labelWidget, label );
484     delete label;
485     return status;
486 }
487
488 int
489 DtTtSetLabel(
490         Widget labelWidget,
491         const char *func,
492         int returnVal
493 )
494 {
495     ostrstream errStream;
496     errStream << func << " = " << returnVal << ends;
497     char *label = errStream.str();
498     DtTtSetLabel( labelWidget, label );
499     delete label;
500     return returnVal;
501 }
502
503
504 static XmString *
505 _DtTtChoices(
506         Tt_pattern **   pPats,
507         int             count
508 )
509 {
510         // XXX when to free?
511         XmString *items = (XmString *)XtMalloc( count * sizeof( XmString ));
512         if (items == 0) {
513                 return 0;
514         }
515         for (int i = 0; i < count; i++) {
516                 ostrstream itemStream;
517                 itemStream << (void *)pPats[ i ];
518                 char *name = (char *)
519                         tt_pattern_user( *pPats[ i ], _DtTtPatsNameKey );
520                 if (! tt_is_err( tt_ptr_error( name ))) {
521                         itemStream << " " << name;
522                         tt_free( name );
523                 }
524                 itemStream << ends;
525                 char *string = itemStream.str();
526                 items[ i ] = XmStringCreateLocalized( string );
527                 delete string;
528         }
529         return items;
530 }
531
532 XmString *
533 _DtTtChoices(
534         DtTtType type,
535         int *    itemCount
536 )
537 {
538         *itemCount = 0;
539         switch (type) {
540                 XmString *items;
541                 int i;
542                 int opCount;
543             case DTTT_PROCID:
544                 items = (XmString *)
545                         XtMalloc( dtTtProcidsCount * sizeof( XmString ));
546                 if (items == 0) {
547                         return 0;
548                 }
549                 *itemCount = dtTtProcidsCount;
550                 for (i = 0; i < dtTtProcidsCount; i++) {
551                         items[ i ] = XmStringCreateLocalized(
552                                         (String)dtTtProcids[ i ] );
553                 }
554                 return items;
555             case DTTT_MESSAGE:
556                 items = (XmString *)
557                         XtMalloc( dtTtMessagesCount * sizeof( XmString ));
558                 if (items == 0) {
559                         return 0;
560                 }
561                 *itemCount = dtTtMessagesCount;
562                 for (i = 0; i < dtTtMessagesCount; i++) {
563                         ostrstream itemStream;
564                         itemStream << (void *)dtTtMessages[ i ];
565                         char *op = tt_message_op( dtTtMessages[ i ] );
566                         if (! tt_is_err( tt_ptr_error( op ))) {
567                                 itemStream << " " << op;
568                                 tt_free( op );
569                         }
570                         char *id = tt_message_id( dtTtMessages[ i ] );
571                         if (! tt_is_err( tt_ptr_error( id ))) {
572                                 itemStream << " " << id;
573                                 tt_free( id );
574                         }
575                         itemStream << ends;
576                         char *string = itemStream.str();
577                         items[ i ] = XmStringCreateLocalized( string );
578                         delete string;
579                 }
580                 return items;
581             case DTTT_PATTERN:
582                 items = (XmString *)
583                         XtMalloc( dtTtPatternsCount * sizeof( XmString ));
584                 if (items == 0) {
585                         return 0;
586                 }
587                 *itemCount = dtTtPatternsCount;
588                 for (i = 0; i < dtTtPatternsCount; i++) {
589                         ostrstream itemStream;
590                         itemStream << (void *)dtTtPatterns[ i ] << ends;
591                         items[ i ] = XmStringCreateLocalized(
592                                         itemStream.str() );
593                         delete itemStream.str();
594                 }
595                 return items;
596             case DTTT_DTSESSION:
597                 *itemCount = dtTtDtSessionsCount;
598                 return _DtTtChoices( dtTtDtSessions, dtTtDtSessionsCount );
599             case DTTT_DTFILE:
600                 *itemCount = dtTtDtFilesCount;
601                 return _DtTtChoices( dtTtDtFiles, dtTtDtFilesCount );
602             case DTTT_OP:
603                 // XXX when to free? ditto for each case
604                 opCount = ((int)TTDT_OP_LAST) - 1;
605                 items = (XmString *)
606                         XtMalloc( opCount * sizeof( XmString ));
607                 if (items == 0) {
608                         return 0;
609                 }
610                 *itemCount = opCount;
611                 for (i = 1; i <= opCount; i++) {
612                         items[ i-1 ] = XmStringCreateLocalized(
613                                         (String)tttk_op_string( (Tttk_op)i ));
614                 }
615                 return items;
616         }
617 }
618
619 #if defined(aix)
620 #define AIX_CONST_STRING        (char *)
621 #else
622 #define AIX_CONST_STRING
623 #endif
624
625 void
626 _DtOpen(
627         Widget          label,
628         const char *    cmd,
629         const char *    tempnamTemplate
630 )
631 {
632     char *file = tempnam( 0, AIX_CONST_STRING tempnamTemplate );
633     ostrstream cmdStream;
634     cmdStream << cmd << " > " << file << ends;
635     int sysStat = system( cmdStream.str() );
636     if (! WIFEXITED( sysStat )) {
637             ostrstream func;
638             func << "system( \"" << cmdStream.str() << "\" )" << ends;
639             DtTtSetLabel( label, func.str(), sysStat );
640             delete cmdStream.str();
641             delete func.str();
642             return;
643     }
644     if (WEXITSTATUS( sysStat ) != 0) {
645             DtTtSetLabel( label, cmdStream.str(), WEXITSTATUS( sysStat ));
646             delete cmdStream.str();
647             return;
648     }
649     delete cmdStream.str();
650     _DtOpen( label, file );
651 }
652
653 void
654 _DtOpen(
655         Widget          label,
656         const char *    file
657 )
658 {
659     ostrstream labelStream;
660     labelStream << "dtaction Open " << file << ends;
661     DtTtSetLabel( label, labelStream.str() );
662     delete labelStream.str();
663
664     ostrstream cmd;
665     cmd << "( unset TT_TRACE_SCRIPT; if dtaction Open " << file
666         << "; then :; else textedit " << file << "; fi; sleep 600; rm -f "
667         << file << " ) &" << ends;
668     system( cmd.str() );
669     delete cmd.str();
670 }
671
672 void
673 _DtOpen(
674         Widget          label,
675         void *          buf,
676         size_t          len,
677         const char *    tempnamTemplate
678 )
679 {
680     char *file = tempnam( 0, AIX_CONST_STRING tempnamTemplate );
681     int fd = open( file, O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR );
682     if (write( fd, buf, len ) < 0) {
683             DtTtSetLabel( label, file, errno );
684             return;
685     }
686     close( fd );
687     _DtOpen( label, file );
688 }
689
690 void
691 _DtMan(
692         Widget          label,
693         const char *    topic
694 )
695 {
696     ostrstream labelStream;
697     labelStream << "dtaction Dtmanpageview " << topic << ends;
698     DtTtSetLabel( label, labelStream.str() );
699     delete labelStream.str();
700
701     ostrstream cmd;
702     cmd << "unset TT_TRACE_SCRIPT; if dtaction Dtmanpageview " << topic
703         << "; then :; else cmdtool -c man " << topic << "; fi &" << ends;
704     system( cmd.str() );
705     delete cmd.str();
706 }
707
708 Boolean
709 _DtCanHelp(
710         const char *topics
711 )
712 {
713         if (topics == 0) return False;
714         if (strchr( topics, ' ' ) != 0) {
715                 // Must not be a list of man pages
716                 return False;
717         }
718         return True;
719 }
720
721 Boolean
722 _DtHelped(
723         Widget helpDialog
724 )
725 {
726         char *topics;
727         XtVaGetValues( helpDialog, DtNstringData, &topics, 0 );
728         if (! _DtCanHelp( topics )) {
729                 return False;
730         }
731         char *newTopics = strdup( topics );
732         const char *whiteSpace = "(12345689) \t:-,.*\n";
733         const char *topic = strtok( newTopics, whiteSpace );
734         while (topic != 0) {
735                 _DtMan( 0, topic );
736                 topic = strtok( 0, whiteSpace );
737         }
738         free( newTopics );
739         return True;
740 }