update dev300-m58
[ooovba.git] / dmake / getinp.c
bloba6791a7e020051248d3970e579d51e054a9bfec3
1 /* RCS $Id: getinp.c,v 1.10 2007-10-15 15:39:23 ihi Exp $
2 --
3 -- SYNOPSIS
4 -- Handle reading of input.
5 --
6 -- DESCRIPTION
7 -- The code in this file reads the input from the specified stream
8 -- into the provided buffer of size Buffer_size. In doing so it deletes
9 -- comments. Comments are delimited by the #, and
10 -- <nl> character sequences. An exception is \# which
11 -- is replaced by # in the input. Line continuations are signalled
12 -- at the end of a line and are recognized inside comments.
13 -- The line continuation is always <\><nl>.
15 -- If the file to read is NIL(FILE) then the Get_line routine returns the
16 -- next rule from the builtin rule table (Rule_tab from ruletab.c) if
17 -- there is one.
19 -- AUTHOR
20 -- Dennis Vadura, dvadura@dmake.wticorp.com
22 -- WWW
23 -- http://dmake.wticorp.com/
25 -- COPYRIGHT
26 -- Copyright (c) 1996,1997 by WTI Corp. All rights reserved.
28 -- This program is NOT free software; you can redistribute it and/or
29 -- modify it under the terms of the Software License Agreement Provided
30 -- in the file <distribution-root>/readme/license.txt.
32 -- LOG
33 -- Use cvs log to obtain detailed change logs.
36 #include "extern.h"
38 #define IS_WHITE(A) ((A == ' ') || (A == '\t') || (A == '\n') || (A == '\r'))
39 #define SCAN_WHITE(A) \
40 while( IS_WHITE(*A) ) A++;
42 static int _is_conditional ANSI((char*));
43 static int _handle_conditional ANSI((int, TKSTRPTR));
45 static int rule_ind = 0; /* index of rule when reading Rule_tab */
46 static int skip = FALSE; /* if true the skip input */
48 int partcomp( char* lhs, int opcode );
49 int parse_complex_expression( char *expr, char **expr_end, int opcode );
52 PUBLIC int
53 Get_line( buf, fil )/*
54 ======================
55 Read a line of input from the file stripping off comments. The routine
56 returns TRUE if EOF. If fil equals NIL(FILE) then the next line from
57 *Rule_tab[] is used. Rule_tab is either the buildin rule table or points
58 to the current environment (used by ReadEnvironment()).
59 The function returns TRUE if the input file/buffer was read to the end
60 and FALSE otherwise. */
61 char *buf;
62 FILE *fil;
64 extern char **Rule_tab;
65 register char *p;
66 register char *c;
67 char *q;
68 char *buf_org;
69 static int ignore = FALSE;
70 int cont = FALSE;
71 int pos = 0;
72 int res = 0;
73 register char *tmp = NIL(char);
75 DB_ENTER( "Get_line" );
77 if( Skip_to_eof ) {
78 Skip_to_eof = FALSE;
79 rule_ind = 0;
81 if( Verbose & V_MAKE )
82 Warning("Ignoring remainder of file %s", Filename());
84 DB_RETURN(TRUE);
87 if( fil == NIL(FILE) ) {
88 /* Reading the internal rule table. Set rule_ind to zero after the
89 * last entry so that ReadEnvironment() works as expected every time. */
91 while( (p = Rule_tab[ rule_ind++ ]) != NIL(char) ) {
92 /* The last test in this if *p != '~', handles the environment
93 * passing conventions used by MKS to pass arguments. We want to
94 * skip those environment entries. Also CYGWIN likes to export '!'
95 * prefixed environment variables that cause severe pain, axe them too.
96 * And finally it is possible to do "env 'GGG HHH'='some value' bash"
97 * which causes that there are env variables with spaces in the name
98 * defined which causes dmake to malfunction too */
99 char *equal = strchr(p,'=');
100 char *space = strchr(p,' ');
101 if( !Readenv || (Readenv && (equal != NIL(char)) && (space == NIL(char) || space > equal) && *p!='~' && *p!='!')){
102 strcpy( buf, p );
104 DB_PRINT( "io", ("Returning [%s]", buf) );
105 DB_RETURN( FALSE );
109 rule_ind = 0;
111 DB_PRINT( "io", ("Done Ruletab") );
112 DB_RETURN( TRUE );
115 buf_org = buf;
117 do_again:
118 do {
119 p = buf+pos;
120 /* fgets() reads at most one less than Buffer_size-pos characters. */
121 if(feof( fil ) || (fgets( p, Buffer_size-pos, fil ) == NIL(char)))
122 DB_RETURN( TRUE );
124 #ifdef _MPW
125 if ( p[0] == 10 && p[1] == COMMENT_CHAR)
126 p[0] = ' ';
127 #endif
129 Line_number++;
131 /* Set q to the last char in p before the \n\0. */
132 q = p+strlen(p)-2;
133 if( q >= p ) { /* Only check for special cases if p points
134 * to a non-empty line. */
136 /* ignore each RETURN at the end of a line before any further
137 * processing */
138 if( q[0] == '\r' && q[1] == '\n' ) {
139 q[0] = '\n';
140 q[1] = '\0';
141 q--;
143 /* you also have to deal with END_OF_FILE chars to process raw
144 * DOS-Files. Normally they are the last chars in file, but after
145 * working on these file with vi, there is an additional NEWLINE
146 * after the last END_OF_FILE. So if the second last char in the
147 * actual line is END_OF_FILE, you can skip the last char. Then
148 * you can search the line back until you find no more END_OF_FILE
149 * and nuke each you found by string termination. */
150 if( q[0] == '\032' )
151 q--;
152 while( q[1] == '\032' ) {
153 q[1] = '\0';
154 q--;
157 /* ignore input if ignore flag set and line ends in a continuation
158 character. */
160 if( ignore ) {
161 if( q[0] != CONTINUATION_CHAR || q[1] != '\n' ) ignore = FALSE;
162 *p = '\0';
163 continue;
166 /* If a comment is found the line does not end in \n anymore. */
167 c = Do_comment(p, &q, Group || (*buf == '\t') || (Notabs && *buf ==' '));
169 /* Does the end of the line end in a continuation sequence? */
171 if( (q[0] == CONTINUATION_CHAR) && (q[1] == '\n')) {
172 /* If the continuation was at the end of a comment then ignore the
173 * next input line, (or lines until we get one ending in just <nl>)
174 * else it's a continuation, so build the input line from several
175 * text lines on input. The maximum size of this is governened by
176 * Buffer_size */
177 if( q != p && q[-1] == CONTINUATION_CHAR ) {
178 strcpy( q, q+1 );
179 q--;
180 cont = FALSE;
182 else if( c != NIL(char) )
183 ignore = TRUE;
184 else
185 cont = TRUE; /* Keep the \<nl>. */
187 else {
188 cont = FALSE;
191 q = ( c == NIL(char) ) ? q+2 : c;
193 else { /* empty line or "" */
194 cont = FALSE;
195 ignore = FALSE;
196 q = p+strlen(p); /* strlen(p) is 1 or 0 */
199 pos += q-p;
201 while( (cont || !*buf) && (pos < Buffer_size-1) );
203 if( pos >= Buffer_size-1 )
204 Fatal( "Input line too long, increase MAXLINELENGTH" );
206 /* Lines that had comments don't contain \n anymore. */
207 /* ??? Continued lines that are followed by an empty or comment only
208 * line will end in \<nl>. */
209 if( (q > p) && (buf[ pos-1 ] == '\n') )
210 buf[ --pos ] = '\0'; /* Remove the final \n. */
212 /* STUPID AUGMAKE uses "include" at the start of a line as
213 * a signal to include a new file, so let's look for it.
214 * if we see it replace it by .INCLUDE: and stick this back
215 * into the buffer. We also allow GNU make if[n]eq/else/endif.
217 * These substitutions are made only if we are not parsing a group
218 * recipe. */
219 if( (p = DmStrSpn(buf, " \t\r\n")) == NIL(char) )
220 p = buf;
222 if (!Group) {
223 if( !strncmp( "include", p, 7 ) &&
224 (p[7] == ' ' || p[7] == '\t') )
225 tmp = DmStrJoin( ".INCLUDE:", p+7, -1, FALSE );
226 else if( !strncmp( "ifeq", p, 4 ) &&
227 (p[4] == ' ' || p[4] == '\t') )
228 tmp = DmStrJoin( ".IFEQ", p+4, -1, FALSE );
229 else if( !strncmp( "ifneq", p, 5 ) &&
230 (p[5] == ' ' || p[5] == '\t') )
231 tmp = DmStrJoin( ".IFNEQ", p+5, -1, FALSE );
232 else if( !strncmp( "elif", p, 4 ) &&
233 (p[4] == ' ' || p[4] == '\t') )
234 tmp = DmStrJoin( ".ELIF", p+4, -1, FALSE );
235 else if( !strncmp( "else", p, 4 ) &&
236 (p[4] == ' ' || p[4] == '\t' || p[4] == '\0') )
237 tmp = DmStrJoin( ".ELSE", p+4, -1, FALSE );
238 else if( !strncmp( "endif", p, 5 ) &&
239 (p[5] == ' ' || p[5] == '\t' || p[5] == '\0') )
240 tmp = DmStrJoin( ".END", p+5, -1, FALSE );
243 if( tmp != NIL(char)) {
244 strcpy( buf, tmp );
245 FREE( tmp );
246 tmp = NIL(char);
249 /* Now that we have the next line of input to make, we should check to
250 * see if it is a conditional expression. If it is then process it,
251 * otherwise pass it on to the parser. */
253 if( *(p = DmStrSpn(buf, " \t\r\n")) == CONDSTART ) {
254 TKSTR token;
256 SET_TOKEN( &token, p );
258 p = Get_token( &token, "", FALSE );
260 if( (res = _is_conditional(p)) != 0 ) /* ignore non-control special */
261 { /* targets */
262 res = _handle_conditional( res, &token );
263 skip = TRUE;
265 else {
266 CLEAR_TOKEN( &token );
267 res = TRUE;
271 if( skip ) {
272 buf = buf_org; /* ignore line just read in */
273 pos = 0;
274 skip = res;
275 goto do_again;
278 DB_PRINT( "io", ("Returning [%s]", buf) );
279 DB_RETURN( FALSE );
283 PUBLIC char *
284 Do_comment(str, pend, keep)/*
285 =============================
286 Search the input string looking for comment chars. If it contains
287 comment chars then NUKE the remainder of the line, if the comment
288 char is preceeded by \ then shift the remainder of the line left
289 by one char. */
290 char *str;
291 char **pend;
292 int keep;
294 char *c = str;
296 while( (c = strchr(c, COMMENT_CHAR)) != NIL(char) ) {
297 if( Comment || State == NORMAL_SCAN )
298 if( c != str && c[-1] == ESCAPE_CHAR ) {
299 strcpy( c-1, c ); /* copy it left, due to \# */
300 if( pend ) (*pend)--; /* shift tail pointer left */
302 else {
303 /* Check/execute if shebang command is present. */
304 if( !No_exec
305 && c == str
306 && c[1] == '!'
307 && Line_number == 1
308 && Nestlevel() == 1 ) {
309 char *cmnd;
311 cmnd = Expand(c+2);
312 cmnd[strlen(cmnd)-1] = '\0'; /* strip last newline */
313 Current_target = Root;
314 #if defined(MSDOS)
315 Swap_on_exec = TRUE;
316 #endif
317 Wait_for_completion = TRUE;
318 Do_cmnd(&cmnd, FALSE, TRUE, Current_target, A_DEFAULT, TRUE);
319 #if defined(MSDOS)
320 Swap_on_exec = FALSE;
321 #endif
322 Wait_for_completion = FALSE;
323 FREE(cmnd);
326 *c = '\0'; /* a true comment so break */
327 break;
329 else {
330 if( keep )
331 c = NIL(char);
332 else
333 *c = '\0';
335 break;
339 return(c);
343 PUBLIC char *
344 Get_token( string, brk, anchor )/*
345 ==================================
346 Return the next token in string.
348 Returns empty string when no more tokens in string.
349 brk is a list of chars that also cause breaks in addition to space and
350 tab, but are themselves returned as tokens. if brk is NULL then the
351 remainder of the line is returned as a single token.
353 'anchor' if 1, says break on chars in the brk list, but only if
354 the entire token begins with the first char of the brk list, if
355 0 then any char of brk will cause a break to occurr.
357 If 'anchor' is 2, then break only seeing the first char in the break
358 list allowing only chars in the break list to form the prefix. */
360 TKSTRPTR string;
361 char *brk;
362 int anchor;
364 register char *s;
365 register char *curp = 0;
366 register char *t;
367 int done = FALSE;
368 char space[100];
370 DB_ENTER( "Get_token" );
372 s = string->tk_str; /* Get string parameters */
373 *s = string->tk_cchar; /* ... and strip leading w/s */
375 SCAN_WHITE( s );
377 DB_PRINT( "tok", ("What's left [%s]", s) );
379 if( !*s ) {
380 DB_PRINT( "tok", ("Returning NULL token") );
381 DB_RETURN( "" );
385 /* Build the space list. space contains all those chars that may possibly
386 * cause breaks. This includes the brk list as well as white space. */
388 if( brk != NIL(char) ) {
389 strcpy( space, " \t\r\n" );
390 strcat( space, brk );
392 else {
393 space[0] = 0xff; /* a char we know will not show up */
394 space[1] = 0;
398 /* Handle processing of quoted tokens. Note that this is disabled if
399 * brk is equal to NIL */
401 while( *s == '\"' && ((brk != NIL(char)) || !string->tk_quote) ) {
402 s++;
403 if( string->tk_quote ) {
404 curp = s-1;
405 do { curp = strchr( curp+1, '\"' ); }
406 while( (curp != NIL(char)) && (*(curp+1) == '\"'));
408 if( curp == NIL(char) ) Fatal( "Unmatched quote in token" );
409 string->tk_quote = !string->tk_quote;
411 /* Check for "" case, and if found ignore it */
412 if( curp == s ) continue;
413 goto found_token;
415 else
416 SCAN_WHITE( s );
418 string->tk_quote = !string->tk_quote;
422 /* Check for a token break character at the beginning of the token.
423 * If found return the next set of break chars as a token. */
425 if( anchor == 2 && brk != NIL(char) ) {
426 curp = s;
427 while( *curp && (strchr(brk,*curp)!=NIL(char)) && (*curp!=*brk) ) curp++;
428 done = (*brk == *curp++);
430 else if( (brk != NIL(char)) && (strchr( brk, *s ) != NIL(char)) ) {
431 curp = DmStrSpn( s, brk );
432 done = (anchor == 0) ? TRUE :
433 ((anchor == 1)?(*s == *brk) : (*brk == curp[-1]));
437 /* Scan for the next token in the list and return it less the break char
438 * that was used to terminate the token. It will possibly be returned in
439 * the next call to Get_token */
441 if( !done ) {
442 SCAN_WHITE( s );
444 t = s;
445 do {
446 done = TRUE;
447 curp = DmStrPbrk(t, space);
449 if( anchor && *curp && !IS_WHITE( *curp ) )
450 if( ((anchor == 1)?*curp:DmStrSpn(curp,brk)[-1]) != *brk ) {
451 t++;
452 done = FALSE;
455 while( !done );
457 if( (curp == s) && (strchr(brk, *curp) != NIL(char)) ) curp++;
460 found_token:
461 string->tk_str = curp;
462 string->tk_cchar = *curp;
463 *curp = '\0';
465 DB_PRINT( "tok", ("Returning [%s]", s) );
466 DB_RETURN( s );
470 static int
471 _is_conditional( tg )/*
472 =======================
473 Look at tg and return it's value if it is a conditional identifier
474 otherwise return 0. */
475 char *tg;
477 DB_ENTER( "_is_conditional" );
479 tg++;
480 switch( *tg )
482 case 'I':
483 if( !strcmp( tg, "IF" )) DB_RETURN( ST_IF );
484 else if( !strcmp( tg, "IFEQ" )) DB_RETURN( ST_IFEQ );
485 else if( !strcmp( tg, "IFNEQ" )) DB_RETURN( ST_IFNEQ );
486 break;
488 case 'E':
489 if( !strcmp( tg, "END" )) DB_RETURN( ST_END );
490 else if( !strcmp( tg, "ENDIF")) DB_RETURN( ST_END );
491 else if( !strcmp( tg, "ELSE" )) DB_RETURN( ST_ELSE );
492 else if( !strcmp( tg, "ELIF" )) DB_RETURN( ST_ELIF );
493 break;
496 DB_RETURN( 0 );
501 #define SEEN_END 0x00
502 #define SEEN_IF 0x01
503 #define SEEN_ELSE 0x02
504 #define SEEN_ELIF 0x04
506 #define ACCEPT_IF 0x10
507 #define ACCEPT_ELIF 0x20
509 static int
510 _handle_conditional( opcode, tg )
511 int opcode;
512 TKSTRPTR tg;
514 static short action[MAX_COND_DEPTH];
515 static char ifcntl[MAX_COND_DEPTH];
516 char *cst;
517 char *lhs, *expr, *expr_end;
518 char *lop;
519 int result;
521 DB_ENTER( "_handle_conditional" );
523 switch( opcode ) {
524 case ST_ELIF:
525 if( !(ifcntl[Nest_level] & SEEN_IF) || (ifcntl[Nest_level]&SEEN_ELSE) )
526 Fatal(".ELIF without a preceeding .IF" );
527 /*FALLTHRU*/
529 case ST_IF:
530 case ST_IFEQ:
531 case ST_IFNEQ:
532 if( opcode != ST_ELIF && (Nest_level+1) == MAX_COND_DEPTH )
533 Fatal( ".IF .ELSE ... .END nesting too deep" );
535 If_expand = TRUE;
536 expr = Expand( Get_token( tg, NIL(char), FALSE ));
537 If_expand = FALSE;
539 /* Remove CONTINUATION_CHAR<nl> and replace with " " so that line
540 * continuations are recognized as whitespace. */
541 for( cst=strchr(expr,CONTINUATION_CHAR); cst != NIL(char); cst=strchr(cst,CONTINUATION_CHAR) )
542 if( cst[1] == '\n' ) {
543 *cst = ' ';
544 cst[1] = ' ';
546 else
547 cst++;
549 lhs = expr;
550 SCAN_WHITE( lhs );
552 /* Parse the expression and get its logical result */
553 if ( ((lop = DmStrStr(lhs, "||" )) != NIL(char)) || ((lop = DmStrStr(lhs, "&&" )) != NIL(char)) )
554 result = parse_complex_expression( lhs, &expr_end, opcode );
555 else
556 result = partcomp( lhs, opcode );
558 if( expr != NIL(char) ) FREE( expr );
560 if( opcode != ST_ELIF ) {
561 Nest_level++;
562 action[Nest_level] = 1;
564 ifcntl[Nest_level] |= (opcode==ST_ELIF)?SEEN_ELIF:SEEN_IF;
566 if( result ) {
567 if( !(ifcntl[Nest_level] & (ACCEPT_IF|ACCEPT_ELIF)) ) {
568 action[ Nest_level ] = action[ Nest_level-1 ];
569 ifcntl[Nest_level] |= (opcode==ST_ELIF)?ACCEPT_ELIF:ACCEPT_IF;
571 else
572 action[Nest_level] = 1;
574 else
575 action[Nest_level] = 1;
576 break;
578 case ST_ELSE:
579 if( Nest_level <= 0 ) Fatal( ".ELSE without .IF" );
580 if( ifcntl[Nest_level] & SEEN_ELSE )
581 Fatal( "Missing .IF or .ELIF before .ELSE" );
583 if( ifcntl[Nest_level] & (ACCEPT_IF|ACCEPT_ELIF) )
584 action[Nest_level] = 1;
585 else if( action[ Nest_level-1 ] != 1 )
586 action[ Nest_level ] ^= 0x1; /* flip between 0 and 1 */
588 ifcntl[Nest_level] |= SEEN_ELSE;
589 break;
591 case ST_END:
592 ifcntl[Nest_level] = SEEN_END;
593 Nest_level--;
594 if( Nest_level < 0 ) Fatal( "Unmatched .END[IF]" );
595 break;
598 DB_RETURN( action[ Nest_level ] );
601 /* uncomment to turn on expression debug statements */
602 /*#define PARSE_DEBUG */
603 #define PARSE_SKIP_WHITE(A) while( *A && ((*A==' ') || (*A=='\t')) ) A++;
605 #define OP_NONE 0
606 #define OP_AND 1
607 #define OP_OR 2
609 static int n = 1;
611 int parse_complex_expression( char *expr, char **expr_end, int opcode )
613 char *p = expr;
614 char *term_start = p;
615 char *term_end;
616 int local_term;
617 char *part;
618 int term_result = FALSE;
619 int final_result = TRUE;
620 unsigned int term_len;
621 unsigned int last_op = OP_NONE;
623 #ifdef PARSE_DEBUG
624 printf( "%d: parse_complex_expression( %s ): Opcode: %d\n", n, expr, opcode );
625 #endif
627 while ( 1 )
629 /* A new sub-expression */
630 local_term = TRUE;
631 if ( *p == '(' )
633 n++;
634 term_result = parse_complex_expression( p+1, &p, opcode );
635 n--;
636 PARSE_SKIP_WHITE( p );
637 term_start = p;
638 term_end = p;
639 local_term = FALSE;
641 else
642 term_end = p;
644 /* Lets do an operation!! */
645 if ( !(*p) /* at the end of the entire line */
646 || ((*p == '&') && (*(p+1) && (*(p+1)=='&'))) /* found an && */
647 || ((*p == '|') && (*(p+1) && (*(p+1)=='|'))) /* found an || */
648 || (*p == ')') ) /* at the end of our term */
650 /* Grab the sub-expression if we parsed it. Otherwise,
651 * it was a () subexpression and we don't need to evaluate
652 * it since that was already done.
654 if ( local_term == TRUE )
656 /* Back up 1 to the end of the actual term */
657 term_end--;
659 /* Evaluate the term */
660 PARSE_SKIP_WHITE( term_start );
661 term_len = term_end - term_start + 1;
662 part = MALLOC( term_len + 1, char );
663 strncpy( part, term_start, term_len );
664 *(part+term_len) = '\0';
665 #ifdef PARSE_DEBUG
666 printf( "%d: evaling '%s'\n", n, part );
667 #endif
668 term_result = partcomp( part, opcode );
669 #ifdef PARSE_DEBUG
670 printf( "%d: evaled, result %d\n", n, term_result );
671 #endif
672 FREE( part );
675 /* Do the actual logical operation using the _preceding_
676 * logical operator, NOT the one we just found.
678 if ( last_op == OP_AND )
679 final_result = final_result && term_result;
680 else if ( last_op == OP_OR )
681 final_result = final_result || term_result;
682 else
683 final_result = term_result;
684 #ifdef PARSE_DEBUG
685 printf( "%d: final_result:%d\n", n, final_result );
686 #endif
688 /* If we're not at the end of the line, just keep going */
689 if ( *p )
691 /* Recognize the operator we just found above */
692 if ( *p == '&' )
693 last_op = OP_AND;
694 else if ( *p == '|' )
695 last_op = OP_OR;
696 if ( *p != ')' )
697 p += 2;
699 /* Get the start of the next term */
700 PARSE_SKIP_WHITE( p );
701 term_start = p;
703 /* If this is the close of a term, we are done and return
704 * to our caller.
706 if ( *p == ')' )
708 p++;
709 break;
712 else break; /* At end of line, all done */
714 else if ( local_term == TRUE ) p++; /* Advance to next char in expression */
716 *expr_end = p;
718 #ifdef PARSE_DEBUG
719 printf( "%d: done, returning '%s', result %d\n", n, *expr_end, final_result );
720 #endif
721 return( final_result );
725 int partcomp( char* lhs, int opcode )
728 char *tok, *rhs, *op = 0;
729 int result, opsind;
730 const int localopscount=4;
731 char* localops[] = { "==", "!=", "<=", ">=" };
732 int lint, rint;
734 #define EQUAL 0
735 #define NOTEQUAL 1
736 #define LESS_EQUAL 2
737 #define GREATER_EQUAL 3
739 #ifdef PARSE_DEBUG
740 printf( "eval: %s\n", lhs);
741 #endif
743 opsind = 0;
744 if( opcode == ST_IFEQ || opcode == ST_IFNEQ )
746 /* IF[N]EQ syntax is: .IF[N]EQ <1> <2>
747 * Here, step over first argument and get to <2> if it exists.
749 for( op = lhs; ((*op)&&(*op != ' ')&&(*op != '\t')); op++ );
750 if( *op ) op++; /* position op at start of <2> */
751 else op = NIL(char); /* only 1 argument given */
753 else
755 /* Find which logical operator we are to use for this expression,
756 * and jump to it */
757 while ( (opsind < localopscount) && ((op = DmStrStr(lhs, localops[opsind])) == NIL(char)) )
758 opsind++;
760 #ifdef PARSE_DEBUG
761 printf(" found op %d: %s\n", opsind, localops[opsind]);
762 #endif
765 /* If the opcode was IFEQ or IFNEQ and only 1 argument was given,
766 * or an unknown logical operator was encountered,
767 * return false if argument is empty string, true if !empty
769 if( op == NIL(char) )
770 result = (*lhs != '\0');
771 else
773 /* Make both characters of the operation the same, replacing the = in op[1]
774 * Its easier to deal with this way???
776 if( opcode != ST_IFEQ && opcode != ST_IFNEQ )
777 op[1] = op[0];
779 #ifdef PARSE_DEBUG
780 printf(" op:%s\n", op);
781 #endif
783 /* Isolate the left half of the expression */
784 if( lhs != op )
786 for( tok = op-1; (tok != lhs) && ((*tok == ' ')||(*tok == '\t')); tok-- );
787 tok[1] = '\0';
789 else
790 lhs = NIL(char); /* Left hand side is empty. */
792 /* Jump over the operation so we can grab the right half of the expression */
793 if( opcode == ST_IFEQ || opcode == ST_IFNEQ )
794 op--;
795 else
796 op++;
798 /* Isolate the right half of the expression */
799 rhs = DmStrSpn( op+1, " \t" );
800 if( !*rhs ) rhs = NIL(char);
802 #ifdef PARSE_DEBUG
803 printf(" lhs:%s, rhs:%s\n", lhs, rhs);
804 #endif
806 /* Do the actual logical operation on the expression */
807 if ( opsind > NOTEQUAL )
809 switch( opsind )
811 case LESS_EQUAL:
812 case GREATER_EQUAL:
813 /* Ignore quotes around the arguments */
814 if ( lhs && lhs[0] == '"' ) lhs++;
815 if ( rhs && rhs[0] == '"' ) rhs++;
817 /* Empty strings evaluate to zero. */
818 lint = lhs ? atoi( lhs ) : 0;
819 rint = rhs ? atoi( rhs ) : 0;
820 result = ( lint >= rint ) ? TRUE : FALSE;
821 if ( opsind == LESS_EQUAL && lint != rint )
822 result = !result;
823 break;
824 default:
825 result = FALSE;
828 else
830 /* Use a simple string compare to determine equality */
831 if( (rhs == NIL(char)) || (lhs == NIL(char)) )
832 result = (rhs == lhs) ? TRUE : FALSE;
833 else
835 /* String off whitespace at the end of the right half of the expression */
836 tok = rhs + strlen( rhs );
837 for( tok=tok-1; (tok != lhs) && ((*tok == ' ')||(*tok == '\t')); tok--);
838 tok[1] = '\0';
840 result = (strcmp( lhs, rhs ) == 0) ? TRUE : FALSE;
843 if( *op == '!' || opcode == ST_IFNEQ ) result = !result;
847 #ifdef PARSE_DEBUG
848 printf("partresult %d\n\n",result);
849 #endif
850 return result;