Back to index

enigmail  1.4.3
parse.c
Go to the documentation of this file.
00001 /* $Xorg: parse.c,v 1.6 2001/02/09 02:03:16 xorgcvs Exp $ */
00002 /*
00003 
00004 Copyright (c) 1993, 1994, 1998 The Open Group
00005 
00006 Permission to use, copy, modify, distribute, and sell this software and its
00007 documentation for any purpose is hereby granted without fee, provided that
00008 the above copyright notice appear in all copies and that both that
00009 copyright notice and this permission notice appear in supporting
00010 documentation.
00011 
00012 The above copyright notice and this permission notice shall be included in
00013 all copies or substantial portions of the Software.
00014 
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00018 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00019 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00020 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00021 
00022 Except as contained in this notice, the name of The Open Group shall not be
00023 used in advertising or otherwise to promote the sale, use or other dealings
00024 in this Software without prior written authorization from The Open Group.
00025 
00026 */
00027 /* $XFree86: xc/config/makedepend/parse.c,v 1.12 2002/02/26 05:09:10 tsi Exp $ */
00028 
00029 #include "def.h"
00030 
00031 extern char   *directives[];
00032 extern struct inclist       inclist[ MAXFILES ],
00033                      *inclistnext,
00034                      maininclist;
00035 extern char   *includedirs[ ],
00036               **includedirsnext;
00037 
00038 static int deftype (char *line, struct filepointer *filep,
00039                   struct inclist *file_red, struct inclist *file,
00040                   int parse_it);
00041 static int zero_value(char *filename, char *exp, struct filepointer *filep,
00042                   struct inclist *file_red);
00043 static int merge2defines(struct inclist *file1, struct inclist *file2);
00044 
00045 static int
00046 gobble(struct filepointer *filep, struct inclist *file,
00047        struct inclist *file_red)
00048 {
00049        char   *line;
00050        int    type;
00051 
00052        while ((line = getnextline(filep))) {
00053               switch(type = deftype(line, filep, file_red, file, FALSE)) {
00054               case IF:
00055               case IFFALSE:
00056               case IFGUESSFALSE:
00057               case IFDEF:
00058               case IFNDEF:
00059                      type = gobble(filep, file, file_red);
00060                      while ((type == ELIF) || (type == ELIFFALSE) ||
00061                             (type == ELIFGUESSFALSE))
00062                          type = gobble(filep, file, file_red);
00063                      if (type == ELSE)
00064                              (void)gobble(filep, file, file_red);
00065                      break;
00066               case ELSE:
00067               case ENDIF:
00068                      debug(0,("%s, line %d: #%s\n",
00069                             file->i_file, filep->f_line,
00070                             directives[type]));
00071                      return(type);
00072               case DEFINE:
00073               case UNDEF:
00074               case INCLUDE:
00075               case INCLUDEDOT:
00076               case PRAGMA:
00077               case ERROR:
00078               case IDENT:
00079               case SCCS:
00080               case EJECT:
00081               case WARNING:
00082               case INCLUDENEXT:
00083               case INCLUDENEXTDOT:
00084                      break;
00085               case ELIF:
00086               case ELIFFALSE:
00087               case ELIFGUESSFALSE:
00088                      return(type);
00089               case -1:
00090                      warning("%s", file_red->i_file);
00091                      if (file_red != file)
00092                             warning1(" (reading %s)", file->i_file);
00093                      warning1(", line %d: unknown directive == \"%s\"\n",
00094                             filep->f_line, line);
00095                      break;
00096               }
00097        }
00098        return(-1);
00099 }
00100 
00101 /*
00102  * Decide what type of # directive this line is.
00103  */
00104 static int 
00105 deftype (char *line, struct filepointer *filep, 
00106             struct inclist *file_red, struct inclist *file, int parse_it)
00107 {
00108        register char *p;
00109        char   *directive, savechar, *q;
00110        register int  ret;
00111 
00112        /*
00113         * Parse the directive...
00114         */
00115        directive=line+1;
00116        while (*directive == ' ' || *directive == '\t')
00117               directive++;
00118 
00119        p = directive;
00120        while ((*p == '_') || (*p >= 'a' && *p <= 'z'))
00121               p++;
00122        savechar = *p;
00123        *p = '\0';
00124        ret = match(directive, directives);
00125        *p = savechar;
00126 
00127        /* If we don't recognize this compiler directive or we happen to just
00128         * be gobbling up text while waiting for an #endif or #elif or #else
00129         * in the case of an #elif we must check the zero_value and return an
00130         * ELIF or an ELIFFALSE.
00131         */
00132 
00133        if (ret == ELIF && !parse_it)
00134        {
00135            while (*p == ' ' || *p == '\t')
00136               p++;
00137            /*
00138             * parse an expression.
00139             */
00140            debug(0,("%s, line %d: #elif %s ",
00141                  file->i_file, filep->f_line, p));
00142            ret = zero_value(file->i_file, p, filep, file_red);
00143            if (ret != IF)
00144            {
00145               debug(0,("false...\n"));
00146               if (ret == IFFALSE)
00147                   return(ELIFFALSE);
00148               else
00149                   return(ELIFGUESSFALSE);
00150            }
00151            else
00152            {
00153               debug(0,("true...\n"));
00154               return(ELIF);
00155            }
00156        }
00157 
00158        if (ret < 0 || ! parse_it)
00159               return(ret);
00160 
00161        /*
00162         * now decide how to parse the directive, and do it.
00163         */
00164        while (*p == ' ' || *p == '\t')
00165               p++;
00166        q = p + strlen(p);
00167        do {
00168               q--;
00169        } while (*q == ' ' || *q == '\t');
00170        q[1] = '\0';
00171        switch (ret) {
00172        case IF:
00173               /*
00174                * parse an expression.
00175                */
00176               ret = zero_value(file->i_file, p, filep, file_red);
00177               debug(0,("%s, line %d: %s #if %s\n",
00178                       file->i_file, filep->f_line, ret?"false":"true", p));
00179               break;
00180        case IFDEF:
00181        case IFNDEF:
00182               debug(0,("%s, line %d: #%s %s\n",
00183                      file->i_file, filep->f_line, directives[ret], p));
00184        case UNDEF:
00185               /*
00186                * separate the name of a single symbol.
00187                */
00188               while (isalnum(*p) || *p == '_')
00189                      *line++ = *p++;
00190               *line = '\0';
00191               break;
00192        case INCLUDE:
00193        case INCLUDENEXT:
00194               debug(2,("%s, line %d: #include%s %s\n",
00195                      file->i_file, filep->f_line,
00196                      (ret == INCLUDE) ? "" : "_next", p));
00197 
00198               /* Support ANSI macro substitution */
00199               while (1) {
00200                      struct symtab **sym;
00201 
00202                      if (!*p || *p == '"' || *p == '<')
00203                             break;
00204 
00205                      sym = isdefined(p, file_red, NULL);
00206                      if (!sym)
00207                             break;
00208 
00209                      p = (*sym)->s_value;
00210                      debug(3,("%s : #includes SYMBOL %s = %s\n",
00211                             file->i_incstring,
00212                             (*sym) -> s_name,
00213                             (*sym) -> s_value));
00214                      /* mark file as having included a 'soft include' */
00215                      file->i_flags |= INCLUDED_SYM; 
00216               }
00217 
00218               /*
00219                * Separate the name of the include file.
00220                */
00221               while (*p && *p != '"' && *p != '<')
00222                      p++;
00223               if (! *p)
00224                      return(-2);
00225               if (*p++ == '"') {
00226                      if (ret == INCLUDE)
00227                             ret = INCLUDEDOT;
00228                      else
00229                             ret = INCLUDENEXTDOT;
00230                      while (*p && *p != '"')
00231                             *line++ = *p++;
00232               } else
00233                      while (*p && *p != '>')
00234                             *line++ = *p++;
00235               *line = '\0';
00236               break;
00237        case DEFINE:
00238               /*
00239                * copy the definition back to the beginning of the line.
00240                */
00241               strcpy (line, p);
00242               break;
00243        case ELSE:
00244        case ENDIF:
00245        case ELIF:
00246        case PRAGMA:
00247        case ERROR:
00248        case IDENT:
00249        case SCCS:
00250        case EJECT:
00251        case WARNING:
00252               debug(0,("%s, line %d: #%s\n",
00253                      file->i_file, filep->f_line, directives[ret]));
00254               /*
00255                * nothing to do.
00256                */
00257               break;
00258        }
00259        return(ret);
00260 }
00261 
00262 struct symtab **
00263 fdefined(char *symbol, struct inclist *file, struct inclist **srcfile)
00264 {
00265        struct inclist       **ip;
00266        struct symtab **val;
00267        int    i;
00268        static int    recurse_lvl = 0;
00269 
00270        if (file->i_flags & DEFCHECKED)
00271               return(NULL);
00272        debug(2,("Looking for %s in %s\n", symbol, file->i_file));
00273        file->i_flags |= DEFCHECKED;
00274        if ((val = slookup(symbol, file)))
00275               debug(1,("%s defined in %s as %s\n",
00276                       symbol, file->i_file, (*val)->s_value));
00277        if (val == NULL && file->i_list)
00278        {
00279               for (ip = file->i_list, i=0; i < file->i_listlen; i++, ip++)
00280                      if (file->i_merged[i]==FALSE) {
00281                             val = fdefined(symbol, *ip, srcfile);
00282                             file->i_merged[i]=merge2defines(file,*ip);
00283                             if (val!=NULL) break;
00284                      }
00285        }
00286        else if (val != NULL && srcfile != NULL) *srcfile = file;
00287        recurse_lvl--;
00288        file->i_flags &= ~DEFCHECKED;
00289 
00290        return(val);
00291 }
00292 
00293 struct symtab **
00294 isdefined(char *symbol, struct inclist *file, struct inclist **srcfile)
00295 {
00296        struct symtab **val;
00297 
00298        if ((val = slookup(symbol, &maininclist))) {
00299               debug(1,("%s defined on command line\n", symbol));
00300               if (srcfile != NULL) *srcfile = &maininclist;
00301               return(val);
00302        }
00303        if ((val = fdefined(symbol, file, srcfile)))
00304               return(val);
00305        debug(1,("%s not defined in %s\n", symbol, file->i_file));
00306        return(NULL);
00307 }
00308 
00309 /*
00310  * Return type based on if the #if expression evaluates to 0
00311  */
00312 static int
00313 zero_value(char *filename,
00314           char *exp,
00315           struct filepointer *filep,
00316           struct inclist *file_red)
00317 {
00318        if (cppsetup(filename, exp, filep, file_red))
00319            return(IFFALSE);
00320        else
00321            return(IF);
00322 }
00323 
00324 void
00325 define2(char *name, char *val, struct inclist *file)
00326 {
00327     int first, last, below;
00328     register struct symtab **sp = NULL, **dest;
00329     struct symtab *stab;
00330 
00331     /* Make space if it's needed */
00332     if (file->i_defs == NULL)
00333     {
00334        file->i_defs = (struct symtab **)
00335                      malloc(sizeof (struct symtab*) * SYMTABINC);
00336        file->i_ndefs = 0;
00337     }
00338     else if (!(file->i_ndefs % SYMTABINC))
00339        file->i_defs = (struct symtab **)
00340                      realloc(file->i_defs,
00341                         sizeof(struct symtab*)*(file->i_ndefs+SYMTABINC));
00342 
00343     if (file->i_defs == NULL)
00344        fatalerr("malloc()/realloc() failure in insert_defn()\n");
00345 
00346     below = first = 0;
00347     last = file->i_ndefs - 1;
00348     while (last >= first)
00349     {
00350        /* Fast inline binary search */
00351        register char *s1;
00352        register char *s2;
00353        register int middle = (first + last) / 2;
00354 
00355        /* Fast inline strchr() */
00356        s1 = name;
00357        s2 = file->i_defs[middle]->s_name;
00358        while (*s1++ == *s2++)
00359            if (s2[-1] == '\0') break;
00360 
00361        /* If exact match, set sp and break */
00362        if (*--s1 == *--s2) 
00363        {
00364            sp = file->i_defs + middle;
00365            break;
00366        }
00367 
00368        /* If name > i_defs[middle] ... */
00369        if (*s1 > *s2) 
00370        {
00371            below = first;
00372            first = middle + 1;
00373        }
00374        /* else ... */
00375        else
00376        {
00377            below = last = middle - 1;
00378        }
00379     }
00380 
00381     /* Search is done.  If we found an exact match to the symbol name,
00382        just replace its s_value */
00383     if (sp != NULL)
00384     {
00385        debug(1,("redefining %s from %s to %s in file %s\n",
00386               name, (*sp)->s_value, val, file->i_file));
00387        free((*sp)->s_value);
00388        (*sp)->s_value = copy(val);
00389        return;
00390     }
00391 
00392     sp = file->i_defs + file->i_ndefs++;
00393     dest = file->i_defs + below + 1;
00394     while (sp > dest)
00395     {
00396        *sp = sp[-1];
00397        sp--;
00398     }
00399     stab = (struct symtab *) malloc(sizeof (struct symtab));
00400     if (stab == NULL)
00401        fatalerr("malloc()/realloc() failure in insert_defn()\n");
00402 
00403     debug(1,("defining %s to %s in file %s\n", name, val, file->i_file));
00404     stab->s_name = copy(name);
00405     stab->s_value = copy(val);
00406     *sp = stab;
00407 }
00408 
00409 void
00410 define(char *def, struct inclist *file)
00411 {
00412     char *val;
00413 
00414     /* Separate symbol name and its value */
00415     val = def;
00416     while (isalnum(*val) || *val == '_')
00417        val++;
00418     if (*val)
00419        *val++ = '\0';
00420     while (*val == ' ' || *val == '\t')
00421        val++;
00422 
00423     if (!*val)
00424        val = "1";
00425     define2(def, val, file);
00426 }
00427 
00428 struct symtab **
00429 slookup(char *symbol, struct inclist *file)
00430 {
00431        register int first = 0;
00432        register int last = file->i_ndefs - 1;
00433 
00434        if (file) while (last >= first)
00435        {
00436            /* Fast inline binary search */
00437            register char *s1;
00438            register char *s2;
00439            register int middle = (first + last) / 2;
00440 
00441            /* Fast inline strchr() */
00442            s1 = symbol;
00443            s2 = file->i_defs[middle]->s_name;
00444            while (*s1++ == *s2++)
00445                if (s2[-1] == '\0') break;
00446 
00447            /* If exact match, we're done */
00448            if (*--s1 == *--s2) 
00449            {
00450                return file->i_defs + middle;
00451            }
00452 
00453            /* If symbol > i_defs[middle] ... */
00454            if (*s1 > *s2) 
00455            {
00456                first = middle + 1;
00457            }
00458            /* else ... */
00459            else
00460            {
00461                last = middle - 1;
00462            }
00463        }
00464        return(NULL);
00465 }
00466 
00467 static int 
00468 merge2defines(struct inclist *file1, struct inclist *file2)
00469 {
00470        int i;
00471 
00472        if ((file1==NULL) || (file2==NULL) ||
00473            !(file2->i_flags & FINISHED))
00474               return 0;
00475 
00476        for (i=0; i < file2->i_listlen; i++)
00477               if (file2->i_merged[i]==FALSE)
00478                      return 0;
00479 
00480        {
00481               int first1 = 0;
00482               int last1 = file1->i_ndefs - 1;
00483 
00484               int first2 = 0;
00485               int last2 = file2->i_ndefs - 1;
00486 
00487                 int first=0;
00488                 struct symtab** i_defs = NULL;
00489               int deflen=file1->i_ndefs+file2->i_ndefs;
00490 
00491               debug(2,("merging %s into %s\n",
00492                      file2->i_file, file1->i_file));
00493 
00494                 if (deflen>0)
00495                 { 
00496                      /* make sure deflen % SYMTABINC == 0 is still true */
00497                      deflen += (SYMTABINC - deflen % SYMTABINC) % SYMTABINC;
00498                      i_defs=(struct symtab**)
00499                          malloc(deflen*sizeof(struct symtab*));
00500                      if (i_defs==NULL) return 0;
00501               }
00502 
00503               while ((last1 >= first1) && (last2 >= first2))
00504               {
00505                      char *s1=file1->i_defs[first1]->s_name;
00506                      char *s2=file2->i_defs[first2]->s_name;
00507 
00508                      if (strcmp(s1,s2) < 0)
00509                             i_defs[first++]=file1->i_defs[first1++];
00510                      else if (strcmp(s1,s2) > 0)
00511                             i_defs[first++]=file2->i_defs[first2++];
00512                         else /* equal */
00513                         {
00514                             i_defs[first++]=file2->i_defs[first2++];
00515                                 first1++;
00516                         }
00517               }
00518               while (last1 >= first1)
00519               {
00520                         i_defs[first++]=file1->i_defs[first1++];
00521               }
00522               while (last2 >= first2)
00523               {
00524                         i_defs[first++]=file2->i_defs[first2++];
00525               }
00526 
00527                 if (file1->i_defs) free(file1->i_defs);
00528                 file1->i_defs=i_defs;
00529                 file1->i_ndefs=first;
00530                 
00531               return 1;
00532        }
00533 }
00534 
00535 void
00536 undefine(char *symbol, struct inclist *file)
00537 {
00538        register struct symtab **ptr;
00539        struct inclist *srcfile;
00540        while ((ptr = isdefined(symbol, file, &srcfile)) != NULL)
00541        {
00542            srcfile->i_ndefs--;
00543            for (; ptr < srcfile->i_defs + srcfile->i_ndefs; ptr++)
00544               *ptr = ptr[1];
00545        }
00546 }
00547 
00548 int
00549 find_includes(struct filepointer *filep, struct inclist *file, 
00550              struct inclist *file_red, int recursion, boolean failOK)
00551 {
00552        struct inclist       *inclistp;
00553        char          **includedirsp;
00554        register char *line;
00555        register int  type;
00556        boolean recfailOK;
00557 
00558        while ((line = getnextline(filep))) {
00559               switch(type = deftype(line, filep, file_red, file, TRUE)) {
00560               case IF:
00561               doif:
00562                      type = find_includes(filep, file,
00563                             file_red, recursion+1, failOK);
00564                      while ((type == ELIF) || (type == ELIFFALSE) ||
00565                             (type == ELIFGUESSFALSE))
00566                             type = gobble(filep, file, file_red);
00567                      if (type == ELSE)
00568                             gobble(filep, file, file_red);
00569                      break;
00570               case IFFALSE:
00571               case IFGUESSFALSE:
00572                   doiffalse:
00573                      if (type == IFGUESSFALSE || type == ELIFGUESSFALSE)
00574                          recfailOK = TRUE;
00575                      else
00576                          recfailOK = failOK;
00577                      type = gobble(filep, file, file_red);
00578                      if (type == ELSE)
00579                          find_includes(filep, file,
00580                                      file_red, recursion+1, recfailOK);
00581                      else
00582                      if (type == ELIF)
00583                          goto doif;
00584                      else
00585                      if ((type == ELIFFALSE) || (type == ELIFGUESSFALSE))
00586                          goto doiffalse;
00587                      break;
00588               case IFDEF:
00589               case IFNDEF:
00590                      if ((type == IFDEF && isdefined(line, file_red, NULL))
00591                       || (type == IFNDEF && !isdefined(line, file_red, NULL))) {
00592                             debug(1,(type == IFNDEF ?
00593                                 "line %d: %s !def'd in %s via %s%s\n" : "",
00594                                 filep->f_line, line,
00595                                 file->i_file, file_red->i_file, ": doit"));
00596                             type = find_includes(filep, file,
00597                                    file_red, recursion+1, failOK);
00598                             while (type == ELIF || type == ELIFFALSE || type == ELIFGUESSFALSE)
00599                                    type = gobble(filep, file, file_red);
00600                             if (type == ELSE)
00601                                    gobble(filep, file, file_red);
00602                      }
00603                      else {
00604                             debug(1,(type == IFDEF ?
00605                                 "line %d: %s !def'd in %s via %s%s\n" : "",
00606                                 filep->f_line, line,
00607                                 file->i_file, file_red->i_file, ": gobble"));
00608                             type = gobble(filep, file, file_red);
00609                             if (type == ELSE)
00610                                    find_includes(filep, file,
00611                                           file_red, recursion+1, failOK);
00612                             else if (type == ELIF)
00613                                    goto doif;
00614                             else if (type == ELIFFALSE || type == ELIFGUESSFALSE)
00615                                    goto doiffalse;
00616                      }
00617                      break;
00618               case ELSE:
00619               case ELIFFALSE:
00620               case ELIFGUESSFALSE:
00621               case ELIF:
00622                      if (!recursion)
00623                             gobble(filep, file, file_red);
00624               case ENDIF:
00625                      if (recursion)
00626                             return(type);
00627               case DEFINE:
00628                      define(line, file);
00629                      break;
00630               case UNDEF:
00631                      if (!*line) {
00632                          warning("%s", file_red->i_file);
00633                          if (file_red != file)
00634                             warning1(" (reading %s)", file->i_file);
00635                          warning1(", line %d: incomplete undef == \"%s\"\n",
00636                             filep->f_line, line);
00637                          break;
00638                      }
00639                      undefine(line, file_red);
00640                      break;
00641               case INCLUDE:
00642               case INCLUDEDOT:
00643               case INCLUDENEXT:
00644               case INCLUDENEXTDOT:
00645                      inclistp = inclistnext;
00646                      includedirsp = includedirsnext;
00647                      debug(2,("%s, reading %s, includes %s\n",
00648                             file_red->i_file, file->i_file, line));
00649                      add_include(filep, file, file_red, line, type, failOK);
00650                      inclistnext = inclistp;
00651                      includedirsnext = includedirsp;
00652                      break;
00653               case ERROR:
00654               case WARNING:
00655                      warning("%s", file_red->i_file);
00656                      if (file_red != file)
00657                             warning1(" (reading %s)", file->i_file);
00658                      warning1(", line %d: %s\n",
00659                              filep->f_line, line);
00660                      break;
00661                   
00662               case PRAGMA:
00663               case IDENT:
00664               case SCCS:
00665               case EJECT:
00666                      break;
00667               case -1:
00668                      warning("%s", file_red->i_file);
00669                      if (file_red != file)
00670                          warning1(" (reading %s)", file->i_file);
00671                      warning1(", line %d: unknown directive == \"%s\"\n",
00672                              filep->f_line, line);
00673                      break;
00674               case -2:
00675                      warning("%s", file_red->i_file);
00676                      if (file_red != file)
00677                          warning1(" (reading %s)", file->i_file);
00678                      warning1(", line %d: incomplete include == \"%s\"\n",
00679                              filep->f_line, line);
00680                      break;
00681               }
00682        }
00683        file->i_flags |= FINISHED;
00684        debug(2,("finished with %s\n", file->i_file));
00685        return(-1);
00686 }