Changeset 3316 in kBuild for trunk/src/kmk/incdep.c
- Timestamp:
- Mar 31, 2020 1:13:22 AM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/incdep.c
r3230 r3316 1233 1233 } 1234 1234 1235 /* Counts slashes backwards from SLASH, stopping at START. */ 1236 static size_t incdep_count_slashes_backwards(const char *slash, const char *start) 1237 { 1238 size_t slashes = 1; 1239 assert (*slash == '\\'); 1240 while ((uintptr_t)slash > (uintptr_t)start && slash[0 - slashes] == '\\') 1241 slashes++; 1242 return slashes; 1243 } 1244 1245 /* Whitespace cannot be escaped at the end of a line, there has to be 1246 some stuff following it other than a line continuation slash. 1247 1248 So, we look ahead and makes sure that there is something non-whitespaced 1249 following this allegedly escaped whitespace. 1250 1251 This code ASSUMES the file content is zero terminated! */ 1252 static int incdep_verify_escaped_whitespace(const char *ws) 1253 { 1254 char ch; 1255 1256 assert(ws[-1] == '\\'); 1257 assert(ISBLANK((unsigned int)ws[0])); 1258 1259 /* If the character following the '\ ' sequence is not a whitespace, 1260 another escape character or null terminator, we're good. */ 1261 ws += 2; 1262 ch = *ws; 1263 if (ch != '\\' && !ISSPACE((unsigned int)ch) && ch != '\0') 1264 return 1; 1265 1266 /* Otherwise we'll have to parse forward till we hit the end of the 1267 line/file or something. */ 1268 while ((ch = *ws++) != '\0') 1269 { 1270 if (ch == '\\') 1271 { 1272 /* escaped newline? */ 1273 ch = *ws; 1274 if (ch == '\n') 1275 ws++; 1276 else if (ch == '\r' && ws[1] == '\n') 1277 ws += 2; 1278 else 1279 return 1; 1280 } 1281 else if (ISBLANK((unsigned int)ch)) 1282 { /* contine */ } 1283 else if (!ISSPACE((unsigned int)ch)) 1284 return 1; 1285 else 1286 return 0; /* newline; all trailing whitespace will be ignored. */ 1287 } 1288 1289 return 0; 1290 } 1291 1292 /* Unescapes the next filename and returns cached copy. 1293 1294 Modifies the input string that START points to. 1295 1296 When NEXTP is not NULL, ASSUME target filename and that END isn't entirely 1297 accurate in case the filename ends with a trailing backslash. There can be 1298 more than one filename in a this case. NEXTP will be set to the first 1299 character after then filename. 1300 1301 When NEXTP is NULL, ASSUME exactly one dependency filename and that END is 1302 accurately deliminating the string. 1303 */ 1304 static const char * 1305 incdep_unescape_and_cache_filename(struct incdep *curdep, 1306 char *start, const char *end, const char **nextp) 1307 { 1308 int const is_dep = nextp == NULL; 1309 unsigned const esc_mask = MAP_BLANK /* ' ' + '\t' */ 1310 | MAP_COLON /* ':' */ 1311 | MAP_COMMENT /* '#' */ 1312 | MAP_EQUALS /* '=' */ 1313 | MAP_SEMI /* ';' */ 1314 | ( is_dep 1315 ? MAP_PIPE /* '|' */ 1316 : MAP_PERCENT); /* '%' */ 1317 unsigned const all_esc_mask = esc_mask | MAP_BLANK | MAP_NEWLINE; 1318 unsigned const stop_mask = nextp ? MAP_BLANK | MAP_NEWLINE | MAP_COLON : 0; 1319 char volatile *src; 1320 char volatile *dst; 1321 1322 /* 1323 * Skip forward to the first escaped character so we can avoid unnecessary shifting. 1324 */ 1325 #if 1 1326 src = start; 1327 dst = start; 1328 #elif 1 1329 static const char s_szStop[] = "\n\r\t "; 1330 1331 src = memchr(start, '$', end - start); 1332 dst = memchr(start, '\\', end - start); 1333 if (src && ((uintptr_t)src < (uintptr_t)dst || dst == NULL)) 1334 dst = src; 1335 else if (dst && ((uintptr_t)dst < (uintptr_t)src || src == NULL)) 1336 src = dst; 1337 else 1338 { 1339 assert(src == NULL && dst == NULL); 1340 if (nextp) 1341 { 1342 int i = sizeof(s_szStop); 1343 while (i-- > 0) 1344 { 1345 char *stop = memchr(start, s_szStop[i], end - start); 1346 if (stop) 1347 end = stop; 1348 } 1349 *nextp = end; 1350 } 1351 return incdep_dep_strcache (curdep, start, end - start); 1352 } 1353 if (nextp) 1354 { 1355 char *stop = src; 1356 int i = sizeof(s_szStop); 1357 while (i-- > 0) 1358 { 1359 char *stop2 = memchr(start, s_szStop[i], stop - start); 1360 if (stop2) 1361 stop = stop2; 1362 } 1363 if (stop != src) 1364 { 1365 *nextp = stop; 1366 return incdep_dep_strcache (curdep, start, stop - start); 1367 } 1368 } 1369 #endif 1370 1371 /* 1372 * Copy char-by-char, undoing escaping as we go along. 1373 */ 1374 while ((uintptr_t)src < (uintptr_t)end) 1375 { 1376 const char ch = *src++; 1377 if (ch != '\\' && ch != '$') 1378 { 1379 if (!STOP_SET (ch, stop_mask)) 1380 *dst++ = ch; 1381 else 1382 { 1383 src--; 1384 break; 1385 } 1386 } 1387 else 1388 { 1389 const char ch2 = *src++; /* No bounds checking to handle "/dir/file\ : ..." when end points at " :". */ 1390 if (ch == '$') 1391 { 1392 if (ch2 != '$') /* $$ -> $ - Ignores secondary expansion! */ 1393 src--; 1394 *dst++ = ch; 1395 } 1396 else 1397 { 1398 unsigned int const ch2_map = stopchar_map[(unsigned char)ch2]; 1399 if (ch2_map & all_esc_mask) 1400 { 1401 /* Count preceeding slashes, unwind half of them regardless of odd/even count. */ 1402 size_t const max_slashes = src - start - 1; 1403 size_t slashes = 1; 1404 while (slashes < max_slashes && src[-2 - slashes] == '\\') 1405 slashes++; 1406 1407 /* Non-whitespace is simple: Slash slashes, output or stop. */ 1408 if (!(ch2_map & (MAP_BLANK | MAP_NEWLINE))) 1409 { 1410 assert(ch2_map & esc_mask); 1411 dst -= slashes / 2; 1412 if ((slashes & 1) || !(stop_mask & ch2_map)) 1413 *dst++ = ch2; 1414 else 1415 { 1416 src--; 1417 break; 1418 } 1419 } 1420 /* Escaped blanks or newlines. 1421 1422 We have to pretent that we've already replaced any escaped newlines 1423 and associated whitespace with a single space here. We also have to 1424 pretend trailing whitespace doesn't exist when IS_DEP is non-zero. 1425 This makes for pretty interesting times... */ 1426 else 1427 { 1428 char ch3; 1429 1430 /* An Escaped blank is interesting because it is striped unconditionally 1431 at the end of a line, regardless of how many escaped newlines may 1432 following it. We join the escaped newline handling if we fine one 1433 following us. */ 1434 if (ch2_map & MAP_BLANK) 1435 { 1436 /* skip whitespace and check for escaped newline. */ 1437 volatile char * const src_saved = src; 1438 while ((ch3 = *src) != '\0' && ISBLANK(ch3)) 1439 src++; 1440 if (ch3 == '\\' && src[1] == '\n') 1441 src += 2; /* Escaped blank & newline joins into single space. */ 1442 else if (ch3 == '\\' && src[1] == '\r' && src[1] == '\n') 1443 src += 3; /* -> Join the escaped newline code below on the next line. */ 1444 else 1445 { 1446 src = src_saved; 1447 dst -= slashes / 2; 1448 if (slashes & 1) 1449 { 1450 *dst++ = ch2; 1451 continue; 1452 } 1453 assert(nextp); 1454 break; 1455 } 1456 } 1457 /* Escaped newlines get special treatment as they an any adjacent whitespace 1458 gets reduced to a single space, including subsequent escaped newlines. 1459 In addition, if this is the final dependency/file and there is no 1460 significant new characters following this escaped newline, the replacement 1461 space will also be stripped and we won't have anything to escape, meaning 1462 that the slashes will remain as is. Finally, none of this space stuff can 1463 be stop characters, unless of course a newline isn't escaped. */ 1464 else 1465 { 1466 assert(ch2_map & MAP_NEWLINE); 1467 if (ch2 == '\r' && *src == '\n') 1468 src++; 1469 } 1470 1471 /* common space/newline code */ 1472 for (;;) 1473 { 1474 while ((uintptr_t)src < (uintptr_t)end && ISBLANK(*src)) 1475 src++; 1476 if ((uintptr_t)src >= (uintptr_t)end) 1477 { 1478 ch3 = '\0'; 1479 break; 1480 } 1481 ch3 = *src; 1482 if (ch3 != '\\') 1483 break; 1484 ch3 = src[1]; 1485 if (ch3 == '\n') 1486 src += 2; 1487 else if (ch3 == '\r' && src[1] == '\n') 1488 src += 3; 1489 else 1490 break; 1491 } 1492 1493 if (!ch3 && is_dep) 1494 break; /* last thing on the line. */ 1495 dst -= slashes / 2; 1496 if (slashes & 1) 1497 *dst++ = ' '; 1498 else 1499 { 1500 assert(nextp); 1501 break; 1502 } 1503 } 1504 } 1505 /* Just output the slash if non-escapable character: */ 1506 else 1507 { 1508 src--; 1509 *dst++ = ch; 1510 } 1511 } 1512 } 1513 } 1514 1515 if (nextp) 1516 *nextp = (const char *)src; 1517 return incdep_dep_strcache(curdep, start, dst - start); 1518 } 1235 1519 1236 1520 /* no nonsense dependency file including. … … 1266 1550 1267 1551 /* now parse the file. */ 1268 while ( cur <file_end)1552 while ((uintptr_t)cur < (uintptr_t)file_end) 1269 1553 { 1270 1554 /* skip empty lines */ 1271 while ( cur <file_end && ISSPACE (*cur) && *cur != '\n')1555 while ((uintptr_t)cur < (uintptr_t)file_end && ISSPACE (*cur) && *cur != '\n') 1272 1556 ++cur; 1273 if ( cur >=file_end)1557 if ((uintptr_t)cur >= (uintptr_t)file_end) 1274 1558 break; 1275 1559 if (*cur == '#') … … 1331 1615 cur = value_end = value_start = value_start + 1; 1332 1616 ++line_no; 1333 while ( cur <file_end)1617 while ((uintptr_t)cur < (uintptr_t)file_end) 1334 1618 { 1335 1619 /* check for endef, don't bother with skipping leading spaces. */ … … 1338 1622 { 1339 1623 endp = cur + 5; 1340 while ( endp <file_end && ISSPACE (*endp) && *endp != '\n')1624 while ((uintptr_t)endp < (uintptr_t)file_end && ISSPACE (*endp) && *endp != '\n') 1341 1625 endp++; 1342 if ( endp >=file_end || *endp == '\n')1626 if ((uintptr_t)endp >= (uintptr_t)file_end || *endp == '\n') 1343 1627 { 1344 1628 found_endef = 1; 1345 cur = endp >=file_end ? file_end : endp + 1;1629 cur = (uintptr_t)endp >= (uintptr_t)file_end ? file_end : endp + 1; 1346 1630 break; 1347 1631 } … … 1382 1666 dst += len; 1383 1667 src = endp; 1384 if ( src + 1 <file_end && src[1] == '\n')1668 if ((uintptr_t)src + 1 < (uintptr_t)file_end && src[1] == '\n') 1385 1669 src++; /* skip the '\r' */ 1386 1670 if (src >= value_end) … … 1411 1695 const char *eol; 1412 1696 1413 /* Look for a colon or an dequal sign. In the assignment case, we1697 /* Look for a colon or an equal sign. In the assignment case, we 1414 1698 require it to be on the same line as the variable name to simplify 1415 1699 the code. Because of clang, we cannot make the same assumptions … … 1421 1705 eol = file_end; 1422 1706 equalp = memchr (cur, '=', eol - cur); 1423 if (equalp )1707 if (equalp && equalp != cur && (ISSPACE(equalp[-1]) || equalp[-1] != '\\')) 1424 1708 { 1425 1709 /* An assignment of some sort. */ … … 1468 1752 /* find the start of the value. */ 1469 1753 cur = equalp + 1; 1470 while ( cur <file_end && ISBLANK (*cur))1754 while ((uintptr_t)cur < (uintptr_t)file_end && ISBLANK (*cur)) 1471 1755 cur++; 1472 1756 value_start = cur; … … 1474 1758 /* find the end of the value / line (this isn't 101% correct). */ 1475 1759 value_end = cur; 1476 while ( cur <file_end)1760 while ((uintptr_t)cur < (uintptr_t)file_end) 1477 1761 { 1478 1762 endp = value_end = memchr (cur, '\n', file_end - cur); … … 1559 1843 /* Expecting: file: dependencies */ 1560 1844 1845 int unescape_filename = 0; 1561 1846 const char *filename; 1562 1847 const char *fnnext; … … 1573 1858 1574 1859 colonp = memchr (cur, ':', file_end - cur); 1860 while ( colonp 1861 && ( ( colonp != cur 1862 && colonp[-1] == '\\' 1863 && incdep_count_slashes_backwards (&colonp[-1], cur) & 1) 1575 1864 #ifdef HAVE_DOS_PATHS 1576 while ( colonp 1577 && colonp + 1 < file_end 1578 && (colonp[1] == '/' || colonp[1] == '\\') 1579 && colonp > cur 1580 && isalpha ((unsigned char)colonp[-1]) 1581 && ( colonp == cur + 1 1582 || strchr (" \t(", colonp[-2]) != 0)) 1865 || ( colonp + 1 < file_end 1866 && (colonp[1] == '/' || colonp[1] == '\\') 1867 && colonp > cur 1868 && isalpha ((unsigned char)colonp[-1]) 1869 && ( colonp == cur + 1 1870 || ISBLANK ((unsigned char)colonp[-2]))) 1871 #endif 1872 ) 1873 ) 1583 1874 colonp = memchr (colonp + 1, ':', file_end - (colonp + 1)); 1584 #endif1585 1875 if (!colonp) 1586 1876 { … … 1637 1927 break; 1638 1928 } 1639 if (memchr (cur, '$', fnend - cur)) 1929 fnnext = cur; 1930 if ( !memchr (cur, '\\', fnend - cur) 1931 && !memchr (cur, '$', fnend - cur)) 1640 1932 { 1641 incdep_warn (curdep, line_no, "fancy file name. (includedep)"); 1642 break; 1933 while (fnnext != fnend && !ISBLANK (*fnnext)) 1934 fnnext++; 1935 filename = incdep_dep_strcache (curdep, cur, fnnext - cur); 1643 1936 } 1644 1645 fnnext = cur;1646 while (fnnext != fnend && !ISBLANK (*fnnext))1647 fnnext++;1648 filename = incdep_dep_strcache (curdep, cur, fnnext - cur);1937 else 1938 { 1939 filename = incdep_unescape_and_cache_filename (curdep, (char *)fnnext, fnend, &fnnext); 1940 unescape_filename = 1; 1941 } 1649 1942 1650 1943 /* parse any dependencies. */ 1651 1944 cur = colonp + 1; 1652 while ( cur <file_end)1945 while ((uintptr_t)cur < (uintptr_t)file_end) 1653 1946 { 1654 1947 /* skip blanks and count lines. */ 1655 while ( cur <file_end && ISSPACE (*cur) && *cur != '\n')1948 while ((uintptr_t)cur < (uintptr_t)file_end && ISSPACE (*cur) && *cur != '\n') 1656 1949 ++cur; 1657 if ( cur >=file_end)1950 if ((uintptr_t)cur >= (uintptr_t)file_end) 1658 1951 break; 1659 1952 if (*cur == '\n') … … 1680 1973 /* find the end of the filename */ 1681 1974 endp = cur; 1682 while (endp < file_end && !ISSPACE (*endp)) 1975 while ( (uintptr_t)endp < (uintptr_t)file_end 1976 && ( !ISSPACE (*endp) 1977 || (endp[-1] == '\\' && incdep_count_slashes_backwards(&endp[-1], cur) & 1))) 1683 1978 ++endp; 1684 1979 1685 1980 /* add it to the list. */ 1686 1981 *nextdep = dep = incdep_alloc_dep (curdep); 1687 dep->name = incdep_dep_strcache (curdep, cur, endp - cur);1688 1982 dep->includedep = 1; 1983 if ( !memchr (cur, '\\', endp - cur) 1984 && !memchr (cur, '$', endp - cur)) 1985 dep->name = incdep_dep_strcache(curdep, cur, endp - cur); 1986 else 1987 dep->name = incdep_unescape_and_cache_filename (curdep, (char *)cur, endp, NULL); 1689 1988 nextdep = &dep->next; 1690 1989 … … 1696 1995 1697 1996 /* More files? Record them with the same dependency list. */ 1698 if ( fnnext !=fnend)1997 if ((uintptr_t)fnnext < (uintptr_t)fnend) 1699 1998 for (;;) 1700 1999 { 1701 2000 const char *filename_prev = filename; 1702 const char *fnstart;1703 2001 while (fnnext != fnend && ISBLANK (*fnnext)) 1704 2002 fnnext++; … … 1706 2004 break; 1707 2005 1708 fnstart = fnnext; 1709 while (fnnext != fnend && !ISBLANK (*fnnext)) 1710 fnnext++; 1711 1712 filename = incdep_dep_strcache (curdep, fnstart, fnnext - fnstart); 2006 if (!unescape_filename) 2007 { 2008 const char *fnstart = fnnext; 2009 while (fnnext != fnend && !ISBLANK (*fnnext)) 2010 fnnext++; 2011 filename = incdep_dep_strcache (curdep, fnstart, fnnext - fnstart); 2012 } 2013 else 2014 filename = incdep_unescape_and_cache_filename (curdep, (char *)fnnext, fnend, &fnnext); 1713 2015 if (filename != filename_prev) /* clang optimization. */ 1714 2016 incdep_record_file (curdep, filename, incdep_dup_dep_list (curdep, deps), f);
Note:
See TracChangeset
for help on using the changeset viewer.