Deleted Added
sdiff udiff text old ( 144787 ) new ( 144894 )
full compact
1/*-
2 * Copyright (c) 1988, 1989, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 1989 by Berkeley Softworks
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor.

--- 25 unchanged lines hidden (view full) ---

34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)parse.c 8.3 (Berkeley) 3/19/94
39 */
40
41#include <sys/cdefs.h>
42__FBSDID("$FreeBSD: head/usr.bin/make/parse.c 144894 2005-04-11 07:20:10Z harti $");
43
44/*-
45 * parse.c --
46 * Functions to parse a makefile.
47 *
48 * One function, Parse_Init, must be called before any functions
49 * in this module are used. After that, the function Parse_File is the
50 * main entry point and controls most of the other functions in this

--- 186 unchanged lines hidden (view full) ---

237 { ".SHELL", ExShell, 0 },
238 { ".SILENT", Silent, OP_SILENT },
239 { ".SINGLESHELL", SingleShell, 0 },
240 { ".SUFFIXES", Suffixes, 0 },
241 { ".USE", Attribute, OP_USE },
242 { ".WAIT", Wait, 0 },
243};
244
245/*
246 * Directive table. We use a hash table. This hash table has been generated
247 * with mph which can be found on the usual GNU mirrors. If you change the
248 * directives (adding, deleting, reordering) you need to create a new table
249 * and hash function (directive_hash). The command line to generate the
250 * table is:
251 *
252 * mph -d2 -m1 <tab | emitc -l -s
253 *
254 * Where tab is a file containing just the directive strings, one per line.
255 *
256 * While inporting the result of this the following changes have been made
257 * to the generated code:
258 *
259 * prefix the names of the g, T0 and T1 arrays with 'directive_'.
260 *
261 * make the type of the tables 'const [un]signed char'.
262 *
263 * make the hash function use the length for termination,
264 * not the trailing '\0'.
265 */
266static void parse_include(char *, int, int);
267static void parse_message(char *, int, int);
268static void parse_undef(char *, int, int);
269static void parse_for(char *, int, int);
270static void parse_endfor(char *, int, int);
271
272static const signed char directive_g[] = {
273 16, 0, -1, 14, 5, 2, 2, -1, 0, 0,
274 -1, -1, 16, 11, -1, 15, -1, 14, 7, -1,
275 8, 6, 1, -1, -1, 0, 4, 6, -1, 0,
276 0, 2, 0, 13, -1, 14, -1, 0,
277};
278
279static const unsigned char directive_T0[] = {
280 11, 25, 14, 30, 14, 26, 23, 15, 9, 37,
281 27, 32, 27, 1, 17, 27, 35, 13, 8, 22,
282 8, 28, 7,
283};
284
285static const unsigned char directive_T1[] = {
286 19, 20, 31, 17, 29, 2, 7, 12, 1, 31,
287 11, 18, 11, 20, 10, 2, 15, 19, 4, 10,
288 13, 36, 3,
289};
290
291static const struct directive {
292 const char *name;
293 int code;
294 Boolean skip_flag; /* execute even when skipped */
295 void (*func)(char *, int, int);
296} directives[] = {
297 { "elif", COND_ELIF, TRUE, Cond_If },
298 { "elifdef", COND_ELIFDEF, TRUE, Cond_If },
299 { "elifmake", COND_ELIFMAKE, TRUE, Cond_If },
300 { "elifndef", COND_ELIFNDEF, TRUE, Cond_If },
301 { "elifnmake", COND_ELIFNMAKE, TRUE, Cond_If },
302 { "else", COND_ELSE, TRUE, Cond_Else },
303 { "endfor", 0, FALSE, parse_endfor },
304 { "endif", COND_ENDIF, TRUE, Cond_Endif },
305 { "error", 1, FALSE, parse_message },
306 { "for", 0, FALSE, parse_for },
307 { "if", COND_IF, TRUE, Cond_If },
308 { "ifdef", COND_IFDEF, TRUE, Cond_If },
309 { "ifmake", COND_IFMAKE, TRUE, Cond_If },
310 { "ifndef", COND_IFNDEF, TRUE, Cond_If },
311 { "ifnmake", COND_IFNMAKE, TRUE, Cond_If },
312 { "include", 0, FALSE, parse_include },
313 { "undef", 0, FALSE, parse_undef },
314 { "warning", 0, FALSE, parse_message },
315};
316#define NDIRECTS (sizeof(directives) / sizeof(directives[0]))
317
318/*-
319 *----------------------------------------------------------------------
320 * ParseFindKeyword --
321 * Look in the table of keywords for one matching the given string.
322 *
323 * Results:
324 * The index of the keyword, or -1 if it isn't there.
325 *

--- 1293 unchanged lines hidden (view full) ---

1619 */
1620void
1621Parse_AddIncludeDir(char *dir)
1622{
1623
1624 Path_AddDir(&parseIncPath, dir);
1625}
1626
1627/*-
1628 *---------------------------------------------------------------------
1629 * Parse_FromString --
1630 * Start Parsing from the given string
1631 *
1632 * Results:
1633 * None
1634 *
1635 * Side Effects:
1636 * A structure is added to the includes Lst and readProc, curFile.lineno,

--- 26 unchanged lines hidden (view full) ---

1663 * curFile.fname and curFile.F are altered for the new file
1664 *---------------------------------------------------------------------
1665 */
1666static void
1667ParseTraditionalInclude(char *file)
1668{
1669 char *fullname; /* full pathname of file */
1670 char *cp; /* current position in file spec */
1671
1672 /*
1673 * Skip over whitespace
1674 */
1675 while (*file == ' ' || *file == '\t') {
1676 file++;
1677 }
1678

--- 10 unchanged lines hidden (view full) ---

1689 }
1690
1691 *cp = '\0';
1692
1693 /*
1694 * Substitute for any variables in the file name before trying to
1695 * find the thing.
1696 */
1697 file = Buf_Peel(Var_Subst(NULL, file, VAR_CMD, FALSE));
1698
1699 /*
1700 * Now we know the file's name, we attempt to find the durn thing.
1701 * Search for it first on the -I search path, then on the .PATH
1702 * search path, if not found in a -I directory.
1703 */
1704 fullname = Path_FindFile(file, &parseIncPath);
1705 if (fullname == NULL) {

--- 395 unchanged lines hidden (view full) ---

2101 if (((const GNode *)Lst_Datum(ln))->type & OP_TRANSFORM)
2102 Suff_EndTransform(Lst_Datum(ln));
2103 }
2104 Lst_Destroy(&targets, ParseHasCommands);
2105 inLine = FALSE;
2106 }
2107}
2108
2109/**
2110 * parse_include
2111 * Parse an .include directive and push the file onto the input stack.
2112 * The input is the line minus the .include. A file spec is a string
2113 * enclosed in <> or "". The former is looked for only in sysIncPath.
2114 * The latter in . and the directories specified by -I command line
2115 * options
2116 */
2117static void
2118parse_include(char *file, int code __unused, int lineno __unused)
2119{
2120 char *fullname; /* full pathname of file */
2121 char endc; /* the character which ends the file spec */
2122 char *cp; /* current position in file spec */
2123 Boolean isSystem; /* TRUE if makefile is a system makefile */
2124 char *prefEnd, *Fname;
2125 char *newName;
2126
2127 /*
2128 * Skip to delimiter character so we know where to look
2129 */
2130 while (*file == ' ' || *file == '\t') {
2131 file++;
2132 }
2133
2134 if (*file != '"' && *file != '<') {
2135 Parse_Error(PARSE_FATAL,
2136 ".include filename must be delimited by '\"' or '<'");
2137 return;
2138 }
2139
2140 /*
2141 * Set the search path on which to find the include file based on the
2142 * characters which bracket its name. Angle-brackets imply it's
2143 * a system Makefile while double-quotes imply it's a user makefile
2144 */
2145 if (*file == '<') {
2146 isSystem = TRUE;
2147 endc = '>';
2148 } else {
2149 isSystem = FALSE;
2150 endc = '"';
2151 }
2152
2153 /*
2154 * Skip to matching delimiter
2155 */
2156 for (cp = ++file; *cp != endc; cp++) {
2157 if (*cp == '\0') {
2158 Parse_Error(PARSE_FATAL,
2159 "Unclosed .include filename. '%c' expected", endc);
2160 return;
2161 }
2162 }
2163 *cp = '\0';
2164
2165 /*
2166 * Substitute for any variables in the file name before trying to
2167 * find the thing.
2168 */
2169 file = Buf_Peel(Var_Subst(NULL, file, VAR_CMD, FALSE));
2170
2171 /*
2172 * Now we know the file's name and its search path, we attempt to
2173 * find the durn thing. A return of NULL indicates the file don't
2174 * exist.
2175 */
2176 if (!isSystem) {
2177 /*
2178 * Include files contained in double-quotes are first searched
2179 * for relative to the including file's location. We don't want
2180 * to cd there, of course, so we just tack on the old file's
2181 * leading path components and call Dir_FindFile to see if
2182 * we can locate the beast.
2183 */
2184
2185 /* Make a temporary copy of this, to be safe. */
2186 Fname = estrdup(CURFILE->fname);
2187
2188 prefEnd = strrchr(Fname, '/');
2189 if (prefEnd != NULL) {
2190 *prefEnd = '\0';
2191 if (file[0] == '/')
2192 newName = estrdup(file);
2193 else
2194 newName = str_concat(Fname, file, STR_ADDSLASH);
2195 fullname = Path_FindFile(newName, &parseIncPath);
2196 if (fullname == NULL) {
2197 fullname = Path_FindFile(newName,
2198 &dirSearchPath);
2199 }
2200 free(newName);
2201 *prefEnd = '/';
2202 } else {
2203 fullname = NULL;
2204 }
2205 free(Fname);
2206 } else {
2207 fullname = NULL;
2208 }
2209
2210 if (fullname == NULL) {
2211 /*
2212 * System makefile or makefile wasn't found in same directory as
2213 * included makefile. Search for it first on the -I search path,
2214 * then on the .PATH search path, if not found in a -I
2215 * directory.
2216 * XXX: Suffix specific?
2217 */
2218 fullname = Path_FindFile(file, &parseIncPath);
2219 if (fullname == NULL) {
2220 fullname = Path_FindFile(file, &dirSearchPath);
2221 }
2222 }
2223
2224 if (fullname == NULL) {
2225 /*
2226 * Still haven't found the makefile. Look for it on the system
2227 * path as a last resort.
2228 */
2229 fullname = Path_FindFile(file, &sysIncPath);
2230 }
2231
2232 if (fullname == NULL) {
2233 *cp = endc;
2234 Parse_Error(PARSE_FATAL, "Could not find %s", file);
2235 free(file);
2236 return;
2237 }
2238 free(file);
2239
2240 /*
2241 * We set up the name of the file to be the absolute
2242 * name of the include file so error messages refer to the right
2243 * place.
2244 */
2245 ParsePushInput(fullname, NULL, NULL, 0);
2246}
2247
2248/**
2249 * parse_message
2250 * Parse a .warning or .error directive
2251 *
2252 * The input is the line minus the ".error"/".warning". We substitute
2253 * variables, print the message and exit(1) (for .error) or just print
2254 * a warning if the directive is malformed.
2255 */
2256static void
2257parse_message(char *line, int iserror, int lineno __unused)
2258{
2259
2260 if (!isspace((u_char)*line)) {
2261 Parse_Error(PARSE_WARNING, "invalid syntax: .%s%s",
2262 iserror ? "error" : "warning", line);
2263 return;
2264 }
2265
2266 while (isspace((u_char)*line))
2267 line++;
2268
2269 line = Buf_Peel(Var_Subst(NULL, line, VAR_GLOBAL, FALSE));
2270 Parse_Error(iserror ? PARSE_FATAL : PARSE_WARNING, "%s", line);
2271 free(line);
2272
2273 if (iserror) {
2274 /* Terminate immediately. */
2275 exit(1);
2276 }
2277}
2278
2279/**
2280 * parse_undef
2281 * Parse an .undef directive.
2282 */
2283static void
2284parse_undef(char *line, int code __unused, int lineno __unused)
2285{
2286 char *cp;
2287
2288 while (isspace((u_char)*line))
2289 line++;
2290
2291 for (cp = line; !isspace((u_char)*cp) && *cp != '\0'; cp++) {
2292 ;
2293 }
2294 *cp = '\0';
2295
2296 cp = Buf_Peel(Var_Subst(NULL, line, VAR_CMD, FALSE));
2297 Var_Delete(cp, VAR_GLOBAL);
2298 free(cp);
2299}
2300
2301/**
2302 * parse_for
2303 * Parse a .for directive.
2304 */
2305static void
2306parse_for(char *line, int code __unused, int lineno)
2307{
2308
2309 if (!For_For(line)) {
2310 /* syntax error */
2311 return;
2312 }
2313 line = NULL;
2314
2315 /*
2316 * Skip after the matching endfor.
2317 */
2318 do {
2319 free(line);
2320 line = ParseSkipLine(0, 1);
2321 if (line == NULL) {
2322 Parse_Error(PARSE_FATAL,
2323 "Unexpected end of file in for loop.\n");
2324 return;
2325 }
2326 } while (For_Eval(line));
2327 free(line);
2328
2329 /* execute */
2330 For_Run(lineno);
2331}
2332
2333/**
2334 * parse_endfor
2335 * Parse endfor. This may only happen if there was no matching .for.
2336 */
2337static void
2338parse_endfor(char *line __unused, int code __unused, int lineno __unused)
2339{
2340
2341 Parse_Error(PARSE_FATAL, "for-less endfor");
2342}
2343
2344/**
2345 * directive_hash
2346 */
2347static int
2348directive_hash(const u_char *key, size_t len)
2349{
2350 unsigned f0, f1;
2351 const u_char *kp = key;
2352
2353 if (len < 2 || len > 9)
2354 return (-1);
2355
2356 for (f0 = f1 = 0; kp < key + len; ++kp) {
2357 if (*kp < 97 || *kp > 119)
2358 return (-1);
2359 f0 += directive_T0[-97 + *kp];
2360 f1 += directive_T1[-97 + *kp];
2361 }
2362
2363 f0 %= 38;
2364 f1 %= 38;
2365
2366 return (directive_g[f0] + directive_g[f1]) % 18;
2367}
2368
2369/**
2370 * parse_directive
2371 * Got a line starting with a '.'. Check if this is a directive
2372 * and parse it.
2373 *
2374 * return:
2375 * TRUE if line was a directive, FALSE otherwise.
2376 */
2377static Boolean
2378parse_directive(char *line)
2379{
2380 char *start;
2381 char *cp;
2382 int dir;
2383
2384 /*
2385 * Get the keyword:
2386 * .[[:space:]]*\([[:alpha:]][[:alnum:]_]*\).*
2387 * \1 is the keyword.
2388 */
2389 for (start = line; isspace((u_char)*start); start++) {
2390 ;
2391 }
2392
2393 if (!isalpha((u_char)*start)) {
2394 return (FALSE);
2395 }
2396
2397 cp = start + 1;
2398 while (isalnum((u_char)*cp) || *cp == '_') {
2399 cp++;
2400 }
2401
2402 dir = directive_hash(start, cp - start);
2403 if (dir < 0 || dir >= (int)NDIRECTS ||
2404 (size_t)(cp - start) != strlen(directives[dir].name) ||
2405 strncmp(start, directives[dir].name, cp - start) != 0) {
2406 /* not actually matched */
2407 return (FALSE);
2408 }
2409
2410 if (!skipLine || directives[dir].skip_flag)
2411 (*directives[dir].func)(cp, directives[dir].code,
2412 CURFILE->lineno);
2413 return (TRUE);
2414}
2415
2416/*-
2417 *---------------------------------------------------------------------
2418 * Parse_File --
2419 * Parse a file into its component parts, incorporating it into the
2420 * current dependency graph. This is the main function and controls
2421 * almost every other function in this module
2422 *
2423 * Results:

--- 4 unchanged lines hidden (view full) ---

2428 * are added to the dependency graph. etc. etc. etc.
2429 *---------------------------------------------------------------------
2430 */
2431void
2432Parse_File(const char *name, FILE *stream)
2433{
2434 char *cp; /* pointer into the line */
2435 char *line; /* the line we're working on */
2436
2437 inLine = FALSE;
2438 fatals = 0;
2439
2440 ParsePushInput(estrdup(name), stream, NULL, 0);
2441
2442 while ((line = ParseReadLine()) != NULL) {
2443 if (*line == '.' && parse_directive(line + 1)) {
2444 /* directive consumed */
2445 goto nextLine;
2446 }
2447 if (skipLine || *line == '#') {
2448 /* Skipping .if block or comment. */
2449 goto nextLine;
2450 }
2451
2452 if (*line == '\t') {
2453 /*
2454 * If a line starts with a tab, it can only
2455 * hope to be a creation command.
2456 */

--- 55 unchanged lines hidden (view full) ---

2512 * being parsed. Tell the variable module to
2513 * complain if some variable is undefined...
2514 * To make life easier on novices, if the line
2515 * is indented we first make sure the line has
2516 * a dependency operator in it. If it doesn't
2517 * have an operator and we're in a dependency
2518 * line's script, we assume it's actually a
2519 * shell command and add it to the current
2520 * list of targets. XXX this comment seems wrong.
2521 */
2522 cp = line;
2523 if (isspace((unsigned char)line[0])) {
2524 while (*cp != '\0' &&
2525 isspace((unsigned char)*cp)) {
2526 cp++;
2527 }
2528 if (*cp == '\0') {
2529 goto nextLine;
2530 }
2531 }
2532
2533 ParseFinishLine();
2534
2535 cp = Buf_Peel(Var_Subst(NULL, line, VAR_CMD, TRUE));
2536
2537 free(line);
2538 line = cp;
2539
2540 /*
2541 * Need a non-circular list for the target nodes
2542 */
2543 Lst_Destroy(&targets, NOFREE);

--- 13 unchanged lines hidden (view full) ---

2557 */
2558 Cond_End();
2559
2560 if (fatals)
2561 errx(1, "fatal errors encountered -- cannot continue");
2562}
2563
2564/*-
2565 *-----------------------------------------------------------------------
2566 * Parse_MainName --
2567 * Return a Lst of the main target to create for main()'s sake. If
2568 * no such target exists, we Punt with an obnoxious error message.
2569 *
2570 * Results:
2571 * A Lst of the single node to create.
2572 *

--- 18 unchanged lines hidden ---