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