Changeset 98364 in vbox for trunk/src/bldprogs
- Timestamp:
- Jan 31, 2023 2:57:25 PM (22 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/bldprogs/scmrw.cpp
r98319 r98364 579 579 return kScmCommentStyle_Rem_Camel; 580 580 return kScmCommentStyle_Rem_Upper; 581 } 582 583 584 /** 585 * Calculates the number of spaces from @a offStart to @a offEnd in @a pchLine, 586 * taking tabs into account. 587 */ 588 static size_t ScmCalcSpacesForSrcSpan(const char *pchLine, size_t offStart, size_t offEnd, PCSCMSETTINGSBASE pSettings) 589 { 590 size_t cchRet = 0; 591 if (offStart < offEnd) 592 { 593 offEnd -= offStart; /* becomes cchLeft now */ 594 pchLine += offStart; 595 while (offEnd > 0) 596 { 597 const char *pszTab = (const char *)memchr(pchLine, '\t', offEnd); 598 if (!pszTab) 599 { 600 cchRet += offEnd; 601 break; 602 } 603 size_t offTab = (size_t)(pszTab - pchLine); 604 size_t cchToTab = pSettings->cchTab - offTab % pSettings->cchTab; 605 cchRet += offTab + cchToTab; 606 offEnd -= offTab + 1; 607 pchLine = pszTab + 1; 608 } 609 } 610 return cchRet; 581 611 } 582 612 … … 2187 2217 { 2188 2218 kKmkToken_Word = 0, 2219 kKmkToken_Comment, 2189 2220 2190 2221 /* Conditionals: */ … … 2213 2244 kKmkToken_unexport, 2214 2245 kKmkToken_local, 2215 kKmkToken_override 2246 kKmkToken_override, 2247 kKmkToken_undefine 2216 2248 } KMKTOKEN; 2217 2249 … … 2226 2258 unsigned iDepth; 2227 2259 unsigned iActualDepth; 2228 bool fInRec eipt;2260 bool fInRecipe; 2229 2261 2230 2262 /** The current line number (for error messages and peeking). */ … … 2236 2268 /** Pointer to the start of the current line. */ 2237 2269 char const *pchLine; 2270 2271 /** @name Only used for rule/assignment parsing. 2272 * @{ */ 2273 /** Number of continuation lines at current rule/assignment. */ 2274 uint32_t cLines; 2275 /** Characters in continuation lines at current rule/assignment. */ 2276 size_t cchTotalLine; 2277 /** @} */ 2238 2278 2239 2279 /** The SCM rewriter state. */ … … 2274 2314 { RT_STR_TUPLE("local"), kKmkToken_local }, 2275 2315 { RT_STR_TUPLE("override"), kKmkToken_override }, 2316 { RT_STR_TUPLE("undefine"), kKmkToken_undefine }, 2276 2317 }; 2277 2318 char chFirst = *pchWord; … … 2297 2338 #endif 2298 2339 2340 if (chFirst == '#') 2341 return kKmkToken_Comment; 2299 2342 return kKmkToken_Word; 2300 2343 } … … 2434 2477 2435 2478 2479 /** Context for scmKmkWordLength. */ 2480 typedef enum 2481 { 2482 /** Target file or assignment. 2483 * Separators: space, '=', ':' */ 2484 kKmkWordCtx_TargetFileOrAssignment, 2485 /** Target file. 2486 * Separators: space, ':' */ 2487 kKmkWordCtx_TargetFile, 2488 /** Dependency file or (target variable) assignment. 2489 * Separators: space, '=', ':', '|' */ 2490 kKmkWordCtx_DepFileOrAssignment, 2491 /** Dependency file. 2492 * Separators: space, '|' */ 2493 kKmkWordCtx_DepFile 2494 } KMKWORDCTX; 2495 2496 /** 2497 * Finds the length of the word (file) @a offStart. 2498 * 2499 * @returns Length of word starting at @a offStart. Zero if there is whitespace 2500 * at given offset or it's beyond the end of the line (both cases will 2501 * assert). 2502 * @param pchLine The line. 2503 * @param cchLine The line length. 2504 * @param offStart Offset to the start of the word. 2505 */ 2506 static size_t scmKmkWordLength(const char *pchLine, size_t cchLine, size_t offStart, KMKWORDCTX enmCtx) 2507 { 2508 AssertReturn(offStart < cchLine && !RT_C_IS_BLANK(pchLine[offStart]), 0); 2509 size_t off = offStart; 2510 while (off < cchLine) 2511 { 2512 char ch = pchLine[off]; 2513 if (RT_C_IS_BLANK(ch)) 2514 break; 2515 2516 if (ch == ':') 2517 { 2518 /* 2519 * Check for plain driver letter, omitting the archive member variant. 2520 */ 2521 if (off - offStart != 1 || !RT_C_IS_ALPHA(pchLine[off - 1])) 2522 { 2523 if (off == offStart) 2524 { 2525 /* We need to check for single and double colon rules as well as 2526 simple and immediate assignments here. */ 2527 off++; 2528 if (pchLine[off] == ':') 2529 { 2530 off++; 2531 if (pchLine[off] == '=') 2532 { 2533 if (enmCtx == kKmkWordCtx_TargetFileOrAssignment || enmCtx == kKmkWordCtx_DepFileOrAssignment) 2534 return 3; /* ::= - immediate assignment. */ 2535 off++; 2536 } 2537 else if (enmCtx != kKmkWordCtx_DepFile) 2538 return 2; /* :: - double colon rule */ 2539 } 2540 else if (pchLine[off] == '=') 2541 { 2542 if (enmCtx == kKmkWordCtx_TargetFileOrAssignment || enmCtx == kKmkWordCtx_DepFileOrAssignment) 2543 return 2; /* := - simple assignment. */ 2544 off++; 2545 } 2546 else if (enmCtx != kKmkWordCtx_DepFile) 2547 return 1; /* : - regular rule. */ 2548 continue; 2549 } 2550 /* ':' is a separator except in DepFile context. */ 2551 else if (enmCtx != kKmkWordCtx_DepFile) 2552 return off - offStart; 2553 } 2554 } 2555 else if (ch == '=') 2556 { 2557 /* 2558 * Assignment. We check for the previous character too so we'll catch 2559 * append, prepend and conditional assignments. Simple and immediate 2560 * assignments are handled above. 2561 */ 2562 if ( enmCtx == kKmkWordCtx_TargetFileOrAssignment 2563 || enmCtx == kKmkWordCtx_DepFileOrAssignment) 2564 { 2565 if (off > offStart) 2566 { 2567 ch = pchLine[off - 1]; 2568 if (ch == '?' || ch == '+' || ch == '>') 2569 off = off - 1 == offStart 2570 ? off + 2 /* return '+=', '?=', '<=' */ 2571 : off - 1; /* up to '+=', '?=', '<=' */ 2572 else 2573 Assert(ch != ':'); /* handled above */ 2574 } 2575 else 2576 off++; /* '=' */ 2577 return off - offStart; 2578 } 2579 } 2580 else if (ch == '|') 2581 { 2582 /* 2583 * This is rather straight forward. 2584 */ 2585 if (enmCtx == kKmkWordCtx_DepFileOrAssignment && enmCtx == kKmkWordCtx_DepFile) 2586 { 2587 if (off == offStart) 2588 return 1; 2589 return off - offStart; 2590 } 2591 } 2592 off++; 2593 } 2594 return off - offStart; 2595 } 2596 2597 2436 2598 static bool scmKmkTailComment(KMKPARSER *pParser, const char *pchLine, size_t cchLine, size_t offSrc, char **ppszDst) 2437 2599 { … … 2449 2611 { 2450 2612 /* Try preserve the start column number. */ 2613 /** @todo tabs */ 2451 2614 size_t const offDst = pszDst - pParser->szBuf; 2452 2615 if (offDst < offSrc) … … 2661 2824 uint32_t cLines = 1; 2662 2825 size_t cchMaxLeadWord = 0; 2663 size_t cch LineTotal= cchLine;2826 size_t cchTotalLine = cchLine; 2664 2827 if (scmKmkIsLineWithContinuation(pchLine, cchLine)) 2665 2828 { 2666 2829 if (enmToken != kKmkToken_if) 2667 2830 return scmKmkGiveUp(pParser, "Line continuation not allowed with '%.*s' directive.", cchToken, &pchLine[offToken]); 2668 cch LineTotal= scmKmkLineContinuationPeek(pParser, &cLines, &cchMaxLeadWord);2831 cchTotalLine = scmKmkLineContinuationPeek(pParser, &cLines, &cchMaxLeadWord); 2669 2832 } 2670 2833 … … 2673 2836 * too long (plain if can be long, but not ifndef/ifdef). 2674 2837 */ 2675 if (cch LineTotal+ pParser->iActualDepth + 32 > sizeof(pParser->szBuf))2838 if (cchTotalLine + pParser->iActualDepth + 32 > sizeof(pParser->szBuf)) 2676 2839 return scmKmkGiveUp(pParser, "Line too long for a '%.*s' directive: %u chars", 2677 cchToken, &pchLine[offToken], cch LineTotal);2840 cchToken, &pchLine[offToken], cchTotalLine); 2678 2841 char *pszDst = pParser->szBuf; 2679 2842 … … 3026 3189 3027 3190 /** 3191 * Passing thru any line continuation lines following the current one. 3192 */ 3193 static bool scmKmkPassThruLineContinuationLines(KMKPARSER *pParser) 3194 { 3195 while (scmKmkIsLineWithContinuation(pParser->pchLine, pParser->cchLine)) 3196 { 3197 pParser->pchLine = ScmStreamGetLine(pParser->pIn, &pParser->cchLine, &pParser->enmEol); 3198 if (!pParser->pchLine) 3199 break; 3200 ScmStreamPutLine(pParser->pOut, pParser->pchLine, pParser->cchLine, pParser->enmEol); 3201 } 3202 return false; 3203 } 3204 3205 3206 /** 3207 * For dealing with a directive w/o special formatting rules (yet). 3208 */ 3209 static bool scmKmkHandleSimple(KMKPARSER *pParser, size_t offToken, bool fIndentIt = true) 3210 { 3211 const char *pchLine = pParser->pchLine; 3212 size_t cchLine = pParser->cchLine; 3213 uint32_t const cchIndent = fIndentIt ? pParser->iActualDepth : 0; 3214 3215 /* 3216 * Just reindent the statement. 3217 */ 3218 ScmStreamWrite(pParser->pOut, g_szSpaces, cchIndent); 3219 ScmStreamWrite(pParser->pOut, &pchLine[offToken], cchLine - offToken); 3220 ScmStreamPutEol(pParser->pOut, pParser->enmEol); 3221 3222 bool fModified = cchIndent != offToken 3223 || !memcmp(pchLine, g_szSpaces, cchIndent); 3224 3225 /* 3226 * Check for line continuation and output concatenated lines. 3227 */ 3228 scmKmkPassThruLineContinuationLines(pParser); 3229 return fModified; 3230 } 3231 3232 3233 static bool scmKmkHandleDefine(KMKPARSER *pParser, size_t offToken) 3234 { 3235 /* Assignments takes us out of recipe mode. */ 3236 pParser->fInRecipe = false; 3237 3238 return scmKmkHandleSimple(pParser, offToken); 3239 } 3240 3241 3242 static bool scmKmkHandleEndef(KMKPARSER *pParser, size_t offToken) 3243 { 3244 /* Leaving a define resets the recipt mode. */ 3245 pParser->fInRecipe = false; 3246 3247 return scmKmkHandleSimple(pParser, offToken); 3248 } 3249 3250 3251 typedef enum KMKASSIGNTYPE 3252 { 3253 kKmkAssignType_Recursive, 3254 kKmkAssignType_Conditional, 3255 kKmkAssignType_Appending, 3256 kKmkAssignType_Prepending, 3257 kKmkAssignType_Simple, 3258 kKmkAssignType_Immediate 3259 } KMKASSIGNTYPE; 3260 3261 3262 static bool scmKmkHandleAssignment2(KMKPARSER *pParser, size_t offVarStart, size_t offVarEnd, KMKASSIGNTYPE enmType, 3263 size_t offAssignOp, unsigned fFlags) 3264 { 3265 unsigned const cchIndent = pParser->iActualDepth; 3266 const char *pchLine = pParser->pchLine; 3267 size_t cchLine = pParser->cchLine; 3268 uint32_t const cLines = pParser->cLines; 3269 uint32_t iSubLine = 0; 3270 3271 RT_NOREF(fFlags); 3272 Assert(offVarStart < cchLine); 3273 Assert(offVarEnd <= cchLine); 3274 Assert(offVarStart < offVarEnd); 3275 Assert(!RT_C_IS_SPACE(pchLine[offVarStart])); 3276 Assert(!RT_C_IS_SPACE(pchLine[offVarEnd - 1])); 3277 3278 /* Assignments takes us out of recipe mode. */ 3279 pParser->fInRecipe = false; 3280 3281 /* This is too much hazzle to deal with. */ 3282 if (cLines > 0 && pchLine[cchLine - 2] == '\\') 3283 return scmKmkGiveUp(pParser, "Escaped slashes at end of line not allowed. Insert space before line continuation slash!"); 3284 if (cchLine + 64 > sizeof(pParser->szBuf)) 3285 return scmKmkGiveUp(pParser, "Line too long!"); 3286 3287 /* 3288 * Indent and output the variable name. 3289 */ 3290 char *pszDst = pParser->szBuf; 3291 memset(pszDst, ' ', cchIndent); 3292 pszDst += cchIndent; 3293 pszDst = (char *)mempcpy(pszDst, &pchLine[offVarStart], offVarEnd - offVarStart); 3294 3295 /* 3296 * Try preserve the assignment operator position, but make sure we've got a 3297 * space in front of it. 3298 */ 3299 if (offAssignOp < cchLine) 3300 { 3301 size_t offDst = (size_t)(pszDst - pParser->szBuf); 3302 size_t offEffAssignOp = ScmCalcSpacesForSrcSpan(pchLine, 0, offAssignOp, pParser->pSettings); 3303 if (offDst < offEffAssignOp) 3304 { 3305 size_t cchSpacesToWrite = offEffAssignOp - offDst; 3306 memset(pszDst, ' ', cchSpacesToWrite); 3307 pszDst += cchSpacesToWrite; 3308 } 3309 else 3310 *pszDst++ = ' '; 3311 } 3312 else 3313 { 3314 /* Pull up the assignment operator to the variable line. */ 3315 *pszDst++ = ' '; 3316 3317 /* Eat up lines till we hit the operator. */ 3318 while (offAssignOp < cchLine) 3319 { 3320 const char * const pchPrevLine = pchLine; 3321 Assert(iSubLine + 1 < cLines); 3322 pParser->pchLine = pchLine = ScmStreamGetLine(pParser->pIn, &pParser->cchLine, &pParser->enmEol); 3323 AssertReturn(pchLine, true); 3324 cchLine = pParser->cchLine; 3325 iSubLine++; 3326 if (iSubLine + 1 < cLines && pchLine[cchLine - 2] == '\\') 3327 return scmKmkGiveUp(pParser, "Escaped slashes at end of line not allowed. Insert space before line continuation slash!"); 3328 3329 /* Adjust offAssignOp: */ 3330 offAssignOp -= (uintptr_t)pchLine - (uintptr_t)pchPrevLine; 3331 Assert(offAssignOp < ~(size_t)0 / 2); 3332 } 3333 3334 if ((size_t)(pszDst - pParser->szBuf) > sizeof(pParser->szBuf)) 3335 return scmKmkGiveUp(pParser, "Line too long!"); 3336 } 3337 3338 /* 3339 * Emit the operator. 3340 */ 3341 size_t offLine = offAssignOp; 3342 switch (enmType) 3343 { 3344 default: AssertReleaseFailed(); 3345 case kKmkAssignType_Recursive: 3346 *pszDst++ = '='; 3347 Assert(pchLine[offLine] == '='); 3348 offLine++; 3349 break; 3350 case kKmkAssignType_Conditional: 3351 *pszDst++ = '?'; 3352 *pszDst++ = '='; 3353 Assert(pchLine[offLine] == '?'); Assert(pchLine[offLine + 1] == '='); 3354 offLine += 2; 3355 break; 3356 case kKmkAssignType_Appending: 3357 *pszDst++ = '+'; 3358 *pszDst++ = '='; 3359 Assert(pchLine[offLine] == '+'); Assert(pchLine[offLine + 1] == '='); 3360 offLine += 2; 3361 break; 3362 case kKmkAssignType_Prepending: 3363 *pszDst++ = '>'; 3364 *pszDst++ = '='; 3365 Assert(pchLine[offLine] == '>'); Assert(pchLine[offLine + 1] == '='); 3366 offLine += 2; 3367 break; 3368 case kKmkAssignType_Immediate: 3369 *pszDst++ = ':'; 3370 Assert(pchLine[offLine] == ':'); 3371 offLine++; 3372 RT_FALL_THRU(); 3373 case kKmkAssignType_Simple: 3374 *pszDst++ = ':'; 3375 *pszDst++ = '='; 3376 Assert(pchLine[offLine] == ':'); Assert(pchLine[offLine + 1] == '='); 3377 offLine += 2; 3378 break; 3379 } 3380 3381 /* 3382 * Skip space till we hit the value or comment. 3383 */ 3384 size_t cchSpaces = 0; 3385 while (offLine < cchLine && RT_C_IS_SPACE(pchLine[offLine])) 3386 cchSpaces++, offLine++; 3387 3388 /** @todo this block can probably be merged into the final loop below. */ 3389 unsigned cPendingEols = 0; 3390 bool fModified = false; 3391 unsigned const iSubLineStart1 = iSubLine; 3392 while (iSubLine + 1 < cLines && offLine + 1 == cchLine && pchLine[offLine] == '\\') 3393 { 3394 pParser->pchLine = pchLine = ScmStreamGetLine(pParser->pIn, &pParser->cchLine, &pParser->enmEol); 3395 AssertReturn(pchLine, fModified); 3396 cchLine = pParser->cchLine; 3397 iSubLine++; 3398 if (iSubLine + 1 < cLines && pchLine[cchLine - 2] == '\\') 3399 { 3400 *pszDst++ = ' '; 3401 *pszDst++ = '\\'; 3402 *pszDst = '\0'; 3403 ScmStreamPutLine(pParser->pOut, pParser->szBuf, pszDst - pParser->szBuf, pParser->enmEol); 3404 return scmKmkGiveUp(pParser, "Escaped slashes at end of line not allowed. Insert space before line continuation slash!"); 3405 } 3406 cPendingEols = 1; 3407 3408 /* Deal with indent/whitespace. */ 3409 offLine = 0; 3410 if ( memcmp(pchLine, g_szSpaces, cchIndent) == 0 3411 && pchLine[cchIndent] == '\t') 3412 offLine = cchIndent + 1; 3413 cchSpaces = 0; 3414 while (offLine < cchLine && RT_C_IS_SPACE(pchLine[offLine])) 3415 cchSpaces++, offLine++; 3416 fModified |= cchSpaces != 0 && pchLine[offLine] != '#'; 3417 } 3418 fModified |= iSubLine > iSubLineStart1 + 1; 3419 3420 /* 3421 * Okay, we've gotten to the value / comment part. 3422 */ 3423 for (;;) 3424 { 3425 /* 3426 * The end? Flush what we've got. 3427 */ 3428 if (offLine == cchLine) 3429 { 3430 Assert(iSubLine + 1 == cLines); 3431 *pszDst = '\0'; 3432 ScmStreamPutLine(pParser->pOut, pParser->szBuf, pszDst - pParser->szBuf, pParser->enmEol); 3433 return fModified || cPendingEols > 0; 3434 } 3435 3436 /* 3437 * Output any non-comment stuff, stripping off newlines. 3438 */ 3439 const char *pchHash = (const char *)memchr(&pchLine[offLine], '#', cchLine - offLine); 3440 if (pchHash != &pchLine[offLine]) 3441 { 3442 /* Add space or flush pending EOLs. */ 3443 if (!cPendingEols) 3444 *pszDst++ = ' '; 3445 else 3446 { 3447 fModified |= cPendingEols > 2; 3448 cPendingEols = RT_MIN(2, cPendingEols); /* reduce to two, i.e. only one empty separator line */ 3449 do 3450 { 3451 *pszDst++ = ' '; 3452 *pszDst++ = '\\'; 3453 *pszDst = '\0'; 3454 ScmStreamPutLine(pParser->pOut, pParser->szBuf, pszDst - pParser->szBuf, pParser->enmEol); 3455 3456 pszDst = pParser->szBuf; 3457 memset(pszDst, ' ', cchIndent); 3458 pszDst += cchIndent; 3459 *pszDst++ = '\t'; 3460 cPendingEols--; 3461 } while (cPendingEols > 0); 3462 } 3463 3464 /* Strip backwards. */ 3465 size_t const offValueEnd2 = pchHash ? (size_t)(pchHash - pchLine) : cchLine - (iSubLine + 1 < cLines); 3466 size_t offValueEnd = offValueEnd2; 3467 while (offValueEnd > offLine && RT_C_IS_BLANK(pchLine[offValueEnd - 1])) 3468 offValueEnd--; 3469 Assert(offValueEnd > offLine); 3470 3471 fModified |= !pchHash && offValueEnd != cchLine - (iSubLine + 1 < cLines ? 2 : 0); 3472 3473 /* Append the value part we found. */ 3474 pszDst = (char *)mempcpy(pszDst, &pchLine[offLine], offValueEnd - offLine); 3475 offLine = offValueEnd2; 3476 } 3477 3478 /* 3479 * If we found a comment hash, emit it and whatever follows just as-is w/o 3480 * any particular reformatting. Comments within a variable definition are 3481 * usually to disable portitions of a property like _DEFS or _SOURCES. 3482 */ 3483 if (pchHash != NULL) 3484 { 3485 if (cPendingEols == 0) 3486 scmKmkTailComment(pParser, pchLine, cchLine, offLine - cchSpaces, &pszDst); 3487 size_t const cchDst = (size_t)(pszDst - pParser->szBuf); 3488 *pszDst = '\0'; 3489 ScmStreamPutLine(pParser->pOut, pParser->szBuf, cchDst, pParser->enmEol); 3490 fModified |= cPendingEols > 0 3491 || cchLine != cchDst 3492 || memcmp(pParser->szBuf, pchLine, cchLine) != 0; 3493 3494 if (cPendingEols > 1) 3495 ScmStreamPutEol(pParser->pOut, pParser->enmEol); 3496 3497 if (cPendingEols > 0) 3498 ScmStreamPutLine(pParser->pOut, pchLine, cchLine, pParser->enmEol); 3499 scmKmkPassThruLineContinuationLines(pParser); 3500 return fModified; 3501 } 3502 3503 /* 3504 * Fetch another line, if we've got one. 3505 */ 3506 if (iSubLine + 1 >= cLines) 3507 Assert(offLine == cchLine); 3508 else 3509 { 3510 Assert(offLine + 1 == cchLine); 3511 unsigned const iSubLineStart2 = iSubLine; 3512 while (iSubLine + 1 < cLines && offLine + 1 == cchLine && pchLine[offLine] == '\\') 3513 { 3514 pParser->pchLine = pchLine = ScmStreamGetLine(pParser->pIn, &pParser->cchLine, &pParser->enmEol); 3515 AssertReturn(pchLine, fModified); 3516 cchLine = pParser->cchLine; 3517 iSubLine++; 3518 if (iSubLine + 1 < cLines && pchLine[cchLine - 2] == '\\') 3519 { 3520 *pszDst++ = ' '; 3521 *pszDst++ = '\\'; 3522 *pszDst = '\0'; 3523 ScmStreamPutLine(pParser->pOut, pParser->szBuf, pszDst - pParser->szBuf, pParser->enmEol); 3524 if (cPendingEols > 1) 3525 ScmError(pParser->pState, VERR_NOT_SUPPORTED, "oops #1: Manually fix the next issue after reverting edits!"); 3526 return scmKmkGiveUp(pParser, "Escaped slashes at end of line not allowed. Insert space before line continuation slash!"); 3527 } 3528 cPendingEols++; 3529 3530 /* Deal with indent/whitespace. */ 3531 offLine = 0; 3532 if ( memcmp(pchLine, g_szSpaces, cchIndent) == 0 3533 && pchLine[cchIndent] == '\t') 3534 offLine = cchIndent + 1; 3535 cchSpaces = 0; 3536 while (offLine < cchLine && RT_C_IS_SPACE(pchLine[offLine])) 3537 cchSpaces++, offLine++; 3538 fModified |= cchSpaces != 0 && pchLine[offLine] != '#'; 3539 } 3540 fModified |= iSubLine > iSubLineStart2 + 1; 3541 } 3542 } 3543 } 3544 3545 3546 /** 3547 * A rule. 3548 * 3549 * This is a bit involved. Sigh. 3550 */ 3551 static bool scmKmkHandleRule(KMKPARSER *pParser, size_t offFirstWord, bool fDoubleColon, size_t offColon) 3552 { 3553 SCMSTREAM *pOut = pParser->pOut; 3554 unsigned const cchIndent = pParser->iActualDepth; 3555 const char *pchLine = pParser->pchLine; 3556 size_t cchLine = pParser->cchLine; 3557 Assert(offFirstWord < cchLine); 3558 uint32_t const cLines = pParser->cLines; 3559 uint32_t iSubLine = 0; 3560 3561 /* Following this, we'll be in recipe-mode. */ 3562 pParser->fInRecipe = true; 3563 3564 /* This is too much hazzle to deal with. */ 3565 if (cLines > 0 && pchLine[cchLine - 2] == '\\') 3566 return scmKmkGiveUp(pParser, "Escaped slashes at end of line not allowed. Insert space before line continuation slash!"); 3567 3568 /* Too special case. */ 3569 if (offColon <= offFirstWord) 3570 return scmKmkGiveUp(pParser, "Missing target file before colon!"); 3571 3572 /* 3573 * Indent it. 3574 */ 3575 bool fModified = offFirstWord != cchIndent 3576 || memcmp(pchLine, g_szSpaces, cchIndent) != 0; 3577 ScmStreamWrite(pOut, g_szSpaces, cchIndent); 3578 size_t offLine = offFirstWord; 3579 3580 /* 3581 * Process word by word past the colon, taking new lines into account. 3582 * 3583 */ 3584 KMKWORDCTX enmCtx = kKmkWordCtx_TargetFileOrAssignment; 3585 bool fPendingEol = false; 3586 for (;;) 3587 { 3588 /* 3589 * Output the next word. 3590 */ 3591 size_t cchWord = scmKmkWordLength(pchLine, cchLine, offLine, enmCtx); 3592 Assert(offLine + cchWord <= offColon); 3593 ScmStreamWrite(pOut, &pchLine[offLine], cchWord); 3594 offLine += cchWord; 3595 3596 /* Skip whitespace (if any). */ 3597 size_t cchSpaces = 0; 3598 while (offLine < cchLine && RT_C_IS_SPACE(pchLine[offLine])) 3599 { 3600 fModified |= pchLine[offLine] != ' '; 3601 cchSpaces++; 3602 offLine++; 3603 } 3604 3605 /* Have we reached the colon already? */ 3606 if (offLine >= offColon) 3607 { 3608 fModified |= cchSpaces != 0; 3609 3610 Assert(pchLine[offLine] == ':'); 3611 Assert(!fDoubleColon || pchLine[offLine + 1] == ':'); 3612 offLine += fDoubleColon ? 2 : 1; 3613 3614 ScmStreamPutCh(pOut, ':'); 3615 if (fDoubleColon) 3616 ScmStreamPutCh(pOut, ':'); 3617 break; 3618 } 3619 3620 /* Deal with new line and emit indentation. */ 3621 if (offLine + 1 == cchLine && pchLine[offLine] == '\\') 3622 { 3623 fModified |= cchSpaces > 1; 3624 3625 /* Get the next input line. */ 3626 for (;;) 3627 { 3628 const char * const pchPrevLine = pchLine; 3629 Assert(iSubLine + 1 < cLines); 3630 pParser->pchLine = pchLine = ScmStreamGetLine(pParser->pIn, &pParser->cchLine, &pParser->enmEol); 3631 AssertReturn(pchLine, fModified); 3632 cchLine = pParser->cchLine; 3633 iSubLine++; 3634 if (iSubLine + 1 < cLines && pchLine[cchLine - 2] == '\\') 3635 return scmKmkGiveUp(pParser, "Escaped slashes at end of line not allowed. Insert space before line continuation slash!"); 3636 3637 /* Adjust offColon: */ 3638 offColon -= (uintptr_t)pchLine - (uintptr_t)pchPrevLine; 3639 Assert(offColon < ~(size_t)0 / 2); 3640 3641 /* Skip leading spaces. */ 3642 offLine = 0; 3643 while (offLine < cchLine && RT_C_IS_SPACE(pchLine[offLine])) 3644 { 3645 fModified |= pchLine[offLine] != ' '; 3646 offLine++; 3647 } 3648 fModified |= offLine == cchIndent 3649 || memcmp(pchLine, g_szSpaces, cchIndent) != 0; 3650 3651 /* Just drop empty lines. */ 3652 if (offLine + 1 == cchLine && pchLine[offLine] == '\\') 3653 { 3654 fModified = true; 3655 continue; 3656 } 3657 3658 /* Complete the current line and emit indent, unless we reached the colon: */ 3659 if (offLine >= offColon) 3660 { 3661 fModified = true; 3662 Assert(pchLine[offLine] == ':'); 3663 Assert(!fDoubleColon || pchLine[offLine + 1] == ':'); 3664 offLine += fDoubleColon ? 2 : 1; 3665 3666 ScmStreamPutCh(pOut, ':'); 3667 if (fDoubleColon) 3668 ScmStreamPutCh(pOut, ':'); 3669 3670 fPendingEol = true; 3671 break; 3672 } 3673 ScmStreamWrite(pOut, RT_STR_TUPLE(" \\")); 3674 ScmStreamPutEol(pOut, pParser->enmEol); 3675 ScmStreamWrite(pOut, g_szSpaces, cchIndent); 3676 } 3677 if (offLine >= offColon) 3678 break; 3679 } 3680 else 3681 { 3682 fModified |= cchSpaces != 1; 3683 ScmStreamPutCh(pOut, ' '); 3684 } 3685 enmCtx = kKmkWordCtx_TargetFile; 3686 } 3687 3688 /* 3689 * We're immediately past the colon now, so eat whitespace and newlines and 3690 * whatever till we get to a solid word. 3691 */ 3692 /* Skip spaces - there should be exactly one. */ 3693 fModified |= pchLine[offLine] != ' '; 3694 if (offLine < cchLine && RT_C_IS_SPACE(pchLine[offLine])) 3695 offLine++; 3696 while (offLine < cchLine && RT_C_IS_SPACE(pchLine[offLine])) 3697 { 3698 fModified = true; 3699 offLine++; 3700 } 3701 3702 /* Deal with new lines: */ 3703 while (offLine + 1 == cchLine && pchLine[offLine] == '\\') 3704 { 3705 fPendingEol = true; 3706 3707 Assert(iSubLine + 1 < cLines); 3708 pParser->pchLine = pchLine = ScmStreamGetLine(pParser->pIn, &pParser->cchLine, &pParser->enmEol); 3709 AssertReturn(pchLine, fModified); 3710 cchLine = pParser->cchLine; 3711 iSubLine++; 3712 if (iSubLine + 1 < cLines && pchLine[cchLine - 2] == '\\') 3713 return scmKmkGiveUp(pParser, "Escaped slashes at end of line not allowed. Insert space before line continuation slash!"); 3714 3715 /* Skip leading spaces. */ 3716 offLine = 0; 3717 if (memcmp(pchLine, g_szSpaces, cchIndent) == 0 && pchLine[cchIndent] == '\t' && pchLine[cchIndent + 1] == '\t') 3718 offLine += cchIndent + 2; 3719 while (offLine < cchLine && RT_C_IS_SPACE(pchLine[offLine])) 3720 { 3721 fModified = true; 3722 offLine++; 3723 } 3724 3725 /* Just drop empty lines. */ 3726 if (offLine + 1 == cchLine && pchLine[offLine] == '\\') 3727 { 3728 fModified = true; 3729 continue; 3730 } 3731 } 3732 3733 /* 3734 * Special case: No dependencies. 3735 */ 3736 if (offLine == cchLine && iSubLine >= cLines) 3737 { 3738 ScmStreamPutEol(pOut, pParser->enmEol); 3739 return fModified; 3740 } 3741 3742 /* 3743 * Work the dependencies word for word. Indent in spaces + two tabs. 3744 * (Pattern rules will also end up here, but we'll just ignore that for now.) 3745 */ 3746 /** @todo fModified isn't updated right here. */ 3747 enmCtx = kKmkWordCtx_DepFileOrAssignment; 3748 for (;;) 3749 { 3750 /* Indent the next word. */ 3751 if (!fPendingEol) 3752 ScmStreamPutCh(pOut, ' '); 3753 else 3754 { 3755 ScmStreamWrite(pOut, RT_STR_TUPLE(" \\")); 3756 ScmStreamPutEol(pOut, pParser->enmEol); 3757 ScmStreamWrite(pOut, g_szSpaces, cchIndent); 3758 ScmStreamWrite(pOut, RT_STR_TUPLE("\t\t")); 3759 fPendingEol = false; 3760 } 3761 3762 /* Get the next word and output it. */ 3763 size_t cchWord = scmKmkWordLength(pchLine, cchLine, offLine, enmCtx); 3764 Assert(offLine + cchWord <= cchLine); 3765 3766 ScmStreamWrite(pOut, &pchLine[offLine], cchWord); 3767 offLine += cchWord; 3768 3769 /* Skip whitespace (if any). */ 3770 size_t cchSpaces = 0; 3771 while (offLine < cchLine && RT_C_IS_SPACE(pchLine[offLine])) 3772 { 3773 fModified |= pchLine[offLine] != ' '; 3774 cchSpaces++; 3775 offLine++; 3776 } 3777 3778 /* Deal with new line and emit indentation. */ 3779 if (iSubLine + 1 < cLines && offLine + 1 == cchLine && pchLine[offLine] == '\\') 3780 { 3781 fModified |= cchSpaces > 1; 3782 3783 /* Get the next input line. */ 3784 unsigned cEmptyLines = 0; 3785 for (;;) 3786 { 3787 Assert(iSubLine + 1 < cLines); 3788 pParser->pchLine = pchLine = ScmStreamGetLine(pParser->pIn, &pParser->cchLine, &pParser->enmEol); 3789 AssertReturn(pchLine, fModified); 3790 cchLine = pParser->cchLine; 3791 iSubLine++; 3792 if (iSubLine + 1 < cLines && pchLine[cchLine - 2] == '\\') 3793 return scmKmkGiveUp(pParser, "Escaped slashes at end of line not allowed. Insert space before line continuation slash!"); 3794 3795 /* Skip leading spaces. */ 3796 offLine = 0; 3797 if (memcmp(pchLine, g_szSpaces, cchIndent) == 0 && pchLine[cchIndent] == '\t' && pchLine[cchIndent + 1] == '\t') 3798 offLine += cchIndent + 2; 3799 while (offLine < cchLine && RT_C_IS_SPACE(pchLine[offLine])) 3800 { 3801 fModified = true; 3802 offLine++; 3803 } 3804 3805 /* Just drop empty lines, we'll re-add one of them afterward if we find more dependencies. */ 3806 if (offLine + 1 == cchLine && pchLine[offLine] == '\\') 3807 { 3808 cEmptyLines++; 3809 continue; 3810 } 3811 3812 fPendingEol = true; 3813 break; 3814 } 3815 cchSpaces = 1; 3816 } 3817 3818 if (offLine < cchLine) 3819 fModified |= cchSpaces != 1; 3820 else 3821 { 3822 /* End of input. */ 3823 /** @todo deal with comments */ 3824 Assert(iSubLine + 1 == cLines); 3825 ScmStreamPutEol(pOut, pParser->enmEol); 3826 return fModified; 3827 } 3828 enmCtx = kKmkWordCtx_DepFile; 3829 } 3830 } 3831 3832 3833 /** 3834 * Checks if the (extended) line is a variable assignment. 3835 * 3836 * We scan past line continuation stuff here as the assignment operator could be 3837 * on the next line, even if that's very unlikely it is recommened by the coding 3838 * guide lines if the line needs to be split. Fortunately, though, the caller 3839 * already removes empty empty leading lines, so we only have to consider the 3840 * line continuation issue if no '=' was found on the first line. 3841 * 3842 * @returns Modified or not. 3843 * @param pParser The parser. 3844 * @param cLines Number of lines to consider. 3845 * @param cchTotalLine Total length of all the lines to consider. 3846 * @param offWord Where the first word of the line starts. 3847 * @param pfIsAssignment Where to return whether this is an assignment or 3848 * not. 3849 */ 3850 static bool scmKmkHandleAssignmentOrRule(KMKPARSER *pParser, size_t offWord) 3851 { 3852 const char *pchLine = pParser->pchLine; 3853 size_t const cchTotalLine = pParser->cchTotalLine; 3854 3855 /* 3856 * Scan words till we find ':' or '='. 3857 */ 3858 uint32_t iWord = 0; 3859 size_t offCurWord = offWord; 3860 size_t offEndPrev = 0; 3861 size_t offLine = offWord; 3862 while (offLine < cchTotalLine) 3863 { 3864 char ch = pchLine[offLine++]; 3865 if (ch == '$') 3866 { 3867 /* 3868 * Skip variable expansion. 3869 */ 3870 char const chOpen = pchLine[offLine++]; 3871 if (chOpen == '(' || chOpen == '{') 3872 { 3873 char const chClose = chOpen == '(' ? ')' : '}'; 3874 unsigned cDepth = 1; 3875 while (offLine < cchTotalLine) 3876 { 3877 ch = pchLine[offLine++]; 3878 if (ch == chOpen) 3879 cDepth++; 3880 else if (ch == chClose) 3881 if (!--cDepth) 3882 break; 3883 } 3884 } 3885 /* else: $x or $$, so just skip the next character. */ 3886 } 3887 else if (RT_C_IS_SPACE(ch)) 3888 { 3889 /* 3890 * End of word. Skip whitespace till the next word starts. 3891 */ 3892 offEndPrev = offLine - 1; 3893 Assert(offLine != offWord); 3894 while (offLine < cchTotalLine) 3895 { 3896 ch = pchLine[offLine]; 3897 if (RT_C_IS_SPACE(ch)) 3898 offLine++; 3899 else if (ch == '\\' && (pchLine[offLine] == '\r' || pchLine[offLine] == '\n')) 3900 offLine += 2; 3901 else 3902 break; 3903 } 3904 offCurWord = offLine; 3905 iWord++; 3906 3907 /* 3908 * To simplify the assignment operator checks, we just check the 3909 * start of the 2nd word when we're here. 3910 */ 3911 if (iWord == 1 && offLine < cchTotalLine) 3912 { 3913 ch = pchLine[offLine]; 3914 if (ch == '=') 3915 return scmKmkHandleAssignment2(pParser, offWord, offEndPrev, kKmkAssignType_Recursive, offLine, 0); 3916 if (offLine + 1 < cchTotalLine && pchLine[offLine + 1] == '=') 3917 { 3918 if (ch == ':') 3919 return scmKmkHandleAssignment2(pParser, offWord, offEndPrev, kKmkAssignType_Simple, offLine, 0); 3920 if (ch == '+') 3921 return scmKmkHandleAssignment2(pParser, offWord, offEndPrev, kKmkAssignType_Appending, offLine, 0); 3922 if (ch == '>') 3923 return scmKmkHandleAssignment2(pParser, offWord, offEndPrev, kKmkAssignType_Prepending, offLine, 0); 3924 if (ch == '?') 3925 return scmKmkHandleAssignment2(pParser, offWord, offEndPrev, kKmkAssignType_Conditional, offLine, 0); 3926 } 3927 else if ( ch == ':' 3928 && pchLine[offLine + 1] == ':' 3929 && pchLine[offLine + 2] == '=') 3930 return scmKmkHandleAssignment2(pParser, offWord, offEndPrev, kKmkAssignType_Immediate, offLine, 0); 3931 3932 /* Check for rule while we're here. */ 3933 if (ch == ':') 3934 return scmKmkHandleRule(pParser, offWord, pchLine[offLine + 1] == ':', offLine); 3935 } 3936 } 3937 /* 3938 * If '=' is found in the first word it's an assignment. 3939 */ 3940 else if (ch == '=') 3941 { 3942 if (iWord == 0) 3943 { 3944 KMKASSIGNTYPE enmType = kKmkAssignType_Recursive; 3945 ch = pchLine[offLine - 2]; 3946 if (ch == '+') 3947 enmType = kKmkAssignType_Appending; 3948 else if (ch == '?') 3949 enmType = kKmkAssignType_Conditional; 3950 else if (ch == '>') 3951 enmType = kKmkAssignType_Prepending; 3952 else 3953 Assert(ch != ':'); 3954 return scmKmkHandleAssignment2(pParser, offWord, offLine - 1, enmType, offLine - 1, 0); 3955 } 3956 } 3957 /* 3958 * When ':' is found it can mean a drive letter, a rule or in the 3959 * first word a simple or immediate assignment. 3960 */ 3961 else if (ch == ':') 3962 { 3963 /* Check for drive letters (we ignore the archive form): */ 3964 if (offLine - offWord == 2 && RT_C_IS_ALPHA(pchLine[offLine - 2])) 3965 { /* ignore */ } 3966 else 3967 { 3968 /* Simple or immediate assignment? */ 3969 ch = pchLine[offLine]; 3970 if (iWord == 0) 3971 { 3972 if (ch == '=') 3973 return scmKmkHandleAssignment2(pParser, offWord, offLine - 1, kKmkAssignType_Simple, offLine - 1, 0); 3974 if (ch == ':' && pchLine[offLine + 1] == '=') 3975 return scmKmkHandleAssignment2(pParser, offWord, offLine - 1, kKmkAssignType_Immediate, offLine - 1, 0); 3976 } 3977 3978 /* Okay, it's a rule then. */ 3979 return scmKmkHandleRule(pParser, offWord, ch == ':', offLine - 1); 3980 } 3981 } 3982 } 3983 3984 /* 3985 * If we didn't find anything, output it as-as. 3986 * We use scmKmkHandleSimple in a special way to do this. 3987 */ 3988 ScmVerbose(pParser->pState, 1, "debug: %u: Unable to make sense of this line!", pParser->iLine); 3989 return scmKmkHandleSimple(pParser, 0 /*offToken*/, false /*fIndentIt*/); 3990 } 3991 3992 3993 static bool scmKmkHandleAssignKeyword(KMKPARSER *pParser, size_t offToken, KMKTOKEN enmToken, size_t cchWord, 3994 bool fMustBeAssignment) 3995 { 3996 /* Assignments takes us out of recipe mode. */ 3997 pParser->fInRecipe = false; 3998 3999 RT_NOREF(pParser, offToken, enmToken, cchWord, fMustBeAssignment); 4000 return scmKmkHandleSimple(pParser, offToken); 4001 } 4002 4003 4004 /** 3028 4005 * Rewrite a kBuild makefile. 3029 4006 * … … 3050 4027 Parser.iDepth = 0; 3051 4028 Parser.iActualDepth = 0; 3052 Parser.fInRec eipt= false;4029 Parser.fInRecipe = false; 3053 4030 Parser.iLine = 0; 3054 4031 Parser.pState = pState; … … 3064 4041 while ((Parser.pchLine = pchLine = ScmStreamGetLine(pIn, &Parser.cchLine, &Parser.enmEol)) != NULL) 3065 4042 { 4043 size_t cchLine = Parser.cchLine; 3066 4044 Parser.iLine++; 3067 size_t const cchLine = Parser.cchLine;3068 4045 3069 4046 /* 3070 * Skip leading whitespace and check for directives (simplified). 4047 * If we're in the command part of a recipe, anything starting with a 4048 * tab is considered another command for the recipe. 3071 4049 */ 3072 size_t offLine = 0; 3073 while (offLine < cchLine && RT_C_IS_BLANK(pchLine[offLine])) 3074 offLine++; 3075 3076 /* Find end of word (if any): */ 3077 size_t cchWord = 0; 3078 while (offLine + cchWord < cchLine && (RT_C_IS_ALNUM(pchLine[offLine + cchWord]) || pchLine[offLine + cchWord] == '-')) 3079 cchWord++; 3080 if (cchWord > 0) 3081 { 3082 KMKTOKEN enmToken = scmKmkIdentifyToken(&pchLine[offLine], cchWord); 3083 switch (enmToken) 4050 if (Parser.fInRecipe && *pchLine == '\t') 4051 { 4052 /* Do we do anything here? */ 4053 } 4054 else 4055 { 4056 /* 4057 * Skip leading whitespace and check for directives (simplified). 4058 * 4059 * This is simplified in the sense that GNU make first checks for variable 4060 * assignments, so that directive can be used as variable names. We don't 4061 * want that, so we do the variable assignment check later. 4062 */ 4063 size_t offLine = 0; 4064 while (offLine < cchLine && RT_C_IS_BLANK(pchLine[offLine])) 4065 offLine++; 4066 4067 /* Find end of word (if any): */ 4068 size_t cchWord = 0; 4069 while ( offLine + cchWord < cchLine 4070 && ( RT_C_IS_ALNUM(pchLine[offLine + cchWord]) 4071 || pchLine[offLine + cchWord] == '-')) 4072 cchWord++; 4073 if (cchWord > 0) 3084 4074 { 3085 case kKmkToken_ifeq: 3086 case kKmkToken_ifneq: 3087 case kKmkToken_if1of: 3088 case kKmkToken_ifn1of: 3089 fModified |= scmKmkHandleIfParentheses(&Parser, offLine, enmToken, cchWord, false /*fElse*/); 4075 /* If the line is just a line continuation slash, simply remove it 4076 (this also makes the parsing a lot easier). */ 4077 if (cchWord == 1 && offLine == cchLine - 1 && pchLine[cchLine] == '\\') 3090 4078 continue; 3091 4079 3092 case kKmkToken_ifdef: 3093 case kKmkToken_ifndef: 3094 case kKmkToken_if: 3095 fModified |= scmKmkHandleIfSpace(&Parser, offLine, enmToken, cchWord, false /*fElse*/); 3096 continue; 3097 3098 case kKmkToken_else: 3099 fModified |= scmKmkHandleElse(&Parser, offLine); 3100 continue; 3101 3102 case kKmkToken_endif: 3103 fModified |= scmKmkHandleEndif(&Parser, offLine); 3104 continue; 3105 3106 /* Includes: */ 3107 case kKmkToken_include: 3108 case kKmkToken_sinclude: 3109 case kKmkToken_dash_include: 3110 case kKmkToken_includedep: 3111 case kKmkToken_includedep_queue: 3112 case kKmkToken_includedep_flush: 3113 break; 3114 3115 /* Others: */ 3116 case kKmkToken_define: 3117 case kKmkToken_endef: 3118 case kKmkToken_export: 3119 case kKmkToken_unexport: 3120 case kKmkToken_local: 3121 case kKmkToken_override: 3122 break; 3123 3124 case kKmkToken_Word: 3125 break; 4080 /* Unlike the GNU make parser, we won't recognize 'if' or any other 4081 directives as variable names, so we can */ 4082 KMKTOKEN enmToken = scmKmkIdentifyToken(&pchLine[offLine], cchWord); 4083 switch (enmToken) 4084 { 4085 case kKmkToken_ifeq: 4086 case kKmkToken_ifneq: 4087 case kKmkToken_if1of: 4088 case kKmkToken_ifn1of: 4089 fModified |= scmKmkHandleIfParentheses(&Parser, offLine, enmToken, cchWord, false /*fElse*/); 4090 continue; 4091 4092 case kKmkToken_ifdef: 4093 case kKmkToken_ifndef: 4094 case kKmkToken_if: 4095 fModified |= scmKmkHandleIfSpace(&Parser, offLine, enmToken, cchWord, false /*fElse*/); 4096 continue; 4097 4098 case kKmkToken_else: 4099 fModified |= scmKmkHandleElse(&Parser, offLine); 4100 continue; 4101 4102 case kKmkToken_endif: 4103 fModified |= scmKmkHandleEndif(&Parser, offLine); 4104 continue; 4105 4106 /* Includes: */ 4107 case kKmkToken_include: 4108 case kKmkToken_sinclude: 4109 case kKmkToken_dash_include: 4110 case kKmkToken_includedep: 4111 case kKmkToken_includedep_queue: 4112 case kKmkToken_includedep_flush: 4113 fModified |= scmKmkHandleSimple(&Parser, offLine); 4114 continue; 4115 4116 /* Others: */ 4117 case kKmkToken_define: 4118 fModified |= scmKmkHandleDefine(&Parser, offLine); 4119 continue; 4120 case kKmkToken_endef: 4121 fModified |= scmKmkHandleEndef(&Parser, offLine); 4122 continue; 4123 4124 case kKmkToken_override: 4125 case kKmkToken_local: 4126 fModified |= scmKmkHandleAssignKeyword(&Parser, offLine, enmToken, cchWord, true /*fMustBeAssignment*/); 4127 continue; 4128 4129 case kKmkToken_export: 4130 fModified |= scmKmkHandleAssignKeyword(&Parser, offLine, enmToken, cchWord, false /*fMustBeAssignment*/); 4131 continue; 4132 4133 case kKmkToken_unexport: 4134 case kKmkToken_undefine: 4135 fModified |= scmKmkHandleSimple(&Parser, offLine); 4136 break; 4137 4138 case kKmkToken_Comment: 4139 break; 4140 4141 /* 4142 * Check if it's perhaps an variable assignment or start of a rule. 4143 * We'll do this in a very simple fashion. 4144 */ 4145 case kKmkToken_Word: 4146 { 4147 Parser.cLines = 1; 4148 Parser.cchTotalLine = cchLine; 4149 if (scmKmkIsLineWithContinuation(pchLine, cchLine)) 4150 Parser.cchTotalLine = scmKmkLineContinuationPeek(&Parser, &Parser.cLines, NULL); 4151 fModified |= scmKmkHandleAssignmentOrRule(&Parser, offLine); 4152 continue; 4153 } 4154 } 3126 4155 } 3127 4156 } 3128 4157 3129 /* Pass it thru as-is: */ 3130 ScmStreamPutLine(pOut, pchLine, cchLine, Parser.enmEol); 4158 /* 4159 * Pass it thru as-is with line continuation. 4160 */ 4161 while (scmKmkIsLineWithContinuation(pchLine, cchLine)) 4162 { 4163 ScmStreamPutLine(pOut, pchLine, cchLine, Parser.enmEol); 4164 Parser.pchLine = pchLine = ScmStreamGetLine(pIn, &Parser.cchLine, &Parser.enmEol); 4165 if (!pchLine) 4166 break; 4167 cchLine = Parser.cchLine; 4168 } 4169 if (pchLine) 4170 ScmStreamPutLine(pOut, pchLine, cchLine, Parser.enmEol); 3131 4171 } 3132 4172
Note:
See TracChangeset
for help on using the changeset viewer.