1 /* condparser.cc
2  * This file belongs to Worker, a file manager for UN*X/X11.
3  * Copyright (C) 2004-2014 Ralf Hoffmann.
4  * You can contact me at: ralf@boomerangsworld.de
5  *   or http://www.boomerangsworld.de/worker
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #include "condparser.h"
23 #include "aguix/lowlevelfunc.h"
24 #include "aguix/awindow.h"
25 #include "aguix/acontainer.h"
26 #include "aguix/fieldlistview.h"
27 #include "aguix/button.h"
28 #include "execlass.h"
29 #include "fileentry.hh"
30 #include "worker.h"
31 #include "datei.h"
32 #include "worker_locale.h"
33 #include "nwc_path.hh"
34 
35 struct CondParser::deftokens CondParser::keywords[] = {
36   { "lasterror", CondParser::TOK_LASTERROR },
37   { "true", CondParser::TOK_TRUE },
38   { "false", CondParser::TOK_FALSE },
39   { "toNum", CondParser::TOK_TONUM },
40   { "toStr", CondParser::TOK_TOSTR },
41   { "isReg", CondParser::TOK_ISREG },
42   { "isSock", CondParser::TOK_ISSOCK },
43   { "isFIFO", CondParser::TOK_ISFIFO },
44   { "isSymlink", CondParser::TOK_ISSYMLINK },
45   { "isBrokenSymlink", CondParser::TOK_ISBROKENSYMLINK },
46   { "size", CondParser::TOK_SIZE },
47   { "perm", CondParser::TOK_PERM },
48   { "toLower", CondParser::TOK_TOLOWER },
49   { "toUpper", CondParser::TOK_TOUPPER },
50   { "contentStr", CondParser::TOK_CONTENTSTR },
51   { "contentNum", CondParser::TOK_CONTENTNUM },
52   { "name", CondParser::TOK_NAME },
53   { "fullname", CondParser::TOK_FULLNAME },
54   { "isLocal", CondParser::TOK_ISLOCAL }
55 };
56 
57 struct CondParser::flaghelp CondParser::flags[] = {
58   { "true", -1, 44 },
59   { "false", -1, 45 },
60   { "toNum(...)", -1, 51 },
61   { "toStr(...)", -1, 52 },
62   { "isReg()", 579, -1 },
63   { "isSock()", 580, -1 },
64   { "isFIFO()", 581, -1 },
65   { "isSymlink()", 582, -1 },
66   { "isBrokenSymlink()", 1036, -1 },
67   { "isLocal()", 626, -1 },
68   { "size()", 583, -1 },
69   { "perm(mask)", 584, -1 },
70   { "toLower(...)", 585, -1 },
71   { "toUpper(...)", 586, -1 },
72   { "contentStr(<Start>[,<Length>])", 587, -1 },
73   { "contentNum(<Start>[,<Length>])", 588, -1 },
74   { "name()", 589, -1 },
75   { "fullname()", 590, -1 },
76   { "${...}", -1, 48 },
77   { "?{...}", -1, 47 },
78   { "{f}", 591, -1 },
79   { "{F}", 592, -1 },
80   { "lasterror", -1, 42 }
81 };
82 
CondParser()83 CondParser::CondParser()
84 {
85   curpos = 0;
86   tokenval = -1;
87   ignore = 0;
88   scanbuf = NULL;
89   scanbuflen = -1;
90   lasterror = 0;
91   fe = NULL;
92   ignoreContent = false;
93 }
94 
~CondParser()95 CondParser::~CondParser()
96 {
97 }
98 
lookup(const char * s)99 int CondParser::lookup( const char *s )
100 {
101   unsigned int p;
102 
103   for ( p = 0; p < ( sizeof(keywords) / sizeof( keywords[0] ) ); p++ )
104     if ( strcasecmp( keywords[p].str, s ) == 0 )
105       return keywords[p].token;
106   return TOK_NONE;
107 }
108 
lex()109 int CondParser::lex()
110 {
111   int t;
112   int base = 10;
113 
114   while ( 1 ) {
115     if ( curpos >= scanbuflen ) break;
116     t = scanbuf[curpos++];
117     if ( isspace( t ) ) {
118     } else if ( isdigit( t ) ) {
119       tokenval = t - '0';
120       if ( tokenval == 0 ) {
121         base = 8;
122       } else {
123         base = 10;
124       }
125       while ( isdigit( t = scanbuf[curpos++] ) ) {
126         if ( ( t - '0' ) >= base ) t = '0';
127 	tokenval = base * tokenval + ( t - '0' );
128       }
129       curpos--;
130       return TOK_NUM;
131     } else if ( isalpha( t ) || ( t == '_' ) ) {
132       int b = 0;
133 
134       while ( isalnum( t ) || ( t == '_' ) ) {
135         lexbuf[b] = t;
136 	t = scanbuf[curpos++];
137 	b = b + 1;
138 	if ( ( b + 1 ) >= BUFSIZE ) {
139 	  // Pufferueberlauf
140           break;
141         }
142       }
143       lexbuf[b] = '\0';
144       if ( t != '\0' ) {
145 	curpos--;
146       }
147       return lookup( lexbuf );
148     } else if ( t == '"' ) {
149       int b = 0;
150       int bs = 0;
151 
152       for ( ;; ) {
153 	t = scanbuf[curpos++];
154 	if ( t == EOF )
155 	  break;
156 	if ( ( t == '\\' ) && ( bs == 0 ) ) {
157 	  bs = 1;
158 	  continue;
159 	}
160 	if ( ( t == '"' ) && ( bs == 0 ) )
161 	  break;
162 	bs = 0;
163         lexbuf[b] = t;
164 	b = b + 1;
165 	if ( ( b + 1 ) >= BUFSIZE ) {
166 	  // Pufferueberlauf
167           break;
168         }
169       }
170       lexbuf[b] = '\0';
171       return TOK_STRING;
172     } else if ( t == '&' ) {
173       t = scanbuf[curpos++];
174       if ( t == '&' )
175 	return TOK_P_AND;
176       return TOK_NONE;
177     } else if ( t == '|' ) {
178       t = scanbuf[curpos++];
179       if ( t == '|' )
180 	return TOK_P_OR;
181       return TOK_NONE;
182     } else if ( t == '=' ) {
183       t = scanbuf[curpos++];
184       if ( t == '=' )
185         return TOK_E;
186       return TOK_NONE;
187     } else if ( t == '!' ) {
188       t = scanbuf[curpos++];
189       if ( t == '=' )
190         return TOK_NE;
191       return TOK_NONE;
192     } else if ( t == '<' ) {
193       t = scanbuf[curpos++];
194       if ( t == '=' )
195         return TOK_LE;
196       curpos--;
197       return TOK_LT;
198     } else if ( t == '>' ) {
199       t = scanbuf[curpos++];
200       if ( t == '=' )
201         return TOK_GE;
202       curpos--;
203       return TOK_GT;
204     } else if ( t == '~' ) {
205       t = scanbuf[curpos++];
206       if ( t == '=' )
207         return TOK_REGEQ;
208       return TOK_NONE;
209     } else if ( t == '\0' ) {
210       return TOK_DONE;
211     } else {
212       tokenval = TOK_NONE;
213       return t;
214     }
215   }
216   return TOK_DONE;
217 }
218 
match(int t)219 int CondParser::match( int t )
220 {
221   if ( lookahead == t ) {
222     lookahead = lex();
223   } else {
224     return 1;
225   }
226   return 0;
227 }
228 
readBrace()229 char *CondParser::readBrace()
230 {
231   int startpos, endpos;
232   int bracecount = 0;
233   int t, ig = 0, len, readpos;
234   char *tstr;
235 
236   startpos = curpos;
237   if ( scanbuf[curpos] == '{' ) {
238     do {
239       t = scanbuf[curpos++];
240       if ( t == '\0' ) break;
241       else if ( ( t == '\\' ) && ( ig == 0 ) ) {
242         ig = 1;
243         continue;
244       } else if ( ( t == '{' ) && ( ig == 0 ) ) {
245         bracecount++;
246       } else if ( ( t == '}' ) && ( ig == 0 ) ) {
247         bracecount--;
248       }
249       ig = 0;
250     } while ( bracecount > 0 );
251   }
252   endpos = curpos;
253 
254   len = endpos - startpos;
255   tstr = (char*)_allocsafe( len + 1 );
256   if ( len > 0 ) {
257       strncpy( tstr, scanbuf + startpos, len );
258   }
259   tstr[len] = '\0';
260   /* now turn backslashed {/} to normal {/} and remove first and last brace */
261   t = 0; readpos = 1;
262   for( readpos = 1; readpos < ( len - 1); readpos++ ) {
263     if ( ( tstr[readpos] == '\\' ) &&
264          ( ( tstr[readpos + 1 ] == '{' ) || ( tstr[readpos + 1] == '}' ) ) ) {
265       tstr[t] = tstr[readpos + 1];
266       readpos++;
267     } else {
268       tstr[t] = tstr[readpos];
269     }
270     t++;
271   }
272   tstr[t] = '\0';
273   return tstr;
274 }
275 
do_parse()276 int CondParser::do_parse()
277 {
278   erg_t *e = NULL;
279   int erg;
280 
281   lookahead = lex();
282   if ( lookahead != TOK_DONE ) {
283     e = expr();
284   }
285   if ( e == NULL ) return -1; /* error */
286   erg = e->numval;
287   _freesafe( e->strval );
288   _freesafe( e );
289   if ( lookahead != TOK_DONE ) return -1; /* Not at the end => error */
290   return ( erg == 0 ) ? 0 : 1;
291 }
292 
expr()293 CondParser::erg_t * CondParser::expr()
294 {
295   erg_t *e = NULL, *e2;
296   int oldignore;
297   int l;
298 
299   if ( ( e = factor() ) == NULL ) return NULL;
300   while ( 1 ) {
301     switch ( lookahead ) {
302       case TOK_P_AND:
303 	if ( match( TOK_P_AND ) ) {
304           _freesafe( e->strval );
305           _freesafe( e );
306           return NULL;
307         }
308 
309         oldignore = ignore;
310         if ( e->numval == 0 ) ignore = 1;
311 
312 	if ( ( e2 = factor() ) == NULL ) {
313           _freesafe( e->strval );
314           _freesafe( e );
315           return NULL;
316         }
317 
318         ignore = oldignore;
319 
320         if ( e->numval != 0 ) {
321           e->numval = e2->numval;
322         }
323         _freesafe( e->strval );
324         e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
325         e->wasstring = 0;
326         sprintf( e->strval, "%d", e->numval );
327         _freesafe( e2->strval );
328         _freesafe( e2 );
329         break;
330       case TOK_P_OR:
331 	if ( match( TOK_P_OR ) ) {
332           _freesafe( e->strval );
333           _freesafe( e );
334           return NULL;
335         }
336 
337         oldignore = ignore;
338         if ( e->numval != 0 ) ignore = 1;
339 
340 	if ( ( e2 = factor() ) == NULL ) {
341           _freesafe( e->strval );
342           _freesafe( e );
343           return NULL;
344         }
345 
346         ignore = oldignore;
347 
348         if ( e->numval == 0 ) {
349           e->numval = e2->numval;
350         }
351         _freesafe( e->strval );
352         e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
353         e->wasstring = 0;
354         sprintf( e->strval, "%d", e->numval );
355         _freesafe( e2->strval );
356         _freesafe( e2 );
357         break;
358       case TOK_E:
359       case TOK_NE:
360       case TOK_LT:
361       case TOK_LE:
362       case TOK_GT:
363       case TOK_GE:
364       case TOK_REGEQ:
365         l = lookahead;
366 	if ( match( lookahead ) ) {
367           _freesafe( e->strval );
368           _freesafe( e );
369           return NULL;
370         }
371 
372 	if ( ( e2 = factor() ) == NULL ) {
373           _freesafe( e->strval );
374           _freesafe( e );
375           return NULL;
376         }
377 
378         if ( ( e->wasstring == 1 ) && ( e2->wasstring == 1 ) ) {
379           /* only do strcmp when both are strings */
380           switch ( l ) {
381             case TOK_NE:
382               e->numval = ( strcmp( e->strval, e2->strval ) != 0 );
383               break;
384             case TOK_LT:
385               e->numval = ( strcmp( e->strval, e2->strval ) < 0 );
386               break;
387             case TOK_LE:
388               e->numval = ( strcmp( e->strval, e2->strval ) <= 0 );
389               break;
390             case TOK_GT:
391               e->numval = ( strcmp( e->strval, e2->strval ) > 0 );
392               break;
393             case TOK_GE:
394               e->numval = ( strcmp( e->strval, e2->strval ) >= 0 );
395               break;
396 	    case TOK_REGEQ:
397 	      e->numval = ( re.match( e2->strval, e->strval ) == true );
398               //TODO:bei false k�nnte man e2 und e vertauschen
399 	      break;
400             default:
401               e->numval = ( strcmp( e->strval, e2->strval ) == 0 );
402               break;
403           }
404         } else {
405           switch ( l ) {
406             case TOK_NE:
407               e->numval = ( e->numval != e2->numval );
408               break;
409             case TOK_LT:
410               e->numval = ( e->numval < e2->numval );
411               break;
412             case TOK_LE:
413               e->numval = ( e->numval <= e2->numval );
414               break;
415             case TOK_GT:
416               e->numval = ( e->numval > e2->numval );
417               break;
418             case TOK_GE:
419               e->numval = ( e->numval >= e2->numval );
420               break;
421 	    case TOK_REGEQ:
422 	      // regular expression without strings is always false
423 	      e->numval = 0;
424 	      break;
425             default:
426               e->numval = ( e->numval == e2->numval );
427               break;
428           }
429         }
430         _freesafe( e->strval );
431         e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
432         e->wasstring = 0;
433         sprintf( e->strval, "%d", e->numval );
434         _freesafe( e2->strval );
435         _freesafe( e2 );
436         break;
437       default:
438 	return e;
439     }
440   }
441   return e;
442 }
443 
444 #define W_FREEERG(e) do { \
445   if ( (e) != NULL ) { \
446     _freesafe( (e)->strval ); \
447     _freesafe( (e) ); \
448   } \
449 } while( 0 );
450 
factor()451 CondParser::erg_t *CondParser::factor()
452 {
453   erg_t *e = NULL, *e2 = NULL;
454   int tnum;
455   char *tstr, *tstr2;
456   ExeClass *ec;
457   int exeerror;
458   const char *cstr;
459   int retval;
460 
461   switch ( lookahead ) {
462     case '(':
463       if ( match( '(' ) ) return NULL;
464       if ( ( e = expr() ) == NULL ) return NULL;
465       if ( match( ')' ) ) {
466         W_FREEERG( e );
467         return NULL;
468       }
469       break;
470     case '-':
471       if ( match( '-' ) ) return NULL;
472       tnum = tokenval;
473       if ( match( TOK_NUM ) ) return NULL;
474       e = (erg_t*)_allocsafe( sizeof( erg_t ) );
475       e->numval = tnum * -1;
476       e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
477       e->wasstring = 0;
478       sprintf( e->strval, "%d", e->numval );
479       break;
480     case TOK_NUM:
481       tnum = tokenval;
482       if ( match( TOK_NUM ) ) return NULL;
483       e = (erg_t*)_allocsafe( sizeof( erg_t ) );
484       e->numval = tnum;
485       e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
486       e->wasstring = 0;
487       sprintf( e->strval, "%d", e->numval );
488       break;
489     case TOK_TRUE:
490       if ( match( TOK_TRUE ) ) return NULL;
491       e = (erg_t*)_allocsafe( sizeof( erg_t ) );
492       e->numval = 1;
493       e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
494       e->wasstring = 0;
495       sprintf( e->strval, "%d", e->numval );
496       break;
497     case TOK_FALSE:
498       if ( match( TOK_FALSE ) ) return NULL;
499       e = (erg_t*)_allocsafe( sizeof( erg_t ) );
500       e->numval = 0;
501       e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
502       e->wasstring = 0;
503       sprintf( e->strval, "%d", e->numval );
504       break;
505     case TOK_LASTERROR:
506       if ( match( TOK_LASTERROR ) ) return NULL;
507       e = (erg_t*)_allocsafe( sizeof( erg_t ) );
508       e->numval = getLastError();
509       e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
510       e->wasstring = 0;
511       sprintf( e->strval, "%d", e->numval );
512       resetLastError();
513       break;
514     case '?':
515     case '$':
516       tstr = readBrace();
517       if ( tstr != NULL ) {
518         if ( ignore == 0 ) {
519           /*execute tstr */
520           tstr2 = replaceFlags( tstr /*, a_max( EXE_STRING_LEN - 1024, 256 ) */);
521           _freesafe( tstr );
522           tstr = tstr2;
523 
524           if ( tstr != NULL ) {
525             if ( fe->findOutputAndRV( tstr, &cstr, &retval ) != 0 ) {
526               e = (erg_t*)_allocsafe( sizeof( erg_t ) );
527               ec = new ExeClass();
528               if ( fe != NULL ) {
529                 tstr2 = NWC::Path::parentDir( fe->fullname, NULL );
530                 if ( tstr2 != NULL ) {
531                   ec->cdDir( tstr2 );
532                   _freesafe( tstr2 );
533                 }
534               }
535               ec->addCommand( "%s", tstr );
536               if ( ec->getOutputAndRV( &(e->strval), &retval, &exeerror ) == 0 ) {
537                 if ( lookahead == '?' ) {
538                   e->numval = retval;
539                   if ( e->strval != NULL ) _freesafe( e->strval );
540                   e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
541                   e->wasstring = 0;
542                   sprintf( e->strval, "%d", e->numval );
543                 } else {
544                   e->wasstring = 1;
545                   if ( e->strval == NULL ) {
546                     e->strval = dupstring( "" );
547                   }
548                   e->numval = atoi( e->strval );
549                 }
550 
551                 fe->addOutput( tstr, e->strval, retval );
552               } else {
553                 e->strval = dupstring( "0" );
554                 e->wasstring = 1;
555                 e->numval = atoi( e->strval );
556               }
557               delete ec;
558 
559               if ( exeerror != 0 ) {
560 #if 0
561 //TODO: Requester are not possible at the moment because
562 //      this thread cannot access GUI functions currently
563 //TODO: I should show content of error file just like in wpucontext
564                 if ( worker->getRequester() != NULL ) {
565                   char *reqstr;
566                   reqstr = (char*)_allocsafe( strlen( catalog.getLocale( 473 ) ) + strlen( tstr ) + 1 );
567                   sprintf( reqstr, catalog.getLocale( 473 ), tstr );
568                   worker->getRequester()->request( catalog.getLocale( 347 ), reqstr, catalog.getLocale( 11 ) );
569                   _freesafe( reqstr );
570                 }
571 #endif
572                 W_FREEERG( e );
573                 _freesafe( tstr );
574                 return NULL;
575               }
576             } else {
577               if ( lookahead == '?' ) {
578                 e = (erg_t*)_allocsafe( sizeof( erg_t ) );
579                 e->numval = retval;
580                 e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
581                 e->wasstring = 0;
582                 sprintf( e->strval, "%d", e->numval );
583               } else {
584                 e = (erg_t*)_allocsafe( sizeof( erg_t ) );
585                 e->strval = dupstring( cstr );
586                 e->wasstring = 1;
587                 e->numval = atoi( e->strval );
588               }
589             }
590             _freesafe( tstr );
591           }
592         } else {
593           e = (erg_t*)_allocsafe( sizeof( erg_t ) );
594           e->strval = dupstring( "0" );
595           e->wasstring = 1;
596           e->numval = atoi( e->strval );
597           _freesafe( tstr );
598         }
599       }
600       if ( match( lookahead ) ) {
601         W_FREEERG( e );
602         return NULL;
603       }
604       break;
605     case TOK_STRING:
606       e = (erg_t*)_allocsafe( sizeof( erg_t ) );
607       e->wasstring = 1;
608       if ( ignore == 1 ) {
609         e->strval = dupstring( "0" );
610       } else {
611         e->strval = replaceFlags( lexbuf /*, a_max( EXE_STRING_LEN - 1024, 256 )*/, false );
612         if ( e->strval == NULL ) e->strval = dupstring( "0" );
613       }
614       e->numval = atoi( e->strval );
615       if ( match( TOK_STRING ) ) {
616         W_FREEERG( e );
617         return NULL;
618       }
619       break;
620     case TOK_TONUM:
621       if ( match( TOK_TONUM ) ) return NULL;
622       if ( match( '(' ) ) return NULL;
623       if ( ( e = expr() ) == NULL ) return NULL;
624       if ( match( ')' ) ) {
625         W_FREEERG( e );
626         return NULL;
627       }
628       _freesafe( e->strval );
629       e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
630       e->wasstring = 0;
631       sprintf( e->strval, "%d", e->numval );
632       break;
633     case TOK_TOSTR:
634       if ( match( TOK_TOSTR ) ) return NULL;
635       if ( match( '(' ) ) return NULL;
636       if ( ( e = expr() ) == NULL ) return NULL;
637       if ( match( ')' ) ) {
638         W_FREEERG( e );
639         return NULL;
640       }
641       _freesafe( e->strval );
642       e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
643       e->wasstring = 1;
644       sprintf( e->strval, "%d", e->numval );
645       break;
646     case TOK_ISREG:
647       if ( match( TOK_ISREG ) ) return NULL;
648       if ( match( '(' ) ) return NULL;
649       if ( match( ')' ) ) return NULL;
650       e = (erg_t*)_allocsafe( sizeof( erg_t ) );
651       e->wasstring = 0;
652       if ( fe == NULL ) {
653         e->numval = 0;
654       } else {
655         e->numval = ( S_ISREG( fe->mode() ) ) ? 1 : 0;
656       }
657       e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
658       sprintf( e->strval, "%d", e->numval );
659       break;
660     case TOK_ISSOCK:
661       if ( match( TOK_ISSOCK ) ) return NULL;
662       if ( match( '(' ) ) return NULL;
663       if ( match( ')' ) ) return NULL;
664       e = (erg_t*)_allocsafe( sizeof( erg_t ) );
665       e->wasstring = 0;
666       if ( fe == NULL ) {
667         e->numval = 0;
668       } else {
669 #ifdef S_ISSOCK
670         e->numval = ( S_ISSOCK( fe->mode() ) ) ? 1 : 0;
671 #else
672         e->numval = 0;
673 #endif
674       }
675       e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
676       sprintf( e->strval, "%d", e->numval );
677       break;
678     case TOK_ISFIFO:
679       if ( match( TOK_ISFIFO ) ) return NULL;
680       if ( match( '(' ) ) return NULL;
681       if ( match( ')' ) ) return NULL;
682       e = (erg_t*)_allocsafe( sizeof( erg_t ) );
683       e->wasstring = 0;
684       if ( fe == NULL ) {
685         e->numval = 0;
686       } else {
687         e->numval = ( S_ISFIFO( fe->mode() ) ) ? 1 : 0;
688       }
689       e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
690       sprintf( e->strval, "%d", e->numval );
691       break;
692     case TOK_ISSYMLINK:
693       if ( match( TOK_ISSYMLINK ) ) return NULL;
694       if ( match( '(' ) ) return NULL;
695       if ( match( ')' ) ) return NULL;
696       e = (erg_t*)_allocsafe( sizeof( erg_t ) );
697       e->wasstring = 0;
698       if ( fe == NULL ) {
699         e->numval = 0;
700       } else {
701         e->numval = ( fe->isLink == true ) ? 1 : 0;
702       }
703       e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
704       sprintf( e->strval, "%d", e->numval );
705       break;
706     case TOK_ISBROKENSYMLINK:
707       if ( match( TOK_ISBROKENSYMLINK ) ) return NULL;
708       if ( match( '(' ) ) return NULL;
709       if ( match( ')' ) ) return NULL;
710       e = (erg_t*)_allocsafe( sizeof( erg_t ) );
711       e->wasstring = 0;
712       if ( fe == NULL ) {
713         e->numval = 0;
714       } else {
715         e->numval = ( fe->isLink == true && fe->isCorrupt == true ) ? 1 : 0;
716       }
717       e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
718       sprintf( e->strval, "%d", e->numval );
719       break;
720     case TOK_SIZE:
721       if ( match( TOK_SIZE ) ) return NULL;
722       if ( match( '(' ) ) return NULL;
723       if ( match( ')' ) ) return NULL;
724       e = (erg_t*)_allocsafe( sizeof( erg_t ) );
725       e->wasstring = 0;
726       if ( fe == NULL ) {
727         e->numval = 0;
728       } else {
729         e->numval = fe->size();
730       }
731       e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
732       sprintf( e->strval, "%d", e->numval );
733       break;
734     case TOK_PERM:
735       if ( match( TOK_PERM ) ) return NULL;
736       if ( match( '(' ) ) return NULL;
737       if ( ( e = expr() ) == NULL ) return NULL;
738       if ( match( ')' ) ) {
739         W_FREEERG( e );
740         return NULL;
741       }
742       _freesafe( e->strval );
743       e->wasstring = 0;
744       if ( fe == NULL ) {
745         e->numval = 0;
746       } else {
747         e->numval = ( fe->mode() & e->numval );
748       }
749       e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
750       sprintf( e->strval, "%d", e->numval );
751       break;
752     case TOK_TOLOWER:
753       if ( match( TOK_TOLOWER ) ) return NULL;
754       if ( match( '(' ) ) return NULL;
755       if ( ( e = expr() ) == NULL ) return NULL;
756       if ( match( ')' ) ) {
757         W_FREEERG( e );
758         return NULL;
759       }
760       for ( tstr = e->strval; *tstr != '\0'; tstr++ ) {
761         *tstr = tolower( *tstr );
762       }
763       break;
764     case TOK_TOUPPER:
765       if ( match( TOK_TOUPPER ) ) return NULL;
766       if ( match( '(' ) ) return NULL;
767       if ( ( e = expr() ) == NULL ) return NULL;
768       if ( match( ')' ) ) {
769         W_FREEERG( e );
770         return NULL;
771       }
772       for ( tstr = e->strval; *tstr != '\0'; tstr++ ) {
773         *tstr = toupper( *tstr );
774       }
775       break;
776     case TOK_CONTENTSTR:
777       if ( match( TOK_CONTENTSTR ) ) return NULL;
778       if ( match( '(' ) ) return NULL;
779       if ( ( e = expr() ) == NULL ) return NULL;
780       e2 = NULL;
781       if ( lookahead == ',' ) {
782         if ( match( ',' ) ) {
783           W_FREEERG( e );
784           return NULL;
785         }
786         if ( ( e2 = expr() ) == NULL ) {
787           W_FREEERG( e );
788           return NULL;
789         }
790       }
791       if ( match( ')' ) ) {
792         W_FREEERG( e );
793         W_FREEERG( e2 );
794         return NULL;
795       }
796       if ( fe == NULL ) {
797         e->numval = 0;
798         e->wasstring = 0;
799         _freesafe( e->strval );
800         e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
801         sprintf( e->strval, "%d", e->numval );
802       } else {
803 	if ( ignoreContent == false ) {
804 	  if ( e2 != NULL ) {
805 	    tstr = fe->getContentStr( e->numval, e2->numval );
806 	  } else {
807 	    tstr = fe->getContentStr( e->numval );
808 	  }
809 	} else {
810 	  tstr = dupstring( "" );
811 	}
812         if ( tstr != NULL ) {
813           _freesafe( e->strval );
814           e->strval = tstr;
815           e->numval = atoi( e->strval );
816           e->wasstring = 1;
817         } else {
818           e->numval = 0;
819           e->wasstring = 0;
820           _freesafe( e->strval );
821           e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
822           sprintf( e->strval, "%d", e->numval );
823         }
824       }
825       W_FREEERG( e2 );
826       break;
827     case TOK_CONTENTNUM:
828       if ( match( TOK_CONTENTNUM ) ) return NULL;
829       if ( match( '(' ) ) return NULL;
830       if ( ( e = expr() ) == NULL ) return NULL;
831       e2 = NULL;
832       if ( lookahead == ',' ) {
833         if ( match( ',' ) ) {
834           W_FREEERG( e );
835           return NULL;
836         }
837         if ( ( e2 = expr() ) == NULL ) {
838           W_FREEERG( e );
839           return NULL;
840         }
841       }
842       if ( match( ')' ) ) {
843         W_FREEERG( e );
844         W_FREEERG( e2 );
845         return NULL;
846       }
847       if ( fe == NULL ) {
848         e->numval = 0;
849         e->wasstring = 0;
850         _freesafe( e->strval );
851         e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
852         sprintf( e->strval, "%d", e->numval );
853       } else {
854 	if ( ignoreContent == false ) {
855 	  if ( e2 != NULL ) {
856 	    e->numval = fe->getContentNum( e->numval, e2->numval );
857 	  } else {
858 	    e->numval = fe->getContentNum( e->numval );
859 	  }
860 	} else {
861 	  e->numval = 0;
862 	}
863         e->wasstring = 0;
864         _freesafe( e->strval );
865         e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
866         sprintf( e->strval, "%d", e->numval );
867       }
868       W_FREEERG( e2 );
869       break;
870     case TOK_NAME:
871       if ( match( TOK_NAME ) ) return NULL;
872       if ( match( '(' ) ) return NULL;
873       if ( match( ')' ) ) return NULL;
874       e = (erg_t*)_allocsafe( sizeof( erg_t ) );
875       if ( fe == NULL ) {
876         e->strval = dupstring( "0" );
877       } else {
878         e->strval = dupstring( fe->name );
879       }
880       e->wasstring = 1;
881       e->numval = atoi( e->strval );
882       break;
883     case TOK_FULLNAME:
884       if ( match( TOK_FULLNAME ) ) return NULL;
885       if ( match( '(' ) ) return NULL;
886       if ( match( ')' ) ) return NULL;
887       e = (erg_t*)_allocsafe( sizeof( erg_t ) );
888       if ( fe == NULL ) {
889         e->strval = dupstring( "0" );
890       } else {
891         e->strval = dupstring( fe->fullname );
892       }
893       e->wasstring = 1;
894       e->numval = atoi( e->strval );
895       break;
896     case TOK_ISLOCAL:
897       if ( match( TOK_ISLOCAL ) ) return NULL;
898       if ( match( '(' ) ) return NULL;
899       if ( match( ')' ) ) return NULL;
900       e = (erg_t*)_allocsafe( sizeof( erg_t ) );
901       e->wasstring = 0;
902       if ( fe == NULL ) {
903         e->numval = 0;
904       } else {
905         e->numval = worker_islocal( fe->fullname );
906       }
907       e->strval = (char*)_allocsafe( A_BYTESFORNUMBER( e->numval ) );
908       sprintf( e->strval, "%d", e->numval );
909       break;
910     default:
911       return NULL;
912   }
913   return e;
914 }
915 
parse(const char * str,FileEntry * tfe)916 int CondParser::parse( const char *str, FileEntry *tfe )
917 {
918   int erg;
919 
920   if ( str == NULL ) return -1;
921   fe = tfe;
922   scanbuf = str;
923   scanbuflen = strlen( str );
924   curpos = 0;
925   erg = do_parse();
926   scanbuf = NULL;
927   scanbuflen = -1;
928   fe = NULL;
929   return erg;
930 }
931 
getLastError() const932 int CondParser::getLastError() const
933 {
934   return lasterror;
935 }
936 
resetLastError()937 void CondParser::resetLastError()
938 {
939   lasterror = 0;
940 }
941 
942 #define PARSECAT( str1 ) \
943 do { \
944   if ( ( quote == true ) && ( force_noquoting == false ) ) { \
945     dstr[dpos] = '\0'; \
946     newdstr = AGUIX_catTrustedAndUnTrusted( dstr, ( str1 ) ); \
947     if ( (int)strlen( newdstr ) >= maxlen ) { \
948       _freesafe( dstr ); \
949       maxlen = 2 * (int)strlen( newdstr ); \
950       dstr = (char*)_allocsafe( maxlen + 1 ); \
951     } \
952     snprintf( dstr, maxlen, "%s", newdstr ); \
953     _freesafe( newdstr ); \
954     dstr[maxlen] = '\0'; \
955     dpos = (int)strlen( dstr ); \
956   } else { \
957     tlen = (int)strlen( ( str1 ) ); \
958     if ( ( dpos + tlen ) >= maxlen ) { \
959       maxlen = ( dpos + tlen ) * 2; \
960       newdstr = (char*)_allocsafe( maxlen + 1 ); \
961       strncpy( newdstr, dstr, dpos ); \
962       _freesafe( dstr ); \
963       dstr = newdstr; \
964     } \
965     strcpy( &dstr[dpos], ( str1 ) ); \
966     dpos += (int)strlen( ( str1 ) ); \
967   } \
968 } while ( 0 );
969 
970 #define PUTCHARDSTR( ch ) \
971 do { \
972   if ( dpos >= maxlen ) { \
973     maxlen = dpos * 2; \
974     newdstr = (char*)_allocsafe( maxlen + 1 ); \
975     strncpy( newdstr, dstr, dpos ); \
976     _freesafe( dstr ); \
977     dstr = newdstr; \
978   } \
979   dstr[dpos++] = ch; \
980 } while ( 0 );
981 
replaceFlags(const char * sstr,bool quote)982 char *CondParser::replaceFlags( const char *sstr, bool quote )
983 {
984   char *dstr = NULL, *buf1, ch, *newdstr;
985   int spos=0,dpos=0,bracketcount=0,bufpos=0;
986   int mode=0;
987   int tlen;
988   bool ende;
989   char *tstr;
990   std::string str1;
991   char *flagbuf;
992   int flagbuf_size;
993   bool force_noquoting;
994   int maxlen;
995 
996   if ( sstr == NULL ) return NULL;
997   maxlen = strlen( sstr );
998   dstr = (char*)_allocsafe( maxlen + 1 );
999   flagbuf_size = strlen( sstr );
1000   flagbuf = (char*)_allocsafe( flagbuf_size + 1 );
1001   if(dstr!=NULL) {
1002     for(ende=false;ende==false;) {
1003       ch=sstr[spos++];
1004       if(ch=='\0') break;
1005       switch(mode) {
1006         case 1:
1007           // we are in a open bracket and waiting for close bracket
1008           if(ch=='{') {
1009             // other flag, perhaps useless, but perhaps it is in a String-requester
1010             // in any case just overtake it in the buffer
1011             if ( bufpos < flagbuf_size ) flagbuf[ bufpos++ ] = ch;
1012             bracketcount++;
1013           } else if(ch=='}') {
1014             // a closeing bracket
1015             if(bracketcount>1) {
1016               // this is a bracket in the bracket
1017               if ( bufpos < flagbuf_size ) flagbuf[ bufpos++ ] = ch;
1018             } else {
1019               // this is the awaited closebracket
1020               flagbuf[ bufpos ] = 0;
1021               // now flagbuf contains a flag which must be parsed
1022               mode=3;
1023             }
1024             bracketcount--;
1025           } else if(ch=='\\') {
1026             // backslash are only resolved on toplevel (bracketcount==0)
1027             // so overtake also this
1028             if ( bufpos < flagbuf_size ) flagbuf[ bufpos++ ] = ch;
1029             mode=4;
1030           } else {
1031             if ( bufpos < flagbuf_size ) flagbuf[ bufpos++ ] = ch;
1032           }
1033           break;
1034         case 2:
1035           PUTCHARDSTR( ch );
1036           mode=0;
1037           break;
1038         case 4:
1039           if ( bufpos < flagbuf_size ) flagbuf[ bufpos++ ] = ch;
1040           mode=1;
1041           break;
1042         default:
1043           // we are in no bracket
1044           if(ch=='\\') {
1045             // next character is protected and will be overtaken
1046             mode=2;
1047           } else if(ch!='{') {
1048             // a normal character
1049             PUTCHARDSTR( ch );
1050           } else {
1051             mode=1;
1052             bracketcount++;
1053             bufpos=0;
1054           }
1055           break;
1056       }
1057       if(mode==3) {
1058         if ( flagbuf[0] == '-' ) {
1059           force_noquoting = true;
1060           buf1 = flagbuf + 1;
1061         } else {
1062           force_noquoting = false;
1063           buf1 = flagbuf;
1064         }
1065         // parse buf1
1066         if ( strncmp( buf1, "f", 1 ) == 0 ) {
1067           if ( fe != NULL ) {
1068             tstr = fe->name;
1069             if ( tstr != NULL ) {
1070               PARSECAT( tstr );
1071             }
1072           }
1073         } else if ( strncmp( buf1, "F", 1 ) == 0 ) {
1074           if ( fe != NULL ) {
1075             tstr = fe->fullname;
1076             if ( tstr != NULL ) {
1077               PARSECAT( tstr );
1078             }
1079           }
1080         }
1081         mode=0;
1082       }
1083     }
1084     dstr[dpos]=0;
1085   }
1086   _freesafe( flagbuf );
1087   return dstr;
1088 }
1089 
requestFlag()1090 const char *CondParser::requestFlag()
1091 {
1092   AGUIX *aguix = Worker::getAGUIX();
1093   AWindow *win;
1094   FieldListView *lv;
1095   AGMessage *msg;
1096   int endmode=-1;
1097   const char *returnstr;
1098   int i, trow, nr;
1099 
1100   win = new AWindow( aguix, 10, 10, 10, 10, catalog.getLocale( 338 ), AWindow::AWINDOW_DIALOG );
1101   win->create();
1102 
1103   AContainer *ac1 = win->setContainer( new AContainer( win, 1, 3 ), true );
1104   ac1->setMinSpace( 5 );
1105   ac1->setMaxSpace( 5 );
1106   ac1->setBorderWidth( 5 );
1107 
1108   win->addMultiLineText( catalog.getLocale( 578 ), *ac1, 0, 0, NULL, NULL );
1109 
1110   lv = (FieldListView*)ac1->add( new FieldListView( aguix,
1111                                                     0,
1112                                                     0,
1113                                                     400,
1114                                                     200,
1115                                                     0 ),
1116                                  0, 1, AContainer::CO_MIN );
1117   lv->setHBarState(2);
1118   lv->setVBarState(2);
1119 
1120   lv->setNrOfFields( 3 );
1121   lv->setFieldWidth( 1, 3 );
1122 
1123   nr = sizeof( flags ) / sizeof( flags[0] );
1124 
1125   for ( i = 0; i < nr; i++ ) {
1126     trow = lv->addRow();
1127     lv->setText( trow, 0, flags[i].flag );
1128     if ( flags[i].catID >= 0 ) {
1129       lv->setText( trow, 2, catalog.getLocale( flags[i].catID ) );
1130     } else {
1131       lv->setText( trow, 2, catalog.getLocaleFlag( flags[i].catflagID ) );
1132     }
1133     lv->setPreColors( trow, FieldListView::PRECOLOR_ONLYACTIVE );
1134     lv->setData( trow, i );
1135   }
1136 
1137   AContainer *ac1_1 = ac1->add( new AContainer( win, 2, 1 ), 0, 2 );
1138   ac1_1->setMinSpace( 5 );
1139   ac1_1->setMaxSpace( -1 );
1140   ac1_1->setBorderWidth( 0 );
1141   Button *okb =(Button*)ac1_1->add( new Button( aguix,
1142                                                 0,
1143                                                 0,
1144                                                 catalog.getLocale( 11 ),
1145                                                 0 ), 0, 0, AContainer::CO_FIX );
1146   Button *cancelb = (Button*)ac1_1->add( new Button( aguix,
1147 						     0,
1148 						     0,
1149 						     catalog.getLocale( 8 ),
1150 						     0 ), 1, 0, AContainer::CO_FIX );
1151 
1152   win->setDoTabCycling( true );
1153   win->contMaximize( true );
1154   win->show();
1155   for(;endmode==-1;) {
1156     msg=aguix->WaitMessage(win);
1157     if(msg!=NULL) {
1158       switch(msg->type) {
1159         case AG_CLOSEWINDOW:
1160           if(msg->closewindow.window==win->getWindow()) endmode=1;
1161           break;
1162         case AG_BUTTONCLICKED:
1163           if(msg->button.button==okb) endmode=0;
1164           else if(msg->button.button==cancelb) endmode=1;
1165           break;
1166       }
1167       aguix->ReplyMessage(msg);
1168     }
1169   }
1170 
1171   returnstr = NULL;
1172   if(endmode==0) {
1173     // ok
1174     trow = lv->getActiveRow();
1175     if ( lv->isValidRow( trow ) == true ) {
1176       i = lv->getData( trow, 0 );
1177       returnstr = flags[i].flag;
1178     }
1179   }
1180 
1181   delete win;
1182 
1183   return returnstr;
1184 }
1185 
getOutput(const char * str,FileEntry * tfe)1186 char *CondParser::getOutput( const char *str, FileEntry *tfe )
1187 {
1188   if ( ( str == NULL ) || ( tfe == NULL ) ) return NULL;
1189   char *erg = NULL;
1190   int retval = 0;
1191   int exeerror = 0;
1192   ExeClass *ec;
1193   char *tstr, *tstr2;
1194 
1195   fe = tfe;
1196   tstr = replaceFlags( str );
1197 
1198   if ( tstr != NULL ) {
1199     ec = new ExeClass();
1200     tstr2 = NWC::Path::parentDir( fe->fullname, NULL );
1201     if ( tstr2 != NULL ) {
1202       ec->cdDir( tstr2 );
1203       _freesafe( tstr2 );
1204     }
1205     ec->addCommand( "%s", tstr );
1206     if ( ec->getOutputAndRV( &erg, &retval, &exeerror ) != 0 ) {
1207       erg = NULL;
1208     }
1209     delete ec;
1210     _freesafe( tstr );
1211   }
1212   fe = NULL;
1213   return erg;
1214 }
1215 
setIgnoreContent(bool nv)1216 void CondParser::setIgnoreContent( bool nv )
1217 {
1218   ignoreContent = nv;
1219 }
1220 
getIgnoreContent() const1221 bool CondParser::getIgnoreContent() const
1222 {
1223   return ignoreContent;
1224 }
1225