summaryrefslogtreecommitdiff
path: root/dmake/getinp.c
diff options
context:
space:
mode:
authorJens-Heiner Rechtien <hr@openoffice.org>2000-09-22 14:33:37 +0000
committerJens-Heiner Rechtien <hr@openoffice.org>2000-09-22 14:33:37 +0000
commitb501a54cf959bc549810fb24ca6f9584dc5c9cf3 (patch)
treeb78fbbc5c0f6959529f2553e3bbb83b077eaa17c /dmake/getinp.c
parent17e0108b4e8d91f9acfe376ee231418830392460 (diff)
initial import
Diffstat (limited to 'dmake/getinp.c')
-rw-r--r--dmake/getinp.c671
1 files changed, 671 insertions, 0 deletions
diff --git a/dmake/getinp.c b/dmake/getinp.c
new file mode 100644
index 000000000000..7d2af1dc8e43
--- /dev/null
+++ b/dmake/getinp.c
@@ -0,0 +1,671 @@
+/* RCS $Id: getinp.c,v 1.1.1.1 2000-09-22 15:33:25 hr Exp $
+--
+-- SYNOPSIS
+-- Handle reading of input.
+--
+-- DESCRIPTION
+-- The code in this file reads the input from the specified stream
+-- into the provided buffer of size Buffer_size. In doing so it deletes
+-- comments. Comments are delimited by the #, and
+-- <nl> character sequences. An exception is \# which
+-- is replaced by # in the input. Line continuations are signalled
+-- at the end of a line and are recognized inside comments.
+-- The line continuation is always <\><nl>.
+--
+-- If the file to read is NIL(FILE) then the Get_line routine returns the
+-- next rule from the builtin rule table if there is one.
+--
+-- 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"
+
+#define IS_WHITE(A) ((A == ' ') || (A == '\t') || (A == '\n') || (A == '\r'))
+#define SCAN_WHITE(A) \
+ while( IS_WHITE(*A) ) A++;
+
+static int _is_conditional ANSI((char*));
+static int _handle_conditional ANSI((int, TKSTRPTR));
+
+static int rule_ind = 0; /* index of rule when reading Rule_tab */
+static int skip = FALSE; /* if true the skip input */
+
+
+PUBLIC int
+Get_line( buf, fil )/*
+======================
+ Read a line of input from the file stripping
+ off comments. The routine returns TRUE if EOF */
+char *buf;
+FILE *fil;
+{
+ extern char **Rule_tab;
+ register char *p;
+ register char *c;
+ char *q;
+ char *buf_org;
+ static int ignore = FALSE;
+ int cont = FALSE;
+ int pos = 0;
+ int res;
+ register char *tmp = NIL(char);
+
+ DB_ENTER( "Get_line" );
+
+ if( Skip_to_eof ) {
+ Skip_to_eof = FALSE;
+ rule_ind = 0;
+
+ if( Verbose & V_MAKE )
+ Warning("Ignoring remainder of file %s", Filename());
+
+ DB_RETURN(TRUE);
+ }
+
+ if( fil == NIL(FILE) ) {
+ /* Reading the internal rule table. Set the rule_index to zero.
+ * This way ReadEnvironment works as expected every time. */
+
+ while( (p = Rule_tab[ rule_ind++ ]) != NIL(char) )
+ /* The last test in this if *p != '~', handles the environment
+ * passing conventions used by MKS to pass arguments. We want to
+ * skip those environment entries. */
+ if( !Readenv || (Readenv && (strchr(p,'=') != NIL(char)) && *p!='~')){
+ strcpy( buf, p );
+
+ DB_PRINT( "io", ("Returning [%s]", buf) );
+ DB_RETURN( FALSE );
+ }
+
+ rule_ind = 0;
+
+ DB_PRINT( "io", ("Done Ruletab") );
+ DB_RETURN( TRUE );
+ }
+
+ buf_org = buf;
+
+do_again:
+ do {
+ p = buf+pos;
+ if(feof( fil ) || (fgets( p, Buffer_size-pos, fil ) == NIL(char)))
+ DB_RETURN( TRUE );
+
+#ifdef _MPW
+ if ( p[0] == 10 && p[1] == COMMENT_CHAR)
+ p[0] = ' ';
+#endif
+
+ Line_number++;
+
+ /* ignore input if ignore flag set and line ends in a continuation
+ character. */
+ q = p+strlen(p)-2;
+ if( q<p ) q=p;
+
+ /* ignore each RETURN at the end of a line before any further
+ * processing */
+ if( q[0] == '\r' && q[1] == '\n' ) {
+ q[0] = '\n';
+ q[1] = '\0';
+ q--;
+ }
+ /* you also have to deal with END_OF_FILE chars to process raw
+ * DOS-Files. Normally they are the last chars in file, but after
+ * working on these file with vi, there is an additional NEWLINE
+ * after the last END_OF_FILE. So if the second last char in the
+ * actual line is END_OF_FILE, you can skip the last char. Then
+ * you can search the line back until you find no more END_OF_FILE
+ * and nuke each you found by string termination. */
+ if( q[0] == '\032' )
+ q--;
+ while( q[1] == '\032' ) {
+ q[1] = '\0';
+ q--;
+ }
+
+ if( ignore ) {
+ if( q[0] != CONTINUATION_CHAR || q[1] != '\n' ) ignore = FALSE;
+ *p = '\0';
+ continue;
+ }
+
+ c = Do_comment(p, &q, Group || (*buf == '\t') || (Notabs && *buf ==' '));
+
+ /* Does the end of the line end in a continuation sequence? */
+
+ if( (q[0] == CONTINUATION_CHAR) && (q[1] == '\n')) {
+ /* If the continuation was at the end of a comment then ignore the
+ * next input line, (or lines until we get one ending in just <nl>)
+ * else it's a continuation, so build the input line from several
+ * text lines on input. The maximum size of this is governened by
+ * Buffer_size */
+ if( q != p && q[-1] == CONTINUATION_CHAR ) {
+ strcpy( q, q+1 );
+ q--;
+ cont = FALSE;
+ }
+ else if( c != NIL(char) )
+ ignore = TRUE;
+ else
+ cont = TRUE;
+ }
+ else {
+ cont = FALSE;
+ }
+
+ q = ( c == NIL(char) ) ? q+2 : c;
+ pos += q-p;
+ }
+ while( (cont || !*buf) && (pos <= Buffer_size) );
+
+ if( buf[ pos-1 ] == '\n' )
+ buf[ --pos ] = '\0';
+ else
+ if( pos == Buffer_size-1 )
+ Fatal( "Input line too long, increase MAXLINELENGTH" );
+
+ /* STUPID AUGMAKE uses "include" at the start of a line as
+ * a signal to include a new file, so let's look for it.
+ * if we see it replace it by .INCLUDE: and stick this back
+ * into the buffer. We also allow GNU make if[n]eq/else/endif.
+ *
+ * These substitutions are made only if we are not parsing a group
+ * recipe. */
+ if( (p = DmStrSpn(buf, " \t\r\n")) == NIL(char) )
+ p = buf;
+
+ if (!Group) {
+ if( !strncmp( "include", p, 7 ) &&
+ (p[7] == ' ' || p[7] == '\t') )
+ tmp = DmStrJoin( ".INCLUDE:", p+7, -1, FALSE );
+ else if( !strncmp( "ifeq", p, 4 ) &&
+ (p[4] == ' ' || p[4] == '\t') )
+ tmp = DmStrJoin( ".IFEQ", p+4, -1, FALSE );
+ else if( !strncmp( "ifneq", p, 5 ) &&
+ (p[5] == ' ' || p[5] == '\t') )
+ tmp = DmStrJoin( ".IFNEQ", p+5, -1, FALSE );
+ else if( !strncmp( "elif", p, 4 ) &&
+ (p[4] == ' ' || p[4] == '\t') )
+ tmp = DmStrJoin( ".ELIF", p+4, -1, FALSE );
+ else if( !strncmp( "else", p, 4 ) &&
+ (p[4] == ' ' || p[4] == '\t' || p[4] == '\0') )
+ tmp = DmStrJoin( ".ELSE", p+4, -1, FALSE );
+ else if( !strncmp( "endif", p, 5 ) &&
+ (p[5] == ' ' || p[5] == '\t' || p[5] == '\0') )
+ tmp = DmStrJoin( ".END", p+5, -1, FALSE );
+ }
+
+ if( tmp != NIL(char)) {
+ strcpy( buf, tmp );
+ FREE( tmp );
+ tmp = NIL(char);
+ }
+
+ /* Now that we have the next line of input to make, we should check to
+ * see if it is a conditional expression. If it is then process it,
+ * otherwise pass it on to the parser. */
+
+ if( *(p = DmStrSpn(buf, " \t\r\n")) == CONDSTART ) {
+ TKSTR token;
+
+ SET_TOKEN( &token, p );
+
+ p = Get_token( &token, "", FALSE );
+
+ if( (res = _is_conditional(p)) != 0 ) /* ignore non-control special */
+ { /* targets */
+ res = _handle_conditional( res, &token );
+ skip = TRUE;
+ }
+ else {
+ CLEAR_TOKEN( &token );
+ res = TRUE;
+ }
+ }
+
+ if( skip ) {
+ buf = buf_org; /* ignore line just read in */
+ pos = 0;
+ skip = res;
+ goto do_again;
+ }
+
+ DB_PRINT( "io", ("Returning [%s]", buf) );
+ DB_RETURN( FALSE );
+}
+
+
+PUBLIC char *
+Do_comment(str, pend, keep)/*
+=============================
+ Search the input string looking for comment chars. If it contains
+ comment chars then NUKE the remainder of the line, if the comment
+ char is preceeded by \ then shift the remainder of the line left
+ by one char. */
+char *str;
+char **pend;
+int keep;
+{
+ char *c = str;
+
+ while( (c = strchr(c, COMMENT_CHAR)) != NIL(char) ) {
+ if( Comment || State == NORMAL_SCAN )
+ if( c != str && c[-1] == ESCAPE_CHAR ) {
+ strcpy( c-1, c ); /* copy it left, due to \# */
+ if( pend ) (*pend)--; /* shift tail pointer left */
+ }
+ else {
+ if( !No_exec
+ && c == str
+ && c[1] == '!'
+ && Line_number == 1
+ && Nestlevel() == 1 ) {
+ char *cmnd;
+
+ cmnd = Expand(c+2);
+ cmnd[strlen(cmnd)-1] = '\0'; /* strip last newline */
+ Current_target = Root;
+ Swap_on_exec = TRUE;
+ Wait_for_completion = TRUE;
+ Do_cmnd(cmnd, FALSE, TRUE, Current_target, FALSE, FALSE, TRUE);
+ }
+
+ *c = '\0'; /* a true comment so break */
+ break;
+ }
+ else {
+ if( keep )
+ c = NIL(char);
+ else
+ *c = '\0';
+
+ break;
+ }
+ }
+
+ return(c);
+}
+
+
+PUBLIC char *
+Get_token( string, brk, anchor )/*
+==================================
+ Return the next token in string.
+
+ Returns empty string when no more tokens in string.
+ brk is a list of chars that also cause breaks in addition to space and
+ tab, but are themselves returned as tokens. if brk is NULL then the
+ remainder of the line is returned as a single token.
+
+ 'anchor' if 1, says break on chars in the brk list, but only if
+ the entire token begins with the first char of the brk list, if
+ 0 then any char of brk will cause a break to occurr.
+
+ If 'anchor' is 2, then break only seeing the first char in the break
+ list allowing only chars in the break list to form the prefix. */
+
+TKSTRPTR string;
+char *brk;
+int anchor;
+{
+ register char *s;
+ register char *curp;
+ register char *t;
+ int done = FALSE;
+ char space[100];
+
+ DB_ENTER( "Get_token" );
+
+ s = string->tk_str; /* Get string parameters */
+ *s = string->tk_cchar; /* ... and strip leading w/s */
+
+ SCAN_WHITE( s );
+
+ DB_PRINT( "tok", ("What's left [%s]", s) );
+
+ if( !*s ) {
+ DB_PRINT( "tok", ("Returning NULL token") );
+ DB_RETURN( "" );
+ }
+
+
+ /* Build the space list. space contains all those chars that may possibly
+ * cause breaks. This includes the brk list as well as white space. */
+
+ if( brk != NIL(char) ) {
+ strcpy( space, " \t\r\n" );
+ strcat( space, brk );
+ }
+ else {
+ space[0] = 0xff; /* a char we know will not show up */
+ space[1] = 0;
+ }
+
+
+ /* Handle processing of quoted tokens. Note that this is disabled if
+ * brk is equal to NIL */
+
+ while( *s == '\"' && ((brk != NIL(char)) || !string->tk_quote) ) {
+ s++;
+ if( string->tk_quote ) {
+ curp = s-1;
+ do { curp = strchr( curp+1, '\"' ); }
+ while( (curp != NIL(char)) && (*(curp+1) == '\"'));
+
+ if( curp == NIL(char) ) Fatal( "Unmatched quote in token" );
+ string->tk_quote = !string->tk_quote;
+
+ /* Check for "" case, and if found ignore it */
+ if( curp == s ) continue;
+ goto found_token;
+ }
+ else
+ SCAN_WHITE( s );
+
+ string->tk_quote = !string->tk_quote;
+ }
+
+
+ /* Check for a token break character at the beginning of the token.
+ * If found return the next set of break chars as a token. */
+
+ if( anchor == 2 && brk != NIL(char) ) {
+ curp = s;
+ while( *curp && (strchr(brk,*curp)!=NIL(char)) && (*curp!=*brk) ) curp++;
+ done = (*brk == *curp++);
+ }
+ else if( (brk != NIL(char)) && (strchr( brk, *s ) != NIL(char)) ) {
+ curp = DmStrSpn( s, brk );
+ done = (anchor == 0) ? TRUE :
+ ((anchor == 1)?(*s == *brk) : (*brk == curp[-1]));
+ }
+
+
+ /* Scan for the next token in the list and return it less the break char
+ * that was used to terminate the token. It will possibly be returned in
+ * the next call to Get_token */
+
+ if( !done ) {
+ SCAN_WHITE( s );
+
+ t = s;
+ do {
+ done = TRUE;
+ curp = DmStrPbrk(t, space);
+
+ if( anchor && *curp && !IS_WHITE( *curp ) )
+ if( ((anchor == 1)?*curp:DmStrSpn(curp,brk)[-1]) != *brk ) {
+ t++;
+ done = FALSE;
+ }
+ }
+ while( !done );
+
+ if( (curp == s) && (strchr(brk, *curp) != NIL(char)) ) curp++;
+ }
+
+found_token:
+ string->tk_str = curp;
+ string->tk_cchar = *curp;
+ *curp = '\0';
+
+ DB_PRINT( "tok", ("Returning [%s]", s) );
+ DB_RETURN( s );
+}
+
+
+static int
+_is_conditional( tg )/*
+=======================
+ Look at tg and return it's value if it is a conditional identifier
+ otherwise return 0. */
+char *tg;
+{
+ DB_ENTER( "_is_conditional" );
+
+ tg++;
+ switch( *tg ) {
+ case 'I': if( !strcmp( tg, "IF" )) DB_RETURN( ST_IF );
+ else if( !strcmp( tg, "IFEQ" )) DB_RETURN( ST_IFEQ );
+ else if( !strcmp( tg, "IFNEQ" )) DB_RETURN( ST_IFNEQ ); break;
+
+ case 'E':
+ if( !strcmp( tg, "END" )) DB_RETURN( ST_END );
+ else if( !strcmp( tg, "ENDIF")) DB_RETURN( ST_END );
+ else if( !strcmp( tg, "ELSE" )) DB_RETURN( ST_ELSE );
+ else if( !strcmp( tg, "ELIF" )) DB_RETURN( ST_ELIF );
+ break;
+ }
+
+ DB_RETURN( 0 );
+}
+
+
+
+#define SEEN_END 0x00
+#define SEEN_IF 0x01
+#define SEEN_ELSE 0x02
+#define SEEN_ELIF 0x04
+
+#define ACCEPT_IF 0x10
+#define ACCEPT_ELIF 0x20
+
+static int
+_handle_conditional( opcode, tg )/*
+===================================
+ Perform the necessary processing for .IF conditinal targets.
+ Someday this should be modified to do bracketted expressions ala
+ CPP... sigh */
+int opcode;
+TKSTRPTR tg;
+{
+ static short action[MAX_COND_DEPTH];
+ static char ifcntl[MAX_COND_DEPTH];
+ char *tok, *lhs, *rhs, *op, *expr;
+ char *lop, *partstr;
+ int result, n, m;
+
+ DB_ENTER( "_handle_conditional" );
+
+ switch( opcode ) {
+ case ST_ELIF:
+ if( !(ifcntl[Nest_level] & SEEN_IF) || (ifcntl[Nest_level]&SEEN_ELSE) )
+ Fatal(".ELIF without a preceeding .IF" );
+ /*FALLTHRU*/
+
+ case ST_IF:
+ case ST_IFEQ:
+ case ST_IFNEQ:
+ if( opcode != ST_ELIF && (Nest_level+1) == MAX_COND_DEPTH )
+ Fatal( ".IF .ELSE ... .END nesting too deep" );
+
+ If_expand = TRUE;
+ expr = Expand( Get_token( tg, NIL(char), FALSE ));
+ If_expand = FALSE;
+ lhs = DmStrSpn( expr, " \t" );
+ if( !*lhs ) lhs = NIL(char);
+
+ if ( (lop = DmStrStr(lhs, "&&" )) != NIL(char) )
+ Fatal( ".IF do not support && " );
+ if ( (lop = DmStrStr(lhs, "defined" )) != NIL(char) )
+ Fatal( ".IF do not support defined " );
+ if ( (lop = DmStrStr(lhs, "DEFINED" )) != NIL(char) )
+ Fatal( ".IF do not support defined " );
+/*-----------------18.03.99 14:38-------------------
+ * hjs - simple OR fixed and less code
+--------------------------------------------------*/
+ if ( (lop = DmStrStr(lhs, "||" )) != NIL(char) )
+ {
+/* printf("todo: %s\n", expr ); */
+ partstr = MALLOC( strlen (lhs ) + 5, char);
+ result = FALSE;
+ while(( lop = DmStrStr(lhs, "||" )) != NIL(char) )
+ {
+ n = strlen( lop );
+ m = strlen( lhs );
+ strncpy( partstr, lhs, m - n );
+ partstr[ m - n ] = '\0';
+ result |= partcomp( partstr, opcode);
+ lhs = lop+2;
+ lhs = DmStrSpn( lhs, " \t" );
+ }
+ result |= partcomp( lhs, opcode );
+/*
+ if ( result )
+ printf("TRUE\n\n");
+ else
+ printf("false\n\n");
+ FREE( partstr );
+*/
+ }
+/*--------------------------------------------------*/
+ else
+ result = partcomp( lhs, opcode );
+
+ if( expr != NIL(char) ) FREE( expr );
+
+ if( opcode != ST_ELIF ) {
+ Nest_level++;
+ action[Nest_level] = 1;
+ }
+ ifcntl[Nest_level] |= (opcode==ST_ELIF)?SEEN_ELIF:SEEN_IF;
+
+ if( result ) {
+ if( !(ifcntl[Nest_level] & (ACCEPT_IF|ACCEPT_ELIF)) ) {
+ action[ Nest_level ] = action[ Nest_level-1 ];
+ ifcntl[Nest_level] |= (opcode==ST_ELIF)?ACCEPT_ELIF:ACCEPT_IF;
+ }
+ else
+ action[Nest_level] = 1;
+ }
+ else
+ action[Nest_level] = 1;
+ break;
+
+ case ST_ELSE:
+ if( Nest_level <= 0 ) Fatal( ".ELSE without .IF" );
+ if( ifcntl[Nest_level] & SEEN_ELSE )
+ Fatal( "Missing .IF or .ELIF before .ELSE" );
+
+ if( ifcntl[Nest_level] & (ACCEPT_IF|ACCEPT_ELIF) )
+ action[Nest_level] = 1;
+ else if( action[ Nest_level-1 ] != 1 )
+ action[ Nest_level ] ^= 0x1; /* flip between 0 and 1 */
+
+ ifcntl[Nest_level] |= SEEN_ELSE;
+ break;
+
+ case ST_END:
+ ifcntl[Nest_level] = SEEN_END;
+ Nest_level--;
+ if( Nest_level < 0 ) Fatal( "Unmatched .END[IF]" );
+ break;
+ }
+
+ DB_RETURN( action[ Nest_level ] );
+}
+
+
+int partcomp( char* lhs, int opcode )
+{
+
+ char *tok, *rhs, *op;
+ int result, opsind;
+ const int localopscount=4;
+ char* localops[]={"==","!=","<=",">="};
+ int lint, rint;
+
+#define EQUAL 0
+#define NOTEQUAL 1
+#define LESS_EQUAL 2
+#define GREATER_EQUAL 3
+
+ opsind=0;
+/* printf( "eval: %s\n", lhs);*/
+ if( opcode == ST_IFEQ || opcode == ST_IFNEQ ) { /* no == */
+ for( op = lhs; ((*op)&&(*op != ' ')&&(*op != '\t')); op++ );
+ if( *op )
+ op++;
+ else
+ op = NIL(char);
+ } else while ( opsind < localopscount && (op = DmStrStr( lhs, localops[opsind] )) == NIL(char))
+ {
+/* printf("%d %s\n", opsind, localops[opsind]);*/
+ opsind++;
+ }
+
+/* if ( opsind == localopscount )
+ Fatal( "Unknown Operator\n" );*/
+
+ if( op == NIL(char) )
+ result = (lhs != NIL(char));
+ else {
+/* printf("op#%s\n",op);*/
+ if( opcode != ST_IFEQ && opcode != ST_IFNEQ ) /* no == */
+ op[1] = op[0];
+/* printf("op#%s\n",op);*/
+ if( lhs != op ) {
+ for( tok = op-1; (tok != lhs) && ((*tok == ' ')||(*tok == '\t'));
+ tok-- );
+ tok[1] = '\0';
+ }
+ else
+ lhs = NIL(char);
+
+ if( opcode == ST_IFEQ || opcode == ST_IFNEQ ) /* no == */
+ op--;
+ else
+ op++;
+ rhs = DmStrSpn( op+1, " \t" );
+ if( !*rhs ) rhs = NIL(char);
+
+ if ( opsind > NOTEQUAL ) {
+/* printf("new ops\n");*/
+ switch( opsind ){
+ case LESS_EQUAL:
+ case GREATER_EQUAL:
+ if ( lhs[0] == '"' ) lhs++;
+ if ( rhs[0] == '"' ) rhs++;
+ lint = atoi( lhs );
+ rint = atoi( rhs );
+ result = ( lint >= rint ) ? TRUE : FALSE;
+ if ( opsind == LESS_EQUAL && lint != rint )
+ result = !result;
+ break;
+ default:
+ result = FALSE;
+ }
+ }
+ else {
+ if( (rhs == NIL(char)) || (lhs == NIL(char)) )
+ result = (rhs == lhs) ? TRUE : FALSE;
+ else {
+ tok = rhs + strlen( rhs );
+ for( tok=tok-1; (tok != lhs) && ((*tok == ' ')||(*tok == '\t'));
+ tok--);
+ tok[1] = '\0';
+
+ result = (strcmp( lhs, rhs ) == 0) ? TRUE : FALSE;
+ }
+ if( *op == '!' || opcode == ST_IFNEQ ) result = !result;
+ }
+ }
+/* printf("partresult %d\n",result);*/
+ return result;
+};
+