remove ultrix support
[oweals/cde.git] / cde / lib / tt / bin / tt_type_comp / mp_type_comp.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 //%%  $TOG: mp_type_comp.C /main/4 1999/10/14 18:37:58 mgreess $                                                        
28 /*
29  *
30  * mp_type_comp.cc
31  *
32  * Copyright (c) 1990 by Sun Microsystems, Inc.
33  *
34  * ToolTalk type compiler. Performs syntax and semantics checks on
35  * type input file and then writes out the type table in xdr format
36  * or in Classing Engine format.
37  */
38
39 #include <locale.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #if defined(__linux__)
43 #include <unistd.h>
44 #endif
45 #if defined(sgi) || defined(CSRG_BASED)
46 #include <getopt.h>
47 #endif
48 #include "mp/mp_global.h"
49 #include "mp/mp_mp.h"
50 #include "mp_otype.h"
51 #include "mp_ptype.h"
52 #include "mp_types_table.h"
53 #include "mp_typedb.h"
54 #include "util/copyright.h"
55 #include "util/tt_global_env.h"
56 #include "util/tt_xdr_version.h"
57 #include "util/tt_port.h"
58 #include "util/tt_gettext.h"
59
60 #define _TT_DBCLIENT_SIDE
61 #include "db/db_server.h"
62
63 typedef void (*cmd_fn)();
64
65 TT_INSERT_COPYRIGHT
66
67 #ifdef OPT_PATCH
68 static char PatchID[] = "Patch Id: 100626_03.";
69 static int Patch_ID100626_03;
70 #endif
71
72 _Tt_string              ifile;
73 _Tt_typedbLevel         cedb = TypedbNone;
74 _Tt_string              ofile;
75 _Tt_string_list_ptr     cargs;
76 int                     option_xdr = 1;
77 int                     option_remap_ptypes = 1;
78 _Tt_string              cpp_options("");
79
80 void
81 print_usage_and_exit()
82 {
83         _tt_syslog(stderr, LOG_ERR, "%s",
84                    catgets(_ttcatd, 4, 2,
85 "Usage:\n"
86 "tt_type_comp [-s] [-d db] [-mM] source_file\n"
87 "tt_type_comp [-s] [-d db] -r type ...\n"
88 "-M     merge source types into specified database, not updating existing types\n"
89 "-m     merge, but update existing types.  Default.\n"
90 "-r     remove source types from the specified database\n"
91 "-d db  database to operate on. One of: user, system, or network. Default: user\n"
92 "-G     perform garbage collection on the ToolTalk database server.\n"
93 "\n"
94 "tt_type_comp [-sE] -p|O|P [-d db]\n"
95 "tt_type_comp [-s]  -p|O|P compiled_file\n"
96 "-O     enumerate on stdout the names of all otypes read\n"
97 "-P     enumerate on stdout the names of all ptypes read\n"
98 "-p     pretty-print on stdout all the ToolTalk types read\n"
99 "-E     use the Classing Engine database(s) instead of the XDR database(s)\n"
100 "-d db  database to read from. One of: user, system, or network. Default: all\n"
101 "\n"
102 "tt_type_comp [-s] -x [-o compiled_file] source_file\n"
103 "-x     compile types from source_file (or stdin, if file is \"-\")\n"
104 "-o     write compiled types to compiled_file (or stdout, if file is \"-\")\n"
105 "       Default: source_file.xdr, or \"types.xdr\" if source is stdin\n"
106 "\n"
107 "tt_type_comp [-hv]\n"
108 "-v     print out version number\n"
109 "-h     print out this message\n"
110 "-s     do not print out any status messages.\n"
111 "\n"
112 "These cpp options will be passed through:\n"
113 "        -undef -Dname -Idirectory -Uname -Ydirectory"));
114         exit(1);
115 }
116
117
118 void
119 read_types(_Tt_string file, _Tt_typedb_ptr &db)
120 {
121         _Tt_parse_status result;
122         _Tt_types_table *table;
123         if (file == "-") {
124                 table = new _Tt_types_table(stdin, result);
125         } else {
126                 table = new _Tt_types_table(file, result);
127         }
128
129         if (result == _TT_PARSE_OK) {
130                 db = new _Tt_typedb();
131
132                 if (table->check_semantics() != _TT_PARSE_OK) {
133                         _tt_syslog(stderr, LOG_ERR,
134                                    catgets(_ttcatd, 4, 3,
135                                            "Semantic error in types file"));
136                         exit(2);
137                 }
138                 db->ptable = table->ptypes();
139                 db->otable = table->otypes();
140         } else {
141                 _Tt_string msg =  catgets(_ttcatd, 4, 4,
142                                           "Not a valid ToolTalk types file" );
143                 if (file.len() > 0) {
144                         msg = msg.cat( ": " ).cat( file );
145                 }
146                 _tt_syslog(stderr, LOG_ERR, msg);
147                 exit(2);
148         }
149 }
150
151
152 void
153 f_ce_print()
154 {
155         _Tt_typedb_ptr  db;
156
157         db = new _Tt_typedb();
158         if (db->init_ce(cedb) != TT_OK) {
159                 _tt_syslog(stderr, LOG_ERR,
160                            catgets(_ttcatd, 4, 5,
161                                    "Cannot read any ToolTalk types "
162                                    "from Classing Engine database"));
163                 exit(3);
164         }
165         db->pretty_print(stdout);
166 }
167
168 void
169 merge(int overwrite)
170 {
171
172         int                             status_ok = 1;
173         int                             exists;
174         _Tt_typedb_ptr                  db;
175         _Tt_ptype_table_cursor          db_ptypes;
176         _Tt_otype_table_cursor          db_otypes;
177         _Tt_typedb_ptr                  xdb;
178         _Tt_ptype_ptr                   pt;
179         _Tt_otype_ptr                   ot;
180         Tt_status                       st = TT_OK;
181
182         if (cedb == TypedbNone) {
183                 cedb = TypedbUser;
184         }
185
186         if (! option_xdr) {
187                 _tt_syslog(stderr, LOG_ERR,
188                            catgets(_ttcatd, 4, 6,
189                                    "Merging Classing Engine tables is no "
190                                    "longer supported"));
191                 exit(1);
192         }
193
194         xdb = new _Tt_typedb();
195         read_types(ifile, db);
196
197         if ((st=xdb->init_xdr(cedb)) != TT_OK) {
198                 // if TT_ERR_DBEXIST is returned from init_ce
199                 // we continue with the merge. It just means
200                 // we're starting up in an environment where
201                 // no tooltalk namespaces exist in any of the
202                 // Classing Engine databases.
203                 if (st != TT_ERR_DBEXIST) {
204                         if (st == TT_ERR_NO_MATCH) {
205                                 _tt_syslog(stderr, LOG_ERR,
206                                            catgets(_ttcatd, 4, 7,
207                                                    "Cannot read types in %s data"
208                                                    "base - version mismatch"),
209                                            _Tt_typedb::level_name(cedb));
210                         } else {
211                                 _tt_syslog(stderr, LOG_ERR,
212                                            catgets(_ttcatd, 4, 8,
213                                                    "Cannot read types in %s data"
214                                                    "base"),
215                                            _Tt_typedb::level_name(cedb));
216                         }
217                         /*
218                          * The most common way for this to fail seems to be
219                          * to not have OPENWINHOME set. Suggest this
220                          * to the user.
221                          */
222                         if (0==getenv("OPENWINHOME")) {
223                                 _tt_syslog(stderr, LOG_ERR,
224                                            catgets(_ttcatd, 4, 9,
225                                                    "$OPENWINHOME not set"));
226                         }
227                         exit(3);
228                 }
229         }
230
231         if (! xdb->begin_write(cedb)) {
232                 _tt_syslog(stderr, LOG_ERR,
233                            catgets(_ttcatd, 4, 10,
234                                    "Cannot initialize %s database for writing"),
235                            _Tt_typedb::level_name(cedb));
236                 exit(3);
237         }
238
239         db_otypes.reset(db->otable);
240         while (db_otypes.next()) {
241                 ot = xdb->otable->lookup(db_otypes->otid());
242                 exists = (! ot.is_null());
243                 if (exists) {
244                         if (! overwrite) {
245                                 continue;
246                         }
247                         if (! xdb->remove_otype(db_otypes->otid())) {
248                                 _tt_syslog(stderr, LOG_ERR,
249                                            catgets(_ttcatd, 4, 11,
250                                                    "Could not remove old "
251                                                    "definition for %s"),
252                                            (char *)db_otypes->otid());
253                                 xdb->abort_write();
254                                 exit(3);
255                         }
256                 }
257                 if (! _tt_global->silent) {
258                         printf( "%s %s...\n",
259                                 (exists)
260                                       ? catgets(_ttcatd, 4, 12, "Overwriting")
261                                       : catgets(_ttcatd, 4, 13, "Writing"),
262                                 (char *)db_otypes->otid());
263                 }
264                 if (! xdb->insert(*db_otypes)) {
265                         _tt_syslog(stderr, LOG_ERR,
266                                    catgets(_ttcatd, 4, 14, "Could not add "
267                                            "new definition for %s"),
268                                    (char *)db_otypes->otid());
269                         xdb->abort_write();
270                         exit(3);
271                 }
272         }
273
274         db_ptypes.reset(db->ptable);
275         while (db_ptypes.next()) {
276                 pt = xdb->ptable->lookup(db_ptypes->ptid());
277                 exists = (! pt.is_null());
278                 if (exists) {
279                         if (! overwrite) {
280                                 continue;
281                         }
282                         if (! xdb->remove_ptype(db_ptypes->ptid())) {
283                                 _tt_syslog(stderr, LOG_ERR,
284                                            catgets(_ttcatd, 4, 15,
285                                                    "Could not remove old "
286                                                    "definition for %s"),
287                                            (char *)db_ptypes->ptid());
288                                 xdb->abort_write();
289                         }
290                 }
291                 if (! _tt_global->silent) {
292                         printf("%s %s...\n",
293                                (exists)
294                                       ? catgets(_ttcatd, 4, 16, "Overwriting")
295                                       : catgets(_ttcatd, 4, 17, "Writing"),
296                                (char *)db_ptypes->ptid());
297                 }
298                 if (! xdb->insert(*db_ptypes)) {
299                         _tt_syslog(stderr, LOG_ERR,
300                                    catgets(_ttcatd, 4, 18, "Could not add "
301                                            "new definition for %s"),
302                                    (char *)db_ptypes->ptid());
303                         xdb->abort_write();
304                 }
305         }
306
307         if (! xdb->end_write()) {
308                 // diagnostic emitted by ::end_write()
309                 exit(3);
310         }
311 }
312
313 void
314 f_merge_overwrite()
315 {
316         merge(1);
317 }
318
319
320 void
321 f_merge_no_overwrite()
322 {
323         merge(0);
324 }
325
326
327 void
328 f_list_types(int otypes)
329 {
330         _Tt_typedb_ptr          db;
331         Tt_status               status;
332         int                     checkOW = 0;
333
334         if (cedb == TypedbNone) {
335                 cedb = TypedbAll;
336         }
337         db = new _Tt_typedb();
338         if (option_xdr) {
339                 if (ifile.len() > 0) {
340                         if (ifile == "-") {
341                                 status = db->init_xdr( stdin );
342                         } else {
343                                 status = db->init_xdr( ifile );
344                         }
345                 } else {
346                         status = db->init_xdr( cedb );
347                 }
348         } else {
349                 status = db->init_ce( cedb );
350         }
351         if (status != TT_OK) {
352                 if (status == TT_ERR_NO_MATCH) {
353                         _tt_syslog(stderr, LOG_ERR,
354                                    catgets(_ttcatd, 4, 19, "Version mismatch "
355                                            "in compiled types"));
356                 } else {
357                         _tt_syslog(stderr, LOG_ERR,
358                                    catgets(_ttcatd, 4, 20, "Cannot read types "
359                                            "in database"));
360                 }
361                 //
362                 // The most common way for this to fail seems to be
363                 // to not have OPENWINHOME set. Suggest this
364                 // to the user.
365                 //
366                 if (0==getenv("OPENWINHOME")) {
367                         _tt_syslog(stderr, LOG_ERR,
368                                    catgets(_ttcatd, 4, 21,
369                                            "$OPENWINHOME not set"));
370                 }
371                 exit(3);
372         }
373         if (otypes) {
374                 _Tt_otype_table_cursor  db_otypes;
375                 db_otypes.reset(db->otable);
376                 while (db_otypes.next()) {
377                         printf("%s\n", (char *)db_otypes->otid());
378                 }
379         } else {
380                 _Tt_ptype_table_cursor  db_ptypes;
381                 db_ptypes.reset(db->ptable);
382                 while (db_ptypes.next()) {
383                         printf("%s\n", (char *)db_ptypes->ptid());
384                 }
385         }
386 }
387
388 void
389 f_list_ptypes()
390 {
391         f_list_types( 0 );
392 }
393
394 void
395 f_list_otypes()
396 {
397         f_list_types( 1 );
398 }
399
400 void
401 f_remove_types()
402 {
403         _Tt_string_list_cursor  argc;
404         _Tt_typedb_ptr          db;
405         _Tt_otype_ptr           ot;
406         _Tt_ptype_ptr           pt;
407         int                     db_changed = 0;
408         Tt_status               err;
409
410         if (cedb == TypedbNone) {
411                 cedb = TypedbUser;
412         }
413         db = new _Tt_typedb();
414         if ((option_xdr && (err = db->init_xdr(cedb)) != TT_OK) ||
415             (!option_xdr && (err = db->init_ce(cedb)) != TT_OK)) {
416                 if (err == TT_ERR_NO_MATCH) {
417                         _tt_syslog(stderr, LOG_ERR,
418                                    catgets(_ttcatd, 4, 22,
419                                            "Cannot read types in %s data"
420                                            "base - version mismatch"),
421                                    _Tt_typedb::level_name(cedb));
422                 } else {
423                         _tt_syslog(stderr, LOG_ERR,
424                                    catgets(_ttcatd, 4, 23,
425                                            "Cannot read types in %s database"),
426                                    _Tt_typedb::level_name(cedb));
427                 }
428                 /*
429                  * The most common way for this to fail seems to be
430                  * to not have OPENWINHOME set. Suggest this
431                  * to the user.
432                  */
433                 if (0==getenv("OPENWINHOME")) {
434                         _tt_syslog(stderr, LOG_ERR,
435                                    catgets(_ttcatd, 4, 24,
436                                            "$OPENWINHOME not set"));
437                 }
438                 exit(3);
439         }
440
441         if (! db->begin_write(cedb)) {
442                 // diagnostic emitted
443                 exit(3);
444         }
445
446         argc.reset(cargs);
447         while (argc.next()) {
448                 pt = db->ptable->lookup(*argc);
449                 if (pt.is_null()) {
450                         ot = db->otable->lookup(*argc);
451                         if (! ot.is_null()) {
452                                 if (! _tt_global->silent) {
453                                         printf(catgets(_ttcatd, 4, 25,
454                                                        "Removing otype %s\n"),
455                                                (char *)(*argc));
456                                 }
457                                 db_changed = 1;
458                                 db->remove_otype(*argc);
459                         }
460                 } else {
461                         if (! _tt_global->silent) {
462                                 printf(catgets(_ttcatd, 4, 26,
463                                                "Removing ptype %s\n"),
464                                        (char *)(*argc));
465                         }
466                         db->remove_ptype(*argc);
467                         db_changed = 1;
468                 }
469         }
470         if (db_changed ) {
471                 // write out changes
472                 if (! db->end_write()) {
473                         exit(3);
474                 }
475         } else {
476                 db->abort_write();
477         }
478 }
479
480
481 void
482 f_xdr_file()
483 {
484         _Tt_typedb_ptr  db;
485
486         if (ofile.len() == 0) {
487                 if (ifile == "-") {
488                         ofile = "types.xdr";
489                 } else {
490                         ofile = ifile.cat(".xdr");
491                 }
492         }
493         read_types(ifile, db);
494
495         Tt_status status;
496         if (ofile == "-") {
497                 status = db->write( stdout );
498         } else {
499                 status = db->write( ofile );
500         }
501         if (status != TT_OK) {
502                 exit( 3 );
503         }
504         if (ofile != "-") {
505                 _Tt_typedb::send_saved( ofile );
506                 printf(catgets(_ttcatd, 4, 27, "output written to %s\n"),
507                        (char *)ofile);
508         }
509 }
510  
511
512 void
513 f_xdr_print()
514 {
515         _Tt_typedb_ptr  db;
516         Tt_status       status;
517         
518         db = new _Tt_typedb();
519         if (ifile.len() != 0) {
520                 if (ifile == "-") {
521                         status = db->init_xdr( stdin );
522                 } else {
523                         status = db->init_xdr( ifile );
524                 }
525         } else {
526                 if (cedb == TypedbNone) {
527                         cedb = TypedbAll;
528                 }
529                 status = db->init_xdr(cedb);
530         }
531         if (status != TT_OK) {
532                 // diagnostic emitted
533                 exit(3);
534         }
535         if (!db.is_null()) {
536                 db->pretty_print(stdout);
537         }
538 }
539
540 //
541 // This sends messages to the 'default' ToolTalk files.
542 // This forces an attempt to contact the sessions registered for
543 // each file, if they are dead, then a deleteSession() is sent
544 // to clear out (garbage collect) the information for that dead
545 // session. Dead sessions can occur in the dbserver if the system
546 // that had registered died without un-registering with dbserver
547 // for a file.
548 //
549 void
550 f_garbage_collect()
551 {
552         _Tt_db_client                   dbClient;
553         _Tt_string                      sessionId;
554
555         if (dbClient.getConnectionResults() == TT_DB_OK) {
556
557                 _Tt_string_list         *sessions;
558                 sessions = dbClient.get_all_sessions();
559
560                 if (sessions != NULL && sessions->count() > 0) {
561             
562                         // Delete the list of sessions that are dead.
563                         do {
564                                 Tt_status       ttstatus;
565
566                                 sessionId = sessions->top();
567                                 if ((ttstatus
568                                      = tt_default_session_set(sessionId))
569                                     != TT_OK) {
570                                         dbClient.delete_session(sessionId);
571                                 }
572                                 sessions->pop();
573                         } while(sessions->count() > 0);
574                 }
575                 dbClient.garbage_collect_in_server();
576         }
577         return;
578 }
579
580 void
581 process_args(int argc, char **argv)
582 {
583         extern char     *optarg;
584         extern int      optind;
585         extern int      opterr;
586         int             c;
587         int             args_left;
588         cmd_fn          fn;
589         int             fn_set = 0;
590
591         // default function is to merge types
592         fn = f_merge_overwrite;
593
594         // Need to parse out the cpp options specially because they
595         // don't work with getopt
596         for (int i = 1; i < argc; i++) {
597                 if (argv[i][0] == '-' &&
598                     (argv[i][1] == 'u' || argv[i][1] == 'D' ||
599                      argv[i][1] == 'I' || argv[i][1] == 'U' ||
600                      argv[i][1] == 'Y')) {
601                         if (argv[i][1] == 'u' &&
602                             strcmp(argv[i], "-undef") != 0) {
603                                 print_usage_and_exit();
604                         }
605                         cpp_options = cpp_options.cat(argv[i]).cat(" ");
606                         // getopt stops processing on an empty string, so
607                         // need a fake option for below
608                         argv[i] = "-Y";
609                 }
610         }
611         int need_file = 1;
612         int only_one_input = 0;
613         while ((c = getopt(argc, argv, "XEGOPsd:hmMo:prvxY")) != -1) {
614                 switch (c) {
615                       case 'X':
616                         option_xdr = 1;
617                         break;
618                       case 'E':
619                         option_xdr = 0;
620                         break;
621                       case 'O':
622                         fn_set++;
623                         fn = f_list_otypes;
624                         need_file = 0;
625                         only_one_input = 1;
626                         break;
627                       case 'P':
628                         fn_set++;
629                         fn = f_list_ptypes;
630                         need_file = 0;
631                         only_one_input = 1;
632                         break;
633                       case 's':
634                         _tt_global->silent = 1;
635                         break;
636                       case 'd':
637                         cedb = _Tt_typedb::level( optarg );
638                         if (cedb == TypedbNone) {
639                                 _tt_syslog( stderr, LOG_ERR,
640                                             catgets(_ttcatd, 4, 28,
641                                                     "Invalid database: %s"),
642                                             optarg );
643                                 print_usage_and_exit();
644                         }
645                         break;
646                       case 'h':
647                         print_usage_and_exit();
648                         break;
649                       case 'm':
650                         fn_set++;
651                         fn = f_merge_overwrite;
652                         break;
653                       case 'M':
654                         fn_set++;
655                         fn = f_merge_no_overwrite;
656                         break;
657                       case 'o':
658                         ofile = optarg;
659                         break;
660                       case 'p':
661                         fn_set++;
662                         need_file = 0;
663                         only_one_input = 1;
664                         if (option_xdr) {
665                                 fn = f_xdr_print;
666                         } else {
667                                 fn = f_ce_print;
668                         }
669                         break;
670                       case 'r':
671                         fn_set++;
672                         fn = f_remove_types;
673                         break;
674                       case 'v':
675                         _TT_PRINT_VERSIONS((char *)_tt_global->progname)
676                         exit(0);
677                       case 'x':
678                         fn_set++;
679                         fn = f_xdr_file;
680                         break;
681                       case 'Y':
682                         // A cpp option was handled, ignore this
683                         break;
684                       case 'G':
685                         // Garbage collect.
686                         need_file = 0;
687                         fn = f_garbage_collect;
688                         break;
689                       case '?':
690                       default:
691                         print_usage_and_exit();
692                         break;
693                 }
694         }
695         if (fn_set > 1) {
696                 _tt_syslog(stderr, LOG_ERR,
697                            catgets(_ttcatd, 4, 29,
698                                    "Specify only one of the options "
699                                    "-O -P -m -M -p -r -x"));
700                 print_usage_and_exit();
701         }
702         //
703         // Extra args are always either a filename or types to remove
704         //
705         ifile = argv[optind];
706         if (ifile.len() == 0) {
707                 if (need_file) {
708                         print_usage_and_exit();
709                 }
710         } else {
711                 if (only_one_input && (cedb != TypedbNone)) {
712                         print_usage_and_exit();
713                 }
714         }
715         if ((ofile.len() > 0) && (fn != f_xdr_file)) {
716                 print_usage_and_exit();
717         }
718         args_left = optind;
719         cargs = new _Tt_string_list();
720         while (argv[args_left]) {
721                 cargs->append(_Tt_string(argv[args_left++]));
722         }
723         (*fn)();
724 }
725
726 int main(int argc, char **argv)
727 {
728         _tt_global = new _Tt_global();
729         _tt_global->progname = argv[0];
730         setlocale( LC_ALL, "" );
731         _tt_openlog( _tt_global->progname, LOG_NOWAIT, 0 );
732         process_args(argc, argv);
733         return((int) 0);
734 }