Line data Source code
1 : /*
2 : --
3 : -- SYNOPSIS
4 : -- GNU style functions for dmake.
5 : --
6 : -- DESCRIPTION
7 : -- All GNU style functions understood by dmake are implemented in this
8 : -- file. Currently the only such function is $(mktmp ...) which is
9 : -- not part of GNU-make is an extension provided by dmake.
10 : --
11 : -- AUTHOR
12 : -- Dennis Vadura, dvadura@dmake.wticorp.com
13 : --
14 : -- WWW
15 : -- http://dmake.wticorp.com/
16 : --
17 : -- COPYRIGHT
18 : -- Copyright (c) 1996,1997 by WTI Corp. All rights reserved.
19 : --
20 : -- This program is NOT free software; you can redistribute it and/or
21 : -- modify it under the terms of the Software License Agreement Provided
22 : -- in the file <distribution-root>/readme/license.txt.
23 : --
24 : -- LOG
25 : -- Use cvs log to obtain detailed change logs.
26 : */
27 :
28 : #include "extern.h"
29 :
30 : static char *_exec_mktmp ANSI((char *, char *, char *));
31 : static char *_exec_subst ANSI((char *, char *, char *));
32 : static char *_exec_iseq ANSI((char *, char *, char *, int));
33 : static char *_exec_sort ANSI((char *));
34 : static char *_exec_echo ANSI((char *));
35 : static char *_exec_uniq ANSI((char *));
36 : static char *_exec_shell ANSI((char *, int));
37 : static char *_exec_call ANSI((char *, char *));
38 : static char *_exec_assign ANSI((char *));
39 : static char *_exec_foreach ANSI((char *, char *, char *));
40 : static char *_exec_andor ANSI((char *, int));
41 : static char *_exec_not ANSI((char *));
42 : static int _mystrcmp ANSI((const DMPVOID, const DMPVOID));
43 :
44 :
45 : PUBLIC char *
46 29592 : Exec_function(buf)/*
47 : ====================
48 : Execute the function given by the value of args.
49 :
50 : So far mktmp is the only valid function, anything else elicits and error
51 : message. It is my hope to support the GNU style functions in this portion
52 : of the code at some time in the future. */
53 : char *buf;
54 : {
55 : char *fname;
56 : char *args;
57 : char *mod1;
58 29592 : char *mod2 = NIL(char);
59 29592 : int mod_count = 0;
60 29592 : char *res = NIL(char);
61 :
62 : /* This must succeed since the presence of ' ', \t or \n is what
63 : * determines if this function is called in the first place.
64 : * Unfortunately this prohibits the use of whitespaces in parameters
65 : * for macro functions. */
66 : /* ??? Using ScanToken to find the next ' ', \t or \n and discarding
67 : * the returned, evaluated result is a misuse of that function. */
68 29592 : FREE(ScanToken(buf, &args, FALSE));
69 29592 : fname = DmSubStr(buf, args);
70 : /* args points to the whitespace after the found token, this leads
71 : * to leading whitespaces. */
72 29592 : if( *args ) {
73 29592 : args = DmStrSpn(args," \t"); /* strip whitespace before */
74 29592 : if( *args ) { /* ... and after value */
75 : char *q;
76 29592 : for(q=args+strlen(args)-1; ((*q == ' ')||(*q == '\t')); q--);
77 29592 : *++q = '\0';
78 : }
79 : }
80 :
81 : /* ??? Some function macros expect comma seperated parameters, but
82 : * no decent parser is included. The desirable solution would be
83 : * to parse fname for the correct number of parameters in fname
84 : * when a function is recognized. We only count the parameters
85 : * at the moment. Note "" is a valid parameter. */
86 29592 : if( (mod1 = strchr(fname,',')) != NIL(char) ){
87 27528 : *mod1 = '\0';
88 27528 : mod1++;
89 27528 : mod_count++;
90 :
91 27528 : if( (mod2 = strchr(mod1,',')) != NIL(char) ){
92 26336 : *mod2 = '\0';
93 26336 : mod2++;
94 26336 : mod_count++;
95 : }
96 : }
97 :
98 : /* ??? At the moment only the leading part of fname compared if it
99 : * matches a known function macro. For example assignXXX or even
100 : * assign,,,, is also erroneously accepted. */
101 29592 : switch( *fname ) {
102 : case 'a':
103 22 : if(strncmp(fname,"assign",6) == 0)
104 22 : res = _exec_assign(args);
105 0 : else if(strncmp(fname,"and",3) == 0)
106 0 : res = _exec_andor(args, TRUE);
107 : else
108 0 : res = _exec_call(fname,args);
109 22 : break;
110 :
111 : case 'e':
112 310 : if(strncmp(fname,"eq",2) == 0)
113 310 : if( mod_count == 2 )
114 310 : res = _exec_iseq(mod1,mod2,args,TRUE);
115 : else
116 0 : Fatal( "Two comma-seperated arguments expected in [%s].\n", buf );
117 0 : else if (strncmp(fname,"echo",4) == 0)
118 0 : res = _exec_echo(args);
119 : else
120 0 : res = _exec_call(fname,args);
121 310 : break;
122 :
123 : case 'f':
124 5796 : if(strncmp(fname,"foreach",7) == 0)
125 5796 : if( mod_count == 2 )
126 5796 : res = _exec_foreach(mod1,mod2,args);
127 : else
128 0 : Fatal( "Two comma-seperated arguments expected in [%s].\n", buf );
129 : else
130 0 : res = _exec_call(fname,args);
131 5796 : break;
132 :
133 : case 'm':
134 362 : if(strncmp(fname,"mktmp",5) == 0)
135 362 : if( mod_count < 3 )
136 362 : res = _exec_mktmp(mod1,mod2,args);
137 : else
138 0 : Fatal( "Maximal two comma-seperated arguments expected in [%s].\n", buf );
139 : else
140 0 : res = _exec_call(fname,args);
141 362 : break;
142 :
143 : case 'n':
144 1192 : if( strncmp(fname,"null", 4) == 0 )
145 1192 : res = _exec_iseq(mod1,NIL(char),args,TRUE);
146 0 : else if (strncmp(fname,"nil",3) == 0 ) {
147 0 : FREE(Expand(args));
148 0 : res = DmStrDup("");
149 : }
150 0 : else if (strncmp(fname,"not",3) == 0 )
151 0 : res = _exec_not(args);
152 0 : else if (strncmp(fname,"normpath",8) == 0 ) {
153 0 : char *eargs = Expand(args);
154 :
155 0 : if( mod_count == 0 ) {
156 0 : res = exec_normpath(eargs);
157 : }
158 0 : else if( mod_count == 1 ) {
159 0 : char *para = Expand(mod1);
160 0 : int tmpUseWinpath = UseWinpath;
161 :
162 0 : if( !*para || strcmp(para, "\"\"") == 0 ) {
163 0 : UseWinpath = FALSE;
164 : } else {
165 0 : UseWinpath = TRUE;
166 : }
167 0 : res = exec_normpath(eargs);
168 0 : UseWinpath = tmpUseWinpath;
169 0 : FREE(para);
170 : }
171 : else
172 0 : Fatal( "One or no comma-seperated arguments expected in [%s].\n", buf );
173 :
174 0 : FREE(eargs);
175 : }
176 : else
177 0 : res = _exec_call(fname,args);
178 1192 : break;
179 :
180 : case '!':
181 0 : if(strncmp(fname,"!null",5) == 0)
182 0 : res = _exec_iseq(mod1,NIL(char),args,FALSE);
183 0 : else if(strncmp(fname,"!eq",3) ==0)
184 0 : if( mod_count == 2 )
185 0 : res = _exec_iseq(mod1,mod2,args,FALSE);
186 : else
187 0 : Fatal( "Two comma-seperated arguments expected in [%s].\n", buf );
188 : else
189 0 : res = _exec_call(fname,args);
190 0 : break;
191 :
192 : case 'o':
193 0 : if(strncmp(fname,"or",2) == 0)
194 0 : res = _exec_andor(args, FALSE);
195 : else
196 0 : res = _exec_call(fname,args);
197 0 : break;
198 :
199 : case 's':
200 21394 : if(strncmp(fname,"sort",4) == 0)
201 0 : res = _exec_sort(args);
202 21394 : else if(strncmp(fname,"shell",5)==0)
203 384 : if( mod_count == 0 ) {
204 384 : res = _exec_shell(args, FALSE);
205 : }
206 0 : else if( mod_count == 1 ) {
207 0 : char *emod = Expand(mod1);
208 0 : if(strncmp(emod,"expand",7)==0)
209 0 : res = _exec_shell(args, TRUE);
210 : else
211 0 : Fatal( "Unknown argument [%s] to shell in [%s].\n", emod, buf );
212 0 : FREE(emod);
213 : }
214 : else
215 0 : Fatal( "One or no comma-seperated arguments expected in [%s].\n", buf );
216 21010 : else if(strncmp(fname,"strip",5)==0)
217 780 : res = Tokenize(Expand(args)," ",'t',TRUE);
218 20230 : else if(strncmp(fname,"subst",5)==0) {
219 20230 : if( mod_count == 2 )
220 20230 : res = _exec_subst(mod1,mod2,args);
221 : else
222 0 : Fatal( "Two comma-seperated arguments expected in [%s].\n", buf );
223 : }
224 : else
225 0 : res = _exec_call(fname,args);
226 21394 : break;
227 :
228 : case 'u':
229 516 : if(strncmp(fname,"uniq",4) == 0)
230 516 : res = _exec_uniq(args);
231 : else
232 0 : res = _exec_call(fname,args);
233 516 : break;
234 :
235 : default:
236 0 : res = _exec_call(fname,args);
237 : }
238 :
239 29592 : if( res == NIL(char) ) res = DmStrDup("");
240 :
241 29592 : FREE(fname);
242 29592 : return(res);
243 : }
244 :
245 :
246 : static char *
247 22 : _exec_assign( macrostring )
248 : char *macrostring;
249 : {
250 22 : if ( !Parse_macro(macrostring, M_MULTI|M_FORCE) ) {
251 0 : Error( "Dynamic macro assignment failed, while making [%s]\n",
252 0 : Current_target ? Current_target->CE_NAME : "NIL");
253 0 : return(DmStrDup(""));
254 : }
255 :
256 22 : return(DmStrDup(LastMacName));
257 : }
258 :
259 :
260 : static char *
261 0 : _exec_echo(data)
262 : char *data;
263 : {
264 0 : return(DmStrDup(DmStrSpn(data," \t")));
265 : }
266 :
267 :
268 : static char *
269 0 : _exec_call( var, list )/*
270 : =========================
271 : Return the (recursively expanded) value of macro var. Expand list and
272 : discard the result.
273 : */
274 : char *var; /* Name of the macro (until first whitespace). */
275 : char *list; /* Rest data (after the whitespace). */
276 : {
277 0 : char *res = NIL(char);
278 :
279 : /* the argument part is expanded. */
280 0 : FREE(Expand(list));
281 :
282 : /* Prepend '$(' and append ')' so that Expand will return the value
283 : * of the 'var' macro. */
284 0 : var = DmStrJoin(DmStrJoin("$(",var,-1,FALSE),")",-1,TRUE);
285 0 : res = Expand(var);
286 :
287 0 : FREE(var);
288 0 : return(res);
289 : }
290 :
291 :
292 : static char *
293 5796 : _exec_foreach( var, list, data )
294 : char *var;
295 : char *list;
296 : char *data;
297 : {
298 5796 : char *res = NIL(char);
299 : char *s;
300 : TKSTR tk;
301 : HASHPTR hp;
302 :
303 5796 : var = Expand(var);
304 5796 : list = Expand(list);
305 :
306 5796 : data = DmStrSpn(data," \t\n");
307 5796 : SET_TOKEN(&tk,list);
308 : /* push previous macro definition and redefine. */
309 5796 : hp = Def_macro(var,"",M_MULTI|M_NOEXPORT|M_FORCE|M_PUSH);
310 :
311 39330 : while( *(s=Get_token(&tk, "", FALSE)) != '\0' ) {
312 27738 : Def_macro(var,s,M_MULTI|M_NOEXPORT|M_FORCE);
313 27738 : res = DmStrAdd(res,Expand(data),TRUE);
314 : }
315 :
316 5796 : CLEAR_TOKEN(&tk);
317 5796 : Pop_macro(hp); /* Get back old macro definition. */
318 5796 : FREE(hp->ht_name);
319 5796 : if(hp->ht_value) FREE(hp->ht_value);
320 5796 : FREE(hp);
321 5796 : FREE(var);
322 5796 : FREE(list);
323 :
324 5796 : return(res);
325 : }
326 :
327 :
328 : static char *
329 362 : _exec_mktmp( file, text, data )
330 : char *file;
331 : char *text;
332 : char *data;
333 : {
334 : char *tmpname;
335 : char *name;
336 362 : FILE *tmpfile = NIL(FILE);
337 :
338 : /* This is only a test of the recipe line so prevent the tempfile side
339 : * effects. */
340 362 : if( Suppress_temp_file ) return(NIL(char));
341 :
342 362 : name = Current_target ? Current_target->CE_NAME:"makefile text";
343 :
344 362 : if( file && *file ) {
345 : /* Expand the file parameter to mktmp if present. */
346 0 : tmpname = Expand(file);
347 :
348 0 : if( *tmpname ) {
349 : #ifdef HAVE_MKSTEMP
350 : /* Only use umask if we are also using mkstemp - this basically
351 : * avoids using the incompatible implementation from MSVC. */
352 : mode_t mask;
353 :
354 : /* Create tempfile with 600 permissions. */
355 0 : mask = umask(0066);
356 : #endif
357 :
358 0 : if( (tmpfile = fopen(tmpname, "w")) == NIL(FILE) )
359 0 : Open_temp_error( tmpname, name );
360 : #ifdef HAVE_MKSTEMP
361 0 : umask(mask);
362 : #endif
363 :
364 0 : Def_macro("TMPFILE", tmpname, M_EXPANDED|M_MULTI);
365 0 : Link_temp( Current_target, tmpfile, tmpname );
366 :
367 : /* Don't free tmpname if it is used. It is stored in a FILELIST
368 : * member in Link_temp() and freed by Unlink_temp_files(). */
369 : }
370 : else
371 0 : FREE(tmpname);
372 : }
373 :
374 : /* If file expanded to a non empty value tmpfile is already opened,
375 : * otherwise open it now. */
376 362 : if( !tmpfile )
377 362 : tmpfile = Start_temp( "", Current_target, &tmpname );
378 :
379 : /* If the text parameter is given return its expanded value
380 : * instead of the used filename. */
381 362 : if( !text || !*text ) {
382 : /* tmpname is freed by Unlink_temp_files(). */
383 362 : text = DmStrDup(DO_WINPATH(tmpname));
384 : }
385 : else {
386 0 : text = Expand(text);
387 : }
388 :
389 362 : data = Expand(data);
390 :
391 362 : Append_line( data, TRUE, tmpfile, name, FALSE, FALSE );
392 362 : Close_temp( Current_target, tmpfile );
393 362 : FREE(data);
394 :
395 362 : return( text );
396 : }
397 :
398 :
399 : static char *
400 1502 : _exec_iseq( lhs, rhs, data, eq )
401 : char *lhs;
402 : char *rhs;
403 : char *data;
404 : int eq;
405 : {
406 1502 : char *l = Expand(lhs);
407 1502 : char *r = Expand(rhs);
408 1502 : char *i = DmStrSpn(data, " \t\n");
409 1502 : char *e = strchr(i, ' ');
410 1502 : char *res = NIL(char);
411 1502 : int val = strcmp(l,r);
412 :
413 1502 : if( (!val && eq) || (val && !eq) ) {
414 1290 : if( e != NIL(char) ) *e = '\0';
415 1290 : res = Expand(i);
416 : }
417 212 : else if( e != NIL(char) ) {
418 212 : e = DmStrSpn(e," \t\n");
419 212 : if( *e ) res = Expand(e);
420 : }
421 :
422 1502 : FREE(l);
423 1502 : FREE(r);
424 1502 : return(res);
425 : }
426 :
427 :
428 : static char *
429 0 : _exec_sort( args )
430 : char *args;
431 : {
432 0 : char *res = NIL(char);
433 0 : char *data = Expand(args);
434 : char **tokens;
435 : char *p;
436 0 : char *white = " \t\n";
437 : int j;
438 : int i;
439 :
440 0 : for(i=0,p=DmStrSpn(data,white);*p;p=DmStrSpn(DmStrPbrk(p,white),white),i++);
441 :
442 0 : if( i != 0 ) {
443 0 : TALLOC(tokens, i, char *);
444 :
445 0 : for( i=0,p=DmStrSpn(data,white); *p; p=DmStrSpn(p,white),i++){
446 0 : tokens[i] = p;
447 0 : p = DmStrPbrk(p,white);
448 0 : if( *p ) *p++ = '\0';
449 : }
450 :
451 0 : qsort( tokens, i, sizeof(char *), _mystrcmp );
452 :
453 0 : for( j=0; j<i; j++ ) res = DmStrApp(res, tokens[j]);
454 0 : FREE(data);
455 0 : FREE(tokens);
456 : }
457 :
458 0 : return(res);
459 : }
460 :
461 :
462 : static char *
463 516 : _exec_uniq( args )
464 : char *args;
465 : {
466 516 : char *res = NIL(char);
467 516 : char *data = Expand(args);
468 : char **tokens;
469 : char **tokens_after;
470 : char *p;
471 516 : char *white = " \t\n";
472 : int j;
473 : int i;
474 516 : char *last = "";
475 516 : int k = 0;
476 :
477 516 : for(i=0,p=DmStrSpn(data,white);*p;p=DmStrSpn(DmStrPbrk(p,white),white),i++);
478 :
479 516 : if( i != 0 ) {
480 2 : TALLOC(tokens, i, char *);
481 2 : TALLOC(tokens_after, i, char *);
482 :
483 4 : for( i=0,p=DmStrSpn(data,white); *p; p=DmStrSpn(p,white),i++){
484 2 : tokens[i] = p;
485 2 : p = DmStrPbrk(p,white);
486 2 : if( *p ) *p++ = '\0';
487 : }
488 :
489 2 : qsort( tokens, i, sizeof(char *), _mystrcmp );
490 :
491 4 : for( j=0; j<i; j++ ) {
492 2 : if (strcmp(tokens[j], last) != 0) {
493 2 : tokens_after[k++] = tokens[j];
494 2 : last = tokens[j];
495 : }
496 : }
497 :
498 2 : for( j=0; j<k; j++ ) res = DmStrApp(res, tokens_after[j]);
499 2 : FREE(tokens);
500 2 : FREE(tokens_after);
501 : }
502 :
503 516 : FREE(data);
504 516 : return(res);
505 : }
506 :
507 : static int
508 0 : _mystrcmp( p, q )
509 : const DMPVOID p;
510 : const DMPVOID q;
511 : {
512 0 : return(strcmp(*((const char **)p),*((const char **)q)));
513 : }
514 :
515 :
516 : static char *
517 20230 : _exec_subst( pat, subst, data )
518 : char *pat;
519 : char *subst;
520 : char *data;
521 : {
522 : char *res;
523 :
524 20230 : pat = Expand(pat);
525 20230 : subst = Expand(subst);
526 :
527 : /* This implies FREE(Expand(data)) */
528 20230 : res = Apply_edit( Expand(data), pat, subst, TRUE, FALSE );
529 20230 : FREE(pat);
530 20230 : FREE(subst);
531 :
532 20230 : return(res);
533 : }
534 :
535 :
536 : static char *
537 384 : _exec_shell( data, expand )/*
538 : =============================
539 : Capture the stdout of an execuded command.
540 : If expand is TRUE expand the result. */
541 : char *data;
542 : int expand;
543 : {
544 : extern char *tempnam();
545 : int bsize;
546 : char *buffer;
547 : char *tmpnm;
548 384 : FILE *old_stdout_redir = stdout_redir;
549 :
550 384 : int wait = Wait_for_completion;
551 384 : int old_is_exec_shell = Is_exec_shell;
552 384 : CELLPTR old_Shell_exec_target = Shell_exec_target;
553 384 : uint16 vflag = Verbose;
554 384 : int tflag = Trace;
555 384 : char *res = NIL(char);
556 : CELL cell;
557 : STRING rcp;
558 : HASH cname;
559 :
560 384 : if( Suppress_temp_file ) return(NIL(char));
561 :
562 : /* Set the temp CELL used for building prerequisite candidates to
563 : * all zero so that we don't have to keep initializing all the
564 : * fields. */
565 : {
566 384 : register char *s = (char *) &cell;
567 384 : register int n = sizeof(CELL);
568 384 : while( n ) { *s++ = '\0'; n--; }
569 : }
570 384 : rcp.st_string = DmStrSpn(data, " \t+-%@");
571 384 : rcp.st_attr = Rcp_attribute( data );
572 384 : rcp.st_next = NIL(STRING);
573 384 : cname.ht_name = "Shell escape";
574 384 : cell.ce_name = &cname;
575 384 : cell.ce_all.cl_prq = &cell;
576 384 : cell.ce_all.cl_next = NIL(LINK);
577 384 : cell.ce_all.cl_flag = 0;
578 384 : cell.ce_fname = cname.ht_name;
579 384 : cell.ce_recipe = &rcp;
580 384 : cell.ce_flag = F_TARGET|F_RULES;
581 : /* Setting A_SILENT supresses the recipe output from Print_cmnd(). */
582 384 : cell.ce_attr = A_PHONY|A_SILENT|A_SHELLESC;
583 :
584 384 : if( Measure & M_TARGET )
585 0 : Do_profile_output( "s", M_TARGET, &cell );
586 :
587 : /* Print the shell escape command. */
588 384 : if( Verbose & V_FORCEECHO ) {
589 0 : printf( "%s: Executing shell macro: %s\n", Pname, data );
590 0 : fflush(stdout);
591 : }
592 :
593 384 : if( (stdout_redir = Get_temp(&tmpnm, "w+")) == NIL(FILE) )
594 0 : Open_temp_error( tmpnm, cname.ht_name );
595 :
596 384 : bsize = (Buffer_size < BUFSIZ)?BUFSIZ:Buffer_size;
597 384 : buffer = MALLOC(bsize,char);
598 :
599 : /* As this function redirects the output of stdout we have to make sure
600 : * that only this single command is executed and all previous recipe lines
601 : * that belong to the same target have finished. With Shell_exec_target and
602 : * Wait_for_completion set this is realized. Current_target being NIL(CELL)
603 : * outside of recipe lines makes sure that no waiting for previous recipe
604 : * lines has to be done. */
605 384 : Wait_for_completion = TRUE;
606 384 : Is_exec_shell = TRUE;
607 384 : Shell_exec_target = Current_target;
608 384 : Verbose &= V_LEAVE_TMP;
609 384 : Trace = FALSE;
610 :
611 : /* The actual redirection happens in runargv(). */
612 384 : Exec_commands( &cell );
613 :
614 384 : Unlink_temp_files( &cell );
615 :
616 384 : Trace = tflag;
617 384 : Verbose = vflag;
618 384 : Wait_for_completion = wait;
619 384 : Is_exec_shell = old_is_exec_shell;
620 384 : Shell_exec_target = old_Shell_exec_target;
621 :
622 : /* Now we have to read the temporary file, get the tokens and return them
623 : * as a string. */
624 384 : rewind(stdout_redir);
625 1150 : while( fgets(buffer, bsize, stdout_redir) ) {
626 382 : char *p = strchr(buffer, '\n');
627 :
628 382 : if( p == NIL(char) )
629 184 : res = DmStrJoin(res,buffer,-1,TRUE);
630 : else {
631 198 : *p = '\0';
632 : /* You might encounter '\r\n' on windows, handle it. */
633 198 : if( p > buffer && *(p-1) == '\r')
634 0 : *(p-1) = '\0';
635 198 : res = DmStrApp(res,buffer);
636 : }
637 : }
638 :
639 384 : fclose(stdout_redir);
640 384 : Remove_file(tmpnm);
641 384 : FREE(tmpnm);
642 384 : FREE(buffer);
643 :
644 384 : stdout_redir = old_stdout_redir;
645 :
646 384 : if ( expand ) {
647 : char *exp_res;
648 0 : exp_res = Expand(res);
649 0 : FREE(res);
650 0 : res = exp_res;
651 : }
652 :
653 384 : return(res);
654 : }
655 :
656 :
657 : static char *
658 0 : _exec_andor( args, doand )
659 : char *args;
660 : int doand;
661 : {
662 : char *next;
663 : char *p;
664 0 : char *white = " \t\n";
665 0 : int res=doand;
666 :
667 0 : args = DmStrSpn(args,white);
668 : do {
669 0 : p=ScanToken(args, &next, TRUE);
670 :
671 0 : if (doand ? !*p : *p) {
672 0 : res = !doand;
673 0 : FREE(p);
674 0 : break;
675 : }
676 :
677 0 : FREE(p);
678 : }
679 0 : while (*(args=DmStrSpn(next,white)));
680 :
681 0 : return(res ? DmStrDup("t") : DmStrDup(""));
682 : }
683 :
684 :
685 : static char *
686 0 : _exec_not( args )
687 : char *args;
688 : {
689 0 : char *white = " \t\n";
690 0 : char *p=Expand(args);
691 0 : int res = (*DmStrSpn(p,white) == '\0');
692 :
693 0 : FREE(p);
694 0 : return(res ? DmStrDup("t") : DmStrDup(""));
695 : }
696 :
697 :
698 : char *
699 0 : exec_normpath( args )/*
700 : =======================
701 : Normalize token-wise. The normalised filenames are returned in a new
702 : string, the original string is not freed. Quoted tokens remain quoted
703 : after the normalizaton. */
704 : char *args;
705 : {
706 : TKSTR str;
707 : char *s, *res;
708 :
709 : /* This honors .WINPATH . */
710 0 : SET_TOKEN( &str, args );
711 0 : res = NIL(char);
712 0 : while( *(s = Get_token( &str, "", FALSE )) != '\0' ) {
713 0 : if(str.tk_quote == 0) {
714 : /* Add leading quote. */
715 0 : res = DmStrApp(res, "\"");
716 0 : res = DmStrJoin(res, DO_WINPATH(normalize_path(s)), -1, TRUE);
717 : /* Append the trailing quote. */
718 0 : res = DmStrJoin(res, "\"", 1, TRUE);
719 : } else {
720 0 : res = DmStrApp(res, DO_WINPATH(normalize_path(s)));
721 : }
722 : }
723 0 : return res;
724 : }
|