trans.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. /*
  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".
  4. *
  5. */
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include "ack.h"
  9. #include "list.h"
  10. #include "trans.h"
  11. #include "grows.h"
  12. #include "data.h"
  13. #ifndef NORCSID
  14. static char rcs_id[] = "$Id$" ;
  15. static char rcs_trans[] = RCS_TRANS ;
  16. #endif
  17. /****************************************************************************/
  18. /* Routines for transforming from one file type to another */
  19. /****************************************************************************/
  20. static growstring head ;
  21. static int touch_head= NO ;
  22. static growstring tail ;
  23. static int touch_tail= NO ;
  24. void set_Rflag(char *argp);
  25. void condit(growstring *line, list_head *fsuff, list_head *lsuff, char *tailval);
  26. void doassign(char *line, char *star, int length);
  27. void getcallargs(trf *phase);
  28. void discardargs(trf *phase);
  29. int transform(trf *phase)
  30. {
  31. int ok ;
  32. if ( !setfiles(phase) ) {
  33. disc_files(phase) ;
  34. return 0 ;
  35. }
  36. getcallargs(phase) ;
  37. ok= runphase(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) ;
  43. disc_files(phase) ;
  44. return ok ;
  45. }
  46. void getmapflags(trf *phase)
  47. {
  48. register path *l_in ;
  49. register list_elem *elem ;
  50. int scanned ;
  51. register char *ptr ;
  52. scanlist(l_first(flags),elem) {
  53. scanned= *(l_content(*elem))&NO_SCAN ;
  54. *(l_content(*elem)) &= ~NO_SCAN ;
  55. if ( mapflag(&(phase->t_mapf),l_content(*elem)) ) {
  56. scanned=NO_SCAN ;
  57. #ifdef DEBUG
  58. if ( debug >=4 ) {
  59. vprint("phase %s, added mapflag for %s\n",
  60. phase->t_name,
  61. l_content(*elem) ) ;
  62. }
  63. #endif
  64. }
  65. *(l_content(*elem)) |= scanned ;
  66. }
  67. if ( phase->t_linker ) {
  68. scanlist(l_first(phase->t_inputs),elem) {
  69. l_in = p_cont(*elem) ;
  70. if ( mapflag(&(phase->t_mapf),l_in->p_path) ) {
  71. ptr= keeps(getvar(LIBVAR)) ;
  72. clr_noscan(ptr) ;
  73. #ifdef DEBUG
  74. if ( debug >=4 ) {
  75. vprint("phase %s, library %s(%s)\n",
  76. phase->t_name,l_in->p_path,ptr) ;
  77. }
  78. #endif
  79. if ( l_in->p_keeps) throws(l_in->p_path) ;
  80. l_in->p_path= ptr ;
  81. l_in->p_keeps=YES ;
  82. }
  83. }
  84. scanlist(l_first(flags),elem) {
  85. /* Get the flags remaining for the loader,
  86. That is: all the flags neither eaten by ack nor
  87. one of the subprograms called so-far.
  88. The last fact is indicated by the NO_SCAN bit
  89. in the first character of the flag.
  90. */
  91. if ( !( *(l_content(*elem))&NO_SCAN ) ) {
  92. l_add(&(phase->t_flags),l_content(*elem)) ;
  93. #ifdef DEBUG
  94. if ( debug >=4 ) {
  95. vprint("phase %s, added flag %s\n",
  96. phase->t_name,
  97. l_content(*elem) ) ;
  98. }
  99. #endif
  100. }
  101. }
  102. }
  103. }
  104. void do_Rflag(char *argp)
  105. {
  106. l_add(&R_list,argp) ;
  107. }
  108. char *headvar()
  109. {
  110. if ( !touch_head) return "" ;
  111. return gr_start(head) ;
  112. }
  113. void add_head(char *str)
  114. {
  115. if ( !touch_head) {
  116. gr_init(&head) ;
  117. touch_head=YES ;
  118. }
  119. gr_cat(&head,str) ;
  120. }
  121. char *tailvar()
  122. {
  123. if ( !touch_tail ) return "" ;
  124. return gr_start(tail) ;
  125. }
  126. void add_tail(char *str)
  127. {
  128. if ( !touch_tail ) {
  129. gr_init(&tail) ;
  130. touch_tail=YES ;
  131. }
  132. gr_cat(&tail,str) ;
  133. }
  134. void transini()
  135. {
  136. register list_elem *elem ;
  137. register trf *phase ;
  138. scanlist(l_first(tr_list), elem) {
  139. phase = t_cont(*elem) ;
  140. if ( !phase->t_linker ) getmapflags(phase);
  141. }
  142. scanlist(l_first(R_list), elem) {
  143. set_Rflag(l_content(*elem)) ;
  144. }
  145. l_clear(&R_list) ;
  146. setpvar(keeps(HEAD),headvar) ;
  147. setpvar(keeps(TAIL),tailvar) ;
  148. }
  149. void set_Rflag(char *argp)
  150. {
  151. register char *eos ;
  152. register list_elem *prog ;
  153. register int length ;
  154. char *eq, *colon ;
  155. eos= strchr(&argp[2],'-');
  156. eq= strchr(&argp[2],EQUAL) ;
  157. colon= strchr(&argp[2],':');
  158. if ( !eos ) {
  159. eos= eq ;
  160. } else {
  161. if ( eq && eq<eos ) eos= eq ;
  162. }
  163. if ( colon && ( !eos || eos>colon ) ) eos= colon ;
  164. if ( !eos ) {
  165. if ( !(argp[0]&NO_SCAN) ) werror("Incorrect use of -R flag") ;
  166. return ;
  167. }
  168. length= eos - &argp[2] ;
  169. scanlist(l_first(tr_list), prog) {
  170. if ( strncmp(t_cont(*prog)->t_name, &argp[2], length )==0 &&
  171. t_cont(*prog)->t_name[length]==0 /* Same name length */) {
  172. if ( *eos=='-' ) {
  173. if ( !(argp[0]&NO_SCAN) ) {
  174. /* If not already taken by a mapflag */
  175. l_add(&(t_cont(*prog)->t_flags),eos) ;
  176. }
  177. } else
  178. if ( *eos=='=' ) {
  179. t_cont(*prog)->t_prog= eos+1 ;
  180. } else {
  181. t_cont(*prog)->t_priority= atoi(eos+1) ;
  182. }
  183. argp[0] |= NO_SCAN ;
  184. return ;
  185. }
  186. }
  187. if ( !(argp[0]&NO_SCAN) ) werror("Cannot find program for %s",argp) ;
  188. return ;
  189. }
  190. /**************************************************************************/
  191. /* */
  192. /* The creation of arguments for exec for a transformation */
  193. /* */
  194. /**************************************************************************/
  195. growstring scanb(char *line)
  196. {
  197. /* Scan a line for backslashes, setting the NO_SCAN bit in characters
  198. preceded by a backslash.
  199. */
  200. register char *in_c ;
  201. register int token ;
  202. growstring result ;
  203. enum { TEXT, ESCAPED } state = TEXT ;
  204. gr_init(&result) ;
  205. for ( in_c= line ; *in_c ; in_c++ ) {
  206. token= *in_c&0377 ;
  207. switch( state ) {
  208. case TEXT :
  209. if ( token==BSLASH ) {
  210. state= ESCAPED ;
  211. } else {
  212. gr_add(&result,token) ;
  213. }
  214. break ;
  215. case ESCAPED :
  216. gr_add(&result,token|NO_SCAN) ;
  217. state=TEXT ;
  218. break ;
  219. }
  220. }
  221. gr_add(&result,0) ;
  222. if ( state!=TEXT ) werror("flag line ends with %c",BSLASH) ;
  223. return result ;
  224. }
  225. growstring scanvars(char *line)
  226. {
  227. /* Scan a line variable replacements started by S_VAR.
  228. Two sequences exist: S_VAR name E_VAR, S_VAR name A_VAR text E_VAR.
  229. neither name nor text may contain further replacements.
  230. In the first form an error message is issued if the name is not
  231. present in the variables, the second form produces text
  232. in that case.
  233. The sequence S_VAR S_VAR is transformed into S_VAR.
  234. This to allow later recognition in mapflags, where B_SLASH
  235. would be preventing any recognition.
  236. */
  237. register char *in_c ;
  238. register int token ;
  239. growstring result ;
  240. growstring name ;
  241. register char *tr ;
  242. enum { TEXT, FIRST, NAME, SKIP, COPY } state = TEXT ;
  243. gr_init(&result) ; gr_init(&name) ;
  244. for ( in_c= line ; *in_c ; in_c++ ) {
  245. token= *in_c&0377 ;
  246. switch( state ) {
  247. case TEXT :
  248. if ( token==S_VAR ) {
  249. state= FIRST ;
  250. } else {
  251. gr_add(&result,token) ;
  252. }
  253. break ;
  254. case FIRST :
  255. switch ( token ) {
  256. case S_VAR :
  257. state= TEXT ;
  258. gr_add(&result,token) ;
  259. break ;
  260. case A_VAR :
  261. case C_VAR :
  262. fatal("empty string variable name") ;
  263. default :
  264. state=NAME ;
  265. gr_add(&name,token) ;
  266. break ;
  267. }
  268. break ;
  269. case NAME:
  270. switch ( token ) {
  271. case A_VAR :
  272. gr_add(&name,0) ;
  273. if ( (tr=getvar(gr_start(name))) ) {
  274. while ( *tr ) {
  275. gr_add(&result,*tr++) ;
  276. }
  277. state=SKIP ;
  278. } else {
  279. state=COPY ;
  280. }
  281. gr_throw(&name) ;
  282. break ;
  283. case C_VAR :
  284. gr_add(&name,0) ;
  285. if ( (tr=getvar(gr_start(name))) ) {
  286. while ( *tr ) {
  287. gr_add(&result,*tr++);
  288. }
  289. } else {
  290. werror("No definition for %s",
  291. gr_start(name)) ;
  292. }
  293. state=TEXT ;
  294. gr_throw(&name) ;
  295. break ;
  296. default:
  297. gr_add(&name,token) ;
  298. break ;
  299. }
  300. break ;
  301. case SKIP :
  302. if ( token==C_VAR ) state= TEXT ;
  303. break ;
  304. case COPY :
  305. if ( token==C_VAR ) state= TEXT ; else {
  306. gr_add(&result,token) ;
  307. }
  308. break ;
  309. }
  310. }
  311. gr_add(&result,0) ;
  312. if ( state!=TEXT ) {
  313. werror("flag line misses %c",C_VAR) ;
  314. gr_throw(&name) ;
  315. }
  316. return result ;
  317. }
  318. growstring scanexpr(char *line)
  319. {
  320. /* Scan a line for conditional or flag expressions,
  321. dependent on the type. The format is
  322. S_EXPR suflist M_EXPR suflist T_EXPR tail C_EXPR
  323. the head and tail are passed to treat, together with the
  324. growstring for futher treatment.
  325. Nesting is not allowed.
  326. */
  327. register char *in_c ;
  328. char *heads ;
  329. register int token ;
  330. growstring sufs, tailval ;
  331. growstring result ;
  332. static list_head fsuff, lsuff ;
  333. enum { TEXT, FDOT, FSUF, LDOT, LSUF, FTAIL } state = TEXT ;
  334. gr_init(&result) ; gr_init(&sufs) ; gr_init(&tailval) ;
  335. for ( in_c= line ; *in_c ; in_c++ ) {
  336. token= *in_c&0377 ;
  337. switch( state ) {
  338. case TEXT :
  339. if ( token==S_EXPR ) {
  340. state= FDOT ;
  341. heads=in_c ;
  342. } else gr_add(&result,token) ;
  343. break ;
  344. case FDOT :
  345. if ( token==M_EXPR ) {
  346. state=LDOT ;
  347. break ;
  348. }
  349. token &= ~NO_SCAN ;
  350. if ( token!=SUFCHAR ) {
  351. error("Missing %c in expression",SUFCHAR) ;
  352. }
  353. gr_add(&sufs,token) ; state=FSUF ;
  354. break ;
  355. case FSUF :
  356. if ( token==M_EXPR || (token&~NO_SCAN)==SUFCHAR) {
  357. gr_add(&sufs,0) ;
  358. l_add(&fsuff,gr_final(&sufs)) ;
  359. }
  360. if ( token==M_EXPR ) {
  361. state=LDOT ;
  362. } else gr_add(&sufs,token&~NO_SCAN) ;
  363. break ;
  364. case LDOT :
  365. if ( token==T_EXPR ) {
  366. state=FTAIL ;
  367. break ;
  368. }
  369. token &= ~NO_SCAN ;
  370. if ( token!=SUFCHAR ) {
  371. error("Missing %c in expression",SUFCHAR) ;
  372. }
  373. gr_add(&sufs,token) ; state=LSUF ;
  374. break ;
  375. case LSUF :
  376. if ( token==T_EXPR || (token&~NO_SCAN)==SUFCHAR) {
  377. gr_add(&sufs,0) ;
  378. l_add(&lsuff,gr_final(&sufs)) ;
  379. }
  380. if ( token==T_EXPR ) {
  381. state=FTAIL ;
  382. } else gr_add(&sufs,token&~NO_SCAN) ;
  383. break ;
  384. case FTAIL :
  385. if ( token==C_EXPR ) {
  386. /* Found one !! */
  387. gr_add(&tailval,0) ;
  388. condit(&result,&fsuff,&lsuff,gr_start(tailval)) ;
  389. l_throw(&fsuff) ; l_throw(&lsuff) ;
  390. gr_throw(&tailval) ;
  391. state=TEXT ;
  392. } else gr_add(&tailval,token) ;
  393. break ;
  394. }
  395. }
  396. gr_add(&result,0) ;
  397. if ( state!=TEXT ) {
  398. l_throw(&fsuff) ; l_throw(&lsuff) ; gr_throw(&tailval) ;
  399. werror("flag line has unclosed expression starting with %6s",
  400. heads) ;
  401. }
  402. return result ;
  403. }
  404. void condit(growstring *line, list_head *fsuff, list_head *lsuff, char *tailval)
  405. {
  406. register list_elem *first ;
  407. register list_elem *last ;
  408. #ifdef DEBUG
  409. if ( debug>=4 ) vprint("Conditional for %s, ",tailval) ;
  410. #endif
  411. scanlist( l_first(*fsuff), first ) {
  412. scanlist( l_first(*lsuff), last ) {
  413. if ( strcmp(l_content(*first),l_content(*last))==0 ) {
  414. /* Found */
  415. #ifdef DEBUG
  416. if ( debug>=4 ) vprint(" matched\n") ;
  417. #endif
  418. while ( *tailval) gr_add(line,*tailval++ ) ;
  419. return ;
  420. }
  421. }
  422. }
  423. #ifdef DEBUG
  424. if ( debug>=4) vprint(" non-matched\n") ;
  425. #endif
  426. }
  427. int mapflag(list_head *maplist, char *cflag)
  428. {
  429. /* Expand a flag expression */
  430. /* The flag "cflag" is checked for each of the mapflags.
  431. A mapflag entry has the form
  432. -text NAME=replacement or -text*text NAME=replacement
  433. The star matches anything as in the shell.
  434. If the entry matches the assignment will take place
  435. This replacement is subjected to argument matching only.
  436. When a match took place the replacement is returned
  437. when not, (char *)0.
  438. The replacement sits in stable storage.
  439. */
  440. register list_elem *elem ;
  441. scanlist(l_first(*maplist),elem) {
  442. if ( mapexpand(l_content(*elem),cflag) ) {
  443. return 1 ;
  444. }
  445. }
  446. return 0 ;
  447. }
  448. int mapexpand(char *mapentry, char *cflag)
  449. {
  450. register char *star ;
  451. register char *ptr ;
  452. register char *space ;
  453. int length ;
  454. star=strchr(mapentry,STAR) ;
  455. space=firstblank(mapentry) ;
  456. if ( star >space ) star= (char *)0 ;
  457. if ( star ) {
  458. length= space-star-1 ;
  459. if ( strncmp(mapentry,cflag,star-mapentry) ||
  460. strncmp(star+1,cflag+strlen(cflag)-length,length) ) {
  461. return 0 ;
  462. }
  463. /* Match */
  464. /* Now set star to the first char of the star
  465. replacement and length to its length
  466. */
  467. length=strlen(cflag)-(star-mapentry)-length ;
  468. if ( length<0 ) return 0 ;
  469. star=cflag+(star-mapentry) ;
  470. #ifdef DEBUG
  471. if ( debug>=6 ) {
  472. vprint("Starmatch (%s,%s) %.*s\n",
  473. mapentry,cflag,length,star) ;
  474. }
  475. #endif
  476. } else {
  477. if ( strncmp(mapentry,cflag,space-mapentry)!=0 ||
  478. cflag[space-mapentry] ) {
  479. return 0 ;
  480. }
  481. }
  482. ptr= skipblank(space) ;
  483. if ( *ptr==0 ) return 1 ;
  484. doassign(ptr,star,length) ;
  485. return 1 ;
  486. }
  487. void doassign(char *line, char *star, int length)
  488. {
  489. growstring varval, name, temp ;
  490. register char *ptr ;
  491. gr_init(&varval) ;
  492. gr_init(&name) ;
  493. ptr= line ;
  494. for ( ; *ptr && *ptr!=SPACE && *ptr!=TAB && *ptr!=EQUAL ; ptr++ ) {
  495. gr_add(&name,*ptr) ;
  496. }
  497. ptr= strchr(ptr,EQUAL) ;
  498. if ( !ptr ) {
  499. error("Missing %c in assignment %s",EQUAL,line);
  500. return ;
  501. }
  502. temp= scanvars(ptr+1) ;
  503. for ( ptr=gr_start(temp); *ptr; ptr++ ) switch ( *ptr ) {
  504. case STAR :
  505. if ( star ) {
  506. while ( length-- ) gr_add(&varval,*star++|NO_SCAN) ;
  507. break ;
  508. }
  509. default :
  510. gr_add(&varval,*ptr) ;
  511. break ;
  512. }
  513. gr_throw(&temp) ;
  514. gr_add(&name,0) ; gr_add(&varval,0) ;
  515. setsvar(gr_final(&name),gr_final(&varval)) ;
  516. }
  517. #define ISBLANK(c) ( (c)==SPACE || (c)==TAB )
  518. void unravel(char *line, void (*action)(char *))
  519. {
  520. /* Unravel the line, get arguments a la shell */
  521. /* each argument is handled to action */
  522. /* The input string is left intact */
  523. register char *in_c ;
  524. register int token ;
  525. enum { BLANK, ARG } state = BLANK ;
  526. growstring argum ;
  527. in_c=line ;
  528. for (;;) {
  529. token= *in_c&0377 ;
  530. switch ( state ) {
  531. case BLANK :
  532. if ( token==0 ) break ;
  533. if ( !ISBLANK(token) ) {
  534. state= ARG ;
  535. gr_init(&argum) ;
  536. gr_add(&argum,token&~NO_SCAN) ;
  537. }
  538. break ;
  539. case ARG :
  540. if ( ISBLANK(token) || token==0 ) {
  541. gr_add(&argum,0) ;
  542. (*action)(gr_start(argum)) ;
  543. gr_throw(&argum) ;
  544. state=BLANK ;
  545. } else {
  546. gr_add(&argum,token&~NO_SCAN) ;
  547. }
  548. break ;
  549. }
  550. if ( token == 0 ) break ;
  551. in_c++ ;
  552. }
  553. }
  554. char *c_rep(char *string, char *place, char *rep)
  555. {
  556. /* Produce a string in stable storage produced from 'string'
  557. with the character at place replaced by rep
  558. */
  559. growstring name ;
  560. register char *nc ;
  561. register char *xc ;
  562. gr_init(&name) ;
  563. for ( nc=string ; *nc && nc<place ; nc++ ) {
  564. gr_add(&name,*nc) ;
  565. }
  566. #ifdef DEBUG
  567. if ( *nc==0 ) fatal("Place is not in string") ;
  568. #endif
  569. for ( xc=rep ; *xc ; xc++ ) gr_add(&name,*xc|NO_SCAN) ;
  570. gr_add(&name,0) ;
  571. gr_cat(&name,nc+1) ;
  572. return gr_final(&name) ;
  573. }
  574. static list_head *curargs ;
  575. static list_head *comb_args ;
  576. void addargs(char *string)
  577. {
  578. register char *temp, *repc ;
  579. register list_elem *elem ;
  580. repc=strchr(string,C_IN) ;
  581. if ( repc ) {
  582. /* INPUT FILE TOKEN seen, replace it and scan further */
  583. if ( repc==string && string[1]==0 ) {
  584. if ( in.p_path ) { /* All but combiner */
  585. l_add(curargs,keeps(in.p_path)) ;
  586. } else {
  587. scanlist( l_first(*comb_args), elem ) {
  588. l_add(curargs,
  589. keeps(p_cont(*elem)->p_path)) ;
  590. }
  591. }
  592. return ;
  593. }
  594. if ( in.p_path ) { /* Not for the combiners */
  595. temp=c_rep(string,repc,in.p_path) ;
  596. addargs(temp) ;
  597. throws(temp) ;
  598. } else { /* For the combiners */
  599. scanlist( l_first(*comb_args), elem ) {
  600. temp=c_rep(string,repc,p_cont(*elem)->p_path);
  601. addargs(temp) ;
  602. throws(temp) ;
  603. }
  604. }
  605. return ;
  606. }
  607. repc=strchr(string,C_OUT) ;
  608. if ( repc ) {
  609. /* replace the outfile token as with the infile token */
  610. #ifdef DEBUG
  611. if ( !out.p_path ) fatal("missing output filename") ;
  612. #endif
  613. temp=c_rep(string,repc,out.p_path) ;
  614. addargs(temp) ;
  615. throws(temp) ;
  616. return ;
  617. }
  618. temp= keeps(string) ;
  619. clr_noscan(temp) ;
  620. l_add(curargs,temp) ;
  621. }
  622. void getcallargs(trf *phase)
  623. {
  624. growstring arg1, arg2 ;
  625. arg1= scanvars(phase->t_argd) ;
  626. #ifdef DEBUG
  627. if ( debug>=3 ) { vprint("\tvars: ") ; prns(gr_start(arg1)) ; }
  628. #endif
  629. arg2= scanexpr(gr_start(arg1)) ;
  630. #ifdef DEBUG
  631. if ( debug>=3 ) { vprint("\texpr: ") ; prns(gr_start(arg2)) ; }
  632. #endif
  633. gr_throw(&arg1) ;
  634. curargs= &phase->t_args ;
  635. if (phase->t_combine) comb_args = &phase->t_inputs ;
  636. unravel( gr_start(arg2), addargs ) ;
  637. gr_throw(&arg2) ;
  638. }
  639. void discardargs(trf *phase)
  640. {
  641. l_throw(&phase->t_args) ;
  642. }