home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume15 / perl2 / part01 next >
Encoding:
Internet Message Format  |  1989-01-05  |  49.0 KB

  1. Subject:  v15i090:  Perl, release 2, Part01/15
  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 15, Issue 90
  8. Archive-name: perl2/part01
  9.  
  10. #! /bin/sh
  11.  
  12. # Make a new directory for the perl sources, cd to it, and run kits 1
  13. # thru 15 through sh.  When all 15 kits have been run, read README.
  14.  
  15. echo "This is perl 2.0 kit 1 (of 15).  If kit 1 is complete, the line"
  16. echo '"'"End of kit 1 (of 15)"'" will echo at the end.'
  17. echo ""
  18. export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
  19. mkdir eg eg/g t 2>/dev/null
  20. echo Extracting README
  21. sed >README <<'!STUFFY!FUNK!' -e 's/X//'
  22. X
  23. X            Perl Kit, Version 2.0
  24. X
  25. X            Copyright (c) 1988, Larry Wall
  26. X
  27. XYou may copy the perl kit in whole or in part as long as you don't try to
  28. Xmake money off it, or pretend that you wrote it.
  29. X--------------------------------------------------------------------------
  30. X
  31. XPerl is a language that combines some of the features of C, sed, awk and shell.
  32. XSee the manual page for more hype.
  33. X
  34. XPerl will probably not run on machines with a small address space.
  35. X
  36. XPlease read all the directions below before you proceed any further, and
  37. Xthen follow them carefully.  Failure to do so may void your warranty. :-)
  38. X
  39. XAfter you have unpacked your kit, you should have all the files listed
  40. Xin MANIFEST.
  41. X
  42. XInstallation
  43. X
  44. X1)  Run Configure.  This will figure out various things about your system.
  45. X    Some things Configure will figure out for itself, other things it will
  46. X    ask you about.  It will then proceed to make config.h, config.sh, and
  47. X    Makefile.
  48. X
  49. X    You might possibly have to trim # comments from the front of Configure
  50. X    if your sh doesn't handle them, but all other # comments will be taken
  51. X    care of.
  52. X
  53. X    (If you don't have sh, you'll have to copy the sample file config.H to
  54. X    config.h and edit the config.h to reflect your system's peculiarities.)
  55. X
  56. X2)  Glance through config.h to make sure system dependencies are correct.
  57. X    Most of them should have been taken care of by running the Configure script.
  58. X
  59. X    If you have any additional changes to make to the C definitions, they
  60. X    can be done in the Makefile, or in config.h.  Bear in mind that they will
  61. X    get undone next time you run Configure.
  62. X
  63. X3)  make depend
  64. X
  65. X    This will look for all the includes and modify Makefile accordingly.
  66. X    Configure will offer to do this for you.
  67. X
  68. X4)  make
  69. X
  70. X    This will attempt to make perl in the current directory.
  71. X
  72. X5)  make test
  73. X
  74. X    This will run the regression tests on the perl you just made.
  75. X    If it doesn't say "All tests successful" then something went wrong.
  76. X    See the README in the t subdirectory.  Note that you can't run it
  77. X    in background if this disables opening of /dev/tty.  If in doubt, just
  78. X    cd to the t directory and run TEST by hand.
  79. X
  80. X6)  make install
  81. X
  82. X    This will put perl into a public directory (normally /usr/local/bin).
  83. X    It will also try to put the man pages in a reasonable place.  It will not
  84. X    nroff the man page, however.  You may need to be root to do this.  If
  85. X    you are not root, you must own the directories in question and you should
  86. X    ignore any messages about chown not working.
  87. X
  88. X7)  Read the manual entry before running perl.
  89. X
  90. X8)  Go down to the x2p directory and do a "make depend, a "make" and a
  91. X    "make install" to create the awk to perl and sed to perl translators.
  92. X
  93. X9)  IMPORTANT!  Help save the world!  Communicate any problems and suggested
  94. X    patches to me, lwall@jpl-devvax.jpl.nasa.gov (Larry Wall), so we can
  95. X    keep the world in sync.  If you have a problem, there's someone else
  96. X    out there who either has had or will have the same problem.
  97. X
  98. X    If possible, send in patches such that the patch program will apply them.
  99. X    Context diffs are the best, then normal diffs.  Don't send ed scripts--
  100. X    I've probably changed my copy since the version you have.
  101. X
  102. X    Watch for perl patches in comp.sources.bugs.  Patches will generally be
  103. X    in a form usable by the patch program.  If you are just now bringing up
  104. X    perl and aren't sure how many patches there are, write to me and I'll
  105. X    send any you don't have.  Your current patch level is shown in patchlevel.h.
  106. X
  107. !STUFFY!FUNK!
  108. echo Extracting eg/README
  109. sed >eg/README <<'!STUFFY!FUNK!' -e 's/X//'
  110. XThis stuff is supplied on an as-is basis--little attempt has been made to make
  111. Xany of it portable.  It's mostly here to give you an idea of what perl code
  112. Xlooks like, and what tricks and idioms are used.
  113. X
  114. XSystem administrators responsible for many computers will enjoy the items
  115. Xdown in the g directory very much.  The scan directory contains the beginnings
  116. Xof a system to check on and report various kinds of anomalies.
  117. X
  118. XIf you machine doesn't support #!, the first thing you'll want to do is
  119. Xreplace the #! with a couple of lines that look like this:
  120. X
  121. X    eval "exec /usr/bin/perl -S $0 $*"
  122. X        if $running_under_some_shell;
  123. X
  124. Xbeing sure to include any flags that were on the #! line.  A supplied script
  125. Xcalled "nih" will translate perl scripts in place for you:
  126. X
  127. X    nih g/g??
  128. !STUFFY!FUNK!
  129. echo Extracting t/README
  130. sed >t/README <<'!STUFFY!FUNK!' -e 's/X//'
  131. XThis is the perl test library.  To run all the tests, just type 'TEST'.
  132. X
  133. XTo add new tests, just look at the current tests and do likewise.
  134. X
  135. XIf a test fails, run it by itself to see if it prints any informative
  136. Xdiagnostics.  If not, modify the test to print informative diagnostics.
  137. XIf you put out extra lines with a '#' character on the front, you don't
  138. Xhave to worry about removing the extra print statements later since TEST
  139. Xignores lines beginning with '#'.
  140. X
  141. XIf you come up with new tests, send them to lwall@jpl-devvax.jpl.nasa.gov.
  142. !STUFFY!FUNK!
  143. echo Extracting arg.c
  144. sed >arg.c <<'!STUFFY!FUNK!' -e 's/X//'
  145. X/* $Header: arg.c,v 2.0 88/06/05 00:08:04 root Exp $
  146. X *
  147. X * $Log:    arg.c,v $
  148. X * Revision 2.0  88/06/05  00:08:04  root
  149. X * Baseline version 2.0.
  150. X * 
  151. X */
  152. X
  153. X#include "EXTERN.h"
  154. X#include "perl.h"
  155. X
  156. X#include <signal.h>
  157. X#include <errno.h>
  158. X
  159. Xextern int errno;
  160. X
  161. XSTR *
  162. Xdo_match(arg,retary,sarg,ptrmaxsarg,sargoff,cushion)
  163. Xregister ARG *arg;
  164. XSTR ***retary;
  165. Xregister STR **sarg;
  166. Xint *ptrmaxsarg;
  167. Xint sargoff;
  168. Xint cushion;
  169. X{
  170. X    register SPAT *spat = arg[2].arg_ptr.arg_spat;
  171. X    register char *t;
  172. X    register char *s = str_get(sarg[1]);
  173. X    char *strend = s + sarg[1]->str_cur;
  174. X
  175. X    if (!spat)
  176. X    return &str_yes;
  177. X    if (!s)
  178. X    fatal("panic: do_match");
  179. X    if (retary) {
  180. X    *retary = sarg;        /* assume no match */
  181. X    *ptrmaxsarg = sargoff;
  182. X    }
  183. X    if (spat->spat_flags & SPAT_USED) {
  184. X#ifdef DEBUGGING
  185. X    if (debug & 8)
  186. X        deb("2.SPAT USED\n");
  187. X#endif
  188. X    return &str_no;
  189. X    }
  190. X    if (spat->spat_runtime) {
  191. X    t = str_get(eval(spat->spat_runtime,Null(STR***),-1));
  192. X#ifdef DEBUGGING
  193. X    if (debug & 8)
  194. X        deb("2.SPAT /%s/\n",t);
  195. X#endif
  196. X    spat->spat_regexp = regcomp(t,spat->spat_flags & SPAT_FOLD,1);
  197. X    if (!*spat->spat_regexp->precomp && lastspat)
  198. X        spat = lastspat;
  199. X    if (regexec(spat->spat_regexp, s, strend, TRUE, 0,
  200. X      sarg[1]->str_pok & 4 ? sarg[1] : Nullstr)) {
  201. X        if (spat->spat_regexp->subbase)
  202. X        curspat = spat;
  203. X        lastspat = spat;
  204. X        goto gotcha;
  205. X    }
  206. X    else
  207. X        return &str_no;
  208. X    }
  209. X    else {
  210. X#ifdef DEBUGGING
  211. X    if (debug & 8) {
  212. X        char ch;
  213. X
  214. X        if (spat->spat_flags & SPAT_ONCE)
  215. X        ch = '?';
  216. X        else
  217. X        ch = '/';
  218. X        deb("2.SPAT %c%s%c\n",ch,spat->spat_regexp->precomp,ch);
  219. X    }
  220. X#endif
  221. X    if (!*spat->spat_regexp->precomp && lastspat)
  222. X        spat = lastspat;
  223. X    t = s;
  224. X    if (hint) {
  225. X        if (hint < s || hint > strend)
  226. X        fatal("panic: hint in do_match");
  227. X        s = hint;
  228. X        hint = Nullch;
  229. X        if (spat->spat_regexp->regback >= 0) {
  230. X        s -= spat->spat_regexp->regback;
  231. X        if (s < t)
  232. X            s = t;
  233. X        }
  234. X        else
  235. X        s = t;
  236. X    }
  237. X    else if (spat->spat_short) {
  238. X        if (spat->spat_flags & SPAT_SCANFIRST) {
  239. X        if (sarg[1]->str_pok == 5) {
  240. X            if (screamfirst[spat->spat_short->str_rare] < 0)
  241. X            goto nope;
  242. X            else if (!(s = screaminstr(sarg[1],spat->spat_short)))
  243. X            goto nope;
  244. X            else if (spat->spat_flags & SPAT_ALL)
  245. X            goto yup;
  246. X        }
  247. X        else if (!(s = fbminstr(s, strend, spat->spat_short)))
  248. X            goto nope;
  249. X        else if (spat->spat_flags & SPAT_ALL)
  250. X            goto yup;
  251. X        else if (spat->spat_regexp->regback >= 0) {
  252. X            ++*(long*)&spat->spat_short->str_nval;
  253. X            s -= spat->spat_regexp->regback;
  254. X            if (s < t)
  255. X            s = t;
  256. X        }
  257. X        else
  258. X            s = t;
  259. X        }
  260. X        else if (!multiline && (*spat->spat_short->str_ptr != *s ||
  261. X          strnNE(spat->spat_short->str_ptr, s, spat->spat_slen) ))
  262. X        goto nope;
  263. X        if (--*(long*)&spat->spat_short->str_nval < 0) {
  264. X        str_free(spat->spat_short);
  265. X        spat->spat_short = Nullstr;    /* opt is being useless */
  266. X        }
  267. X    }
  268. X    if (regexec(spat->spat_regexp, s, strend, s == t, 0,
  269. X      sarg[1]->str_pok & 4 ? sarg[1] : Nullstr)) {
  270. X        if (spat->spat_regexp->subbase)
  271. X        curspat = spat;
  272. X        lastspat = spat;
  273. X        if (spat->spat_flags & SPAT_ONCE)
  274. X        spat->spat_flags |= SPAT_USED;
  275. X        goto gotcha;
  276. X    }
  277. X    else
  278. X        return &str_no;
  279. X    }
  280. X    /*NOTREACHED*/
  281. X
  282. X  gotcha:
  283. X    if (retary && curspat == spat) {
  284. X    int iters, i, len;
  285. X
  286. X    iters = spat->spat_regexp->nparens;
  287. X    *ptrmaxsarg = iters + sargoff;
  288. X    sarg = (STR**)saferealloc((char*)(sarg - sargoff),
  289. X      (iters+2+cushion+sargoff)*sizeof(STR*)) + sargoff;
  290. X
  291. X    for (i = 1; i <= iters; i++) {
  292. X        sarg[i] = str_static(&str_no);
  293. X        if (s = spat->spat_regexp->startp[i]) {
  294. X        len = spat->spat_regexp->endp[i] - s;
  295. X        if (len > 0)
  296. X            str_nset(sarg[i],s,len);
  297. X        }
  298. X    }
  299. X    *retary = sarg;
  300. X    }
  301. X    return &str_yes;
  302. X
  303. Xyup:
  304. X    ++*(long*)&spat->spat_short->str_nval;
  305. X    return &str_yes;
  306. X
  307. Xnope:
  308. X    ++*(long*)&spat->spat_short->str_nval;
  309. X    return &str_no;
  310. X}
  311. X
  312. Xint
  313. Xdo_subst(str,arg)
  314. XSTR *str;
  315. Xregister ARG *arg;
  316. X{
  317. X    register SPAT *spat;
  318. X    register STR *dstr;
  319. X    register char *s = str_get(str);
  320. X    char *strend = s + str->str_cur;
  321. X    register char *m;
  322. X
  323. X    spat = arg[2].arg_ptr.arg_spat;
  324. X    if (!spat || !s)
  325. X    fatal("panic: do_subst");
  326. X    else if (spat->spat_runtime) {
  327. X    m = str_get(eval(spat->spat_runtime,Null(STR***),-1));
  328. X    spat->spat_regexp = regcomp(m,spat->spat_flags & SPAT_FOLD,1);
  329. X    }
  330. X#ifdef DEBUGGING
  331. X    if (debug & 8) {
  332. X    deb("2.SPAT /%s/\n",spat->spat_regexp->precomp);
  333. X    }
  334. X#endif
  335. X    if (!*spat->spat_regexp->precomp && lastspat)
  336. X    spat = lastspat;
  337. X    m = s;
  338. X    if (hint) {
  339. X    if (hint < s || hint > strend)
  340. X        fatal("panic: hint in do_match");
  341. X    s = hint;
  342. X    hint = Nullch;
  343. X    if (spat->spat_regexp->regback >= 0) {
  344. X        s -= spat->spat_regexp->regback;
  345. X        if (s < m)
  346. X        s = m;
  347. X    }
  348. X    else
  349. X        s = m;
  350. X    }
  351. X    else if (spat->spat_short) {
  352. X    if (spat->spat_flags & SPAT_SCANFIRST) {
  353. X        if (str->str_pok == 5) {
  354. X        if (screamfirst[spat->spat_short->str_rare] < 0)
  355. X            goto nope;
  356. X        else if (!(s = screaminstr(str,spat->spat_short)))
  357. X            goto nope;
  358. X        }
  359. X        else if (!(s = fbminstr(s, strend, spat->spat_short)))
  360. X        goto nope;
  361. X        else if (spat->spat_regexp->regback >= 0) {
  362. X        ++*(long*)&spat->spat_short->str_nval;
  363. X        s -= spat->spat_regexp->regback;
  364. X        if (s < m)
  365. X            s = m;
  366. X        }
  367. X        else
  368. X        s = m;
  369. X    }
  370. X    else if (!multiline && (*spat->spat_short->str_ptr != *s ||
  371. X      strnNE(spat->spat_short->str_ptr, s, spat->spat_slen) ))
  372. X        goto nope;
  373. X    if (--*(long*)&spat->spat_short->str_nval < 0) {
  374. X        str_free(spat->spat_short);
  375. X        spat->spat_short = Nullstr;    /* opt is being useless */
  376. X    }
  377. X    }
  378. X    if (regexec(spat->spat_regexp, s, strend, s == m, 1,
  379. X      str->str_pok & 4 ? str : Nullstr)) {
  380. X    int iters = 0;
  381. X
  382. X    dstr = str_new(str_len(str));
  383. X    str_nset(dstr,m,s-m);
  384. X    if (spat->spat_regexp->subbase)
  385. X        curspat = spat;
  386. X    lastspat = spat;
  387. X    do {
  388. X        m = spat->spat_regexp->startp[0];
  389. X        if (iters++ > 10000)
  390. X        fatal("Substitution loop");
  391. X        if (spat->spat_regexp->subbase)
  392. X        s = spat->spat_regexp->subbase;
  393. X        str_ncat(dstr,s,m-s);
  394. X        s = spat->spat_regexp->endp[0];
  395. X        str_scat(dstr,eval(spat->spat_repl,Null(STR***),-1));
  396. X        if (spat->spat_flags & SPAT_ONCE)
  397. X        break;
  398. X    } while (regexec(spat->spat_regexp, s, strend, FALSE, 1, Nullstr));
  399. X    str_cat(dstr,s);
  400. X    str_replace(str,dstr);
  401. X    STABSET(str);
  402. X    return iters;
  403. X    }
  404. X    return 0;
  405. X
  406. Xnope:
  407. X    ++*(long*)&spat->spat_short->str_nval;
  408. X    return 0;
  409. X}
  410. X
  411. Xint
  412. Xdo_trans(str,arg)
  413. XSTR *str;
  414. Xregister ARG *arg;
  415. X{
  416. X    register char *tbl;
  417. X    register char *s;
  418. X    register int matches = 0;
  419. X    register int ch;
  420. X
  421. X    tbl = arg[2].arg_ptr.arg_cval;
  422. X    s = str_get(str);
  423. X    if (!tbl || !s)
  424. X    fatal("panic: do_trans");
  425. X#ifdef DEBUGGING
  426. X    if (debug & 8) {
  427. X    deb("2.TBL\n");
  428. X    }
  429. X#endif
  430. X    while (*s) {
  431. X    if (ch = tbl[*s & 0377]) {
  432. X        matches++;
  433. X        *s = ch;
  434. X    }
  435. X    s++;
  436. X    }
  437. X    STABSET(str);
  438. X    return matches;
  439. X}
  440. X
  441. Xint
  442. Xdo_split(spat,retary,sarg,ptrmaxsarg,sargoff,cushion)
  443. Xregister SPAT *spat;
  444. XSTR ***retary;
  445. Xregister STR **sarg;
  446. Xint *ptrmaxsarg;
  447. Xint sargoff;
  448. Xint cushion;
  449. X{
  450. X    register char *s = str_get(sarg[1]);
  451. X    char *strend = s + sarg[1]->str_cur;
  452. X    register STR *dstr;
  453. X    register char *m;
  454. X    register ARRAY *ary;
  455. X    static ARRAY *myarray = Null(ARRAY*);
  456. X    int iters = 0;
  457. X    int i;
  458. X
  459. X    if (!spat || !s)
  460. X    fatal("panic: do_split");
  461. X    else if (spat->spat_runtime) {
  462. X    m = str_get(eval(spat->spat_runtime,Null(STR***),-1));
  463. X    if (!*m || (*m == ' ' && !m[1])) {
  464. X        m = "\\s+";
  465. X        spat->spat_flags |= SPAT_SKIPWHITE;
  466. X    }
  467. X    if (spat->spat_runtime->arg_type == O_ITEM &&
  468. X      spat->spat_runtime[1].arg_type == A_SINGLE) {
  469. X        arg_free(spat->spat_runtime);    /* it won't change, so */
  470. X        spat->spat_runtime = Nullarg;    /* no point compiling again */
  471. X    }
  472. X    spat->spat_regexp = regcomp(m,spat->spat_flags & SPAT_FOLD,1);
  473. X    }
  474. X#ifdef DEBUGGING
  475. X    if (debug & 8) {
  476. X    deb("2.SPAT /%s/\n",spat->spat_regexp->precomp);
  477. X    }
  478. X#endif
  479. X    if (retary)
  480. X    ary = myarray;
  481. X    else
  482. X    ary = spat->spat_repl[1].arg_ptr.arg_stab->stab_array;
  483. X    if (!ary)
  484. X    myarray = ary = anew(Nullstab);
  485. X    ary->ary_fill = -1;
  486. X    if (spat->spat_flags & SPAT_SKIPWHITE) {
  487. X    while (isspace(*s))
  488. X        s++;
  489. X    }
  490. X    if (spat->spat_short) {
  491. X    i = spat->spat_short->str_cur;
  492. X    while (*s && (m = fbminstr(s, strend, spat->spat_short))) {
  493. X        dstr = str_new(m-s);
  494. X        str_nset(dstr,s,m-s);
  495. X        astore(ary, iters++, dstr);
  496. X        if (iters > 10000)
  497. X        fatal("Substitution loop");
  498. X        s = m + i;
  499. X    }
  500. X    }
  501. X    else {
  502. X    while (*s && regexec(spat->spat_regexp, s, strend, (iters == 0), 1,
  503. X      Nullstr)) {
  504. X        m = spat->spat_regexp->startp[0];
  505. X        if (spat->spat_regexp->subbase)
  506. X        s = spat->spat_regexp->subbase;
  507. X        dstr = str_new(m-s);
  508. X        str_nset(dstr,s,m-s);
  509. X        astore(ary, iters++, dstr);
  510. X        if (iters > 10000)
  511. X        fatal("Substitution loop");
  512. X        s = spat->spat_regexp->endp[0];
  513. X    }
  514. X    }
  515. X    if (*s) {            /* ignore field after final "whitespace" */
  516. X    dstr = str_new(0);    /*   if they interpolate, it's null anyway */
  517. X    str_set(dstr,s);
  518. X    astore(ary, iters++, dstr);
  519. X    }
  520. X    else {
  521. X    while (iters > 0 && !*str_get(afetch(ary,iters-1)))
  522. X        iters--;
  523. X    }
  524. X    if (retary) {
  525. X    *ptrmaxsarg = iters + sargoff;
  526. X    sarg = (STR**)saferealloc((char*)(sarg - sargoff),
  527. X      (iters+2+cushion+sargoff)*sizeof(STR*)) + sargoff;
  528. X
  529. X    for (i = 1; i <= iters; i++)
  530. X        sarg[i] = afetch(ary,i-1);
  531. X    *retary = sarg;
  532. X    }
  533. X    return iters;
  534. X}
  535. X
  536. Xvoid
  537. Xdo_join(arg,delim,str)
  538. Xregister ARG *arg;
  539. Xregister char *delim;
  540. Xregister STR *str;
  541. X{
  542. X    STR **tmpary;    /* must not be register */
  543. X    register STR **elem;
  544. X    register int items;
  545. X
  546. X    (void)eval(arg[2].arg_ptr.arg_arg,&tmpary,-1);
  547. X    items = (int)str_gnum(*tmpary);
  548. X    elem = tmpary+1;
  549. X    if (items-- > 0)
  550. X    str_sset(str,*elem++);
  551. X    for (; items > 0; items--,elem++) {
  552. X    str_cat(str,delim);
  553. X    str_scat(str,*elem);
  554. X    }
  555. X    STABSET(str);
  556. X    safefree((char*)tmpary);
  557. X}
  558. X
  559. XFILE *
  560. Xforkopen(name,mode)
  561. Xchar *name;
  562. Xchar *mode;
  563. X{
  564. X    int pfd[2];
  565. X
  566. X    if (pipe(pfd) < 0)
  567. X    return Nullfp;
  568. X    while ((forkprocess = fork()) == -1) {
  569. X    if (errno != EAGAIN)
  570. X        return Nullfp;
  571. X    sleep(5);
  572. X    }
  573. X    if (*mode == 'w') {
  574. X    if (forkprocess) {
  575. X        close(pfd[0]);
  576. X        return fdopen(pfd[1],"w");
  577. X    }
  578. X    else {
  579. X        close(pfd[1]);
  580. X        close(0);
  581. X        dup(pfd[0]);    /* substitute our pipe for stdin */
  582. X        close(pfd[0]);
  583. X        return Nullfp;
  584. X    }
  585. X    }
  586. X    else {
  587. X    if (forkprocess) {
  588. X        close(pfd[1]);
  589. X        return fdopen(pfd[0],"r");
  590. X    }
  591. X    else {
  592. X        close(pfd[0]);
  593. X        close(1);
  594. X        if (dup(pfd[1]) == 0)
  595. X        dup(pfd[1]);    /* substitute our pipe for stdout */
  596. X        close(pfd[1]);
  597. X        return Nullfp;
  598. X    }
  599. X    }
  600. X}
  601. X
  602. Xbool
  603. Xdo_open(stab,name)
  604. XSTAB *stab;
  605. Xregister char *name;
  606. X{
  607. X    FILE *fp;
  608. X    int len = strlen(name);
  609. X    register STIO *stio = stab->stab_io;
  610. X    char *myname = savestr(name);
  611. X    int result;
  612. X    int fd;
  613. X
  614. X    name = myname;
  615. X    forkprocess = 1;        /* assume true if no fork */
  616. X    while (len && isspace(name[len-1]))
  617. X    name[--len] = '\0';
  618. X    if (!stio)
  619. X    stio = stab->stab_io = stio_new();
  620. X    if (stio->fp) {
  621. X    fd = fileno(stio->fp);
  622. X    if (stio->type == '|')
  623. X        result = pclose(stio->fp);
  624. X    else if (stio->type != '-')
  625. X        result = fclose(stio->fp);
  626. X    else
  627. X        result = 0;
  628. X    if (result == EOF && fd > 2)
  629. X        fprintf(stderr,"Warning: unable to close filehandle %s properly.\n",
  630. X          stab->stab_name);
  631. X    stio->fp = Nullfp;
  632. X    }
  633. X    stio->type = *name;
  634. X    if (*name == '|') {
  635. X    for (name++; isspace(*name); name++) ;
  636. X    if (strNE(name,"-"))
  637. X        fp = popen(name,"w");
  638. X    else {
  639. X        fp = forkopen(name,"w");
  640. X        stio->subprocess = forkprocess;
  641. X        stio->type = '%';
  642. X    }
  643. X    }
  644. X    else if (*name == '>' && name[1] == '>') {
  645. X    stio->type = 'a';
  646. X    for (name += 2; isspace(*name); name++) ;
  647. X    fp = fopen(name,"a");
  648. X    }
  649. X    else if (*name == '>' && name[1] == '&') {
  650. X    for (name += 2; isspace(*name); name++) ;
  651. X    if (isdigit(*name))
  652. X        fd = atoi(name);
  653. X    else {
  654. X        stab = stabent(name,FALSE);
  655. X        if (stab->stab_io && stab->stab_io->fp) {
  656. X        fd = fileno(stab->stab_io->fp);
  657. X        stio->type = stab->stab_io->type;
  658. X        }
  659. X        else
  660. X        fd = -1;
  661. X    }
  662. X    fp = fdopen(dup(fd),stio->type == 'a' ? "a" :
  663. X      (stio->type == '<' ? "r" : "w") );
  664. X    }
  665. X    else if (*name == '>') {
  666. X    for (name++; isspace(*name); name++) ;
  667. X    if (strEQ(name,"-")) {
  668. X        fp = stdout;
  669. X        stio->type = '-';
  670. X    }
  671. X    else
  672. X        fp = fopen(name,"w");
  673. X    }
  674. X    else {
  675. X    if (*name == '<') {
  676. X        for (name++; isspace(*name); name++) ;
  677. X        if (strEQ(name,"-")) {
  678. X        fp = stdin;
  679. X        stio->type = '-';
  680. X        }
  681. X        else
  682. X        fp = fopen(name,"r");
  683. X    }
  684. X    else if (name[len-1] == '|') {
  685. X        name[--len] = '\0';
  686. X        while (len && isspace(name[len-1]))
  687. X        name[--len] = '\0';
  688. X        for (; isspace(*name); name++) ;
  689. X        if (strNE(name,"-")) {
  690. X        fp = popen(name,"r");
  691. X        stio->type = '|';
  692. X        }
  693. X        else {
  694. X        fp = forkopen(name,"r");
  695. X        stio->subprocess = forkprocess;
  696. X        stio->type = '%';
  697. X        }
  698. X    }
  699. X    else {
  700. X        stio->type = '<';
  701. X        for (; isspace(*name); name++) ;
  702. X        if (strEQ(name,"-")) {
  703. X        fp = stdin;
  704. X        stio->type = '-';
  705. X        }
  706. X        else
  707. X        fp = fopen(name,"r");
  708. X    }
  709. X    }
  710. X    safefree(myname);
  711. X    if (!fp)
  712. X    return FALSE;
  713. X    if (stio->type &&
  714. X      stio->type != '|' && stio->type != '-' && stio->type != '%') {
  715. X    if (fstat(fileno(fp),&statbuf) < 0) {
  716. X        fclose(fp);
  717. X        return FALSE;
  718. X    }
  719. X    if ((statbuf.st_mode & S_IFMT) != S_IFREG &&
  720. X        (statbuf.st_mode & S_IFMT) != S_IFCHR) {
  721. X        fclose(fp);
  722. X        return FALSE;
  723. X    }
  724. X    }
  725. X    stio->fp = fp;
  726. X    return TRUE;
  727. X}
  728. X
  729. XFILE *
  730. Xnextargv(stab)
  731. Xregister STAB *stab;
  732. X{
  733. X    register STR *str;
  734. X    char *oldname;
  735. X    int filemode,fileuid,filegid;
  736. X
  737. X    while (alen(stab->stab_array) >= 0) {
  738. X    str = ashift(stab->stab_array);
  739. X    str_sset(stab->stab_val,str);
  740. X    STABSET(stab->stab_val);
  741. X    oldname = str_get(stab->stab_val);
  742. X    if (do_open(stab,oldname)) {
  743. X        if (inplace) {
  744. X        filemode = statbuf.st_mode;
  745. X        fileuid = statbuf.st_uid;
  746. X        filegid = statbuf.st_gid;
  747. X        if (*inplace) {
  748. X            str_cat(str,inplace);
  749. X#ifdef RENAME
  750. X            rename(oldname,str->str_ptr);
  751. X#else
  752. X            UNLINK(str->str_ptr);
  753. X            link(oldname,str->str_ptr);
  754. X            UNLINK(oldname);
  755. X#endif
  756. X        }
  757. X        else {
  758. X            UNLINK(oldname);
  759. X        }
  760. X        sprintf(tokenbuf,">%s",oldname);
  761. X        errno = 0;        /* in case sprintf set errno */
  762. X        do_open(argvoutstab,tokenbuf);
  763. X        defoutstab = argvoutstab;
  764. X#ifdef FCHMOD
  765. X        fchmod(fileno(argvoutstab->stab_io->fp),filemode);
  766. X#else
  767. X        chmod(oldname,filemode);
  768. X#endif
  769. X#ifdef FCHOWN
  770. X        fchown(fileno(argvoutstab->stab_io->fp),fileuid,filegid);
  771. X#else
  772. X        chown(oldname,fileuid,filegid);
  773. X#endif
  774. X        }
  775. X        str_free(str);
  776. X        return stab->stab_io->fp;
  777. X    }
  778. X    else
  779. X        fprintf(stderr,"Can't open %s\n",str_get(str));
  780. X    str_free(str);
  781. X    }
  782. X    if (inplace) {
  783. X    do_close(argvoutstab,FALSE);
  784. X    defoutstab = stabent("stdout",TRUE);
  785. X    }
  786. X    return Nullfp;
  787. X}
  788. X
  789. Xbool
  790. Xdo_close(stab,explicit)
  791. XSTAB *stab;
  792. Xbool explicit;
  793. X{
  794. X    bool retval = FALSE;
  795. X    register STIO *stio = stab->stab_io;
  796. X    int status;
  797. X    int tmp;
  798. X
  799. X    if (!stio) {        /* never opened */
  800. X    if (dowarn && explicit)
  801. X        warn("Close on unopened file <%s>",stab->stab_name);
  802. X    return FALSE;
  803. X    }
  804. X    if (stio->fp) {
  805. X    if (stio->type == '|')
  806. X        retval = (pclose(stio->fp) >= 0);
  807. X    else if (stio->type == '-')
  808. X        retval = TRUE;
  809. X    else {
  810. X        retval = (fclose(stio->fp) != EOF);
  811. X        if (stio->type == '%' && stio->subprocess) {
  812. X        while ((tmp = wait(&status)) != stio->subprocess && tmp != -1)
  813. X            ;
  814. X        if (tmp == -1)
  815. X            statusvalue = -1;
  816. X        else
  817. X            statusvalue = (unsigned)status & 0xffff;
  818. X        }
  819. X    }
  820. X    stio->fp = Nullfp;
  821. X    }
  822. X    if (explicit)
  823. X    stio->lines = 0;
  824. X    stio->type = ' ';
  825. X    return retval;
  826. X}
  827. X
  828. Xbool
  829. Xdo_eof(stab)
  830. XSTAB *stab;
  831. X{
  832. X    register STIO *stio;
  833. X    int ch;
  834. X
  835. X    if (!stab)            /* eof() */
  836. X    stio = argvstab->stab_io;
  837. X    else
  838. X    stio = stab->stab_io;
  839. X
  840. X    if (!stio)
  841. X    return TRUE;
  842. X
  843. X    while (stio->fp) {
  844. X
  845. X#ifdef STDSTDIO            /* (the code works without this) */
  846. X    if (stio->fp->_cnt)        /* cheat a little, since */
  847. X        return FALSE;        /* this is the most usual case */
  848. X#endif
  849. X
  850. X    ch = getc(stio->fp);
  851. X    if (ch != EOF) {
  852. X        ungetc(ch, stio->fp);
  853. X        return FALSE;
  854. X    }
  855. X    if (!stab) {            /* not necessarily a real EOF yet? */
  856. X        if (!nextargv(argvstab))    /* get another fp handy */
  857. X        return TRUE;
  858. X    }
  859. X    else
  860. X        return TRUE;        /* normal fp, definitely end of file */
  861. X    }
  862. X    return TRUE;
  863. X}
  864. X
  865. Xlong
  866. Xdo_tell(stab)
  867. XSTAB *stab;
  868. X{
  869. X    register STIO *stio;
  870. X
  871. X    if (!stab)
  872. X    goto phooey;
  873. X
  874. X    stio = stab->stab_io;
  875. X    if (!stio || !stio->fp)
  876. X    goto phooey;
  877. X
  878. X    return ftell(stio->fp);
  879. X
  880. Xphooey:
  881. X    if (dowarn)
  882. X    warn("tell() on unopened file");
  883. X    return -1L;
  884. X}
  885. X
  886. Xbool
  887. Xdo_seek(stab, pos, whence)
  888. XSTAB *stab;
  889. Xlong pos;
  890. Xint whence;
  891. X{
  892. X    register STIO *stio;
  893. X
  894. X    if (!stab)
  895. X    goto nuts;
  896. X
  897. X    stio = stab->stab_io;
  898. X    if (!stio || !stio->fp)
  899. X    goto nuts;
  900. X
  901. X    return fseek(stio->fp, pos, whence) >= 0;
  902. X
  903. Xnuts:
  904. X    if (dowarn)
  905. X    warn("seek() on unopened file");
  906. X    return FALSE;
  907. X}
  908. X
  909. Xstatic CMD *sortcmd;
  910. Xstatic STAB *firststab = Nullstab;
  911. Xstatic STAB *secondstab = Nullstab;
  912. X
  913. Xdo_sort(arg,stab,retary,sarg,ptrmaxsarg,sargoff,cushion)
  914. Xregister ARG *arg;
  915. XSTAB *stab;
  916. XSTR ***retary;
  917. Xregister STR **sarg;
  918. Xint *ptrmaxsarg;
  919. Xint sargoff;
  920. Xint cushion;
  921. X{
  922. X    STR **tmpary;    /* must not be register */
  923. X    register STR **elem;
  924. X    register bool retval;
  925. X    register int max;
  926. X    register int i;
  927. X    int sortcmp();
  928. X    int sortsub();
  929. X    STR *oldfirst;
  930. X    STR *oldsecond;
  931. X
  932. X    (void)eval(arg[1].arg_ptr.arg_arg,&tmpary,-1);
  933. X    max = (int)str_gnum(*tmpary);
  934. X
  935. X    if (retary) {
  936. X    sarg = (STR**)saferealloc((char*)(sarg - sargoff),
  937. X      (max+2+cushion+sargoff)*sizeof(STR*)) + sargoff;
  938. X    for (i = 1; i <= max; i++)
  939. X        sarg[i] = tmpary[i];
  940. X    *retary = sarg;
  941. X    if (max > 1) {
  942. X        if (stab->stab_sub && (sortcmd = stab->stab_sub->cmd)) {
  943. X        if (!firststab) {
  944. X            firststab = stabent("a",TRUE);
  945. X            secondstab = stabent("b",TRUE);
  946. X        }
  947. X        oldfirst = firststab->stab_val;
  948. X        oldsecond = secondstab->stab_val;
  949. X        qsort((char*)(sarg+1),max,sizeof(STR*),sortsub);
  950. X        firststab->stab_val = oldfirst;
  951. X        secondstab->stab_val = oldsecond;
  952. X        }
  953. X        else
  954. X        qsort((char*)(sarg+1),max,sizeof(STR*),sortcmp);
  955. X    }
  956. X    while (max > 0 && !sarg[max])
  957. X        max--;
  958. X    *ptrmaxsarg = max + sargoff;
  959. X    }
  960. X    safefree((char*)tmpary);
  961. X    return max;
  962. X}
  963. X
  964. Xint
  965. Xsortcmp(str1,str2)
  966. XSTR **str1;
  967. XSTR **str2;
  968. X{
  969. X    char *tmps;
  970. X
  971. X    if (!*str1)
  972. X    return -1;
  973. X    if (!*str2)
  974. X    return 1;
  975. X    tmps = str_get(*str1);
  976. X    return strcmp(tmps,str_get(*str2));
  977. X}
  978. X
  979. Xint
  980. Xsortsub(str1,str2)
  981. XSTR **str1;
  982. XSTR **str2;
  983. X{
  984. X    STR *str;
  985. X
  986. X    if (!*str1)
  987. X    return -1;
  988. X    if (!*str2)
  989. X    return 1;
  990. X    firststab->stab_val = *str1;
  991. X    secondstab->stab_val = *str2;
  992. X    return (int)str_gnum(cmd_exec(sortcmd));
  993. X}
  994. X
  995. Xdo_stat(arg,retary,sarg,ptrmaxsarg,sargoff,cushion)
  996. Xregister ARG *arg;
  997. XSTR ***retary;
  998. Xregister STR **sarg;
  999. Xint *ptrmaxsarg;
  1000. Xint sargoff;
  1001. Xint cushion;
  1002. X{
  1003. X    register ARRAY *ary;
  1004. X    static ARRAY *myarray = Null(ARRAY*);
  1005. X    int max = 13;
  1006. X    register int i;
  1007. X
  1008. X    ary = myarray;
  1009. X    if (!ary)
  1010. X    myarray = ary = anew(Nullstab);
  1011. X    ary->ary_fill = -1;
  1012. X    if (arg[1].arg_type == A_LVAL) {
  1013. X    tmpstab = arg[1].arg_ptr.arg_stab;
  1014. X    if (!tmpstab->stab_io ||
  1015. X      fstat(fileno(tmpstab->stab_io->fp),&statbuf) < 0) {
  1016. X        max = 0;
  1017. X    }
  1018. X    }
  1019. X    else
  1020. X    if (stat(str_get(sarg[1]),&statbuf) < 0)
  1021. X        max = 0;
  1022. X
  1023. X    if (retary) {
  1024. X    if (max) {
  1025. X        apush(ary,str_nmake((double)statbuf.st_dev));
  1026. X        apush(ary,str_nmake((double)statbuf.st_ino));
  1027. X        apush(ary,str_nmake((double)statbuf.st_mode));
  1028. X        apush(ary,str_nmake((double)statbuf.st_nlink));
  1029. X        apush(ary,str_nmake((double)statbuf.st_uid));
  1030. X        apush(ary,str_nmake((double)statbuf.st_gid));
  1031. X        apush(ary,str_nmake((double)statbuf.st_rdev));
  1032. X        apush(ary,str_nmake((double)statbuf.st_size));
  1033. X        apush(ary,str_nmake((double)statbuf.st_atime));
  1034. X        apush(ary,str_nmake((double)statbuf.st_mtime));
  1035. X        apush(ary,str_nmake((double)statbuf.st_ctime));
  1036. X#ifdef STATBLOCKS
  1037. X        apush(ary,str_nmake((double)statbuf.st_blksize));
  1038. X        apush(ary,str_nmake((double)statbuf.st_blocks));
  1039. X#else
  1040. X        apush(ary,str_make(""));
  1041. X        apush(ary,str_make(""));
  1042. X#endif
  1043. X    }
  1044. X    *ptrmaxsarg = max + sargoff;
  1045. X    sarg = (STR**)saferealloc((char*)(sarg - sargoff),
  1046. X      (max+2+cushion+sargoff)*sizeof(STR*)) + sargoff;
  1047. X    for (i = 1; i <= max; i++)
  1048. X        sarg[i] = afetch(ary,i-1);
  1049. X    *retary = sarg;
  1050. X    }
  1051. X    return max;
  1052. X}
  1053. X
  1054. Xdo_tms(retary,sarg,ptrmaxsarg,sargoff,cushion)
  1055. XSTR ***retary;
  1056. XSTR **sarg;
  1057. Xint *ptrmaxsarg;
  1058. Xint sargoff;
  1059. Xint cushion;
  1060. X{
  1061. X    register ARRAY *ary;
  1062. X    static ARRAY *myarray = Null(ARRAY*);
  1063. X    int max = 4;
  1064. X    register int i;
  1065. X
  1066. X    ary = myarray;
  1067. X    if (!ary)
  1068. X    myarray = ary = anew(Nullstab);
  1069. X    ary->ary_fill = -1;
  1070. X    times(×buf);
  1071. X
  1072. X#ifndef HZ
  1073. X#define HZ 60
  1074. X#endif
  1075. X
  1076. X    if (retary) {
  1077. X    if (max) {
  1078. X        apush(ary,str_nmake(((double)timesbuf.tms_utime)/HZ));
  1079. X        apush(ary,str_nmake(((double)timesbuf.tms_stime)/HZ));
  1080. X        apush(ary,str_nmake(((double)timesbuf.tms_cutime)/HZ));
  1081. X        apush(ary,str_nmake(((double)timesbuf.tms_cstime)/HZ));
  1082. X    }
  1083. X    *ptrmaxsarg = max + sargoff;
  1084. X    sarg = (STR**)saferealloc((char*)(sarg - sargoff),
  1085. X      (max+2+cushion+sargoff)*sizeof(STR*)) + sargoff;
  1086. X    for (i = 1; i <= max; i++)
  1087. X        sarg[i] = afetch(ary,i-1);
  1088. X    *retary = sarg;
  1089. X    }
  1090. X    return max;
  1091. X}
  1092. X
  1093. Xdo_time(tmbuf,retary,sarg,ptrmaxsarg,sargoff,cushion)
  1094. Xstruct tm *tmbuf;
  1095. XSTR ***retary;
  1096. XSTR **sarg;
  1097. Xint *ptrmaxsarg;
  1098. Xint sargoff;
  1099. Xint cushion;
  1100. X{
  1101. X    register ARRAY *ary;
  1102. X    static ARRAY *myarray = Null(ARRAY*);
  1103. X    int max = 9;
  1104. X    register int i;
  1105. X
  1106. X    ary = myarray;
  1107. X    if (!ary)
  1108. X    myarray = ary = anew(Nullstab);
  1109. X    ary->ary_fill = -1;
  1110. X    if (!tmbuf)
  1111. X    max = 0;
  1112. X
  1113. X    if (retary) {
  1114. X    if (max) {
  1115. X        apush(ary,str_nmake((double)tmbuf->tm_sec));
  1116. X        apush(ary,str_nmake((double)tmbuf->tm_min));
  1117. X        apush(ary,str_nmake((double)tmbuf->tm_hour));
  1118. X        apush(ary,str_nmake((double)tmbuf->tm_mday));
  1119. X        apush(ary,str_nmake((double)tmbuf->tm_mon));
  1120. X        apush(ary,str_nmake((double)tmbuf->tm_year));
  1121. X        apush(ary,str_nmake((double)tmbuf->tm_wday));
  1122. X        apush(ary,str_nmake((double)tmbuf->tm_yday));
  1123. X        apush(ary,str_nmake((double)tmbuf->tm_isdst));
  1124. X    }
  1125. X    *ptrmaxsarg = max + sargoff;
  1126. X    sarg = (STR**)saferealloc((char*)(sarg - sargoff),
  1127. X      (max+2+cushion+sargoff)*sizeof(STR*)) + sargoff;
  1128. X    for (i = 1; i <= max; i++)
  1129. X        sarg[i] = afetch(ary,i-1);
  1130. X    *retary = sarg;
  1131. X    }
  1132. X    return max;
  1133. X}
  1134. X
  1135. Xvoid
  1136. Xdo_sprintf(str,len,sarg)
  1137. Xregister STR *str;
  1138. Xregister int len;
  1139. Xregister STR **sarg;
  1140. X{
  1141. X    register char *s;
  1142. X    register char *t;
  1143. X    bool dolong;
  1144. X    char ch;
  1145. X    static STR *sargnull = &str_no;
  1146. X
  1147. X    str_set(str,"");
  1148. X    len--;            /* don't count pattern string */
  1149. X    sarg++;
  1150. X    for (s = str_get(*(sarg++)); *s; len--) {
  1151. X    if (len <= 0 || !*sarg) {
  1152. X        sarg = &sargnull;
  1153. X        len = 0;
  1154. X    }
  1155. X    dolong = FALSE;
  1156. X    for (t = s; *t && *t != '%'; t++) ;
  1157. X    if (!*t)
  1158. X        break;        /* not enough % patterns, oh well */
  1159. X    for (t++; *sarg && *t && t != s; t++) {
  1160. X        switch (*t) {
  1161. X        case '\0':
  1162. X        t--;
  1163. X        break;
  1164. X        case '%':
  1165. X        ch = *(++t);
  1166. X        *t = '\0';
  1167. X        sprintf(buf,s);
  1168. X        s = t;
  1169. X        *(t--) = ch;
  1170. X        break;
  1171. X        case 'l':
  1172. X        dolong = TRUE;
  1173. X        break;
  1174. X        case 'D': case 'X': case 'O':
  1175. X        dolong = TRUE;
  1176. X        /* FALL THROUGH */
  1177. X        case 'd': case 'x': case 'o': case 'c': case 'u':
  1178. X        ch = *(++t);
  1179. X        *t = '\0';
  1180. X        if (dolong)
  1181. X            sprintf(buf,s,(long)str_gnum(*(sarg++)));
  1182. X        else
  1183. X            sprintf(buf,s,(int)str_gnum(*(sarg++)));
  1184. X        s = t;
  1185. X        *(t--) = ch;
  1186. X        break;
  1187. X        case 'E': case 'e': case 'f': case 'G': case 'g':
  1188. X        ch = *(++t);
  1189. X        *t = '\0';
  1190. X        sprintf(buf,s,str_gnum(*(sarg++)));
  1191. X        s = t;
  1192. X        *(t--) = ch;
  1193. X        break;
  1194. X        case 's':
  1195. X        ch = *(++t);
  1196. X        *t = '\0';
  1197. X        if (strEQ(s,"%s")) {    /* some printfs fail on >128 chars */
  1198. X            *buf = '\0';
  1199. X            str_scat(str,*(sarg++));  /* so handle simple case */
  1200. X        }
  1201. X        else
  1202. X            sprintf(buf,s,str_get(*(sarg++)));
  1203. X        s = t;
  1204. X        *(t--) = ch;
  1205. X        break;
  1206. X        }
  1207. X    }
  1208. X    str_cat(str,buf);
  1209. X    }
  1210. X    if (*s)
  1211. X    str_cat(str,s);
  1212. X    STABSET(str);
  1213. X}
  1214. X
  1215. Xbool
  1216. Xdo_print(str,fp)
  1217. Xregister STR *str;
  1218. XFILE *fp;
  1219. X{
  1220. X    if (!fp) {
  1221. X    if (dowarn)
  1222. X        warn("print to unopened file");
  1223. X    return FALSE;
  1224. X    }
  1225. X    if (!str)
  1226. X    return FALSE;
  1227. X    if (ofmt &&
  1228. X      ((str->str_nok && str->str_nval != 0.0) || str_gnum(str) != 0.0) )
  1229. X    fprintf(fp, ofmt, str->str_nval);
  1230. X    else
  1231. X    fputs(str_get(str),fp);
  1232. X    return TRUE;
  1233. X}
  1234. X
  1235. Xbool
  1236. Xdo_aprint(arg,fp)
  1237. Xregister ARG *arg;
  1238. Xregister FILE *fp;
  1239. X{
  1240. X    STR **tmpary;    /* must not be register */
  1241. X    register STR **elem;
  1242. X    register bool retval;
  1243. X    register int items;
  1244. X
  1245. X    if (!fp) {
  1246. X    if (dowarn)
  1247. X        warn("print to unopened file");
  1248. X    return FALSE;
  1249. X    }
  1250. X    (void)eval(arg[1].arg_ptr.arg_arg,&tmpary,-1);
  1251. X    items = (int)str_gnum(*tmpary);
  1252. X    if (arg->arg_type == O_PRTF) {
  1253. X    do_sprintf(arg->arg_ptr.arg_str,items,tmpary);
  1254. X    retval = do_print(arg->arg_ptr.arg_str,fp);
  1255. X    }
  1256. X    else {
  1257. X    retval = FALSE;
  1258. X    for (elem = tmpary+1; items > 0; items--,elem++) {
  1259. X        if (retval && ofs)
  1260. X        fputs(ofs, fp);
  1261. X        retval = do_print(*elem, fp);
  1262. X        if (!retval)
  1263. X        break;
  1264. X    }
  1265. X    if (ors)
  1266. X        fputs(ors, fp);
  1267. X    }
  1268. X    safefree((char*)tmpary);
  1269. X    return retval;
  1270. X}
  1271. X
  1272. Xbool
  1273. Xdo_aexec(arg)
  1274. Xregister ARG *arg;
  1275. X{
  1276. X    STR **tmpary;    /* must not be register */
  1277. X    register STR **elem;
  1278. X    register char **a;
  1279. X    register int items;
  1280. X    char **argv;
  1281. X
  1282. X    (void)eval(arg[1].arg_ptr.arg_arg,&tmpary,-1);
  1283. X    items = (int)str_gnum(*tmpary);
  1284. X    if (items) {
  1285. X    argv = (char**)safemalloc((items+1)*sizeof(char*));
  1286. X    a = argv;
  1287. X    for (elem = tmpary+1; items > 0; items--,elem++) {
  1288. X        if (*elem)
  1289. X        *a++ = str_get(*elem);
  1290. X        else
  1291. X        *a++ = "";
  1292. X    }
  1293. X    *a = Nullch;
  1294. X    execvp(argv[0],argv);
  1295. X    safefree((char*)argv);
  1296. X    }
  1297. X    safefree((char*)tmpary);
  1298. X    return FALSE;
  1299. X}
  1300. X
  1301. Xbool
  1302. Xdo_exec(str)
  1303. XSTR *str;
  1304. X{
  1305. X    register char **a;
  1306. X    register char *s;
  1307. X    char **argv;
  1308. X    char *cmd = str_get(str);
  1309. X
  1310. X    /* see if there are shell metacharacters in it */
  1311. X
  1312. X    for (s = cmd; *s; s++) {
  1313. X    if (*s != ' ' && !isalpha(*s) && index("$&*(){}[]'\";\\|?<>~`",*s)) {
  1314. X        execl("/bin/sh","sh","-c",cmd,(char*)0);
  1315. X        return FALSE;
  1316. X    }
  1317. X    }
  1318. X    argv = (char**)safemalloc(((s - cmd) / 2 + 2)*sizeof(char*));
  1319. X
  1320. X    a = argv;
  1321. X    for (s = cmd; *s;) {
  1322. X    while (isspace(*s)) s++;
  1323. X    if (*s)
  1324. X        *(a++) = s;
  1325. X    while (*s && !isspace(*s)) s++;
  1326. X    if (*s)
  1327. X        *s++ = '\0';
  1328. X    }
  1329. X    *a = Nullch;
  1330. X    if (argv[0])
  1331. X    execvp(argv[0],argv);
  1332. X    safefree((char*)argv);
  1333. X    return FALSE;
  1334. X}
  1335. X
  1336. XSTR *
  1337. Xdo_push(arg,ary)
  1338. Xregister ARG *arg;
  1339. Xregister ARRAY *ary;
  1340. X{
  1341. X    STR **tmpary;    /* must not be register */
  1342. X    register STR **elem;
  1343. X    register STR *str = &str_no;
  1344. X    register int items;
  1345. X
  1346. X    (void)eval(arg[1].arg_ptr.arg_arg,&tmpary,-1);
  1347. X    items = (int)str_gnum(*tmpary);
  1348. X    for (elem = tmpary+1; items > 0; items--,elem++) {
  1349. X    str = str_new(0);
  1350. X    if (*elem)
  1351. X        str_sset(str,*elem);
  1352. X    apush(ary,str);
  1353. X    }
  1354. X    safefree((char*)tmpary);
  1355. X    return str;
  1356. X}
  1357. X
  1358. Xdo_unshift(arg,ary)
  1359. Xregister ARG *arg;
  1360. Xregister ARRAY *ary;
  1361. X{
  1362. X    STR **tmpary;    /* must not be register */
  1363. X    register STR **elem;
  1364. X    register STR *str = &str_no;
  1365. X    register int i;
  1366. X    register int items;
  1367. X
  1368. X    (void)eval(arg[1].arg_ptr.arg_arg,&tmpary,-1);
  1369. X    items = (int)str_gnum(*tmpary);
  1370. X    aunshift(ary,items);
  1371. X    i = 0;
  1372. X    for (elem = tmpary+1; i < items; i++,elem++) {
  1373. X    str = str_new(0);
  1374. X    str_sset(str,*elem);
  1375. X    astore(ary,i,str);
  1376. X    }
  1377. X    safefree((char*)tmpary);
  1378. X}
  1379. X
  1380. Xapply(type,arg,sarg)
  1381. Xint type;
  1382. Xregister ARG *arg;
  1383. XSTR **sarg;
  1384. X{
  1385. X    STR **tmpary;    /* must not be register */
  1386. X    register STR **elem;
  1387. X    register int items;
  1388. X    register int val;
  1389. X    register int val2;
  1390. X    char *s;
  1391. X
  1392. X    if (sarg) {
  1393. X    tmpary = sarg;
  1394. X    items = 0;
  1395. X    for (elem = tmpary+1; *elem; elem++)
  1396. X        items++;
  1397. X    }
  1398. X    else {
  1399. X    (void)eval(arg[1].arg_ptr.arg_arg,&tmpary,-1);
  1400. X    items = (int)str_gnum(*tmpary);
  1401. X    }
  1402. X    switch (type) {
  1403. X    case O_CHMOD:
  1404. X    if (--items > 0) {
  1405. X        val = (int)str_gnum(tmpary[1]);
  1406. X        for (elem = tmpary+2; *elem; elem++)
  1407. X        if (chmod(str_get(*elem),val))
  1408. X            items--;
  1409. X    }
  1410. X    break;
  1411. X    case O_CHOWN:
  1412. X    if (items > 2) {
  1413. X        items -= 2;
  1414. X        val = (int)str_gnum(tmpary[1]);
  1415. X        val2 = (int)str_gnum(tmpary[2]);
  1416. X        for (elem = tmpary+3; *elem; elem++)
  1417. X        if (chown(str_get(*elem),val,val2))
  1418. X            items--;
  1419. X    }
  1420. X    else
  1421. X        items = 0;
  1422. X    break;
  1423. X    case O_KILL:
  1424. X    if (--items > 0) {
  1425. X        val = (int)str_gnum(tmpary[1]);
  1426. X        if (val < 0) {
  1427. X        val = -val;
  1428. X        for (elem = tmpary+2; *elem; elem++)
  1429. X#ifdef KILLPG
  1430. X            if (killpg((int)(str_gnum(*elem)),val))    /* BSD */
  1431. X#else
  1432. X            if (kill(-(int)(str_gnum(*elem)),val))    /* SYSV */
  1433. X#endif
  1434. X            items--;
  1435. X        }
  1436. X        else {
  1437. X        for (elem = tmpary+2; *elem; elem++)
  1438. X            if (kill((int)(str_gnum(*elem)),val))
  1439. X            items--;
  1440. X        }
  1441. X    }
  1442. X    break;
  1443. X    case O_UNLINK:
  1444. X    for (elem = tmpary+1; *elem; elem++) {
  1445. X        s = str_get(*elem);
  1446. X        if (euid || unsafe) {
  1447. X        if (UNLINK(s))
  1448. X            items--;
  1449. X        }
  1450. X        else {    /* don't let root wipe out directories without -U */
  1451. X        if (stat(s,&statbuf) < 0 ||
  1452. X          (statbuf.st_mode & S_IFMT) == S_IFDIR )
  1453. X            items--;
  1454. X        else {
  1455. X            if (UNLINK(s))
  1456. X            items--;
  1457. X        }
  1458. X        }
  1459. X    }
  1460. X    break;
  1461. X    case O_UTIME:
  1462. X    if (items > 2) {
  1463. X        struct {
  1464. X        long    atime,
  1465. X            mtime;
  1466. X        } utbuf;
  1467. X
  1468. X        utbuf.atime = (long)str_gnum(tmpary[1]);    /* time accessed */
  1469. X        utbuf.mtime = (long)str_gnum(tmpary[2]);    /* time modified */
  1470. X        items -= 2;
  1471. X        for (elem = tmpary+3; *elem; elem++)
  1472. X        if (utime(str_get(*elem),&utbuf))
  1473. X            items--;
  1474. X    }
  1475. X    else
  1476. X        items = 0;
  1477. X    break;
  1478. X    }
  1479. X    if (!sarg)
  1480. X    safefree((char*)tmpary);
  1481. X    return items;
  1482. X}
  1483. X
  1484. XSTR *
  1485. Xdo_subr(arg,sarg)
  1486. Xregister ARG *arg;
  1487. Xregister STR **sarg;
  1488. X{
  1489. X    register SUBR *sub;
  1490. X    ARRAY *savearray;
  1491. X    STR *str;
  1492. X    STAB *stab;
  1493. X    char *oldfile = filename;
  1494. X    int oldsave = savestack->ary_fill;
  1495. X    int oldtmps_base = tmps_base;
  1496. X
  1497. X    if (arg[2].arg_type == A_WORD)
  1498. X    stab = arg[2].arg_ptr.arg_stab;
  1499. X    else
  1500. X    stab = stabent(str_get(arg[2].arg_ptr.arg_stab->stab_val),TRUE);
  1501. X    if (!stab) {
  1502. X    if (dowarn)
  1503. X        warn("Undefined subroutine called");
  1504. X    return &str_no;
  1505. X    }
  1506. X    sub = stab->stab_sub;
  1507. X    if (!sub) {
  1508. X    if (dowarn)
  1509. X        warn("Undefined subroutine \"%s\" called", stab->stab_name);
  1510. X    return &str_no;
  1511. X    }
  1512. X    savearray = defstab->stab_array;
  1513. X    defstab->stab_array = anew(defstab);
  1514. X    if (arg[1].arg_flags & AF_SPECIAL)
  1515. X    (void)do_push(arg,defstab->stab_array);
  1516. X    else if (arg[1].arg_type != A_NULL) {
  1517. X    str = str_new(0);
  1518. X    str_sset(str,sarg[1]);
  1519. X    apush(defstab->stab_array,str);
  1520. X    }
  1521. X    sub->depth++;
  1522. X    if (sub->depth >= 2) {    /* save temporaries on recursion? */
  1523. X    if (sub->depth == 100 && dowarn)
  1524. X        warn("Deep recursion on subroutine \"%s\"",stab->stab_name);
  1525. X    savelist(sub->tosave->ary_array,sub->tosave->ary_fill);
  1526. X    }
  1527. X    filename = sub->filename;
  1528. X    tmps_base = tmps_max;
  1529. X
  1530. X    str = cmd_exec(sub->cmd);        /* so do it already */
  1531. X
  1532. X    sub->depth--;    /* assuming no longjumps out of here */
  1533. X    afree(defstab->stab_array);  /* put back old $_[] */
  1534. X    defstab->stab_array = savearray;
  1535. X    filename = oldfile;
  1536. X    tmps_base = oldtmps_base;
  1537. X    if (savestack->ary_fill > oldsave) {
  1538. X    str = str_static(str);    /* in case restore wipes old str */
  1539. X    restorelist(oldsave);
  1540. X    }
  1541. X    return str;
  1542. X}
  1543. X
  1544. Xvoid
  1545. Xdo_assign(retstr,arg,sarg)
  1546. XSTR *retstr;
  1547. Xregister ARG *arg;
  1548. Xregister STR **sarg;
  1549. X{
  1550. X    STR **tmpary;    /* must not be register */
  1551. X    register ARG *larg = arg[1].arg_ptr.arg_arg;
  1552. X    register STR **elem;
  1553. X    register STR *str;
  1554. X    register ARRAY *ary;
  1555. X    register int i;
  1556. X    register int items;
  1557. X    STR *tmpstr;
  1558. X
  1559. X    if (arg[2].arg_flags & AF_SPECIAL) {
  1560. X    (void)eval(arg[2].arg_ptr.arg_arg,&tmpary,-1);
  1561. X    items = (int)str_gnum(*tmpary);
  1562. X    }
  1563. X    else {
  1564. X    tmpary = sarg;
  1565. X    sarg[1] = sarg[2];
  1566. X    sarg[2] = Nullstr;
  1567. X    items = 1;
  1568. X    }
  1569. X
  1570. X    if (arg->arg_flags & AF_COMMON) {    /* always true currently, alas */
  1571. X    if (*(tmpary+1)) {
  1572. X        for (i=2,elem=tmpary+2; i <= items; i++,elem++) {
  1573. X        *elem = str_static(*elem);
  1574. X        }
  1575. X    }
  1576. X    }
  1577. X    if (larg->arg_type == O_LIST) {
  1578. X    for (i=1,elem=tmpary+1; i <= larg->arg_len; i++) {
  1579. X        switch (larg[i].arg_type) {
  1580. X        case A_STAB:
  1581. X        case A_LVAL:
  1582. X        str = STAB_STR(larg[i].arg_ptr.arg_stab);
  1583. X        break;
  1584. X        case A_LEXPR:
  1585. X        str = eval(larg[i].arg_ptr.arg_arg,Null(STR***),-1);
  1586. X        break;
  1587. X        }
  1588. X        if (larg->arg_flags & AF_LOCAL) {
  1589. X        apush(savestack,str);    /* save pointer */
  1590. X        tmpstr = str_new(0);
  1591. X        str_sset(tmpstr,str);
  1592. X        apush(savestack,tmpstr); /* save value */
  1593. X        }
  1594. X        if (*elem)
  1595. X        str_sset(str,*(elem++));
  1596. X        else
  1597. X        str_set(str,"");
  1598. X        STABSET(str);
  1599. X    }
  1600. X    }
  1601. X    else {            /* should be an array name */
  1602. X    ary = larg[1].arg_ptr.arg_stab->stab_array;
  1603. X    for (i=0,elem=tmpary+1; i < items; i++) {
  1604. X        str = str_new(0);
  1605. X        if (*elem)
  1606. X        str_sset(str,*(elem++));
  1607. X        astore(ary,i,str);
  1608. X    }
  1609. X    ary->ary_fill = items - 1;/* they can get the extra ones back by */
  1610. X    }                /*   setting $#ary larger than old fill */
  1611. X    str_numset(retstr,(double)items);
  1612. X    STABSET(retstr);
  1613. X    if (tmpary != sarg);
  1614. X    safefree((char*)tmpary);
  1615. X}
  1616. X
  1617. Xint
  1618. Xdo_kv(hash,kv,retary,sarg,ptrmaxsarg,sargoff,cushion)
  1619. XHASH *hash;
  1620. Xint kv;
  1621. XSTR ***retary;
  1622. Xregister STR **sarg;
  1623. Xint *ptrmaxsarg;
  1624. Xint sargoff;
  1625. Xint cushion;
  1626. X{
  1627. X    register ARRAY *ary;
  1628. X    int max = 0;
  1629. X    int i;
  1630. X    static ARRAY *myarray = Null(ARRAY*);
  1631. X    register HENT *entry;
  1632. X
  1633. X    ary = myarray;
  1634. X    if (!ary)
  1635. X    myarray = ary = anew(Nullstab);
  1636. X    ary->ary_fill = -1;
  1637. X
  1638. X    hiterinit(hash);
  1639. X    while (entry = hiternext(hash)) {
  1640. X    max++;
  1641. X    if (kv == O_KEYS)
  1642. X        apush(ary,str_make(hiterkey(entry)));
  1643. X    else
  1644. X        apush(ary,str_make(str_get(hiterval(entry))));
  1645. X    }
  1646. X    if (retary) { /* array wanted */
  1647. X    *ptrmaxsarg = max + sargoff;
  1648. X    sarg = (STR**)saferealloc((char*)(sarg - sargoff),
  1649. X      (max+2+cushion+sargoff)*sizeof(STR*)) + sargoff;
  1650. X    for (i = 1; i <= max; i++)
  1651. X        sarg[i] = afetch(ary,i-1);
  1652. X    *retary = sarg;
  1653. X    }
  1654. X    return max;
  1655. X}
  1656. X
  1657. XSTR *
  1658. Xdo_each(hash,retary,sarg,ptrmaxsarg,sargoff,cushion)
  1659. XHASH *hash;
  1660. XSTR ***retary;
  1661. XSTR **sarg;
  1662. Xint *ptrmaxsarg;
  1663. Xint sargoff;
  1664. Xint cushion;
  1665. X{
  1666. X    static STR *mystr = Nullstr;
  1667. X    STR *retstr;
  1668. X    HENT *entry = hiternext(hash);
  1669. X
  1670. X    if (mystr) {
  1671. X    str_free(mystr);
  1672. X    mystr = Nullstr;
  1673. X    }
  1674. X
  1675. X    if (retary) { /* array wanted */
  1676. X    if (entry) {
  1677. X        *ptrmaxsarg = 2 + sargoff;
  1678. X        sarg = (STR**)saferealloc((char*)(sarg - sargoff),
  1679. X          (2+2+cushion+sargoff)*sizeof(STR*)) + sargoff;
  1680. X        sarg[1] = mystr = str_make(hiterkey(entry));
  1681. X        retstr = sarg[2] = hiterval(entry);
  1682. X        *retary = sarg;
  1683. X    }
  1684. X    else {
  1685. X        *ptrmaxsarg = sargoff;
  1686. X        sarg = (STR**)saferealloc((char*)(sarg - sargoff),
  1687. X          (2+cushion+sargoff)*sizeof(STR*)) + sargoff;
  1688. X        retstr = Nullstr;
  1689. X        *retary = sarg;
  1690. X    }
  1691. X    }
  1692. X    else
  1693. X    retstr = hiterval(entry);
  1694. X    
  1695. X    return retstr;
  1696. X}
  1697. X
  1698. Xint
  1699. Xmystat(arg,str)
  1700. XARG *arg;
  1701. XSTR *str;
  1702. X{
  1703. X    STIO *stio;
  1704. X
  1705. X    if (arg[1].arg_flags & AF_SPECIAL) {
  1706. X    stio = arg[1].arg_ptr.arg_stab->stab_io;
  1707. X    if (stio && stio->fp)
  1708. X        return fstat(fileno(stio->fp), &statbuf);
  1709. X    else {
  1710. X        if (dowarn)
  1711. X        warn("Stat on unopened file <%s>",
  1712. X          arg[1].arg_ptr.arg_stab->stab_name);
  1713. X        return -1;
  1714. X    }
  1715. X    }
  1716. X    else
  1717. X    return stat(str_get(str),&statbuf);
  1718. X}
  1719. X
  1720. XSTR *
  1721. Xdo_fttext(arg,str)
  1722. Xregister ARG *arg;
  1723. XSTR *str;
  1724. X{
  1725. X    int i;
  1726. X    int len;
  1727. X    int odd = 0;
  1728. X    STDCHAR tbuf[512];
  1729. X    register STDCHAR *s;
  1730. X    register STIO *stio;
  1731. X
  1732. X    if (arg[1].arg_flags & AF_SPECIAL) {
  1733. X    stio = arg[1].arg_ptr.arg_stab->stab_io;
  1734. X    if (stio && stio->fp) {
  1735. X#ifdef STDSTDIO
  1736. X        if (stio->fp->_cnt <= 0) {
  1737. X        i = getc(stio->fp);
  1738. X        ungetc(i,stio->fp);
  1739. X        }
  1740. X        if (stio->fp->_cnt <= 0)    /* null file is anything */
  1741. X        return &str_yes;
  1742. X        len = stio->fp->_cnt + (stio->fp->_ptr - stio->fp->_base);
  1743. X        s = stio->fp->_base;
  1744. X#else
  1745. X        fatal("-T and -B not implemented on filehandles\n");
  1746. X#endif
  1747. X    }
  1748. X    else {
  1749. X        if (dowarn)
  1750. X        warn("Test on unopened file <%s>",
  1751. X          arg[1].arg_ptr.arg_stab->stab_name);
  1752. X        return &str_no;
  1753. X    }
  1754. X    }
  1755. X    else {
  1756. X    i = open(str_get(str),0);
  1757. X    if (i < 0)
  1758. X        return &str_no;
  1759. X    len = read(i,tbuf,512);
  1760. X    if (len <= 0)        /* null file is anything */
  1761. X        return &str_yes;
  1762. X    close(i);
  1763. X    s = tbuf;
  1764. X    }
  1765. X
  1766. X    /* now scan s to look for textiness */
  1767. X
  1768. X    for (i = 0; i < len; i++,s++) {
  1769. X    if (!*s) {            /* null never allowed in text */
  1770. X        odd += len;
  1771. X        break;
  1772. X    }
  1773. X    else if (*s & 128)
  1774. X        odd++;
  1775. X    else if (*s < 32 &&
  1776. X      *s != '\n' && *s != '\r' && *s != '\b' &&
  1777. X      *s != '\t' && *s != '\f' && *s != 27)
  1778. X        odd++;
  1779. X    }
  1780. X
  1781. X    if ((odd * 10 > len) == (arg->arg_type == O_FTTEXT)) /* allow 10% odd */
  1782. X    return &str_no;
  1783. X    else
  1784. X    return &str_yes;
  1785. X}
  1786. X
  1787. Xint
  1788. Xdo_study(str)
  1789. XSTR *str;
  1790. X{
  1791. X    register char *s = str_get(str);
  1792. X    register int pos = str->str_cur;
  1793. X    register int ch;
  1794. X    register int *sfirst;
  1795. X    register int *snext;
  1796. X    static int maxscream = -1;
  1797. X    static STR *lastscream = Nullstr;
  1798. X
  1799. X    if (lastscream && lastscream->str_pok == 5)
  1800. X    lastscream->str_pok &= ~4;
  1801. X    lastscream = str;
  1802. X    if (pos <= 0)
  1803. X    return 0;
  1804. X    if (pos > maxscream) {
  1805. X    if (maxscream < 0) {
  1806. X        maxscream = pos + 80;
  1807. X        screamfirst = (int*)safemalloc((MEM_SIZE)(256 * sizeof(int)));
  1808. X        screamnext = (int*)safemalloc((MEM_SIZE)(maxscream * sizeof(int)));
  1809. X    }
  1810. X    else {
  1811. X        maxscream = pos + pos / 4;
  1812. X        screamnext = (int*)saferealloc((char*)screamnext,
  1813. X        (MEM_SIZE)(maxscream * sizeof(int)));
  1814. X    }
  1815. X    }
  1816. X
  1817. X    sfirst = screamfirst;
  1818. X    snext = screamnext;
  1819. X
  1820. X    if (!sfirst || !snext)
  1821. X    fatal("do_study: out of memory");
  1822. X
  1823. X    for (ch = 256; ch; --ch)
  1824. X    *sfirst++ = -1;
  1825. X    sfirst -= 256;
  1826. X
  1827. X    while (--pos >= 0) {
  1828. X    ch = s[pos];
  1829. X    if (sfirst[ch] >= 0)
  1830. X        snext[pos] = sfirst[ch] - pos;
  1831. X    else
  1832. X        snext[pos] = -pos;
  1833. X    sfirst[ch] = pos;
  1834. X    }
  1835. X
  1836. X    str->str_pok |= 4;
  1837. X    return 1;
  1838. X}
  1839. X
  1840. Xinit_eval()
  1841. X{
  1842. X#define A(e1,e2,e3) (e1+(e2<<1)+(e3<<2))
  1843. X    opargs[O_ITEM] =        A(1,0,0);
  1844. X    opargs[O_ITEM2] =        A(0,0,0);
  1845. X    opargs[O_ITEM3] =        A(0,0,0);
  1846. X    opargs[O_CONCAT] =        A(1,1,0);
  1847. X    opargs[O_MATCH] =        A(1,0,0);
  1848. X    opargs[O_NMATCH] =        A(1,0,0);
  1849. X    opargs[O_SUBST] =        A(1,0,0);
  1850. X    opargs[O_NSUBST] =        A(1,0,0);
  1851. X    opargs[O_ASSIGN] =        A(1,1,0);
  1852. X    opargs[O_MULTIPLY] =    A(1,1,0);
  1853. X    opargs[O_DIVIDE] =        A(1,1,0);
  1854. X    opargs[O_MODULO] =        A(1,1,0);
  1855. X    opargs[O_ADD] =        A(1,1,0);
  1856. X    opargs[O_SUBTRACT] =    A(1,1,0);
  1857. X    opargs[O_LEFT_SHIFT] =    A(1,1,0);
  1858. X    opargs[O_RIGHT_SHIFT] =    A(1,1,0);
  1859. X    opargs[O_LT] =        A(1,1,0);
  1860. X    opargs[O_GT] =        A(1,1,0);
  1861. X    opargs[O_LE] =        A(1,1,0);
  1862. X    opargs[O_GE] =        A(1,1,0);
  1863. X    opargs[O_EQ] =        A(1,1,0);
  1864. X    opargs[O_NE] =        A(1,1,0);
  1865. X    opargs[O_BIT_AND] =        A(1,1,0);
  1866. X    opargs[O_XOR] =        A(1,1,0);
  1867. X    opargs[O_BIT_OR] =        A(1,1,0);
  1868. X    opargs[O_AND] =        A(1,0,0);    /* don't eval arg 2 (yet) */
  1869. X    opargs[O_OR] =        A(1,0,0);    /* don't eval arg 2 (yet) */
  1870. X    opargs[O_COND_EXPR] =    A(1,0,0);    /* don't eval args 2 or 3 */
  1871. X    opargs[O_COMMA] =        A(1,1,0);
  1872. X    opargs[O_NEGATE] =        A(1,0,0);
  1873. X    opargs[O_NOT] =        A(1,0,0);
  1874. X    opargs[O_COMPLEMENT] =    A(1,0,0);
  1875. X    opargs[O_WRITE] =        A(1,0,0);
  1876. X    opargs[O_OPEN] =        A(1,1,0);
  1877. X    opargs[O_TRANS] =        A(1,0,0);
  1878. X    opargs[O_NTRANS] =        A(1,0,0);
  1879. X    opargs[O_CLOSE] =        A(0,0,0);
  1880. X    opargs[O_ARRAY] =        A(1,0,0);
  1881. X    opargs[O_HASH] =        A(1,0,0);
  1882. X    opargs[O_LARRAY] =        A(1,0,0);
  1883. X    opargs[O_LHASH] =        A(1,0,0);
  1884. X    opargs[O_PUSH] =        A(1,0,0);
  1885. X    opargs[O_POP] =        A(0,0,0);
  1886. X    opargs[O_SHIFT] =        A(0,0,0);
  1887. X    opargs[O_SPLIT] =        A(1,0,0);
  1888. X    opargs[O_LENGTH] =        A(1,0,0);
  1889. X    opargs[O_SPRINTF] =        A(1,0,0);
  1890. X    opargs[O_SUBSTR] =        A(1,1,1);
  1891. X    opargs[O_JOIN] =        A(1,0,0);
  1892. X    opargs[O_SLT] =        A(1,1,0);
  1893. X    opargs[O_SGT] =        A(1,1,0);
  1894. X    opargs[O_SLE] =        A(1,1,0);
  1895. X    opargs[O_SGE] =        A(1,1,0);
  1896. X    opargs[O_SEQ] =        A(1,1,0);
  1897. X    opargs[O_SNE] =        A(1,1,0);
  1898. X    opargs[O_SUBR] =        A(1,0,0);
  1899. X    opargs[O_PRINT] =        A(1,1,0);
  1900. X    opargs[O_CHDIR] =        A(1,0,0);
  1901. X    opargs[O_DIE] =        A(1,0,0);
  1902. X    opargs[O_EXIT] =        A(1,0,0);
  1903. X    opargs[O_RESET] =        A(1,0,0);
  1904. X    opargs[O_LIST] =        A(0,0,0);
  1905. X    opargs[O_EOF] =        A(1,0,0);
  1906. X    opargs[O_TELL] =        A(1,0,0);
  1907. X    opargs[O_SEEK] =        A(1,1,1);
  1908. X    opargs[O_LAST] =        A(1,0,0);
  1909. X    opargs[O_NEXT] =        A(1,0,0);
  1910. X    opargs[O_REDO] =        A(1,0,0);
  1911. X    opargs[O_GOTO] =        A(1,0,0);
  1912. X    opargs[O_INDEX] =        A(1,1,0);
  1913. X    opargs[O_TIME] =         A(0,0,0);
  1914. X    opargs[O_TMS] =         A(0,0,0);
  1915. X    opargs[O_LOCALTIME] =    A(1,0,0);
  1916. X    opargs[O_GMTIME] =        A(1,0,0);
  1917. X    opargs[O_STAT] =        A(1,0,0);
  1918. X    opargs[O_CRYPT] =        A(1,1,0);
  1919. X    opargs[O_EXP] =        A(1,0,0);
  1920. X    opargs[O_LOG] =        A(1,0,0);
  1921. X    opargs[O_SQRT] =        A(1,0,0);
  1922. X    opargs[O_INT] =        A(1,0,0);
  1923. X    opargs[O_PRTF] =        A(1,1,0);
  1924. X    opargs[O_ORD] =         A(1,0,0);
  1925. X    opargs[O_SLEEP] =        A(1,0,0);
  1926. X    opargs[O_FLIP] =        A(1,0,0);
  1927. X    opargs[O_FLOP] =        A(0,1,0);
  1928. X    opargs[O_KEYS] =        A(0,0,0);
  1929. X    opargs[O_VALUES] =        A(0,0,0);
  1930. X    opargs[O_EACH] =        A(0,0,0);
  1931. X    opargs[O_CHOP] =        A(1,0,0);
  1932. X    opargs[O_FORK] =        A(1,0,0);
  1933. X    opargs[O_EXEC] =        A(1,0,0);
  1934. X    opargs[O_SYSTEM] =        A(1,0,0);
  1935. X    opargs[O_OCT] =        A(1,0,0);
  1936. X    opargs[O_HEX] =        A(1,0,0);
  1937. X    opargs[O_CHMOD] =        A(1,0,0);
  1938. X    opargs[O_CHOWN] =        A(1,0,0);
  1939. X    opargs[O_KILL] =        A(1,0,0);
  1940. X    opargs[O_RENAME] =        A(1,1,0);
  1941. X    opargs[O_UNLINK] =        A(1,0,0);
  1942. X    opargs[O_UMASK] =        A(1,0,0);
  1943. X    opargs[O_UNSHIFT] =        A(1,0,0);
  1944. X    opargs[O_LINK] =        A(1,1,0);
  1945. X    opargs[O_REPEAT] =        A(1,1,0);
  1946. X    opargs[O_EVAL] =        A(1,0,0);
  1947. X    opargs[O_FTEREAD] =        A(1,0,0);
  1948. X    opargs[O_FTEWRITE] =    A(1,0,0);
  1949. X    opargs[O_FTEEXEC] =        A(1,0,0);
  1950. X    opargs[O_FTEOWNED] =    A(1,0,0);
  1951. X    opargs[O_FTRREAD] =        A(1,0,0);
  1952. X    opargs[O_FTRWRITE] =    A(1,0,0);
  1953. X    opargs[O_FTREXEC] =        A(1,0,0);
  1954. X    opargs[O_FTROWNED] =    A(1,0,0);
  1955. X    opargs[O_FTIS] =        A(1,0,0);
  1956. X    opargs[O_FTZERO] =        A(1,0,0);
  1957. X    opargs[O_FTSIZE] =        A(1,0,0);
  1958. X    opargs[O_FTFILE] =        A(1,0,0);
  1959. X    opargs[O_FTDIR] =        A(1,0,0);
  1960. X    opargs[O_FTLINK] =        A(1,0,0);
  1961. X    opargs[O_SYMLINK] =        A(1,1,0);
  1962. X    opargs[O_FTPIPE] =        A(1,0,0);
  1963. X    opargs[O_FTSUID] =        A(1,0,0);
  1964. X    opargs[O_FTSGID] =        A(1,0,0);
  1965. X    opargs[O_FTSVTX] =        A(1,0,0);
  1966. X    opargs[O_FTCHR] =        A(1,0,0);
  1967. X    opargs[O_FTBLK] =        A(1,0,0);
  1968. X    opargs[O_FTSOCK] =        A(1,0,0);
  1969. X    opargs[O_FTTTY] =        A(1,0,0);
  1970. X    opargs[O_DOFILE] =        A(1,0,0);
  1971. X    opargs[O_FTTEXT] =        A(1,0,0);
  1972. X    opargs[O_FTBINARY] =    A(1,0,0);
  1973. X    opargs[O_UTIME] =        A(1,0,0);
  1974. X    opargs[O_WAIT] =        A(0,0,0);
  1975. X    opargs[O_SORT] =        A(1,0,0);
  1976. X    opargs[O_STUDY] =        A(1,0,0);
  1977. X    opargs[O_DELETE] =        A(1,0,0);
  1978. X}
  1979. !STUFFY!FUNK!
  1980. echo Extracting eg/g/ged
  1981. sed >eg/g/ged <<'!STUFFY!FUNK!' -e 's/X//'
  1982. X#!/usr/bin/perl
  1983. X
  1984. X# $Header: ged,v 2.0 88/06/05 00:17:08 root Exp $
  1985. X
  1986. X# Does inplace edits on a set of files on a set of machines.
  1987. X#
  1988. X# Typical invokation:
  1989. X#
  1990. X#    ged vax+sun /etc/passwd
  1991. X#    s/Freddy/Freddie/;
  1992. X#    ^D
  1993. X#
  1994. X
  1995. X$class = shift;
  1996. X$files = join(' ',@ARGV);
  1997. X
  1998. Xdie "Usage: ged class files <perlcmds\n" unless $files;
  1999. X
  2000. Xexec "gsh", $class, "-d", "perl -pi.bak - $files";
  2001. X
  2002. Xdie "Couldn't execute gsh for some reason, stopped";
  2003. !STUFFY!FUNK!
  2004. echo ""
  2005. echo "End of kit 1 (of 15)"
  2006. cat /dev/null >kit1isdone
  2007. run=''
  2008. config=''
  2009. for iskit in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
  2010.     if test -f kit${iskit}isdone; then
  2011.     run="$run $iskit"
  2012.     else
  2013.     todo="$todo $iskit"
  2014.     fi
  2015. done
  2016. case $todo in
  2017.     '')
  2018.     echo "You have run all your kits.  Please read README and then type Configure."
  2019.     chmod 755 Configure
  2020.     ;;
  2021.     *)  echo "You have run$run."
  2022.     echo "You still need to run$todo."
  2023.     ;;
  2024. esac
  2025. : Someone might mail this, so...
  2026. exit
  2027.  
  2028.