"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:
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 }