Subversion Repositories DevTools

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/** -*- mode: c; tabs: 4 -*- ************************************************
* Module name   : macro.c
* Module type   : CMDFILE source file
* Environment(s): n/a
*
* Description:
*
   Macro
*
* Version   Who     Date        Description
            APY     02/03/00    Created
            APY     14/03/00    Handle .. correctly
                    16/04/02    realpath() macro
                    26/04/04    argument() macro
                    05/10/04    vpath3, vlib3 and vglob3
                                pathargument
                                vsep and vhost
                                vlint
*
* $Source: /cvsroot/device/DEVL/UTILS/CMDFILE/macro.c,v $
* $Revision: 1.5 $ $Date: 2004/10/11 08:59:27 $ $State: Exp $
* $Author: ayoung $ $Locker:  $
*.........................................................................*/

#include "cmdfile.h"

static int              mlvl;                   /* macro level */

#define FSTRING         0x01
#define FEMBEDDEDSPACES 0x02

static int              nextword( int, const char *, char *, int );


int
macro( String_t *str, const char *s )
{
    char name[ 128 ];                           /* macro name */
    int len, len2;

/* macro name */
    mlvl++;
    if (*s != LDELIMITOR ||
            (len = token( s+1, name, sizeof(name) )) < 1) {
        StringPut( str, MACROCHAR );
        mlvl--;
        return (0);
    }
    len++;                                      /* include '(' */

    verbose(" [%d] Macro(%s)", mlvl, name);

/* invoke */
    if (strcasecmp( "vpath", name ) == 0 || strcasecmp( "vpath1", name ) == 0)
        len2 = vpath(str, s+len, VFLAG_PATH);

    else if (strcasecmp( "vpath2", name ) == 0)
        len2 = vpath(str, s+len, VFLAG_PATH|VFLAG_MUSTRESOLVE);

    else if (strcasecmp( "vpath3", name ) == 0)
        len2 = vpath(str, s+len, VFLAG_PATH|VFLAG_OPTIONAL);

    else if (strcasecmp( "vlib",  name ) == 0 || strcasecmp( "vlib1",  name ) == 0)
        len2 = vpath(str, s+len, VFLAG_LIBRARY);

    else if (strcasecmp( "vlib2", name ) == 0)
        len2 = vpath(str, s+len, VFLAG_LIBRARY|VFLAG_MUSTRESOLVE);

    else if (strcasecmp( "vlib3", name ) == 0)
        len2 = vpath(str, s+len, VFLAG_LIBRARY|VFLAG_OPTIONAL);

    else if (strcasecmp( "vlibgcc", name ) == 0)
        len2 = do_vlibgcc( str, s+len );

    else if (strcasecmp( "vhost", name ) == 0)
        len2 = do_vhost(s+len);

    else if (strcasecmp( "vsep", name ) == 0)
        len2 = do_vsep(s+len);

    else if (strcasecmp( "vglob",  name ) == 0 || strcasecmp( "vglob1",  name ) == 0)
        len2 = vpath(str, s+len, VFLAG_GLOB);

    else if (strcasecmp( "vglob2", name ) == 0)
        len2 = vpath(str, s+len, VFLAG_GLOB|VFLAG_MUSTRESOLVE);

    else if (strcasecmp( "vglob3", name ) == 0)
        len2 = vpath(str, s+len, VFLAG_GLOB|VFLAG_OPTIONAL);

    else if (strcasecmp( "vlint",  name ) == 0 || strcasecmp( "vlint1",  name ) == 0)
        len2 = vpath(str, s+len, VFLAG_LINT);

    else if (strcasecmp( "vlint2", name ) == 0)
        len2 = vpath(str, s+len, VFLAG_LINT|VFLAG_MUSTRESOLVE);

    else if (strcasecmp( "vlint3", name ) == 0)
        len2 = vpath(str, s+len, VFLAG_LINT|VFLAG_OPTIONAL);

    else if (strcasecmp( "dosify", name ) == 0)
        len2 = dosify(str, s+len);

    else if (strcasecmp( "sep", name ) == 0)
        len2 = do_clean_sep(str, s+len);
        
    else if (strcasecmp( "realpath", name ) == 0)
        len2 = do_realpath(str, s+len);

    else if (strcasecmp( "shortpath", name ) == 0)
        len2 = do_shortpath(str, s+len);

    else if (strcasecmp( "url2path", name ) == 0)
        len2 = do_url2path(str, s+len);

    else if (strcasecmp( "path2url", name ) == 0)
        len2 = do_path2url(str, s+len);

    else if (strcasecmp( "env", name ) == 0)
        len2 = from_env(str, s+len);

    else
    {
        warning( "unknown macro '%s' -- ignored", name );
        len2 = 0;
    }

/* termination */
    if (len2 > 0 && expected(s+len+len2, RDELIMITOR) > 0)
    {
        verbose(" [%d] Macro(%s) ok = %s", mlvl, name, StringData(str));
        mlvl--;
        return (len+len2+1);
    }
    verbose(" [%d] Macro(%s) bad = %s", mlvl, name,
        (StringData(str) ? StringData(str) : "NULL") );

    StringPut(str, MACROCHAR);
    mlvl--;
    return (0);                                 /* echo invalid macro */
}


int
expected(
    const char *s, char c)
{
    if (*s != c) {
        if (*s == '\0')
            warning( "expected '%c', found end-of-file", c );
        else if (*s == '\n')
            warning( "expected '%c', found newline\n", c );
        else warning( "expected '%c', found '%c'\n", c, *s );
        return (0);
    }
    return (1);
}


/*
 *  token ---
 *      Retrieve the next stream word.
 */
int
token( const char *s, char *buf, int len )
{
    return nextword( 0, s, buf, len );
}


/*
 *  argument ---
 *      Retrieve the next stream word, allowing strings.
 */
int
argument( const char *s, char *buf, int len )
{
    return nextword( FSTRING, s, buf, len );
}


/*
 *  pathargument ---
 *      Retrieve the next stream word, allowing strings and
 *      embedded white-spaces.
 */
int
pathargument( const char *s, char *buf, int len )
{
    return nextword( FSTRING|FEMBEDDEDSPACES, s, buf, len );
}


/*
 *  nextword ---
 *      Retrieve the next stream word.
 *
 *  Returns:
 *      -1 on failure, otherwise the number of characters consumed.
 *
 *  Notes:
 *      The consumed count and resulting word length may differ if
 *      leading white space, quotes or strings are envcountered.
 */
static int
nextword( int flags, const register char *s, char *buf, int len )
{
    String_t mstr;                              /* macro buffer */
    int str, err, blen, sidx;                   /* token length */
    const char *os = s;
    char *p;

#define SIGNORE         0                       /* string parse status */
#define SALLOWED        1
#define SDOUBLE         2
#define SSINGLE         3

    if (flags & FSTRING)
        str = SALLOWED;
    else str = SIGNORE;

    for (err = sidx = blen = 0; !err; sidx++, s++)
    {
        if (*s == '\0')
        {
            warning( "unexpected end-of-string in token '%s' -- ignored", os );
            err = 1;
        }
        else if (*s == '\n')
        {
            warning( "unexpected new-line in token '%s' -- ignored", os );
            err = 1;
        }

    /* white space */
        else if (*s == ' ' || *s == '\t')
        {
            if (str == SDOUBLE || str == SSINGLE ||
                    (blen && *s == ' ' && (flags & FEMBEDDEDSPACES)) )
            {
                /*
                 *  Inside a string or embedded spaces are allowed.
                 */
                if (blen < len-1)
                    buf[ blen++ ] = *s;
                continue;                       /* embedded whitespace */

            } else if (blen) {
                break;                          /* end of token */
            }

            continue;                           /* consume leading white space */
        }

    /* macros */
        else if (*s == MACROCHAR && blen == 0)
        {
            register int mlen;                  /* macro length */

            StringInit( &mstr, NULL, MACRO_MAX );
            mlen = macro( &mstr, s+1 );         /* nested macro def */
            for (p = StringData(&mstr); *p; p++)
            {
                if (blen < len-1)
                    buf[ blen++ ] = *p;
            }
            free( StringData(&mstr) );
            sidx += mlen, s += mlen;            /* skip definition */
        }

        else if ((*s == RDELIMITOR || *s == ',') &&
                    (str == SIGNORE || str == SALLOWED))
        {
            break;                              /* end of token */
        }

    /* strings */
        else if (*s == '"' && (str == SALLOWED || str == SDOUBLE))
        {
            if (str == SDOUBLE) {
                sidx++, s++;
                break;                          /* end-of-string */
            }
            str = SDOUBLE;                      /* first character of string */
        }

        else if (*s == '\'' && (str == SALLOWED || str == SSINGLE))
        {
            if (str == SSINGLE) {
                sidx++, s++;
                break;                          /* end-of-string */
            }
            str = SSINGLE;                      /* first character of string */
        }

        else if (*s == '\\' && str > SALLOWED &&
                    (s[1] == '"' || s[1] == '\'' || s[1] == '\\'))
        {
            if (blen < len-1)
                buf[ blen++ ] = s[1];           /* quote next */
            sidx++, s++;
        }

    /* general */
        else if (blen < len-1)                  /* buffer overflow ? */
        {
            buf[ blen++ ] = *s;
        }
    }

    if (blen < len-1)                           /* terminate buffer */
        buf[ blen ] = '\0';
    else buf[ len-1 ] = '\0';

    if (vflg > 2)
        verbose( "  = [%d] token(%s) : %d", mlvl, buf, err ? -1 : sidx );

    return (err ? -1 : sidx);
}