2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
27 * COMPONENT_NAME: (CMDMSG) Message Catalogue Facilities
29 * FUNCTIONS: main, mkcatdefs, incl, chkcontin, insert, nsearch, hash
33 * IBM CONFIDENTIAL -- (IBM Confidential Restricted when
34 * combined with the aggregated modules for this product)
35 * OBJECT CODE ONLY SOURCE MATERIALS
36 * (C) COPYRIGHT International Business Machines Corp. 1988, 1989, 1991
39 * US Government Users Restricted Rights - Use, duplication or
40 * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
66 #define NL_TEXTMAX 8192
73 #define MAXLINELEN NL_TEXTMAX
77 #define MDIRSIZ _D_NAME_MAX
82 static int errflg = 0;
85 static int symbflg = 0;
86 static int inclfile = 1;
89 static FILE *descfile;
90 static char inname [PATH_MAX];
91 static char outname [PATH_MAX];
92 static char catname [PATH_MAX];
94 static void mkcatdefs(char *);
95 static int chkcontin(char *);
96 static int insert(char *, int);
97 static int nsearch(char *);
98 static int hash(char *);
104 * FUNCTION: Make message catalog defines.
106 * EXECUTION ENVIRONMENT:
110 * mkcatdefs <name> <msg_file>
112 * Results are 1) Creates header file <name>.h.
113 * 2) Displays message file to stdout. The message file is
114 * ready to be used as input to gencat.
116 * mkcatdefs takes a message definition file and produces
117 * a header file containing #defines for the message catalog,
118 * the message sets and the messages themselves. It also
119 * produces a new message file which has the symbolic message set and
120 * message identifiers replaced by their numeric values (in the form
121 * required by gencat).
123 * DATA STRUCTURES: Effects on global data structures -- none.
125 * RETURNS: 1 - error condition
137 setlocale (LC_ALL,"");
139 /* usage: handle multiple files; -h option has to be at the end */
142 "mkcatdefs: Usage: %s header_file msg_file [msg_file...] [-h]\n",
147 /* check if include file should be created; -h is the last argument */
148 if (argv[argc-1][0] == '-' && argv[argc-1][1] == 'h')
151 /* open header output file */
154 if ((int)strlen((t = strrchr(mname,'/')) ? t + 1 : mname) > MDIRSIZ) {
155 fprintf (stderr, "mkcatdefs: header file name too long\n");
158 sprintf (outname, "%s", mname);
159 if (strrchr(mname,'/'))
160 mname = strrchr(mname,'/') + 1;
161 if ((outfp = fopen (outname, "w")) == NULL) {
162 fprintf (stderr, "mkcatdefs: Cannot open %s\n", outname);
165 /* convert name to upper case */
166 for (cp=mname; *cp; cp+=i) {
167 i = mblen(cp, MB_CUR_MAX);
169 fprintf (stderr, "mkcatdefs: filename contains invalid character\n");
173 if (islower(*cp) != 0)
175 else if (!isupper(*cp) && !isdigit(*cp))
180 } else sprintf (outname, "msg.h");
183 /* open new msg output file */
186 /* if message descriptor files were specified then process each one in turn
193 for (i = 2; i < count; i++) {
194 /* open input file */
195 sprintf (inname, "%s", argv[i]);
196 if (strcmp(inname,"-") == 0) {
197 strcpy(inname,"stdin");
198 descfile = stdin; /* input from stdin if no source files */
201 if ((descfile = fopen(inname,"r")) == NULL) {
202 fprintf (stderr, "mkcatdefs: Cannot open %s\n", inname);
214 if (ferror (outfp)) {
215 fprintf (stderr, "mkcatdefs: There were write errors on file %s\n",
223 fprintf (stderr, "mkcatdefs: Errors found: no %s created\n", outname);
224 if (inclfile) unlink(outname);
228 fprintf (stderr, "mkcatdefs: %s created\n", outname);
230 fprintf (stderr, "mkcatdefs: No symbolic identifiers; no %s created\n",
236 fprintf(stderr, "mkcatdefs: no %s created\n", outname);
244 * FUNCTION: Make message catalog definitions.
246 * EXECUTION ENVIRONMENT:
252 mkcatdefs(char *fname)
253 /*---- fname: message descriptor file name ----*/
255 char msgname [PATH_MAX];
256 char line [MAXLINELEN];
262 int len; /* # bytes in a character */
265 /* put out header for include file */
268 fprintf (outfp, "/* $%s$ */\n", "XConsortium");
269 fprintf (outfp, "\n\n/* The following was generated from %s. */\n\n",
273 /* process the message file */
274 while (fgets(line, MAXLINELEN, descfile)) {
275 line[MAXLINELEN-1] = '\0'; /* terminate in case length exceeded */
276 /* find first nonblank character */
277 for (cp=line; *cp; cp+=len) {
278 len = mblen(cp, MB_CUR_MAX);
281 "mkcatdefs: sourcefile contains invalid character:\n\t%s",
286 if (len == 1 && isspace(*cp) == 0)
289 if (*cp == KEY_START) {
291 for (cpt = cp; *cp; cp += len) {
292 len = mblen(cp, MB_CUR_MAX);
295 "mkcatdefs: sourcefile contains invalid character:\n\t%s",
300 if (len == 1 && isspace(*cp) == 0)
304 sscanf (cp, "%s", msgname);
305 if ((m = nsearch(msgname)) > 0) {
306 fprintf (msgfp, "$ %d", m);
307 cp += strlen(msgname);
308 fprintf (msgfp, "%s", cp);
311 continue; /* line is a comment */
313 if ((strncmp (cp, "set", 3) == 0) &&
314 ((len = mblen(&(cp[3]), MB_CUR_MAX)) == 1) &&
315 (isspace(cp[3]) != 0)) {
316 char setname [MAXIDLEN];
318 sscanf (cp+3+len, "%s", setname);
320 fprintf (outfp, "\n/* definitions for set %s */\n", setname, "");
321 if (isdigit(setname[0])) {
324 if (!isdigit(*cpt)) {
325 fprintf(stderr, "mkcatdefs: %s is an invalid identifier\n",
336 fprintf(stderr, "mkcatdefs: %s is an invalid identifier\n",
340 "mkcatdefs: set # %d already assigned or sets not in ascending sequence\n",
348 len = mblen(cpt, MB_CUR_MAX);
351 "mkcatdefs: sourcefile contains invalid character:\n\t%s",
356 if (len == 1 && (isalnum(*cpt) == 0) && (*cpt != '_')) {
358 "mkcatdefs: %s is an invalid identifier\n",
363 } while (*(cpt += len));
365 fprintf (outfp, "#define %s %d\n\n", setname, setno);
369 fprintf (msgfp,"$delset");
370 fprintf (msgfp," %d\n", setno);
372 fprintf (msgfp,"%.4s", line);
373 fprintf (msgfp," %d\n", setno++);
377 /* !!!other command */
381 if (!chkcontin(line))
383 } else if (setno > 1) { /* set must have been seen first */
384 char msgname [MAXIDLEN];
387 if (sscanf (cp, "%s", msgname) && msgname[0]) {
388 len = mblen(cp, MB_CUR_MAX);
391 "mkcatdefs: sourcefile contains invalid character:\n\t%s",
396 if (len == 1 && isalpha(*cp) != 0) {
399 len = mblen(cpt, MB_CUR_MAX);
402 "mkcatdefs: sourcefile contains invalid character:\n\t%s",
407 if (len == 1 && (isalnum(*cpt) == 0) && (*cpt != '_')) {
408 fprintf(stderr, "mkcatdefs: %s is an invalid identifier\n",
413 } while (*(cpt += len));
414 cp += strlen(msgname);
415 fprintf (msgfp,"%d%s", msgno,cp);
417 fprintf (outfp, "#define %s %d\n", msgname, msgno);
421 if(insert(msgname,msgno++) < 0) {
422 fprintf(stderr, "mkcatdefs: name %s used more than once\n",
428 } else if (isdigit (msgname[0])){
431 if (!isdigit(*cpt)) {
432 fprintf(stderr, "mkcatdefs: invalid syntax in %s\n", line);
438 if ((n >= msgno) || (n == 0 && msgno == 1))
443 fprintf(stderr, "mkcatdefs: %d is an invalid identifier\n",
447 "mkcatdefs: message id %s already assigned to identifier\n",
451 "mkcatdefs: source messages not in ascending sequence\n");
462 /* make sure the operations read/write operations were successful */
463 if (ferror(descfile)) {
464 fprintf (stderr, "mkcatdefs: There were read errors on file %s\n", inname);
473 * FUNCTION: Check for continuation line.
475 * EXECUTION ENVIRONMENT:
478 * RETURNS: 0 - not a continuation line.
479 * 1 - continuation line.
482 chkcontin(char *line)
484 int len; /* # bytes in character */
485 wchar_t wc; /* process code of current character in line */
486 wchar_t wcprev; /* process code of previous character in line */
488 for (wc=0; *line; line+=len) {
490 len = mbtowc(&wc, line, MB_CUR_MAX);
493 "mkcatdefs: sourcefile contains invalid character:\n\t%s",
499 if (wcprev == '\\' && wc == '\n')
504 #define HASHSIZE 256 /* must be a power of 2 */
505 #define HASHMAX HASHSIZE - 1
514 static struct name *symtab[HASHSIZE]; /* hashed pointers to binary trees */
519 * FUNCTION: Insert symbol
521 * EXECUTION ENVIRONMENT:
524 * NOTES: These routines manipulate a symbol table for the mkcatdefs program.
525 * The symbol table is organized as a hashed set of binary trees. If the
526 * symbol being passed in is found then a -1 is returned, otherwise the
527 * symbol is placed in the symbol table and a 0 is returned. The purpose
528 * of the symbol table is to keep mkcatdefs from assigning two different
529 * message set / message numbers to the same symbol.
530 * Read the next line from the open message catalog descriptor file.
532 * RETURNS: 0 - symbol inserted.
533 * -1 - symbol exists.
540 tname - pointer to symbol
541 seqno - integer value of symbol
545 register struct name *ptr,*optr;
546 int rslt = -1,i,hashval;
548 hashval = hash(tname);
549 ptr = symtab[hashval];
551 /* search the binary tree for specified symbol */
552 while (ptr && (rslt = strcmp(tname,ptr->regname))) {
560 if (rslt == 0) /* found the symbol already defined */
562 else { /* symbol not defined yet so put it into symbol table */
563 ptr = (struct name *)calloc(sizeof(struct name), 1);
564 ptr->regname = malloc(strlen(tname) + 1);
565 strcpy (ptr->regname, tname);
568 /* not first entry in tree so update branch pointer */
569 if (symtab[hashval]) {
575 /* first entry in tree so set the root pointer */
577 symtab[hashval] = ptr;
586 * FUNCTION: Search for symbol
588 * EXECUTION ENVIRONMENT:
591 * NOTES: Searches for specific identifier. If found, return allocated number.
592 * If not found, return -1.
594 * RETURNS: Symbol sequence number if symbol is found.
595 * -1 if symbol is not found.
598 nsearch (char *tname)
600 tname - pointer to symbol
604 register struct name *ptr,*optr;
605 int rslt = -1,i,hashval;
607 hashval = hash(tname);
608 ptr = symtab[hashval];
610 /* search the binary tree for specified symbol */
611 while (ptr && (rslt = strcmp(tname,ptr->regname))) {
619 if (rslt == 0) /* found the symbol already defined */
629 * FUNCTION: Create hash value from symbol name.
631 * EXECUTION ENVIRONMENT:
634 * NOTES: Hash the symbol name using simple addition algorithm.
635 * Make sure that the hash value is in range when it is returned.
637 * RETURNS: A hash value.
641 hash (char *name) /* pointer to symbol */
643 register int hashval = 0;
648 return (hashval & HASHMAX);