home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume20 / perl3.0 / part10 < prev    next >
Encoding:
Internet Message Format  |  1989-10-30  |  48.7 KB

  1. Subject:  v20i093:  Perl, a language with features of C/sed/awk/shell/etc, Part10/24
  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 20, Issue 93
  8. Archive-name: perl3.0/part10
  9.  
  10. #! /bin/sh
  11.  
  12. # Make a new directory for the perl sources, cd to it, and run kits 1
  13. # thru 24 through sh.  When all 24 kits have been run, read README.
  14.  
  15. echo "This is perl 3.0 kit 10 (of 24).  If kit 10 is complete, the line"
  16. echo '"'"End of kit 10 (of 24)"'" will echo at the end.'
  17. echo ""
  18. export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
  19. mkdir t 2>/dev/null
  20. echo Extracting cons.c
  21. sed >cons.c <<'!STUFFY!FUNK!' -e 's/X//'
  22. X/* $Header: cons.c,v 3.0 89/10/18 15:10:23 lwall Locked $
  23. X *
  24. X *    Copyright (c) 1989, Larry Wall
  25. X *
  26. X *    You may distribute under the terms of the GNU General Public License
  27. X *    as specified in the README file that comes with the perl 3.0 kit.
  28. X *
  29. X * $Log:    cons.c,v $
  30. X * Revision 3.0  89/10/18  15:10:23  lwall
  31. X * 3.0 baseline
  32. X * 
  33. X */
  34. X
  35. X#include "EXTERN.h"
  36. X#include "perl.h"
  37. X#include "perly.h"
  38. X
  39. Xextern char *tokename[];
  40. Xextern int yychar;
  41. X
  42. Xstatic int cmd_tosave();
  43. Xstatic int arg_tosave();
  44. Xstatic int spat_tosave();
  45. X
  46. Xstatic bool saw_return;
  47. X
  48. XSUBR *
  49. Xmake_sub(name,cmd)
  50. Xchar *name;
  51. XCMD *cmd;
  52. X{
  53. X    register SUBR *sub;
  54. X    STAB *stab = stabent(name,TRUE);
  55. X
  56. X    Newz(101,sub,1,SUBR);
  57. X    if (stab_sub(stab)) {
  58. X    if (dowarn) {
  59. X        line_t oldline = line;
  60. X
  61. X        if (cmd)
  62. X        line = cmd->c_line;
  63. X        warn("Subroutine %s redefined",name);
  64. X        line = oldline;
  65. X    }
  66. X    cmd_free(stab_sub(stab)->cmd);
  67. X    afree(stab_sub(stab)->tosave);
  68. X    Safefree(stab_sub(stab));
  69. X    }
  70. X    sub->filename = filename;
  71. X    saw_return = FALSE;
  72. X    tosave = anew(Nullstab);
  73. X    tosave->ary_fill = 0;    /* make 1 based */
  74. X    (void)cmd_tosave(cmd,FALSE);    /* this builds the tosave array */
  75. X    sub->tosave = tosave;
  76. X    if (saw_return) {
  77. X    struct compcmd mycompblock;
  78. X
  79. X    mycompblock.comp_true = cmd;
  80. X    mycompblock.comp_alt = Nullcmd;
  81. X    cmd = add_label(savestr("SUB"),make_ccmd(C_BLOCK,Nullarg,mycompblock));
  82. X    saw_return = FALSE;
  83. X    }
  84. X    sub->cmd = cmd;
  85. X    stab_sub(stab) = sub;
  86. X    if (perldb) {
  87. X    STR *str = str_nmake((double)subline);
  88. X
  89. X    str_cat(str,"-");
  90. X    sprintf(buf,"%ld",(long)line);
  91. X    str_cat(str,buf);
  92. X    name = str_get(subname);
  93. X    hstore(stab_xhash(DBsub),name,strlen(name),str,0);
  94. X    str_set(subname,"main");
  95. X    }
  96. X    subline = 0;
  97. X    return sub;
  98. X}
  99. X
  100. XCMD *
  101. Xblock_head(tail)
  102. Xregister CMD *tail;
  103. X{
  104. X    CMD *head;
  105. X    register int opt;
  106. X    register int last_opt = 0;
  107. X    register STAB *last_stab = Nullstab;
  108. X    register int count = 0;
  109. X    register CMD *switchbeg = Nullcmd;
  110. X
  111. X    if (tail == Nullcmd) {
  112. X    return tail;
  113. X    }
  114. X    head = tail->c_head;
  115. X
  116. X    for (tail = head; tail; tail = tail->c_next) {
  117. X
  118. X    /* save one measly dereference at runtime */
  119. X    if (tail->c_type == C_IF) {
  120. X        if (!(tail->ucmd.ccmd.cc_alt = tail->ucmd.ccmd.cc_alt->c_next))
  121. X        tail->c_flags |= CF_TERM;
  122. X    }
  123. X    else if (tail->c_type == C_EXPR) {
  124. X        ARG *arg;
  125. X
  126. X        if (tail->ucmd.acmd.ac_expr)
  127. X        arg = tail->ucmd.acmd.ac_expr;
  128. X        else
  129. X        arg = tail->c_expr;
  130. X        if (arg) {
  131. X        if (arg->arg_type == O_RETURN)
  132. X            tail->c_flags |= CF_TERM;
  133. X        else if (arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD)
  134. X            tail->c_flags |= CF_TERM;
  135. X        }
  136. X    }
  137. X    if (!tail->c_next)
  138. X        tail->c_flags |= CF_TERM;
  139. X
  140. X    if (tail->c_expr && (tail->c_flags & CF_OPTIMIZE) == CFT_FALSE)
  141. X        opt_arg(tail,1, tail->c_type == C_EXPR);
  142. X
  143. X    /* now do a little optimization on case-ish structures */
  144. X    switch(tail->c_flags & (CF_OPTIMIZE|CF_FIRSTNEG|CF_INVERT)) {
  145. X    case CFT_ANCHOR:
  146. X        if (stabent("*",FALSE)) {    /* bad assumption here!!! */
  147. X        opt = 0;
  148. X        break;
  149. X        }
  150. X        /* FALL THROUGH */
  151. X    case CFT_STROP:
  152. X        opt = (tail->c_flags & CF_NESURE) ? CFT_STROP : 0;
  153. X        break;
  154. X    case CFT_CCLASS:
  155. X        opt = CFT_STROP;
  156. X        break;
  157. X    case CFT_NUMOP:
  158. X        opt = (tail->c_slen == O_NE ? 0 : CFT_NUMOP);
  159. X        if ((tail->c_flags&(CF_NESURE|CF_EQSURE)) != (CF_NESURE|CF_EQSURE))
  160. X        opt = 0;
  161. X        break;
  162. X    default:
  163. X        opt = 0;
  164. X    }
  165. X    if (opt && opt == last_opt && tail->c_stab == last_stab)
  166. X        count++;
  167. X    else {
  168. X        if (count >= 3) {        /* is this the breakeven point? */
  169. X        if (last_opt == CFT_NUMOP)
  170. X            make_nswitch(switchbeg,count);
  171. X        else
  172. X            make_cswitch(switchbeg,count);
  173. X        }
  174. X        if (opt) {
  175. X        count = 1;
  176. X        switchbeg = tail;
  177. X        }
  178. X        else
  179. X        count = 0;
  180. X    }
  181. X    last_opt = opt;
  182. X    last_stab = tail->c_stab;
  183. X    }
  184. X    if (count >= 3) {        /* is this the breakeven point? */
  185. X    if (last_opt == CFT_NUMOP)
  186. X        make_nswitch(switchbeg,count);
  187. X    else
  188. X        make_cswitch(switchbeg,count);
  189. X    }
  190. X    return head;
  191. X}
  192. X
  193. X/* We've spotted a sequence of CMDs that all test the value of the same
  194. X * spat.  Thus we can insert a SWITCH in front and jump directly
  195. X * to the correct one.
  196. X */
  197. Xmake_cswitch(head,count)
  198. Xregister CMD *head;
  199. Xint count;
  200. X{
  201. X    register CMD *cur;
  202. X    register CMD **loc;
  203. X    register int i;
  204. X    register int min = 255;
  205. X    register int max = 0;
  206. X
  207. X    /* make a new head in the exact same spot */
  208. X    New(102,cur, 1, CMD);
  209. X#ifdef STRUCTCOPY
  210. X    *cur = *head;
  211. X#else
  212. X    Copy(head,cur,1,CMD);
  213. X#endif
  214. X    Zero(head,1,CMD);
  215. X    head->c_type = C_CSWITCH;
  216. X    head->c_next = cur;        /* insert new cmd at front of list */
  217. X    head->c_stab = cur->c_stab;
  218. X
  219. X    Newz(103,loc,258,CMD*);
  220. X    loc++;                /* lie a little */
  221. X    while (count--) {
  222. X    if ((cur->c_flags & CF_OPTIMIZE) == CFT_CCLASS) {
  223. X        for (i = 0; i <= 255; i++) {
  224. X        if (!loc[i] && cur->c_short->str_ptr[i>>3] & (1 << (i&7))) {
  225. X            loc[i] = cur;
  226. X            if (i < min)
  227. X            min = i;
  228. X            if (i > max)
  229. X            max = i;
  230. X        }
  231. X        }
  232. X    }
  233. X    else {
  234. X        i = *cur->c_short->str_ptr & 255;
  235. X        if (!loc[i]) {
  236. X        loc[i] = cur;
  237. X        if (i < min)
  238. X            min = i;
  239. X        if (i > max)
  240. X            max = i;
  241. X        }
  242. X    }
  243. X    cur = cur->c_next;
  244. X    }
  245. X    max++;
  246. X    if (min > 0)
  247. X    Copy(&loc[min],&loc[0], max - min, CMD*);
  248. X    loc--;
  249. X    min--;
  250. X    max -= min;
  251. X    for (i = 0; i <= max; i++)
  252. X    if (!loc[i])
  253. X        loc[i] = cur;
  254. X    Renew(loc,max+1,CMD*);    /* chop it down to size */
  255. X    head->ucmd.scmd.sc_offset = min;
  256. X    head->ucmd.scmd.sc_max = max;
  257. X    head->ucmd.scmd.sc_next = loc;
  258. X}
  259. X
  260. Xmake_nswitch(head,count)
  261. Xregister CMD *head;
  262. Xint count;
  263. X{
  264. X    register CMD *cur = head;
  265. X    register CMD **loc;
  266. X    register int i;
  267. X    register int min = 32767;
  268. X    register int max = -32768;
  269. X    int origcount = count;
  270. X    double value;        /* or your money back! */
  271. X    short changed;        /* so triple your money back! */
  272. X
  273. X    while (count--) {
  274. X    i = (int)str_gnum(cur->c_short);
  275. X    value = (double)i;
  276. X    if (value != cur->c_short->str_u.str_nval)
  277. X        return;        /* fractional values--just forget it */
  278. X    changed = i;
  279. X    if (changed != i)
  280. X        return;        /* too big for a short */
  281. X    if (cur->c_slen == O_LE)
  282. X        i++;
  283. X    else if (cur->c_slen == O_GE)    /* we only do < or > here */
  284. X        i--;
  285. X    if (i < min)
  286. X        min = i;
  287. X    if (i > max)
  288. X        max = i;
  289. X    cur = cur->c_next;
  290. X    }
  291. X    count = origcount;
  292. X    if (max - min > count * 2 + 10)        /* too sparse? */
  293. X    return;
  294. X
  295. X    /* now make a new head in the exact same spot */
  296. X    New(104,cur, 1, CMD);
  297. X#ifdef STRUCTCOPY
  298. X    *cur = *head;
  299. X#else
  300. X    Copy(head,cur,1,CMD);
  301. X#endif
  302. X    Zero(head,1,CMD);
  303. X    head->c_type = C_NSWITCH;
  304. X    head->c_next = cur;        /* insert new cmd at front of list */
  305. X    head->c_stab = cur->c_stab;
  306. X
  307. X    Newz(105,loc, max - min + 3, CMD*);
  308. X    loc++;
  309. X    while (count--) {
  310. X    i = (int)str_gnum(cur->c_short);
  311. X    i -= min;
  312. X    max -= min;
  313. X    max++;
  314. X    switch(cur->c_slen) {
  315. X    case O_LE:
  316. X        i++;
  317. X    case O_LT:
  318. X        for (i--; i >= -1; i--)
  319. X        if (!loc[i])
  320. X            loc[i] = cur;
  321. X        break;
  322. X    case O_GE:
  323. X        i--;
  324. X    case O_GT:
  325. X        for (i++; i <= max; i++)
  326. X        if (!loc[i])
  327. X            loc[i] = cur;
  328. X        break;
  329. X    case O_EQ:
  330. X        if (!loc[i])
  331. X        loc[i] = cur;
  332. X        break;
  333. X    }
  334. X    cur = cur->c_next;
  335. X    }
  336. X    loc--;
  337. X    min--;
  338. X    for (i = 0; i <= max; i++)
  339. X    if (!loc[i])
  340. X        loc[i] = cur;
  341. X    head->ucmd.scmd.sc_offset = min;
  342. X    head->ucmd.scmd.sc_max = max;
  343. X    head->ucmd.scmd.sc_next = loc;
  344. X}
  345. X
  346. XCMD *
  347. Xappend_line(head,tail)
  348. Xregister CMD *head;
  349. Xregister CMD *tail;
  350. X{
  351. X    if (tail == Nullcmd)
  352. X    return head;
  353. X    if (!tail->c_head)            /* make sure tail is well formed */
  354. X    tail->c_head = tail;
  355. X    if (head != Nullcmd) {
  356. X    tail = tail->c_head;        /* get to start of tail list */
  357. X    if (!head->c_head)
  358. X        head->c_head = head;    /* start a new head list */
  359. X    while (head->c_next) {
  360. X        head->c_next->c_head = head->c_head;
  361. X        head = head->c_next;    /* get to end of head list */
  362. X    }
  363. X    head->c_next = tail;        /* link to end of old list */
  364. X    tail->c_head = head->c_head;    /* propagate head pointer */
  365. X    }
  366. X    while (tail->c_next) {
  367. X    tail->c_next->c_head = tail->c_head;
  368. X    tail = tail->c_next;
  369. X    }
  370. X    return tail;
  371. X}
  372. X
  373. XCMD *
  374. Xdodb(cur)
  375. XCMD *cur;
  376. X{
  377. X    register CMD *cmd;
  378. X    register CMD *head = cur->c_head;
  379. X    register ARG *arg;
  380. X    STR *str;
  381. X
  382. X    if (!head)
  383. X    head = cur;
  384. X    if (!head->c_line)
  385. X    return cur;
  386. X    str = afetch(lineary,(int)head->c_line,FALSE);
  387. X    if (!str || str->str_nok)
  388. X    return cur;
  389. X    str->str_u.str_nval = (double)head->c_line;
  390. X    str->str_nok = 1;
  391. X    Newz(106,cmd,1,CMD);
  392. X    cmd->c_type = C_EXPR;
  393. X    cmd->ucmd.acmd.ac_stab = Nullstab;
  394. X    cmd->ucmd.acmd.ac_expr = Nullarg;
  395. X    arg = make_op(O_ITEM,1,Nullarg,Nullarg,Nullarg);
  396. X    arg[1].arg_type = A_SINGLE;
  397. X    arg[1].arg_ptr.arg_str = str_nmake((double)head->c_line);
  398. X    cmd->c_expr = make_op(O_SUBR, 2,
  399. X    stab2arg(A_WORD,DBstab),
  400. X    make_list(arg),
  401. X    Nullarg);
  402. X    cmd->c_flags |= CF_COND;
  403. X    cmd->c_line = head->c_line;
  404. X    cmd->c_label = head->c_label;
  405. X    cmd->c_file = filename;
  406. X    return append_line(cmd, cur);
  407. X}
  408. X
  409. XCMD *
  410. Xmake_acmd(type,stab,cond,arg)
  411. Xint type;
  412. XSTAB *stab;
  413. XARG *cond;
  414. XARG *arg;
  415. X{
  416. X    register CMD *cmd;
  417. X
  418. X    Newz(107,cmd,1,CMD);
  419. X    cmd->c_type = type;
  420. X    cmd->ucmd.acmd.ac_stab = stab;
  421. X    cmd->ucmd.acmd.ac_expr = arg;
  422. X    cmd->c_expr = cond;
  423. X    if (cond)
  424. X    cmd->c_flags |= CF_COND;
  425. X    if (cmdline != NOLINE) {
  426. X    cmd->c_line = cmdline;
  427. X    cmdline = NOLINE;
  428. X    }
  429. X    cmd->c_file = filename;
  430. X    if (perldb)
  431. X    cmd = dodb(cmd);
  432. X    return cmd;
  433. X}
  434. X
  435. XCMD *
  436. Xmake_ccmd(type,arg,cblock)
  437. Xint type;
  438. XARG *arg;
  439. Xstruct compcmd cblock;
  440. X{
  441. X    register CMD *cmd;
  442. X
  443. X    Newz(108,cmd, 1, CMD);
  444. X    cmd->c_type = type;
  445. X    cmd->c_expr = arg;
  446. X    cmd->ucmd.ccmd.cc_true = cblock.comp_true;
  447. X    cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
  448. X    if (arg)
  449. X    cmd->c_flags |= CF_COND;
  450. X    if (cmdline != NOLINE) {
  451. X    cmd->c_line = cmdline;
  452. X    cmdline = NOLINE;
  453. X    }
  454. X    if (perldb)
  455. X    cmd = dodb(cmd);
  456. X    return cmd;
  457. X}
  458. X
  459. XCMD *
  460. Xmake_icmd(type,arg,cblock)
  461. Xint type;
  462. XARG *arg;
  463. Xstruct compcmd cblock;
  464. X{
  465. X    register CMD *cmd;
  466. X    register CMD *alt;
  467. X    register CMD *cur;
  468. X    register CMD *head;
  469. X    struct compcmd ncblock;
  470. X
  471. X    Newz(109,cmd, 1, CMD);
  472. X    head = cmd;
  473. X    cmd->c_type = type;
  474. X    cmd->c_expr = arg;
  475. X    cmd->ucmd.ccmd.cc_true = cblock.comp_true;
  476. X    cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
  477. X    if (arg)
  478. X    cmd->c_flags |= CF_COND;
  479. X    if (cmdline != NOLINE) {
  480. X    cmd->c_line = cmdline;
  481. X    cmdline = NOLINE;
  482. X    }
  483. X    cur = cmd;
  484. X    alt = cblock.comp_alt;
  485. X    while (alt && alt->c_type == C_ELSIF) {
  486. X    cur = alt;
  487. X    alt = alt->ucmd.ccmd.cc_alt;
  488. X    }
  489. X    if (alt) {            /* a real life ELSE at the end? */
  490. X    ncblock.comp_true = alt;
  491. X    ncblock.comp_alt = Nullcmd;
  492. X    alt = append_line(cur,make_ccmd(C_ELSE,Nullarg,ncblock));
  493. X    cur->ucmd.ccmd.cc_alt = alt;
  494. X    }
  495. X    else
  496. X    alt = cur;        /* no ELSE, so cur is proxy ELSE */
  497. X
  498. X    cur = cmd;
  499. X    while (cmd) {        /* now point everyone at the ELSE */
  500. X    cur = cmd;
  501. X    cmd = cur->ucmd.ccmd.cc_alt;
  502. X    cur->c_head = head;
  503. X    if (cur->c_type == C_ELSIF)
  504. X        cur->c_type = C_IF;
  505. X    if (cur->c_type == C_IF)
  506. X        cur->ucmd.ccmd.cc_alt = alt;
  507. X    if (cur == alt)
  508. X        break;
  509. X    cur->c_next = cmd;
  510. X    }
  511. X    if (perldb)
  512. X    cur = dodb(cur);
  513. X    return cur;
  514. X}
  515. X
  516. Xvoid
  517. Xopt_arg(cmd,fliporflop,acmd)
  518. Xregister CMD *cmd;
  519. Xint fliporflop;
  520. Xint acmd;
  521. X{
  522. X    register ARG *arg;
  523. X    int opt = CFT_EVAL;
  524. X    int sure = 0;
  525. X    ARG *arg2;
  526. X    int context = 0;    /* 0 = normal, 1 = before &&, 2 = before || */
  527. X    int flp = fliporflop;
  528. X
  529. X    if (!cmd)
  530. X    return;
  531. X    if (!(arg = cmd->c_expr)) {
  532. X    cmd->c_flags &= ~CF_COND;
  533. X    return;
  534. X    }
  535. X
  536. X    /* Can we turn && and || into if and unless? */
  537. X
  538. X    if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM) &&
  539. X      (arg->arg_type == O_AND || arg->arg_type == O_OR) ) {
  540. X    dehoist(arg,1);
  541. X    arg[2].arg_type &= A_MASK;    /* don't suppress eval */
  542. X    dehoist(arg,2);
  543. X    cmd->ucmd.acmd.ac_expr = arg[2].arg_ptr.arg_arg;
  544. X    cmd->c_expr = arg[1].arg_ptr.arg_arg;
  545. X    if (arg->arg_type == O_OR)
  546. X        cmd->c_flags ^= CF_INVERT;        /* || is like unless */
  547. X    arg->arg_len = 0;
  548. X    free_arg(arg);
  549. X    arg = cmd->c_expr;
  550. X    }
  551. X
  552. X    /* Turn "if (!expr)" into "unless (expr)" */
  553. X
  554. X    if (!(cmd->c_flags & CF_TERM)) {        /* unless return value wanted */
  555. X    while (arg->arg_type == O_NOT) {
  556. X        dehoist(arg,1);
  557. X        cmd->c_flags ^= CF_INVERT;        /* flip sense of cmd */
  558. X        cmd->c_expr = arg[1].arg_ptr.arg_arg; /* hoist the rest of expr */
  559. X        free_arg(arg);
  560. X        arg = cmd->c_expr;            /* here we go again */
  561. X    }
  562. X    }
  563. X
  564. X    if (!arg->arg_len) {        /* sanity check */
  565. X    cmd->c_flags |= opt;
  566. X    return;
  567. X    }
  568. X
  569. X    /* for "cond .. cond" we set up for the initial check */
  570. X
  571. X    if (arg->arg_type == O_FLIP)
  572. X    context |= 4;
  573. X
  574. X    /* for "cond && expr" and "cond || expr" we can ignore expr, sort of */
  575. X
  576. X  morecontext:
  577. X    if (arg->arg_type == O_AND)
  578. X    context |= 1;
  579. X    else if (arg->arg_type == O_OR)
  580. X    context |= 2;
  581. X    if (context && (arg[flp].arg_type & A_MASK) == A_EXPR) {
  582. X    arg = arg[flp].arg_ptr.arg_arg;
  583. X    flp = 1;
  584. X    if (arg->arg_type == O_AND || arg->arg_type == O_OR)
  585. X        goto morecontext;
  586. X    }
  587. X    if ((context & 3) == 3)
  588. X    return;
  589. X
  590. X    if (arg[flp].arg_flags & (AF_PRE|AF_POST)) {
  591. X    cmd->c_flags |= opt;
  592. X    return;                /* side effect, can't optimize */
  593. X    }
  594. X
  595. X    if (arg->arg_type == O_ITEM || arg->arg_type == O_FLIP ||
  596. X      arg->arg_type == O_AND || arg->arg_type == O_OR) {
  597. X    if ((arg[flp].arg_type & A_MASK) == A_SINGLE) {
  598. X        opt = (str_true(arg[flp].arg_ptr.arg_str) ? CFT_TRUE : CFT_FALSE);
  599. X        cmd->c_short = str_smake(arg[flp].arg_ptr.arg_str);
  600. X        goto literal;
  601. X    }
  602. X    else if ((arg[flp].arg_type & A_MASK) == A_STAB ||
  603. X      (arg[flp].arg_type & A_MASK) == A_LVAL) {
  604. X        cmd->c_stab  = arg[flp].arg_ptr.arg_stab;
  605. X        opt = CFT_REG;
  606. X      literal:
  607. X        if (!context) {    /* no && or ||? */
  608. X        free_arg(arg);
  609. X        cmd->c_expr = Nullarg;
  610. X        }
  611. X        if (!(context & 1))
  612. X        cmd->c_flags |= CF_EQSURE;
  613. X        if (!(context & 2))
  614. X        cmd->c_flags |= CF_NESURE;
  615. X    }
  616. X    }
  617. X    else if (arg->arg_type == O_MATCH || arg->arg_type == O_SUBST ||
  618. X         arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST) {
  619. X    if ((arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) &&
  620. X        (arg[2].arg_type & A_MASK) == A_SPAT &&
  621. X        arg[2].arg_ptr.arg_spat->spat_short ) {
  622. X        cmd->c_stab  = arg[1].arg_ptr.arg_stab;
  623. X        cmd->c_short = str_smake(arg[2].arg_ptr.arg_spat->spat_short);
  624. X        cmd->c_slen  = arg[2].arg_ptr.arg_spat->spat_slen;
  625. X        if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ALL &&
  626. X        !(arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ONCE) &&
  627. X        (arg->arg_type == O_MATCH || arg->arg_type == O_NMATCH) )
  628. X        sure |= CF_EQSURE;        /* (SUBST must be forced even */
  629. X                        /* if we know it will work.) */
  630. X        if (arg->arg_type != O_SUBST) {
  631. X        arg[2].arg_ptr.arg_spat->spat_short = Nullstr;
  632. X        arg[2].arg_ptr.arg_spat->spat_slen = 0; /* only one chk */
  633. X        }
  634. X        sure |= CF_NESURE;        /* normally only sure if it fails */
  635. X        if (arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST)
  636. X        cmd->c_flags |= CF_FIRSTNEG;
  637. X        if (context & 1) {        /* only sure if thing is false */
  638. X        if (cmd->c_flags & CF_FIRSTNEG)
  639. X            sure &= ~CF_NESURE;
  640. X        else
  641. X            sure &= ~CF_EQSURE;
  642. X        }
  643. X        else if (context & 2) {    /* only sure if thing is true */
  644. X        if (cmd->c_flags & CF_FIRSTNEG)
  645. X            sure &= ~CF_EQSURE;
  646. X        else
  647. X            sure &= ~CF_NESURE;
  648. X        }
  649. X        if (sure & (CF_EQSURE|CF_NESURE)) {    /* if we know anything*/
  650. X        if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_SCANFIRST)
  651. X            opt = CFT_SCAN;
  652. X        else
  653. X            opt = CFT_ANCHOR;
  654. X        if (sure == (CF_EQSURE|CF_NESURE)    /* really sure? */
  655. X            && arg->arg_type == O_MATCH
  656. X            && context & 4
  657. X            && fliporflop == 1) {
  658. X            spat_free(arg[2].arg_ptr.arg_spat);
  659. X            arg[2].arg_ptr.arg_spat = Nullspat;    /* don't do twice */
  660. X        }
  661. X        cmd->c_flags |= sure;
  662. X        }
  663. X    }
  664. X    }
  665. X    else if (arg->arg_type == O_SEQ || arg->arg_type == O_SNE ||
  666. X         arg->arg_type == O_SLT || arg->arg_type == O_SGT) {
  667. X    if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) {
  668. X        if (arg[2].arg_type == A_SINGLE) {
  669. X        cmd->c_stab  = arg[1].arg_ptr.arg_stab;
  670. X        cmd->c_short = str_smake(arg[2].arg_ptr.arg_str);
  671. X        cmd->c_slen  = cmd->c_short->str_cur+1;
  672. X        switch (arg->arg_type) {
  673. X        case O_SLT: case O_SGT:
  674. X            sure |= CF_EQSURE;
  675. X            cmd->c_flags |= CF_FIRSTNEG;
  676. X            break;
  677. X        case O_SNE:
  678. X            cmd->c_flags |= CF_FIRSTNEG;
  679. X            /* FALL THROUGH */
  680. X        case O_SEQ:
  681. X            sure |= CF_NESURE|CF_EQSURE;
  682. X            break;
  683. X        }
  684. X        if (context & 1) {    /* only sure if thing is false */
  685. X            if (cmd->c_flags & CF_FIRSTNEG)
  686. X            sure &= ~CF_NESURE;
  687. X            else
  688. X            sure &= ~CF_EQSURE;
  689. X        }
  690. X        else if (context & 2) { /* only sure if thing is true */
  691. X            if (cmd->c_flags & CF_FIRSTNEG)
  692. X            sure &= ~CF_EQSURE;
  693. X            else
  694. X            sure &= ~CF_NESURE;
  695. X        }
  696. X        if (sure & (CF_EQSURE|CF_NESURE)) {
  697. X            opt = CFT_STROP;
  698. X            cmd->c_flags |= sure;
  699. X        }
  700. X        }
  701. X    }
  702. X    }
  703. X    else if (arg->arg_type == O_EQ || arg->arg_type == O_NE ||
  704. X         arg->arg_type == O_LE || arg->arg_type == O_GE ||
  705. X         arg->arg_type == O_LT || arg->arg_type == O_GT) {
  706. X    if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) {
  707. X        if (arg[2].arg_type == A_SINGLE) {
  708. X        cmd->c_stab  = arg[1].arg_ptr.arg_stab;
  709. X        if (dowarn) {
  710. X            STR *str = arg[2].arg_ptr.arg_str;
  711. X
  712. X            if ((!str->str_nok && !looks_like_number(str)))
  713. X            warn("Possible use of == on string value");
  714. X        }
  715. X        cmd->c_short = str_nmake(str_gnum(arg[2].arg_ptr.arg_str));
  716. X        cmd->c_slen = arg->arg_type;
  717. X        sure |= CF_NESURE|CF_EQSURE;
  718. X        if (context & 1) {    /* only sure if thing is false */
  719. X            sure &= ~CF_EQSURE;
  720. X        }
  721. X        else if (context & 2) { /* only sure if thing is true */
  722. X            sure &= ~CF_NESURE;
  723. X        }
  724. X        if (sure & (CF_EQSURE|CF_NESURE)) {
  725. X            opt = CFT_NUMOP;
  726. X            cmd->c_flags |= sure;
  727. X        }
  728. X        }
  729. X    }
  730. X    }
  731. X    else if (arg->arg_type == O_ASSIGN &&
  732. X         (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) &&
  733. X         arg[1].arg_ptr.arg_stab == defstab &&
  734. X         arg[2].arg_type == A_EXPR ) {
  735. X    arg2 = arg[2].arg_ptr.arg_arg;
  736. X    if (arg2->arg_type == O_ITEM && arg2[1].arg_type == A_READ) {
  737. X        opt = CFT_GETS;
  738. X        cmd->c_stab = arg2[1].arg_ptr.arg_stab;
  739. X        if (!(stab_io(arg2[1].arg_ptr.arg_stab)->flags & IOF_ARGV)) {
  740. X        free_arg(arg2);
  741. X        free_arg(arg);
  742. X        cmd->c_expr = Nullarg;
  743. X        }
  744. X    }
  745. X    }
  746. X    else if (arg->arg_type == O_CHOP &&
  747. X         (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) ) {
  748. X    opt = CFT_CHOP;
  749. X    cmd->c_stab = arg[1].arg_ptr.arg_stab;
  750. X    free_arg(arg);
  751. X    cmd->c_expr = Nullarg;
  752. X    }
  753. X    if (context & 4)
  754. X    opt |= CF_FLIP;
  755. X    cmd->c_flags |= opt;
  756. X
  757. X    if (cmd->c_flags & CF_FLIP) {
  758. X    if (fliporflop == 1) {
  759. X        arg = cmd->c_expr;    /* get back to O_FLIP arg */
  760. X        New(110,arg[3].arg_ptr.arg_cmd, 1, CMD);
  761. X        Copy(cmd, arg[3].arg_ptr.arg_cmd, 1, CMD);
  762. X        New(111,arg[4].arg_ptr.arg_cmd,1,CMD);
  763. X        Copy(cmd, arg[4].arg_ptr.arg_cmd, 1, CMD);
  764. X        opt_arg(arg[4].arg_ptr.arg_cmd,2,acmd);
  765. X        arg->arg_len = 2;        /* this is a lie */
  766. X    }
  767. X    else {
  768. X        if ((opt & CF_OPTIMIZE) == CFT_EVAL)
  769. X        cmd->c_flags = (cmd->c_flags & ~CF_OPTIMIZE) | CFT_UNFLIP;
  770. X    }
  771. X    }
  772. X}
  773. X
  774. XCMD *
  775. Xadd_label(lbl,cmd)
  776. Xchar *lbl;
  777. Xregister CMD *cmd;
  778. X{
  779. X    if (cmd)
  780. X    cmd->c_label = lbl;
  781. X    return cmd;
  782. X}
  783. X
  784. XCMD *
  785. Xaddcond(cmd, arg)
  786. Xregister CMD *cmd;
  787. Xregister ARG *arg;
  788. X{
  789. X    cmd->c_expr = arg;
  790. X    cmd->c_flags |= CF_COND;
  791. X    return cmd;
  792. X}
  793. X
  794. XCMD *
  795. Xaddloop(cmd, arg)
  796. Xregister CMD *cmd;
  797. Xregister ARG *arg;
  798. X{
  799. X    void while_io();
  800. X
  801. X    cmd->c_expr = arg;
  802. X    cmd->c_flags |= CF_COND|CF_LOOP;
  803. X
  804. X    if (!(cmd->c_flags & CF_INVERT))
  805. X    while_io(cmd);        /* add $_ =, if necessary */
  806. X
  807. X    if (cmd->c_type == C_BLOCK)
  808. X    cmd->c_flags &= ~CF_COND;
  809. X    else {
  810. X    arg = cmd->ucmd.acmd.ac_expr;
  811. X    if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD)
  812. X        cmd->c_flags &= ~CF_COND;  /* "do {} while" happens at least once */
  813. X    if (arg && arg->arg_type == O_SUBR)
  814. X        cmd->c_flags &= ~CF_COND;  /* likewise for "do subr() while" */
  815. X    }
  816. X    return cmd;
  817. X}
  818. X
  819. XCMD *
  820. Xinvert(cmd)
  821. Xregister CMD *cmd;
  822. X{
  823. X    if (cmd->c_head)
  824. X    cmd->c_head->c_flags ^= CF_INVERT;
  825. X    else
  826. X    cmd->c_flags ^= CF_INVERT;
  827. X    return cmd;
  828. X}
  829. X
  830. Xyyerror(s)
  831. Xchar *s;
  832. X{
  833. X    char tmpbuf[258];
  834. X    char tmp2buf[258];
  835. X    char *tname = tmpbuf;
  836. X
  837. X    if (bufptr > oldoldbufptr && bufptr - oldoldbufptr < 200 &&
  838. X      oldoldbufptr != oldbufptr && oldbufptr != bufptr) {
  839. X    while (isspace(*oldoldbufptr))
  840. X        oldoldbufptr++;
  841. X    strncpy(tmp2buf, oldoldbufptr, bufptr - oldoldbufptr);
  842. X    tmp2buf[bufptr - oldoldbufptr] = '\0';
  843. X    sprintf(tname,"next 2 tokens \"%s\"",tmp2buf);
  844. X    }
  845. X    else if (bufptr > oldbufptr && bufptr - oldbufptr < 200 &&
  846. X      oldbufptr != bufptr) {
  847. X    while (isspace(*oldbufptr))
  848. X        oldbufptr++;
  849. X    strncpy(tmp2buf, oldbufptr, bufptr - oldbufptr);
  850. X    tmp2buf[bufptr - oldbufptr] = '\0';
  851. X    sprintf(tname,"next token \"%s\"",tmp2buf);
  852. X    }
  853. X    else if (yychar > 256)
  854. X    tname = "next token ???";
  855. X    else if (!yychar)
  856. X    (void)strcpy(tname,"at EOF");
  857. X    else if (yychar < 32)
  858. X    (void)sprintf(tname,"next char ^%c",yychar+64);
  859. X    else if (yychar == 127)
  860. X    (void)strcpy(tname,"at EOF");
  861. X    else
  862. X    (void)sprintf(tname,"next char %c",yychar);
  863. X    (void)sprintf(buf, "%s in file %s at line %d, %s\n",
  864. X      s,filename,line,tname);
  865. X    if (line == multi_end && multi_start < multi_end)
  866. X    sprintf(buf+strlen(buf),
  867. X      "  (Might be a runaway multi-line %c%c string starting on line %d)\n",
  868. X      multi_open,multi_close,multi_start);
  869. X    if (in_eval)
  870. X    str_cat(stab_val(stabent("@",TRUE)),buf);
  871. X    else
  872. X    fputs(buf,stderr);
  873. X    if (++error_count >= 10)
  874. X    fatal("Too many errors\n");
  875. X}
  876. X
  877. Xvoid
  878. Xwhile_io(cmd)
  879. Xregister CMD *cmd;
  880. X{
  881. X    register ARG *arg = cmd->c_expr;
  882. X    STAB *asgnstab;
  883. X
  884. X    /* hoist "while (<channel>)" up into command block */
  885. X
  886. X    if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_READ) {
  887. X    cmd->c_flags &= ~CF_OPTIMIZE;    /* clear optimization type */
  888. X    cmd->c_flags |= CFT_GETS;    /* and set it to do the input */
  889. X    cmd->c_stab = arg[1].arg_ptr.arg_stab;
  890. X    if (stab_io(arg[1].arg_ptr.arg_stab)->flags & IOF_ARGV) {
  891. X        cmd->c_expr = l(make_op(O_ASSIGN, 2,    /* fake up "$_ =" */
  892. X           stab2arg(A_LVAL,defstab), arg, Nullarg));
  893. X    }
  894. X    else {
  895. X        free_arg(arg);
  896. X        cmd->c_expr = Nullarg;
  897. X    }
  898. X    }
  899. X    else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_INDREAD) {
  900. X    cmd->c_flags &= ~CF_OPTIMIZE;    /* clear optimization type */
  901. X    cmd->c_flags |= CFT_INDGETS;    /* and set it to do the input */
  902. X    cmd->c_stab = arg[1].arg_ptr.arg_stab;
  903. X    free_arg(arg);
  904. X    cmd->c_expr = Nullarg;
  905. X    }
  906. X    else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_GLOB) {
  907. X    if ((cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY)
  908. X        asgnstab = cmd->c_stab;
  909. X    else
  910. X        asgnstab = defstab;
  911. X    cmd->c_expr = l(make_op(O_ASSIGN, 2,    /* fake up "$foo =" */
  912. X       stab2arg(A_LVAL,asgnstab), arg, Nullarg));
  913. X    cmd->c_flags &= ~CF_OPTIMIZE;    /* clear optimization type */
  914. X    }
  915. X}
  916. X
  917. XCMD *
  918. Xwopt(cmd)
  919. Xregister CMD *cmd;
  920. X{
  921. X    register CMD *tail;
  922. X    CMD *newtail;
  923. X    register int i;
  924. X
  925. X    if (cmd->c_expr && (cmd->c_flags & CF_OPTIMIZE) == CFT_FALSE)
  926. X    opt_arg(cmd,1, cmd->c_type == C_EXPR);
  927. X
  928. X    while_io(cmd);        /* add $_ =, if necessary */
  929. X
  930. X    /* First find the end of the true list */
  931. X
  932. X    tail = cmd->ucmd.ccmd.cc_true;
  933. X    if (tail == Nullcmd)
  934. X    return cmd;
  935. X    New(112,newtail, 1, CMD);    /* guaranteed continue */
  936. X    for (;;) {
  937. X    /* optimize "next" to point directly to continue block */
  938. X    if (tail->c_type == C_EXPR &&
  939. X        tail->ucmd.acmd.ac_expr &&
  940. X        tail->ucmd.acmd.ac_expr->arg_type == O_NEXT &&
  941. X        (tail->ucmd.acmd.ac_expr->arg_len == 0 ||
  942. X         (cmd->c_label &&
  943. X          strEQ(cmd->c_label,
  944. X            tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
  945. X    {
  946. X        arg_free(tail->ucmd.acmd.ac_expr);
  947. X        tail->c_type = C_NEXT;
  948. X        if (cmd->ucmd.ccmd.cc_alt != Nullcmd)
  949. X        tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt;
  950. X        else
  951. X        tail->ucmd.ccmd.cc_alt = newtail;
  952. X        tail->ucmd.ccmd.cc_true = Nullcmd;
  953. X    }
  954. X    else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) {
  955. X        if (cmd->ucmd.ccmd.cc_alt != Nullcmd)
  956. X        tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt;
  957. X        else
  958. X        tail->ucmd.ccmd.cc_alt = newtail;
  959. X    }
  960. X    else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) {
  961. X        if (cmd->ucmd.ccmd.cc_alt != Nullcmd) {
  962. X        for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
  963. X            if (!tail->ucmd.scmd.sc_next[i])
  964. X            tail->ucmd.scmd.sc_next[i] = cmd->ucmd.ccmd.cc_alt;
  965. X        }
  966. X        else {
  967. X        for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
  968. X            if (!tail->ucmd.scmd.sc_next[i])
  969. X            tail->ucmd.scmd.sc_next[i] = newtail;
  970. X        }
  971. X    }
  972. X
  973. X    if (!tail->c_next)
  974. X        break;
  975. X    tail = tail->c_next;
  976. X    }
  977. X
  978. X    /* if there's a continue block, link it to true block and find end */
  979. X
  980. X    if (cmd->ucmd.ccmd.cc_alt != Nullcmd) {
  981. X    tail->c_next = cmd->ucmd.ccmd.cc_alt;
  982. X    tail = tail->c_next;
  983. X    for (;;) {
  984. X        /* optimize "next" to point directly to continue block */
  985. X        if (tail->c_type == C_EXPR &&
  986. X        tail->ucmd.acmd.ac_expr &&
  987. X        tail->ucmd.acmd.ac_expr->arg_type == O_NEXT &&
  988. X        (tail->ucmd.acmd.ac_expr->arg_len == 0 ||
  989. X         (cmd->c_label &&
  990. X          strEQ(cmd->c_label,
  991. X            tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
  992. X        {
  993. X        arg_free(tail->ucmd.acmd.ac_expr);
  994. X        tail->c_type = C_NEXT;
  995. X        tail->ucmd.ccmd.cc_alt = newtail;
  996. X        tail->ucmd.ccmd.cc_true = Nullcmd;
  997. X        }
  998. X        else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) {
  999. X        tail->ucmd.ccmd.cc_alt = newtail;
  1000. X        }
  1001. X        else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) {
  1002. X        for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
  1003. X            if (!tail->ucmd.scmd.sc_next[i])
  1004. X            tail->ucmd.scmd.sc_next[i] = newtail;
  1005. X        }
  1006. X
  1007. X        if (!tail->c_next)
  1008. X        break;
  1009. X        tail = tail->c_next;
  1010. X    }
  1011. X    for ( ; tail->c_next; tail = tail->c_next) ;
  1012. X    }
  1013. X
  1014. X    /* Here's the real trick: link the end of the list back to the beginning,
  1015. X     * inserting a "last" block to break out of the loop.  This saves one or
  1016. X     * two procedure calls every time through the loop, because of how cmd_exec
  1017. X     * does tail recursion.
  1018. X     */
  1019. X
  1020. X    tail->c_next = newtail;
  1021. X    tail = newtail;
  1022. X    if (!cmd->ucmd.ccmd.cc_alt)
  1023. X    cmd->ucmd.ccmd.cc_alt = tail;    /* every loop has a continue now */
  1024. X
  1025. X#ifndef lint
  1026. X    (void)bcopy((char *)cmd, (char *)tail, sizeof(CMD));
  1027. X#endif
  1028. X    tail->c_type = C_EXPR;
  1029. X    tail->c_flags ^= CF_INVERT;        /* turn into "last unless" */
  1030. X    tail->c_next = tail->ucmd.ccmd.cc_true;    /* loop directly back to top */
  1031. X    tail->ucmd.acmd.ac_expr = make_op(O_LAST,0,Nullarg,Nullarg,Nullarg);
  1032. X    tail->ucmd.acmd.ac_stab = Nullstab;
  1033. X    return cmd;
  1034. X}
  1035. X
  1036. XCMD *
  1037. Xover(eachstab,cmd)
  1038. XSTAB *eachstab;
  1039. Xregister CMD *cmd;
  1040. X{
  1041. X    /* hoist "for $foo (@bar)" up into command block */
  1042. X
  1043. X    cmd->c_flags &= ~CF_OPTIMIZE;    /* clear optimization type */
  1044. X    cmd->c_flags |= CFT_ARRAY;        /* and set it to do the iteration */
  1045. X    cmd->c_stab = eachstab;
  1046. X
  1047. X    return cmd;
  1048. X}
  1049. X
  1050. Xcmd_free(cmd)
  1051. Xregister CMD *cmd;
  1052. X{
  1053. X    register CMD *tofree;
  1054. X    register CMD *head = cmd;
  1055. X
  1056. X    while (cmd) {
  1057. X    if (cmd->c_type != C_WHILE) {    /* WHILE block is duplicated */
  1058. X        if (cmd->c_label)
  1059. X        Safefree(cmd->c_label);
  1060. X        if (cmd->c_short)
  1061. X        str_free(cmd->c_short);
  1062. X        if (cmd->c_spat)
  1063. X        spat_free(cmd->c_spat);
  1064. X        if (cmd->c_expr)
  1065. X        arg_free(cmd->c_expr);
  1066. X    }
  1067. X    switch (cmd->c_type) {
  1068. X    case C_WHILE:
  1069. X    case C_BLOCK:
  1070. X    case C_ELSE:
  1071. X    case C_IF:
  1072. X        if (cmd->ucmd.ccmd.cc_true)
  1073. X        cmd_free(cmd->ucmd.ccmd.cc_true);
  1074. X        break;
  1075. X    case C_EXPR:
  1076. X        if (cmd->ucmd.acmd.ac_expr)
  1077. X        arg_free(cmd->ucmd.acmd.ac_expr);
  1078. X        break;
  1079. X    }
  1080. X    tofree = cmd;
  1081. X    cmd = cmd->c_next;
  1082. X    Safefree(tofree);
  1083. X    if (cmd && cmd == head)        /* reached end of while loop */
  1084. X        break;
  1085. X    }
  1086. X}
  1087. X
  1088. Xarg_free(arg)
  1089. Xregister ARG *arg;
  1090. X{
  1091. X    register int i;
  1092. X
  1093. X    for (i = 1; i <= arg->arg_len; i++) {
  1094. X    switch (arg[i].arg_type & A_MASK) {
  1095. X    case A_NULL:
  1096. X        break;
  1097. X    case A_LEXPR:
  1098. X        if (arg->arg_type == O_AASSIGN &&
  1099. X          arg[i].arg_ptr.arg_arg->arg_type == O_LARRAY) {
  1100. X        char *name = 
  1101. X          stab_name(arg[i].arg_ptr.arg_arg[1].arg_ptr.arg_stab);
  1102. X
  1103. X        if (strnEQ("_GEN_",name, 5))    /* array for foreach */
  1104. X            hdelete(defstash,name,strlen(name));
  1105. X        }
  1106. X        /* FALL THROUGH */
  1107. X    case A_EXPR:
  1108. X        arg_free(arg[i].arg_ptr.arg_arg);
  1109. X        break;
  1110. X    case A_CMD:
  1111. X        cmd_free(arg[i].arg_ptr.arg_cmd);
  1112. X        break;
  1113. X    case A_WORD:
  1114. X    case A_STAB:
  1115. X    case A_LVAL:
  1116. X    case A_READ:
  1117. X    case A_GLOB:
  1118. X    case A_ARYLEN:
  1119. X    case A_LARYLEN:
  1120. X    case A_ARYSTAB:
  1121. X    case A_LARYSTAB:
  1122. X        break;
  1123. X    case A_SINGLE:
  1124. X    case A_DOUBLE:
  1125. X    case A_BACKTICK:
  1126. X        str_free(arg[i].arg_ptr.arg_str);
  1127. X        break;
  1128. X    case A_SPAT:
  1129. X        spat_free(arg[i].arg_ptr.arg_spat);
  1130. X        break;
  1131. X    }
  1132. X    }
  1133. X    free_arg(arg);
  1134. X}
  1135. X
  1136. Xspat_free(spat)
  1137. Xregister SPAT *spat;
  1138. X{
  1139. X    register SPAT *sp;
  1140. X    HENT *entry;
  1141. X
  1142. X    if (spat->spat_runtime)
  1143. X    arg_free(spat->spat_runtime);
  1144. X    if (spat->spat_repl) {
  1145. X    arg_free(spat->spat_repl);
  1146. X    }
  1147. X    if (spat->spat_short) {
  1148. X    str_free(spat->spat_short);
  1149. X    }
  1150. X    if (spat->spat_regexp) {
  1151. X    regfree(spat->spat_regexp);
  1152. X    }
  1153. X
  1154. X    /* now unlink from spat list */
  1155. X
  1156. X    for (entry = defstash->tbl_array['_']; entry; entry = entry->hent_next) {
  1157. X    register HASH *stash;
  1158. X    STAB *stab = (STAB*)entry->hent_val;
  1159. X
  1160. X    if (!stab)
  1161. X        continue;
  1162. X    stash = stab_hash(stab);
  1163. X    if (!stash || stash->tbl_spatroot == Null(SPAT*))
  1164. X        continue;
  1165. X    if (stash->tbl_spatroot == spat)
  1166. X        stash->tbl_spatroot = spat->spat_next;
  1167. X    else {
  1168. X        for (sp = stash->tbl_spatroot;
  1169. X          sp && sp->spat_next != spat;
  1170. X          sp = sp->spat_next)
  1171. X        ;
  1172. X        if (sp)
  1173. X        sp->spat_next = spat->spat_next;
  1174. X    }
  1175. X    }
  1176. X    Safefree(spat);
  1177. X}
  1178. X
  1179. X/* Recursively descend a command sequence and push the address of any string
  1180. X * that needs saving on recursion onto the tosave array.
  1181. X */
  1182. X
  1183. Xstatic int
  1184. Xcmd_tosave(cmd,willsave)
  1185. Xregister CMD *cmd;
  1186. Xint willsave;                /* willsave passes down the tree */
  1187. X{
  1188. X    register CMD *head = cmd;
  1189. X    int shouldsave = FALSE;        /* shouldsave passes up the tree */
  1190. X    int tmpsave;
  1191. X    register CMD *lastcmd = Nullcmd;
  1192. X
  1193. X    while (cmd) {
  1194. X    if (cmd->c_spat)
  1195. X        shouldsave |= spat_tosave(cmd->c_spat);
  1196. X    if (cmd->c_expr)
  1197. X        shouldsave |= arg_tosave(cmd->c_expr,willsave);
  1198. X    switch (cmd->c_type) {
  1199. X    case C_WHILE:
  1200. X        if (cmd->ucmd.ccmd.cc_true) {
  1201. X        tmpsave = cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
  1202. X
  1203. X        /* Here we check to see if the temporary array generated for
  1204. X         * a foreach needs to be localized because of recursion.
  1205. X         */
  1206. X        if (tmpsave && (cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY &&
  1207. X          lastcmd &&
  1208. X          lastcmd->c_type == C_EXPR &&
  1209. X          lastcmd->ucmd.acmd.ac_expr) {
  1210. X            ARG *arg = lastcmd->ucmd.acmd.ac_expr;
  1211. X
  1212. X            if (arg->arg_type == O_ASSIGN &&
  1213. X            arg[1].arg_type == A_LEXPR &&
  1214. X            arg[1].arg_ptr.arg_arg->arg_type == O_LARRAY &&
  1215. X            strnEQ("_GEN_",
  1216. X              stab_name(arg[1].arg_ptr.arg_arg[1].arg_ptr.arg_stab),
  1217. X              5)) {        /* array generated for foreach */
  1218. X            (void)localize(arg[1].arg_ptr.arg_arg);
  1219. X            }
  1220. X        }
  1221. X        shouldsave |= tmpsave;
  1222. X        }
  1223. X        break;
  1224. X    case C_BLOCK:
  1225. X    case C_ELSE:
  1226. X    case C_IF:
  1227. X        if (cmd->ucmd.ccmd.cc_true)
  1228. X        shouldsave |= cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
  1229. X        break;
  1230. X    case C_EXPR:
  1231. X        if (cmd->ucmd.acmd.ac_expr)
  1232. X        shouldsave |= arg_tosave(cmd->ucmd.acmd.ac_expr,willsave);
  1233. X        break;
  1234. X    }
  1235. X    lastcmd = cmd;
  1236. X    cmd = cmd->c_next;
  1237. X    if (cmd && cmd == head)        /* reached end of while loop */
  1238. X        break;
  1239. X    }
  1240. X    return shouldsave;
  1241. X}
  1242. X
  1243. Xstatic int
  1244. Xarg_tosave(arg,willsave)
  1245. Xregister ARG *arg;
  1246. Xint willsave;
  1247. X{
  1248. X    register int i;
  1249. X    int shouldsave = FALSE;
  1250. X
  1251. X    for (i = arg->arg_len; i >= 1; i--) {
  1252. X    switch (arg[i].arg_type & A_MASK) {
  1253. X    case A_NULL:
  1254. X        break;
  1255. X    case A_LEXPR:
  1256. X    case A_EXPR:
  1257. X        shouldsave |= arg_tosave(arg[i].arg_ptr.arg_arg,shouldsave);
  1258. X        break;
  1259. X    case A_CMD:
  1260. X        shouldsave |= cmd_tosave(arg[i].arg_ptr.arg_cmd,shouldsave);
  1261. X        break;
  1262. X    case A_WORD:
  1263. X    case A_STAB:
  1264. X    case A_LVAL:
  1265. X    case A_READ:
  1266. X    case A_GLOB:
  1267. X    case A_ARYLEN:
  1268. X    case A_SINGLE:
  1269. X    case A_DOUBLE:
  1270. X    case A_BACKTICK:
  1271. X        break;
  1272. X    case A_SPAT:
  1273. X        shouldsave |= spat_tosave(arg[i].arg_ptr.arg_spat);
  1274. X        break;
  1275. X    }
  1276. X    }
  1277. X    switch (arg->arg_type) {
  1278. X    case O_RETURN:
  1279. X    saw_return = TRUE;
  1280. X    break;
  1281. X    case O_EVAL:
  1282. X    case O_SUBR:
  1283. X    shouldsave = TRUE;
  1284. X    break;
  1285. X    }
  1286. X    if (willsave)
  1287. X    (void)apush(tosave,arg->arg_ptr.arg_str);
  1288. X    return shouldsave;
  1289. X}
  1290. X
  1291. Xstatic int
  1292. Xspat_tosave(spat)
  1293. Xregister SPAT *spat;
  1294. X{
  1295. X    int shouldsave = FALSE;
  1296. X
  1297. X    if (spat->spat_runtime)
  1298. X    shouldsave |= arg_tosave(spat->spat_runtime,FALSE);
  1299. X    if (spat->spat_repl) {
  1300. X    shouldsave |= arg_tosave(spat->spat_repl,FALSE);
  1301. X    }
  1302. X
  1303. X    return shouldsave;
  1304. X}
  1305. X
  1306. !STUFFY!FUNK!
  1307. echo Extracting Copying
  1308. sed >Copying <<'!STUFFY!FUNK!' -e 's/X//'
  1309. X            GNU GENERAL PUBLIC LICENSE
  1310. X             Version 1, February 1989
  1311. X
  1312. X Copyright (C) 1989 Free Software Foundation, Inc.
  1313. X                    675 Mass Ave, Cambridge, MA 02139, USA
  1314. X Everyone is permitted to copy and distribute verbatim copies
  1315. X of this license document, but changing it is not allowed.
  1316. X
  1317. X                Preamble
  1318. X
  1319. X  The license agreements of most software companies try to keep users
  1320. Xat the mercy of those companies.  By contrast, our General Public
  1321. XLicense is intended to guarantee your freedom to share and change free
  1322. Xsoftware--to make sure the software is free for all its users.  The
  1323. XGeneral Public License applies to the Free Software Foundation's
  1324. Xsoftware and to any other program whose authors commit to using it.
  1325. XYou can use it for your programs, too.
  1326. X
  1327. X  When we speak of free software, we are referring to freedom, not
  1328. Xprice.  Specifically, the General Public License is designed to make
  1329. Xsure that you have the freedom to give away or sell copies of free
  1330. Xsoftware, that you receive source code or can get it if you want it,
  1331. Xthat you can change the software or use pieces of it in new free
  1332. Xprograms; and that you know you can do these things.
  1333. X
  1334. X  To protect your rights, we need to make restrictions that forbid
  1335. Xanyone to deny you these rights or to ask you to surrender the rights.
  1336. XThese restrictions translate to certain responsibilities for you if you
  1337. Xdistribute copies of the software, or if you modify it.
  1338. X
  1339. X  For example, if you distribute copies of a such a program, whether
  1340. Xgratis or for a fee, you must give the recipients all the rights that
  1341. Xyou have.  You must make sure that they, too, receive or can get the
  1342. Xsource code.  And you must tell them their rights.
  1343. X
  1344. X  We protect your rights with two steps: (1) copyright the software, and
  1345. X(2) offer you this license which gives you legal permission to copy,
  1346. Xdistribute and/or modify the software.
  1347. X
  1348. X  Also, for each author's protection and ours, we want to make certain
  1349. Xthat everyone understands that there is no warranty for this free
  1350. Xsoftware.  If the software is modified by someone else and passed on, we
  1351. Xwant its recipients to know that what they have is not the original, so
  1352. Xthat any problems introduced by others will not reflect on the original
  1353. Xauthors' reputations.
  1354. X
  1355. X  The precise terms and conditions for copying, distribution and
  1356. Xmodification follow.
  1357. X
  1358. X            GNU GENERAL PUBLIC LICENSE
  1359. X   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
  1360. X
  1361. X  0. This License Agreement applies to any program or other work which
  1362. Xcontains a notice placed by the copyright holder saying it may be
  1363. Xdistributed under the terms of this General Public License.  The
  1364. X"Program", below, refers to any such program or work, and a "work based
  1365. Xon the Program" means either the Program or any work containing the
  1366. XProgram or a portion of it, either verbatim or with modifications.  Each
  1367. Xlicensee is addressed as "you".
  1368. X
  1369. X  1. You may copy and distribute verbatim copies of the Program's source
  1370. Xcode as you receive it, in any medium, provided that you conspicuously and
  1371. Xappropriately publish on each copy an appropriate copyright notice and
  1372. Xdisclaimer of warranty; keep intact all the notices that refer to this
  1373. XGeneral Public License and to the absence of any warranty; and give any
  1374. Xother recipients of the Program a copy of this General Public License
  1375. Xalong with the Program.  You may charge a fee for the physical act of
  1376. Xtransferring a copy.
  1377. X
  1378. X  2. You may modify your copy or copies of the Program or any portion of
  1379. Xit, and copy and distribute such modifications under the terms of Paragraph
  1380. X1 above, provided that you also do the following:
  1381. X
  1382. X    a) cause the modified files to carry prominent notices stating that
  1383. X    you changed the files and the date of any change; and
  1384. X
  1385. X    b) cause the whole of any work that you distribute or publish, that
  1386. X    in whole or in part contains the Program or any part thereof, either
  1387. X    with or without modifications, to be licensed at no charge to all
  1388. X    third parties under the terms of this General Public License (except
  1389. X    that you may choose to grant warranty protection to some or all
  1390. X    third parties, at your option).
  1391. X
  1392. X    c) If the modified program normally reads commands interactively when
  1393. X    run, you must cause it, when started running for such interactive use
  1394. X    in the simplest and most usual way, to print or display an
  1395. X    announcement including an appropriate copyright notice and a notice
  1396. X    that there is no warranty (or else, saying that you provide a
  1397. X    warranty) and that users may redistribute the program under these
  1398. X    conditions, and telling the user how to view a copy of this General
  1399. X    Public License.
  1400. X
  1401. X    d) You may charge a fee for the physical act of transferring a
  1402. X    copy, and you may at your option offer warranty protection in
  1403. X    exchange for a fee.
  1404. X
  1405. XMere aggregation of another independent work with the Program (or its
  1406. Xderivative) on a volume of a storage or distribution medium does not bring
  1407. Xthe other work under the scope of these terms.
  1408. X
  1409. X  3. You may copy and distribute the Program (or a portion or derivative of
  1410. Xit, under Paragraph 2) in object code or executable form under the terms of
  1411. XParagraphs 1 and 2 above provided that you also do one of the following:
  1412. X
  1413. X    a) accompany it with the complete corresponding machine-readable
  1414. X    source code, which must be distributed under the terms of
  1415. X    Paragraphs 1 and 2 above; or,
  1416. X
  1417. X    b) accompany it with a written offer, valid for at least three
  1418. X    years, to give any third party free (except for a nominal charge
  1419. X    for the cost of distribution) a complete machine-readable copy of the
  1420. X    corresponding source code, to be distributed under the terms of
  1421. X    Paragraphs 1 and 2 above; or,
  1422. X
  1423. X    c) accompany it with the information you received as to where the
  1424. X    corresponding source code may be obtained.  (This alternative is
  1425. X    allowed only for noncommercial distribution and only if you
  1426. X    received the program in object code or executable form alone.)
  1427. X
  1428. XSource code for a work means the preferred form of the work for making
  1429. Xmodifications to it.  For an executable file, complete source code means
  1430. Xall the source code for all modules it contains; but, as a special
  1431. Xexception, it need not include source code for modules which are standard
  1432. Xlibraries that accompany the operating system on which the executable
  1433. Xfile runs, or for standard header files or definitions files that
  1434. Xaccompany that operating system.
  1435. X
  1436. X  4. You may not copy, modify, sublicense, distribute or transfer the
  1437. XProgram except as expressly provided under this General Public License.
  1438. XAny attempt otherwise to copy, modify, sublicense, distribute or transfer
  1439. Xthe Program is void, and will automatically terminate your rights to use
  1440. Xthe Program under this License.  However, parties who have received
  1441. Xcopies, or rights to use copies, from you under this General Public
  1442. XLicense will not have their licenses terminated so long as such parties
  1443. Xremain in full compliance.
  1444. X
  1445. X  5. By copying, distributing or modifying the Program (or any work based
  1446. Xon the Program) you indicate your acceptance of this license to do so,
  1447. Xand all its terms and conditions.
  1448. X
  1449. X  6. Each time you redistribute the Program (or any work based on the
  1450. XProgram), the recipient automatically receives a license from the original
  1451. Xlicensor to copy, distribute or modify the Program subject to these
  1452. Xterms and conditions.  You may not impose any further restrictions on the
  1453. Xrecipients' exercise of the rights granted herein.
  1454. X
  1455. X  7. The Free Software Foundation may publish revised and/or new versions
  1456. Xof the General Public License from time to time.  Such new versions will
  1457. Xbe similar in spirit to the present version, but may differ in detail to
  1458. Xaddress new problems or concerns.
  1459. X
  1460. XEach version is given a distinguishing version number.  If the Program
  1461. Xspecifies a version number of the license which applies to it and "any
  1462. Xlater version", you have the option of following the terms and conditions
  1463. Xeither of that version or of any later version published by the Free
  1464. XSoftware Foundation.  If the Program does not specify a version number of
  1465. Xthe license, you may choose any version ever published by the Free Software
  1466. XFoundation.
  1467. X
  1468. X  8. If you wish to incorporate parts of the Program into other free
  1469. Xprograms whose distribution conditions are different, write to the author
  1470. Xto ask for permission.  For software which is copyrighted by the Free
  1471. XSoftware Foundation, write to the Free Software Foundation; we sometimes
  1472. Xmake exceptions for this.  Our decision will be guided by the two goals
  1473. Xof preserving the free status of all derivatives of our free software and
  1474. Xof promoting the sharing and reuse of software generally.
  1475. X
  1476. X                NO WARRANTY
  1477. X
  1478. X  9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
  1479. XFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
  1480. XOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
  1481. XPROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
  1482. XOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  1483. XMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
  1484. XTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
  1485. XPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
  1486. XREPAIR OR CORRECTION.
  1487. X
  1488. X  10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
  1489. XWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
  1490. XREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
  1491. XINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
  1492. XOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
  1493. XTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
  1494. XYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
  1495. XPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
  1496. XPOSSIBILITY OF SUCH DAMAGES.
  1497. X
  1498. X             END OF TERMS AND CONDITIONS
  1499. X
  1500. X    Appendix: How to Apply These Terms to Your New Programs
  1501. X
  1502. X  If you develop a new program, and you want it to be of the greatest
  1503. Xpossible use to humanity, the best way to achieve this is to make it
  1504. Xfree software which everyone can redistribute and change under these
  1505. Xterms.
  1506. X
  1507. X  To do so, attach the following notices to the program.  It is safest to
  1508. Xattach them to the start of each source file to most effectively convey
  1509. Xthe exclusion of warranty; and each file should have at least the
  1510. X"copyright" line and a pointer to where the full notice is found.
  1511. X
  1512. X    <one line to give the program's name and a brief idea of what it does.>
  1513. X    Copyright (C) 19yy  <name of author>
  1514. X
  1515. X    This program is free software; you can redistribute it and/or modify
  1516. X    it under the terms of the GNU General Public License as published by
  1517. X    the Free Software Foundation; either version 1, or (at your option)
  1518. X    any later version.
  1519. X
  1520. X    This program is distributed in the hope that it will be useful,
  1521. X    but WITHOUT ANY WARRANTY; without even the implied warranty of
  1522. X    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1523. X    GNU General Public License for more details.
  1524. X
  1525. X    You should have received a copy of the GNU General Public License
  1526. X    along with this program; if not, write to the Free Software
  1527. X    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  1528. X
  1529. XAlso add information on how to contact you by electronic and paper mail.
  1530. X
  1531. XIf the program is interactive, make it output a short notice like this
  1532. Xwhen it starts in an interactive mode:
  1533. X
  1534. X    Gnomovision version 69, Copyright (C) 19xx name of author
  1535. X    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
  1536. X    This is free software, and you are welcome to redistribute it
  1537. X    under certain conditions; type `show c' for details.
  1538. X
  1539. XThe hypothetical commands `show w' and `show c' should show the
  1540. Xappropriate parts of the General Public License.  Of course, the
  1541. Xcommands you use may be called something other than `show w' and `show
  1542. Xc'; they could even be mouse-clicks or menu items--whatever suits your
  1543. Xprogram.
  1544. X
  1545. XYou should also get your employer (if you work as a programmer) or your
  1546. Xschool, if any, to sign a "copyright disclaimer" for the program, if
  1547. Xnecessary.  Here a sample; alter the names:
  1548. X
  1549. X  Yoyodyne, Inc., hereby disclaims all copyright interest in the
  1550. X  program `Gnomovision' (a program to direct compilers to make passes
  1551. X  at assemblers) written by James Hacker.
  1552. X
  1553. X  <signature of Ty Coon>, 1 April 1989
  1554. X  Ty Coon, President of Vice
  1555. X
  1556. XThat's all there is to it!
  1557. !STUFFY!FUNK!
  1558. echo Extracting t/op.list
  1559. sed >t/op.list <<'!STUFFY!FUNK!' -e 's/X//'
  1560. X#!./perl
  1561. X
  1562. X# $Header: op.list,v 3.0 89/10/18 15:29:44 lwall Locked $
  1563. X
  1564. Xprint "1..27\n";
  1565. X
  1566. X@foo = (1, 2, 3, 4);
  1567. Xif ($foo[0] == 1 && $foo[3] == 4) {print "ok 1\n";} else {print "not ok 1\n";}
  1568. X
  1569. X$_ = join(':',@foo);
  1570. Xif ($_ eq '1:2:3:4') {print "ok 2\n";} else {print "not ok 2\n";}
  1571. X
  1572. X($a,$b,$c,$d) = (1,2,3,4);
  1573. Xif ("$a;$b;$c;$d" eq '1;2;3;4') {print "ok 3\n";} else {print "not ok 3\n";}
  1574. X
  1575. X($c,$b,$a) = split(/ /,"111 222 333");
  1576. Xif ("$a;$b;$c" eq '333;222;111') {print "ok 4\n";} else {print "not ok 4\n";}
  1577. X
  1578. X($a,$b,$c) = ($c,$b,$a);
  1579. Xif ("$a;$b;$c" eq '111;222;333') {print "ok 5\n";} else {print "not ok 5 $a;$b;$c\n";}
  1580. X
  1581. X($a, $b) = ($b, $a);
  1582. Xif ("$a;$b;$c" eq '222;111;333') {print "ok 6\n";} else {print "not ok 6\n";}
  1583. X
  1584. X($a, $b[1], $c{2}, $d) = (1, 2, 3, 4);
  1585. Xif ($a eq 1) {print "ok 7\n";} else {print "not ok 7\n";}
  1586. Xif ($b[1] eq 2) {print "ok 8\n";} else {print "not ok 8\n";}
  1587. Xif ($c{2} eq 3) {print "ok 9\n";} else {print "not ok 9\n";}
  1588. Xif ($d eq 4) {print "ok 10\n";} else {print "not ok 10\n";}
  1589. X
  1590. X@foo = (1,2,3,4,5,6,7,8);
  1591. X($a, $b, $c, $d) = @foo;
  1592. Xprint "#11    $a;$b;$c;$d eq 1;2;3;4\n";
  1593. Xif ("$a;$b;$c;$d" eq '1;2;3;4') {print "ok 11\n";} else {print "not ok 11\n";}
  1594. X
  1595. X@foo = @bar = (1);
  1596. Xif (join(':',@foo,@bar) eq '1:1') {print "ok 12\n";} else {print "not ok 12\n";}
  1597. X
  1598. X@foo = ();
  1599. X@foo = 1+2+3;
  1600. Xif (join(':',@foo) eq '6') {print "ok 13\n";} else {print "not ok 13\n";}
  1601. X
  1602. Xfor ($x = 0; $x < 3; $x++) {
  1603. X    ($a, $b, $c) = 
  1604. X        $x == 0?
  1605. X            ('ok ', 14, "\n"):
  1606. X        $x == 1?
  1607. X            ('ok ', 15, "\n"):
  1608. X        # default
  1609. X            ('ok ', 16, "\n");
  1610. X
  1611. X    print $a,$b,$c;
  1612. X}
  1613. X
  1614. X@a = ($x == 12345 || (1,2,3));
  1615. Xif (join('',@a) eq '123') {print "ok 17\n";} else {print "not ok 17\n";}
  1616. X
  1617. X@a = ($x == $x || (4,5,6));
  1618. Xif (join('',@a) eq '1') {print "ok 18\n";} else {print "not ok 18\n";}
  1619. X
  1620. Xif (join('',1,2,(3,4,5)) eq '12345'){print "ok 19\n";}else{print "not ok 19\n";}
  1621. Xif (join('',(1,2,3,4,5)) eq '12345'){print "ok 20\n";}else{print "not ok 20\n";}
  1622. Xif (join('',(1,2,3,4),5) eq '12345'){print "ok 21\n";}else{print "not ok 21\n";}
  1623. Xif (join('',1,(2,3,4),5) eq '12345'){print "ok 22\n";}else{print "not ok 22\n";}
  1624. Xif (join('',1,2,(3,4),5) eq '12345'){print "ok 23\n";}else{print "not ok 23\n";}
  1625. Xif (join('',1,2,3,(4),5) eq '12345'){print "ok 24\n";}else{print "not ok 24\n";}
  1626. X
  1627. Xfor ($x = 0; $x < 3; $x++) {
  1628. X    ($a, $b, $c) = do {
  1629. X        if ($x == 0) {
  1630. X        ('ok ', 25, "\n");
  1631. X        }
  1632. X        elsif ($x == 1) {
  1633. X        ('ok ', 26, "\n");
  1634. X        }
  1635. X        else {
  1636. X        ('ok ', 27, "\n");
  1637. X        }
  1638. X    };
  1639. X
  1640. X    print $a,$b,$c;
  1641. X}
  1642. X
  1643. !STUFFY!FUNK!
  1644. echo Extracting patchlevel.h
  1645. sed >patchlevel.h <<'!STUFFY!FUNK!' -e 's/X//'
  1646. X#define PATCHLEVEL 0
  1647. !STUFFY!FUNK!
  1648. echo ""
  1649. echo "End of kit 10 (of 24)"
  1650. cat /dev/null >kit10isdone
  1651. run=''
  1652. config=''
  1653. for iskit in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24; do
  1654.     if test -f kit${iskit}isdone; then
  1655.     run="$run $iskit"
  1656.     else
  1657.     todo="$todo $iskit"
  1658.     fi
  1659. done
  1660. case $todo in
  1661.     '')
  1662.     echo "You have run all your kits.  Please read README and then type Configure."
  1663.     chmod 755 Configure
  1664.     ;;
  1665.     *)  echo "You have run$run."
  1666.     echo "You still need to run$todo."
  1667.     ;;
  1668. esac
  1669. : Someone might mail this, so...
  1670. exit
  1671.  
  1672.