Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dthelp / parser / pass2 / util / conutil.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 /* $XConsortium: conutil.c /main/3 1995/11/08 11:03:16 rswiston $ */
24 /*
25               Copyright 1986 Tandem Computers Incorporated.
26 This product and information is proprietary of Tandem Computers Incorporated.
27                Copyright (c) 1986, 1987, 1988, 1989 Hewlett-Packard Co.
28 */
29
30 /* Conutil has utility procedures for program CONTEXT. */
31 #include <stdio.h>
32 #include <string.h>
33 #include <malloc.h>
34 #if defined(MSDOS)
35 #include <process.h>
36 #endif
37 #include "basic.h"
38 #include "trie.h"
39
40 #include "cont.h"
41
42 /* Output declaration of dlmptr */
43 void dumpdlmptr(M_NOPAR)
44   {
45     int n;
46
47     fprintf(delim, "M_DELIMEXTERN M_WCHAR *m_dlmptr[%d];\n", dcount+1);
48     fprintf(delim, "M_DELIMEXTERN char *mb_dlmptr[%d]\n", dcount+1);
49     fprintf(delim, "#if defined(M_DELIMDEF)\n  = {\n");
50     for (n = 0 ; n < dcount ; n++) {
51       if (n) fputs(",\n", delim);
52       fprintf(delim, "  %s", dlmptr[n]);
53       }
54     fprintf(delim, endif);
55     }
56
57 /* Output the generated data structures */
58 #if defined(M_PROTO)
59 void dumptree(LOGICAL sparse)
60 #else
61 void dumptree(sparse)
62   LOGICAL sparse;
63 #endif
64   {
65     int i, count = 0;
66
67     for (i = 0 ; i < ccount ; i++)
68       if (contree[i])
69         countdown(contree[i], &count);
70     fprintf(delim,
71      "M_DELIMEXTERN M_PTRIE m_delimtrie[%d]\n#if defined(M_DELIMDEF)\n = {\n",
72       count);
73     fprintf(context,
74       "M_CONEXTERN int m_contree[%d]\n#if defined(M_CONDEF)\n = {\n  ",
75       ccount);
76
77     count = 0;
78     for (i = 0 ; i < ccount ; i++) {
79       if (contree[i]) {
80         fprintf(context, "%d", count + 1);
81         dumpnode(&first, delim, contree[i], &count, (void *)printval);
82         }
83       else fprintf(context, "0");
84       if (i < ccount - 1) fprintf(context, ",\n  ");
85       }
86     fprintf(delim, endif);
87     fprintf(context, endif);
88     nextcon(sparse);
89     }
90
91 /* Enter a delimiter into the delimiter tree for a particular context */
92 void enterdelim(n)
93   int n;
94 {
95 if (! contree[n])
96     {
97     contree[n] = m_gettrienode();
98     }
99
100 if (m_ntrtrie(dstruct->string,
101               contree[n],
102               (void *) (unsigned long) dstruct->count))
103     {
104     char *mb_dstring, *mb_contexts;
105
106     mb_dstring = MakeMByteString(dstring);
107     mb_contexts = MakeMByteString(contexts[n]);
108     dcount--;
109     warning2("Duplicate assignment to delimiter \"%s\" in context \"%s\"",
110              mb_dstring,
111              mb_contexts);
112     m_free(mb_dstring,"multi-byte string");
113     m_free(mb_contexts,"multi-byte string");
114     }
115 }
116
117 /* Read the code to be executed with a given state transition */
118 void getcode(n)
119 int n;
120 {
121 int c ; /* c is int instead of char for use with ungetc */
122 int nested = 1;
123 LOGICAL comment = FALSE;
124 char *mb_context;
125 M_WCHAR wlb = 0, wcm, wnl, wsl, wst;
126
127
128 if (!wlb)
129     {
130     mbtowc(&wlb, "{", 1); /* keep the "}" balanced */
131     mbtowc(&wcm, ",", 1);
132     mbtowc(&wnl, "\n", 1);
133     mbtowc(&wsl, "/", 1);
134     mbtowc(&wst, "*", 1);
135     }
136
137 while (m_whitespace((M_WCHAR) (c = readchar(FALSE))));
138 if (c != wlb && c != wcm)
139     {
140     unread(c);
141     return;
142     }
143
144 if (! casestarted)
145     {
146     char *mb_dname;
147
148     mb_dname = MakeMByteString(dname);
149     casestarted = TRUE;
150     fprintf(fcase, "      case %s:\n", mb_dname);
151     fprintf(fcase, "        switch (m_prevcon) {\n") ; /* balance the } */
152     m_free(mb_dname,"multi-byte string");
153     }
154
155 mb_context = MakeMByteString(contexts[n]);
156 fprintf(fcase, "          case %s:\n", mb_context);
157 m_free(mb_context,"multi-byte string");
158
159 if (c == wcm) return;
160
161 fprintf(fcase, "/* line %d \"context.dat\" */\n", m_line);
162
163 while (TRUE)
164     {
165     char mb_c[32]; /* arbitrarily large */
166     int  length;
167
168     c = readchar(FALSE);
169     if (c == EOF)
170         {
171         warning("Unexpected EOF");
172         exit(TRUE);
173         }
174
175     length = wctomb(mb_c, c);
176     mb_c[length] = 0;
177     if (length == 1)
178         {
179         switch (mb_c[0])
180             {
181             case '{':
182                 if (! comment) nested++;
183                 break;
184             case '}': 
185                 if (! comment)
186                 if (! --nested)
187                     {
188                     fprintf(fcase,"\n            break ;\n");
189                     return;
190                     }
191                 break;
192             case '/':
193                 if (! comment)
194                     {
195                     fprintf(fcase, "/");
196                     c = readchar(FALSE);
197                     if (c == wst) comment = TRUE;
198                     length = wctomb(mb_c, c);
199                     mb_c[length] = 0;
200                     }
201                 break;
202             case '*':
203                 if (comment)
204                     {
205                     fprintf(fcase, "*");
206                     c = readchar(FALSE);
207                     if (c == wsl) comment = FALSE;
208                     length = wctomb(mb_c, c);
209                     mb_c[length] = 0;
210                     }
211             } /* End case */
212         }
213     fprintf(fcase, "%s", mb_c);
214 #if 0
215     if (c == wnl)
216         fprintf(fcase, "#line %d \"context.dat\"\n", m_line);
217 #endif
218     } /* End while */
219 } /* End proc getcode() */
220
221 /* Read the colon separating the two states in a transition pair */
222 void getcolon(M_NOPAR)
223 {
224 int c ; /* c is int instead of char for use with ungetc */
225 M_WCHAR wcl;
226 char unexp[32]; /* arbitraily large */
227 int  length;
228
229 mbtowc(&wcl, ":", 1);
230
231 while (TRUE)
232     {
233     c = readchar(FALSE);
234     if (! m_whitespace((M_WCHAR) c)) break;
235     }
236 if (c != wcl)
237     {
238     length = wctomb(unexp, (M_WCHAR) c);
239     unexp[length] = 0;
240     warning1("Expecting : instead of '%s'\n", unexp);
241     }
242 }
243
244 /* Read a context name from an input line */
245 int getContext(M_NOPAR)
246 {
247 M_WCHAR name[CNAMELEN + 1];
248 int c ; /* c is int instead of char for use with ungetc */
249 int i = 0;
250 M_WCHAR wsm = 0, wcl, wcm;
251 char *mb_name;
252
253 if (!wsm)
254     {
255     mbtowc(&wsm, ";", 1);
256     mbtowc(&wcl, ":", 1);
257     mbtowc(&wcm, ",", 1);
258     }
259
260 while (TRUE)
261     {
262     c = readchar(TRUE);
263     if (c == EOF) return(NOMORE);
264     *name = (M_WCHAR) c;
265     if (*name == wsm) return(NOMORE);
266     if (! m_whitespace(*name)) break;
267     }
268
269 while (TRUE)
270     {
271     i++;
272     if (i >= CNAMELEN)
273         {
274         while (! m_whitespace((M_WCHAR) (c = readchar(TRUE)))
275         && c != wcl
276         && c != wcm
277         && c != EOF
278         && c != wsm);
279         unread(c);
280         break;
281         }
282     c = readchar(TRUE);
283     if (m_whitespace((M_WCHAR) c) ||
284     c == wsm ||
285     c == wcl ||
286     c == wcm ||
287     c == EOF)
288         {
289         unread(c);
290         break;
291         }
292     name[i] = (M_WCHAR) c;
293     }
294 name[i] = M_EOS;
295
296 for (i = 0 ; i < ccount ; i++)
297     if (! w_strcmp(name, contexts[i])) return(i);
298
299 inccon() ;
300 i = w_strlen(name) + 1;
301 contexts[ccount - 1] = (M_WCHAR *) m_malloc(i, "context name");
302 memcpy(contexts[ccount - 1], name, i * sizeof(M_WCHAR));
303
304 mb_name = MakeMByteString(name);
305 fprintf(context, "#define %s %d\n", mb_name, ccount);
306 m_free(mb_name,"multi-byte string");
307
308 return(ccount - 1);
309 }
310
311 /* Read a delimiter name from the input line */
312 LOGICAL getdname(M_NOPAR)
313 {
314 int c;
315 M_WCHAR *p;
316
317 /* Skip leading blanks */
318 while (TRUE)
319     {
320     c = readchar(TRUE);
321     if (c == EOF) return(FALSE);
322     if (! m_whitespace((M_WCHAR) c)) break;
323     }
324 for (p = dname;
325 ! m_whitespace((M_WCHAR) c) && c != EOF;
326 c = readchar(TRUE))
327     {
328     if (p - dname >= DNAMELEN)
329         {
330         while (! m_whitespace((M_WCHAR) c) && c != EOF) c = readchar(TRUE);
331         break;
332         }
333     *p++ = (M_WCHAR) c;
334     }
335 *p = M_EOS;
336 if (dstruct = (struct dstruct *) m_lookfortrie(dname, &delimtrie))
337     {
338     withdelim = TRUE;
339     curdelim = dstruct->count - 1;
340     }
341 else
342     {
343     char *mb_dname;
344
345     curdelim = dcount;
346     incdelim();
347     withdelim = FALSE;
348     mb_dname = MakeMByteString(dname);
349     fprintf(delim, "#define %s %d\n", mb_dname, dcount);
350     m_free(mb_dname,"multi-byte string");
351     }
352 return(TRUE);
353 }
354
355 /* Out of context space.  Increase. */
356 void inccon(M_NOPAR)
357   {
358     M_TRIE **newtrie = NULL;
359     int *newtransit = NULL;
360     M_WCHAR **newcontexts = NULL;
361     int trysize;
362     int i, j;
363
364     if (ccount < NUMCON) {
365       ccount++;
366       return;
367       }
368     trysize = m_plus10p(NUMCON);
369     newtrie = (M_TRIE **) calloc(trysize, sizeof(M_TRIE *));
370     newtransit = (int *) calloc(trysize * NUMDELIM, sizeof(int));
371     newcontexts = (M_WCHAR **) calloc(trysize, sizeof(M_WCHAR *));
372     if (! newtrie || ! newtransit || ! newcontexts) {
373       trysize = NUMCON + 1;
374       if (newtrie) free((M_POINTER) newtrie);
375       if (newtransit) free((M_POINTER) newtransit);
376       if (newcontexts) free((M_POINTER) newcontexts);
377       newtrie = (M_TRIE **) calloc(trysize, sizeof(M_TRIE *));
378       newtransit = (int *) calloc(trysize * NUMDELIM, sizeof(int));
379       newcontexts = (M_WCHAR **) calloc(trysize, sizeof(M_WCHAR *));
380       }
381     if (! newtrie || ! newtransit || ! newcontexts) {
382       m_error("Out of memory for contexts");
383       exit(TRUE);
384       }
385     for (i = 0 ; i < ccount ; i++) 
386       for (j = 0 ; j < dcount ; j++)
387         newtransit[i * NUMDELIM + j] = transit(i, j);
388     NUMCON = trysize;
389     free((M_POINTER) xtransit);
390     xtransit = newtransit;
391     memcpy((M_POINTER) newtrie, (M_POINTER) contree,
392            ccount * sizeof(M_TRIE **));
393     memcpy((M_POINTER) newcontexts, (M_POINTER) contexts,
394            ccount * sizeof(M_WCHAR **));
395     free((M_POINTER) contree);
396     free((M_POINTER) contexts);
397     contree = newtrie;
398     contexts = newcontexts;
399     ccount++;
400     }
401
402 /* Increase delimiter space. */
403 void incdelim(M_NOPAR)
404 {
405 int *newtransit = NULL;
406 char **newdlm = NULL;
407 int trysize;
408 int i, j;
409
410 if (dcount < NUMDELIM)
411     {
412     dcount++;
413     return;
414     }
415
416 trysize = m_plus10p(NUMDELIM);
417 newtransit = (int *) calloc(NUMCON * trysize, sizeof(int));
418 if (loading) newdlm = (char **) calloc(trysize, sizeof(M_WCHAR *));
419 if (! newtransit || (loading && ! newdlm))
420     {
421     trysize = NUMDELIM + 1;
422     newtransit = (int *) calloc(NUMCON * trysize, sizeof(int));
423     if (loading) newdlm = (char **) calloc(trysize, sizeof(M_WCHAR *));
424     }
425 if (! newtransit || (loading && ! newdlm))
426     {
427     m_error("Out of memory for delimiters");
428     exit(TRUE);
429     }
430 for (i = 0 ; i < ccount ; i++) 
431 for (j = 0 ; j < dcount ; j++)
432 newtransit[i * trysize + j] = transit(i, j);
433 free((M_POINTER) xtransit);
434 if (loading)
435     {
436     memcpy((M_POINTER) newdlm, (M_POINTER) dlmptr, dcount * sizeof(M_TRIE **));
437     free((M_POINTER) dlmptr);
438     dlmptr = newdlm;
439     }
440 NUMDELIM = trysize;
441 xtransit = newtransit;
442 dcount++;
443 }
444
445 /* Read delimiter definitions from delim.dat */
446 void loaddelim(M_NOPAR)
447 {
448 int c;
449 M_WCHAR *p;
450 int i;
451 M_WCHAR wnl;
452 char *mb_dname, *mb_dstring;
453
454 mbtowc(&wnl, "\n", 1);
455
456 loading = TRUE;
457 while ((c = getc(ddat)) != EOF)
458     {
459     /* Skip leading white space */
460     if (c == wnl) continue;
461     if (m_whitespace((M_WCHAR) c))
462         {
463         while ((c = getc(ddat)) != wnl)
464         if (c == EOF) return;
465         continue;
466         }
467     /* Delimiter name into dname */
468     for (p = dname ; ! m_whitespace((M_WCHAR) c) ; c = getc(ddat))
469         {
470         if (c == EOF)
471             {
472             warning("Unexpected EOF");
473             exit(TRUE);
474             }
475         if (p - dname >= DNAMELEN)
476             {
477             while (! m_whitespace((M_WCHAR) c) && c != EOF) c = getc(ddat);
478             if (c == EOF)
479                 {
480                 warning("Unexpected EOF");
481                 exit(TRUE);
482                 }
483             break;
484             }
485         *p++ = m_upper(c);
486         }
487     *p = M_EOS;
488     /* Skip intervening white space */
489     while (m_whitespace((M_WCHAR) c) && c != EOF) c = getc(ddat);
490     if (c == EOF)
491         {
492         warning("Unexpected EOF");
493         exit(TRUE);
494         }
495     /* Delimiter string into dstring */
496     for (p = dstring;
497     ! m_whitespace((M_WCHAR) c) && c != EOF;
498     c = getc(ddat))
499         {
500         if (p - dstring >= DELIMLEN)
501             {
502             m_error("Delimiter string too long");
503             exit(TRUE);
504             }
505         *p++ = c;
506         }
507     *p = M_EOS;
508     if (w_strlen(dstring) > maxd) maxd = w_strlen(dstring);
509     /* Write definitions to output file.  Save data for later. */
510     incdelim();
511     dstruct = (struct dstruct *)
512         m_malloc(sizeof(struct dstruct), "delimiter structure");
513     dstruct->string = (M_WCHAR *) m_malloc(w_strlen(dstring) + 1, "delimiter");
514     w_strcpy(dstruct->string, dstring);
515     dstruct->count = dcount;
516
517     mb_dname = MakeMByteString(dname);
518     fprintf(delim, "#define %s %d\n", mb_dname, dcount);
519     m_free(mb_dname,"multi-byte string");
520
521     for (i = 0 ; dname[i] ; i++)
522         dname[i] = m_lower(dname[i]);
523     mb_dname = MakeMByteString(dname);
524
525     mb_dstring = MakeMByteString(dstring);
526     fprintf(delim,
527             "M_DELIMEXTERN char %s[%d] M_DELIMINIT(\"",
528             mb_dname,
529             strlen(mb_dstring) + 1);
530
531     for (p = dstring ; *p ; p++)
532         {
533         char *pc;
534         char mb_p[32]; /* arbitrarily large */
535         int  length, i;
536
537         length = wctomb(mb_p, *p);
538         mb_p[length] = 0;
539
540         pc = mb_p;
541         while (*pc)
542             {
543             if (*pc == '"' || *pc == '\\') putc('\\', delim);
544             putc(*pc, delim);
545             pc++;
546             }
547         }
548     fputs("\") ;\n", delim);
549
550     dlmptr[dcount - 1] = MakeMByteString(dname);
551     if (m_ntrtrie(dname, &delimtrie, dstruct)) 
552         m_err1("Duplicate definition of %s", mb_dname);
553     while (c != wnl)
554         {
555         if (c == EOF) break;
556         c = getc(ddat);
557         }
558     m_free(mb_dname,"multi-byte string");
559     m_free(mb_dstring,"multi-byte string");
560     }
561 dumpdlmptr();
562 loading = FALSE;
563 }
564
565 /* Output transition matrix */
566 #if defined(M_PROTO)
567 void nextcon(LOGICAL sparse)
568 #else
569 void nextcon(sparse)
570   LOGICAL sparse;
571 #endif
572   {
573     int i, j;
574     int firstinrow;
575
576     if (sparse) {
577       for (i = 0 ; i < ccount ; i++) {
578         for (j = 0 ; j < dcount ; j++)
579           if (transit(i, j)) nonzero++;
580         nonzero++;
581         }
582       fprintf(delim,
583         "M_DELIMEXTERN struct {\n  %s context ;\n  %s nextcon ;\n",
584           contype, contype);
585       fprintf(delim, "  } m_trnsit [%d]\n", nonzero);
586
587       nonzero = 0;
588       fprintf(delim, "#if defined(M_DELIMDEF)\n  = {\n");
589       fprintf(context, "M_CONEXTERN int m_trnsptr[%d]\n", ccount);
590       fprintf(context, "#if defined(M_CONDEF)\n  = {\n");
591       for (i = 0 ; i < ccount ; i++) {
592         firstinrow = 0;
593         for (j = 0 ; j < dcount ; j++) {
594           if (! transit(i, j)) continue;
595           prtctxt(j, transit(i, j));
596           if (! firstinrow) firstinrow = nonzero;
597           }
598         prtctxt(0, 0);
599         if (i > 0) fprintf(context, ",\n");
600         fprintf(context, "  %d", firstinrow);
601         }
602       fprintf(delim, endif);
603       fprintf(context, endif);
604       }
605     else {
606       fprintf(context,
607         "M_CONEXTERN %s m_nextcon[%d][%d]\n#if defined(M_CONDEF)\n  = {\n",
608         contype, ccount, dcount);
609       for (i = 0 ; i < ccount ; i++) {
610         fprintf(context, "  {\n");
611         for (j = 0 ; j < dcount ; j++) {
612           fprintf(context, "    %d", transit(i, j));
613           if (j < dcount - 1) fprintf(context, ",\n");
614           }
615         fprintf(context, "}");
616         if (i < ccount - 1) fprintf(context, ",");
617         fprintf(context, "\n");
618         }
619       fprintf(context, endif);
620       }
621     }
622   
623 /* If sparse matrix output option, generate a single element of transit
624    array */
625 void prtctxt(column, value)
626   int column, value;
627   {
628     static LOGICAL first = TRUE;
629
630     if (! first) fprintf(delim, ",\n");
631     first = FALSE;
632     fprintf(delim, "  %d, %d", column, value);
633     nonzero++;
634     }
635
636
637 /* Read the next input character */
638 #if defined(M_PROTO)
639 int readchar(LOGICAL cap)
640 #else
641 int readchar(cap)
642   LOGICAL cap;
643 #endif
644 {
645 int c;
646 M_WCHAR wnl;
647
648 mbtowc(&wnl, "\n", 1);
649
650 c = mb_getwc(cdat); /* use mb_getwc so we read multi-byte chars */
651 if (cap && c != EOF) c = m_upper(c);
652
653 if (c == wnl) m_line++;
654
655 return(c);
656 }
657
658 /* Called by utility procedure m_error() -- has content in other programs
659    that use m_error() */
660 void skiptoend(M_NOPAR)
661 {
662 }
663
664 /* Return a character to the input stream for re-reading */
665 void unread(c)
666 int c;
667 {
668 M_WCHAR wnl;
669
670 mbtowc(&wnl, "\n", 1);
671
672 ungetc(c, cdat);
673 if (c == wnl) m_line--;
674 }