home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume13 / perl / part02 < prev    next >
Encoding:
Internet Message Format  |  1988-01-30  |  57.6 KB

  1. Subject:  v13i002:  Perl, a "replacement" for awk and sed, Part02/10
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Larry Wall <lwall@jpl-devvax.jpl.nasa.gov>
  7. Posting-number: Volume 13, Issue 2
  8. Archive-name: perl/part02
  9.  
  10.  
  11. #! /bin/sh
  12.  
  13. # Make a new directory for the perl sources, cd to it, and run kits 1
  14. # thru 10 through sh.  When all 10 kits have been run, read README.
  15.  
  16. echo "This is perl 1.0 kit 2 (of 10).  If kit 2 is complete, the line"
  17. echo '"'"End of kit 2 (of 10)"'" will echo at the end.'
  18. echo ""
  19. export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
  20. echo Extracting perly.c
  21. sed >perly.c <<'!STUFFY!FUNK!' -e 's/X//'
  22. Xchar rcsid[] = "$Header: perly.c,v 1.0 87/12/18 15:53:31 root Exp $";
  23. X/*
  24. X * $Log:    perly.c,v $
  25. X * Revision 1.0  87/12/18  15:53:31  root
  26. X * Initial revision
  27. X * 
  28. X */
  29. X
  30. Xbool preprocess = FALSE;
  31. Xbool assume_n = FALSE;
  32. Xbool assume_p = FALSE;
  33. Xbool doswitches = FALSE;
  34. Xchar *filename;
  35. Xchar *e_tmpname = "/tmp/perl-eXXXXXX";
  36. XFILE *e_fp = Nullfp;
  37. XARG *l();
  38. X
  39. Xmain(argc,argv,env)
  40. Xregister int argc;
  41. Xregister char **argv;
  42. Xregister char **env;
  43. X{
  44. X    register STR *str;
  45. X    register char *s;
  46. X    char *index();
  47. X
  48. X    linestr = str_new(80);
  49. X    str = str_make("-I/usr/lib/perl ");    /* first used for -I flags */
  50. X    for (argc--,argv++; argc; argc--,argv++) {
  51. X    if (argv[0][0] != '-' || !argv[0][1])
  52. X        break;
  53. X      reswitch:
  54. X    switch (argv[0][1]) {
  55. X#ifdef DEBUGGING
  56. X    case 'D':
  57. X        debug = atoi(argv[0]+2);
  58. X#ifdef YYDEBUG
  59. X        yydebug = (debug & 1);
  60. X#endif
  61. X        break;
  62. X#endif
  63. X    case 'e':
  64. X        if (!e_fp) {
  65. X        mktemp(e_tmpname);
  66. X        e_fp = fopen(e_tmpname,"w");
  67. X        }
  68. X        if (argv[1])
  69. X        fputs(argv[1],e_fp);
  70. X        putc('\n', e_fp);
  71. X        argc--,argv++;
  72. X        break;
  73. X    case 'i':
  74. X        inplace = savestr(argv[0]+2);
  75. X        argvoutstab = stabent("ARGVOUT",TRUE);
  76. X        break;
  77. X    case 'I':
  78. X        str_cat(str,argv[0]);
  79. X        str_cat(str," ");
  80. X        if (!argv[0][2]) {
  81. X        str_cat(str,argv[1]);
  82. X        argc--,argv++;
  83. X        str_cat(str," ");
  84. X        }
  85. X        break;
  86. X    case 'n':
  87. X        assume_n = TRUE;
  88. X        strcpy(argv[0], argv[0]+1);
  89. X        goto reswitch;
  90. X    case 'p':
  91. X        assume_p = TRUE;
  92. X        strcpy(argv[0], argv[0]+1);
  93. X        goto reswitch;
  94. X    case 'P':
  95. X        preprocess = TRUE;
  96. X        strcpy(argv[0], argv[0]+1);
  97. X        goto reswitch;
  98. X    case 's':
  99. X        doswitches = TRUE;
  100. X        strcpy(argv[0], argv[0]+1);
  101. X        goto reswitch;
  102. X    case 'v':
  103. X        version();
  104. X        exit(0);
  105. X    case '-':
  106. X        argc--,argv++;
  107. X        goto switch_end;
  108. X    case 0:
  109. X        break;
  110. X    default:
  111. X        fatal("Unrecognized switch: %s\n",argv[0]);
  112. X    }
  113. X    }
  114. X  switch_end:
  115. X    if (e_fp) {
  116. X    fclose(e_fp);
  117. X    argc++,argv--;
  118. X    argv[0] = e_tmpname;
  119. X    }
  120. X
  121. X    str_set(&str_no,No);
  122. X    str_set(&str_yes,Yes);
  123. X    init_eval();
  124. X
  125. X    /* open script */
  126. X
  127. X    if (argv[0] == Nullch)
  128. X    argv[0] = "-";
  129. X    filename = savestr(argv[0]);
  130. X    if (strEQ(filename,"-"))
  131. X    argv[0] = "";
  132. X    if (preprocess) {
  133. X    sprintf(buf, "\
  134. X/bin/sed -e '/^[^#]/b' \
  135. X -e '/^#[     ]*include[     ]/b' \
  136. X -e '/^#[     ]*define[     ]/b' \
  137. X -e '/^#[     ]*if[     ]/b' \
  138. X -e '/^#[     ]*ifdef[     ]/b' \
  139. X -e '/^#[     ]*else/b' \
  140. X -e '/^#[     ]*endif/b' \
  141. X -e 's/^#.*//' \
  142. X %s | /lib/cpp -C %s-",
  143. X      argv[0], str_get(str));
  144. X    rsfp = popen(buf,"r");
  145. X    }
  146. X    else if (!*argv[0])
  147. X    rsfp = stdin;
  148. X    else
  149. X    rsfp = fopen(argv[0],"r");
  150. X    if (rsfp == Nullfp)
  151. X    fatal("Perl script \"%s\" doesn't seem to exist.\n",filename);
  152. X    str_free(str);        /* free -I directories */
  153. X
  154. X    defstab = stabent("_",TRUE);
  155. X
  156. X    /* init tokener */
  157. X
  158. X    bufptr = str_get(linestr);
  159. X
  160. X    /* now parse the report spec */
  161. X
  162. X    if (yyparse())
  163. X    fatal("Execution aborted due to compilation errors.\n");
  164. X
  165. X    if (e_fp) {
  166. X    e_fp = Nullfp;
  167. X    UNLINK(e_tmpname);
  168. X    }
  169. X    argc--,argv++;    /* skip name of script */
  170. X    if (doswitches) {
  171. X    for (; argc > 0 && **argv == '-'; argc--,argv++) {
  172. X        if (argv[0][1] == '-') {
  173. X        argc--,argv++;
  174. X        break;
  175. X        }
  176. X        str_numset(stabent(argv[0]+1,TRUE)->stab_val,(double)1.0);
  177. X    }
  178. X    }
  179. X    if (argvstab = stabent("ARGV",FALSE)) {
  180. X    for (; argc > 0; argc--,argv++) {
  181. X        apush(argvstab->stab_array,str_make(argv[0]));
  182. X    }
  183. X    }
  184. X    if (envstab = stabent("ENV",FALSE)) {
  185. X    for (; *env; env++) {
  186. X        if (!(s = index(*env,'=')))
  187. X        continue;
  188. X        *s++ = '\0';
  189. X        str = str_make(s);
  190. X        str->str_link.str_magic = envstab;
  191. X        hstore(envstab->stab_hash,*env,str);
  192. X        *--s = '=';
  193. X    }
  194. X    }
  195. X    sigstab = stabent("SIG",FALSE);
  196. X
  197. X    magicalize("!#?^~=-%0123456789.+&*(),\\/[|");
  198. X
  199. X    (tmpstab = stabent("0",FALSE)) && str_set(STAB_STR(tmpstab),filename);
  200. X    (tmpstab = stabent("$",FALSE)) &&
  201. X    str_numset(STAB_STR(tmpstab),(double)getpid());
  202. X
  203. X    tmpstab = stabent("stdin",TRUE);
  204. X    tmpstab->stab_io = stio_new();
  205. X    tmpstab->stab_io->fp = stdin;
  206. X
  207. X    tmpstab = stabent("stdout",TRUE);
  208. X    tmpstab->stab_io = stio_new();
  209. X    tmpstab->stab_io->fp = stdout;
  210. X    defoutstab = tmpstab;
  211. X    curoutstab = tmpstab;
  212. X
  213. X    tmpstab = stabent("stderr",TRUE);
  214. X    tmpstab->stab_io = stio_new();
  215. X    tmpstab->stab_io->fp = stderr;
  216. X
  217. X    setjmp(top_env);    /* sets goto_targ on longjump */
  218. X
  219. X#ifdef DEBUGGING
  220. X    if (debug & 1024)
  221. X    dump_cmd(main_root,Nullcmd);
  222. X    if (debug)
  223. X    fprintf(stderr,"\nEXECUTING...\n\n");
  224. X#endif
  225. X
  226. X    /* do it */
  227. X
  228. X    (void) cmd_exec(main_root);
  229. X
  230. X    if (goto_targ)
  231. X    fatal("Can't find label \"%s\"--aborting.\n",goto_targ);
  232. X    exit(0);
  233. X}
  234. X
  235. Xmagicalize(list)
  236. Xregister char *list;
  237. X{
  238. X    register STAB *stab;
  239. X    char sym[2];
  240. X
  241. X    sym[1] = '\0';
  242. X    while (*sym = *list++) {
  243. X    if (stab = stabent(sym,FALSE)) {
  244. X        stab->stab_flags = SF_VMAGIC;
  245. X        stab->stab_val->str_link.str_magic = stab;
  246. X    }
  247. X    }
  248. X}
  249. X
  250. X#define RETURN(retval) return (bufptr = s,retval)
  251. X#define OPERATOR(retval) return (expectterm = TRUE,bufptr = s,retval)
  252. X#define TERM(retval) return (expectterm = FALSE,bufptr = s,retval)
  253. X#define LOOPX(f) return (yylval.ival = f,expectterm = FALSE,bufptr = s,LOOPEX)
  254. X#define UNI(f) return (yylval.ival = f,expectterm = TRUE,bufptr = s,UNIOP)
  255. X#define FUN0(f) return (yylval.ival = f,expectterm = FALSE,bufptr = s,FUNC0)
  256. X#define FUN1(f) return (yylval.ival = f,expectterm = FALSE,bufptr = s,FUNC1)
  257. X#define FUN2(f) return (yylval.ival = f,expectterm = FALSE,bufptr = s,FUNC2)
  258. X#define FUN3(f) return (yylval.ival = f,expectterm = FALSE,bufptr = s,FUNC3)
  259. X#define SFUN(f) return (yylval.ival = f,expectterm = FALSE,bufptr = s,STABFUN)
  260. X
  261. Xyylex()
  262. X{
  263. X    register char *s = bufptr;
  264. X    register char *d;
  265. X    register int tmp;
  266. X    static bool in_format = FALSE;
  267. X    static bool firstline = TRUE;
  268. X
  269. X  retry:
  270. X#ifdef YYDEBUG
  271. X    if (yydebug)
  272. X    if (index(s,'\n'))
  273. X        fprintf(stderr,"Tokener at %s",s);
  274. X    else
  275. X        fprintf(stderr,"Tokener at %s\n",s);
  276. X#endif
  277. X    switch (*s) {
  278. X    default:
  279. X    fprintf(stderr,
  280. X        "Unrecognized character %c in file %s line %d--ignoring.\n",
  281. X         *s++,filename,line);
  282. X    goto retry;
  283. X    case 0:
  284. X    s = str_get(linestr);
  285. X    *s = '\0';
  286. X    if (firstline && (assume_n || assume_p)) {
  287. X        firstline = FALSE;
  288. X        str_set(linestr,"while (<>) {");
  289. X        s = str_get(linestr);
  290. X        goto retry;
  291. X    }
  292. X    if (!rsfp)
  293. X        RETURN(0);
  294. X    if (in_format) {
  295. X        yylval.formval = load_format();    /* leaves . in buffer */
  296. X        in_format = FALSE;
  297. X        s = str_get(linestr);
  298. X        TERM(FORMLIST);
  299. X    }
  300. X    line++;
  301. X    if ((s = str_gets(linestr, rsfp)) == Nullch) {
  302. X        if (preprocess)
  303. X        pclose(rsfp);
  304. X        else if (rsfp != stdin)
  305. X        fclose(rsfp);
  306. X        rsfp = Nullfp;
  307. X        if (assume_n || assume_p) {
  308. X        str_set(linestr,assume_p ? "}continue{print;" : "");
  309. X        str_cat(linestr,"}");
  310. X        s = str_get(linestr);
  311. X        goto retry;
  312. X        }
  313. X        s = str_get(linestr);
  314. X        RETURN(0);
  315. X    }
  316. X#ifdef DEBUG
  317. X    else if (firstline) {
  318. X        char *showinput();
  319. X        s = showinput();
  320. X    }
  321. X#endif
  322. X    firstline = FALSE;
  323. X    goto retry;
  324. X    case ' ': case '\t':
  325. X    s++;
  326. X    goto retry;
  327. X    case '\n':
  328. X    case '#':
  329. X    if (preprocess && s == str_get(linestr) &&
  330. X           s[1] == ' ' && isdigit(s[2])) {
  331. X        line = atoi(s+2)-1;
  332. X        for (s += 2; isdigit(*s); s++) ;
  333. X        while (*s && isspace(*s)) s++;
  334. X        if (filename)
  335. X        safefree(filename);
  336. X        s[strlen(s)-1] = '\0';    /* wipe out newline */
  337. X        filename = savestr(s);
  338. X        s = str_get(linestr);
  339. X    }
  340. X    *s = '\0';
  341. X    if (lex_newlines)
  342. X        RETURN('\n');
  343. X    goto retry;
  344. X    case '+':
  345. X    case '-':
  346. X    if (s[1] == *s) {
  347. X        s++;
  348. X        if (*s++ == '+')
  349. X        RETURN(INC);
  350. X        else
  351. X        RETURN(DEC);
  352. X    }
  353. X    /* FALL THROUGH */
  354. X    case '*':
  355. X    case '%':
  356. X    case '^':
  357. X    case '~':
  358. X    case '(':
  359. X    case ',':
  360. X    case ':':
  361. X    case ';':
  362. X    case '{':
  363. X    case '[':
  364. X    tmp = *s++;
  365. X    OPERATOR(tmp);
  366. X    case ')':
  367. X    case ']':
  368. X    case '}':
  369. X    tmp = *s++;
  370. X    TERM(tmp);
  371. X    case '&':
  372. X    s++;
  373. X    tmp = *s++;
  374. X    if (tmp == '&')
  375. X        OPERATOR(ANDAND);
  376. X    s--;
  377. X    OPERATOR('&');
  378. X    case '|':
  379. X    s++;
  380. X    tmp = *s++;
  381. X    if (tmp == '|')
  382. X        OPERATOR(OROR);
  383. X    s--;
  384. X    OPERATOR('|');
  385. X    case '=':
  386. X    s++;
  387. X    tmp = *s++;
  388. X    if (tmp == '=')
  389. X        OPERATOR(EQ);
  390. X    if (tmp == '~')
  391. X        OPERATOR(MATCH);
  392. X    s--;
  393. X    OPERATOR('=');
  394. X    case '!':
  395. X    s++;
  396. X    tmp = *s++;
  397. X    if (tmp == '=')
  398. X        OPERATOR(NE);
  399. X    if (tmp == '~')
  400. X        OPERATOR(NMATCH);
  401. X    s--;
  402. X    OPERATOR('!');
  403. X    case '<':
  404. X    if (expectterm) {
  405. X        s = scanstr(s);
  406. X        TERM(RSTRING);
  407. X    }
  408. X    s++;
  409. X    tmp = *s++;
  410. X    if (tmp == '<')
  411. X        OPERATOR(LS);
  412. X    if (tmp == '=')
  413. X        OPERATOR(LE);
  414. X    s--;
  415. X    OPERATOR('<');
  416. X    case '>':
  417. X    s++;
  418. X    tmp = *s++;
  419. X    if (tmp == '>')
  420. X        OPERATOR(RS);
  421. X    if (tmp == '=')
  422. X        OPERATOR(GE);
  423. X    s--;
  424. X    OPERATOR('>');
  425. X
  426. X#define SNARFWORD \
  427. X    d = tokenbuf; \
  428. X    while (isalpha(*s) || isdigit(*s) || *s == '_') \
  429. X        *d++ = *s++; \
  430. X    *d = '\0'; \
  431. X    d = tokenbuf;
  432. X
  433. X    case '$':
  434. X    if (s[1] == '#' && (isalpha(s[2]) || s[2] == '_')) {
  435. X        s++;
  436. X        s = scanreg(s,tokenbuf);
  437. X        yylval.stabval = aadd(stabent(tokenbuf,TRUE));
  438. X        TERM(ARYLEN);
  439. X    }
  440. X    s = scanreg(s,tokenbuf);
  441. X    yylval.stabval = stabent(tokenbuf,TRUE);
  442. X    TERM(REG);
  443. X
  444. X    case '@':
  445. X    s = scanreg(s,tokenbuf);
  446. X    yylval.stabval = aadd(stabent(tokenbuf,TRUE));
  447. X    TERM(ARY);
  448. X
  449. X    case '/':            /* may either be division or pattern */
  450. X    case '?':            /* may either be conditional or pattern */
  451. X    if (expectterm) {
  452. X        s = scanpat(s);
  453. X        TERM(PATTERN);
  454. X    }
  455. X    tmp = *s++;
  456. X    OPERATOR(tmp);
  457. X
  458. X    case '.':
  459. X    if (!expectterm || !isdigit(s[1])) {
  460. X        s++;
  461. X        tmp = *s++;
  462. X        if (tmp == '.')
  463. X        OPERATOR(DOTDOT);
  464. X        s--;
  465. X        OPERATOR('.');
  466. X    }
  467. X    /* FALL THROUGH */
  468. X    case '0': case '1': case '2': case '3': case '4':
  469. X    case '5': case '6': case '7': case '8': case '9':
  470. X    case '\'': case '"': case '`':
  471. X    s = scanstr(s);
  472. X    TERM(RSTRING);
  473. X
  474. X    case '_':
  475. X    SNARFWORD;
  476. X    yylval.cval = savestr(d);
  477. X    OPERATOR(WORD);
  478. X    case 'a': case 'A':
  479. X    SNARFWORD;
  480. X    yylval.cval = savestr(d);
  481. X    OPERATOR(WORD);
  482. X    case 'b': case 'B':
  483. X    SNARFWORD;
  484. X    yylval.cval = savestr(d);
  485. X    OPERATOR(WORD);
  486. X    case 'c': case 'C':
  487. X    SNARFWORD;
  488. X    if (strEQ(d,"continue"))
  489. X        OPERATOR(CONTINUE);
  490. X    if (strEQ(d,"chdir"))
  491. X        UNI(O_CHDIR);
  492. X    if (strEQ(d,"close"))
  493. X        OPERATOR(CLOSE);
  494. X    if (strEQ(d,"crypt"))
  495. X        FUN2(O_CRYPT);
  496. X    if (strEQ(d,"chop"))
  497. X        OPERATOR(CHOP);
  498. X    if (strEQ(d,"chmod")) {
  499. X        yylval.ival = O_CHMOD;
  500. X        OPERATOR(PRINT);
  501. X    }
  502. X    if (strEQ(d,"chown")) {
  503. X        yylval.ival = O_CHOWN;
  504. X        OPERATOR(PRINT);
  505. X    }
  506. X    yylval.cval = savestr(d);
  507. X    OPERATOR(WORD);
  508. X    case 'd': case 'D':
  509. X    SNARFWORD;
  510. X    if (strEQ(d,"do"))
  511. X        OPERATOR(DO);
  512. X    if (strEQ(d,"die"))
  513. X        UNI(O_DIE);
  514. X    yylval.cval = savestr(d);
  515. X    OPERATOR(WORD);
  516. X    case 'e': case 'E':
  517. X    SNARFWORD;
  518. X    if (strEQ(d,"else"))
  519. X        OPERATOR(ELSE);
  520. X    if (strEQ(d,"elsif"))
  521. X        OPERATOR(ELSIF);
  522. X    if (strEQ(d,"eq") || strEQ(d,"EQ"))
  523. X        OPERATOR(SEQ);
  524. X    if (strEQ(d,"exit"))
  525. X        UNI(O_EXIT);
  526. X    if (strEQ(d,"eof"))
  527. X        TERM(FEOF);
  528. X    if (strEQ(d,"exp"))
  529. X        FUN1(O_EXP);
  530. X    if (strEQ(d,"each"))
  531. X        SFUN(O_EACH);
  532. X    if (strEQ(d,"exec")) {
  533. X        yylval.ival = O_EXEC;
  534. X        OPERATOR(PRINT);
  535. X    }
  536. X    yylval.cval = savestr(d);
  537. X    OPERATOR(WORD);
  538. X    case 'f': case 'F':
  539. X    SNARFWORD;
  540. X    if (strEQ(d,"for"))
  541. X        OPERATOR(FOR);
  542. X    if (strEQ(d,"format")) {
  543. X        in_format = TRUE;
  544. X        OPERATOR(FORMAT);
  545. X    }
  546. X    if (strEQ(d,"fork"))
  547. X        FUN0(O_FORK);
  548. X    yylval.cval = savestr(d);
  549. X    OPERATOR(WORD);
  550. X    case 'g': case 'G':
  551. X    SNARFWORD;
  552. X    if (strEQ(d,"gt") || strEQ(d,"GT"))
  553. X        OPERATOR(SGT);
  554. X    if (strEQ(d,"ge") || strEQ(d,"GE"))
  555. X        OPERATOR(SGE);
  556. X    if (strEQ(d,"goto"))
  557. X        LOOPX(O_GOTO);
  558. X    if (strEQ(d,"gmtime"))
  559. X        FUN1(O_GMTIME);
  560. X    yylval.cval = savestr(d);
  561. X    OPERATOR(WORD);
  562. X    case 'h': case 'H':
  563. X    SNARFWORD;
  564. X    if (strEQ(d,"hex"))
  565. X        FUN1(O_HEX);
  566. X    yylval.cval = savestr(d);
  567. X    OPERATOR(WORD);
  568. X    case 'i': case 'I':
  569. X    SNARFWORD;
  570. X    if (strEQ(d,"if"))
  571. X        OPERATOR(IF);
  572. X    if (strEQ(d,"index"))
  573. X        FUN2(O_INDEX);
  574. X    if (strEQ(d,"int"))
  575. X        FUN1(O_INT);
  576. X    yylval.cval = savestr(d);
  577. X    OPERATOR(WORD);
  578. X    case 'j': case 'J':
  579. X    SNARFWORD;
  580. X    if (strEQ(d,"join"))
  581. X        OPERATOR(JOIN);
  582. X    yylval.cval = savestr(d);
  583. X    OPERATOR(WORD);
  584. X    case 'k': case 'K':
  585. X    SNARFWORD;
  586. X    if (strEQ(d,"keys"))
  587. X        SFUN(O_KEYS);
  588. X    if (strEQ(d,"kill")) {
  589. X        yylval.ival = O_KILL;
  590. X        OPERATOR(PRINT);
  591. X    }
  592. X    yylval.cval = savestr(d);
  593. X    OPERATOR(WORD);
  594. X    case 'l': case 'L':
  595. X    SNARFWORD;
  596. X    if (strEQ(d,"last"))
  597. X        LOOPX(O_LAST);
  598. X    if (strEQ(d,"length"))
  599. X        FUN1(O_LENGTH);
  600. X    if (strEQ(d,"lt") || strEQ(d,"LT"))
  601. X        OPERATOR(SLT);
  602. X    if (strEQ(d,"le") || strEQ(d,"LE"))
  603. X        OPERATOR(SLE);
  604. X    if (strEQ(d,"localtime"))
  605. X        FUN1(O_LOCALTIME);
  606. X    if (strEQ(d,"log"))
  607. X        FUN1(O_LOG);
  608. X    if (strEQ(d,"link"))
  609. X        FUN2(O_LINK);
  610. X    yylval.cval = savestr(d);
  611. X    OPERATOR(WORD);
  612. X    case 'm': case 'M':
  613. X    SNARFWORD;
  614. X    if (strEQ(d,"m")) {
  615. X        s = scanpat(s-1);
  616. X        TERM(PATTERN);
  617. X    }
  618. X    yylval.cval = savestr(d);
  619. X    OPERATOR(WORD);
  620. X    case 'n': case 'N':
  621. X    SNARFWORD;
  622. X    if (strEQ(d,"next"))
  623. X        LOOPX(O_NEXT);
  624. X    if (strEQ(d,"ne") || strEQ(d,"NE"))
  625. X        OPERATOR(SNE);
  626. X    yylval.cval = savestr(d);
  627. X    OPERATOR(WORD);
  628. X    case 'o': case 'O':
  629. X    SNARFWORD;
  630. X    if (strEQ(d,"open"))
  631. X        OPERATOR(OPEN);
  632. X    if (strEQ(d,"ord"))
  633. X        FUN1(O_ORD);
  634. X    if (strEQ(d,"oct"))
  635. X        FUN1(O_OCT);
  636. X    yylval.cval = savestr(d);
  637. X    OPERATOR(WORD);
  638. X    case 'p': case 'P':
  639. X    SNARFWORD;
  640. X    if (strEQ(d,"print")) {
  641. X        yylval.ival = O_PRINT;
  642. X        OPERATOR(PRINT);
  643. X    }
  644. X    if (strEQ(d,"printf")) {
  645. X        yylval.ival = O_PRTF;
  646. X        OPERATOR(PRINT);
  647. X    }
  648. X    if (strEQ(d,"push")) {
  649. X        yylval.ival = O_PUSH;
  650. X        OPERATOR(PUSH);
  651. X    }
  652. X    if (strEQ(d,"pop"))
  653. X        OPERATOR(POP);
  654. X    yylval.cval = savestr(d);
  655. X    OPERATOR(WORD);
  656. X    case 'q': case 'Q':
  657. X    SNARFWORD;
  658. X    yylval.cval = savestr(d);
  659. X    OPERATOR(WORD);
  660. X    case 'r': case 'R':
  661. X    SNARFWORD;
  662. X    if (strEQ(d,"reset"))
  663. X        UNI(O_RESET);
  664. X    if (strEQ(d,"redo"))
  665. X        LOOPX(O_REDO);
  666. X    if (strEQ(d,"rename"))
  667. X        FUN2(O_RENAME);
  668. X    yylval.cval = savestr(d);
  669. X    OPERATOR(WORD);
  670. X    case 's': case 'S':
  671. X    SNARFWORD;
  672. X    if (strEQ(d,"s")) {
  673. X        s = scansubst(s);
  674. X        TERM(SUBST);
  675. X    }
  676. X    if (strEQ(d,"shift"))
  677. X        TERM(SHIFT);
  678. X    if (strEQ(d,"split"))
  679. X        TERM(SPLIT);
  680. X    if (strEQ(d,"substr"))
  681. X        FUN3(O_SUBSTR);
  682. X    if (strEQ(d,"sprintf"))
  683. X        OPERATOR(SPRINTF);
  684. X    if (strEQ(d,"sub"))
  685. X        OPERATOR(SUB);
  686. X    if (strEQ(d,"select"))
  687. X        OPERATOR(SELECT);
  688. X    if (strEQ(d,"seek"))
  689. X        OPERATOR(SEEK);
  690. X    if (strEQ(d,"stat"))
  691. X        OPERATOR(STAT);
  692. X    if (strEQ(d,"sqrt"))
  693. X        FUN1(O_SQRT);
  694. X    if (strEQ(d,"sleep"))
  695. X        UNI(O_SLEEP);
  696. X    if (strEQ(d,"system")) {
  697. X        yylval.ival = O_SYSTEM;
  698. X        OPERATOR(PRINT);
  699. X    }
  700. X    yylval.cval = savestr(d);
  701. X    OPERATOR(WORD);
  702. X    case 't': case 'T':
  703. X    SNARFWORD;
  704. X    if (strEQ(d,"tr")) {
  705. X        s = scantrans(s);
  706. X        TERM(TRANS);
  707. X    }
  708. X    if (strEQ(d,"tell"))
  709. X        TERM(TELL);
  710. X    if (strEQ(d,"time"))
  711. X        FUN0(O_TIME);
  712. X    if (strEQ(d,"times"))
  713. X        FUN0(O_TMS);
  714. X    yylval.cval = savestr(d);
  715. X    OPERATOR(WORD);
  716. X    case 'u': case 'U':
  717. X    SNARFWORD;
  718. X    if (strEQ(d,"using"))
  719. X        OPERATOR(USING);
  720. X    if (strEQ(d,"until"))
  721. X        OPERATOR(UNTIL);
  722. X    if (strEQ(d,"unless"))
  723. X        OPERATOR(UNLESS);
  724. X    if (strEQ(d,"umask"))
  725. X        FUN1(O_UMASK);
  726. X    if (strEQ(d,"unshift")) {
  727. X        yylval.ival = O_UNSHIFT;
  728. X        OPERATOR(PUSH);
  729. X    }
  730. X    if (strEQ(d,"unlink")) {
  731. X        yylval.ival = O_UNLINK;
  732. X        OPERATOR(PRINT);
  733. X    }
  734. X    yylval.cval = savestr(d);
  735. X    OPERATOR(WORD);
  736. X    case 'v': case 'V':
  737. X    SNARFWORD;
  738. X    if (strEQ(d,"values"))
  739. X        SFUN(O_VALUES);
  740. X    yylval.cval = savestr(d);
  741. X    OPERATOR(WORD);
  742. X    case 'w': case 'W':
  743. X    SNARFWORD;
  744. X    if (strEQ(d,"write"))
  745. X        TERM(WRITE);
  746. X    if (strEQ(d,"while"))
  747. X        OPERATOR(WHILE);
  748. X    yylval.cval = savestr(d);
  749. X    OPERATOR(WORD);
  750. X    case 'x': case 'X':
  751. X    SNARFWORD;
  752. X    if (!expectterm && strEQ(d,"x"))
  753. X        OPERATOR('x');
  754. X    yylval.cval = savestr(d);
  755. X    OPERATOR(WORD);
  756. X    case 'y': case 'Y':
  757. X    SNARFWORD;
  758. X    if (strEQ(d,"y")) {
  759. X        s = scantrans(s);
  760. X        TERM(TRANS);
  761. X    }
  762. X    yylval.cval = savestr(d);
  763. X    OPERATOR(WORD);
  764. X    case 'z': case 'Z':
  765. X    SNARFWORD;
  766. X    yylval.cval = savestr(d);
  767. X    OPERATOR(WORD);
  768. X    }
  769. X}
  770. X
  771. XSTAB *
  772. Xstabent(name,add)
  773. Xregister char *name;
  774. Xint add;
  775. X{
  776. X    register STAB *stab;
  777. X
  778. X    for (stab = stab_index[*name]; stab; stab = stab->stab_next) {
  779. X    if (strEQ(name,stab->stab_name))
  780. X        return stab;
  781. X    }
  782. X    
  783. X    /* no entry--should we add one? */
  784. X
  785. X    if (add) {
  786. X    stab = (STAB *) safemalloc(sizeof(STAB));
  787. X    bzero((char*)stab, sizeof(STAB));
  788. X    stab->stab_name = savestr(name);
  789. X    stab->stab_val = str_new(0);
  790. X    stab->stab_next = stab_index[*name];
  791. X    stab_index[*name] = stab;
  792. X    return stab;
  793. X    }
  794. X    return Nullstab;
  795. X}
  796. X
  797. XSTIO *
  798. Xstio_new()
  799. X{
  800. X    STIO *stio = (STIO *) safemalloc(sizeof(STIO));
  801. X
  802. X    bzero((char*)stio, sizeof(STIO));
  803. X    stio->page_len = 60;
  804. X    return stio;
  805. X}
  806. X
  807. Xchar *
  808. Xscanreg(s,dest)
  809. Xregister char *s;
  810. Xchar *dest;
  811. X{
  812. X    register char *d;
  813. X
  814. X    s++;
  815. X    d = dest;
  816. X    while (isalpha(*s) || isdigit(*s) || *s == '_')
  817. X    *d++ = *s++;
  818. X    *d = '\0';
  819. X    d = dest;
  820. X    if (!*d) {
  821. X    *d = *s++;
  822. X    if (*d == '{') {
  823. X        d = dest;
  824. X        while (*s && *s != '}')
  825. X        *d++ = *s++;
  826. X        *d = '\0';
  827. X        d = dest;
  828. X        if (*s)
  829. X        s++;
  830. X    }
  831. X    else
  832. X        d[1] = '\0';
  833. X    }
  834. X    if (*d == '^' && !isspace(*s))
  835. X    *d = *s++ & 31;
  836. X    return s;
  837. X}
  838. X
  839. XSTR *
  840. Xscanconst(string)
  841. Xchar *string;
  842. X{
  843. X    register STR *retstr;
  844. X    register char *t;
  845. X    register char *d;
  846. X
  847. X    if (index(string,'|')) {
  848. X    return Nullstr;
  849. X    }
  850. X    retstr = str_make(string);
  851. X    t = str_get(retstr);
  852. X    for (d=t; *d; ) {
  853. X    switch (*d) {
  854. X    case '.': case '[': case '$': case '(': case ')': case '|':
  855. X        *d = '\0';
  856. X        break;
  857. X    case '\\':
  858. X        if (index("wWbB0123456789",d[1])) {
  859. X        *d = '\0';
  860. X        break;
  861. X        }
  862. X        strcpy(d,d+1);
  863. X        switch(*d) {
  864. X        case 'n':
  865. X        *d = '\n';
  866. X        break;
  867. X        case 't':
  868. X        *d = '\t';
  869. X        break;
  870. X        case 'f':
  871. X        *d = '\f';
  872. X        break;
  873. X        case 'r':
  874. X        *d = '\r';
  875. X        break;
  876. X        }
  877. X        /* FALL THROUGH */
  878. X    default:
  879. X        if (d[1] == '*' || d[1] == '+' || d[1] == '?') {
  880. X        *d = '\0';
  881. X        break;
  882. X        }
  883. X        d++;
  884. X    }
  885. X    }
  886. X    if (!*t) {
  887. X    str_free(retstr);
  888. X    return Nullstr;
  889. X    }
  890. X    retstr->str_cur = strlen(retstr->str_ptr);    /* XXX cheating here */
  891. X    return retstr;
  892. X}
  893. X
  894. Xchar *
  895. Xscanpat(s)
  896. Xregister char *s;
  897. X{
  898. X    register SPAT *spat = (SPAT *) safemalloc(sizeof (SPAT));
  899. X    register char *d;
  900. X
  901. X    bzero((char *)spat, sizeof(SPAT));
  902. X    spat->spat_next = spat_root;    /* link into spat list */
  903. X    spat_root = spat;
  904. X    init_compex(&spat->spat_compex);
  905. X
  906. X    switch (*s++) {
  907. X    case 'm':
  908. X    s++;
  909. X    break;
  910. X    case '/':
  911. X    break;
  912. X    case '?':
  913. X    spat->spat_flags |= SPAT_USE_ONCE;
  914. X    break;
  915. X    default:
  916. X    fatal("Search pattern not found:\n%s",str_get(linestr));
  917. X    }
  918. X    s = cpytill(tokenbuf,s,s[-1]);
  919. X    if (!*s)
  920. X    fatal("Search pattern not terminated:\n%s",str_get(linestr));
  921. X    s++;
  922. X    if (*tokenbuf == '^') {
  923. X    spat->spat_first = scanconst(tokenbuf+1);
  924. X    if (spat->spat_first) {
  925. X        spat->spat_flen = strlen(spat->spat_first->str_ptr);
  926. X        if (spat->spat_flen == strlen(tokenbuf+1))
  927. X        spat->spat_flags |= SPAT_SCANALL;
  928. X    }
  929. X    }
  930. X    else {
  931. X    spat->spat_flags |= SPAT_SCANFIRST;
  932. X    spat->spat_first = scanconst(tokenbuf);
  933. X    if (spat->spat_first) {
  934. X        spat->spat_flen = strlen(spat->spat_first->str_ptr);
  935. X        if (spat->spat_flen == strlen(tokenbuf))
  936. X        spat->spat_flags |= SPAT_SCANALL;
  937. X    }
  938. X    }    
  939. X    if (d = compile(&spat->spat_compex,tokenbuf,TRUE,FALSE))
  940. X    fatal(d);
  941. X    yylval.arg = make_match(O_MATCH,stab_to_arg(A_STAB,defstab),spat);
  942. X    return s;
  943. X}
  944. X
  945. Xchar *
  946. Xscansubst(s)
  947. Xregister char *s;
  948. X{
  949. X    register SPAT *spat = (SPAT *) safemalloc(sizeof (SPAT));
  950. X    register char *d;
  951. X
  952. X    bzero((char *)spat, sizeof(SPAT));
  953. X    spat->spat_next = spat_root;    /* link into spat list */
  954. X    spat_root = spat;
  955. X    init_compex(&spat->spat_compex);
  956. X
  957. X    s = cpytill(tokenbuf,s+1,*s);
  958. X    if (!*s)
  959. X    fatal("Substitution pattern not terminated:\n%s",str_get(linestr));
  960. X    for (d=tokenbuf; *d; d++) {
  961. X    if (*d == '$' && d[1] && d[-1] != '\\' && d[1] != '|') {
  962. X        register ARG *arg;
  963. X
  964. X        spat->spat_runtime = arg = op_new(1);
  965. X        arg->arg_type = O_ITEM;
  966. X        arg[1].arg_type = A_DOUBLE;
  967. X        arg[1].arg_ptr.arg_str = str_make(tokenbuf);
  968. X        goto get_repl;        /* skip compiling for now */
  969. X    }
  970. X    }
  971. X    if (*tokenbuf == '^') {
  972. X    spat->spat_first = scanconst(tokenbuf+1);
  973. X    if (spat->spat_first)
  974. X        spat->spat_flen = strlen(spat->spat_first->str_ptr);
  975. X    }
  976. X    else {
  977. X    spat->spat_flags |= SPAT_SCANFIRST;
  978. X    spat->spat_first = scanconst(tokenbuf);
  979. X    if (spat->spat_first)
  980. X        spat->spat_flen = strlen(spat->spat_first->str_ptr);
  981. X    }    
  982. X    if (d = compile(&spat->spat_compex,tokenbuf,TRUE,FALSE))
  983. X    fatal(d);
  984. Xget_repl:
  985. X    s = scanstr(s);
  986. X    if (!*s)
  987. X    fatal("Substitution replacement not terminated:\n%s",str_get(linestr));
  988. X    spat->spat_repl = yylval.arg;
  989. X    if (*s == 'g') {
  990. X    s++;
  991. X    spat->spat_flags &= ~SPAT_USE_ONCE;
  992. X    }
  993. X    else
  994. X    spat->spat_flags |= SPAT_USE_ONCE;
  995. X    yylval.arg = make_match(O_SUBST,stab_to_arg(A_STAB,defstab),spat);
  996. X    return s;
  997. X}
  998. X
  999. XARG *
  1000. Xmake_split(stab,arg)
  1001. Xregister STAB *stab;
  1002. Xregister ARG *arg;
  1003. X{
  1004. X    if (arg->arg_type != O_MATCH) {
  1005. X    register SPAT *spat = (SPAT *) safemalloc(sizeof (SPAT));
  1006. X    register char *d;
  1007. X
  1008. X    bzero((char *)spat, sizeof(SPAT));
  1009. X    spat->spat_next = spat_root;    /* link into spat list */
  1010. X    spat_root = spat;
  1011. X    init_compex(&spat->spat_compex);
  1012. X
  1013. X    spat->spat_runtime = arg;
  1014. X    arg = make_match(O_MATCH,stab_to_arg(A_STAB,defstab),spat);
  1015. X    }
  1016. X    arg->arg_type = O_SPLIT;
  1017. X    arg[2].arg_ptr.arg_spat->spat_repl = stab_to_arg(A_STAB,aadd(stab));
  1018. X    return arg;
  1019. X}
  1020. X
  1021. Xchar *
  1022. Xexpand_charset(s)
  1023. Xregister char *s;
  1024. X{
  1025. X    char t[512];
  1026. X    register char *d = t;
  1027. X    register int i;
  1028. X
  1029. X    while (*s) {
  1030. X    if (s[1] == '-' && s[2]) {
  1031. X        for (i = s[0]; i <= s[2]; i++)
  1032. X        *d++ = i;
  1033. X        s += 3;
  1034. X    }
  1035. X    else
  1036. X        *d++ = *s++;
  1037. X    }
  1038. X    *d = '\0';
  1039. X    return savestr(t);
  1040. X}
  1041. X
  1042. Xchar *
  1043. Xscantrans(s)
  1044. Xregister char *s;
  1045. X{
  1046. X    ARG *arg =
  1047. X    l(make_op(O_TRANS,2,stab_to_arg(A_STAB,defstab),Nullarg,Nullarg,0));
  1048. X    register char *t;
  1049. X    register char *r;
  1050. X    register char *tbl = safemalloc(256);
  1051. X    register int i;
  1052. X
  1053. X    arg[2].arg_type = A_NULL;
  1054. X    arg[2].arg_ptr.arg_cval = tbl;
  1055. X    for (i=0; i<256; i++)
  1056. X    tbl[i] = 0;
  1057. X    s = scanstr(s);
  1058. X    if (!*s)
  1059. X    fatal("Translation pattern not terminated:\n%s",str_get(linestr));
  1060. X    t = expand_charset(str_get(yylval.arg[1].arg_ptr.arg_str));
  1061. X    free_arg(yylval.arg);
  1062. X    s = scanstr(s-1);
  1063. X    if (!*s)
  1064. X    fatal("Translation replacement not terminated:\n%s",str_get(linestr));
  1065. X    r = expand_charset(str_get(yylval.arg[1].arg_ptr.arg_str));
  1066. X    free_arg(yylval.arg);
  1067. X    yylval.arg = arg;
  1068. X    if (!*r) {
  1069. X    safefree(r);
  1070. X    r = t;
  1071. X    }
  1072. X    for (i = 0; t[i]; i++) {
  1073. X    if (!r[i])
  1074. X        r[i] = r[i-1];
  1075. X    tbl[t[i] & 0377] = r[i];
  1076. X    }
  1077. X    if (r != t)
  1078. X    safefree(r);
  1079. X    safefree(t);
  1080. X    return s;
  1081. X}
  1082. X
  1083. XCMD *
  1084. Xblock_head(tail)
  1085. Xregister CMD *tail;
  1086. X{
  1087. X    if (tail == Nullcmd) {
  1088. X    return tail;
  1089. X    }
  1090. X    return tail->c_head;
  1091. X}
  1092. X
  1093. XCMD *
  1094. Xappend_line(head,tail)
  1095. Xregister CMD *head;
  1096. Xregister CMD *tail;
  1097. X{
  1098. X    if (tail == Nullcmd)
  1099. X    return head;
  1100. X    if (!tail->c_head)            /* make sure tail is well formed */
  1101. X    tail->c_head = tail;
  1102. X    if (head != Nullcmd) {
  1103. X    tail = tail->c_head;        /* get to start of tail list */
  1104. X    if (!head->c_head)
  1105. X        head->c_head = head;    /* start a new head list */
  1106. X    while (head->c_next) {
  1107. X        head->c_next->c_head = head->c_head;
  1108. X        head = head->c_next;    /* get to end of head list */
  1109. X    }
  1110. X    head->c_next = tail;        /* link to end of old list */
  1111. X    tail->c_head = head->c_head;    /* propagate head pointer */
  1112. X    }
  1113. X    while (tail->c_next) {
  1114. X    tail->c_next->c_head = tail->c_head;
  1115. X    tail = tail->c_next;
  1116. X    }
  1117. X    return tail;
  1118. X}
  1119. X
  1120. XCMD *
  1121. Xmake_acmd(type,stab,cond,arg)
  1122. Xint type;
  1123. XSTAB *stab;
  1124. XARG *cond;
  1125. XARG *arg;
  1126. X{
  1127. X    register CMD *cmd = (CMD *) safemalloc(sizeof (CMD));
  1128. X
  1129. X    bzero((char *)cmd, sizeof(CMD));
  1130. X    cmd->c_type = type;
  1131. X    cmd->ucmd.acmd.ac_stab = stab;
  1132. X    cmd->ucmd.acmd.ac_expr = arg;
  1133. X    cmd->c_expr = cond;
  1134. X    if (cond) {
  1135. X    opt_arg(cmd,1);
  1136. X    cmd->c_flags |= CF_COND;
  1137. X    }
  1138. X    return cmd;
  1139. X}
  1140. X
  1141. XCMD *
  1142. Xmake_ccmd(type,arg,cblock)
  1143. Xint type;
  1144. Xregister ARG *arg;
  1145. Xstruct compcmd cblock;
  1146. X{
  1147. X    register CMD *cmd = (CMD *) safemalloc(sizeof (CMD));
  1148. X
  1149. X    bzero((char *)cmd, sizeof(CMD));
  1150. X    cmd->c_type = type;
  1151. X    cmd->c_expr = arg;
  1152. X    cmd->ucmd.ccmd.cc_true = cblock.comp_true;
  1153. X    cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
  1154. X    if (arg) {
  1155. X    opt_arg(cmd,1);
  1156. X    cmd->c_flags |= CF_COND;
  1157. X    }
  1158. X    return cmd;
  1159. X}
  1160. X
  1161. Xvoid
  1162. Xopt_arg(cmd,fliporflop)
  1163. Xregister CMD *cmd;
  1164. Xint fliporflop;
  1165. X{
  1166. X    register ARG *arg;
  1167. X    int opt = CFT_EVAL;
  1168. X    int sure = 0;
  1169. X    ARG *arg2;
  1170. X    char *tmps;    /* for True macro */
  1171. X    int context = 0;    /* 0 = normal, 1 = before &&, 2 = before || */
  1172. X    int flp = fliporflop;
  1173. X
  1174. X    if (!cmd)
  1175. X    return;
  1176. X    arg = cmd->c_expr;
  1177. X
  1178. X    /* Turn "if (!expr)" into "unless (expr)" */
  1179. X
  1180. X    while (arg->arg_type == O_NOT && arg[1].arg_type == A_EXPR) {
  1181. X    cmd->c_flags ^= CF_INVERT;        /* flip sense of cmd */
  1182. X    cmd->c_expr = arg[1].arg_ptr.arg_arg;    /* hoist the rest of expr */
  1183. X    free_arg(arg);
  1184. X    arg = cmd->c_expr;            /* here we go again */
  1185. X    }
  1186. X
  1187. X    if (!arg->arg_len) {        /* sanity check */
  1188. X    cmd->c_flags |= opt;
  1189. X    return;
  1190. X    }
  1191. X
  1192. X    /* for "cond .. cond" we set up for the initial check */
  1193. X
  1194. X    if (arg->arg_type == O_FLIP)
  1195. X    context |= 4;
  1196. X
  1197. X    /* for "cond && expr" and "cond || expr" we can ignore expr, sort of */
  1198. X
  1199. X    if (arg->arg_type == O_AND)
  1200. X    context |= 1;
  1201. X    else if (arg->arg_type == O_OR)
  1202. X    context |= 2;
  1203. X    if (context && arg[flp].arg_type == A_EXPR) {
  1204. X    arg = arg[flp].arg_ptr.arg_arg;
  1205. X    flp = 1;
  1206. X    }
  1207. X
  1208. X    if (arg[flp].arg_flags & (AF_PRE|AF_POST)) {
  1209. X    cmd->c_flags |= opt;
  1210. X    return;                /* side effect, can't optimize */
  1211. X    }
  1212. X
  1213. X    if (arg->arg_type == O_ITEM || arg->arg_type == O_FLIP ||
  1214. X      arg->arg_type == O_AND || arg->arg_type == O_OR) {
  1215. X    if (arg[flp].arg_type == A_SINGLE) {
  1216. X        opt = (str_true(arg[flp].arg_ptr.arg_str) ? CFT_TRUE : CFT_FALSE);
  1217. X        cmd->c_first = arg[flp].arg_ptr.arg_str;
  1218. X        goto literal;
  1219. X    }
  1220. X    else if (arg[flp].arg_type == A_STAB || arg[flp].arg_type == A_LVAL) {
  1221. X        cmd->c_stab  = arg[flp].arg_ptr.arg_stab;
  1222. X        opt = CFT_REG;
  1223. X      literal:
  1224. X        if (!context) {    /* no && or ||? */
  1225. X        free_arg(arg);
  1226. X        cmd->c_expr = Nullarg;
  1227. X        }
  1228. X        if (!(context & 1))
  1229. X        cmd->c_flags |= CF_EQSURE;
  1230. X        if (!(context & 2))
  1231. X        cmd->c_flags |= CF_NESURE;
  1232. X    }
  1233. X    }
  1234. X    else if (arg->arg_type == O_MATCH || arg->arg_type == O_SUBST ||
  1235. X             arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST) {
  1236. X    if ((arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) &&
  1237. X        arg[2].arg_type == A_SPAT &&
  1238. X        arg[2].arg_ptr.arg_spat->spat_first ) {
  1239. X        cmd->c_stab  = arg[1].arg_ptr.arg_stab;
  1240. X        cmd->c_first = arg[2].arg_ptr.arg_spat->spat_first;
  1241. X        cmd->c_flen  = arg[2].arg_ptr.arg_spat->spat_flen;
  1242. X        if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_SCANALL &&
  1243. X        (arg->arg_type == O_MATCH || arg->arg_type == O_NMATCH) )
  1244. X        sure |= CF_EQSURE;        /* (SUBST must be forced even */
  1245. X                        /* if we know it will work.) */
  1246. X        arg[2].arg_ptr.arg_spat->spat_first = Nullstr;
  1247. X        arg[2].arg_ptr.arg_spat->spat_flen = 0; /* only one chk */
  1248. X        sure |= CF_NESURE;        /* normally only sure if it fails */
  1249. X        if (arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST)
  1250. X        cmd->c_flags |= CF_FIRSTNEG;
  1251. X        if (context & 1) {        /* only sure if thing is false */
  1252. X        if (cmd->c_flags & CF_FIRSTNEG)
  1253. X            sure &= ~CF_NESURE;
  1254. X        else
  1255. X            sure &= ~CF_EQSURE;
  1256. X        }
  1257. X        else if (context & 2) {    /* only sure if thing is true */
  1258. X        if (cmd->c_flags & CF_FIRSTNEG)
  1259. X            sure &= ~CF_EQSURE;
  1260. X        else
  1261. X            sure &= ~CF_NESURE;
  1262. X        }
  1263. X        if (sure & (CF_EQSURE|CF_NESURE)) {    /* if we know anything*/
  1264. X        if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_SCANFIRST)
  1265. X            opt = CFT_SCAN;
  1266. X        else
  1267. X            opt = CFT_ANCHOR;
  1268. X        if (sure == (CF_EQSURE|CF_NESURE)    /* really sure? */
  1269. X            && arg->arg_type == O_MATCH
  1270. X            && context & 4
  1271. X            && fliporflop == 1) {
  1272. X            arg[2].arg_type = A_SINGLE;        /* don't do twice */
  1273. X            arg[2].arg_ptr.arg_str = &str_yes;
  1274. X        }
  1275. X        cmd->c_flags |= sure;
  1276. X        }
  1277. X    }
  1278. X    }
  1279. X    else if (arg->arg_type == O_SEQ || arg->arg_type == O_SNE ||
  1280. X         arg->arg_type == O_SLT || arg->arg_type == O_SGT) {
  1281. X    if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) {
  1282. X        if (arg[2].arg_type == A_SINGLE) {
  1283. X        cmd->c_stab  = arg[1].arg_ptr.arg_stab;
  1284. X        cmd->c_first = arg[2].arg_ptr.arg_str;
  1285. X        cmd->c_flen  = 30000;
  1286. X        switch (arg->arg_type) {
  1287. X        case O_SLT: case O_SGT:
  1288. X            sure |= CF_EQSURE;
  1289. X            cmd->c_flags |= CF_FIRSTNEG;
  1290. X            break;
  1291. X        case O_SNE:
  1292. X            cmd->c_flags |= CF_FIRSTNEG;
  1293. X            /* FALL THROUGH */
  1294. X        case O_SEQ:
  1295. X            sure |= CF_NESURE|CF_EQSURE;
  1296. X            break;
  1297. X        }
  1298. X        if (context & 1) {    /* only sure if thing is false */
  1299. X            if (cmd->c_flags & CF_FIRSTNEG)
  1300. X            sure &= ~CF_NESURE;
  1301. X            else
  1302. X            sure &= ~CF_EQSURE;
  1303. X        }
  1304. X        else if (context & 2) { /* only sure if thing is true */
  1305. X            if (cmd->c_flags & CF_FIRSTNEG)
  1306. X            sure &= ~CF_EQSURE;
  1307. X            else
  1308. X            sure &= ~CF_NESURE;
  1309. X        }
  1310. X        if (sure & (CF_EQSURE|CF_NESURE)) {
  1311. X            opt = CFT_STROP;
  1312. X            cmd->c_flags |= sure;
  1313. X        }
  1314. X        }
  1315. X    }
  1316. X    }
  1317. X    else if (arg->arg_type == O_ASSIGN &&
  1318. X         (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) &&
  1319. X         arg[1].arg_ptr.arg_stab == defstab &&
  1320. X         arg[2].arg_type == A_EXPR ) {
  1321. X    arg2 = arg[2].arg_ptr.arg_arg;
  1322. X    if (arg2->arg_type == O_ITEM && arg2[1].arg_type == A_READ) {
  1323. X        opt = CFT_GETS;
  1324. X        cmd->c_stab = arg2[1].arg_ptr.arg_stab;
  1325. X        if (!(arg2[1].arg_ptr.arg_stab->stab_io->flags & IOF_ARGV)) {
  1326. X        free_arg(arg2);
  1327. X        free_arg(arg);
  1328. X        cmd->c_expr = Nullarg;
  1329. X        }
  1330. X    }
  1331. X    }
  1332. X    else if (arg->arg_type == O_CHOP &&
  1333. X         (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) ) {
  1334. X    opt = CFT_CHOP;
  1335. X    cmd->c_stab = arg[1].arg_ptr.arg_stab;
  1336. X    free_arg(arg);
  1337. X    cmd->c_expr = Nullarg;
  1338. X    }
  1339. X    if (context & 4)
  1340. X    opt |= CF_FLIP;
  1341. X    cmd->c_flags |= opt;
  1342. X
  1343. X    if (cmd->c_flags & CF_FLIP) {
  1344. X    if (fliporflop == 1) {
  1345. X        arg = cmd->c_expr;    /* get back to O_FLIP arg */
  1346. X        arg[3].arg_ptr.arg_cmd = (CMD*)safemalloc(sizeof(CMD));
  1347. X        bcopy((char *)cmd, (char *)arg[3].arg_ptr.arg_cmd, sizeof(CMD));
  1348. X        arg[4].arg_ptr.arg_cmd = (CMD*)safemalloc(sizeof(CMD));
  1349. X        bcopy((char *)cmd, (char *)arg[4].arg_ptr.arg_cmd, sizeof(CMD));
  1350. X        opt_arg(arg[4].arg_ptr.arg_cmd,2);
  1351. X        arg->arg_len = 2;        /* this is a lie */
  1352. X    }
  1353. X    else {
  1354. X        if ((opt & CF_OPTIMIZE) == CFT_EVAL)
  1355. X        cmd->c_flags = (cmd->c_flags & ~CF_OPTIMIZE) | CFT_UNFLIP;
  1356. X    }
  1357. X    }
  1358. X}
  1359. X
  1360. XARG *
  1361. Xmod_match(type,left,pat)
  1362. Xregister ARG *left;
  1363. Xregister ARG *pat;
  1364. X{
  1365. X
  1366. X    register SPAT *spat;
  1367. X    register ARG *newarg;
  1368. X
  1369. X    if ((pat->arg_type == O_MATCH ||
  1370. X     pat->arg_type == O_SUBST ||
  1371. X     pat->arg_type == O_TRANS ||
  1372. X     pat->arg_type == O_SPLIT
  1373. X    ) &&
  1374. X    pat[1].arg_ptr.arg_stab == defstab ) {
  1375. X    switch (pat->arg_type) {
  1376. X    case O_MATCH:
  1377. X        newarg = make_op(type == O_MATCH ? O_MATCH : O_NMATCH,
  1378. X        pat->arg_len,
  1379. X        left,Nullarg,Nullarg,0);
  1380. X        break;
  1381. X    case O_SUBST:
  1382. X        newarg = l(make_op(type == O_MATCH ? O_SUBST : O_NSUBST,
  1383. X        pat->arg_len,
  1384. X        left,Nullarg,Nullarg,0));
  1385. X        break;
  1386. X    case O_TRANS:
  1387. X        newarg = l(make_op(type == O_MATCH ? O_TRANS : O_NTRANS,
  1388. X        pat->arg_len,
  1389. X        left,Nullarg,Nullarg,0));
  1390. X        break;
  1391. X    case O_SPLIT:
  1392. X        newarg = make_op(type == O_MATCH ? O_SPLIT : O_SPLIT,
  1393. X        pat->arg_len,
  1394. X        left,Nullarg,Nullarg,0);
  1395. X        break;
  1396. X    }
  1397. X    if (pat->arg_len >= 2) {
  1398. X        newarg[2].arg_type = pat[2].arg_type;
  1399. X        newarg[2].arg_ptr = pat[2].arg_ptr;
  1400. X        newarg[2].arg_flags = pat[2].arg_flags;
  1401. X        if (pat->arg_len >= 3) {
  1402. X        newarg[3].arg_type = pat[3].arg_type;
  1403. X        newarg[3].arg_ptr = pat[3].arg_ptr;
  1404. X        newarg[3].arg_flags = pat[3].arg_flags;
  1405. X        }
  1406. X    }
  1407. X    safefree((char*)pat);
  1408. X    }
  1409. X    else {
  1410. X    spat = (SPAT *) safemalloc(sizeof (SPAT));
  1411. X    bzero((char *)spat, sizeof(SPAT));
  1412. X    spat->spat_next = spat_root;    /* link into spat list */
  1413. X    spat_root = spat;
  1414. X    init_compex(&spat->spat_compex);
  1415. X
  1416. X    spat->spat_runtime = pat;
  1417. X    newarg = make_op(type,2,left,Nullarg,Nullarg,0);
  1418. X    newarg[2].arg_type = A_SPAT;
  1419. X    newarg[2].arg_ptr.arg_spat = spat;
  1420. X    newarg[2].arg_flags = AF_SPECIAL;
  1421. X    }
  1422. X
  1423. X    return newarg;
  1424. X}
  1425. X
  1426. XCMD *
  1427. Xadd_label(lbl,cmd)
  1428. Xchar *lbl;
  1429. Xregister CMD *cmd;
  1430. X{
  1431. X    if (cmd)
  1432. X    cmd->c_label = lbl;
  1433. X    return cmd;
  1434. X}
  1435. X
  1436. XCMD *
  1437. Xaddcond(cmd, arg)
  1438. Xregister CMD *cmd;
  1439. Xregister ARG *arg;
  1440. X{
  1441. X    cmd->c_expr = arg;
  1442. X    opt_arg(cmd,1);
  1443. X    cmd->c_flags |= CF_COND;
  1444. X    return cmd;
  1445. X}
  1446. X
  1447. XCMD *
  1448. Xaddloop(cmd, arg)
  1449. Xregister CMD *cmd;
  1450. Xregister ARG *arg;
  1451. X{
  1452. X    cmd->c_expr = arg;
  1453. X    opt_arg(cmd,1);
  1454. X    cmd->c_flags |= CF_COND|CF_LOOP;
  1455. X    if (cmd->c_type == C_BLOCK)
  1456. X    cmd->c_flags &= ~CF_COND;
  1457. X    else {
  1458. X    arg = cmd->ucmd.acmd.ac_expr;
  1459. X    if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD)
  1460. X        cmd->c_flags &= ~CF_COND;  /* "do {} while" happens at least once */
  1461. X    if (arg && arg->arg_type == O_SUBR)
  1462. X        cmd->c_flags &= ~CF_COND;  /* likewise for "do subr() while" */
  1463. X    }
  1464. X    return cmd;
  1465. X}
  1466. X
  1467. XCMD *
  1468. Xinvert(cmd)
  1469. Xregister CMD *cmd;
  1470. X{
  1471. X    cmd->c_flags ^= CF_INVERT;
  1472. X    return cmd;
  1473. X}
  1474. X
  1475. Xyyerror(s)
  1476. Xchar *s;
  1477. X{
  1478. X    char tmpbuf[128];
  1479. X    char *tname = tmpbuf;
  1480. X
  1481. X    if (yychar > 256) {
  1482. X    tname = tokename[yychar-256];
  1483. X    if (strEQ(tname,"word"))
  1484. X        strcpy(tname,tokenbuf);
  1485. X    else if (strEQ(tname,"register"))
  1486. X        sprintf(tname,"$%s",tokenbuf);
  1487. X    else if (strEQ(tname,"array_length"))
  1488. X        sprintf(tname,"$#%s",tokenbuf);
  1489. X    }
  1490. X    else if (!yychar)
  1491. X    strcpy(tname,"EOF");
  1492. X    else if (yychar < 32)
  1493. X    sprintf(tname,"^%c",yychar+64);
  1494. X    else if (yychar == 127)
  1495. X    strcpy(tname,"^?");
  1496. X    else
  1497. X    sprintf(tname,"%c",yychar);
  1498. X    printf("%s in file %s at line %d, next token \"%s\"\n",
  1499. X      s,filename,line,tname);
  1500. X}
  1501. X
  1502. Xchar *
  1503. Xscanstr(s)
  1504. Xregister char *s;
  1505. X{
  1506. X    register char term;
  1507. X    register char *d;
  1508. X    register ARG *arg;
  1509. X    register bool makesingle = FALSE;
  1510. X    char *leave = "\\$nrtfb0123456789";    /* which backslash sequences to keep */
  1511. X
  1512. X    arg = op_new(1);
  1513. X    yylval.arg = arg;
  1514. X    arg->arg_type = O_ITEM;
  1515. X
  1516. X    switch (*s) {
  1517. X    default:            /* a substitution replacement */
  1518. X    arg[1].arg_type = A_DOUBLE;
  1519. X    makesingle = TRUE;    /* maybe disable runtime scanning */
  1520. X    term = *s;
  1521. X    if (term == '\'')
  1522. X        leave = Nullch;
  1523. X    goto snarf_it;
  1524. X    case '0':
  1525. X    {
  1526. X        long i;
  1527. X        int shift;
  1528. X
  1529. X        arg[1].arg_type = A_SINGLE;
  1530. X        if (s[1] == 'x') {
  1531. X        shift = 4;
  1532. X        s += 2;
  1533. X        }
  1534. X        else if (s[1] == '.')
  1535. X        goto decimal;
  1536. X        else
  1537. X        shift = 3;
  1538. X        i = 0;
  1539. X        for (;;) {
  1540. X        switch (*s) {
  1541. X        default:
  1542. X            goto out;
  1543. X        case '8': case '9':
  1544. X            if (shift != 4)
  1545. X            fatal("Illegal octal digit at line %d",line);
  1546. X            /* FALL THROUGH */
  1547. X        case '0': case '1': case '2': case '3': case '4':
  1548. X        case '5': case '6': case '7':
  1549. X            i <<= shift;
  1550. X            i += *s++ & 15;
  1551. X            break;
  1552. X        case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  1553. X        case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  1554. X            if (shift != 4)
  1555. X            goto out;
  1556. X            i <<= 4;
  1557. X            i += (*s++ & 7) + 9;
  1558. X            break;
  1559. X        }
  1560. X        }
  1561. X      out:
  1562. X        sprintf(tokenbuf,"%d",i);
  1563. X        arg[1].arg_ptr.arg_str = str_make(tokenbuf);
  1564. X    }
  1565. X    break;
  1566. X    case '1': case '2': case '3': case '4': case '5':
  1567. X    case '6': case '7': case '8': case '9': case '.':
  1568. X      decimal:
  1569. X    arg[1].arg_type = A_SINGLE;
  1570. X    d = tokenbuf;
  1571. X    while (isdigit(*s) || *s == '_')
  1572. X        *d++ = *s++;
  1573. X    if (*s == '.' && index("0123456789eE",s[1]))
  1574. X        *d++ = *s++;
  1575. X    while (isdigit(*s) || *s == '_')
  1576. X        *d++ = *s++;
  1577. X    if (index("eE",*s) && index("+-0123456789",s[1]))
  1578. X        *d++ = *s++;
  1579. X    if (*s == '+' || *s == '-')
  1580. X        *d++ = *s++;
  1581. X    while (isdigit(*s))
  1582. X        *d++ = *s++;
  1583. X    *d = '\0';
  1584. X    arg[1].arg_ptr.arg_str = str_make(tokenbuf);
  1585. X    break;
  1586. X    case '\'':
  1587. X    arg[1].arg_type = A_SINGLE;
  1588. X    term = *s;
  1589. X    leave = Nullch;
  1590. X    goto snarf_it;
  1591. X
  1592. X    case '<':
  1593. X    arg[1].arg_type = A_READ;
  1594. X    s = cpytill(tokenbuf,s+1,'>');
  1595. X    if (!*tokenbuf)
  1596. X        strcpy(tokenbuf,"ARGV");
  1597. X    if (*s)
  1598. X        s++;
  1599. X    if (rsfp == stdin && strEQ(tokenbuf,"stdin"))
  1600. X        fatal("Can't get both program and data from <stdin>\n");
  1601. X    arg[1].arg_ptr.arg_stab = stabent(tokenbuf,TRUE);
  1602. X    arg[1].arg_ptr.arg_stab->stab_io = stio_new();
  1603. X    if (strEQ(tokenbuf,"ARGV")) {
  1604. X        aadd(arg[1].arg_ptr.arg_stab);
  1605. X        arg[1].arg_ptr.arg_stab->stab_io->flags |= IOF_ARGV|IOF_START;
  1606. X    }
  1607. X    break;
  1608. X    case '"': 
  1609. X    arg[1].arg_type = A_DOUBLE;
  1610. X    makesingle = TRUE;    /* maybe disable runtime scanning */
  1611. X    term = *s;
  1612. X    goto snarf_it;
  1613. X    case '`':
  1614. X    arg[1].arg_type = A_BACKTICK;
  1615. X    term = *s;
  1616. X      snarf_it:
  1617. X    {
  1618. X        STR *tmpstr;
  1619. X        int sqstart = line;
  1620. X        char *tmps;
  1621. X
  1622. X        tmpstr = str_new(strlen(s));
  1623. X        s = str_append_till(tmpstr,s+1,term,leave);
  1624. X        while (!*s) {    /* multiple line string? */
  1625. X        s = str_gets(linestr, rsfp);
  1626. X        if (!*s)
  1627. X            fatal("EOF in string at line %d\n",sqstart);
  1628. X        line++;
  1629. X        s = str_append_till(tmpstr,s,term,leave);
  1630. X        }
  1631. X        s++;
  1632. X        if (term == '\'') {
  1633. X        arg[1].arg_ptr.arg_str = tmpstr;
  1634. X        break;
  1635. X        }
  1636. X        tmps = s;
  1637. X        s = d = tmpstr->str_ptr;    /* assuming shrinkage only */
  1638. X        while (*s) {
  1639. X        if (*s == '$' && s[1]) {
  1640. X            makesingle = FALSE;    /* force interpretation */
  1641. X            if (!isalpha(s[1])) {    /* an internal register? */
  1642. X            int len;
  1643. X
  1644. X            len = scanreg(s,tokenbuf) - s;
  1645. X            stabent(tokenbuf,TRUE);    /* make sure it's created */
  1646. X            while (len--)
  1647. X                *d++ = *s++;
  1648. X            continue;
  1649. X            }
  1650. X        }
  1651. X        else if (*s == '\\' && s[1]) {
  1652. X            s++;
  1653. X            switch (*s) {
  1654. X            default:
  1655. X              defchar:
  1656. X            if (!leave || index(leave,*s))
  1657. X                *d++ = '\\';
  1658. X            *d++ = *s++;
  1659. X            continue;
  1660. X            case '0': case '1': case '2': case '3':
  1661. X            case '4': case '5': case '6': case '7':
  1662. X            *d = *s++ - '0';
  1663. X            if (index("01234567",*s)) {
  1664. X                *d <<= 3;
  1665. X                *d += *s++ - '0';
  1666. X            }
  1667. X            else if (!index('`"',term)) {    /* oops, a subpattern */
  1668. X                s--;
  1669. X                goto defchar;
  1670. X            }
  1671. X            if (index("01234567",*s)) {
  1672. X                *d <<= 3;
  1673. X                *d += *s++ - '0';
  1674. X            }
  1675. X            d++;
  1676. X            continue;
  1677. X            case 'b':
  1678. X            *d++ = '\b';
  1679. X            break;
  1680. X            case 'n':
  1681. X            *d++ = '\n';
  1682. X            break;
  1683. X            case 'r':
  1684. X            *d++ = '\r';
  1685. X            break;
  1686. X            case 'f':
  1687. X            *d++ = '\f';
  1688. X            break;
  1689. X            case 't':
  1690. X            *d++ = '\t';
  1691. X            break;
  1692. X            }
  1693. X            s++;
  1694. X            continue;
  1695. X        }
  1696. X        *d++ = *s++;
  1697. X        }
  1698. X        *d = '\0';
  1699. X        if (arg[1].arg_type == A_DOUBLE) {
  1700. X        if (makesingle)
  1701. X            arg[1].arg_type = A_SINGLE;    /* now we can optimize on it */
  1702. X        else
  1703. X            leave = "\\";
  1704. X        for (d = s = tmpstr->str_ptr; *s; *d++ = *s++) {
  1705. X            if (*s == '\\' && (!leave || index(leave,s[1])))
  1706. X            s++;
  1707. X        }
  1708. X        *d = '\0';
  1709. X        }
  1710. X        tmpstr->str_cur = d - tmpstr->str_ptr;    /* XXX cheat */
  1711. X        arg[1].arg_ptr.arg_str = tmpstr;
  1712. X        s = tmps;
  1713. X        break;
  1714. X    }
  1715. X    }
  1716. X    return s;
  1717. X}
  1718. X
  1719. XARG *
  1720. Xmake_op(type,newlen,arg1,arg2,arg3,dolist)
  1721. Xint type;
  1722. Xint newlen;
  1723. XARG *arg1;
  1724. XARG *arg2;
  1725. XARG *arg3;
  1726. Xint dolist;
  1727. X{
  1728. X    register ARG *arg;
  1729. X    register ARG *chld;
  1730. X    register int doarg;
  1731. X
  1732. X    arg = op_new(newlen);
  1733. X    arg->arg_type = type;
  1734. X    doarg = opargs[type];
  1735. X    if (chld = arg1) {
  1736. X    if (!(doarg & 1))
  1737. X        arg[1].arg_flags |= AF_SPECIAL;
  1738. X    if (doarg & 16)
  1739. X        arg[1].arg_flags |= AF_NUMERIC;
  1740. X    if (chld->arg_type == O_ITEM &&
  1741. X        (hoistable[chld[1].arg_type] || chld[1].arg_type == A_LVAL) ) {
  1742. X        arg[1].arg_type = chld[1].arg_type;
  1743. X        arg[1].arg_ptr = chld[1].arg_ptr;
  1744. X        arg[1].arg_flags |= chld[1].arg_flags;
  1745. X        free_arg(chld);
  1746. X    }
  1747. X    else {
  1748. X        arg[1].arg_type = A_EXPR;
  1749. X        arg[1].arg_ptr.arg_arg = chld;
  1750. X        if (dolist & 1) {
  1751. X        if (chld->arg_type == O_LIST) {
  1752. X            if (newlen == 1) {    /* we can hoist entire list */
  1753. X            chld->arg_type = type;
  1754. X            free_arg(arg);
  1755. X            arg = chld;
  1756. X            }
  1757. X            else {
  1758. X            arg[1].arg_flags |= AF_SPECIAL;
  1759. X            }
  1760. X        }
  1761. X        else if (chld->arg_type == O_ARRAY && chld->arg_len == 1)
  1762. X            arg[1].arg_flags |= AF_SPECIAL;
  1763. X        }
  1764. X    }
  1765. X    }
  1766. X    if (chld = arg2) {
  1767. X    if (!(doarg & 2))
  1768. X        arg[2].arg_flags |= AF_SPECIAL;
  1769. X    if (doarg & 32)
  1770. X        arg[2].arg_flags |= AF_NUMERIC;
  1771. X    if (chld->arg_type == O_ITEM && 
  1772. X        (hoistable[chld[1].arg_type] || 
  1773. X         (type == O_ASSIGN && 
  1774. X          (chld[1].arg_type == A_READ ||
  1775. X           chld[1].arg_type == A_DOUBLE ||
  1776. X           chld[1].arg_type == A_BACKTICK ) ) ) ) {
  1777. X        arg[2].arg_type = chld[1].arg_type;
  1778. X        arg[2].arg_ptr = chld[1].arg_ptr;
  1779. X        free_arg(chld);
  1780. X    }
  1781. X    else {
  1782. X        arg[2].arg_type = A_EXPR;
  1783. X        arg[2].arg_ptr.arg_arg = chld;
  1784. X        if ((dolist & 2) &&
  1785. X          (chld->arg_type == O_LIST ||
  1786. X           (chld->arg_type == O_ARRAY && chld->arg_len == 1) ))
  1787. X        arg[2].arg_flags |= AF_SPECIAL;
  1788. X    }
  1789. X    }
  1790. X    if (chld = arg3) {
  1791. X    if (!(doarg & 4))
  1792. X        arg[3].arg_flags |= AF_SPECIAL;
  1793. X    if (doarg & 64)
  1794. X        arg[3].arg_flags |= AF_NUMERIC;
  1795. X    if (chld->arg_type == O_ITEM && hoistable[chld[1].arg_type]) {
  1796. X        arg[3].arg_type = chld[1].arg_type;
  1797. X        arg[3].arg_ptr = chld[1].arg_ptr;
  1798. X        free_arg(chld);
  1799. X    }
  1800. X    else {
  1801. X        arg[3].arg_type = A_EXPR;
  1802. X        arg[3].arg_ptr.arg_arg = chld;
  1803. X        if ((dolist & 4) &&
  1804. X          (chld->arg_type == O_LIST ||
  1805. X           (chld->arg_type == O_ARRAY && chld->arg_len == 1) ))
  1806. X        arg[3].arg_flags |= AF_SPECIAL;
  1807. X    }
  1808. X    }
  1809. X#ifdef DEBUGGING
  1810. X    if (debug & 16) {
  1811. X    fprintf(stderr,"%lx <= make_op(%s",arg,opname[arg->arg_type]);
  1812. X    if (arg1)
  1813. X        fprintf(stderr,",%s=%lx",
  1814. X        argname[arg[1].arg_type],arg[1].arg_ptr.arg_arg);
  1815. X    if (arg2)
  1816. X        fprintf(stderr,",%s=%lx",
  1817. X        argname[arg[2].arg_type],arg[2].arg_ptr.arg_arg);
  1818. X    if (arg3)
  1819. X        fprintf(stderr,",%s=%lx",
  1820. X        argname[arg[3].arg_type],arg[3].arg_ptr.arg_arg);
  1821. X    fprintf(stderr,")\n");
  1822. X    }
  1823. X#endif
  1824. X    evalstatic(arg);        /* see if we can consolidate anything */
  1825. X    return arg;
  1826. X}
  1827. X
  1828. X/* turn 123 into 123 == $. */
  1829. X
  1830. XARG *
  1831. Xflipflip(arg)
  1832. Xregister ARG *arg;
  1833. X{
  1834. X    if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_SINGLE) {
  1835. X    arg = (ARG*)saferealloc((char*)arg,3*sizeof(ARG));
  1836. X    arg->arg_type = O_EQ;
  1837. X    arg->arg_len = 2;
  1838. X    arg[2].arg_type = A_STAB;
  1839. X    arg[2].arg_flags = 0;
  1840. X    arg[2].arg_ptr.arg_stab = stabent(".",TRUE);
  1841. X    }
  1842. X    return arg;
  1843. X}
  1844. X
  1845. Xvoid
  1846. Xevalstatic(arg)
  1847. Xregister ARG *arg;
  1848. X{
  1849. X    register STR *str;
  1850. X    register STR *s1;
  1851. X    register STR *s2;
  1852. X    double value;        /* must not be register */
  1853. X    register char *tmps;
  1854. X    int i;
  1855. X    double exp(), log(), sqrt(), modf();
  1856. X    char *crypt();
  1857. X
  1858. X    if (!arg || !arg->arg_len)
  1859. X    return;
  1860. X
  1861. X    if (arg[1].arg_type == A_SINGLE &&
  1862. X        (arg->arg_len == 1 || arg[2].arg_type == A_SINGLE) ) {
  1863. X    str = str_new(0);
  1864. X    s1 = arg[1].arg_ptr.arg_str;
  1865. X    if (arg->arg_len > 1)
  1866. X        s2 = arg[2].arg_ptr.arg_str;
  1867. X    else
  1868. X        s2 = Nullstr;
  1869. X    switch (arg->arg_type) {
  1870. X    default:
  1871. X        str_free(str);
  1872. X        str = Nullstr;        /* can't be evaluated yet */
  1873. X        break;
  1874. X    case O_CONCAT:
  1875. X        str_sset(str,s1);
  1876. X        str_scat(str,s2);
  1877. X        break;
  1878. X    case O_REPEAT:
  1879. X        i = (int)str_gnum(s2);
  1880. X        while (i--)
  1881. X        str_scat(str,s1);
  1882. X        break;
  1883. X    case O_MULTIPLY:
  1884. X        value = str_gnum(s1);
  1885. X        str_numset(str,value * str_gnum(s2));
  1886. X        break;
  1887. X    case O_DIVIDE:
  1888. X        value = str_gnum(s1);
  1889. X        str_numset(str,value / str_gnum(s2));
  1890. X        break;
  1891. X    case O_MODULO:
  1892. X        value = str_gnum(s1);
  1893. X        str_numset(str,(double)(((long)value) % ((long)str_gnum(s2))));
  1894. X        break;
  1895. X    case O_ADD:
  1896. X        value = str_gnum(s1);
  1897. X        str_numset(str,value + str_gnum(s2));
  1898. X        break;
  1899. X    case O_SUBTRACT:
  1900. X        value = str_gnum(s1);
  1901. X        str_numset(str,value - str_gnum(s2));
  1902. X        break;
  1903. X    case O_LEFT_SHIFT:
  1904. X        value = str_gnum(s1);
  1905. X        str_numset(str,(double)(((long)value) << ((long)str_gnum(s2))));
  1906. X        break;
  1907. X    case O_RIGHT_SHIFT:
  1908. X        value = str_gnum(s1);
  1909. X        str_numset(str,(double)(((long)value) >> ((long)str_gnum(s2))));
  1910. X        break;
  1911. X    case O_LT:
  1912. X        value = str_gnum(s1);
  1913. X        str_numset(str,(double)(value < str_gnum(s2)));
  1914. X        break;
  1915. X    case O_GT:
  1916. X        value = str_gnum(s1);
  1917. X        str_numset(str,(double)(value > str_gnum(s2)));
  1918. X        break;
  1919. X    case O_LE:
  1920. X        value = str_gnum(s1);
  1921. X        str_numset(str,(double)(value <= str_gnum(s2)));
  1922. X        break;
  1923. X    case O_GE:
  1924. X        value = str_gnum(s1);
  1925. X        str_numset(str,(double)(value >= str_gnum(s2)));
  1926. X        break;
  1927. X    case O_EQ:
  1928. X        value = str_gnum(s1);
  1929. X        str_numset(str,(double)(value == str_gnum(s2)));
  1930. X        break;
  1931. X    case O_NE:
  1932. X        value = str_gnum(s1);
  1933. X        str_numset(str,(double)(value != str_gnum(s2)));
  1934. X        break;
  1935. X    case O_BIT_AND:
  1936. X        value = str_gnum(s1);
  1937. X        str_numset(str,(double)(((long)value) & ((long)str_gnum(s2))));
  1938. X        break;
  1939. X    case O_XOR:
  1940. X        value = str_gnum(s1);
  1941. X        str_numset(str,(double)(((long)value) ^ ((long)str_gnum(s2))));
  1942. X        break;
  1943. X    case O_BIT_OR:
  1944. X        value = str_gnum(s1);
  1945. X        str_numset(str,(double)(((long)value) | ((long)str_gnum(s2))));
  1946. X        break;
  1947. X    case O_AND:
  1948. X        if (str_true(s1))
  1949. X        str = str_make(str_get(s2));
  1950. X        else
  1951. X        str = str_make(str_get(s1));
  1952. X        break;
  1953. X    case O_OR:
  1954. X        if (str_true(s1))
  1955. X        str = str_make(str_get(s1));
  1956. X        else
  1957. X        str = str_make(str_get(s2));
  1958. X        break;
  1959. X    case O_COND_EXPR:
  1960. X        if (arg[3].arg_type != A_SINGLE) {
  1961. X        str_free(str);
  1962. X        str = Nullstr;
  1963. X        }
  1964. X        else {
  1965. X        str = str_make(str_get(str_true(s1) ? s2 : arg[3].arg_ptr.arg_str));
  1966. X        str_free(arg[3].arg_ptr.arg_str);
  1967. X        }
  1968. X        break;
  1969. X    case O_NEGATE:
  1970. X        str_numset(str,(double)(-str_gnum(s1)));
  1971. X        break;
  1972. X    case O_NOT:
  1973. X        str_numset(str,(double)(!str_true(s1)));
  1974. X        break;
  1975. X    case O_COMPLEMENT:
  1976. X        str_numset(str,(double)(~(long)str_gnum(s1)));
  1977. X        break;
  1978. X    case O_LENGTH:
  1979. X        str_numset(str, (double)str_len(s1));
  1980. X        break;
  1981. X    case O_SUBSTR:
  1982. X        if (arg[3].arg_type != A_SINGLE || stabent("[",FALSE)) {
  1983. X        str_free(str);        /* making the fallacious assumption */
  1984. X        str = Nullstr;        /* that any $[ occurs before substr()*/
  1985. X        }
  1986. X        else {
  1987. X        char *beg;
  1988. X        int len = (int)str_gnum(s2);
  1989. X        int tmp;
  1990. X
  1991. X        for (beg = str_get(s1); *beg && len > 0; beg++,len--) ;
  1992. X        len = (int)str_gnum(arg[3].arg_ptr.arg_str);
  1993. X        str_free(arg[3].arg_ptr.arg_str);
  1994. X        if (len > (tmp = strlen(beg)))
  1995. X            len = tmp;
  1996. X        str_nset(str,beg,len);
  1997. X        }
  1998. X        break;
  1999. X    case O_SLT:
  2000. X        tmps = str_get(s1);
  2001. X        str_numset(str,(double)(strLT(tmps,str_get(s2))));
  2002. X        break;
  2003. X    case O_SGT:
  2004. X        tmps = str_get(s1);
  2005. X        str_numset(str,(double)(strGT(tmps,str_get(s2))));
  2006. X        break;
  2007. X    case O_SLE:
  2008. X        tmps = str_get(s1);
  2009. X        str_numset(str,(double)(strLE(tmps,str_get(s2))));
  2010. X        break;
  2011. X    case O_SGE:
  2012. X        tmps = str_get(s1);
  2013. X        str_numset(str,(double)(strGE(tmps,str_get(s2))));
  2014. X        break;
  2015. X    case O_SEQ:
  2016. X        tmps = str_get(s1);
  2017. X        str_numset(str,(double)(strEQ(tmps,str_get(s2))));
  2018. X        break;
  2019. X    case O_SNE:
  2020. X        tmps = str_get(s1);
  2021. X        str_numset(str,(double)(strNE(tmps,str_get(s2))));
  2022. X        break;
  2023. X    case O_CRYPT:
  2024. X        tmps = str_get(s1);
  2025. X        str_set(str,crypt(tmps,str_get(s2)));
  2026. X        break;
  2027. X    case O_EXP:
  2028. X        str_numset(str,exp(str_gnum(s1)));
  2029. X        break;
  2030. X    case O_LOG:
  2031. X        str_numset(str,log(str_gnum(s1)));
  2032. X        break;
  2033. X    case O_SQRT:
  2034. X        str_numset(str,sqrt(str_gnum(s1)));
  2035. X        break;
  2036. X    case O_INT:
  2037. X        modf(str_gnum(s1),&value);
  2038. X        str_numset(str,value);
  2039. X        break;
  2040. X    case O_ORD:
  2041. X        str_numset(str,(double)(*str_get(s1)));
  2042. X        break;
  2043. X    }
  2044. X    if (str) {
  2045. X        arg->arg_type = O_ITEM;    /* note arg1 type is already SINGLE */
  2046. X        str_free(s1);
  2047. X        str_free(s2);
  2048. X        arg[1].arg_ptr.arg_str = str;
  2049. X    }
  2050. X    }
  2051. X}
  2052. X
  2053. XARG *
  2054. Xl(arg)
  2055. Xregister ARG *arg;
  2056. X{
  2057. X    register int i;
  2058. X    register ARG *arg1;
  2059. X
  2060. X    arg->arg_flags |= AF_COMMON;    /* XXX should cross-match */
  2061. X
  2062. X    /* see if it's an array reference */
  2063. X
  2064. X    if (arg[1].arg_type == A_EXPR) {
  2065. X    arg1 = arg[1].arg_ptr.arg_arg;
  2066. X
  2067. X    if (arg1->arg_type == O_LIST && arg->arg_type != O_ITEM) {
  2068. X                        /* assign to list */
  2069. X        arg[1].arg_flags |= AF_SPECIAL;
  2070. X        arg[2].arg_flags |= AF_SPECIAL;
  2071. X        for (i = arg1->arg_len; i >= 1; i--) {
  2072. X        switch (arg1[i].arg_type) {
  2073. X        case A_STAB: case A_LVAL:
  2074. X            arg1[i].arg_type = A_LVAL;
  2075. X            break;
  2076. X        case A_EXPR: case A_LEXPR:
  2077. X            arg1[i].arg_type = A_LEXPR;
  2078. X            if (arg1[i].arg_ptr.arg_arg->arg_type == O_ARRAY)
  2079. X            arg1[i].arg_ptr.arg_arg->arg_type = O_LARRAY;
  2080. X            else if (arg1[i].arg_ptr.arg_arg->arg_type == O_HASH)
  2081. X            arg1[i].arg_ptr.arg_arg->arg_type = O_LHASH;
  2082. X            if (arg1[i].arg_ptr.arg_arg->arg_type == O_LARRAY)
  2083. X            break;
  2084. X            if (arg1[i].arg_ptr.arg_arg->arg_type == O_LHASH)
  2085. X            break;
  2086. X            /* FALL THROUGH */
  2087. X        default:
  2088. X            sprintf(tokenbuf,
  2089. X              "Illegal item (%s) as lvalue",argname[arg1[i].arg_type]);
  2090. X            yyerror(tokenbuf);
  2091. X        }
  2092. X        }
  2093. X    }
  2094. X    else if (arg1->arg_type == O_ARRAY) {
  2095. X        if (arg1->arg_len == 1 && arg->arg_type != O_ITEM) {
  2096. X                        /* assign to array */
  2097. X        arg[1].arg_flags |= AF_SPECIAL;
  2098. X        arg[2].arg_flags |= AF_SPECIAL;
  2099. X        }
  2100. X        else
  2101. X        arg1->arg_type = O_LARRAY;    /* assign to array elem */
  2102. X    }
  2103. X    else if (arg1->arg_type == O_HASH)
  2104. X        arg1->arg_type = O_LHASH;
  2105. X    else {
  2106. X        sprintf(tokenbuf,
  2107. X          "Illegal expression (%s) as lvalue",opname[arg1->arg_type]);
  2108. X        yyerror(tokenbuf);
  2109. X    }
  2110. X    arg[1].arg_type = A_LEXPR;
  2111. X#ifdef DEBUGGING
  2112. X    if (debug & 16)
  2113. X        fprintf(stderr,"lval LEXPR\n");
  2114. X#endif
  2115. X    return arg;
  2116. X    }
  2117. X
  2118. X    /* not an array reference, should be a register name */
  2119. X
  2120. X    if (arg[1].arg_type != A_STAB && arg[1].arg_type != A_LVAL) {
  2121. X    sprintf(tokenbuf,
  2122. X      "Illegal item (%s) as lvalue",argname[arg[1].arg_type]);
  2123. X    yyerror(tokenbuf);
  2124. X    }
  2125. X    arg[1].arg_type = A_LVAL;
  2126. X#ifdef DEBUGGING
  2127. X    if (debug & 16)
  2128. X    fprintf(stderr,"lval LVAL\n");
  2129. X#endif
  2130. X    return arg;
  2131. X}
  2132. X
  2133. XARG *
  2134. Xaddflags(i,flags,arg)
  2135. Xregister ARG *arg;
  2136. X{
  2137. X    arg[i].arg_flags |= flags;
  2138. X    return arg;
  2139. X}
  2140. X
  2141. XARG *
  2142. Xhide_ary(arg)
  2143. XARG *arg;
  2144. X{
  2145. X    if (arg->arg_type == O_ARRAY)
  2146. X    return make_op(O_ITEM,1,arg,Nullarg,Nullarg,0);
  2147. X    return arg;
  2148. X}
  2149. X
  2150. XARG *
  2151. Xmake_list(arg)
  2152. Xregister ARG *arg;
  2153. X{
  2154. X    register int i;
  2155. X    register ARG *node;
  2156. X    register ARG *nxtnode;
  2157. X    register int j;
  2158. X    STR *tmpstr;
  2159. X
  2160. X    if (!arg) {
  2161. X    arg = op_new(0);
  2162. X    arg->arg_type = O_LIST;
  2163. X    }
  2164. X    if (arg->arg_type != O_COMMA) {
  2165. X    arg->arg_flags |= AF_LISTISH;    /* see listish() below */
  2166. X    return arg;
  2167. X    }
  2168. X    for (i = 2, node = arg; ; i++) {
  2169. X    if (node->arg_len < 2)
  2170. X        break;
  2171. X        if (node[2].arg_type != A_EXPR)
  2172. X        break;
  2173. X    node = node[2].arg_ptr.arg_arg;
  2174. X    if (node->arg_type != O_COMMA)
  2175. X        break;
  2176. X    }
  2177. X    if (i > 2) {
  2178. X    node = arg;
  2179. X    arg = op_new(i);
  2180. X    tmpstr = arg->arg_ptr.arg_str;
  2181. X    *arg = *node;        /* copy everything except the STR */
  2182. X    arg->arg_ptr.arg_str = tmpstr;
  2183. X    for (j = 1; ; ) {
  2184. X        arg[j++] = node[1];
  2185. X        if (j >= i) {
  2186. X        arg[j] = node[2];
  2187. X        free_arg(node);
  2188. X        break;
  2189. X        }
  2190. X        nxtnode = node[2].arg_ptr.arg_arg;
  2191. X        free_arg(node);
  2192. X        node = nxtnode;
  2193. X    }
  2194. X    }
  2195. X    arg->arg_type = O_LIST;
  2196. X    arg->arg_len = i;
  2197. X    return arg;
  2198. X}
  2199. X
  2200. X/* turn a single item into a list */
  2201. X
  2202. XARG *
  2203. Xlistish(arg)
  2204. XARG *arg;
  2205. X{
  2206. X    if (arg->arg_flags & AF_LISTISH)
  2207. X    arg = make_op(O_LIST,1,arg,Nullarg,Nullarg,0);
  2208. X    return arg;
  2209. X}
  2210. X
  2211. XARG *
  2212. Xstab_to_arg(atype,stab)
  2213. Xint atype;
  2214. Xregister STAB *stab;
  2215. X{
  2216. X    register ARG *arg;
  2217. X
  2218. X    arg = op_new(1);
  2219. X    arg->arg_type = O_ITEM;
  2220. X    arg[1].arg_type = atype;
  2221. X    arg[1].arg_ptr.arg_stab = stab;
  2222. X    return arg;
  2223. X}
  2224. X
  2225. XARG *
  2226. Xcval_to_arg(cval)
  2227. Xregister char *cval;
  2228. X{
  2229. X    register ARG *arg;
  2230. X
  2231. X    arg = op_new(1);
  2232. X    arg->arg_type = O_ITEM;
  2233. X    arg[1].arg_type = A_SINGLE;
  2234. X    arg[1].arg_ptr.arg_str = str_make(cval);
  2235. X    safefree(cval);
  2236. X    return arg;
  2237. X}
  2238. X
  2239. XARG *
  2240. Xop_new(numargs)
  2241. Xint numargs;
  2242. X{
  2243. X    register ARG *arg;
  2244. X
  2245. X    arg = (ARG*)safemalloc((numargs + 1) * sizeof (ARG));
  2246. X    bzero((char *)arg, (numargs + 1) * sizeof (ARG));
  2247. X    arg->arg_ptr.arg_str = str_new(0);
  2248. X    arg->arg_len = numargs;
  2249. X    return arg;
  2250. X}
  2251. X
  2252. Xvoid
  2253. Xfree_arg(arg)
  2254. XARG *arg;
  2255. X{
  2256. X    str_free(arg->arg_ptr.arg_str);
  2257. X    safefree((char*)arg);
  2258. X}
  2259. X
  2260. XARG *
  2261. Xmake_match(type,expr,spat)
  2262. Xint type;
  2263. XARG *expr;
  2264. XSPAT *spat;
  2265. X{
  2266. X    register ARG *arg;
  2267. X
  2268. X    arg = make_op(type,2,expr,Nullarg,Nullarg,0);
  2269. X
  2270. X    arg[2].arg_type = A_SPAT;
  2271. X    arg[2].arg_ptr.arg_spat = spat;
  2272. X#ifdef DEBUGGING
  2273. X    if (debug & 16)
  2274. X    fprintf(stderr,"make_match SPAT=%lx\n",spat);
  2275. X#endif
  2276. X
  2277. X    if (type == O_SUBST || type == O_NSUBST) {
  2278. X    if (arg[1].arg_type != A_STAB)
  2279. X        yyerror("Illegal lvalue");
  2280. X    arg[1].arg_type = A_LVAL;
  2281. X    }
  2282. X    return arg;
  2283. X}
  2284. X
  2285. XARG *
  2286. Xcmd_to_arg(cmd)
  2287. XCMD *cmd;
  2288. X{
  2289. X    register ARG *arg;
  2290. X
  2291. X    arg = op_new(1);
  2292. X    arg->arg_type = O_ITEM;
  2293. X    arg[1].arg_type = A_CMD;
  2294. X    arg[1].arg_ptr.arg_cmd = cmd;
  2295. X    return arg;
  2296. X}
  2297. X
  2298. XCMD *
  2299. Xwopt(cmd)
  2300. Xregister CMD *cmd;
  2301. X{
  2302. X    register CMD *tail;
  2303. X    register ARG *arg = cmd->c_expr;
  2304. X    char *tmps;    /* used by True macro */
  2305. X
  2306. X    /* hoist "while (<channel>)" up into command block */
  2307. X
  2308. X    if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_READ) {
  2309. X    cmd->c_flags &= ~CF_OPTIMIZE;    /* clear optimization type */
  2310. X    cmd->c_flags |= CFT_GETS;    /* and set it to do the input */
  2311. X    cmd->c_stab = arg[1].arg_ptr.arg_stab;
  2312. X    if (arg[1].arg_ptr.arg_stab->stab_io->flags & IOF_ARGV) {
  2313. X        cmd->c_expr = l(make_op(O_ASSIGN, 2,    /* fake up "$_ =" */
  2314. X           stab_to_arg(A_LVAL,defstab), arg, Nullarg,1 ));
  2315. X    }
  2316. X    else {
  2317. X        free_arg(arg);
  2318. X        cmd->c_expr = Nullarg;
  2319. X    }
  2320. X    }
  2321. X
  2322. X    /* First find the end of the true list */
  2323. X
  2324. X    if (cmd->ucmd.ccmd.cc_true == Nullcmd)
  2325. X    return cmd;
  2326. X    for (tail = cmd->ucmd.ccmd.cc_true; tail->c_next; tail = tail->c_next) ;
  2327. X
  2328. X    /* if there's a continue block, link it to true block and find end */
  2329. X
  2330. X    if (cmd->ucmd.ccmd.cc_alt != Nullcmd) {
  2331. X    tail->c_next = cmd->ucmd.ccmd.cc_alt;
  2332. X    for ( ; tail->c_next; tail = tail->c_next) ;
  2333. X    }
  2334. X
  2335. X    /* Here's the real trick: link the end of the list back to the beginning,
  2336. X     * inserting a "last" block to break out of the loop.  This saves one or
  2337. X     * two procedure calls every time through the loop, because of how cmd_exec
  2338. X     * does tail recursion.
  2339. X     */
  2340. X
  2341. X    tail->c_next = (CMD *) safemalloc(sizeof (CMD));
  2342. X    tail = tail->c_next;
  2343. X    if (!cmd->ucmd.ccmd.cc_alt)
  2344. X    cmd->ucmd.ccmd.cc_alt = tail;    /* every loop has a continue now */
  2345. X
  2346. X    bcopy((char *)cmd, (char *)tail, sizeof(CMD));
  2347. X    tail->c_type = C_EXPR;
  2348. X    tail->c_flags ^= CF_INVERT;        /* turn into "last unless" */
  2349. X    tail->c_next = tail->ucmd.ccmd.cc_true;    /* loop directly back to top */
  2350. X    tail->ucmd.acmd.ac_expr = make_op(O_LAST,0,Nullarg,Nullarg,Nullarg,0);
  2351. X    tail->ucmd.acmd.ac_stab = Nullstab;
  2352. X    return cmd;
  2353. X}
  2354. X
  2355. XFCMD *
  2356. Xload_format()
  2357. X{
  2358. X    FCMD froot;
  2359. X    FCMD *flinebeg;
  2360. X    register FCMD *fprev = &froot;
  2361. X    register FCMD *fcmd;
  2362. X    register char *s;
  2363. X    register char *t;
  2364. X    register char tmpchar;
  2365. X    bool noblank;
  2366. X
  2367. X    while ((s = str_gets(linestr,rsfp)) != Nullch) {
  2368. X    line++;
  2369. X    if (strEQ(s,".\n")) {
  2370. X        bufptr = s;
  2371. X        return froot.f_next;
  2372. X    }
  2373. X    if (*s == '#')
  2374. X        continue;
  2375. X    flinebeg = Nullfcmd;
  2376. X    noblank = FALSE;
  2377. X    while (*s) {
  2378. X        fcmd = (FCMD *)safemalloc(sizeof (FCMD));
  2379. X        bzero((char*)fcmd, sizeof (FCMD));
  2380. X        fprev->f_next = fcmd;
  2381. X        fprev = fcmd;
  2382. X        for (t=s; *t && *t != '@' && *t != '^'; t++) {
  2383. X        if (*t == '~') {
  2384. X            noblank = TRUE;
  2385. X            *t = ' ';
  2386. X        }
  2387. X        }
  2388. X        tmpchar = *t;
  2389. X        *t = '\0';
  2390. X        fcmd->f_pre = savestr(s);
  2391. X        fcmd->f_presize = strlen(s);
  2392. X        *t = tmpchar;
  2393. X        s = t;
  2394. X        if (!*s) {
  2395. X        if (noblank)
  2396. X            fcmd->f_flags |= FC_NOBLANK;
  2397. X        break;
  2398. X        }
  2399. X        if (!flinebeg)
  2400. X        flinebeg = fcmd;        /* start values here */
  2401. X        if (*s++ == '^')
  2402. X        fcmd->f_flags |= FC_CHOP;    /* for doing text filling */
  2403. X        switch (*s) {
  2404. X        case '*':
  2405. X        fcmd->f_type = F_LINES;
  2406. X        *s = '\0';
  2407. X        break;
  2408. X        case '<':
  2409. X        fcmd->f_type = F_LEFT;
  2410. X        while (*s == '<')
  2411. X            s++;
  2412. X        break;
  2413. X        case '>':
  2414. X        fcmd->f_type = F_RIGHT;
  2415. X        while (*s == '>')
  2416. X            s++;
  2417. X        break;
  2418. X        case '|':
  2419. X        fcmd->f_type = F_CENTER;
  2420. X        while (*s == '|')
  2421. X            s++;
  2422. X        break;
  2423. X        default:
  2424. X        fcmd->f_type = F_LEFT;
  2425. X        break;
  2426. X        }
  2427. X        if (fcmd->f_flags & FC_CHOP && *s == '.') {
  2428. X        fcmd->f_flags |= FC_MORE;
  2429. X        while (*s == '.')
  2430. X            s++;
  2431. X        }
  2432. X        fcmd->f_size = s-t;
  2433. X    }
  2434. X    if (flinebeg) {
  2435. X      again:
  2436. X        if ((bufptr = str_gets(linestr ,rsfp)) == Nullch)
  2437. X        goto badform;
  2438. X        line++;
  2439. X        if (strEQ(bufptr,".\n")) {
  2440. X        yyerror("Missing values line");
  2441. X        return froot.f_next;
  2442. X        }
  2443. X        if (*bufptr == '#')
  2444. X        goto again;
  2445. X        lex_newlines = TRUE;
  2446. X        while (flinebeg || *bufptr) {
  2447. X        switch(yylex()) {
  2448. X        default:
  2449. X            yyerror("Bad value in format");
  2450. X            *bufptr = '\0';
  2451. X            break;
  2452. X        case '\n':
  2453. X            if (flinebeg)
  2454. X            yyerror("Missing value in format");
  2455. X            *bufptr = '\0';
  2456. X            break;
  2457. X        case REG:
  2458. X            yylval.arg = stab_to_arg(A_LVAL,yylval.stabval);
  2459. X            /* FALL THROUGH */
  2460. X        case RSTRING:
  2461. X            if (!flinebeg)
  2462. X            yyerror("Extra value in format");
  2463. X            else {
  2464. X            flinebeg->f_expr = yylval.arg;
  2465. X            do {
  2466. X                flinebeg = flinebeg->f_next;
  2467. X            } while (flinebeg && flinebeg->f_size == 0);
  2468. X            }
  2469. X            break;
  2470. X        case ',': case ';':
  2471. X            continue;
  2472. X        }
  2473. X        }
  2474. X        lex_newlines = FALSE;
  2475. X    }
  2476. X    }
  2477. X  badform:
  2478. X    bufptr = str_get(linestr);
  2479. X    yyerror("Format not terminated");
  2480. X    return froot.f_next;
  2481. X}
  2482. !STUFFY!FUNK!
  2483. echo ""
  2484. echo "End of kit 2 (of 10)"
  2485. cat /dev/null >kit2isdone
  2486. config=true
  2487. for iskit in 1 2 3 4 5 6 7 8 9 10; do
  2488.     if test -f kit${iskit}isdone; then
  2489.     echo "You have run kit ${iskit}."
  2490.     else
  2491.     echo "You still need to run kit ${iskit}."
  2492.     config=false
  2493.     fi
  2494. done
  2495. case $config in
  2496.     true)
  2497.     echo "You have run all your kits.  Please read README and then type Configure."
  2498.     chmod 755 Configure
  2499.     ;;
  2500. esac
  2501. : Someone might mail this, so...
  2502. exit
  2503.