home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume18 / perl / part13 < prev    next >
Internet Message Format  |  1991-04-15  |  51KB

  1. From: lwall@netlabs.com (Larry Wall)
  2. Newsgroups: comp.sources.misc
  3. Subject: v18i031:  perl - The perl programming language, Part13/36
  4. Message-ID: <1991Apr16.000055.22898@sparky.IMD.Sterling.COM>
  5. Date: 16 Apr 91 00:00:55 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Checksum-Snefru: e7499025 189af290 df5e914e c3e89925
  8.  
  9. Submitted-by: Larry Wall <lwall@netlabs.com>
  10. Posting-number: Volume 18, Issue 31
  11. Archive-name: perl/part13
  12.  
  13. [There are 36 kits for perl version 4.0.]
  14.  
  15. #! /bin/sh
  16.  
  17. # Make a new directory for the perl sources, cd to it, and run kits 1
  18. # thru 36 through sh.  When all 36 kits have been run, read README.
  19.  
  20. echo "This is perl 4.0 kit 13 (of 36).  If kit 13 is complete, the line"
  21. echo '"'"End of kit 13 (of 36)"'" will echo at the end.'
  22. echo ""
  23. export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
  24. mkdir msdos x2p 2>/dev/null
  25. echo Extracting cons.c
  26. sed >cons.c <<'!STUFFY!FUNK!' -e 's/X//'
  27. X/* $Header: cons.c,v 4.0 91/03/20 01:05:51 lwall Locked $
  28. X *
  29. X *    Copyright (c) 1989, Larry Wall
  30. X *
  31. X *    You may distribute under the terms of the GNU General Public License
  32. X *    as specified in the README file that comes with the perl 3.0 kit.
  33. X *
  34. X * $Log:    cons.c,v $
  35. X * Revision 4.0  91/03/20  01:05:51  lwall
  36. X * 4.0 baseline.
  37. X * 
  38. X */
  39. X
  40. X#include "EXTERN.h"
  41. X#include "perl.h"
  42. X#include "perly.h"
  43. X
  44. Xextern char *tokename[];
  45. Xextern int yychar;
  46. X
  47. Xstatic int cmd_tosave();
  48. Xstatic int arg_tosave();
  49. Xstatic int spat_tosave();
  50. X
  51. Xstatic bool saw_return;
  52. X
  53. XSUBR *
  54. Xmake_sub(name,cmd)
  55. Xchar *name;
  56. XCMD *cmd;
  57. X{
  58. X    register SUBR *sub;
  59. X    STAB *stab = stabent(name,TRUE);
  60. X
  61. X    Newz(101,sub,1,SUBR);
  62. X    if (stab_sub(stab)) {
  63. X    if (dowarn) {
  64. X        CMD *oldcurcmd = curcmd;
  65. X
  66. X        if (cmd)
  67. X        curcmd = cmd;
  68. X        warn("Subroutine %s redefined",name);
  69. X        curcmd = oldcurcmd;
  70. X    }
  71. X    if (stab_sub(stab)->cmd) {
  72. X        cmd_free(stab_sub(stab)->cmd);
  73. X        stab_sub(stab)->cmd = Nullcmd;
  74. X        afree(stab_sub(stab)->tosave);
  75. X    }
  76. X    Safefree(stab_sub(stab));
  77. X    }
  78. X    stab_sub(stab) = sub;
  79. X    sub->filestab = curcmd->c_filestab;
  80. X    saw_return = FALSE;
  81. X    tosave = anew(Nullstab);
  82. X    tosave->ary_fill = 0;    /* make 1 based */
  83. X    (void)cmd_tosave(cmd,FALSE);    /* this builds the tosave array */
  84. X    sub->tosave = tosave;
  85. X    if (saw_return) {
  86. X    struct compcmd mycompblock;
  87. X
  88. X    mycompblock.comp_true = cmd;
  89. X    mycompblock.comp_alt = Nullcmd;
  90. X    cmd = add_label(savestr("_SUB_"),make_ccmd(C_BLOCK,Nullarg,mycompblock));
  91. X    saw_return = FALSE;
  92. X    cmd->c_flags |= CF_TERM;
  93. X    }
  94. X    sub->cmd = cmd;
  95. X    if (perldb) {
  96. X    STR *str;
  97. X    STR *tmpstr = str_mortal(&str_undef);
  98. X
  99. X    sprintf(buf,"%s:%ld",stab_val(curcmd->c_filestab)->str_ptr,
  100. X      (long)subline);
  101. X    str = str_make(buf,0);
  102. X    str_cat(str,"-");
  103. X    sprintf(buf,"%ld",(long)curcmd->c_line);
  104. X    str_cat(str,buf);
  105. X    name = str_get(subname);
  106. X    stab_fullname(tmpstr,stab);
  107. X    hstore(stab_xhash(DBsub), tmpstr->str_ptr, tmpstr->str_cur, str, 0);
  108. X    str_set(subname,"main");
  109. X    }
  110. X    subline = 0;
  111. X    return sub;
  112. X}
  113. X
  114. XSUBR *
  115. Xmake_usub(name, ix, subaddr, filename)
  116. Xchar *name;
  117. Xint ix;
  118. Xint (*subaddr)();
  119. Xchar *filename;
  120. X{
  121. X    register SUBR *sub;
  122. X    STAB *stab = stabent(name,allstabs);
  123. X
  124. X    if (!stab)                /* unused function */
  125. X    return Null(SUBR*);
  126. X    Newz(101,sub,1,SUBR);
  127. X    if (stab_sub(stab)) {
  128. X    if (dowarn)
  129. X        warn("Subroutine %s redefined",name);
  130. X    if (stab_sub(stab)->cmd) {
  131. X        cmd_free(stab_sub(stab)->cmd);
  132. X        stab_sub(stab)->cmd = Nullcmd;
  133. X        afree(stab_sub(stab)->tosave);
  134. X    }
  135. X    Safefree(stab_sub(stab));
  136. X    }
  137. X    stab_sub(stab) = sub;
  138. X    sub->filestab = fstab(filename);
  139. X    sub->usersub = subaddr;
  140. X    sub->userindex = ix;
  141. X    return sub;
  142. X}
  143. X
  144. Xmake_form(stab,fcmd)
  145. XSTAB *stab;
  146. XFCMD *fcmd;
  147. X{
  148. X    if (stab_form(stab)) {
  149. X    FCMD *tmpfcmd;
  150. X    FCMD *nextfcmd;
  151. X
  152. X    for (tmpfcmd = stab_form(stab); tmpfcmd; tmpfcmd = nextfcmd) {
  153. X        nextfcmd = tmpfcmd->f_next;
  154. X        if (tmpfcmd->f_expr)
  155. X        arg_free(tmpfcmd->f_expr);
  156. X        if (tmpfcmd->f_unparsed)
  157. X        str_free(tmpfcmd->f_unparsed);
  158. X        if (tmpfcmd->f_pre)
  159. X        Safefree(tmpfcmd->f_pre);
  160. X        Safefree(tmpfcmd);
  161. X    }
  162. X    }
  163. X    stab_form(stab) = fcmd;
  164. X}
  165. X
  166. XCMD *
  167. Xblock_head(tail)
  168. Xregister CMD *tail;
  169. X{
  170. X    CMD *head;
  171. X    register int opt;
  172. X    register int last_opt = 0;
  173. X    register STAB *last_stab = Nullstab;
  174. X    register int count = 0;
  175. X    register CMD *switchbeg = Nullcmd;
  176. X
  177. X    if (tail == Nullcmd) {
  178. X    return tail;
  179. X    }
  180. X    head = tail->c_head;
  181. X
  182. X    for (tail = head; tail; tail = tail->c_next) {
  183. X
  184. X    /* save one measly dereference at runtime */
  185. X    if (tail->c_type == C_IF) {
  186. X        if (!(tail->ucmd.ccmd.cc_alt = tail->ucmd.ccmd.cc_alt->c_next))
  187. X        tail->c_flags |= CF_TERM;
  188. X    }
  189. X    else if (tail->c_type == C_EXPR) {
  190. X        ARG *arg;
  191. X
  192. X        if (tail->ucmd.acmd.ac_expr)
  193. X        arg = tail->ucmd.acmd.ac_expr;
  194. X        else
  195. X        arg = tail->c_expr;
  196. X        if (arg) {
  197. X        if (arg->arg_type == O_RETURN)
  198. X            tail->c_flags |= CF_TERM;
  199. X        else if (arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD)
  200. X            tail->c_flags |= CF_TERM;
  201. X        }
  202. X    }
  203. X    if (!tail->c_next)
  204. X        tail->c_flags |= CF_TERM;
  205. X
  206. X    if (tail->c_expr && (tail->c_flags & CF_OPTIMIZE) == CFT_FALSE)
  207. X        opt_arg(tail,1, tail->c_type == C_EXPR);
  208. X
  209. X    /* now do a little optimization on case-ish structures */
  210. X    switch(tail->c_flags & (CF_OPTIMIZE|CF_FIRSTNEG|CF_INVERT)) {
  211. X    case CFT_ANCHOR:
  212. X        if (stabent("*",FALSE)) {    /* bad assumption here!!! */
  213. X        opt = 0;
  214. X        break;
  215. X        }
  216. X        /* FALL THROUGH */
  217. X    case CFT_STROP:
  218. X        opt = (tail->c_flags & CF_NESURE) ? CFT_STROP : 0;
  219. X        break;
  220. X    case CFT_CCLASS:
  221. X        opt = CFT_STROP;
  222. X        break;
  223. X    case CFT_NUMOP:
  224. X        opt = (tail->c_slen == O_NE ? 0 : CFT_NUMOP);
  225. X        if ((tail->c_flags&(CF_NESURE|CF_EQSURE)) != (CF_NESURE|CF_EQSURE))
  226. X        opt = 0;
  227. X        break;
  228. X    default:
  229. X        opt = 0;
  230. X    }
  231. X    if (opt && opt == last_opt && tail->c_stab == last_stab)
  232. X        count++;
  233. X    else {
  234. X        if (count >= 3) {        /* is this the breakeven point? */
  235. X        if (last_opt == CFT_NUMOP)
  236. X            make_nswitch(switchbeg,count);
  237. X        else
  238. X            make_cswitch(switchbeg,count);
  239. X        }
  240. X        if (opt) {
  241. X        count = 1;
  242. X        switchbeg = tail;
  243. X        }
  244. X        else
  245. X        count = 0;
  246. X    }
  247. X    last_opt = opt;
  248. X    last_stab = tail->c_stab;
  249. X    }
  250. X    if (count >= 3) {        /* is this the breakeven point? */
  251. X    if (last_opt == CFT_NUMOP)
  252. X        make_nswitch(switchbeg,count);
  253. X    else
  254. X        make_cswitch(switchbeg,count);
  255. X    }
  256. X    return head;
  257. X}
  258. X
  259. X/* We've spotted a sequence of CMDs that all test the value of the same
  260. X * spat.  Thus we can insert a SWITCH in front and jump directly
  261. X * to the correct one.
  262. X */
  263. Xmake_cswitch(head,count)
  264. Xregister CMD *head;
  265. Xint count;
  266. X{
  267. X    register CMD *cur;
  268. X    register CMD **loc;
  269. X    register int i;
  270. X    register int min = 255;
  271. X    register int max = 0;
  272. X
  273. X    /* make a new head in the exact same spot */
  274. X    New(102,cur, 1, CMD);
  275. X#ifdef STRUCTCOPY
  276. X    *cur = *head;
  277. X#else
  278. X    Copy(head,cur,1,CMD);
  279. X#endif
  280. X    Zero(head,1,CMD);
  281. X    head->c_type = C_CSWITCH;
  282. X    head->c_next = cur;        /* insert new cmd at front of list */
  283. X    head->c_stab = cur->c_stab;
  284. X
  285. X    Newz(103,loc,258,CMD*);
  286. X    loc++;                /* lie a little */
  287. X    while (count--) {
  288. X    if ((cur->c_flags & CF_OPTIMIZE) == CFT_CCLASS) {
  289. X        for (i = 0; i <= 255; i++) {
  290. X        if (!loc[i] && cur->c_short->str_ptr[i>>3] & (1 << (i&7))) {
  291. X            loc[i] = cur;
  292. X            if (i < min)
  293. X            min = i;
  294. X            if (i > max)
  295. X            max = i;
  296. X        }
  297. X        }
  298. X    }
  299. X    else {
  300. X        i = *cur->c_short->str_ptr & 255;
  301. X        if (!loc[i]) {
  302. X        loc[i] = cur;
  303. X        if (i < min)
  304. X            min = i;
  305. X        if (i > max)
  306. X            max = i;
  307. X        }
  308. X    }
  309. X    cur = cur->c_next;
  310. X    }
  311. X    max++;
  312. X    if (min > 0)
  313. X    Copy(&loc[min],&loc[0], max - min, CMD*);
  314. X    loc--;
  315. X    min--;
  316. X    max -= min;
  317. X    for (i = 0; i <= max; i++)
  318. X    if (!loc[i])
  319. X        loc[i] = cur;
  320. X    Renew(loc,max+1,CMD*);    /* chop it down to size */
  321. X    head->ucmd.scmd.sc_offset = min;
  322. X    head->ucmd.scmd.sc_max = max;
  323. X    head->ucmd.scmd.sc_next = loc;
  324. X}
  325. X
  326. Xmake_nswitch(head,count)
  327. Xregister CMD *head;
  328. Xint count;
  329. X{
  330. X    register CMD *cur = head;
  331. X    register CMD **loc;
  332. X    register int i;
  333. X    register int min = 32767;
  334. X    register int max = -32768;
  335. X    int origcount = count;
  336. X    double value;        /* or your money back! */
  337. X    short changed;        /* so triple your money back! */
  338. X
  339. X    while (count--) {
  340. X    i = (int)str_gnum(cur->c_short);
  341. X    value = (double)i;
  342. X    if (value != cur->c_short->str_u.str_nval)
  343. X        return;        /* fractional values--just forget it */
  344. X    changed = i;
  345. X    if (changed != i)
  346. X        return;        /* too big for a short */
  347. X    if (cur->c_slen == O_LE)
  348. X        i++;
  349. X    else if (cur->c_slen == O_GE)    /* we only do < or > here */
  350. X        i--;
  351. X    if (i < min)
  352. X        min = i;
  353. X    if (i > max)
  354. X        max = i;
  355. X    cur = cur->c_next;
  356. X    }
  357. X    count = origcount;
  358. X    if (max - min > count * 2 + 10)        /* too sparse? */
  359. X    return;
  360. X
  361. X    /* now make a new head in the exact same spot */
  362. X    New(104,cur, 1, CMD);
  363. X#ifdef STRUCTCOPY
  364. X    *cur = *head;
  365. X#else
  366. X    Copy(head,cur,1,CMD);
  367. X#endif
  368. X    Zero(head,1,CMD);
  369. X    head->c_type = C_NSWITCH;
  370. X    head->c_next = cur;        /* insert new cmd at front of list */
  371. X    head->c_stab = cur->c_stab;
  372. X
  373. X    Newz(105,loc, max - min + 3, CMD*);
  374. X    loc++;
  375. X    max -= min;
  376. X    max++;
  377. X    while (count--) {
  378. X    i = (int)str_gnum(cur->c_short);
  379. X    i -= min;
  380. X    switch(cur->c_slen) {
  381. X    case O_LE:
  382. X        i++;
  383. X    case O_LT:
  384. X        for (i--; i >= -1; i--)
  385. X        if (!loc[i])
  386. X            loc[i] = cur;
  387. X        break;
  388. X    case O_GE:
  389. X        i--;
  390. X    case O_GT:
  391. X        for (i++; i <= max; i++)
  392. X        if (!loc[i])
  393. X            loc[i] = cur;
  394. X        break;
  395. X    case O_EQ:
  396. X        if (!loc[i])
  397. X        loc[i] = cur;
  398. X        break;
  399. X    }
  400. X    cur = cur->c_next;
  401. X    }
  402. X    loc--;
  403. X    min--;
  404. X    max++;
  405. X    for (i = 0; i <= max; i++)
  406. X    if (!loc[i])
  407. X        loc[i] = cur;
  408. X    head->ucmd.scmd.sc_offset = min;
  409. X    head->ucmd.scmd.sc_max = max;
  410. X    head->ucmd.scmd.sc_next = loc;
  411. X}
  412. X
  413. XCMD *
  414. Xappend_line(head,tail)
  415. Xregister CMD *head;
  416. Xregister CMD *tail;
  417. X{
  418. X    if (tail == Nullcmd)
  419. X    return head;
  420. X    if (!tail->c_head)            /* make sure tail is well formed */
  421. X    tail->c_head = tail;
  422. X    if (head != Nullcmd) {
  423. X    tail = tail->c_head;        /* get to start of tail list */
  424. X    if (!head->c_head)
  425. X        head->c_head = head;    /* start a new head list */
  426. X    while (head->c_next) {
  427. X        head->c_next->c_head = head->c_head;
  428. X        head = head->c_next;    /* get to end of head list */
  429. X    }
  430. X    head->c_next = tail;        /* link to end of old list */
  431. X    tail->c_head = head->c_head;    /* propagate head pointer */
  432. X    }
  433. X    while (tail->c_next) {
  434. X    tail->c_next->c_head = tail->c_head;
  435. X    tail = tail->c_next;
  436. X    }
  437. X    return tail;
  438. X}
  439. X
  440. XCMD *
  441. Xdodb(cur)
  442. XCMD *cur;
  443. X{
  444. X    register CMD *cmd;
  445. X    register CMD *head = cur->c_head;
  446. X    STR *str;
  447. X
  448. X    if (!head)
  449. X    head = cur;
  450. X    if (!head->c_line)
  451. X    return cur;
  452. X    str = afetch(stab_xarray(curcmd->c_filestab),(int)head->c_line,FALSE);
  453. X    if (str == &str_undef || str->str_nok)
  454. X    return cur;
  455. X    str->str_u.str_nval = (double)head->c_line;
  456. X    str->str_nok = 1;
  457. X    Newz(106,cmd,1,CMD);
  458. X    str_magic(str, curcmd->c_filestab, 0, Nullch, 0);
  459. X    str->str_magic->str_u.str_cmd = cmd;
  460. X    cmd->c_type = C_EXPR;
  461. X    cmd->ucmd.acmd.ac_stab = Nullstab;
  462. X    cmd->ucmd.acmd.ac_expr = Nullarg;
  463. X    cmd->c_expr = make_op(O_SUBR, 2,
  464. X    stab2arg(A_WORD,DBstab),
  465. X    Nullarg,
  466. X    Nullarg);
  467. X    cmd->c_flags |= CF_COND|CF_DBSUB|CFT_D0;
  468. X    cmd->c_line = head->c_line;
  469. X    cmd->c_label = head->c_label;
  470. X    cmd->c_filestab = curcmd->c_filestab;
  471. X    cmd->c_stash = curstash;
  472. X    return append_line(cmd, cur);
  473. X}
  474. X
  475. XCMD *
  476. Xmake_acmd(type,stab,cond,arg)
  477. Xint type;
  478. XSTAB *stab;
  479. XARG *cond;
  480. XARG *arg;
  481. X{
  482. X    register CMD *cmd;
  483. X
  484. X    Newz(107,cmd,1,CMD);
  485. X    cmd->c_type = type;
  486. X    cmd->ucmd.acmd.ac_stab = stab;
  487. X    cmd->ucmd.acmd.ac_expr = arg;
  488. X    cmd->c_expr = cond;
  489. X    if (cond)
  490. X    cmd->c_flags |= CF_COND;
  491. X    if (cmdline == NOLINE)
  492. X    cmd->c_line = curcmd->c_line;
  493. X    else {
  494. X    cmd->c_line = cmdline;
  495. X    cmdline = NOLINE;
  496. X    }
  497. X    cmd->c_filestab = curcmd->c_filestab;
  498. X    cmd->c_stash = curstash;
  499. X    if (perldb)
  500. X    cmd = dodb(cmd);
  501. X    return cmd;
  502. X}
  503. X
  504. XCMD *
  505. Xmake_ccmd(type,arg,cblock)
  506. Xint type;
  507. XARG *arg;
  508. Xstruct compcmd cblock;
  509. X{
  510. X    register CMD *cmd;
  511. X
  512. X    Newz(108,cmd, 1, CMD);
  513. X    cmd->c_type = type;
  514. X    cmd->c_expr = arg;
  515. X    cmd->ucmd.ccmd.cc_true = cblock.comp_true;
  516. X    cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
  517. X    if (arg)
  518. X    cmd->c_flags |= CF_COND;
  519. X    if (cmdline == NOLINE)
  520. X    cmd->c_line = curcmd->c_line;
  521. X    else {
  522. X    cmd->c_line = cmdline;
  523. X    cmdline = NOLINE;
  524. X    }
  525. X    cmd->c_filestab = curcmd->c_filestab;
  526. X    cmd->c_stash = curstash;
  527. X    if (perldb)
  528. X    cmd = dodb(cmd);
  529. X    return cmd;
  530. X}
  531. X
  532. XCMD *
  533. Xmake_icmd(type,arg,cblock)
  534. Xint type;
  535. XARG *arg;
  536. Xstruct compcmd cblock;
  537. X{
  538. X    register CMD *cmd;
  539. X    register CMD *alt;
  540. X    register CMD *cur;
  541. X    register CMD *head;
  542. X    struct compcmd ncblock;
  543. X
  544. X    Newz(109,cmd, 1, CMD);
  545. X    head = cmd;
  546. X    cmd->c_type = type;
  547. X    cmd->c_expr = arg;
  548. X    cmd->ucmd.ccmd.cc_true = cblock.comp_true;
  549. X    cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
  550. X    if (arg)
  551. X    cmd->c_flags |= CF_COND;
  552. X    if (cmdline == NOLINE)
  553. X    cmd->c_line = curcmd->c_line;
  554. X    else {
  555. X    cmd->c_line = cmdline;
  556. X    cmdline = NOLINE;
  557. X    }
  558. X    cmd->c_filestab = curcmd->c_filestab;
  559. X    cmd->c_stash = curstash;
  560. X    cur = cmd;
  561. X    alt = cblock.comp_alt;
  562. X    while (alt && alt->c_type == C_ELSIF) {
  563. X    cur = alt;
  564. X    alt = alt->ucmd.ccmd.cc_alt;
  565. X    }
  566. X    if (alt) {            /* a real life ELSE at the end? */
  567. X    ncblock.comp_true = alt;
  568. X    ncblock.comp_alt = Nullcmd;
  569. X    alt = append_line(cur,make_ccmd(C_ELSE,Nullarg,ncblock));
  570. X    cur->ucmd.ccmd.cc_alt = alt;
  571. X    }
  572. X    else
  573. X    alt = cur;        /* no ELSE, so cur is proxy ELSE */
  574. X
  575. X    cur = cmd;
  576. X    while (cmd) {        /* now point everyone at the ELSE */
  577. X    cur = cmd;
  578. X    cmd = cur->ucmd.ccmd.cc_alt;
  579. X    cur->c_head = head;
  580. X    if (cur->c_type == C_ELSIF)
  581. X        cur->c_type = C_IF;
  582. X    if (cur->c_type == C_IF)
  583. X        cur->ucmd.ccmd.cc_alt = alt;
  584. X    if (cur == alt)
  585. X        break;
  586. X    cur->c_next = cmd;
  587. X    }
  588. X    if (perldb)
  589. X    cur = dodb(cur);
  590. X    return cur;
  591. X}
  592. X
  593. Xvoid
  594. Xopt_arg(cmd,fliporflop,acmd)
  595. Xregister CMD *cmd;
  596. Xint fliporflop;
  597. Xint acmd;
  598. X{
  599. X    register ARG *arg;
  600. X    int opt = CFT_EVAL;
  601. X    int sure = 0;
  602. X    ARG *arg2;
  603. X    int context = 0;    /* 0 = normal, 1 = before &&, 2 = before || */
  604. X    int flp = fliporflop;
  605. X
  606. X    if (!cmd)
  607. X    return;
  608. X    if (!(arg = cmd->c_expr)) {
  609. X    cmd->c_flags &= ~CF_COND;
  610. X    return;
  611. X    }
  612. X
  613. X    /* Can we turn && and || into if and unless? */
  614. X
  615. X    if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM) &&
  616. X      (arg->arg_type == O_AND || arg->arg_type == O_OR) ) {
  617. X    dehoist(arg,1);
  618. X    arg[2].arg_type &= A_MASK;    /* don't suppress eval */
  619. X    dehoist(arg,2);
  620. X    cmd->ucmd.acmd.ac_expr = arg[2].arg_ptr.arg_arg;
  621. X    cmd->c_expr = arg[1].arg_ptr.arg_arg;
  622. X    if (arg->arg_type == O_OR)
  623. X        cmd->c_flags ^= CF_INVERT;        /* || is like unless */
  624. X    arg->arg_len = 0;
  625. X    free_arg(arg);
  626. X    arg = cmd->c_expr;
  627. X    }
  628. X
  629. X    /* Turn "if (!expr)" into "unless (expr)" */
  630. X
  631. X    if (!(cmd->c_flags & CF_TERM)) {        /* unless return value wanted */
  632. X    while (arg->arg_type == O_NOT) {
  633. X        dehoist(arg,1);
  634. X        cmd->c_flags ^= CF_INVERT;        /* flip sense of cmd */
  635. X        cmd->c_expr = arg[1].arg_ptr.arg_arg; /* hoist the rest of expr */
  636. X        free_arg(arg);
  637. X        arg = cmd->c_expr;            /* here we go again */
  638. X    }
  639. X    }
  640. X
  641. X    if (!arg->arg_len) {        /* sanity check */
  642. X    cmd->c_flags |= opt;
  643. X    return;
  644. X    }
  645. X
  646. X    /* for "cond .. cond" we set up for the initial check */
  647. X
  648. X    if (arg->arg_type == O_FLIP)
  649. X    context |= 4;
  650. X
  651. X    /* for "cond && expr" and "cond || expr" we can ignore expr, sort of */
  652. X
  653. X  morecontext:
  654. X    if (arg->arg_type == O_AND)
  655. X    context |= 1;
  656. X    else if (arg->arg_type == O_OR)
  657. X    context |= 2;
  658. X    if (context && (arg[flp].arg_type & A_MASK) == A_EXPR) {
  659. X    arg = arg[flp].arg_ptr.arg_arg;
  660. X    flp = 1;
  661. X    if (arg->arg_type == O_AND || arg->arg_type == O_OR)
  662. X        goto morecontext;
  663. X    }
  664. X    if ((context & 3) == 3)
  665. X    return;
  666. X
  667. X    if (arg[flp].arg_flags & (AF_PRE|AF_POST)) {
  668. X    cmd->c_flags |= opt;
  669. X    if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM)
  670. X      && cmd->c_expr->arg_type == O_ITEM) {
  671. X        arg[flp].arg_flags &= ~AF_POST;    /* prefer ++$foo to $foo++ */
  672. X        arg[flp].arg_flags |= AF_PRE;    /*  if value not wanted */
  673. X    }
  674. X    return;                /* side effect, can't optimize */
  675. X    }
  676. X
  677. X    if (arg->arg_type == O_ITEM || arg->arg_type == O_FLIP ||
  678. X      arg->arg_type == O_AND || arg->arg_type == O_OR) {
  679. X    if ((arg[flp].arg_type & A_MASK) == A_SINGLE) {
  680. X        opt = (str_true(arg[flp].arg_ptr.arg_str) ? CFT_TRUE : CFT_FALSE);
  681. X        cmd->c_short = str_smake(arg[flp].arg_ptr.arg_str);
  682. X        goto literal;
  683. X    }
  684. X    else if ((arg[flp].arg_type & A_MASK) == A_STAB ||
  685. X      (arg[flp].arg_type & A_MASK) == A_LVAL) {
  686. X        cmd->c_stab  = arg[flp].arg_ptr.arg_stab;
  687. X        if (!context)
  688. X        arg[flp].arg_ptr.arg_stab = Nullstab;
  689. X        opt = CFT_REG;
  690. X      literal:
  691. X        if (!context) {    /* no && or ||? */
  692. X        arg_free(arg);
  693. X        cmd->c_expr = Nullarg;
  694. X        }
  695. X        if (!(context & 1))
  696. X        cmd->c_flags |= CF_EQSURE;
  697. X        if (!(context & 2))
  698. X        cmd->c_flags |= CF_NESURE;
  699. X    }
  700. X    }
  701. X    else if (arg->arg_type == O_MATCH || arg->arg_type == O_SUBST ||
  702. X         arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST) {
  703. X    if ((arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) &&
  704. X        (arg[2].arg_type & A_MASK) == A_SPAT &&
  705. X        arg[2].arg_ptr.arg_spat->spat_short ) {
  706. X        cmd->c_stab  = arg[1].arg_ptr.arg_stab;
  707. X        cmd->c_short = str_smake(arg[2].arg_ptr.arg_spat->spat_short);
  708. X        cmd->c_slen  = arg[2].arg_ptr.arg_spat->spat_slen;
  709. X        if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ALL &&
  710. X        !(arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ONCE) &&
  711. X        (arg->arg_type == O_MATCH || arg->arg_type == O_NMATCH) )
  712. X        sure |= CF_EQSURE;        /* (SUBST must be forced even */
  713. X                        /* if we know it will work.) */
  714. X        if (arg->arg_type != O_SUBST) {
  715. X        arg[2].arg_ptr.arg_spat->spat_short = Nullstr;
  716. X        arg[2].arg_ptr.arg_spat->spat_slen = 0; /* only one chk */
  717. X        }
  718. X        sure |= CF_NESURE;        /* normally only sure if it fails */
  719. X        if (arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST)
  720. X        cmd->c_flags |= CF_FIRSTNEG;
  721. X        if (context & 1) {        /* only sure if thing is false */
  722. X        if (cmd->c_flags & CF_FIRSTNEG)
  723. X            sure &= ~CF_NESURE;
  724. X        else
  725. X            sure &= ~CF_EQSURE;
  726. X        }
  727. X        else if (context & 2) {    /* only sure if thing is true */
  728. X        if (cmd->c_flags & CF_FIRSTNEG)
  729. X            sure &= ~CF_EQSURE;
  730. X        else
  731. X            sure &= ~CF_NESURE;
  732. X        }
  733. X        if (sure & (CF_EQSURE|CF_NESURE)) {    /* if we know anything*/
  734. X        if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_SCANFIRST)
  735. X            opt = CFT_SCAN;
  736. X        else
  737. X            opt = CFT_ANCHOR;
  738. X        if (sure == (CF_EQSURE|CF_NESURE)    /* really sure? */
  739. X            && arg->arg_type == O_MATCH
  740. X            && context & 4
  741. X            && fliporflop == 1) {
  742. X            spat_free(arg[2].arg_ptr.arg_spat);
  743. X            arg[2].arg_ptr.arg_spat = Nullspat;    /* don't do twice */
  744. X        }
  745. X        else
  746. X            cmd->c_spat = arg[2].arg_ptr.arg_spat;
  747. X        cmd->c_flags |= sure;
  748. X        }
  749. X    }
  750. X    }
  751. X    else if (arg->arg_type == O_SEQ || arg->arg_type == O_SNE ||
  752. X         arg->arg_type == O_SLT || arg->arg_type == O_SGT) {
  753. X    if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) {
  754. X        if (arg[2].arg_type == A_SINGLE) {
  755. X        char *junk = str_get(arg[2].arg_ptr.arg_str);
  756. X
  757. X        cmd->c_stab  = arg[1].arg_ptr.arg_stab;
  758. X        cmd->c_short = str_smake(arg[2].arg_ptr.arg_str);
  759. X        cmd->c_slen  = cmd->c_short->str_cur+1;
  760. X        switch (arg->arg_type) {
  761. X        case O_SLT: case O_SGT:
  762. X            sure |= CF_EQSURE;
  763. X            cmd->c_flags |= CF_FIRSTNEG;
  764. X            break;
  765. X        case O_SNE:
  766. X            cmd->c_flags |= CF_FIRSTNEG;
  767. X            /* FALL THROUGH */
  768. X        case O_SEQ:
  769. X            sure |= CF_NESURE|CF_EQSURE;
  770. X            break;
  771. X        }
  772. X        if (context & 1) {    /* only sure if thing is false */
  773. X            if (cmd->c_flags & CF_FIRSTNEG)
  774. X            sure &= ~CF_NESURE;
  775. X            else
  776. X            sure &= ~CF_EQSURE;
  777. X        }
  778. X        else if (context & 2) { /* only sure if thing is true */
  779. X            if (cmd->c_flags & CF_FIRSTNEG)
  780. X            sure &= ~CF_EQSURE;
  781. X            else
  782. X            sure &= ~CF_NESURE;
  783. X        }
  784. X        if (sure & (CF_EQSURE|CF_NESURE)) {
  785. X            opt = CFT_STROP;
  786. X            cmd->c_flags |= sure;
  787. X        }
  788. X        }
  789. X    }
  790. X    }
  791. X    else if (arg->arg_type == O_EQ || arg->arg_type == O_NE ||
  792. X         arg->arg_type == O_LE || arg->arg_type == O_GE ||
  793. X         arg->arg_type == O_LT || arg->arg_type == O_GT) {
  794. X    if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) {
  795. X        if (arg[2].arg_type == A_SINGLE) {
  796. X        cmd->c_stab  = arg[1].arg_ptr.arg_stab;
  797. X        if (dowarn) {
  798. X            STR *str = arg[2].arg_ptr.arg_str;
  799. X
  800. X            if ((!str->str_nok && !looks_like_number(str)))
  801. X            warn("Possible use of == on string value");
  802. X        }
  803. X        cmd->c_short = str_nmake(str_gnum(arg[2].arg_ptr.arg_str));
  804. X        cmd->c_slen = arg->arg_type;
  805. X        sure |= CF_NESURE|CF_EQSURE;
  806. X        if (context & 1) {    /* only sure if thing is false */
  807. X            sure &= ~CF_EQSURE;
  808. X        }
  809. X        else if (context & 2) { /* only sure if thing is true */
  810. X            sure &= ~CF_NESURE;
  811. X        }
  812. X        if (sure & (CF_EQSURE|CF_NESURE)) {
  813. X            opt = CFT_NUMOP;
  814. X            cmd->c_flags |= sure;
  815. X        }
  816. X        }
  817. X    }
  818. X    }
  819. X    else if (arg->arg_type == O_ASSIGN &&
  820. X         (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) &&
  821. X         arg[1].arg_ptr.arg_stab == defstab &&
  822. X         arg[2].arg_type == A_EXPR ) {
  823. X    arg2 = arg[2].arg_ptr.arg_arg;
  824. X    if (arg2->arg_type == O_ITEM && arg2[1].arg_type == A_READ) {
  825. X        opt = CFT_GETS;
  826. X        cmd->c_stab = arg2[1].arg_ptr.arg_stab;
  827. X        if (!(stab_io(arg2[1].arg_ptr.arg_stab)->flags & IOF_ARGV)) {
  828. X        free_arg(arg2);
  829. X        arg[2].arg_ptr.arg_arg = Nullarg;
  830. X        free_arg(arg);
  831. X        cmd->c_expr = Nullarg;
  832. X        }
  833. X    }
  834. X    }
  835. X    else if (arg->arg_type == O_CHOP &&
  836. X         (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) ) {
  837. X    opt = CFT_CHOP;
  838. X    cmd->c_stab = arg[1].arg_ptr.arg_stab;
  839. X    free_arg(arg);
  840. X    cmd->c_expr = Nullarg;
  841. X    }
  842. X    if (context & 4)
  843. X    opt |= CF_FLIP;
  844. X    cmd->c_flags |= opt;
  845. X
  846. X    if (cmd->c_flags & CF_FLIP) {
  847. X    if (fliporflop == 1) {
  848. X        arg = cmd->c_expr;    /* get back to O_FLIP arg */
  849. X        New(110,arg[3].arg_ptr.arg_cmd, 1, CMD);
  850. X        Copy(cmd, arg[3].arg_ptr.arg_cmd, 1, CMD);
  851. X        New(111,arg[4].arg_ptr.arg_cmd,1,CMD);
  852. X        Copy(cmd, arg[4].arg_ptr.arg_cmd, 1, CMD);
  853. X        opt_arg(arg[4].arg_ptr.arg_cmd,2,acmd);
  854. X        arg->arg_len = 2;        /* this is a lie */
  855. X    }
  856. X    else {
  857. X        if ((opt & CF_OPTIMIZE) == CFT_EVAL)
  858. X        cmd->c_flags = (cmd->c_flags & ~CF_OPTIMIZE) | CFT_UNFLIP;
  859. X    }
  860. X    }
  861. X}
  862. X
  863. XCMD *
  864. Xadd_label(lbl,cmd)
  865. Xchar *lbl;
  866. Xregister CMD *cmd;
  867. X{
  868. X    if (cmd)
  869. X    cmd->c_label = lbl;
  870. X    return cmd;
  871. X}
  872. X
  873. XCMD *
  874. Xaddcond(cmd, arg)
  875. Xregister CMD *cmd;
  876. Xregister ARG *arg;
  877. X{
  878. X    cmd->c_expr = arg;
  879. X    cmd->c_flags |= CF_COND;
  880. X    return cmd;
  881. X}
  882. X
  883. XCMD *
  884. Xaddloop(cmd, arg)
  885. Xregister CMD *cmd;
  886. Xregister ARG *arg;
  887. X{
  888. X    void while_io();
  889. X
  890. X    cmd->c_expr = arg;
  891. X    cmd->c_flags |= CF_COND|CF_LOOP;
  892. X
  893. X    if (!(cmd->c_flags & CF_INVERT))
  894. X    while_io(cmd);        /* add $_ =, if necessary */
  895. X
  896. X    if (cmd->c_type == C_BLOCK)
  897. X    cmd->c_flags &= ~CF_COND;
  898. X    else {
  899. X    arg = cmd->ucmd.acmd.ac_expr;
  900. X    if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD)
  901. X        cmd->c_flags &= ~CF_COND;  /* "do {} while" happens at least once */
  902. X    if (arg && (arg->arg_flags & AF_DEPR) &&
  903. X      (arg->arg_type == O_SUBR || arg->arg_type == O_DBSUBR) )
  904. X        cmd->c_flags &= ~CF_COND;  /* likewise for "do subr() while" */
  905. X    }
  906. X    return cmd;
  907. X}
  908. X
  909. XCMD *
  910. Xinvert(cmd)
  911. XCMD *cmd;
  912. X{
  913. X    register CMD *targ = cmd;
  914. X    if (targ->c_head)
  915. X    targ = targ->c_head;
  916. X    if (targ->c_flags & CF_DBSUB)
  917. X    targ = targ->c_next;
  918. X    targ->c_flags ^= CF_INVERT;
  919. X    return cmd;
  920. X}
  921. X
  922. Xyyerror(s)
  923. Xchar *s;
  924. X{
  925. X    char tmpbuf[258];
  926. X    char tmp2buf[258];
  927. X    char *tname = tmpbuf;
  928. X
  929. X    if (bufptr > oldoldbufptr && bufptr - oldoldbufptr < 200 &&
  930. X      oldoldbufptr != oldbufptr && oldbufptr != bufptr) {
  931. X    while (isspace(*oldoldbufptr))
  932. X        oldoldbufptr++;
  933. X    strncpy(tmp2buf, oldoldbufptr, bufptr - oldoldbufptr);
  934. X    tmp2buf[bufptr - oldoldbufptr] = '\0';
  935. X    sprintf(tname,"next 2 tokens \"%s\"",tmp2buf);
  936. X    }
  937. X    else if (bufptr > oldbufptr && bufptr - oldbufptr < 200 &&
  938. X      oldbufptr != bufptr) {
  939. X    while (isspace(*oldbufptr))
  940. X        oldbufptr++;
  941. X    strncpy(tmp2buf, oldbufptr, bufptr - oldbufptr);
  942. X    tmp2buf[bufptr - oldbufptr] = '\0';
  943. X    sprintf(tname,"next token \"%s\"",tmp2buf);
  944. X    }
  945. X    else if (yychar > 256)
  946. X    tname = "next token ???";
  947. X    else if (!yychar)
  948. X    (void)strcpy(tname,"at EOF");
  949. X    else if (yychar < 32)
  950. X    (void)sprintf(tname,"next char ^%c",yychar+64);
  951. X    else if (yychar == 127)
  952. X    (void)strcpy(tname,"at EOF");
  953. X    else
  954. X    (void)sprintf(tname,"next char %c",yychar);
  955. X    (void)sprintf(buf, "%s in file %s at line %d, %s\n",
  956. X      s,stab_val(curcmd->c_filestab)->str_ptr,curcmd->c_line,tname);
  957. X    if (curcmd->c_line == multi_end && multi_start < multi_end)
  958. X    sprintf(buf+strlen(buf),
  959. X      "  (Might be a runaway multi-line %c%c string starting on line %d)\n",
  960. X      multi_open,multi_close,multi_start);
  961. X    if (in_eval)
  962. X    str_cat(stab_val(stabent("@",TRUE)),buf);
  963. X    else
  964. X    fputs(buf,stderr);
  965. X    if (++error_count >= 10)
  966. X    fatal("%s has too many errors.\n",
  967. X    stab_val(curcmd->c_filestab)->str_ptr);
  968. X}
  969. X
  970. Xvoid
  971. Xwhile_io(cmd)
  972. Xregister CMD *cmd;
  973. X{
  974. X    register ARG *arg = cmd->c_expr;
  975. X    STAB *asgnstab;
  976. X
  977. X    /* hoist "while (<channel>)" up into command block */
  978. X
  979. X    if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_READ) {
  980. X    cmd->c_flags &= ~CF_OPTIMIZE;    /* clear optimization type */
  981. X    cmd->c_flags |= CFT_GETS;    /* and set it to do the input */
  982. X    cmd->c_stab = arg[1].arg_ptr.arg_stab;
  983. X    if (stab_io(arg[1].arg_ptr.arg_stab)->flags & IOF_ARGV) {
  984. X        cmd->c_expr = l(make_op(O_ASSIGN, 2,    /* fake up "$_ =" */
  985. X           stab2arg(A_LVAL,defstab), arg, Nullarg));
  986. X    }
  987. X    else {
  988. X        free_arg(arg);
  989. X        cmd->c_expr = Nullarg;
  990. X    }
  991. X    }
  992. X    else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_INDREAD) {
  993. X    cmd->c_flags &= ~CF_OPTIMIZE;    /* clear optimization type */
  994. X    cmd->c_flags |= CFT_INDGETS;    /* and set it to do the input */
  995. X    cmd->c_stab = arg[1].arg_ptr.arg_stab;
  996. X    free_arg(arg);
  997. X    cmd->c_expr = Nullarg;
  998. X    }
  999. X    else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_GLOB) {
  1000. X    if ((cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY)
  1001. X        asgnstab = cmd->c_stab;
  1002. X    else
  1003. X        asgnstab = defstab;
  1004. X    cmd->c_expr = l(make_op(O_ASSIGN, 2,    /* fake up "$foo =" */
  1005. X       stab2arg(A_LVAL,asgnstab), arg, Nullarg));
  1006. X    cmd->c_flags &= ~CF_OPTIMIZE;    /* clear optimization type */
  1007. X    }
  1008. X}
  1009. X
  1010. XCMD *
  1011. Xwopt(cmd)
  1012. Xregister CMD *cmd;
  1013. X{
  1014. X    register CMD *tail;
  1015. X    CMD *newtail;
  1016. X    register int i;
  1017. X
  1018. X    if (cmd->c_expr && (cmd->c_flags & CF_OPTIMIZE) == CFT_FALSE)
  1019. X    opt_arg(cmd,1, cmd->c_type == C_EXPR);
  1020. X
  1021. X    while_io(cmd);        /* add $_ =, if necessary */
  1022. X
  1023. X    /* First find the end of the true list */
  1024. X
  1025. X    tail = cmd->ucmd.ccmd.cc_true;
  1026. X    if (tail == Nullcmd)
  1027. X    return cmd;
  1028. X    New(112,newtail, 1, CMD);    /* guaranteed continue */
  1029. X    for (;;) {
  1030. X    /* optimize "next" to point directly to continue block */
  1031. X    if (tail->c_type == C_EXPR &&
  1032. X        tail->ucmd.acmd.ac_expr &&
  1033. X        tail->ucmd.acmd.ac_expr->arg_type == O_NEXT &&
  1034. X        (tail->ucmd.acmd.ac_expr->arg_len == 0 ||
  1035. X         (cmd->c_label &&
  1036. X          strEQ(cmd->c_label,
  1037. X            tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
  1038. X    {
  1039. X        arg_free(tail->ucmd.acmd.ac_expr);
  1040. X        tail->ucmd.acmd.ac_expr = Nullarg;
  1041. X        tail->c_type = C_NEXT;
  1042. X        if (cmd->ucmd.ccmd.cc_alt != Nullcmd)
  1043. X        tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt;
  1044. X        else
  1045. X        tail->ucmd.ccmd.cc_alt = newtail;
  1046. X        tail->ucmd.ccmd.cc_true = Nullcmd;
  1047. X    }
  1048. X    else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) {
  1049. X        if (cmd->ucmd.ccmd.cc_alt != Nullcmd)
  1050. X        tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt;
  1051. X        else
  1052. X        tail->ucmd.ccmd.cc_alt = newtail;
  1053. X    }
  1054. X    else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) {
  1055. X        if (cmd->ucmd.ccmd.cc_alt != Nullcmd) {
  1056. X        for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
  1057. X            if (!tail->ucmd.scmd.sc_next[i])
  1058. X            tail->ucmd.scmd.sc_next[i] = cmd->ucmd.ccmd.cc_alt;
  1059. X        }
  1060. X        else {
  1061. X        for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
  1062. X            if (!tail->ucmd.scmd.sc_next[i])
  1063. X            tail->ucmd.scmd.sc_next[i] = newtail;
  1064. X        }
  1065. X    }
  1066. X
  1067. X    if (!tail->c_next)
  1068. X        break;
  1069. X    tail = tail->c_next;
  1070. X    }
  1071. X
  1072. X    /* if there's a continue block, link it to true block and find end */
  1073. X
  1074. X    if (cmd->ucmd.ccmd.cc_alt != Nullcmd) {
  1075. X    tail->c_next = cmd->ucmd.ccmd.cc_alt;
  1076. X    tail = tail->c_next;
  1077. X    for (;;) {
  1078. X        /* optimize "next" to point directly to continue block */
  1079. X        if (tail->c_type == C_EXPR &&
  1080. X        tail->ucmd.acmd.ac_expr &&
  1081. X        tail->ucmd.acmd.ac_expr->arg_type == O_NEXT &&
  1082. X        (tail->ucmd.acmd.ac_expr->arg_len == 0 ||
  1083. X         (cmd->c_label &&
  1084. X          strEQ(cmd->c_label,
  1085. X            tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
  1086. X        {
  1087. X        arg_free(tail->ucmd.acmd.ac_expr);
  1088. X        tail->ucmd.acmd.ac_expr = Nullarg;
  1089. X        tail->c_type = C_NEXT;
  1090. X        tail->ucmd.ccmd.cc_alt = newtail;
  1091. X        tail->ucmd.ccmd.cc_true = Nullcmd;
  1092. X        }
  1093. X        else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) {
  1094. X        tail->ucmd.ccmd.cc_alt = newtail;
  1095. X        }
  1096. X        else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) {
  1097. X        for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
  1098. X            if (!tail->ucmd.scmd.sc_next[i])
  1099. X            tail->ucmd.scmd.sc_next[i] = newtail;
  1100. X        }
  1101. X
  1102. X        if (!tail->c_next)
  1103. X        break;
  1104. X        tail = tail->c_next;
  1105. X    }
  1106. X    for ( ; tail->c_next; tail = tail->c_next) ;
  1107. X    }
  1108. X
  1109. X    /* Here's the real trick: link the end of the list back to the beginning,
  1110. X     * inserting a "last" block to break out of the loop.  This saves one or
  1111. X     * two procedure calls every time through the loop, because of how cmd_exec
  1112. X     * does tail recursion.
  1113. X     */
  1114. X
  1115. X    tail->c_next = newtail;
  1116. X    tail = newtail;
  1117. X    if (!cmd->ucmd.ccmd.cc_alt)
  1118. X    cmd->ucmd.ccmd.cc_alt = tail;    /* every loop has a continue now */
  1119. X
  1120. X#ifndef lint
  1121. X    (void)bcopy((char *)cmd, (char *)tail, sizeof(CMD));
  1122. X#endif
  1123. X    tail->c_type = C_EXPR;
  1124. X    tail->c_flags ^= CF_INVERT;        /* turn into "last unless" */
  1125. X    tail->c_next = tail->ucmd.ccmd.cc_true;    /* loop directly back to top */
  1126. X    tail->ucmd.acmd.ac_expr = make_op(O_LAST,0,Nullarg,Nullarg,Nullarg);
  1127. X    tail->ucmd.acmd.ac_stab = Nullstab;
  1128. X    return cmd;
  1129. X}
  1130. X
  1131. XCMD *
  1132. Xover(eachstab,cmd)
  1133. XSTAB *eachstab;
  1134. Xregister CMD *cmd;
  1135. X{
  1136. X    /* hoist "for $foo (@bar)" up into command block */
  1137. X
  1138. X    cmd->c_flags &= ~CF_OPTIMIZE;    /* clear optimization type */
  1139. X    cmd->c_flags |= CFT_ARRAY;        /* and set it to do the iteration */
  1140. X    cmd->c_stab = eachstab;
  1141. X    cmd->c_short = str_new(0);        /* just to save a field in struct cmd */
  1142. X    cmd->c_short->str_u.str_useful = -1;
  1143. X
  1144. X    return cmd;
  1145. X}
  1146. X
  1147. Xcmd_free(cmd)
  1148. Xregister CMD *cmd;
  1149. X{
  1150. X    register CMD *tofree;
  1151. X    register CMD *head = cmd;
  1152. X
  1153. X    while (cmd) {
  1154. X    if (cmd->c_type != C_WHILE) {    /* WHILE block is duplicated */
  1155. X        if (cmd->c_label) {
  1156. X        Safefree(cmd->c_label);
  1157. X        cmd->c_label = Nullch;
  1158. X        }
  1159. X        if (cmd->c_short) {
  1160. X        str_free(cmd->c_short);
  1161. X        cmd->c_short = Nullstr;
  1162. X        }
  1163. X        if (cmd->c_expr) {
  1164. X        arg_free(cmd->c_expr);
  1165. X        cmd->c_expr = Nullarg;
  1166. X        }
  1167. X    }
  1168. X    switch (cmd->c_type) {
  1169. X    case C_WHILE:
  1170. X    case C_BLOCK:
  1171. X    case C_ELSE:
  1172. X    case C_IF:
  1173. X        if (cmd->ucmd.ccmd.cc_true) {
  1174. X        cmd_free(cmd->ucmd.ccmd.cc_true);
  1175. X        cmd->ucmd.ccmd.cc_true = Nullcmd;
  1176. X        }
  1177. X        break;
  1178. X    case C_EXPR:
  1179. X        if (cmd->ucmd.acmd.ac_expr) {
  1180. X        arg_free(cmd->ucmd.acmd.ac_expr);
  1181. X        cmd->ucmd.acmd.ac_expr = Nullarg;
  1182. X        }
  1183. X        break;
  1184. X    }
  1185. X    tofree = cmd;
  1186. X    cmd = cmd->c_next;
  1187. X    if (tofree != head)        /* to get Saber to shut up */
  1188. X        Safefree(tofree);
  1189. X    if (cmd && cmd == head)        /* reached end of while loop */
  1190. X        break;
  1191. X    }
  1192. X    Safefree(head);
  1193. X}
  1194. X
  1195. Xarg_free(arg)
  1196. Xregister ARG *arg;
  1197. X{
  1198. X    register int i;
  1199. X
  1200. X    for (i = 1; i <= arg->arg_len; i++) {
  1201. X    switch (arg[i].arg_type & A_MASK) {
  1202. X    case A_NULL:
  1203. X        if (arg->arg_type == O_TRANS) {
  1204. X        Safefree(arg[i].arg_ptr.arg_cval);
  1205. X        arg[i].arg_ptr.arg_cval = Nullch;
  1206. X        }
  1207. X        break;
  1208. X    case A_LEXPR:
  1209. X        if (arg->arg_type == O_AASSIGN &&
  1210. X          arg[i].arg_ptr.arg_arg->arg_type == O_LARRAY) {
  1211. X        char *name = 
  1212. X          stab_name(arg[i].arg_ptr.arg_arg[1].arg_ptr.arg_stab);
  1213. X
  1214. X        if (strnEQ("_GEN_",name, 5))    /* array for foreach */
  1215. X            hdelete(defstash,name,strlen(name));
  1216. X        }
  1217. X        /* FALL THROUGH */
  1218. X    case A_EXPR:
  1219. X        arg_free(arg[i].arg_ptr.arg_arg);
  1220. X        arg[i].arg_ptr.arg_arg = Nullarg;
  1221. X        break;
  1222. X    case A_CMD:
  1223. X        cmd_free(arg[i].arg_ptr.arg_cmd);
  1224. X        arg[i].arg_ptr.arg_cmd = Nullcmd;
  1225. X        break;
  1226. X    case A_WORD:
  1227. X    case A_STAB:
  1228. X    case A_LVAL:
  1229. X    case A_READ:
  1230. X    case A_GLOB:
  1231. X    case A_ARYLEN:
  1232. X    case A_LARYLEN:
  1233. X    case A_ARYSTAB:
  1234. X    case A_LARYSTAB:
  1235. X        break;
  1236. X    case A_SINGLE:
  1237. X    case A_DOUBLE:
  1238. X    case A_BACKTICK:
  1239. X        str_free(arg[i].arg_ptr.arg_str);
  1240. X        arg[i].arg_ptr.arg_str = Nullstr;
  1241. X        break;
  1242. X    case A_SPAT:
  1243. X        spat_free(arg[i].arg_ptr.arg_spat);
  1244. X        arg[i].arg_ptr.arg_spat = Nullspat;
  1245. X        break;
  1246. X    }
  1247. X    }
  1248. X    free_arg(arg);
  1249. X}
  1250. X
  1251. Xspat_free(spat)
  1252. Xregister SPAT *spat;
  1253. X{
  1254. X    register SPAT *sp;
  1255. X    HENT *entry;
  1256. X
  1257. X    if (spat->spat_runtime) {
  1258. X    arg_free(spat->spat_runtime);
  1259. X    spat->spat_runtime = Nullarg;
  1260. X    }
  1261. X    if (spat->spat_repl) {
  1262. X    arg_free(spat->spat_repl);
  1263. X    spat->spat_repl = Nullarg;
  1264. X    }
  1265. X    if (spat->spat_short) {
  1266. X    str_free(spat->spat_short);
  1267. X    spat->spat_short = Nullstr;
  1268. X    }
  1269. X    if (spat->spat_regexp) {
  1270. X    regfree(spat->spat_regexp);
  1271. X    spat->spat_regexp = Null(REGEXP*);
  1272. X    }
  1273. X
  1274. X    /* now unlink from spat list */
  1275. X
  1276. X    for (entry = defstash->tbl_array['_']; entry; entry = entry->hent_next) {
  1277. X    register HASH *stash;
  1278. X    STAB *stab = (STAB*)entry->hent_val;
  1279. X
  1280. X    if (!stab)
  1281. X        continue;
  1282. X    stash = stab_hash(stab);
  1283. X    if (!stash || stash->tbl_spatroot == Null(SPAT*))
  1284. X        continue;
  1285. X    if (stash->tbl_spatroot == spat)
  1286. X        stash->tbl_spatroot = spat->spat_next;
  1287. X    else {
  1288. X        for (sp = stash->tbl_spatroot;
  1289. X          sp && sp->spat_next != spat;
  1290. X          sp = sp->spat_next)
  1291. X        ;
  1292. X        if (sp)
  1293. X        sp->spat_next = spat->spat_next;
  1294. X    }
  1295. X    }
  1296. X    Safefree(spat);
  1297. X}
  1298. X
  1299. X/* Recursively descend a command sequence and push the address of any string
  1300. X * that needs saving on recursion onto the tosave array.
  1301. X */
  1302. X
  1303. Xstatic int
  1304. Xcmd_tosave(cmd,willsave)
  1305. Xregister CMD *cmd;
  1306. Xint willsave;                /* willsave passes down the tree */
  1307. X{
  1308. X    register CMD *head = cmd;
  1309. X    int shouldsave = FALSE;        /* shouldsave passes up the tree */
  1310. X    int tmpsave;
  1311. X    register CMD *lastcmd = Nullcmd;
  1312. X
  1313. X    while (cmd) {
  1314. X    if (cmd->c_expr)
  1315. X        shouldsave |= arg_tosave(cmd->c_expr,willsave);
  1316. X    switch (cmd->c_type) {
  1317. X    case C_WHILE:
  1318. X        if (cmd->ucmd.ccmd.cc_true) {
  1319. X        tmpsave = cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
  1320. X
  1321. X        /* Here we check to see if the temporary array generated for
  1322. X         * a foreach needs to be localized because of recursion.
  1323. X         */
  1324. X        if (tmpsave && (cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY) {
  1325. X            if (lastcmd &&
  1326. X              lastcmd->c_type == C_EXPR &&
  1327. X              lastcmd->c_expr) {
  1328. X            ARG *arg = lastcmd->c_expr;
  1329. X
  1330. X            if (arg->arg_type == O_ASSIGN &&
  1331. X                arg[1].arg_type == A_LEXPR &&
  1332. X                arg[1].arg_ptr.arg_arg->arg_type == O_LARRAY &&
  1333. X                strnEQ("_GEN_",
  1334. X                  stab_name(
  1335. X                arg[1].arg_ptr.arg_arg[1].arg_ptr.arg_stab),
  1336. X                  5)) {    /* array generated for foreach */
  1337. X                (void)localize(arg);
  1338. X            }
  1339. X            }
  1340. X
  1341. X            /* in any event, save the iterator */
  1342. X
  1343. X            (void)apush(tosave,cmd->c_short);
  1344. X        }
  1345. X        shouldsave |= tmpsave;
  1346. X        }
  1347. X        break;
  1348. X    case C_BLOCK:
  1349. X    case C_ELSE:
  1350. X    case C_IF:
  1351. X        if (cmd->ucmd.ccmd.cc_true)
  1352. X        shouldsave |= cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
  1353. X        break;
  1354. X    case C_EXPR:
  1355. X        if (cmd->ucmd.acmd.ac_expr)
  1356. X        shouldsave |= arg_tosave(cmd->ucmd.acmd.ac_expr,willsave);
  1357. X        break;
  1358. X    }
  1359. X    lastcmd = cmd;
  1360. X    cmd = cmd->c_next;
  1361. X    if (cmd && cmd == head)        /* reached end of while loop */
  1362. X        break;
  1363. X    }
  1364. X    return shouldsave;
  1365. X}
  1366. X
  1367. Xstatic int
  1368. Xarg_tosave(arg,willsave)
  1369. Xregister ARG *arg;
  1370. Xint willsave;
  1371. X{
  1372. X    register int i;
  1373. X    int shouldsave = FALSE;
  1374. X
  1375. X    for (i = arg->arg_len; i >= 1; i--) {
  1376. X    switch (arg[i].arg_type & A_MASK) {
  1377. X    case A_NULL:
  1378. X        break;
  1379. X    case A_LEXPR:
  1380. X    case A_EXPR:
  1381. X        shouldsave |= arg_tosave(arg[i].arg_ptr.arg_arg,shouldsave);
  1382. X        break;
  1383. X    case A_CMD:
  1384. X        shouldsave |= cmd_tosave(arg[i].arg_ptr.arg_cmd,shouldsave);
  1385. X        break;
  1386. X    case A_WORD:
  1387. X    case A_STAB:
  1388. X    case A_LVAL:
  1389. X    case A_READ:
  1390. X    case A_GLOB:
  1391. X    case A_ARYLEN:
  1392. X    case A_SINGLE:
  1393. X    case A_DOUBLE:
  1394. X    case A_BACKTICK:
  1395. X        break;
  1396. X    case A_SPAT:
  1397. X        shouldsave |= spat_tosave(arg[i].arg_ptr.arg_spat);
  1398. X        break;
  1399. X    }
  1400. X    }
  1401. X    switch (arg->arg_type) {
  1402. X    case O_RETURN:
  1403. X    saw_return = TRUE;
  1404. X    break;
  1405. X    case O_EVAL:
  1406. X    case O_SUBR:
  1407. X    shouldsave = TRUE;
  1408. X    break;
  1409. X    }
  1410. X    if (willsave)
  1411. X    (void)apush(tosave,arg->arg_ptr.arg_str);
  1412. X    return shouldsave;
  1413. X}
  1414. X
  1415. Xstatic int
  1416. Xspat_tosave(spat)
  1417. Xregister SPAT *spat;
  1418. X{
  1419. X    int shouldsave = FALSE;
  1420. X
  1421. X    if (spat->spat_runtime)
  1422. X    shouldsave |= arg_tosave(spat->spat_runtime,FALSE);
  1423. X    if (spat->spat_repl) {
  1424. X    shouldsave |= arg_tosave(spat->spat_repl,FALSE);
  1425. X    }
  1426. X
  1427. X    return shouldsave;
  1428. X}
  1429. X
  1430. !STUFFY!FUNK!
  1431. echo Extracting x2p/str.c
  1432. sed >x2p/str.c <<'!STUFFY!FUNK!' -e 's/X//'
  1433. X/* $Header: str.c,v 4.0 91/03/20 01:58:15 lwall Locked $
  1434. X *
  1435. X *    Copyright (c) 1989, Larry Wall
  1436. X *
  1437. X *    You may distribute under the terms of the GNU General Public License
  1438. X *    as specified in the README file that comes with the perl 3.0 kit.
  1439. X *
  1440. X * $Log:    str.c,v $
  1441. X * Revision 4.0  91/03/20  01:58:15  lwall
  1442. X * 4.0 baseline.
  1443. X * 
  1444. X */
  1445. X
  1446. X#include "handy.h"
  1447. X#include "EXTERN.h"
  1448. X#include "util.h"
  1449. X#include "a2p.h"
  1450. X
  1451. Xstr_numset(str,num)
  1452. Xregister STR *str;
  1453. Xdouble num;
  1454. X{
  1455. X    str->str_nval = num;
  1456. X    str->str_pok = 0;        /* invalidate pointer */
  1457. X    str->str_nok = 1;        /* validate number */
  1458. X}
  1459. X
  1460. Xchar *
  1461. Xstr_2ptr(str)
  1462. Xregister STR *str;
  1463. X{
  1464. X    register char *s;
  1465. X
  1466. X    if (!str)
  1467. X    return "";
  1468. X    GROWSTR(&(str->str_ptr), &(str->str_len), 24);
  1469. X    s = str->str_ptr;
  1470. X    if (str->str_nok) {
  1471. X    sprintf(s,"%.20g",str->str_nval);
  1472. X    while (*s) s++;
  1473. X    }
  1474. X    *s = '\0';
  1475. X    str->str_cur = s - str->str_ptr;
  1476. X    str->str_pok = 1;
  1477. X#ifdef DEBUGGING
  1478. X    if (debug & 32)
  1479. X    fprintf(stderr,"0x%lx ptr(%s)\n",str,str->str_ptr);
  1480. X#endif
  1481. X    return str->str_ptr;
  1482. X}
  1483. X
  1484. Xdouble
  1485. Xstr_2num(str)
  1486. Xregister STR *str;
  1487. X{
  1488. X    if (!str)
  1489. X    return 0.0;
  1490. X    if (str->str_len && str->str_pok)
  1491. X    str->str_nval = atof(str->str_ptr);
  1492. X    else
  1493. X    str->str_nval = 0.0;
  1494. X    str->str_nok = 1;
  1495. X#ifdef DEBUGGING
  1496. X    if (debug & 32)
  1497. X    fprintf(stderr,"0x%lx num(%g)\n",str,str->str_nval);
  1498. X#endif
  1499. X    return str->str_nval;
  1500. X}
  1501. X
  1502. Xstr_sset(dstr,sstr)
  1503. XSTR *dstr;
  1504. Xregister STR *sstr;
  1505. X{
  1506. X    if (!sstr)
  1507. X    str_nset(dstr,No,0);
  1508. X    else if (sstr->str_nok)
  1509. X    str_numset(dstr,sstr->str_nval);
  1510. X    else if (sstr->str_pok)
  1511. X    str_nset(dstr,sstr->str_ptr,sstr->str_cur);
  1512. X    else
  1513. X    str_nset(dstr,"",0);
  1514. X}
  1515. X
  1516. Xstr_nset(str,ptr,len)
  1517. Xregister STR *str;
  1518. Xregister char *ptr;
  1519. Xregister int len;
  1520. X{
  1521. X    GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
  1522. X    bcopy(ptr,str->str_ptr,len);
  1523. X    str->str_cur = len;
  1524. X    *(str->str_ptr+str->str_cur) = '\0';
  1525. X    str->str_nok = 0;        /* invalidate number */
  1526. X    str->str_pok = 1;        /* validate pointer */
  1527. X}
  1528. X
  1529. Xstr_set(str,ptr)
  1530. Xregister STR *str;
  1531. Xregister char *ptr;
  1532. X{
  1533. X    register int len;
  1534. X
  1535. X    if (!ptr)
  1536. X    ptr = "";
  1537. X    len = strlen(ptr);
  1538. X    GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
  1539. X    bcopy(ptr,str->str_ptr,len+1);
  1540. X    str->str_cur = len;
  1541. X    str->str_nok = 0;        /* invalidate number */
  1542. X    str->str_pok = 1;        /* validate pointer */
  1543. X}
  1544. X
  1545. Xstr_chop(str,ptr)    /* like set but assuming ptr is in str */
  1546. Xregister STR *str;
  1547. Xregister char *ptr;
  1548. X{
  1549. X    if (!(str->str_pok))
  1550. X    str_2ptr(str);
  1551. X    str->str_cur -= (ptr - str->str_ptr);
  1552. X    bcopy(ptr,str->str_ptr, str->str_cur + 1);
  1553. X    str->str_nok = 0;        /* invalidate number */
  1554. X    str->str_pok = 1;        /* validate pointer */
  1555. X}
  1556. X
  1557. Xstr_ncat(str,ptr,len)
  1558. Xregister STR *str;
  1559. Xregister char *ptr;
  1560. Xregister int len;
  1561. X{
  1562. X    if (!(str->str_pok))
  1563. X    str_2ptr(str);
  1564. X    GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
  1565. X    bcopy(ptr,str->str_ptr+str->str_cur,len);
  1566. X    str->str_cur += len;
  1567. X    *(str->str_ptr+str->str_cur) = '\0';
  1568. X    str->str_nok = 0;        /* invalidate number */
  1569. X    str->str_pok = 1;        /* validate pointer */
  1570. X}
  1571. X
  1572. Xstr_scat(dstr,sstr)
  1573. XSTR *dstr;
  1574. Xregister STR *sstr;
  1575. X{
  1576. X    if (!(sstr->str_pok))
  1577. X    str_2ptr(sstr);
  1578. X    if (sstr)
  1579. X    str_ncat(dstr,sstr->str_ptr,sstr->str_cur);
  1580. X}
  1581. X
  1582. Xstr_cat(str,ptr)
  1583. Xregister STR *str;
  1584. Xregister char *ptr;
  1585. X{
  1586. X    register int len;
  1587. X
  1588. X    if (!ptr)
  1589. X    return;
  1590. X    if (!(str->str_pok))
  1591. X    str_2ptr(str);
  1592. X    len = strlen(ptr);
  1593. X    GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
  1594. X    bcopy(ptr,str->str_ptr+str->str_cur,len+1);
  1595. X    str->str_cur += len;
  1596. X    str->str_nok = 0;        /* invalidate number */
  1597. X    str->str_pok = 1;        /* validate pointer */
  1598. X}
  1599. X
  1600. Xchar *
  1601. Xstr_append_till(str,from,delim,keeplist)
  1602. Xregister STR *str;
  1603. Xregister char *from;
  1604. Xregister int delim;
  1605. Xchar *keeplist;
  1606. X{
  1607. X    register char *to;
  1608. X    register int len;
  1609. X
  1610. X    if (!from)
  1611. X    return Nullch;
  1612. X    len = strlen(from);
  1613. X    GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
  1614. X    str->str_nok = 0;        /* invalidate number */
  1615. X    str->str_pok = 1;        /* validate pointer */
  1616. X    to = str->str_ptr+str->str_cur;
  1617. X    for (; *from; from++,to++) {
  1618. X    if (*from == '\\' && from[1] && delim != '\\') {
  1619. X        if (!keeplist) {
  1620. X        if (from[1] == delim || from[1] == '\\')
  1621. X            from++;
  1622. X        else
  1623. X            *to++ = *from++;
  1624. X        }
  1625. X        else if (index(keeplist,from[1]))
  1626. X        *to++ = *from++;
  1627. X        else
  1628. X        from++;
  1629. X    }
  1630. X    else if (*from == delim)
  1631. X        break;
  1632. X    *to = *from;
  1633. X    }
  1634. X    *to = '\0';
  1635. X    str->str_cur = to - str->str_ptr;
  1636. X    return from;
  1637. X}
  1638. X
  1639. XSTR *
  1640. Xstr_new(len)
  1641. Xint len;
  1642. X{
  1643. X    register STR *str;
  1644. X    
  1645. X    if (freestrroot) {
  1646. X    str = freestrroot;
  1647. X    freestrroot = str->str_link.str_next;
  1648. X    }
  1649. X    else {
  1650. X    str = (STR *) safemalloc(sizeof(STR));
  1651. X    bzero((char*)str,sizeof(STR));
  1652. X    }
  1653. X    if (len)
  1654. X    GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
  1655. X    return str;
  1656. X}
  1657. X
  1658. Xvoid
  1659. Xstr_grow(str,len)
  1660. Xregister STR *str;
  1661. Xint len;
  1662. X{
  1663. X    if (len && str)
  1664. X    GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
  1665. X}
  1666. X
  1667. X/* make str point to what nstr did */
  1668. X
  1669. Xvoid
  1670. Xstr_replace(str,nstr)
  1671. Xregister STR *str;
  1672. Xregister STR *nstr;
  1673. X{
  1674. X    safefree(str->str_ptr);
  1675. X    str->str_ptr = nstr->str_ptr;
  1676. X    str->str_len = nstr->str_len;
  1677. X    str->str_cur = nstr->str_cur;
  1678. X    str->str_pok = nstr->str_pok;
  1679. X    if (str->str_nok = nstr->str_nok)
  1680. X    str->str_nval = nstr->str_nval;
  1681. X    safefree((char*)nstr);
  1682. X}
  1683. X
  1684. Xvoid
  1685. Xstr_free(str)
  1686. Xregister STR *str;
  1687. X{
  1688. X    if (!str)
  1689. X    return;
  1690. X    if (str->str_len)
  1691. X    str->str_ptr[0] = '\0';
  1692. X    str->str_cur = 0;
  1693. X    str->str_nok = 0;
  1694. X    str->str_pok = 0;
  1695. X    str->str_link.str_next = freestrroot;
  1696. X    freestrroot = str;
  1697. X}
  1698. X
  1699. Xstr_len(str)
  1700. Xregister STR *str;
  1701. X{
  1702. X    if (!str)
  1703. X    return 0;
  1704. X    if (!(str->str_pok))
  1705. X    str_2ptr(str);
  1706. X    if (str->str_len)
  1707. X    return str->str_cur;
  1708. X    else
  1709. X    return 0;
  1710. X}
  1711. X
  1712. Xchar *
  1713. Xstr_gets(str,fp)
  1714. Xregister STR *str;
  1715. Xregister FILE *fp;
  1716. X{
  1717. X#ifdef STDSTDIO        /* Here is some breathtakingly efficient cheating */
  1718. X
  1719. X    register char *bp;        /* we're going to steal some values */
  1720. X    register int cnt;        /*  from the stdio struct and put EVERYTHING */
  1721. X    register STDCHAR *ptr;    /*   in the innermost loop into registers */
  1722. X    register char newline = '\n';    /* (assuming at least 6 registers) */
  1723. X    int i;
  1724. X    int bpx;
  1725. X
  1726. X    cnt = fp->_cnt;            /* get count into register */
  1727. X    str->str_nok = 0;            /* invalidate number */
  1728. X    str->str_pok = 1;            /* validate pointer */
  1729. X    if (str->str_len <= cnt)        /* make sure we have the room */
  1730. X    GROWSTR(&(str->str_ptr), &(str->str_len), cnt+1);
  1731. X    bp = str->str_ptr;            /* move these two too to registers */
  1732. X    ptr = fp->_ptr;
  1733. X    for (;;) {
  1734. X    while (--cnt >= 0) {
  1735. X        if ((*bp++ = *ptr++) == newline)
  1736. X        if (bp <= str->str_ptr || bp[-2] != '\\')
  1737. X            goto thats_all_folks;
  1738. X        else {
  1739. X            line++;
  1740. X            bp -= 2;
  1741. X        }
  1742. X    }
  1743. X    
  1744. X    fp->_cnt = cnt;            /* deregisterize cnt and ptr */
  1745. X    fp->_ptr = ptr;
  1746. X    i = _filbuf(fp);        /* get more characters */
  1747. X    cnt = fp->_cnt;
  1748. X    ptr = fp->_ptr;            /* reregisterize cnt and ptr */
  1749. X
  1750. X    bpx = bp - str->str_ptr;    /* prepare for possible relocation */
  1751. X    GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + cnt + 1);
  1752. X    bp = str->str_ptr + bpx;    /* reconstitute our pointer */
  1753. X
  1754. X    if (i == newline) {        /* all done for now? */
  1755. X        *bp++ = i;
  1756. X        goto thats_all_folks;
  1757. X    }
  1758. X    else if (i == EOF)        /* all done for ever? */
  1759. X        goto thats_all_folks;
  1760. X    *bp++ = i;            /* now go back to screaming loop */
  1761. X    }
  1762. X
  1763. Xthats_all_folks:
  1764. X    fp->_cnt = cnt;            /* put these back or we're in trouble */
  1765. X    fp->_ptr = ptr;
  1766. X    *bp = '\0';
  1767. X    str->str_cur = bp - str->str_ptr;    /* set length */
  1768. X
  1769. X#else /* !STDSTDIO */    /* The big, slow, and stupid way */
  1770. X
  1771. X    static char buf[4192];
  1772. X
  1773. X    if (fgets(buf, sizeof buf, fp) != Nullch)
  1774. X    str_set(str, buf);
  1775. X    else
  1776. X    str_set(str, No);
  1777. X
  1778. X#endif /* STDSTDIO */
  1779. X
  1780. X    return str->str_cur ? str->str_ptr : Nullch;
  1781. X}
  1782. X
  1783. Xvoid
  1784. Xstr_inc(str)
  1785. Xregister STR *str;
  1786. X{
  1787. X    register char *d;
  1788. X
  1789. X    if (!str)
  1790. X    return;
  1791. X    if (str->str_nok) {
  1792. X    str->str_nval += 1.0;
  1793. X    str->str_pok = 0;
  1794. X    return;
  1795. X    }
  1796. X    if (!str->str_pok) {
  1797. X    str->str_nval = 1.0;
  1798. X    str->str_nok = 1;
  1799. X    return;
  1800. X    }
  1801. X    for (d = str->str_ptr; *d && *d != '.'; d++) ;
  1802. X    d--;
  1803. X    if (!isdigit(*str->str_ptr) || !isdigit(*d) ) {
  1804. X        str_numset(str,atof(str->str_ptr) + 1.0);  /* punt */
  1805. X    return;
  1806. X    }
  1807. X    while (d >= str->str_ptr) {
  1808. X    if (++*d <= '9')
  1809. X        return;
  1810. X    *(d--) = '0';
  1811. X    }
  1812. X    /* oh,oh, the number grew */
  1813. X    GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + 2);
  1814. X    str->str_cur++;
  1815. X    for (d = str->str_ptr + str->str_cur; d > str->str_ptr; d--)
  1816. X    *d = d[-1];
  1817. X    *d = '1';
  1818. X}
  1819. X
  1820. Xvoid
  1821. Xstr_dec(str)
  1822. Xregister STR *str;
  1823. X{
  1824. X    register char *d;
  1825. X
  1826. X    if (!str)
  1827. X    return;
  1828. X    if (str->str_nok) {
  1829. X    str->str_nval -= 1.0;
  1830. X    str->str_pok = 0;
  1831. X    return;
  1832. X    }
  1833. X    if (!str->str_pok) {
  1834. X    str->str_nval = -1.0;
  1835. X    str->str_nok = 1;
  1836. X    return;
  1837. X    }
  1838. X    for (d = str->str_ptr; *d && *d != '.'; d++) ;
  1839. X    d--;
  1840. X    if (!isdigit(*str->str_ptr) || !isdigit(*d) || (*d == '0' && d == str->str_ptr)) {
  1841. X        str_numset(str,atof(str->str_ptr) - 1.0);  /* punt */
  1842. X    return;
  1843. X    }
  1844. X    while (d >= str->str_ptr) {
  1845. X    if (--*d >= '0')
  1846. X        return;
  1847. X    *(d--) = '9';
  1848. X    }
  1849. X}
  1850. X
  1851. X/* make a string that will exist for the duration of the expression eval */
  1852. X
  1853. XSTR *
  1854. Xstr_mortal(oldstr)
  1855. XSTR *oldstr;
  1856. X{
  1857. X    register STR *str = str_new(0);
  1858. X    static long tmps_size = -1;
  1859. X
  1860. X    str_sset(str,oldstr);
  1861. X    if (++tmps_max > tmps_size) {
  1862. X    tmps_size = tmps_max;
  1863. X    if (!(tmps_size & 127)) {
  1864. X        if (tmps_size)
  1865. X        tmps_list = (STR**)saferealloc((char*)tmps_list,
  1866. X            (tmps_size + 128) * sizeof(STR*) );
  1867. X        else
  1868. X        tmps_list = (STR**)safemalloc(128 * sizeof(char*));
  1869. X    }
  1870. X    }
  1871. X    tmps_list[tmps_max] = str;
  1872. X    return str;
  1873. X}
  1874. X
  1875. XSTR *
  1876. Xstr_make(s)
  1877. Xchar *s;
  1878. X{
  1879. X    register STR *str = str_new(0);
  1880. X
  1881. X    str_set(str,s);
  1882. X    return str;
  1883. X}
  1884. X
  1885. XSTR *
  1886. Xstr_nmake(n)
  1887. Xdouble n;
  1888. X{
  1889. X    register STR *str = str_new(0);
  1890. X
  1891. X    str_numset(str,n);
  1892. X    return str;
  1893. X}
  1894. !STUFFY!FUNK!
  1895. echo Extracting msdos/Changes.dds
  1896. sed >msdos/Changes.dds <<'!STUFFY!FUNK!' -e 's/X//'
  1897. XThese are the changes done by the `patches' file:
  1898. X
  1899. X[These patches have been applied, more or less, so I don't supply the
  1900. Xpatches file--law]
  1901. X
  1902. XCompilation of some portions is done conditional on the definition
  1903. Xof the following symbols:
  1904. X
  1905. XBINARY        Enables the usage of setmode under MSDOS (added binmode command)
  1906. XBUGGY_MSC    Adds #pragma_function(memset) to avoid internal compiler error
  1907. XCHOWN        Enables chown
  1908. XCHROOT        Enables chroot
  1909. XFORK        Enables fork and changes the compilation of system
  1910. XGETLOGIN    Enables getlogin
  1911. XGETPPID        Enables getppid
  1912. XGROUP        Enables all the group access functions
  1913. XKILL        Enables kill
  1914. XLINK        Enables link
  1915. XPASSWD        Enables all the password access functions
  1916. XPIPE        Enables the pipe function
  1917. XWAIT        Enables the wait function
  1918. XUMASK        Enables the umask function
  1919. X
  1920. XS_IFBLK *    Enables the block special device check
  1921. XS_ISGID *    Enables the setgid check
  1922. XS_ISUID *    Enables the setuid check
  1923. XS_ISVTX *    Enables the vtx check
  1924. Xunix *        Compiles globbing for Unix
  1925. XMSDOS *        Compiles globbing for MS-DOS
  1926. X        Closes stdaux and stdprn on startup
  1927. X        Adds a copyright message for -v
  1928. X        Disables the compilation of my_popen, my_pclose as the
  1929. X        are in a separate file.
  1930. X
  1931. XSymbols marked with * are defined in the compilation environment.  The
  1932. Xrest should be added to config.h (config.h.SH).  All functions when not
  1933. Xsupported give a fatal error.
  1934. X
  1935. XAdded documentation for the binmode function in the manual.
  1936. X
  1937. XFixed the following bugs:
  1938. X
  1939. XIn eval.c function eval if ioctl or fcntl returned something
  1940. Xother than 0 or -1 the result was a random number as the
  1941. Xdouble `value' variable wasn't set to `anum'.
  1942. X
  1943. XIn doio.c function do_exec there were two errors associated with
  1944. Xfiring up the shell when the execv fails.  First argv was not freed,
  1945. Xsecondly an attempt was made to start up the shell with the cmd
  1946. Xstring that was now cut to pieces for the execv.  Also the maxible
  1947. Xpossible length of argv was calculated by (s - cmd).  Problem was
  1948. Xthat s was not pointing to the end of the string, but to the first
  1949. Xnon alpha.
  1950. X
  1951. X[These are incorporated in patches 15 and 16--law]
  1952. X
  1953. XDiomidis Spinellis, March 1990
  1954. !STUFFY!FUNK!
  1955. echo " "
  1956. echo "End of kit 13 (of 36)"
  1957. cat /dev/null >kit13isdone
  1958. run=''
  1959. config=''
  1960. 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 25 26 27 28 29 30 31 32 33 34 35 36; do
  1961.     if test -f kit${iskit}isdone; then
  1962.     run="$run $iskit"
  1963.     else
  1964.     todo="$todo $iskit"
  1965.     fi
  1966. done
  1967. case $todo in
  1968.     '')
  1969.     echo "You have run all your kits.  Please read README and then type Configure."
  1970.     for combo in *:AA; do
  1971.         if test -f "$combo"; then
  1972.         realfile=`basename $combo :AA`
  1973.         cat $realfile:[A-Z][A-Z] >$realfile
  1974.         rm -rf $realfile:[A-Z][A-Z]
  1975.         fi
  1976.     done
  1977.     rm -rf kit*isdone
  1978.     chmod 755 Configure
  1979.     ;;
  1980.     *)  echo "You have run$run."
  1981.     echo "You still need to run$todo."
  1982.     ;;
  1983. esac
  1984. : Someone might mail this, so...
  1985. exit
  1986.  
  1987. exit 0 # Just in case...
  1988. -- 
  1989. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1990. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1991. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1992. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1993.