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