Ejemplo n.º 1
0
/**
 * Queries the value of an SVN property.
 *
 * This will automatically adjust for scheduled changes.
 *
 * @returns IPRT status code.
 * @retval  VERR_INVALID_STATE if not a SVN WC file.
 * @retval  VERR_NOT_FOUND if the property wasn't found.
 * @param   pState              The rewrite state to work on.
 * @param   pszName             The property name.
 * @param   ppszValue           Where to return the property value.  Free this
 *                              using RTStrFree.  Optional.
 */
int ScmSvnQueryProperty(PSCMRWSTATE pState, const char *pszName, char **ppszValue)
{
    /*
     * Look it up in the scheduled changes.
     */
    size_t i = pState->cSvnPropChanges;
    while (i-- > 0)
        if (!strcmp(pState->paSvnPropChanges[i].pszName, pszName))
        {
            const char *pszValue = pState->paSvnPropChanges[i].pszValue;
            if (!pszValue)
                return VERR_NOT_FOUND;
            if (ppszValue)
                return RTStrDupEx(ppszValue, pszValue);
            return VINF_SUCCESS;
        }

#ifdef SCM_WITHOUT_LIBSVN
    int rc;
    scmSvnFindSvnBinary(pState);
    if (g_enmSvnVersion < kScmSvnVersion_1_7)
    {
        /*
         * Hack: Read the .svn/props/<file>.svn-work file exists.
         */
        char szPath[RTPATH_MAX];
        rc = scmSvnConstructName(pState, ".svn/props/", ".svn-work", szPath);
        if (RT_SUCCESS(rc) && !RTFileExists(szPath))
            rc = scmSvnConstructName(pState, ".svn/prop-base/", ".svn-base", szPath);
        if (RT_SUCCESS(rc))
        {
            SCMSTREAM Stream;
            rc = ScmStreamInitForReading(&Stream, szPath);
            if (RT_SUCCESS(rc))
            {
                /*
                 * The current format is K len\n<name>\nV len\n<value>\n" ... END.
                 */
                rc = VERR_NOT_FOUND;
                size_t const    cchName = strlen(pszName);
                SCMEOL          enmEol;
                size_t          cchLine;
                const char     *pchLine;
                while ((pchLine = ScmStreamGetLine(&Stream, &cchLine, &enmEol)) != NULL)
                {
                    /*
                     * Parse the 'K num' / 'END' line.
                     */
                    if (   cchLine == 3
                        && !memcmp(pchLine, "END", 3))
                        break;
                    size_t cchKey;
                    if (   cchLine < 3
                        || pchLine[0] != 'K'
                        || pchLine[1] != ' '
                        || !scmSvnReadNumber(&pchLine[2], cchLine - 2, &cchKey)
                        || cchKey == 0
                        || cchKey > 4096)
                    {
                        RTMsgError("%s:%u: Unexpected data '%.*s'\n", szPath, ScmStreamTellLine(&Stream), cchLine, pchLine);
                        rc = VERR_PARSE_ERROR;
                        break;
                    }

                    /*
                     * Match the key and skip to the value line.  Don't bother with
                     * names containing EOL markers.
                     */
                    size_t const offKey = ScmStreamTell(&Stream);
                    bool fMatch = cchName == cchKey;
                    if (fMatch)
                    {
                        pchLine = ScmStreamGetLine(&Stream, &cchLine, &enmEol);
                        if (!pchLine)
                            break;
                        fMatch = cchLine == cchName
                              && !memcmp(pchLine, pszName, cchName);
                    }

                    if (RT_FAILURE(ScmStreamSeekAbsolute(&Stream, offKey + cchKey)))
                        break;
                    if (RT_FAILURE(ScmStreamSeekByLine(&Stream, ScmStreamTellLine(&Stream) + 1)))
                        break;

                    /*
                     * Read and Parse the 'V num' line.
                     */
                    pchLine = ScmStreamGetLine(&Stream, &cchLine, &enmEol);
                    if (!pchLine)
                        break;
                    size_t cchValue;
                    if (   cchLine < 3
                        || pchLine[0] != 'V'
                        || pchLine[1] != ' '
                        || !scmSvnReadNumber(&pchLine[2], cchLine - 2, &cchValue)
                        || cchValue > _1M)
                    {
                        RTMsgError("%s:%u: Unexpected data '%.*s'\n", szPath, ScmStreamTellLine(&Stream), cchLine, pchLine);
                        rc = VERR_PARSE_ERROR;
                        break;
                    }

                    /*
                     * If we have a match, allocate a return buffer and read the
                     * value into it.  Otherwise skip this value and continue
                     * searching.
                     */
                    if (fMatch)
                    {
                        if (!ppszValue)
                            rc = VINF_SUCCESS;
                        else
                        {
                            char *pszValue;
                            rc = RTStrAllocEx(&pszValue, cchValue + 1);
                            if (RT_SUCCESS(rc))
                            {
                                rc = ScmStreamRead(&Stream, pszValue, cchValue);
                                if (RT_SUCCESS(rc))
                                    *ppszValue = pszValue;
                                else
                                    RTStrFree(pszValue);
                            }
                        }
                        break;
                    }

                    if (RT_FAILURE(ScmStreamSeekRelative(&Stream, cchValue)))
                        break;
                    if (RT_FAILURE(ScmStreamSeekByLine(&Stream, ScmStreamTellLine(&Stream) + 1)))
                        break;
                }

                if (RT_FAILURE(ScmStreamGetStatus(&Stream)))
                {
                    rc = ScmStreamGetStatus(&Stream);
                    RTMsgError("%s: stream error %Rrc\n", szPath, rc);
                }
                ScmStreamDelete(&Stream);
            }
        }

        if (rc == VERR_FILE_NOT_FOUND)
            rc = VERR_NOT_FOUND;
    }
    else
    {
        const char *apszArgs[] = { g_szSvnPath, "propget", "--strict", pszName, pState->pszFilename, NULL };
        char       *pszValue;
        rc = scmSvnRunAndGetOutput(pState, apszArgs, false, &pszValue);
        if (RT_SUCCESS(rc))
        {
            if (pszValue && *pszValue)
            {
                if (ppszValue)
                {
                    *ppszValue = pszValue;
                    pszValue = NULL;
                }
            }
            else
                rc = VERR_NOT_FOUND;
            RTStrFree(pszValue);
        }
    }
    return rc;

#else
    NOREF(pState);
#endif
    return VERR_NOT_FOUND;
}
Ejemplo n.º 2
0
/**
 * Reports a difference and propels the streams to the lines following the
 * resync.
 *
 *
 * @returns New pState->cDiff value (just to return something).
 * @param   pState              The diff state.  The cDiffs member will be
 *                              incremented.
 * @param   cMatches            The resync length.
 * @param   iLeft               Where the difference starts on the left side.
 * @param   cLeft               How long it is on this side.  ~(size_t)0 is used
 *                              to indicate that it goes all the way to the end.
 * @param   iRight              Where the difference starts on the right side.
 * @param   cRight              How long it is.
 */
static size_t scmDiffReport(PSCMDIFFSTATE pState, size_t cMatches,
                            size_t iLeft, size_t cLeft,
                            size_t iRight, size_t cRight)
{
    /*
     * Adjust the input.
     */
    if (cLeft == ~(size_t)0)
    {
        size_t c = ScmStreamCountLines(pState->pLeft);
        if (c >= iLeft)
            cLeft = c - iLeft;
        else
        {
            iLeft = c;
            cLeft = 0;
        }
    }

    if (cRight == ~(size_t)0)
    {
        size_t c = ScmStreamCountLines(pState->pRight);
        if (c >= iRight)
            cRight = c - iRight;
        else
        {
            iRight = c;
            cRight = 0;
        }
    }

    /*
     * Print header if it's the first difference
     */
    if (!pState->cDiffs)
        RTStrmPrintf(pState->pDiff, "diff %s %s\n", pState->pszFilename, pState->pszFilename);

    /*
     * Emit the change description.
     */
    char ch = cLeft == 0
            ? 'a'
            : cRight == 0
            ? 'd'
            : 'c';
    if (cLeft > 1 && cRight > 1)
        RTStrmPrintf(pState->pDiff, "%zu,%zu%c%zu,%zu\n", iLeft + 1, iLeft + cLeft, ch, iRight + 1, iRight + cRight);
    else if (cLeft > 1)
        RTStrmPrintf(pState->pDiff, "%zu,%zu%c%zu\n",     iLeft + 1, iLeft + cLeft, ch, iRight + 1);
    else if (cRight > 1)
        RTStrmPrintf(pState->pDiff, "%zu%c%zu,%zu\n",     iLeft + 1,                ch, iRight + 1, iRight + cRight);
    else
        RTStrmPrintf(pState->pDiff, "%zu%c%zu\n",         iLeft + 1,                ch, iRight + 1);

    /*
     * And the lines.
     */
    if (cLeft)
        scmDiffPrintLines(pState, '<', pState->pLeft, iLeft, cLeft);
    if (cLeft && cRight)
        RTStrmPrintf(pState->pDiff, "---\n");
    if (cRight)
        scmDiffPrintLines(pState, '>', pState->pRight, iRight, cRight);

    /*
     * Reposition the streams (safely ignores return value).
     */
    ScmStreamSeekByLine(pState->pLeft,  iLeft  + cLeft  + cMatches);
    ScmStreamSeekByLine(pState->pRight, iRight + cRight + cMatches);

    pState->cDiffs++;
    return pState->cDiffs;
}