"Fossies" - the Fresh Open Source Software Archive

Member "schily-2021-09-18/smake/readfile.c" (5 Sep 2021, 11319 Bytes) of package /linux/privat/schily-2021-09-18.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* @(#)readfile.c   1.68 21/09/05 Copyright 1985-2021 J. Schilling */
    2 #include <schily/mconfig.h>
    3 #ifndef lint
    4 static  UConst char sccsid[] =
    5     "@(#)readfile.c 1.68 21/09/05 Copyright 1985-2021 J. Schilling";
    6 #endif
    7 /*
    8  *  Make program
    9  *  File/string reading routines
   10  *
   11  *  Copyright (c) 1985-2021 by J. Schilling
   12  */
   13 /*
   14  * The contents of this file are subject to the terms of the
   15  * Common Development and Distribution License, Version 1.0 only
   16  * (the "License").  You may not use this file except in compliance
   17  * with the License.
   18  *
   19  * See the file CDDL.Schily.txt in this distribution for details.
   20  * A copy of the CDDL is also available via the Internet at
   21  * http://www.opensource.org/licenses/cddl1.txt
   22  *
   23  * When distributing Covered Code, include this CDDL HEADER in each
   24  * file and include the License file CDDL.Schily.txt from this distribution.
   25  */
   26 
   27 #include <schily/stdio.h>
   28 #include <schily/types.h>
   29 #include <schily/standard.h>
   30 #include <schily/stdlib.h>
   31 #include <schily/string.h>
   32 #include <schily/schily.h>
   33 #include <schily/ctype.h>
   34 #include "make.h"
   35 
   36 LOCAL   int fillrdbuf   __PR((void));
   37 EXPORT  char    *peekrdbuf  __PR((void));
   38 EXPORT  char    *getrdbuf   __PR((void));
   39 EXPORT  int getrdbufsize    __PR((void));
   40 EXPORT  void    setincmd    __PR((BOOL isincmd));
   41 EXPORT  void    getch       __PR((void));
   42 EXPORT  int peekch      __PR((void));
   43 EXPORT  void    skipline    __PR((void));
   44 EXPORT  void    readstring  __PR((char *str, char *strname));
   45 EXPORT  void    readfile    __PR((char *name, BOOL must_exist));
   46 EXPORT  void    doinclude   __PR((char *name, BOOL must_exist));
   47 EXPORT  void    makeincs    __PR((void));
   48 
   49 #if defined(unix) || defined(IS_UNIX)
   50 #   define  RDBUF_SIZE  1024
   51 #else
   52 #   define  RDBUF_SIZE  512
   53 #endif
   54 
   55 /*
   56  * Several variables needed for reading with look ahead
   57  * to allow easy parsing of make files.
   58  */
   59 EXPORT  int lastc       = 0;        /* last input character     */
   60 EXPORT  int firstc      = 0;        /* first character in line  */
   61 LOCAL   FILE    *mfp        = (FILE *)NULL; /* currently open make file */
   62 EXPORT  char    *mfname     = NULL;     /* name of current make file */
   63 LOCAL   int olineno     = 1;        /* old line number (include) */
   64 EXPORT  int lineno      = 1;        /* current line number      */
   65 EXPORT  int col     = 0;        /* current column       */
   66 LOCAL   BOOL    incmd       = FALSE;    /* cmd list line starts \n\t */
   67 LOCAL   char    *readbfp;           /* current read buf pointer  */
   68 LOCAL   char    *readbfstart;           /* start of current read buf */
   69 LOCAL   char    *readbfend;         /* end of current read buf  */
   70 LOCAL   char    rdbuf[RDBUF_SIZE];      /* the real read buffer     */
   71 LOCAL   char    *rd_buffer  = rdbuf;    /* a pointer to start of buf */
   72 
   73 #define UC  (unsigned char)
   74 /*
   75  * Get or peek a character from current Makefile.
   76  */
   77 #define mygetc()    ((readbfp >= readbfend) ? fillrdbuf() : UC *readbfp++)
   78 #define mypeekc()   ((readbfp >= readbfend) ? (fillrdbuf() == EOF ? \
   79                         EOF : UC *--readbfp) : UC *readbfp)
   80 #define myungetc(c) (*(--readbfp) = c)
   81 
   82 /*
   83  * Fill or refill the read buffer that is used by the mygetc() CPP macro.
   84  */
   85 LOCAL int
   86 fillrdbuf()
   87 {
   88     ssize_t ret;
   89 
   90     if (mfp == (FILE *) NULL)   /* EOF while reading from a string. */
   91         return (EOF);
   92     readbfp = rd_buffer;
   93     readbfstart = rd_buffer;    /* used for better error reporting */
   94     ret = fileread(mfp, rd_buffer, RDBUF_SIZE);
   95     if (ret < 0)
   96         comerr("Read error on '%s'.\n", mfname);
   97     readbfend = rd_buffer + ret;
   98     if (readbfp >= readbfend)
   99         return (EOF);
  100     return ((int) UC *readbfp++);
  101 }
  102 
  103 EXPORT BOOL
  104 istext(c)
  105     int c;
  106 {
  107     return (isalnum(c) || c == SLASH);
  108 }
  109 
  110 /*
  111  * Copy easy characters to speed up parsing by avoiding to call getch()
  112  */
  113 EXPORT char *
  114 gtext(s)
  115     char    *s;
  116 {
  117     register int    c = 0;      /* keep stupid gcc happy */
  118     register char   *p = readbfp;
  119 
  120     while (p < readbfend) {
  121         c = (int) UC *p++;
  122         /*
  123          * We support easy to detect chars that are very probable
  124          * with the usual names.
  125          */
  126         if (!isalnum(c) && c != SLASH && c != '-' && c != '.') {
  127             --p;
  128             break;
  129         }
  130         if (s >= gbufend)
  131             s = growgbuf(s);
  132         *s++ = c;
  133     }
  134     if (p != readbfp) {
  135         lastc = c;
  136         readbfp = p;
  137     }
  138     return (s);
  139 }
  140 
  141 EXPORT char *
  142 peekrdbuf()
  143 {
  144     return (readbfp);
  145 }
  146 
  147 EXPORT char *
  148 getrdbuf()
  149 {
  150     return (readbfstart);
  151 }
  152 
  153 EXPORT int
  154 getrdbufsize()
  155 {
  156     return (readbfend - readbfstart);
  157 }
  158 
  159 /*
  160  * Switch the behaviour of the reader for parsing commandlines/others.
  161  */
  162 EXPORT void
  163 setincmd(isincmd)
  164     BOOL    isincmd;
  165 {
  166     incmd = isincmd ? TRUE:FALSE;
  167 }
  168 
  169 /*
  170  * Get a character.
  171  * Handle backslash-newline combinations and special conditions
  172  * for comment and command lines.
  173  * Count lines for error messages.
  174  */
  175 EXPORT void
  176 getch()
  177 {
  178     col++;
  179     lastc = mygetc();
  180     if (lastc == EOF)
  181         return;
  182     if (lastc == '\n') {
  183         firstc = mypeekc();
  184         lineno++;
  185         col = 0;
  186         return;
  187     } else if (lastc == '\\' && !incmd && mypeekc() == '\n') {
  188         lastc = mygetc();
  189         firstc = mypeekc();
  190         lineno++;
  191         col = 0;
  192         for (;;) {      /* Skip white space at start of line */
  193             register int    c;
  194 
  195             c = mypeekc();
  196             if (c != ' ' && c != '\t') {
  197                 lastc = ' ';
  198                 return;
  199             }
  200             mygetc();
  201             col++;
  202         }
  203     }
  204 
  205     if (lastc == '#' && !incmd) {
  206         if (mfp == (FILE *) NULL)   /* Do not skip past # when */
  207             return;         /* reading from string.    */
  208         skipline();
  209     }
  210 }
  211 
  212 EXPORT int
  213 peekch()
  214 {
  215     return (mypeekc());
  216 }
  217 
  218 /*
  219  * Unget a character.
  220  */
  221 EXPORT void
  222 ungetch(c)
  223     int c;
  224 {
  225     myungetc(c);
  226 }
  227 
  228 /*
  229  * Fast method to skip to the end of a commented out line.
  230  * Always use the POSIX method (skip to next un-escaped new line).
  231  */
  232 EXPORT void
  233 skipline()
  234 {
  235     register int    c = lastc;
  236 
  237     if (c == '\n')
  238         return;
  239 
  240     while (c != EOF) {
  241         c = mygetc();
  242         if (c == '\n') {
  243             lineno++;
  244             col = 0;
  245             lastc = c;
  246             firstc = mypeekc();
  247             return;
  248         } else if (c == '\\' && mypeekc() == '\n') {
  249             lineno++;
  250             col = 0;
  251             c = mygetc();
  252         }
  253     }
  254     firstc = lastc = c;
  255 }
  256 
  257 /*
  258  * Parse input from a string.
  259  */
  260 EXPORT void
  261 readstring(str, strname)
  262     char    *str;
  263     char    *strname;
  264 {
  265     mfname = strname;
  266     readbfp = str;
  267     readbfstart = str;  /* used for better error reporting */
  268     readbfend = str + strlen(str);
  269     firstc = *str;
  270     incmd = FALSE;
  271     parsefile();
  272     mfname = NULL;
  273 }
  274 
  275 /*
  276  * Parse input from the current Makefile.
  277  */
  278 EXPORT void
  279 readfile(name, must_exist)
  280     char    *name;
  281     BOOL    must_exist;
  282 {
  283     /*
  284      * Diese Meldung ist noch falsch (Rekursion/Makefiles)
  285      */
  286     if (Do_Warn)
  287         error("Reading file '%s' in line %d of '%s'\n", name,
  288             olineno, mfname);
  289 
  290     if (streql(name, "-")) {
  291         mfp = stdin;
  292         name = "Standard in";
  293     } else {
  294         if ((mfp = fileopen(name, "ru")) == (FILE *)NULL && must_exist)
  295             comerr("Can not open '%s'.\n", name);
  296     }
  297     file_raise(mfp, FALSE);
  298     mfname = name;
  299     readbfp = readbfend;        /* Force immediate call of fillrdbuf.*/
  300     firstc = mypeekc();
  301     incmd = FALSE;
  302     if (mfp) {
  303         parsefile();
  304         fclose(mfp);
  305     }
  306     mfp = (FILE *) NULL;
  307     mfname = NULL;
  308     col = 0;
  309 }
  310 
  311 list_t  *Incs;
  312 list_t  **inctail = &Incs;
  313 
  314 /*
  315  * Handle the "include" directive in makefiles.
  316  * If an include file does not exists, first try to find a rule to make it.
  317  * If this does not help, try to call include failure exception handling.
  318  * This exception handling enables some automake features of smake in allowing
  319  * the to call a shell script that will create the missing (may be architecture
  320  * dependant) include file on the fly with something that will at least allow
  321  * smake to continue on this platform.
  322  */
  323 EXPORT void
  324 doinclude(name, must_exist)
  325     char    *name;
  326     BOOL    must_exist;
  327 {
  328     int slc = lastc;
  329     int sfc = firstc;
  330     FILE    *smf = mfp;
  331     char    *smfn = mfname;
  332     int slineno = lineno;
  333     int scol = col;
  334     char    *srbp = readbfp;
  335     char    *srbs = readbfstart;
  336     char    *srbe = readbfend;
  337     char    *srbf = rd_buffer;
  338     char    include_buf[RDBUF_SIZE];
  339     obj_t   *st = default_tgt;
  340     obj_t   *o;
  341     list_t  *lp;
  342 
  343     olineno = lineno-1;
  344     lastc   = 0;
  345     firstc  = 0;
  346     lineno  = 1;
  347     col = 0;
  348     rd_buffer = include_buf;
  349 
  350     setup_dotvars();
  351     name = substitute(name, NullObj, 0, 0);
  352     name = strsave(name);
  353 
  354     /*
  355      * Try to make "name". Do not fail if this does not succeed.
  356      * We just decide on how to continue based on o->o_date is != 0.
  357      * If o->o_date == and must_exist == TRUE, we trigger the
  358      * .INCLUDE_FAILED: action.
  359      */
  360     xmake(name, FALSE);
  361     default_tgt = st;
  362 
  363     o = objlook(name, TRUE);
  364 
  365     /*
  366      * In order to work around a gmake bug, we need to write Makefiles that
  367      * make an included file to depend on a previously included file in
  368      * order to make gmake believe that a rule exists to make the included
  369      * file. This is otherwise nonsense but it is in conflict with our
  370      * strategy to reset o->o_date after the file has been included in
  371      * order to force to re-evaluate the complete set of rules after
  372      * everything has been read. In this special case, it looks as if the
  373      * file could not be made as it depends on a "nonexistent" target.
  374      * A solution is to fetch the time again before we decide how to go on.
  375      */
  376     if (o->o_date == 0) {
  377         o->o_date = gftime(name);   /* Check if file is present */
  378     }
  379 
  380     if (Debug > 1)
  381         error("doinclude(%s, %d)= date: %s level: %d\n",
  382             name, must_exist, prtime(o->o_date), o->o_level);
  383 
  384     /*
  385      * "name" does not exist and could not be made.
  386      * If must_exist == TRUE, trigger the .INCLUDE_FAILED: action.
  387      */
  388     if (must_exist && o->o_date == 0 && IncludeFailed) {
  389         list_t  l;
  390 
  391         o->o_date = newtime;        /* Force to be out of date  */
  392         l.l_next = (list_t *)0;     /* Only one element:        */
  393         l.l_obj = o;            /* The file to be included  */
  394         IncludeFailed->o_list = &l; /* Make it $^           */
  395         IncludeFailed->o_date = (date_t)0;
  396         omake(IncludeFailed, FALSE);    /* Try to apply rules       */
  397         o->o_date = gftime(name);   /* Check if file is present */
  398     }
  399 
  400     /*
  401      * If "name" exists or could be made by a specific rule or the
  402      * fall back rule .INCLUDE_FAILED:, parse the content of the file
  403      * to be included.
  404      */
  405     if (must_exist || o->o_date != 0) {
  406         char    includename[TYPICAL_NAMEMAX];
  407         char    *iname;
  408 
  409         if (Prdep)
  410             error("Reading file '%s' from '%s'\n", name, mfname);
  411 
  412         /*
  413          * Now add this object to the list of objects that must be
  414          * remade to force integrity of our lists before we start
  415          * to make the real targets.
  416          */
  417         lp = (list_t *) fastalloc(sizeof (*lp));
  418         lp->l_obj = o;
  419         *inctail = lp;
  420         inctail = &lp->l_next;
  421         lp->l_next = 0;
  422 
  423         /*
  424          * The code in update.c needs to make sure that o->o_level has
  425          * the right value tp create the right name for include.
  426          */
  427         iname = build_path(o->o_level, o->o_name, o->o_namelen,
  428                     includename, sizeof (includename));
  429 /*error("include '%s' -> '%s' %s\n", o->o_name, iname, prtime(o->o_date));*/
  430         if (iname != NULL) {
  431             readfile(iname, must_exist);
  432             if (iname != o->o_name && iname != includename)
  433                 free(iname);
  434         } else {
  435             comerrno(EX_BAD,
  436                 "Cannot build path for 'include %s'.\n",
  437                 o->o_name);
  438         }
  439         /*
  440          * Zurücksetzen des Datums bewirkt Neuauswertung
  441          * der Abhängigkeitsliste.
  442          * XXX Das kann Probleme bei make depend geben.
  443          */
  444         o->o_date = 0;
  445     }
  446 
  447     lastc = slc;
  448     firstc = sfc;
  449     mfp = smf;
  450     mfname = smfn;
  451     lineno = slineno;
  452     col = scol;
  453     readbfp = srbp;
  454     readbfstart = srbs;
  455     readbfend = srbe;
  456     rd_buffer = srbf;
  457 }
  458 
  459 /*
  460  * Re-make the included files.
  461  * This must be done because after they have been made the first time,
  462  * the dependency list may have changed. If we don't remake the included
  463  * files, the xxx.d dependency files will not be remade after we touch a file
  464  * that is not in the primary source list.
  465  */
  466 EXPORT void
  467 makeincs()
  468 {
  469     list_t  *l;
  470 
  471     for (l = Incs; l != 0; l = l->l_next) {
  472 /*      printf("inc(%s)\n", l->l_obj->o_name);*/
  473         omake(l->l_obj, TRUE);
  474     }
  475 }