dtudcfonted: Resolve CID 86280
[oweals/cde.git] / cde / config / makedepend / parse.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 /* $TOG: parse.c /main/35 1998/03/25 08:17:55 kaleb $ */
24 /*
25
26 Copyright (c) 1993, 1994, 1998 The Open Group
27
28 All Rights Reserved.
29
30 The above copyright notice and this permission notice shall be included in
31 all copies or substantial portions of the Software.
32
33 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
36 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
37 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
38 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39
40 Except as contained in this notice, the name of The Open Group shall not be
41 used in advertising or otherwise to promote the sale, use or other dealings
42 in this Software without prior written authorization from The Open Group.
43
44 */
45
46 #include "def.h"
47
48 static int deftype();
49 static int zero_value();
50 static int merge2defines();
51
52 extern char     *directives[];
53 extern struct inclist   maininclist;
54
55 int
56 gobble(filep, file, file_red)
57         register struct filepointer *filep;
58         struct inclist          *file, *file_red;
59 {
60         register char   *line;
61         register int    type;
62
63         while ((line = our_getline(filep))) {
64                 switch(type = deftype(line, filep, file_red, file, FALSE)) {
65                 case IF:
66                 case IFFALSE:
67                 case IFGUESSFALSE:
68                 case IFDEF:
69                 case IFNDEF:
70                         type = gobble(filep, file, file_red);
71                         while ((type == ELIF) || (type == ELIFFALSE) ||
72                                (type == ELIFGUESSFALSE))
73                             type = gobble(filep, file, file_red);
74                         if (type == ELSE)
75                                 (void)gobble(filep, file, file_red);
76                         break;
77                 case ELSE:
78                 case ENDIF:
79                         debug(0,("%s, line %d: #%s\n",
80                                 file->i_file, filep->f_line,
81                                 directives[type]));
82                         return(type);
83                 case DEFINE:
84                 case UNDEF:
85                 case INCLUDE:
86                 case INCLUDEDOT:
87                 case PRAGMA:
88                 case ERROR:
89                 case IDENT:
90                 case SCCS:
91                 case EJECT:
92                 case WARNING:
93                         break;
94                 case ELIF:
95                 case ELIFFALSE:
96                 case ELIFGUESSFALSE:
97                         return(type);
98                 case -1:
99                         warning("%s, line %d: unknown directive == \"%s\"\n",
100                                 file_red->i_file, filep->f_line, line);
101                         break;
102                 }
103         }
104         return(-1);
105 }
106
107 /*
108  * Decide what type of # directive this line is.
109  */
110 int deftype (line, filep, file_red, file, parse_it)
111         register char   *line;
112         register struct filepointer *filep;
113         register struct inclist *file_red, *file;
114         int     parse_it;
115 {
116         register char   *p;
117         char    *directive, savechar, *q;
118         register int    ret;
119
120         /*
121          * Parse the directive...
122          */
123         directive=line+1;
124         while (*directive == ' ' || *directive == '\t')
125                 directive++;
126
127         p = directive;
128         while (*p >= 'a' && *p <= 'z')
129                 p++;
130         savechar = *p;
131         *p = '\0';
132         ret = match(directive, directives);
133         *p = savechar;
134
135         /* If we don't recognize this compiler directive or we happen to just
136          * be gobbling up text while waiting for an #endif or #elif or #else
137          * in the case of an #elif we must check the zero_value and return an
138          * ELIF or an ELIFFALSE.
139          */
140
141         if (ret == ELIF && !parse_it)
142         {
143             while (*p == ' ' || *p == '\t')
144                 p++;
145             /*
146              * parse an expression.
147              */
148             debug(0,("%s, line %d: #elif %s ",
149                    file->i_file, filep->f_line, p));
150             ret = zero_value(p, filep, file_red);
151             if (ret != IF)
152             {
153                 debug(0,("false...\n"));
154                 if (ret == IFFALSE)
155                     return(ELIFFALSE);
156                 else
157                     return(ELIFGUESSFALSE);
158             }
159             else
160             {
161                 debug(0,("true...\n"));
162                 return(ELIF);
163             }
164         }
165
166         if (ret < 0 || ! parse_it)
167                 return(ret);
168
169         /*
170          * now decide how to parse the directive, and do it.
171          */
172         while (*p == ' ' || *p == '\t')
173                 p++;
174         q = p + strlen(p);
175         do {
176                 q--;
177         } while (*q == ' ' || *q == '\t');
178         q[1] = '\0';
179         switch (ret) {
180         case IF:
181                 /*
182                  * parse an expression.
183                  */
184                 ret = zero_value(p, filep, file_red);
185                 debug(0,("%s, line %d: %s #if %s\n",
186                          file->i_file, filep->f_line, ret?"false":"true", p));
187                 break;
188         case IFDEF:
189         case IFNDEF:
190                 debug(0,("%s, line %d: #%s %s\n",
191                         file->i_file, filep->f_line, directives[ret], p));
192         case UNDEF:
193                 /*
194                  * separate the name of a single symbol.
195                  */
196                 while (isalnum((int)*p) || *p == '_')
197                         *line++ = *p++;
198                 *line = '\0';
199                 break;
200         case INCLUDE:
201                 debug(2,("%s, line %d: #include %s\n",
202                         file->i_file, filep->f_line, p));
203
204                 /* Support ANSI macro substitution */
205                 {
206                     struct symtab **sym = isdefined(p, file_red, NULL);
207                     while (sym) {
208                         p = (*sym)->s_value;
209                         debug(3,("%s : #includes SYMBOL %s = %s\n",
210                                file->i_incstring,
211                                (*sym) -> s_name,
212                                (*sym) -> s_value));
213                         /* mark file as having included a 'soft include' */
214                         file->i_flags |= INCLUDED_SYM; 
215                         sym = isdefined(p, file_red, NULL);
216                     }
217                 }
218
219                 /*
220                  * Separate the name of the include file.
221                  */
222                 while (*p && *p != '"' && *p != '<')
223                         p++;
224                 if (! *p)
225                         return(-2);
226                 if (*p++ == '"') {
227                         ret = INCLUDEDOT;
228                         while (*p && *p != '"')
229                                 *line++ = *p++;
230                 } else
231                         while (*p && *p != '>')
232                                 *line++ = *p++;
233                 *line = '\0';
234                 break;
235         case DEFINE:
236                 /*
237                  * copy the definition back to the beginning of the line.
238                  */
239                 memmove (line, p, strlen(p) + 1);
240                 break;
241         case ELSE:
242         case ENDIF:
243         case ELIF:
244         case PRAGMA:
245         case ERROR:
246         case IDENT:
247         case SCCS:
248         case EJECT:
249                 debug(0,("%s, line %d: #%s\n",
250                         file->i_file, filep->f_line, directives[ret]));
251                 /*
252                  * nothing to do.
253                  */
254                 break;
255         }
256         return(ret);
257 }
258
259 struct symtab **fdefined(symbol, file, srcfile)
260         register char   *symbol;
261         struct inclist  *file;
262         struct inclist  **srcfile;
263 {
264         register struct inclist **ip;
265         register struct symtab  **val;
266         register int    i;
267         static int      recurse_lvl = 0;
268
269         if (file->i_flags & DEFCHECKED)
270                 return(NULL);
271         file->i_flags |= DEFCHECKED;
272         if ((val = slookup(symbol, file)))
273                 debug(1,("%s defined in %s as %s\n",
274                          symbol, file->i_file, (*val)->s_value));
275         if (val == NULL && file->i_list)
276                 {
277                 for (ip = file->i_list, i=0; i < file->i_listlen; i++, ip++)
278                         if (file->i_merged[i]==FALSE) {
279                                 val = fdefined(symbol, *ip, srcfile);
280                                 if ((*ip)->i_flags & FINISHED) {
281                                         merge2defines(file,*ip);
282                                         file->i_merged[i]=TRUE;
283                                     }
284                                 if (val!=NULL) break;
285                         }
286                 }
287         else if (val != NULL && srcfile != NULL) *srcfile = file;
288         recurse_lvl--;
289         file->i_flags &= ~DEFCHECKED;
290
291         return(val);
292 }
293
294 struct symtab **isdefined(symbol, file, srcfile)
295         register char   *symbol;
296         struct inclist  *file;
297         struct inclist  **srcfile;
298 {
299         register struct symtab  **val;
300
301         if ((val = slookup(symbol, &maininclist))) {
302                 debug(1,("%s defined on command line\n", symbol));
303                 if (srcfile != NULL) *srcfile = &maininclist;
304                 return(val);
305         }
306         if ((val = fdefined(symbol, file, srcfile)))
307                 return(val);
308         debug(1,("%s not defined in %s\n", symbol, file->i_file));
309         return(NULL);
310 }
311
312 /*
313  * Return type based on if the #if expression evaluates to 0
314  */
315 int
316 zero_value(exp, filep, file_red)
317         register char   *exp;
318         register struct filepointer *filep;
319         register struct inclist *file_red;
320 {
321         if ((cppsetup(exp, filep, file_red)))
322             return(IFFALSE);
323         else
324             return(IF);
325 }
326
327 void
328 define2(name, val, file)
329         char    *name, *val;
330         struct inclist  *file;
331 {
332     int first, last, below;
333     register struct symtab **sp = NULL, **dest;
334     struct symtab *stab;
335
336     /* Make space if it's needed */
337     if (file->i_defs == NULL)
338     {
339         file->i_defs = (struct symtab **)
340                         malloc(sizeof (struct symtab*) * SYMTABINC);
341         file->i_ndefs = 0;
342     }
343     else if (!(file->i_ndefs % SYMTABINC))
344         file->i_defs = (struct symtab **)
345                         realloc(file->i_defs,
346                            sizeof(struct symtab*)*(file->i_ndefs+SYMTABINC));
347
348     if (file->i_defs == NULL)
349         fatalerr("malloc()/realloc() failure in insert_defn()\n");
350
351     below = first = 0;
352     last = file->i_ndefs - 1;
353     while (last >= first)
354     {
355         /* Fast inline binary search */
356         register char *s1;
357         register char *s2;
358         register int middle = (first + last) / 2;
359
360         /* Fast inline strchr() */
361         s1 = name;
362         s2 = file->i_defs[middle]->s_name;
363         while (*s1++ == *s2++)
364             if (s2[-1] == '\0') break;
365
366         /* If exact match, set sp and break */
367         if (*--s1 == *--s2) 
368         {
369             sp = file->i_defs + middle;
370             break;
371         }
372
373         /* If name > i_defs[middle] ... */
374         if (*s1 > *s2) 
375         {
376             below = first;
377             first = middle + 1;
378         }
379         /* else ... */
380         else
381         {
382             below = last = middle - 1;
383         }
384     }
385
386     /* Search is done.  If we found an exact match to the symbol name,
387        just replace its s_value */
388     if (sp != NULL)
389     {
390         free((*sp)->s_value);
391         (*sp)->s_value = copy(val);
392         return;
393     }
394
395     sp = file->i_defs + file->i_ndefs++;
396     dest = file->i_defs + below + 1;
397     while (sp > dest)
398     {
399         *sp = sp[-1];
400         sp--;
401     }
402     stab = (struct symtab *) malloc(sizeof (struct symtab));
403     if (stab == NULL)
404         fatalerr("malloc()/realloc() failure in insert_defn()\n");
405
406     stab->s_name = copy(name);
407     stab->s_value = copy(val);
408     *sp = stab;
409 }
410
411 void
412 define(def, file)
413         char    *def;
414         struct inclist  *file;
415 {
416     char *val;
417
418     /* Separate symbol name and its value */
419     val = def;
420     while (isalnum((int)*val) || *val == '_')
421         val++;
422     if (*val)
423         *val++ = '\0';
424     while (*val == ' ' || *val == '\t')
425         val++;
426
427     if (!*val)
428         val = "1";
429     define2(def, val, file);
430 }
431
432 struct symtab **slookup(symbol, file)
433         register char   *symbol;
434         register struct inclist *file;
435 {
436         register int first = 0;
437         register int last = file->i_ndefs - 1;
438
439         if (file) while (last >= first)
440         {
441             /* Fast inline binary search */
442             register char *s1;
443             register char *s2;
444             register int middle = (first + last) / 2;
445
446             /* Fast inline strchr() */
447             s1 = symbol;
448             s2 = file->i_defs[middle]->s_name;
449             while (*s1++ == *s2++)
450                 if (s2[-1] == '\0') break;
451
452             /* If exact match, we're done */
453             if (*--s1 == *--s2) 
454             {
455                 return file->i_defs + middle;
456             }
457
458             /* If symbol > i_defs[middle] ... */
459             if (*s1 > *s2) 
460             {
461                 first = middle + 1;
462             }
463             /* else ... */
464             else
465             {
466                 last = middle - 1;
467             }
468         }
469         return(NULL);
470 }
471
472 int merge2defines(file1, file2)
473         struct inclist  *file1;
474         struct inclist  *file2;
475 {
476         if ((file1!=NULL) && (file2!=NULL)) 
477         {
478                 int first1 = 0;
479                 int last1 = file1->i_ndefs - 1;
480
481                 int first2 = 0;
482                 int last2 = file2->i_ndefs - 1;
483
484                 int first=0;
485                 struct symtab** i_defs = NULL;
486                 int deflen=file1->i_ndefs+file2->i_ndefs;
487
488                 if (deflen>0)
489                 { 
490                         /* make sure deflen % SYMTABINC == 0 is still true */
491                         deflen += (SYMTABINC - deflen % SYMTABINC) % SYMTABINC;
492                         i_defs=(struct symtab**)
493                             malloc(deflen*sizeof(struct symtab*));
494                         if (i_defs==NULL) return 0;
495                 }
496
497                 while ((last1 >= first1) && (last2 >= first2))
498                 {
499                         char *s1=file1->i_defs[first1]->s_name;
500                         char *s2=file2->i_defs[first2]->s_name;
501
502                         if (strcmp(s1,s2) < 0)
503                                 i_defs[first++]=file1->i_defs[first1++];
504                         else if (strcmp(s1,s2) > 0)
505                                 i_defs[first++]=file2->i_defs[first2++];
506                         else /* equal */
507                         {
508                                 i_defs[first++]=file2->i_defs[first2++];
509                                 first1++;
510                         }
511                 }
512                 while (last1 >= first1)
513                 {
514                         i_defs[first++]=file1->i_defs[first1++];
515                 }
516                 while (last2 >= first2)
517                 {
518                         i_defs[first++]=file2->i_defs[first2++];
519                 }
520
521                 if (file1->i_defs) free(file1->i_defs);
522                 file1->i_defs=i_defs;
523                 file1->i_ndefs=first;
524                 
525                 return 1;
526         }
527         return 0;
528 }
529
530 void
531 undefine(symbol, file)
532         char    *symbol;
533         register struct inclist *file;
534 {
535         register struct symtab **ptr;
536         struct inclist *srcfile;
537         while ((ptr = isdefined(symbol, file, &srcfile)) != NULL)
538         {
539             srcfile->i_ndefs--;
540             for (; ptr < srcfile->i_defs + srcfile->i_ndefs; ptr++)
541                 *ptr = ptr[1];
542         }
543 }
544
545 int
546 find_includes(filep, file, file_red, recursion, failOK)
547         struct filepointer      *filep;
548         struct inclist          *file, *file_red;
549         int                     recursion;
550         boolean                 failOK;
551 {
552         register char   *line;
553         register int    type;
554         boolean recfailOK;
555
556         while ((line = our_getline(filep))) {
557                 switch(type = deftype(line, filep, file_red, file, TRUE)) {
558                 case IF:
559                 doif:
560                         type = find_includes(filep, file,
561                                 file_red, recursion+1, failOK);
562                         while ((type == ELIF) || (type == ELIFFALSE) ||
563                                (type == ELIFGUESSFALSE))
564                                 type = gobble(filep, file, file_red);
565                         if (type == ELSE)
566                                 gobble(filep, file, file_red);
567                         break;
568                 case IFFALSE:
569                 case IFGUESSFALSE:
570                     doiffalse:
571                         if (type == IFGUESSFALSE || type == ELIFGUESSFALSE)
572                             recfailOK = TRUE;
573                         else
574                             recfailOK = failOK;
575                         type = gobble(filep, file, file_red);
576                         if (type == ELSE)
577                             find_includes(filep, file,
578                                           file_red, recursion+1, recfailOK);
579                         else
580                         if (type == ELIF)
581                             goto doif;
582                         else
583                         if ((type == ELIFFALSE) || (type == ELIFGUESSFALSE))
584                             goto doiffalse;
585                         break;
586                 case IFDEF:
587                 case IFNDEF:
588                         if ((type == IFDEF && isdefined(line, file_red, NULL))
589                          || (type == IFNDEF && !isdefined(line, file_red, NULL))) {
590                                 debug(1,(type == IFNDEF ?
591                                     "line %d: %s !def'd in %s via %s%s\n" : "",
592                                     filep->f_line, line,
593                                     file->i_file, file_red->i_file, ": doit"));
594                                 type = find_includes(filep, file,
595                                         file_red, recursion+1, failOK);
596                                 while (type == ELIF || type == ELIFFALSE || type == ELIFGUESSFALSE)
597                                         type = gobble(filep, file, file_red);
598                                 if (type == ELSE)
599                                         gobble(filep, file, file_red);
600                         }
601                         else {
602                                 debug(1,(type == IFDEF ?
603                                     "line %d: %s !def'd in %s via %s%s\n" : "",
604                                     filep->f_line, line,
605                                     file->i_file, file_red->i_file, ": gobble"));
606                                 type = gobble(filep, file, file_red);
607                                 if (type == ELSE)
608                                         find_includes(filep, file,
609                                                 file_red, recursion+1, failOK);
610                                 else if (type == ELIF)
611                                         goto doif;
612                                 else if (type == ELIFFALSE || type == ELIFGUESSFALSE)
613                                         goto doiffalse;
614                         }
615                         break;
616                 case ELSE:
617                 case ELIFFALSE:
618                 case ELIFGUESSFALSE:
619                 case ELIF:
620                         if (!recursion)
621                                 gobble(filep, file, file_red);
622                 case ENDIF:
623                         if (recursion)
624                                 return(type);
625                 case DEFINE:
626                         define(line, file);
627                         break;
628                 case UNDEF:
629                         if (!*line) {
630                             warning("%s, line %d: incomplete undef == \"%s\"\n",
631                                 file_red->i_file, filep->f_line, line);
632                             break;
633                         }
634                         undefine(line, file_red);
635                         break;
636                 case INCLUDE:
637                         add_include(filep, file, file_red, line, FALSE, failOK);
638                         break;
639                 case INCLUDEDOT:
640                         add_include(filep, file, file_red, line, TRUE, failOK);
641                         break;
642                 case ERROR:
643                         warning("%s: %d: %s\n", file_red->i_file,
644                                  filep->f_line, line);
645                         break;
646                     
647                 case PRAGMA:
648                 case IDENT:
649                 case SCCS:
650                 case EJECT:
651                         break;
652                 case -1:
653                         warning("%s", file_red->i_file);
654                         if (file_red != file)
655                             warning1(" (reading %s)", file->i_file);
656                         warning1(", line %d: unknown directive == \"%s\"\n",
657                                  filep->f_line, line);
658                         break;
659                 case -2:
660                         warning("%s", file_red->i_file);
661                         if (file_red != file)
662                             warning1(" (reading %s)", file->i_file);
663                         warning1(", line %d: incomplete include == \"%s\"\n",
664                                  filep->f_line, line);
665                         break;
666                 }
667         }
668         file->i_flags |= FINISHED;
669         return(-1);
670 }