2 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
3 * See the copyright notice in the ACK home directory, in the file "Copyright".
14 static char rcs_id[] = "$Id: trans.c,v 2.10 1994/06/24 10:13:15 ceriel Exp $" ;
15 static char rcs_trans[] = RCS_TRANS ;
18 /****************************************************************************/
19 /* Routines for transforming from one file type to another */
20 /****************************************************************************/
22 static growstring head ;
23 static int touch_head= NO ;
24 static growstring tail ;
25 static int touch_tail= NO ;
27 char *headvar(),*tailvar() ;
29 int transform(phase) register trf *phase ; {
32 if ( !setfiles(phase) ) {
38 if ( !ok ) rmfile(&out) ;
39 /* Free the space occupied by the arguments,
40 except for the linker, since we are bound to exit soon
41 and do not foresee further need of memory space */
42 if ( !phase->t_linker ) discardargs(phase) ;
47 getmapflags(phase) register trf *phase ; {
49 register list_elem *elem ;
53 scanlist(l_first(flags),elem) {
54 scanned= *(l_content(*elem))&NO_SCAN ;
55 *(l_content(*elem)) &= ~NO_SCAN ;
56 if ( mapflag(&(phase->t_mapf),l_content(*elem)) ) {
60 vprint("phase %s, added mapflag for %s\n",
66 *(l_content(*elem)) |= scanned ;
68 if ( phase->t_linker ) {
69 scanlist(l_first(phase->t_inputs),elem) {
70 l_in = p_cont(*elem) ;
71 if ( mapflag(&(phase->t_mapf),l_in->p_path) ) {
72 ptr= keeps(getvar(LIBVAR)) ;
76 vprint("phase %s, library %s(%s)\n",
77 phase->t_name,l_in->p_path,ptr) ;
80 if ( l_in->p_keeps) throws(l_in->p_path) ;
85 scanlist(l_first(flags),elem) {
86 /* Get the flags remaining for the loader,
87 That is: all the flags neither eaten by ack nor
88 one of the subprograms called so-far.
89 The last fact is indicated by the NO_SCAN bit
90 in the first character of the flag.
92 if ( !( *(l_content(*elem))&NO_SCAN ) ) {
93 l_add(&(phase->t_flags),l_content(*elem)) ;
96 vprint("phase %s, added flag %s\n",
107 do_Rflag(argp) char *argp ; {
108 l_add(&R_list,argp) ;
112 if ( !touch_head) return "" ;
113 return gr_start(head) ;
116 add_head(str) char *str; {
125 if ( !touch_tail ) return "" ;
126 return gr_start(tail) ;
129 add_tail(str) char *str ; {
139 register list_elem *elem ;
140 register trf *phase ;
142 scanlist(l_first(tr_list), elem) {
143 phase = t_cont(*elem) ;
144 if ( !phase->t_linker ) getmapflags(phase);
146 scanlist(l_first(R_list), elem) {
147 set_Rflag(l_content(*elem)) ;
150 setpvar(keeps(HEAD),headvar) ;
151 setpvar(keeps(TAIL),tailvar) ;
154 set_Rflag(argp) register char *argp ; {
156 register list_elem *prog ;
157 register int length ;
160 eos= strindex(&argp[2],'-');
161 eq= strindex(&argp[2],EQUAL) ;
162 colon= strindex(&argp[2],':');
166 if ( eq && eq<eos ) eos= eq ;
168 if ( colon && ( !eos || eos>colon ) ) eos= colon ;
170 if ( !(argp[0]&NO_SCAN) ) werror("Incorrect use of -R flag") ;
173 length= eos - &argp[2] ;
174 scanlist(l_first(tr_list), prog) {
175 if ( strncmp(t_cont(*prog)->t_name, &argp[2], length )==0 &&
176 t_cont(*prog)->t_name[length]==0 /* Same name length */) {
178 if ( !(argp[0]&NO_SCAN) ) {
179 /* If not already taken by a mapflag */
180 l_add(&(t_cont(*prog)->t_flags),eos) ;
184 t_cont(*prog)->t_prog= eos+1 ;
186 t_cont(*prog)->t_priority= atoi(eos+1) ;
192 if ( !(argp[0]&NO_SCAN) ) werror("Cannot find program for %s",argp) ;
196 /**************************************************************************/
198 /* The creation of arguments for exec for a transformation */
200 /**************************************************************************/
202 growstring scanb(line) char *line ; {
203 /* Scan a line for backslashes, setting the NO_SCAN bit in characters
204 preceded by a backslash.
206 register char *in_c ;
209 enum { TEXT, ESCAPED } state = TEXT ;
212 for ( in_c= line ; *in_c ; in_c++ ) {
216 if ( token==BSLASH ) {
219 gr_add(&result,token) ;
223 gr_add(&result,token|NO_SCAN) ;
229 if ( state!=TEXT ) werror("flag line ends with %c",BSLASH) ;
233 growstring scanvars(line) char *line ; {
234 /* Scan a line variable replacements started by S_VAR.
235 Two sequences exist: S_VAR name E_VAR, S_VAR name A_VAR text E_VAR.
236 neither name nor text may contain further replacements.
237 In the first form an error message is issued if the name is not
238 present in the variables, the second form produces text
240 The sequence S_VAR S_VAR is transformed into S_VAR.
241 This to allow later recognition in mapflags, where B_SLASH
242 would be preventing any recognition.
244 register char *in_c ;
249 enum { TEXT, FIRST, NAME, SKIP, COPY } state = TEXT ;
251 gr_init(&result) ; gr_init(&name) ;
252 for ( in_c= line ; *in_c ; in_c++ ) {
256 if ( token==S_VAR ) {
259 gr_add(&result,token) ;
266 gr_add(&result,token) ;
270 fatal("empty string variable name") ;
273 gr_add(&name,token) ;
281 if ( tr=getvar(gr_start(name)) ) {
283 gr_add(&result,*tr++) ;
293 if ( tr=getvar(gr_start(name)) ) {
295 gr_add(&result,*tr++);
298 werror("No definition for %s",
305 gr_add(&name,token) ;
310 if ( token==C_VAR ) state= TEXT ;
313 if ( token==C_VAR ) state= TEXT ; else {
314 gr_add(&result,token) ;
321 werror("flag line misses %c",C_VAR) ;
327 growstring scanexpr(line) char *line ; {
328 /* Scan a line for conditional or flag expressions,
329 dependent on the type. The format is
330 S_EXPR suflist M_EXPR suflist T_EXPR tail C_EXPR
331 the head and tail are passed to treat, together with the
332 growstring for futher treatment.
333 Nesting is not allowed.
335 register char *in_c ;
338 growstring sufs, tailval ;
340 static list_head fsuff, lsuff ;
341 enum { TEXT, FDOT, FSUF, LDOT, LSUF, FTAIL } state = TEXT ;
343 gr_init(&result) ; gr_init(&sufs) ; gr_init(&tailval) ;
344 for ( in_c= line ; *in_c ; in_c++ ) {
348 if ( token==S_EXPR ) {
351 } else gr_add(&result,token) ;
354 if ( token==M_EXPR ) {
359 if ( token!=SUFCHAR ) {
360 error("Missing %c in expression",SUFCHAR) ;
362 gr_add(&sufs,token) ; state=FSUF ;
365 if ( token==M_EXPR || (token&~NO_SCAN)==SUFCHAR) {
367 l_add(&fsuff,gr_final(&sufs)) ;
369 if ( token==M_EXPR ) {
371 } else gr_add(&sufs,token&~NO_SCAN) ;
374 if ( token==T_EXPR ) {
379 if ( token!=SUFCHAR ) {
380 error("Missing %c in expression",SUFCHAR) ;
382 gr_add(&sufs,token) ; state=LSUF ;
385 if ( token==T_EXPR || (token&~NO_SCAN)==SUFCHAR) {
387 l_add(&lsuff,gr_final(&sufs)) ;
389 if ( token==T_EXPR ) {
391 } else gr_add(&sufs,token&~NO_SCAN) ;
394 if ( token==C_EXPR ) {
397 condit(&result,&fsuff,&lsuff,gr_start(tailval)) ;
398 l_throw(&fsuff) ; l_throw(&lsuff) ;
401 } else gr_add(&tailval,token) ;
407 l_throw(&fsuff) ; l_throw(&lsuff) ; gr_throw(&tailval) ;
408 werror("flag line has unclosed expression starting with %6s",
414 condit(line,fsuff,lsuff,tailval) growstring *line ;
415 list_head *fsuff, *lsuff;
418 register list_elem *first ;
419 register list_elem *last ;
422 if ( debug>=4 ) vprint("Conditional for %s, ",tailval) ;
424 scanlist( l_first(*fsuff), first ) {
425 scanlist( l_first(*lsuff), last ) {
426 if ( strcmp(l_content(*first),l_content(*last))==0 ) {
429 if ( debug>=4 ) vprint(" matched\n") ;
431 while ( *tailval) gr_add(line,*tailval++ ) ;
437 if ( debug>=4) vprint(" non-matched\n") ;
441 int mapflag(maplist,cflag) list_head *maplist ; char *cflag ; {
442 /* Expand a flag expression */
443 /* The flag "cflag" is checked for each of the mapflags.
444 A mapflag entry has the form
445 -text NAME=replacement or -text*text NAME=replacement
446 The star matches anything as in the shell.
447 If the entry matches the assignment will take place
448 This replacement is subjected to argument matching only.
449 When a match took place the replacement is returned
451 The replacement sits in stable storage.
453 register list_elem *elem ;
455 scanlist(l_first(*maplist),elem) {
456 if ( mapexpand(l_content(*elem),cflag) ) {
463 int mapexpand(mapentry,cflag)
464 char *mapentry, *cflag ;
466 register char *star ;
468 register char *space ;
471 star=strindex(mapentry,STAR) ;
472 space=firstblank(mapentry) ;
473 if ( star >space ) star= (char *)0 ;
475 length= space-star-1 ;
476 if ( strncmp(mapentry,cflag,star-mapentry) ||
477 strncmp(star+1,cflag+strlen(cflag)-length,length) ) {
481 /* Now set star to the first char of the star
482 replacement and length to its length
484 length=strlen(cflag)-(star-mapentry)-length ;
485 if ( length<0 ) return 0 ;
486 star=cflag+(star-mapentry) ;
489 vprint("Starmatch (%s,%s) %.*s\n",
490 mapentry,cflag,length,star) ;
494 if ( strncmp(mapentry,cflag,space-mapentry)!=0 ||
495 cflag[space-mapentry] ) {
499 ptr= skipblank(space) ;
500 if ( *ptr==0 ) return 1 ;
501 doassign(ptr,star,length) ;
505 doassign(line,star,length) char *line, *star ; {
506 growstring varval, name, temp ;
512 for ( ; *ptr && *ptr!=SPACE && *ptr!=TAB && *ptr!=EQUAL ; ptr++ ) {
515 ptr= strindex(ptr,EQUAL) ;
517 error("Missing %c in assignment %s",EQUAL,line);
520 temp= scanvars(ptr+1) ;
521 for ( ptr=gr_start(temp); *ptr; ptr++ ) switch ( *ptr ) {
524 while ( length-- ) gr_add(&varval,*star++|NO_SCAN) ;
528 gr_add(&varval,*ptr) ;
532 gr_add(&name,0) ; gr_add(&varval,0) ;
533 setsvar(gr_final(&name),gr_final(&varval)) ;
536 #define ISBLANK(c) ( (c)==SPACE || (c)==TAB )
538 unravel(line,action) char *line ; int (*action)() ; {
539 /* Unravel the line, get arguments a la shell */
540 /* each argument is handled to action */
541 /* The input string is left intact */
542 register char *in_c ;
544 enum { BLANK, ARG } state = BLANK ;
552 if ( token==0 ) break ;
553 if ( !ISBLANK(token) ) {
556 gr_add(&argum,token&~NO_SCAN) ;
560 if ( ISBLANK(token) || token==0 ) {
562 (*action)(gr_start(argum)) ;
566 gr_add(&argum,token&~NO_SCAN) ;
570 if ( token == 0 ) break ;
575 char *c_rep(string,place,rep) char *string, *place, *rep ; {
576 /* Produce a string in stable storage produced from 'string'
577 with the character at place replaced by rep
584 for ( nc=string ; *nc && nc<place ; nc++ ) {
588 if ( *nc==0 ) fatal("Place is not in string") ;
590 for ( xc=rep ; *xc ; xc++ ) gr_add(&name,*xc|NO_SCAN) ;
593 return gr_final(&name) ;
596 static list_head *curargs ;
597 static list_head *comb_args ;
599 addargs(string) char *string ; {
600 register char *temp, *repc ;
601 register list_elem *elem ;
603 repc=strindex(string,C_IN) ;
605 /* INPUT FILE TOKEN seen, replace it and scan further */
606 if ( repc==string && string[1]==0 ) {
607 if ( in.p_path ) { /* All but combiner */
608 l_add(curargs,keeps(in.p_path)) ;
610 scanlist( l_first(*comb_args), elem ) {
612 keeps(p_cont(*elem)->p_path)) ;
617 if ( in.p_path ) { /* Not for the combiners */
618 temp=c_rep(string,repc,in.p_path) ;
621 } else { /* For the combiners */
622 scanlist( l_first(*comb_args), elem ) {
623 temp=c_rep(string,repc,p_cont(*elem)->p_path);
630 repc=strindex(string,C_OUT) ;
632 /* replace the outfile token as with the infile token */
634 if ( !out.p_path ) fatal("missing output filename") ;
636 temp=c_rep(string,repc,out.p_path) ;
641 temp= keeps(string) ;
643 l_add(curargs,temp) ;
646 getcallargs(phase) register trf *phase ; {
647 growstring arg1, arg2 ;
649 arg1= scanvars(phase->t_argd) ;
651 if ( debug>=3 ) { vprint("\tvars: ") ; prns(gr_start(arg1)) ; }
653 arg2= scanexpr(gr_start(arg1)) ;
655 if ( debug>=3 ) { vprint("\texpr: ") ; prns(gr_start(arg2)) ; }
658 curargs= &phase->t_args ;
659 if (phase->t_combine) comb_args = &phase->t_inputs ;
660 unravel( gr_start(arg2), addargs ) ;
664 discardargs(phase) register trf *phase ; {
665 l_throw(&phase->t_args) ;