Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions

stringutils.c File Reference

#include "postgres_fe.h"
#include <ctype.h>
#include "common.h"
#include "stringutils.h"
Include dependency graph for stringutils.c:

Go to the source code of this file.

Functions

char * strtokx (const char *s, const char *whitespace, const char *delim, const char *quote, char escape, bool e_strings, bool del_quotes, int encoding)
void strip_quotes (char *source, char quote, char escape, int encoding)
char * quote_if_needed (const char *source, const char *entails_quote, char quote, char escape, int encoding)

Function Documentation

char* quote_if_needed ( const char *  source,
const char *  entails_quote,
char  quote,
char  escape,
int  encoding 
)

Definition at line 291 of file stringutils.c.

References Assert, free, i, NULL, pg_malloc(), and PQmblen().

{
    const char *src;
    char       *ret;
    char       *dst;
    bool        need_quotes = false;

    Assert(source != NULL);
    Assert(quote != '\0');

    src = source;
    dst = ret = pg_malloc(2 * strlen(src) + 3); /* excess */

    *dst++ = quote;

    while (*src)
    {
        char        c = *src;
        int         i;

        if (c == quote)
        {
            need_quotes = true;
            *dst++ = quote;
        }
        else if (c == escape)
        {
            need_quotes = true;
            *dst++ = escape;
        }
        else if (strchr(entails_quote, c))
            need_quotes = true;

        i = PQmblen(src, encoding);
        while (i--)
            *dst++ = *src++;
    }

    *dst++ = quote;
    *dst = '\0';

    if (!need_quotes)
    {
        free(ret);
        ret = NULL;
    }

    return ret;
}

void strip_quotes ( char *  source,
char  quote,
char  escape,
int  encoding 
)

Definition at line 240 of file stringutils.c.

References Assert, i, NULL, and PQmblen().

Referenced by parse_slash_copy(), and strtokx().

{
    char       *src;
    char       *dst;

    Assert(source != NULL);
    Assert(quote != '\0');

    src = dst = source;

    if (*src && *src == quote)
        src++;                  /* skip leading quote */

    while (*src)
    {
        char        c = *src;
        int         i;

        if (c == quote && src[1] == '\0')
            break;              /* skip trailing quote */
        else if (c == quote && src[1] == quote)
            src++;              /* process doubled quote */
        else if (c == escape && src[1] != '\0')
            src++;              /* process escaped character */

        i = PQmblen(src, encoding);
        while (i--)
            *dst++ = *src++;
    }

    *dst = '\0';
}

char* strtokx ( const char *  s,
const char *  whitespace,
const char *  delim,
const char *  quote,
char  escape,
bool  e_strings,
bool  del_quotes,
int  encoding 
)

Definition at line 52 of file stringutils.c.

References free, memmove, pg_malloc(), PQmblen(), and strip_quotes().

Referenced by parse_slash_copy().

{
    static char *storage = NULL;/* store the local copy of the users string
                                 * here */
    static char *string = NULL; /* pointer into storage where to continue on
                                 * next call */

    /* variously abused variables: */
    unsigned int offset;
    char       *start;
    char       *p;

    if (s)
    {
        free(storage);

        /*
         * We may need extra space to insert delimiter nulls for adjacent
         * tokens.  2X the space is a gross overestimate, but it's unlikely
         * that this code will be used on huge strings anyway.
         */
        storage = pg_malloc(2 * strlen(s) + 1);
        strcpy(storage, s);
        string = storage;
    }

    if (!storage)
        return NULL;

    /* skip leading whitespace */
    offset = strspn(string, whitespace);
    start = &string[offset];

    /* end of string reached? */
    if (*start == '\0')
    {
        /* technically we don't need to free here, but we're nice */
        free(storage);
        storage = NULL;
        string = NULL;
        return NULL;
    }

    /* test if delimiter character */
    if (delim && strchr(delim, *start))
    {
        /*
         * If not at end of string, we need to insert a null to terminate the
         * returned token.  We can just overwrite the next character if it
         * happens to be in the whitespace set ... otherwise move over the
         * rest of the string to make room.  (This is why we allocated extra
         * space above).
         */
        p = start + 1;
        if (*p != '\0')
        {
            if (!strchr(whitespace, *p))
                memmove(p + 1, p, strlen(p) + 1);
            *p = '\0';
            string = p + 1;
        }
        else
        {
            /* at end of string, so no extra work */
            string = p;
        }

        return start;
    }

    /* check for E string */
    p = start;
    if (e_strings &&
        (*p == 'E' || *p == 'e') &&
        p[1] == '\'')
    {
        quote = "'";
        escape = '\\';          /* if std strings before, not any more */
        p++;
    }

    /* test if quoting character */
    if (quote && strchr(quote, *p))
    {
        /* okay, we have a quoted token, now scan for the closer */
        char        thisquote = *p++;

        for (; *p; p += PQmblen(p, encoding))
        {
            if (*p == escape && p[1] != '\0')
                p++;            /* process escaped anything */
            else if (*p == thisquote && p[1] == thisquote)
                p++;            /* process doubled quote */
            else if (*p == thisquote)
            {
                p++;            /* skip trailing quote */
                break;
            }
        }

        /*
         * If not at end of string, we need to insert a null to terminate the
         * returned token.  See notes above.
         */
        if (*p != '\0')
        {
            if (!strchr(whitespace, *p))
                memmove(p + 1, p, strlen(p) + 1);
            *p = '\0';
            string = p + 1;
        }
        else
        {
            /* at end of string, so no extra work */
            string = p;
        }

        /* Clean up the token if caller wants that */
        if (del_quotes)
            strip_quotes(start, thisquote, escape, encoding);

        return start;
    }

    /*
     * Otherwise no quoting character.  Scan till next whitespace, delimiter
     * or quote.  NB: at this point, *start is known not to be '\0',
     * whitespace, delim, or quote, so we will consume at least one character.
     */
    offset = strcspn(start, whitespace);

    if (delim)
    {
        unsigned int offset2 = strcspn(start, delim);

        if (offset > offset2)
            offset = offset2;
    }

    if (quote)
    {
        unsigned int offset2 = strcspn(start, quote);

        if (offset > offset2)
            offset = offset2;
    }

    p = start + offset;

    /*
     * If not at end of string, we need to insert a null to terminate the
     * returned token.  See notes above.
     */
    if (*p != '\0')
    {
        if (!strchr(whitespace, *p))
            memmove(p + 1, p, strlen(p) + 1);
        *p = '\0';
        string = p + 1;
    }
    else
    {
        /* at end of string, so no extra work */
        string = p;
    }

    return start;
}