VirtualBox

Changeset 98364 in vbox for trunk/src/bldprogs


Ignore:
Timestamp:
Jan 31, 2023 2:57:25 PM (22 months ago)
Author:
vboxsync
Message:

scm: More on the kmk makefile cleanup. bugref:10348

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/bldprogs/scmrw.cpp

    r98319 r98364  
    579579        return kScmCommentStyle_Rem_Camel;
    580580    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 */
     588static 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;
    581611}
    582612
     
    21872217{
    21882218    kKmkToken_Word = 0,
     2219    kKmkToken_Comment,
    21892220
    21902221    /* Conditionals: */
     
    22132244    kKmkToken_unexport,
    22142245    kKmkToken_local,
    2215     kKmkToken_override
     2246    kKmkToken_override,
     2247    kKmkToken_undefine
    22162248} KMKTOKEN;
    22172249
     
    22262258    unsigned            iDepth;
    22272259    unsigned            iActualDepth;
    2228     bool                fInReceipt;
     2260    bool                fInRecipe;
    22292261
    22302262    /** The current line number (for error messages and peeking).   */
     
    22362268    /** Pointer to the start of the current line. */
    22372269    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    /** @} */
    22382278
    22392279    /** The SCM rewriter state. */
     
    22742314        { RT_STR_TUPLE("local"),            kKmkToken_local },
    22752315        { RT_STR_TUPLE("override"),         kKmkToken_override },
     2316        { RT_STR_TUPLE("undefine"),         kKmkToken_undefine },
    22762317    };
    22772318    char chFirst = *pchWord;
     
    22972338#endif
    22982339
     2340    if (chFirst == '#')
     2341        return kKmkToken_Comment;
    22992342    return kKmkToken_Word;
    23002343}
     
    24342477
    24352478
     2479/** Context for scmKmkWordLength. */
     2480typedef 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 */
     2506static 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
    24362598static bool scmKmkTailComment(KMKPARSER *pParser, const char *pchLine, size_t cchLine, size_t offSrc, char **ppszDst)
    24372599{
     
    24492611    {
    24502612        /* Try preserve the start column number. */
     2613/** @todo tabs */
    24512614        size_t const offDst = pszDst - pParser->szBuf;
    24522615        if (offDst < offSrc)
     
    26612824    uint32_t cLines         = 1;
    26622825    size_t   cchMaxLeadWord = 0;
    2663     size_t   cchLineTotal   = cchLine;
     2826    size_t   cchTotalLine   = cchLine;
    26642827    if (scmKmkIsLineWithContinuation(pchLine, cchLine))
    26652828    {
    26662829        if (enmToken != kKmkToken_if)
    26672830            return scmKmkGiveUp(pParser, "Line continuation not allowed with '%.*s' directive.", cchToken, &pchLine[offToken]);
    2668         cchLineTotal = scmKmkLineContinuationPeek(pParser, &cLines, &cchMaxLeadWord);
     2831        cchTotalLine = scmKmkLineContinuationPeek(pParser, &cLines, &cchMaxLeadWord);
    26692832    }
    26702833
     
    26732836     * too long (plain if can be long, but not ifndef/ifdef).
    26742837     */
    2675     if (cchLineTotal + pParser->iActualDepth + 32 > sizeof(pParser->szBuf))
     2838    if (cchTotalLine + pParser->iActualDepth + 32 > sizeof(pParser->szBuf))
    26762839        return scmKmkGiveUp(pParser, "Line too long for a '%.*s' directive: %u chars",
    2677                             cchToken, &pchLine[offToken], cchLineTotal);
     2840                            cchToken, &pchLine[offToken], cchTotalLine);
    26782841    char *pszDst = pParser->szBuf;
    26792842
     
    30263189
    30273190/**
     3191 * Passing thru any line continuation lines following the current one.
     3192 */
     3193static 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 */
     3209static 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
     3233static 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
     3242static 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
     3251typedef 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
     3262static 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 */
     3551static 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 */
     3850static 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
     3993static 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/**
    30284005 * Rewrite a kBuild makefile.
    30294006 *
     
    30504027    Parser.iDepth       = 0;
    30514028    Parser.iActualDepth = 0;
    3052     Parser.fInReceipt   = false;
     4029    Parser.fInRecipe    = false;
    30534030    Parser.iLine        = 0;
    30544031    Parser.pState       = pState;
     
    30644041    while ((Parser.pchLine = pchLine = ScmStreamGetLine(pIn, &Parser.cchLine, &Parser.enmEol)) != NULL)
    30654042    {
     4043        size_t cchLine = Parser.cchLine;
    30664044        Parser.iLine++;
    3067         size_t const cchLine = Parser.cchLine;
    30684045
    30694046        /*
    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.
    30714049         */
    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)
    30844074            {
    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] == '\\')
    30904078                    continue;
    30914079
    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                }
    31264155            }
    31274156        }
    31284157
    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);
    31314171    }
    31324172
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette