Exemple #1
0
/***********************************************************************************************************************************
Get the list of WAL files ready to be pushed according to PostgreSQL
***********************************************************************************************************************************/
static StringList *
archivePushReadyList(const String *walPath)
{
    FUNCTION_LOG_BEGIN(logLevelTrace);
        FUNCTION_LOG_PARAM(STRING, walPath);
    FUNCTION_LOG_END();

    ASSERT(walPath != NULL);

    StringList *result = NULL;

    MEM_CONTEXT_TEMP_BEGIN()
    {
        result = strLstNew();

        // Read the ready files from the archive_status directory
        StringList *readyListRaw = strLstSort(
            storageListP(
                storagePg(), strNewFmt("%s/" PG_PATH_ARCHIVE_STATUS, strPtr(walPath)),
                .expression = STRDEF("\\" STATUS_EXT_READY "$"), .errorOnMissing = true),
            sortOrderAsc);

        for (unsigned int readyIdx = 0; readyIdx < strLstSize(readyListRaw); readyIdx++)
        {
            strLstAdd(
                result,
                strSubN(strLstGet(readyListRaw, readyIdx), 0, strSize(strLstGet(readyListRaw, readyIdx)) - STATUS_EXT_READY_SIZE));
        }

        strLstMove(result, MEM_CONTEXT_OLD());
    }
    MEM_CONTEXT_TEMP_END();

    FUNCTION_LOG_RETURN(STRING_LIST, result);
}
Exemple #2
0
/*
 * prepare_body
 *
 * Builds a lexeme sequence with the expansion of the body of
 * a macro.
 */
static int
prepare_body (macroctx_t mctx, expansion_t *curexp, lexseq_t *result)
{
    expr_ctx_t ctx = mctx->ectx;
    parse_ctx_t pctx = expr_parse_ctx(ctx);
    lexctx_t lctx = parser_lexmemctx(pctx);
    struct macrodecl_s *macro = name_extraspace(curexp->curmacro);
    lexeme_t *lex;
    name_t *np;
    static strdesc_t mend = STRDEF("<macro-end>");

    // Prepare the grouper and separator lexemes, in case
    // they are needed (only applicable to iterative macros)
    if (curexp->count == 0 && macro->type == MACRO_ITER) {
        curexp->sep = parser_punct_separator(pctx);
        lex = parser_punct_grouper(pctx, 0);
        if (lex != 0) {
            lexseq_instail(result, lex);
        }
        curexp->closer = parser_punct_grouper(pctx, 1);
    }

    // Associate the iterative-formals with any actuals
    if (macro->type == MACRO_ITER) {
        nameref_t *iformal;
        lextype_t lt, terms[1] = { LEXTYPE_DELIM_COMMA };

        for (iformal = namereflist_head(&macro->ilist); iformal != 0;
             iformal = iformal->tq_next) {
            strdesc_t *namestr = name_string(iformal->np);
            np = macparam_special(curexp->expscope, namestr, 0);
            parse_lexeme_seq(pctx, &curexp->remaining, QL_MACRO, terms, 1,
                             macparam_lexseq(np), &lt);
        }
    }

    // Expand the macro parameters here, instead of relying on the parser
    // to do this while processing the expansion.  If we were to wait, we'd
    // have to push a new scope on the parser's stack and remove it when we're
    // done -- but the expansion could declare other names, and those would
    // get declared in the scope we're removing.
    for (lex = lexseq_head(&macro->body); lex != 0; lex = lexeme_next(lex)) {
        if (curexp->expscope != 0 && lexeme_boundtype(lex) == LEXTYPE_NAME) {
            lexseq_t seq;
            lexseq_init(&seq);
            if (macparam_lookup(lctx, curexp->expscope, lexeme_text(lex), &seq) != 0) {
                lexseq_append(result, &seq);
            } else {
                lexseq_instail(result, lexeme_copy(lctx, lex));
            }
        } else {
            lexseq_instail(result, lexeme_copy(lctx, lex));
        }
    }
    lexseq_instail(result, lexeme_create(lctx, LEXTYPE_MACROEND, &mend));
    curexp->count += 1;

    return 1;

} /* prepare_body */
Exemple #3
0
/*
 * lexer_filename
 *
 * Given a filename index (from a lexeme's position),
 * return the relevant filename.  This is invoked through
 * the 'filename_fetch' function pointer by the logger.
 */
static strdesc_t *
lexer_filename (void *vctx, int filename_index)
{
    lexer_ctx_t lctx = vctx;
    struct saved_filename_s *sf;
    static strdesc_t internalsrc = STRDEF("<Internal source>");

    if (filename_index == -1) {
        return &internalsrc;
    }

    for (sf = lctx->saved_filenames; sf != 0; sf = sf->next) {
        if (sf->filename_index == filename_index) {
            return sf->filename;
        }
    }
    return 0;

} /* lexer_filename */
Exemple #4
0
/*
 * macros_init
 *
 * Module initialization routine.
 */
macroctx_t
macros_init (scopectx_t kwdscope, expr_ctx_t ctx)
{
    namectx_t namectx = scope_namectx(kwdscope);
    lexctx_t lctx = expr_lexmemctx(ctx);
    parse_ctx_t pctx = expr_parse_ctx(ctx);
    macroctx_t mctx = malloc(sizeof(struct macroctx_s));
    nametype_vectors_t vec;
    int i;

    for (i = 0; i < sizeof(macro_names)/sizeof(macro_names[0]); i++) {
        name_declare(kwdscope, &macro_names[i], 0, 0, 0, 0);
    }

    memset(mctx, 0, sizeof(struct macroctx_s));
    mctx->ectx = ctx;
    mctx->state = EXP_NORMAL;
    lextype_register(lctx, mctx, LEXTYPE_NAME_MACRO, macro_bind);
    lextype_register(lctx, ctx, LEXTYPE_NAME_MAC_PARAM, macparam_bind);
    lextype_register(lctx, mctx, LEXTYPE_MACROEND, macroend_bind);
    parser_lexfunc_register(pctx, mctx, LEXTYPE_LXF_REMAINING, handle_specials);
    parser_lexfunc_register(pctx, mctx, LEXTYPE_LXF_COUNT, handle_specials);
    parser_lexfunc_register(pctx, mctx, LEXTYPE_LXF_LENGTH, handle_specials);
    parser_lexfunc_register(pctx, mctx, LEXTYPE_LXF_EXITMACRO, handle_exits);
    parser_lexfunc_register(pctx, mctx, LEXTYPE_LXF_EXITITER, handle_exits);
    parser_lexfunc_register(pctx, mctx, LEXTYPE_LXF_ERRORMACRO, handle_exits);
    memset(&vec, 0, sizeof(vec));
    vec.typesize = sizeof(struct macrodecl_s);
    vec.typeinit = macro_initdata;
    vec.typefree = macro_freedata;
    vec.typecopy = macro_copydata;
    vec.typeser  = macro_serialize;
    vec.typedes  = macro_deserialize;
    nametype_dataop_register(namectx, LEXTYPE_NAME_MACRO, &vec, ctx);
    memset(&vec, 0, sizeof(vec));
    vec.typesize = sizeof(lexseq_t);
    vec.typeinit = macparam_initdata;
    vec.typefree = macparam_freedata;
    vec.typecopy = macparam_copydata;
    vec.typeser  = macparam_serialize;
    vec.typedes  = macparam_deserialize;
    nametype_dataop_register(namectx, LEXTYPE_NAME_MAC_PARAM, &vec, ctx);

    for (i = 0; i < sizeof(predeclared_macros)/sizeof(predeclared_macros[0]); i++) {
        name_t *np;
        struct macrodecl_s *m;

        np = name_declare(kwdscope, &predeclared_macros[i], 0, 0, 0, &m);
        if (np == 0 || m == 0) {
            expr_signal(ctx, STC__INTCMPERR, "macros_init");
            continue;
        }
        m->type = MACRO_COND;
        // Index 0 is the %BLISSM[] macro
        if (i == 0) {
            strdesc_t pctremain = STRDEF("%REMAINING");
            lexeme_t *lex = lexeme_create(lctx, LEXTYPE_LXF_REMAINING, &pctremain);
            lexseq_instail(&m->body, lex);
        }
        // All other macro bodies are empty
    }

    return mctx;

} /* macros_init */
Exemple #5
0
/*
 * macro_expand
 *
 * Expands a macro.
 */
static int
macro_expand (macroctx_t mctx, name_t *macroname, lexseq_t *result)
{
    struct macrodecl_s *macro = name_extraspace(macroname);
    expr_ctx_t ctx = mctx->ectx;
    parse_ctx_t pctx = expr_parse_ctx(ctx);
    lexctx_t lctx = parser_lexmemctx(pctx);
    expansion_t *curexp = expansion_alloc(mctx);
    expansion_t *prev_exp;
    lextype_t lt;
    lexeme_t *lex;
    lexseq_t extras;
    name_t *np;
    scopectx_t expscope;
    int which;
    int nactuals;
    punctclass_t pcl;
    lextype_t psep;
    lextype_t terms[3];
    static strdesc_t comma = STRDEF(",");

    if (macro == 0 || curexp == 0) {
        expr_signal(ctx, STC__INTCMPERR, "macro_expand");
        return 1;
    }
    memset(curexp, 0, sizeof(struct expansion_s));

    // We save the punctuation class here, since it will get
    // munged by the parsing of the macro parameters.
    parser_punctclass_get(pctx, &pcl, &psep);

    prev_exp = 0;
    if (macro->type == MACRO_COND) {
        for (prev_exp = mctx->curexp; prev_exp != 0 && prev_exp->curmacro != macroname;
             prev_exp = prev_exp->next);
    }

    nactuals = 0;
    lexseq_init(&extras);

    // Simple macros with no formal arguments get no processing
    // of parameter lists whatsoever.
    if (macro->type == MACRO_SIMPLE && namereflist_length(&macro->plist) == 0) {
        expscope = 0;
        which = 3;
    } else {
        // For keyword macros, prime the scope with the declared
        // formals, so we can inherit the default values.
        if (macro->type == MACRO_KWD) {
            expscope = scope_copy(macro->ptable, 0);
        } else {
            expscope = scope_begin(scope_namectx(parser_scope_get(pctx)), 0);
        }

        lt = parser_next(pctx, QL_NORMAL, &lex);
        if (macro->type == MACRO_KWD) {
            if (lt != LEXTYPE_DELIM_LPAR) {
                expr_signal(ctx, STC__DELIMEXP, "(");
                parser_insert(pctx, lex);
                return 1;
            }
            which = 0;
            lexeme_free(lctx, lex);
        } else {
            for (which = 0; lt != openers[which] && which < 3; which++);
            if (which >= 3 && namereflist_length(&macro->plist) > 0) {
                expr_signal(ctx, STC__DELIMEXP, "(");
                parser_insert(pctx, lex);
                return 1;
            }
            if (which >= 3) {
                parser_insert(pctx, lex);
            } else {
                lexeme_free(lctx, lex);
            }
        }
    }

    // If we had a match on an opener, process
    // the actual parameters.
    if (which < 3) {

        nameref_t *formal;
        lexseq_t val;

        terms[0] = LEXTYPE_DELIM_COMMA;
        terms[1] = closers[which];

        formal = namereflist_head(&macro->plist);

        while (1) {
            // Keyword macro actuals are of the form name=value
            // For positionals, grab the next formal-parameter name,
            // or set np to NULL to add the actual to %REMAINING.
            if (macro->type == MACRO_KWD) {
                lt = parser_next(pctx, QL_NAME, &lex);
                if (lexeme_boundtype(lex) != LEXTYPE_NAME) {
                    expr_signal(ctx, STC__NAMEEXP);
                    lexeme_free(lctx, lex);
                    break;
                }
                np = name_search(macro->ptable, lex->text.ptr, lex->text.len, 0);
                if (np == 0) {
                    expr_signal(ctx, STC__INTCMPERR, "macro_expand[2]");
                }
                lexeme_free(lctx, lex);
                if (!parser_expect(pctx, QL_NORMAL, LEXTYPE_OP_ASSIGN, 0, 1)) {
                    expr_signal(ctx, STC__OPEREXP, "=");
                    break;
                }
            } else if (nactuals < namereflist_length(&macro->plist)) {
                np = formal->np;
                formal = formal->tq_next;
            } else {
                np = 0;
            }
            lexseq_init(&val);
            // Now parse the actual-parameter, which can be an expression
            if (!parse_lexeme_seq(pctx, 0, QL_NAME, terms, 2, &val, &lt)) {
                lexseq_free(lctx, &val);
                break;
            }

            // If we are recursively expanding a conditional macro and
            // there are no parameters, we're done - no expansion.
            if (prev_exp != 0 && lexseq_length(&val) == 0 && nactuals == 0) {
                scope_end(expscope);
                free(curexp);
                return 1;
            }

            if (np == 0) {
                if (lexseq_length(&extras) > 0) {
                    lexseq_instail(&extras,
                                   lexeme_create(lctx, LEXTYPE_DELIM_COMMA, &comma));
                }
                lexseq_append(&extras, &val);
            } else {
                name_t *actual;
                // Associate the actual with the formal.  For keyword
                // macros, the scope_copy() above sets a special "no check"
                // flag that allows each name to be redeclared once.
                // name_declare() clears this flag, so we can catch genuine
                // redeclarations.
                actual = macparam_special(expscope, name_string(np), &val);
                if (actual == 0) {
                    expr_signal(ctx, STC__INTCMPERR, "macro_expand[3]");
                }
                lexseq_free(lctx, &val);
            }

            nactuals += 1;

            if (lt == closers[which]) {
                break;
            }

            if (lt != LEXTYPE_DELIM_COMMA) {
                expr_signal(ctx, STC__DELIMEXP, ",");
                break;
            }

        } /* while (1) */

        if (lt != closers[which]) {
            expr_signal(ctx, STC__DELIMEXP, "closer");
            lexseq_free(lctx, &extras);
            scope_end(expscope);
            return 1;
        }

        if (nactuals < namereflist_length(&macro->plist)) {
            name_t *anp;
            while (formal != 0) {
                anp = macparam_special(expscope, name_string(formal->np), 0);
                if (anp == 0) {
                    expr_signal(ctx, STC__INTCMPERR, "macro_expand[4]");
                }
                formal = formal->tq_next;
            }
        }

    } /* if which < 3 */

    // The macro actual parameters are now processed; hook
    // the scope into the current hierarchy, restore the punctuation
    // class to what it was before we parsed the actuals, and
    // generate the expansion sequence.

    parser_punctclass_set(pctx, pcl, psep);

    curexp->count = (prev_exp == 0 ? 0 : prev_exp->count);
    curexp->expscope = expscope;
    curexp->curmacro = macroname;
    curexp->next = mctx->curexp;
    curexp->nactuals = nactuals;
    lexseq_append(&curexp->remaining, &extras);
    mctx->curexp = curexp;

    return prepare_body(mctx, curexp, result);

} /* macro_expand */
Exemple #6
0
/*
 * parse_fields
 *
 * Recursive routine for defining individual fields
 * and field-sets.  If the 'fldset' parameter is null,
 * we check for the SET keyword and call ourselves again
 * to parse the fields in the set, if that keyword is
 * encountered.
 */
static int
parse_fields (expr_ctx_t ctx, scopectx_t scope, namereflist_t *fldset)
{
    parse_ctx_t pctx = expr_parse_ctx(ctx);
    namectx_t namectx = expr_namectx(ctx);
    strdesc_t *fldname;
    textpos_t fpos;
    lexseq_t *fseq;
    lexeme_t *lex;
    name_t *fldnp;
    namedef_t ndef;
    lextype_t delims[2] = { LEXTYPE_DELIM_COMMA, LEXTYPE_DELIM_RBRACK };
    int which;
    static strdesc_t zero = STRDEF("0");

    while (1) {
        if (!parse_decl_name(pctx, &fldname, &fpos)) {
            expr_signal(ctx, STC__NAMEEXP);
            break;
        }
        memset(&ndef, 0, sizeof(ndef));
        ndef.name = fldname->ptr;
        ndef.namelen = fldname->len;
        ndef.flags = NAME_M_DECLARED;
        if (!parser_expect(pctx, QL_NORMAL, LEXTYPE_OP_ASSIGN, 0, 1)) {
            expr_signal(ctx, STC__OPEREXP, "=");
        }
        // Check for fieldset and recurse
        if (fldset == 0 && parser_expect(pctx, QL_NORMAL, LEXTYPE_KWD_SET, 0, 1)) {
            namereflist_t *frefs;
            ndef.lt = LEXTYPE_NAME_FIELDSET;
            fldnp = name_declare(scope, &ndef, fpos, 0, 0, &frefs);
            if (fldnp == 0) {
                expr_signal(ctx, STC__INTCMPERR, "parse_fields[1]");
                break;
            }
            if (!parse_fields(ctx, scope, frefs)) {
                expr_signal(ctx, STC__SYNTAXERR);
                return 0;
            }
            if (!parser_expect(pctx, QL_NORMAL, LEXTYPE_KWD_TES, 0, 1)) {
                expr_signal(ctx, STC__KWDEXP, "TES");
            }
            if (!parser_expect(pctx, QL_NORMAL, LEXTYPE_DELIM_COMMA, 0, 1)) {
                break;
            }
            continue; // set defined; move on to the next name
        }
        // Just a regular field
        ndef.lt = LEXTYPE_NAME_FIELD;
        fldnp = name_declare(scope, &ndef, fpos, 0, 0, &fseq);
        if (fldnp == 0) {
            expr_signal(ctx, STC__INTCMPERR, "parse_fields[2]");
            break;
        }
        if (fldset != 0) {
            namereflist_instail(fldset, nameref_alloc(namectx, fldnp));
        }
        if (!parser_expect(pctx, QL_NORMAL, LEXTYPE_DELIM_LBRACK, 0, 1)) {
            expr_signal(ctx, STC__DELIMEXP, "]");
        }
        while (1) {
            if (expr_parse_ctce(ctx, &lex, 0)) {
                lexseq_instail(fseq, lex);
            } else {
                expr_signal(ctx, STC__EXPCTCE);
                lexseq_instail(fseq,
                               lexeme_create(parser_lexmemctx(pctx),
                                             LEXTYPE_NUMERIC, &zero));
            }
            which = parser_expect_oneof(pctx, QL_NORMAL, delims, 2, &lex, 1);
            if (which != 0) {
                if (which < 0) {
                    expr_signal(ctx, STC__DELIMEXP, ",");
                }
                break;
            }
            lexseq_instail(fseq, lex);
        }
        if (!parser_expect(pctx, QL_NORMAL, LEXTYPE_DELIM_COMMA, 0, 1)) {
            break;
        }
    } /* while */

    return 1;

} /* parse_fields */
Exemple #7
0
 * information about the access and
 * allocation parameters and the macro
 * bodies for each.
 */
struct strudef_s {
    scopectx_t acctbl, allotbl;
    namereflist_t accformals;
    namereflist_t alloformals;
    lexseq_t accbody, allobody;
};

/*
 * Some commonly-used data used throughout this module.
 */
static lextype_t bodyends[] = { LEXTYPE_DELIM_COMMA, LEXTYPE_DELIM_SEMI };
static strdesc_t leftparen = STRDEF("(");
static strdesc_t rightparen = STRDEF(")");
static strdesc_t zero = STRDEF("0");
static namedef_t mynames[] = {
    NAMEDEF("%FIELDEXPAND", LEXTYPE_LXF_FIELDEXPAND, NAME_M_RESERVED),
    NAMEDEF("%SIZE", LEXTYPE_LXF_SIZE, NAME_M_RESERVED)
};

/*
 * The following definitions are used in the initialization
 * routine to set up the predeclared structures.  It was simpler
 * to provide these in text form and run them through the parser
 * than to set up the structures manually. There are different
 * flavors of these definitions, based on whether or not the
 * target machine allows for UNIT and EXT parameters.
 */
Exemple #8
0
/***********************************************************************************************************************************
Test Run
***********************************************************************************************************************************/
void
testRun(void)
{
    FUNCTION_HARNESS_VOID();

    // *****************************************************************************************************************************
    if (testBegin("strNew(), strNewBuf(), strNewN(), strEmpty(), strPtr(), strSize(), and strFree()"))
    {
        // We don't want this struct to grow since there are generally a lot of strings, so make sure it doesn't grow without us
        // knowing about it
        TEST_RESULT_UINT(sizeof(StringConst), TEST_64BIT() ? 16 : 12, "check StringConst struct size");

        // Test the size macro
        TEST_RESULT_VOID(CHECK_SIZE(555), "valid size");
        TEST_ERROR(CHECK_SIZE(STRING_SIZE_MAX + 1), AssertError, "string size must be <= 1073741824 bytes");

        String *string = strNew("static string");
        TEST_RESULT_STR(strPtr(string), "static string", "new with static string");
        TEST_RESULT_INT(strSize(string), 13, "check size");
        TEST_RESULT_BOOL(strEmpty(string), false, "is not empty");
        TEST_RESULT_INT(strlen(strPtr(string)), 13, "check size with strlen()");
        TEST_RESULT_CHAR(strPtr(string)[2], 'a', "check character");

        TEST_RESULT_VOID(strFree(string), "free string");

        // -------------------------------------------------------------------------------------------------------------------------
        TEST_RESULT_STR(strPtr(strNewN("testmorestring", 4)), "test", "new string with size limit");

        // -------------------------------------------------------------------------------------------------------------------------
        Buffer *buffer = bufNew(8);
        memcpy(bufPtr(buffer), "12345678", 8);
        bufUsedSet(buffer, 8);

        TEST_RESULT_STR(strPtr(strNewBuf(buffer)), "12345678", "new string from buffer");

        // -------------------------------------------------------------------------------------------------------------------------
        string = strNewFmt("formatted %s %04d", "string", 1);
        TEST_RESULT_STR(strPtr(string), "formatted string 0001", "new with formatted string");
        TEST_RESULT_PTR(strPtr(NULL), NULL, "null string pointer");

        TEST_RESULT_VOID(strFree(string), "free string");
        TEST_RESULT_VOID(strFree(NULL), "free null string");
    }

    // *****************************************************************************************************************************
    if (testBegin("STRING_STATIC()"))
    {
        TEST_RESULT_STR(strPtr(TEST_STRING), "a very interesting string!", "check static string");
        TEST_RESULT_STR(strPtr(strSubN(TEST_STRING, 0, 6)), "a very", "read-only strSub() works");
    }

    // *****************************************************************************************************************************
    if (testBegin("strBase() and strPath()"))
    {
        TEST_RESULT_STR(strPtr(strBase(STRDEF(""))), "", "empty string");
        TEST_RESULT_STR(strPtr(strBase(STRDEF("/"))), "", "/ only");
        TEST_RESULT_STR(strPtr(strBase(STRDEF("/file"))), "file", "root file");
        TEST_RESULT_STR(strPtr(strBase(STRDEF("/dir1/dir2/file"))), "file", "subdirectory file");

        TEST_RESULT_STR(strPtr(strPath(STRDEF(""))), "", "empty string");
        TEST_RESULT_STR(strPtr(strPath(STRDEF("/"))), "/", "/ only");
        TEST_RESULT_STR(strPtr(strPath(STRDEF("/file"))), "/", "root path");
        TEST_RESULT_STR(strPtr(strPath(STRDEF("/dir1/dir2/file"))), "/dir1/dir2", "subdirectory file");
    }

    // *****************************************************************************************************************************
    if (testBegin("strCat(), strCatChr(), and strCatFmt()"))
    {
        String *string = strNew("XXXX");
        String *string2 = strNew("ZZZZ");

        TEST_RESULT_STR(strPtr(strCat(string, "YYYY")), "XXXXYYYY", "cat string");
        TEST_RESULT_SIZE(string->extra, 4, "check extra");
        TEST_RESULT_STR(strPtr(strCatFmt(string, "%05d", 777)), "XXXXYYYY00777", "cat formatted string");
        TEST_RESULT_SIZE(string->extra, 6, "check extra");
        TEST_RESULT_STR(strPtr(strCatChr(string, '!')), "XXXXYYYY00777!", "cat chr");
        TEST_RESULT_SIZE(string->extra, 5, "check extra");

        TEST_RESULT_STR(strPtr(string2), "ZZZZ", "check unaltered string");
    }

    // *****************************************************************************************************************************
    if (testBegin("strDup()"))
    {
        const String *string = STRDEF("duplicated string");
        String *stringDup = strDup(string);
        TEST_RESULT_STR(strPtr(stringDup), strPtr(string), "duplicated strings match");

        TEST_RESULT_PTR(strDup(NULL), NULL, "duplicate null string");
    }

    // *****************************************************************************************************************************
    if (testBegin("strBeginsWith() and strBeginsWithZ()"))
    {
        TEST_RESULT_BOOL(strBeginsWith(STRDEF(""), STRDEF("aaa")), false, "empty string");
        TEST_RESULT_BOOL(strBeginsWith(STRDEF("astring"), STRDEF("")), true, "empty begins with");
        TEST_RESULT_BOOL(strBeginsWithZ(STRDEF("astring"), "astr"), true, "partial begins with");
        TEST_RESULT_BOOL(strBeginsWithZ(STRDEF("astring"), "astring"), true, "equal strings");
    }

    // *****************************************************************************************************************************
    if (testBegin("strEndsWith() and strEndsWithZ()"))
    {
        TEST_RESULT_BOOL(strEndsWith(STRDEF(""), STRDEF(".doc")), false, "empty string");
        TEST_RESULT_BOOL(strEndsWith(STRDEF("astring"), STRDEF("")), true, "empty ends with");
        TEST_RESULT_BOOL(strEndsWithZ(STRDEF("astring"), "ing"), true, "partial ends with");
        TEST_RESULT_BOOL(strEndsWithZ(STRDEF("astring"), "astring"), true, "equal strings");
    }

    // *****************************************************************************************************************************
    if (testBegin("strEq(), strEqZ(), strCmp(), strCmpZ()"))
    {
        TEST_RESULT_BOOL(strEq(STRDEF("equalstring"), STRDEF("equalstring")), true, "strings equal");
        TEST_RESULT_BOOL(strEq(STRDEF("astring"), STRDEF("anotherstring")), false, "strings not equal");
        TEST_RESULT_BOOL(strEq(STRDEF("astring"), STRDEF("bstring")), false, "equal length strings not equal");

        TEST_RESULT_INT(strCmp(STRDEF("equalstring"), STRDEF("equalstring")), 0, "strings equal");
        TEST_RESULT_INT(strCmp(STRDEF("a"), STRDEF("b")), -1, "a < b");
        TEST_RESULT_INT(strCmp(STRDEF("b"), STRDEF("a")), 1, "b > a");

        TEST_RESULT_BOOL(strEqZ(STRDEF("equalstring"), "equalstring"), true, "strings equal");
        TEST_RESULT_BOOL(strEqZ(STRDEF("astring"), "anotherstring"), false, "strings not equal");
        TEST_RESULT_BOOL(strEqZ(STRDEF("astring"), "bstring"), false, "equal length strings not equal");

        TEST_RESULT_INT(strCmpZ(STRDEF("equalstring"), "equalstring"), 0, "strings equal");
        TEST_RESULT_INT(strCmpZ(STRDEF("a"), "b"), -1, "a < b");
        TEST_RESULT_INT(strCmpZ(STRDEF("b"), "a"), 1, "b > a");
    }

    // *****************************************************************************************************************************
    if (testBegin("strFirstUpper(), strFirstLower(), strUpper(), strLower()"))
    {
        TEST_RESULT_STR(strPtr(strFirstUpper(strNew(""))), "", "empty first upper");
        TEST_RESULT_STR(strPtr(strFirstUpper(strNew("aaa"))), "Aaa", "first upper");
        TEST_RESULT_STR(strPtr(strFirstUpper(strNew("Aaa"))), "Aaa", "first already upper");

        TEST_RESULT_STR(strPtr(strFirstLower(strNew(""))), "", "empty first lower");
        TEST_RESULT_STR(strPtr(strFirstLower(strNew("AAA"))), "aAA", "first lower");
        TEST_RESULT_STR(strPtr(strFirstLower(strNew("aAA"))), "aAA", "first already lower");

        TEST_RESULT_STR(strPtr(strLower(strNew("K123aBc"))), "k123abc", "all lower");
        TEST_RESULT_STR(strPtr(strLower(strNew("k123abc"))), "k123abc", "already lower");
        TEST_RESULT_STR(strPtr(strLower(strNew("C"))), "c", "char lower");
        TEST_RESULT_STR(strPtr(strLower(strNew(""))), "", "empty lower");

        TEST_RESULT_STR(strPtr(strUpper(strNew("K123aBc"))), "K123ABC", "all upper");
        TEST_RESULT_STR(strPtr(strUpper(strNew("K123ABC"))), "K123ABC", "already upper");
        TEST_RESULT_STR(strPtr(strUpper(strNew("c"))), "C", "char upper");
        TEST_RESULT_STR(strPtr(strUpper(strNew(""))), "", "empty upper");
    }

    // *****************************************************************************************************************************
    if (testBegin("strQuote()"))
    {
        TEST_RESULT_STR(strPtr(strQuote(STRDEF("abcd"), STRDEF("'"))), "'abcd'", "quote string");
    }

    // *****************************************************************************************************************************
    if (testBegin("strReplaceChr()"))
    {
        TEST_RESULT_STR(strPtr(strReplaceChr(strNew("ABCD"), 'B', 'R')), "ARCD", "replace chr");
    }

    // *****************************************************************************************************************************
    if (testBegin("strSub() and strSubN()"))
    {
        TEST_RESULT_STR(strPtr(strSub(STRDEF("ABCD"), 2)), "CD", "sub string");
        TEST_RESULT_STR(strPtr(strSubN(STRDEF("ABCD"), 1, 2)), "BC", "sub string with length");
    }

    // *****************************************************************************************************************************
    if (testBegin("strTrim()"))
    {
        TEST_RESULT_STR(strPtr(strTrim(strNew(""))), "", "trim empty");
        TEST_RESULT_STR(strPtr(strTrim(strNew("X"))), "X", "no trim (one char)");
        TEST_RESULT_STR(strPtr(strTrim(strNew("no-trim"))), "no-trim", "no trim (string)");
        TEST_RESULT_STR(strPtr(strTrim(strNew(" \t\r\n"))), "", "all whitespace");
        TEST_RESULT_STR(strPtr(strTrim(strNew(" \tbegin-only"))), "begin-only", "trim begin");
        TEST_RESULT_STR(strPtr(strTrim(strNew("end-only\t "))), "end-only", "trim end");
        TEST_RESULT_STR(strPtr(strTrim(strNew("\n\rboth\r\n"))), "both", "trim both");
        TEST_RESULT_STR(strPtr(strTrim(strNew("begin \r\n\tend"))), "begin \r\n\tend", "ignore whitespace in middle");
    }

    // *****************************************************************************************************************************
    if (testBegin("strChr() and strTrunc()"))
    {
        TEST_RESULT_INT(strChr(STRDEF("abcd"), 'c'), 2, "c found");
        TEST_RESULT_INT(strChr(STRDEF("abcd"), 'C'), -1, "capital C not found");
        TEST_RESULT_INT(strChr(STRDEF("abcd"), 'i'), -1, "i not found");
        TEST_RESULT_INT(strChr(STRDEF(""), 'x'), -1, "empty string - x not found");

        String *val = strNew("abcdef");
        TEST_ERROR(
            strTrunc(val, (int)(strSize(val) + 1)), AssertError,
            "assertion 'idx >= 0 && (size_t)idx <= this->size' failed");
        TEST_ERROR(strTrunc(val, -1), AssertError, "assertion 'idx >= 0 && (size_t)idx <= this->size' failed");

        TEST_RESULT_STR(strPtr(strTrunc(val, strChr(val, 'd'))), "abc", "simple string truncated");
        strCat(val, "\r\n to end");
        TEST_RESULT_STR(strPtr(strTrunc(val, strChr(val, 'n'))), "abc\r\n to e", "complex string truncated");
        TEST_RESULT_STR(strPtr(strTrunc(val, strChr(val, 'a'))), "", "complete string truncated - empty string");

        TEST_RESULT_INT(strSize(val), 0, "0 size");
        TEST_RESULT_STR(strPtr(strTrunc(val, 0)), "", "test coverage of empty string - no error thrown for index 0");
    }

    // *****************************************************************************************************************************
    if (testBegin("strToLog() and strObjToLog()"))
    {
        TEST_RESULT_STR(strPtr(strToLog(STRDEF("test"))), "{\"test\"}", "format string");
        TEST_RESULT_STR(strPtr(strToLog(NULL)), "null", "format null string");

        char buffer[256];
        TEST_RESULT_UINT(strObjToLog(NULL, (StrObjToLogFormat)strToLog, buffer, sizeof(buffer)), 4, "format null string");
        TEST_RESULT_STR(buffer, "null", "check null string");

        TEST_RESULT_UINT(strObjToLog(STRDEF("teststr"), (StrObjToLogFormat)strToLog, buffer, sizeof(buffer)), 11, "format string");
        TEST_RESULT_STR(buffer, "{\"teststr\"}", "check string");
    }

    // *****************************************************************************************************************************
    if (testBegin("strSizeFormat()"))
    {
        TEST_RESULT_STR(strPtr(strSizeFormat(0)), "0B", "zero bytes");
        TEST_RESULT_STR(strPtr(strSizeFormat(1023)), "1023B", "1023 bytes");
        TEST_RESULT_STR(strPtr(strSizeFormat(1024)), "1KB", "1 KB");
        TEST_RESULT_STR(strPtr(strSizeFormat(2200)), "2.1KB", "2.1 KB");
        TEST_RESULT_STR(strPtr(strSizeFormat(1048576)), "1MB", "1 MB");
        TEST_RESULT_STR(strPtr(strSizeFormat(20162900)), "19.2MB", "19.2 MB");
        TEST_RESULT_STR(strPtr(strSizeFormat(1073741824)), "1GB", "1 GB");
        TEST_RESULT_STR(strPtr(strSizeFormat(1073741824 + 107374183)), "1.1GB", "1.1 GB");
        TEST_RESULT_STR(strPtr(strSizeFormat(UINT64_MAX)), "17179869183GB", "uint64 max");
    }

    // *****************************************************************************************************************************
    if (testBegin("strLstNew(), strLstAdd*(), strLstGet(), strLstMove(), strLstSize(), and strLstFree()"))
    {
        // Add strings to the list
        // -------------------------------------------------------------------------------------------------------------------------
        StringList *list = NULL;

        MEM_CONTEXT_TEMP_BEGIN()
        {
            list = strLstNew();

            for (int listIdx = 0; listIdx <= LIST_INITIAL_SIZE; listIdx++)
            {
                if (listIdx == 0)
                {
                    TEST_RESULT_PTR(strLstAdd(list, NULL), list, "add null item");
                }
                else
                    TEST_RESULT_PTR(strLstAdd(list, strNewFmt("STR%02d", listIdx)), list, "add item %d", listIdx);
            }

            strLstMove(list, MEM_CONTEXT_OLD());
        }
        MEM_CONTEXT_TEMP_END();

        TEST_RESULT_INT(strLstSize(list), 9, "list size");

        // Read them back and check values
        // -------------------------------------------------------------------------------------------------------------------------
        for (unsigned int listIdx = 0; listIdx < strLstSize(list); listIdx++)
        {
            if (listIdx == 0)
            {
                TEST_RESULT_PTR(strLstGet(list, listIdx), NULL, "check null item");
            }
            else
                TEST_RESULT_STR(strPtr(strLstGet(list, listIdx)), strPtr(strNewFmt("STR%02u", listIdx)), "check item %u", listIdx);
        }

        TEST_RESULT_VOID(strLstFree(list), "free string list");
        TEST_RESULT_VOID(strLstFree(NULL), "free null string list");
    }
Exemple #9
0
    char        main_input[FNAME_LEN];
    liststate_t *cur_state;
    liststate_t  main_state;
    unsigned int blockdepth;
    unsigned int pagenum;
    unsigned int nlines;
    int          require_depth;
    int          haveabuf;
    size_t       linelen;
    char         header1[132];
    char         header2[132];
    char         linebuf[132];
};

static strdesc_t loptswitch[LISTOPT_COUNT] = {
    STRDEF("SOURCE"), STRDEF("REQUIRE"), STRDEF("EXPAND"), STRDEF("TRACE"),
    STRDEF("LIBRARY"), STRDEF("OBJECT"), STRDEF("ASSEMBLY"), STRDEF("SYMBOLIC"),
    STRDEF("BINARY"), STRDEF("COMMENTARY")
};

static lextype_t lopt_lextypes[] = {
    LEXTYPE_NAME_TOGGLE_OFF, LEXTYPE_NAME_TOGGLE_ON,
    LEXTYPE_DCL_REQUIRE, LEXTYPE_DCL_LIBRARY
};

static int
listopt_handler (parse_ctx_t pctx, void *vctx, int togidx, lextype_t dtype, name_t *togname)
{
    lstgctx_t ctx = vctx;
    int set_on = (name_type(togname) == LEXTYPE_NAME_TOGGLE_ON);