Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / doc / util / dbtoman / instant / traninit.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: traninit.c /main/1 1996/07/23 19:43:52 rws $ */
24 /*
25  *  Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
26  *  All rights reserved.
27  */
28 /*
29  * Copyright (c) 1994  
30  * Open Software Foundation, Inc. 
31  *  
32  * Permission is hereby granted to use, copy, modify and freely distribute 
33  * the software in this file and its documentation for any purpose without 
34  * fee, provided that the above copyright notice appears in all copies and 
35  * that both the copyright notice and this permission notice appear in 
36  * supporting documentation.  Further, provided that the name of Open 
37  * Software Foundation, Inc. ("OSF") not be used in advertising or 
38  * publicity pertaining to distribution of the software without prior 
39  * written permission from OSF.  OSF makes no representations about the 
40  * suitability of this software for any purpose.  It is provided "as is" 
41  * without express or implied warranty. 
42  */
43 /*
44  * Copyright (c) 1996 X Consortium
45  * Copyright (c) 1995, 1996 Dalrymple Consulting
46  * 
47  * Permission is hereby granted, free of charge, to any person obtaining a copy
48  * of this software and associated documentation files (the "Software"), to deal
49  * in the Software without restriction, including without limitation the rights
50  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
51  * copies of the Software, and to permit persons to whom the Software is
52  * furnished to do so, subject to the following conditions:
53  * 
54  * The above copyright notice and this permission notice shall be included in
55  * all copies or substantial portions of the Software.
56  * 
57  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
58  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
59  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
60  * X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
61  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
62  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
63  * OTHER DEALINGS IN THE SOFTWARE.
64  * 
65  * Except as contained in this notice, the names of the X Consortium and
66  * Dalrymple Consulting shall not be used in advertising or otherwise to
67  * promote the sale, use or other dealings in this Software without prior
68  * written authorization.
69  */
70 /* ________________________________________________________________________
71  *
72  *  Program to manipulate SGML instances.
73  *
74  *  This module contains the initialization routines for translation module.
75  *  They mostly deal with reading data files (translation specs, SDATA
76  *  mappings, character mappings).
77  *
78  *  Entry points:
79  *      ReadTransSpec(transfile)        read/store translation spec from file
80  *      ReadSDATA(sdatafile)            read/store SDATA mappings from file
81  *      ReadMapping(mapfile)            read/store char mappings from file
82  * ________________________________________________________________________
83  */
84
85 #include <stdio.h>
86 #include <stdlib.h>
87 #include <ctype.h>
88 #include <string.h>
89 #include <memory.h>
90 #include <sys/types.h>
91 #include <errno.h>
92
93 #include <tptregexp.h>
94 #include "general.h"
95 #include "translate.h"
96
97 #ifndef TRUE
98 #define TRUE    (1 == 1)
99 #endif
100
101 /* forward references */
102 void    RememberTransSpec(Trans_t *, int);
103
104 /* ______________________________________________________________________ */
105 /*  Read the translation specs from the input file, storing in memory.
106  *  Arguments:
107  *      Name of translation spec file.
108  */
109
110 void
111 ReadTransSpec(
112     char *transfile
113 )
114 {
115     FILE        *fp;
116     char        buf[LINESIZE], *cp, *fn, *cp2;
117     int         lineno=0, c, i;
118     Trans_t     T;
119
120     if ((fp=OpenFile(transfile)) == NULL) {
121         fprintf(stderr, "Can not open translation spec file '%s'.\n%s\n",
122                 transfile, strerror(errno));
123         return;
124     }
125
126     memset(&T, 0, sizeof T);            /* initialize/clear structure */
127     while (fgets(buf, LINESIZE, fp))    /* read line from .ts file */
128     {
129         lineno++;
130         /* skip comment and blank lines */
131         if (buf[0] == '#' || buf[0] == NL) continue;
132
133         /* '-' indicates end of a spec.  When we hit one, remember what we've
134          * accumulated so far, and null-out the accumulating structure. */
135         if (buf[0] == '-') {
136             T.lineno = lineno;
137             RememberTransSpec(&T, lineno);
138             memset(&T, 0, sizeof T);
139             continue;
140         }
141
142         stripNL(buf);
143
144         /*  See if next line is continued from this one -- ie. it starts with
145          *  whitespace.  If so, append to current line.  (This is similar to
146          *  how e-mail headers work...) */
147         while (1) {
148             c = getc(fp);               /* 1st char of next line */
149             if (IsWhite(c)) {           /* space or tab? */
150                 /* keep getting characters until it's a non-whitespace */
151                 c = getc(fp);
152                 while (IsWhite(c)) c = getc(fp);
153                 ungetc(c, fp);          /* put back non-whitespace */
154                 i = strlen(buf);
155                 buf[i++] = ' ';
156                 fn = buf + i;           /* point to end of string in buffer */
157                 fgets(fn, LINESIZE-i, fp);      /* read and append to buf */
158                 lineno++;
159                 stripNL(buf);
160             }
161             else {
162                 ungetc(c, fp);          /* put back non-whitespace */
163                 break;
164             }
165         }
166         /* Isolate field value */
167         if ((cp=strchr(buf, ':'))) {
168             cp++;                               /* point past colon */
169             while (*cp && IsWhite(*cp)) cp++;   /* point to content */
170         }
171         else {
172             fprintf(stderr,
173                 "Trans spec error, missing colon (skipping line):\n  %s\n", fn);
174             continue;
175         }
176         fn = buf;               /* fn is name of the field, cp the value. */
177
178         /* Check field names in order that they're likely to occur. */
179         if (!strncmp("GI:",          fn, 3)) {
180             /* if we are folding the case of GIs, make all upper (unless
181                it's an internal pseudo-GI name, which starts with '_') */
182             if (fold_case && cp[0] != '_' && cp[0] != '#') {
183                 for (cp2=cp; *cp2; cp2++)
184                     if (islower(*cp2)) *cp2 = toupper(*cp2);
185             }
186             T.gi = AddElemName(cp);
187         }
188         else if (!strncmp("StartText:",   fn, 10)) T.starttext  = strdup(cp);
189         else if (!strncmp("EndText:",     fn, 8))  T.endtext    = strdup(cp);
190         else if (!strncmp("Relation:",    fn, 9))  {
191             if (!T.relations) T.relations = NewMap(IMS_relations);
192             SetMapping(T.relations, cp);
193         }
194         else if (!strncmp("Replace:",     fn, 8))  T.replace    = strdup(cp);
195         else if (!strncmp("AttValue:",    fn, 9)) {
196             if (!T.nattpairs) {
197                 Malloc(1, T.attpair, AttPair_t);
198             }
199             else
200                 Realloc((T.nattpairs+1), T.attpair, AttPair_t);
201             /* we'll split name/value pairs later */
202             T.attpair[T.nattpairs].name = strdup(cp);
203             T.nattpairs++;
204         }
205         /* If there's only one item in context, it's the parent.  Treat
206          * it specially, since it's easier to just check parent gi.
207          */
208         else if (!strncmp("Context:",     fn, 8))  T.context    = strdup(cp);
209         else if (!strncmp("Message:",     fn, 8))  T.message    = strdup(cp);
210         else if (!strncmp("SpecID:",      fn, 7))  T.my_id      = atoi(cp);
211         else if (!strncmp("Action:",      fn, 7))  T.use_id     = atoi(cp);
212         else if (!strncmp("Content:",     fn, 8))  T.content    = strdup(cp);
213         else if (!strncmp("PAttSet:",     fn, 8))  T.pattrset   = strdup(cp);
214         else if (!strncmp("Verbatim:",    fn, 9))  T.verbatim   = TRUE;
215         else if (!strncmp("Ignore:",      fn, 7)) {
216             if (!strcmp(cp, "all"))             T.ignore = IGN_ALL;
217             else if (!strcmp(cp, "data"))       T.ignore = IGN_DATA;
218             else if (!strcmp(cp, "children"))   T.ignore = IGN_CHILDREN;
219             else
220                 fprintf(stderr, "Bad 'Ignore:' arg in transpec (line %d): %s\n",
221                         lineno, cp);
222         }
223         else if (!strncmp("VarValue:",    fn, 9)) {
224             char        **tok;
225             i = 2;
226             tok = Split(cp, &i, S_STRDUP);
227             T.var_name  = tok[0];
228             T.var_value = tok[1];
229         }
230         else if (!strncmp("VarREValue:",    fn, 11)) {
231             char        **tok;
232             i = 2;
233             tok = Split(cp, &i, S_STRDUP);
234             T.var_RE_name = tok[0];
235             ExpandVariables(tok[1], buf, 0);
236             if (!(T.var_RE_value=tpt_regcomp(buf)))     {
237                 fprintf(stderr, "Regex error in VarREValue Content: %s\n",
238                                         tok[1]);
239             }
240         }
241         else if (!strncmp("Set:", fn, 4)) {
242             if (!T.set_var) T.set_var = NewMap(IMS_setvar);
243             SetMapping(T.set_var, cp);
244         }
245         else if (!strncmp("Increment:",   fn, 10)) {
246             if (!T.incr_var) T.incr_var = NewMap(IMS_incvar);
247             SetMapping(T.incr_var, cp);
248         }
249         else if (!strncmp("NthChild:",    fn, 9))  T.nth_child  = atoi(cp);
250         else if (!strncmp("Var:", fn, 4)) SetMapping(Variables, cp);
251         else if (!strncmp("Quit:",        fn, 5))  T.quit       = strdup(cp);
252         else
253             fprintf(stderr, "Unknown translation spec (skipping it): %s\n", fn);
254     }
255     fclose(fp);
256 }
257
258 /* ______________________________________________________________________ */
259 /*  Store translation spec 't' in memory.
260  *  Arguments:
261  *      Pointer to translation spec to remember.
262  *      Line number where translation spec ends.
263  */
264 void
265 RememberTransSpec(
266     Trans_t     *t,
267     int         lineno
268 )
269 {
270     char        *cp;
271     int         i, do_regex;
272     static Trans_t *last_t;
273     char buf[1000];
274
275     /* If context testing, check some details and set things up for later. */
276     if (t->context) {
277         /* See if the context specified is a regular expression.
278          * If so, compile the reg expr.  It is assumed to be a regex if
279          * it contains a character other than what's allowed for GIs in the
280          * OSF sgml declaration (alphas, nums, '-', and '.').
281          */
282         for (do_regex=0,cp=t->context; *cp; cp++) {
283             if (!isalnum(*cp) && *cp != '-' && *cp != '.' && *cp != ' ') {
284                 do_regex = 1;
285                 break;
286             }
287         }
288
289         if (do_regex) {
290             t->depth = MAX_DEPTH;
291             if (!(t->context_re=tpt_regcomp(t->context))) {
292                 fprintf(stderr, "Regex error in Context: %s\n", t->context);
293             }
294         }
295         else {
296             /* If there's only one item in context, it's the parent.  Treat
297              * it specially, since it's faster to just check parent gi.
298              */
299             cp = t->context;
300             if (!strchr(cp, ' ')) {
301                 t->parent  = t->context;
302                 t->context = NULL;
303             }
304             else {
305                 /* Figure out depth of context string */
306                 t->depth = 0;
307                 while (*cp) {
308                     if (*cp) t->depth++;
309                     while (*cp && !IsWhite(*cp)) cp++;  /* find end of gi */
310                     while (*cp && IsWhite(*cp)) cp++;   /* skip space */
311                 }
312             }
313         }
314     }
315
316     /* Compile regular expressions for each attribute */
317     for (i=0; i<t->nattpairs; i++) {
318         /* Initially, name points to "name value".  Split them... */
319         cp = t->attpair[i].name;
320         while (*cp && !IsWhite(*cp)) cp++;      /* point past end of name */
321         if (*cp) {      /* value found */
322             *cp++ = EOS;                        /* terminate name */
323             while (*cp && IsWhite(*cp)) cp++;   /* point to value */
324             ExpandVariables(cp, buf, 0);        /* expand any variables */
325             t->attpair[i].val = strdup(buf);
326         }
327         else {          /* value not found */
328             t->attpair[i].val = ".";
329         }
330         if (!(t->attpair[i].rex=tpt_regcomp(t->attpair[i].val))) {
331             fprintf(stderr, "Regex error in AttValue: %s %s\n",
332                     t->attpair[i].name, t->attpair[i].val);
333         }
334     }
335
336     /* Compile regular expression for content */
337     t->content_re = 0;
338     if (t->content) {
339         ExpandVariables(t->content, buf, 0);
340         if (!(t->content_re=tpt_regcomp(buf)))
341             fprintf(stderr, "Regex error in Content: %s\n",
342                     t->content);
343     }
344
345     /* If multiple GIs, break up into a vector, then remember it.  We either
346      * sture the individual, or the list - not both. */
347     if (t->gi && strchr(t->gi, ' ')) {
348         t->gilist = Split(t->gi, 0, S_ALVEC);
349         t->gi = NULL;
350     }
351
352     /* Now, store structure in linked list. */
353     if (!TrSpecs) {
354         Malloc(1, TrSpecs, Trans_t);
355         last_t = TrSpecs;
356     }
357     else {
358         Malloc(1, last_t->next, Trans_t);
359         last_t = last_t->next;
360     }
361     *last_t = *t;
362 }
363
364
365 /* ______________________________________________________________________ */
366 /*  Read mapping file, filling in structure slots (just name-value pairs).
367  *  Arguments:
368  *      Name of character mapping file.
369  */
370
371 void
372 ReadCharMap(
373     char *filename
374 )
375 {
376     FILE        *fp;
377     char        buf[LINESIZE], *name, *val;
378     int         lineno=0;
379     int         n_alloc=0;      /* number of slots allocated so far */
380
381     if ((fp=OpenFile(filename)) == NULL) {
382         fprintf(stderr, "Can not open character mapping file '%s'.\n%s\n",
383                 filename, strerror(errno));
384         return;
385     }
386
387     /* We allocate slots in blocks of N, so we don't have to call
388      * malloc so many times. */
389     n_alloc  = 32;
390     Calloc(n_alloc, CharMap, Mapping_t);
391
392     nCharMap = 0;
393     while (fgets(buf, LINESIZE, fp))
394     {
395         lineno++;
396         /* skip comment and blank lines */
397         if (buf[0] == '#' || buf[0] == NL) continue;
398         stripNL(buf);
399
400         /* Need more slots for mapping structures? */
401         if (nCharMap >= n_alloc) {
402             n_alloc += 32;
403             Realloc(n_alloc, CharMap, Mapping_t);
404         }
405         name = val = buf;
406         while (*val && !IsWhite(*val)) val++;   /* point past end of name */
407         if (*val) {
408             *val++ = EOS;                               /* terminate name */
409             while (*val && IsWhite(*val)) val++;        /* point to value */
410         }
411         if (name) {
412             CharMap[nCharMap].name = strdup(name);
413             if (val) CharMap[nCharMap].sval = strdup(val);
414             if (CharMap[nCharMap].name[0] == '\\') CharMap[nCharMap].name++;
415             nCharMap++;
416         }
417     }
418     fclose(fp);
419 }
420
421 /* ______________________________________________________________________ */
422 /* Read SDATA mapping file, remembering the mappings in memory.
423  * Input file format is 2 columns, name and value, separated by one or
424  * more tabs (not spaces).
425  * This can be called multuple times, reading several files.
426  *  Arguments:
427  *      Name of SDATA entity mapping file.
428  */
429
430 void
431 ReadSDATA(
432     char *filename
433 )
434 {
435     FILE        *fp;
436     char        buf[LINESIZE], *name, *val;
437     int         lineno=0;
438
439     if ((fp=OpenFile(filename)) == NULL) {
440         fprintf(stderr, "Can not open SDATA file '%s': %s", filename,
441                 strerror(errno));
442         return;
443     }
444
445     if (!SDATAmap) SDATAmap = NewMap(IMS_sdata);
446
447     while (fgets(buf, LINESIZE, fp))
448     {
449         lineno++;
450         /* skip comment and blank lines */
451         if (buf[0] == '#' || buf[0] == NL) continue;
452         stripNL(buf);
453
454         name = val = buf;
455         while (*val && *val != TAB) val++;      /* point past end of name */
456         if (*val) {
457             *val++ = EOS;                       /* terminate name */
458             while (*val && *val == TAB) val++;  /* point to value */
459         }
460
461         SetMappingNV(SDATAmap, name, val);
462     }
463     fclose(fp);
464 }
465
466 /* ______________________________________________________________________ */