/** -*- 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 ); /*---------------------------------------------------------------------------- ** FUNCTION : macro_from_env ** ** DESCRIPTION : Get data from the users environment and process it ** as a macro ** ** ** INPUTS : str - output string ** s - input arguments ** ** RETURNS : length of arguments consumed ** ----------------------------------------------------------------------------*/ int macro_from_env(String_t *str, const char *s) { char varname[ 32 ]; int len = 0, len2; char *sp; if (expected(s++, ',') > 0 && (len2 = argument(s, varname, sizeof(varname))) > 0) { len = 1+len2, s += len2; sp = getenv(varname); if ( ! sp ) fatalerr( "Environment Variable not found: '%s'\n", varname ); verbose( " MacroEnvVar %s = %s", varname, sp ); process_string (sp); } return (len); } 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 if (strcasecmp( "envmacro", name ) == 0) len2 = macro_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); }