summaryrefslogtreecommitdiff
path: root/dmake/macparse.c
diff options
context:
space:
mode:
Diffstat (limited to 'dmake/macparse.c')
-rw-r--r--dmake/macparse.c232
1 files changed, 232 insertions, 0 deletions
diff --git a/dmake/macparse.c b/dmake/macparse.c
new file mode 100644
index 000000000000..88db1230ec84
--- /dev/null
+++ b/dmake/macparse.c
@@ -0,0 +1,232 @@
+/* RCS $Id: macparse.c,v 1.3 2007-10-15 15:40:02 ihi Exp $
+--
+-- SYNOPSIS
+-- Parse a macro definition
+--
+-- DESCRIPTION
+-- This file contains the code that parses a macro definition
+-- stored in a buffer. If the string in buffer is not a valid
+-- macro definition the routie Parse_macro returns 0, otherwise it
+-- returns 1 to indicate success.
+--
+-- AUTHOR
+-- Dennis Vadura, dvadura@dmake.wticorp.com
+--
+-- WWW
+-- http://dmake.wticorp.com/
+--
+-- COPYRIGHT
+-- Copyright (c) 1996,1997 by WTI Corp. All rights reserved.
+--
+-- This program is NOT free software; you can redistribute it and/or
+-- modify it under the terms of the Software License Agreement Provided
+-- in the file <distribution-root>/readme/license.txt.
+--
+-- LOG
+-- Use cvs log to obtain detailed change logs.
+*/
+
+#include "extern.h"
+
+PUBLIC int
+Parse_macro( buffer, flag )/*
+=============================
+ Parse the string in buffer and define it as a macro if it is a valid macro.
+ Note especially the string .SETDIR= since it is an attribute, but looks a
+ lot like a macro definition. This would not be a problem if make used
+ white space as token separators, since this is not the case we must do
+ something about it. */
+char *buffer;
+int flag;
+{
+ char *result; /* temporary pointer for strings */
+ TKSTR input; /* place to scan the buffer from */
+ HASHPTR hv; /* pointer to hash table value */
+ int operator; /* what macro operator do we have */
+ char *tok1; /* temporary place to keep a token */
+ char *tok2; /* temporary place to keep a token */
+ int toklen; /* length of a token */
+
+ DB_ENTER( "Parse_macro" );
+
+ SET_TOKEN( &input, buffer );
+ tok1 = Get_token( &input, "=+:*!?", 0 );
+
+ operator=Macro_op(tok1);
+ if( operator ) {
+ CLEAR_TOKEN( &input );
+ Error( "Assignment without macro name: [%s].", buffer );
+ DB_RETURN( 1 );
+ }
+
+ tok1 = DmStrDup(tok1);
+ tok2 = Get_token( &input, "=+:*!?", 2 );
+ if( !(operator = Macro_op(tok2)) || !strcmp(tok1,".SETDIR") ) {
+ CLEAR_TOKEN( &input );
+ FREE(tok1);
+ DB_RETURN(0);
+ }
+
+ tok2 = Expand(tok1); FREE(tok1); tok1 = tok2;
+ if ( !(toklen = strlen(tok1)) ) {
+ Warning( "Empty macro name after expansion: [%s].", buffer );
+ }
+
+ /* Catch illegal single character macro names. */
+ if ( toklen == 1 && strchr("{()}", tok1[0]) ) {
+ CLEAR_TOKEN( &input );
+ Fatal( "Syntax error in macro assignment [%s]. The following characters cannot be used as single letter macro names: '{()}'.", buffer );
+ }
+
+ /* Catch ':' in macro names. */
+ if ( strchr(tok1, ':') ) {
+ CLEAR_TOKEN( &input );
+ Fatal( "Syntax error in macro assignment [%s]. The character ':' is not allowed in macro names.", buffer );
+ }
+
+ tok2 = Get_token(&input, NIL( char ), FALSE);
+
+ /* Make sure we can force the assignment. */
+ if ( operator & M_OP_SI ) {
+ flag |= M_FORCE|M_MULTI;
+ operator &= ~M_OP_SI;
+ }
+
+ switch( operator ) {
+ case M_OP_PLCL:
+ tok2 = Expand( tok2 );
+ /* Fall thru */
+
+ case M_OP_PL:
+ /* Add to an existing macro, if it is not defined, though, then
+ * just define a new macro */
+
+ if( (hv = GET_MACRO(tok1)) == NIL(HASH) || hv->ht_value == NIL(char) )
+ Def_macro( tok1, tok2, flag );
+ else {
+ result = DmStrAdd( hv->ht_value, tok2, FALSE );
+ Def_macro( tok1, result, flag );
+ FREE( result );
+ }
+ if( operator == M_OP_PLCL ) FREE(tok2);
+ break;
+
+ case M_OP_DF:
+ /* *= */
+ /* internal default macros or initialized empty macros set M_INIT. */
+ if( (hv = GET_MACRO(tok1)) != NIL(HASH) && !(hv->ht_flag & M_INIT) )
+ break;
+ /* else FALLTHRU */
+
+ case M_OP_EQ:
+ Def_macro( tok1, tok2, flag );
+ break;
+
+ case M_OP_DFCL:
+ /* *:= */
+ /* internal default macros or initialized empty macros set M_INIT. */
+ if( (hv = GET_MACRO(tok1)) != NIL(HASH) && !(hv->ht_flag & M_INIT) )
+ break;
+ /* else FALLTHRU */
+
+ case M_OP_CL:
+ tok2 = Expand( tok2 );
+ Def_macro( tok1, tok2, M_EXPANDED | flag );
+ FREE( tok2 );
+ break;
+
+ case M_OP_CM:{
+ CELLPTR cp;
+ STRINGPTR sp;
+
+ if (flag & M_PUSH) {
+ Error("Nested conditional definition [%s ?= %s] ignored",
+ tok1, tok2);
+ }
+ else {
+ cp = Def_cell(tok1);
+ if (cp->ce_flag & F_MULTI) {
+ LINKPTR lp;
+ for(lp=cp->ce_prq; lp->cl_next; lp=lp->cl_next);
+ cp = lp->cl_prq;
+ }
+ TALLOC(sp,1,STRING);
+ sp->st_string = DmStrDup(tok2);
+ sp->st_next = cp->ce_cond;
+ cp->ce_cond = sp;
+
+ tok1 = NIL(char);
+ }
+ }
+ break;
+ }
+
+ if (tok1) {
+ if ( LastMacName != NIL(char) )
+ FREE( LastMacName );
+
+ LastMacName = tok1;
+ }
+
+ DB_RETURN( 1 );
+}
+
+
+
+PUBLIC int
+Macro_op( op )/*
+================
+ Check the passed in op string and map it to one of the macro operators */
+char *op;
+{
+ int ret = 0;
+ DB_ENTER( "macro_op" );
+
+ if ( *op == '!' ) {
+ ret = M_OP_SI;
+ op++;
+ }
+
+ switch( *op ) {
+ case '=': ret |= M_OP_EQ; break;
+ case ':': ret |= M_OP_CL; op++; break;
+
+ case '+':
+ op++;
+ if( *op == ':' ) {
+ ret |= M_OP_PLCL;
+ op++;
+ }
+ else {
+ ret |= M_OP_PL;
+ }
+ break;
+
+ case '*':
+ op++;
+ if( *op == ':' ) {
+ ret |= M_OP_DFCL;
+ op++;
+ }
+ else {
+ ret |= M_OP_DF;
+ }
+ break;
+
+ case '?':
+ ret |= M_OP_CM;
+ op++;
+ break;
+ }
+
+ if( *op != '=' )
+ ret = 0;
+ else {
+ op++;
+
+ if( *op != '\0' )
+ ret = 0;
+ }
+
+ DB_RETURN( ret );
+}