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

  1. From: lwall@netlabs.com (Larry Wall)
  2. Newsgroups: comp.sources.misc
  3. Subject: v18i033:  perl - The perl programming language, Part15/36
  4. Message-ID: <1991Apr16.000130.23012@sparky.IMD.Sterling.COM>
  5. Date: 16 Apr 91 00:01:30 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Checksum-Snefru: 240705d4 4f939858 e1bffa83 a217750d
  8.  
  9. Submitted-by: Larry Wall <lwall@netlabs.com>
  10. Posting-number: Volume 18, Issue 33
  11. Archive-name: perl/part15
  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 15 (of 36).  If kit 15 is complete, the line"
  21. echo '"'"End of kit 15 (of 36)"'" will echo at the end.'
  22. echo ""
  23. export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
  24. mkdir t t/cmd 2>/dev/null
  25. echo Extracting str.c
  26. sed >str.c <<'!STUFFY!FUNK!' -e 's/X//'
  27. X/* $RCSfile: str.c,v $$Revision: 4.0.1.1 $$Date: 91/04/12 09:15:30 $
  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:    str.c,v $
  35. X * Revision 4.0.1.1  91/04/12  09:15:30  lwall
  36. X * patch1: fixed undefined environ problem
  37. X * patch1: substr($ENV{"PATH"},0,0) = "/foo:" didn't modify environment
  38. X * patch1: $foo .= <BAR> could cause core dump for certain lengths of $foo
  39. X * 
  40. X * Revision 4.0  91/03/20  01:39:55  lwall
  41. X * 4.0 baseline.
  42. X * 
  43. X */
  44. X
  45. X#include "EXTERN.h"
  46. X#include "perl.h"
  47. X#include "perly.h"
  48. X
  49. X#ifndef str_get
  50. Xchar *
  51. Xstr_get(str)
  52. XSTR *str;
  53. X{
  54. X#ifdef TAINT
  55. X    tainted |= str->str_tainted;
  56. X#endif
  57. X    return str->str_pok ? str->str_ptr : str_2ptr(str);
  58. X}
  59. X#endif
  60. X
  61. X/* dlb ... guess we have a "crippled cc".
  62. X * dlb the following functions are usually macros.
  63. X */
  64. X#ifndef str_true
  65. Xstr_true(Str)
  66. XSTR *Str;
  67. X{
  68. X    if (Str->str_pok) {
  69. X        if (*Str->str_ptr > '0' ||
  70. X          Str->str_cur > 1 ||
  71. X          (Str->str_cur && *Str->str_ptr != '0'))
  72. X        return 1;
  73. X        return 0;
  74. X    }
  75. X    if (Str->str_nok)
  76. X        return (Str->str_u.str_nval != 0.0);
  77. X    return 0;
  78. X}
  79. X#endif /* str_true */
  80. X
  81. X#ifndef str_gnum
  82. Xdouble str_gnum(Str)
  83. XSTR *Str;
  84. X{
  85. X#ifdef TAINT
  86. X    tainted |= Str->str_tainted;
  87. X#endif /* TAINT*/
  88. X    if (Str->str_nok)
  89. X        return Str->str_u.str_nval;
  90. X    return str_2num(Str);
  91. X}
  92. X#endif /* str_gnum */
  93. X/* dlb ... end of crutch */
  94. X
  95. Xchar *
  96. Xstr_grow(str,newlen)
  97. Xregister STR *str;
  98. X#ifndef MSDOS
  99. Xregister int newlen;
  100. X#else
  101. Xunsigned long newlen;
  102. X#endif
  103. X{
  104. X    register char *s = str->str_ptr;
  105. X
  106. X#ifdef MSDOS
  107. X    if (newlen >= 0x10000) {
  108. X    fprintf(stderr, "Allocation too large: %lx\n", newlen);
  109. X    exit(1);
  110. X    }
  111. X#endif /* MSDOS */
  112. X    if (str->str_state == SS_INCR) {        /* data before str_ptr? */
  113. X    str->str_len += str->str_u.str_useful;
  114. X    str->str_ptr -= str->str_u.str_useful;
  115. X    str->str_u.str_useful = 0L;
  116. X    bcopy(s, str->str_ptr, str->str_cur+1);
  117. X    s = str->str_ptr;
  118. X    str->str_state = SS_NORM;            /* normal again */
  119. X    if (newlen > str->str_len)
  120. X        newlen += 10 * (newlen - str->str_cur); /* avoid copy each time */
  121. X    }
  122. X    if (newlen > str->str_len) {        /* need more room? */
  123. X        if (str->str_len)
  124. X        Renew(s,newlen,char);
  125. X        else
  126. X        New(703,s,newlen,char);
  127. X    str->str_ptr = s;
  128. X        str->str_len = newlen;
  129. X    }
  130. X    return s;
  131. X}
  132. X
  133. Xstr_numset(str,num)
  134. Xregister STR *str;
  135. Xdouble num;
  136. X{
  137. X    if (str->str_pok) {
  138. X    str->str_pok = 0;    /* invalidate pointer */
  139. X    if (str->str_state == SS_INCR)
  140. X        Str_Grow(str,0);
  141. X    }
  142. X    str->str_u.str_nval = num;
  143. X    str->str_state = SS_NORM;
  144. X    str->str_nok = 1;            /* validate number */
  145. X#ifdef TAINT
  146. X    str->str_tainted = tainted;
  147. X#endif
  148. X}
  149. X
  150. Xchar *
  151. Xstr_2ptr(str)
  152. Xregister STR *str;
  153. X{
  154. X    register char *s;
  155. X    int olderrno;
  156. X
  157. X    if (!str)
  158. X    return "";
  159. X    if (str->str_nok) {
  160. X    STR_GROW(str, 30);
  161. X    s = str->str_ptr;
  162. X    olderrno = errno;    /* some Xenix systems wipe out errno here */
  163. X#if defined(scs) && defined(ns32000)
  164. X    gcvt(str->str_u.str_nval,20,s);
  165. X#else
  166. X#ifdef apollo
  167. X    if (str->str_u.str_nval == 0.0)
  168. X        (void)strcpy(s,"0");
  169. X    else
  170. X#endif /*apollo*/
  171. X    (void)sprintf(s,"%.20g",str->str_u.str_nval);
  172. X#endif /*scs*/
  173. X    errno = olderrno;
  174. X    while (*s) s++;
  175. X#ifdef hcx
  176. X    if (s[-1] == '.')
  177. X        s--;
  178. X#endif
  179. X    }
  180. X    else {
  181. X    if (str == &str_undef)
  182. X        return No;
  183. X    if (dowarn)
  184. X        warn("Use of uninitialized variable");
  185. X    STR_GROW(str, 30);
  186. X    s = str->str_ptr;
  187. X    }
  188. X    *s = '\0';
  189. X    str->str_cur = s - str->str_ptr;
  190. X    str->str_pok = 1;
  191. X#ifdef DEBUGGING
  192. X    if (debug & 32)
  193. X    fprintf(stderr,"0x%lx ptr(%s)\n",str,str->str_ptr);
  194. X#endif
  195. X    return str->str_ptr;
  196. X}
  197. X
  198. Xdouble
  199. Xstr_2num(str)
  200. Xregister STR *str;
  201. X{
  202. X    if (!str)
  203. X    return 0.0;
  204. X    if (str->str_state == SS_INCR)
  205. X    Str_Grow(str,0);       /* just force copy down */
  206. X    str->str_state = SS_NORM;
  207. X    if (str->str_len && str->str_pok)
  208. X    str->str_u.str_nval = atof(str->str_ptr);
  209. X    else  {
  210. X    if (str == &str_undef)
  211. X        return 0.0;
  212. X    if (dowarn)
  213. X        warn("Use of uninitialized variable");
  214. X    str->str_u.str_nval = 0.0;
  215. X    }
  216. X    str->str_nok = 1;
  217. X#ifdef DEBUGGING
  218. X    if (debug & 32)
  219. X    fprintf(stderr,"0x%lx num(%g)\n",str,str->str_u.str_nval);
  220. X#endif
  221. X    return str->str_u.str_nval;
  222. X}
  223. X
  224. X/* Note: str_sset() should not be called with a source string that needs
  225. X * be reused, since it may destroy the source string if it is marked
  226. X * as temporary.
  227. X */
  228. X
  229. Xstr_sset(dstr,sstr)
  230. XSTR *dstr;
  231. Xregister STR *sstr;
  232. X{
  233. X#ifdef TAINT
  234. X    if (sstr)
  235. X    tainted |= sstr->str_tainted;
  236. X#endif
  237. X    if (sstr == dstr || dstr == &str_undef)
  238. X    return;
  239. X    if (!sstr)
  240. X    dstr->str_pok = dstr->str_nok = 0;
  241. X    else if (sstr->str_pok) {
  242. X
  243. X    /*
  244. X     * Check to see if we can just swipe the string.  If so, it's a
  245. X     * possible small lose on short strings, but a big win on long ones.
  246. X     * It might even be a win on short strings if dstr->str_ptr
  247. X     * has to be allocated and sstr->str_ptr has to be freed.
  248. X     */
  249. X
  250. X    if (sstr->str_pok & SP_TEMP) {        /* slated for free anyway? */
  251. X        if (dstr->str_ptr) {
  252. X        if (dstr->str_state == SS_INCR)
  253. X            dstr->str_ptr -= dstr->str_u.str_useful;
  254. X        Safefree(dstr->str_ptr);
  255. X        }
  256. X        dstr->str_ptr = sstr->str_ptr;
  257. X        dstr->str_len = sstr->str_len;
  258. X        dstr->str_cur = sstr->str_cur;
  259. X        dstr->str_state = sstr->str_state;
  260. X        dstr->str_pok = sstr->str_pok & ~SP_TEMP;
  261. X#ifdef TAINT
  262. X        dstr->str_tainted = sstr->str_tainted;
  263. X#endif
  264. X        sstr->str_ptr = Nullch;
  265. X        sstr->str_len = 0;
  266. X        sstr->str_pok = 0;            /* wipe out any weird flags */
  267. X        sstr->str_state = 0;        /* so sstr frees uneventfully */
  268. X    }
  269. X    else {                    /* have to copy actual string */
  270. X        if (dstr->str_ptr) {
  271. X        if (dstr->str_state == SS_INCR) {
  272. X            Str_Grow(dstr,0);
  273. X        }
  274. X        }
  275. X        str_nset(dstr,sstr->str_ptr,sstr->str_cur);
  276. X    }
  277. X    if (dstr->str_nok = sstr->str_nok)
  278. X        dstr->str_u.str_nval = sstr->str_u.str_nval;
  279. X    else {
  280. X#ifdef STRUCTCOPY
  281. X        dstr->str_u = sstr->str_u;
  282. X#else
  283. X        dstr->str_u.str_nval = sstr->str_u.str_nval;
  284. X#endif
  285. X        if (dstr->str_cur == sizeof(STBP)) {
  286. X        char *tmps = dstr->str_ptr;
  287. X
  288. X        if (*tmps == 'S' && bcmp(tmps,"StB",4) == 0) {
  289. X            if (!dstr->str_magic) {
  290. X            dstr->str_magic = str_smake(sstr->str_magic);
  291. X            dstr->str_magic->str_rare = 'X';
  292. X            }
  293. X        }
  294. X        }
  295. X    }
  296. X    }
  297. X    else if (sstr->str_nok)
  298. X    str_numset(dstr,sstr->str_u.str_nval);
  299. X    else {
  300. X    if (dstr->str_state == SS_INCR)
  301. X        Str_Grow(dstr,0);       /* just force copy down */
  302. X
  303. X#ifdef STRUCTCOPY
  304. X    dstr->str_u = sstr->str_u;
  305. X#else
  306. X    dstr->str_u.str_nval = sstr->str_u.str_nval;
  307. X#endif
  308. X    dstr->str_pok = dstr->str_nok = 0;
  309. X    }
  310. X}
  311. X
  312. Xstr_nset(str,ptr,len)
  313. Xregister STR *str;
  314. Xregister char *ptr;
  315. Xregister STRLEN len;
  316. X{
  317. X    if (str == &str_undef)
  318. X    return;
  319. X    STR_GROW(str, len + 1);
  320. X    if (ptr)
  321. X    (void)bcopy(ptr,str->str_ptr,len);
  322. X    str->str_cur = len;
  323. X    *(str->str_ptr+str->str_cur) = '\0';
  324. X    str->str_nok = 0;        /* invalidate number */
  325. X    str->str_pok = 1;        /* validate pointer */
  326. X#ifdef TAINT
  327. X    str->str_tainted = tainted;
  328. X#endif
  329. X}
  330. X
  331. Xstr_set(str,ptr)
  332. Xregister STR *str;
  333. Xregister char *ptr;
  334. X{
  335. X    register STRLEN len;
  336. X
  337. X    if (str == &str_undef)
  338. X    return;
  339. X    if (!ptr)
  340. X    ptr = "";
  341. X    len = strlen(ptr);
  342. X    STR_GROW(str, len + 1);
  343. X    (void)bcopy(ptr,str->str_ptr,len+1);
  344. X    str->str_cur = len;
  345. X    str->str_nok = 0;        /* invalidate number */
  346. X    str->str_pok = 1;        /* validate pointer */
  347. X#ifdef TAINT
  348. X    str->str_tainted = tainted;
  349. X#endif
  350. X}
  351. X
  352. Xstr_chop(str,ptr)    /* like set but assuming ptr is in str */
  353. Xregister STR *str;
  354. Xregister char *ptr;
  355. X{
  356. X    register STRLEN delta;
  357. X
  358. X    if (!ptr || !(str->str_pok))
  359. X    return;
  360. X    delta = ptr - str->str_ptr;
  361. X    str->str_len -= delta;
  362. X    str->str_cur -= delta;
  363. X    str->str_ptr += delta;
  364. X    if (str->str_state == SS_INCR)
  365. X    str->str_u.str_useful += delta;
  366. X    else {
  367. X    str->str_u.str_useful = delta;
  368. X    str->str_state = SS_INCR;
  369. X    }
  370. X    str->str_nok = 0;        /* invalidate number */
  371. X    str->str_pok = 1;        /* validate pointer (and unstudy str) */
  372. X}
  373. X
  374. Xstr_ncat(str,ptr,len)
  375. Xregister STR *str;
  376. Xregister char *ptr;
  377. Xregister STRLEN len;
  378. X{
  379. X    if (str == &str_undef)
  380. X    return;
  381. X    if (!(str->str_pok))
  382. X    (void)str_2ptr(str);
  383. X    STR_GROW(str, str->str_cur + len + 1);
  384. X    (void)bcopy(ptr,str->str_ptr+str->str_cur,len);
  385. X    str->str_cur += len;
  386. X    *(str->str_ptr+str->str_cur) = '\0';
  387. X    str->str_nok = 0;        /* invalidate number */
  388. X    str->str_pok = 1;        /* validate pointer */
  389. X#ifdef TAINT
  390. X    str->str_tainted |= tainted;
  391. X#endif
  392. X}
  393. X
  394. Xstr_scat(dstr,sstr)
  395. XSTR *dstr;
  396. Xregister STR *sstr;
  397. X{
  398. X#ifdef TAINT
  399. X    tainted |= sstr->str_tainted;
  400. X#endif
  401. X    if (!sstr)
  402. X    return;
  403. X    if (!(sstr->str_pok))
  404. X    (void)str_2ptr(sstr);
  405. X    if (sstr)
  406. X    str_ncat(dstr,sstr->str_ptr,sstr->str_cur);
  407. X}
  408. X
  409. Xstr_cat(str,ptr)
  410. Xregister STR *str;
  411. Xregister char *ptr;
  412. X{
  413. X    register STRLEN len;
  414. X
  415. X    if (str == &str_undef)
  416. X    return;
  417. X    if (!ptr)
  418. X    return;
  419. X    if (!(str->str_pok))
  420. X    (void)str_2ptr(str);
  421. X    len = strlen(ptr);
  422. X    STR_GROW(str, str->str_cur + len + 1);
  423. X    (void)bcopy(ptr,str->str_ptr+str->str_cur,len+1);
  424. X    str->str_cur += len;
  425. X    str->str_nok = 0;        /* invalidate number */
  426. X    str->str_pok = 1;        /* validate pointer */
  427. X#ifdef TAINT
  428. X    str->str_tainted |= tainted;
  429. X#endif
  430. X}
  431. X
  432. Xchar *
  433. Xstr_append_till(str,from,fromend,delim,keeplist)
  434. Xregister STR *str;
  435. Xregister char *from;
  436. Xregister char *fromend;
  437. Xregister int delim;
  438. Xchar *keeplist;
  439. X{
  440. X    register char *to;
  441. X    register STRLEN len;
  442. X
  443. X    if (str == &str_undef)
  444. X    return Nullch;
  445. X    if (!from)
  446. X    return Nullch;
  447. X    len = fromend - from;
  448. X    STR_GROW(str, str->str_cur + len + 1);
  449. X    str->str_nok = 0;        /* invalidate number */
  450. X    str->str_pok = 1;        /* validate pointer */
  451. X    to = str->str_ptr+str->str_cur;
  452. X    for (; from < fromend; from++,to++) {
  453. X    if (*from == '\\' && from+1 < fromend && delim != '\\') {
  454. X        if (!keeplist) {
  455. X        if (from[1] == delim || from[1] == '\\')
  456. X            from++;
  457. X        else
  458. X            *to++ = *from++;
  459. X        }
  460. X        else if (from[1] && index(keeplist,from[1]))
  461. X        *to++ = *from++;
  462. X        else
  463. X        from++;
  464. X    }
  465. X    else if (*from == delim)
  466. X        break;
  467. X    *to = *from;
  468. X    }
  469. X    *to = '\0';
  470. X    str->str_cur = to - str->str_ptr;
  471. X    return from;
  472. X}
  473. X
  474. XSTR *
  475. X#ifdef LEAKTEST
  476. Xstr_new(x,len)
  477. Xint x;
  478. X#else
  479. Xstr_new(len)
  480. X#endif
  481. XSTRLEN len;
  482. X{
  483. X    register STR *str;
  484. X    
  485. X    if (freestrroot) {
  486. X    str = freestrroot;
  487. X    freestrroot = str->str_magic;
  488. X    str->str_magic = Nullstr;
  489. X    str->str_state = SS_NORM;
  490. X    }
  491. X    else {
  492. X    Newz(700+x,str,1,STR);
  493. X    }
  494. X    if (len)
  495. X    STR_GROW(str, len + 1);
  496. X    return str;
  497. X}
  498. X
  499. Xvoid
  500. Xstr_magic(str, stab, how, name, namlen)
  501. Xregister STR *str;
  502. XSTAB *stab;
  503. Xint how;
  504. Xchar *name;
  505. XSTRLEN namlen;
  506. X{
  507. X    if (str == &str_undef || str->str_magic)
  508. X    return;
  509. X    str->str_magic = Str_new(75,namlen);
  510. X    str = str->str_magic;
  511. X    str->str_u.str_stab = stab;
  512. X    str->str_rare = how;
  513. X    if (name)
  514. X    str_nset(str,name,namlen);
  515. X}
  516. X
  517. Xvoid
  518. Xstr_insert(bigstr,offset,len,little,littlelen)
  519. XSTR *bigstr;
  520. XSTRLEN offset;
  521. XSTRLEN len;
  522. Xchar *little;
  523. XSTRLEN littlelen;
  524. X{
  525. X    register char *big;
  526. X    register char *mid;
  527. X    register char *midend;
  528. X    register char *bigend;
  529. X    register int i;
  530. X
  531. X    if (bigstr == &str_undef)
  532. X    return;
  533. X    bigstr->str_nok = 0;
  534. X    bigstr->str_pok = SP_VALID;    /* disable possible screamer */
  535. X
  536. X    i = littlelen - len;
  537. X    if (i > 0) {            /* string might grow */
  538. X    STR_GROW(bigstr, bigstr->str_cur + i + 1);
  539. X    big = bigstr->str_ptr;
  540. X    mid = big + offset + len;
  541. X    midend = bigend = big + bigstr->str_cur;
  542. X    bigend += i;
  543. X    *bigend = '\0';
  544. X    while (midend > mid)        /* shove everything down */
  545. X        *--bigend = *--midend;
  546. X    (void)bcopy(little,big+offset,littlelen);
  547. X    bigstr->str_cur += i;
  548. X    STABSET(bigstr);
  549. X    return;
  550. X    }
  551. X    else if (i == 0) {
  552. X    (void)bcopy(little,bigstr->str_ptr+offset,len);
  553. X    STABSET(bigstr);
  554. X    return;
  555. X    }
  556. X
  557. X    big = bigstr->str_ptr;
  558. X    mid = big + offset;
  559. X    midend = mid + len;
  560. X    bigend = big + bigstr->str_cur;
  561. X
  562. X    if (midend > bigend)
  563. X    fatal("panic: str_insert");
  564. X
  565. X    if (mid - big > bigend - midend) {    /* faster to shorten from end */
  566. X    if (littlelen) {
  567. X        (void)bcopy(little, mid, littlelen);
  568. X        mid += littlelen;
  569. X    }
  570. X    i = bigend - midend;
  571. X    if (i > 0) {
  572. X        (void)bcopy(midend, mid, i);
  573. X        mid += i;
  574. X    }
  575. X    *mid = '\0';
  576. X    bigstr->str_cur = mid - big;
  577. X    }
  578. X    else if (i = mid - big) {    /* faster from front */
  579. X    midend -= littlelen;
  580. X    mid = midend;
  581. X    str_chop(bigstr,midend-i);
  582. X    big += i;
  583. X    while (i--)
  584. X        *--midend = *--big;
  585. X    if (littlelen)
  586. X        (void)bcopy(little, mid, littlelen);
  587. X    }
  588. X    else if (littlelen) {
  589. X    midend -= littlelen;
  590. X    str_chop(bigstr,midend);
  591. X    (void)bcopy(little,midend,littlelen);
  592. X    }
  593. X    else {
  594. X    str_chop(bigstr,midend);
  595. X    }
  596. X    STABSET(bigstr);
  597. X}
  598. X
  599. X/* make str point to what nstr did */
  600. X
  601. Xvoid
  602. Xstr_replace(str,nstr)
  603. Xregister STR *str;
  604. Xregister STR *nstr;
  605. X{
  606. X    if (str == &str_undef)
  607. X    return;
  608. X    if (str->str_state == SS_INCR)
  609. X    Str_Grow(str,0);    /* just force copy down */
  610. X    if (nstr->str_state == SS_INCR)
  611. X    Str_Grow(nstr,0);
  612. X    if (str->str_ptr)
  613. X    Safefree(str->str_ptr);
  614. X    str->str_ptr = nstr->str_ptr;
  615. X    str->str_len = nstr->str_len;
  616. X    str->str_cur = nstr->str_cur;
  617. X    str->str_pok = nstr->str_pok;
  618. X    str->str_nok = nstr->str_nok;
  619. X#ifdef STRUCTCOPY
  620. X    str->str_u = nstr->str_u;
  621. X#else
  622. X    str->str_u.str_nval = nstr->str_u.str_nval;
  623. X#endif
  624. X#ifdef TAINT
  625. X    str->str_tainted = nstr->str_tainted;
  626. X#endif
  627. X    if (nstr->str_magic)
  628. X    str_free(nstr->str_magic);
  629. X    Safefree(nstr);
  630. X}
  631. X
  632. Xvoid
  633. Xstr_free(str)
  634. Xregister STR *str;
  635. X{
  636. X    if (!str || str == &str_undef)
  637. X    return;
  638. X    if (str->str_state) {
  639. X    if (str->str_state == SS_FREE)    /* already freed */
  640. X        return;
  641. X    if (str->str_state == SS_INCR && !(str->str_pok & 2)) {
  642. X        str->str_ptr -= str->str_u.str_useful;
  643. X        str->str_len += str->str_u.str_useful;
  644. X    }
  645. X    }
  646. X    if (str->str_magic)
  647. X    str_free(str->str_magic);
  648. X    str->str_magic = freestrroot;
  649. X#ifdef LEAKTEST
  650. X    if (str->str_len) {
  651. X    Safefree(str->str_ptr);
  652. X    str->str_ptr = Nullch;
  653. X    }
  654. X    if ((str->str_pok & SP_INTRP) && str->str_u.str_args)
  655. X    arg_free(str->str_u.str_args);
  656. X    Safefree(str);
  657. X#else /* LEAKTEST */
  658. X    if (str->str_len) {
  659. X    if (str->str_len > 127) {    /* next user not likely to want more */
  660. X        Safefree(str->str_ptr);    /* so give it back to malloc */
  661. X        str->str_ptr = Nullch;
  662. X        str->str_len = 0;
  663. X    }
  664. X    else
  665. X        str->str_ptr[0] = '\0';
  666. X    }
  667. X    if ((str->str_pok & SP_INTRP) && str->str_u.str_args)
  668. X    arg_free(str->str_u.str_args);
  669. X    str->str_cur = 0;
  670. X    str->str_nok = 0;
  671. X    str->str_pok = 0;
  672. X    str->str_state = SS_FREE;
  673. X#ifdef TAINT
  674. X    str->str_tainted = 0;
  675. X#endif
  676. X    freestrroot = str;
  677. X#endif /* LEAKTEST */
  678. X}
  679. X
  680. XSTRLEN
  681. Xstr_len(str)
  682. Xregister STR *str;
  683. X{
  684. X    if (!str)
  685. X    return 0;
  686. X    if (!(str->str_pok))
  687. X    (void)str_2ptr(str);
  688. X    if (str->str_ptr)
  689. X    return str->str_cur;
  690. X    else
  691. X    return 0;
  692. X}
  693. X
  694. Xstr_eq(str1,str2)
  695. Xregister STR *str1;
  696. Xregister STR *str2;
  697. X{
  698. X    if (!str1 || str1 == &str_undef)
  699. X    return (str2 == Nullstr || str2 == &str_undef || !str2->str_cur);
  700. X    if (!str2 || str2 == &str_undef)
  701. X    return !str1->str_cur;
  702. X
  703. X    if (!str1->str_pok)
  704. X    (void)str_2ptr(str1);
  705. X    if (!str2->str_pok)
  706. X    (void)str_2ptr(str2);
  707. X
  708. X    if (str1->str_cur != str2->str_cur)
  709. X    return 0;
  710. X
  711. X    return !bcmp(str1->str_ptr, str2->str_ptr, str1->str_cur);
  712. X}
  713. X
  714. Xstr_cmp(str1,str2)
  715. Xregister STR *str1;
  716. Xregister STR *str2;
  717. X{
  718. X    int retval;
  719. X
  720. X    if (!str1 || str1 == &str_undef)
  721. X    return (str2 == Nullstr || str2 == &str_undef || !str2->str_cur)?0:-1;
  722. X    if (!str2 || str2 == &str_undef)
  723. X    return str1->str_cur != 0;
  724. X
  725. X    if (!str1->str_pok)
  726. X    (void)str_2ptr(str1);
  727. X    if (!str2->str_pok)
  728. X    (void)str_2ptr(str2);
  729. X
  730. X    if (str1->str_cur < str2->str_cur) {
  731. X    if (retval = memcmp(str1->str_ptr, str2->str_ptr, str1->str_cur))
  732. X        return retval < 0 ? -1 : 1;
  733. X    else
  734. X        return -1;
  735. X    }
  736. X    else if (retval = memcmp(str1->str_ptr, str2->str_ptr, str2->str_cur))
  737. X    return retval < 0 ? -1 : 1;
  738. X    else if (str1->str_cur == str2->str_cur)
  739. X    return 0;
  740. X    else
  741. X    return 1;
  742. X}
  743. X
  744. Xchar *
  745. Xstr_gets(str,fp,append)
  746. Xregister STR *str;
  747. Xregister FILE *fp;
  748. Xint append;
  749. X{
  750. X    register char *bp;        /* we're going to steal some values */
  751. X    register int cnt;        /*  from the stdio struct and put EVERYTHING */
  752. X    register STDCHAR *ptr;    /*   in the innermost loop into registers */
  753. X    register int newline = rschar;/* (assuming >= 6 registers) */
  754. X    int i;
  755. X    STRLEN bpx;
  756. X    int shortbuffered;
  757. X
  758. X    if (str == &str_undef)
  759. X    return Nullch;
  760. X#ifdef STDSTDIO        /* Here is some breathtakingly efficient cheating */
  761. X    cnt = fp->_cnt;            /* get count into register */
  762. X    str->str_nok = 0;            /* invalidate number */
  763. X    str->str_pok = 1;            /* validate pointer */
  764. X    if (str->str_len <= cnt + 1) {    /* make sure we have the room */
  765. X    if (cnt > 80 && str->str_len > append) {
  766. X        shortbuffered = cnt - str->str_len + append + 1;
  767. X        cnt -= shortbuffered;
  768. X    }
  769. X    else {
  770. X        shortbuffered = 0;
  771. X        STR_GROW(str, append+cnt+2);/* (remembering cnt can be -1) */
  772. X    }
  773. X    }
  774. X    else
  775. X    shortbuffered = 0;
  776. X    bp = str->str_ptr + append;        /* move these two too to registers */
  777. X    ptr = fp->_ptr;
  778. X    for (;;) {
  779. X      screamer:
  780. X    while (--cnt >= 0) {            /* this */    /* eat */
  781. X        if ((*bp++ = *ptr++) == newline)    /* really */    /* dust */
  782. X        goto thats_all_folks;        /* screams */    /* sed :-) */ 
  783. X    }
  784. X    
  785. X    if (shortbuffered) {            /* oh well, must extend */
  786. X        cnt = shortbuffered;
  787. X        shortbuffered = 0;
  788. X        bpx = bp - str->str_ptr;    /* prepare for possible relocation */
  789. X        str->str_cur = bpx;
  790. X        STR_GROW(str, str->str_len + append + cnt + 2);
  791. X        bp = str->str_ptr + bpx;    /* reconstitute our pointer */
  792. X        continue;
  793. X    }
  794. X
  795. X    fp->_cnt = cnt;            /* deregisterize cnt and ptr */
  796. X    fp->_ptr = ptr;
  797. X    i = _filbuf(fp);        /* get more characters */
  798. X    cnt = fp->_cnt;
  799. X    ptr = fp->_ptr;            /* reregisterize cnt and ptr */
  800. X
  801. X    bpx = bp - str->str_ptr;    /* prepare for possible relocation */
  802. X    str->str_cur = bpx;
  803. X    STR_GROW(str, bpx + cnt + 2);
  804. X    bp = str->str_ptr + bpx;    /* reconstitute our pointer */
  805. X
  806. X    if (i == newline) {        /* all done for now? */
  807. X        *bp++ = i;
  808. X        goto thats_all_folks;
  809. X    }
  810. X    else if (i == EOF)        /* all done for ever? */
  811. X        goto thats_really_all_folks;
  812. X    *bp++ = i;            /* now go back to screaming loop */
  813. X    }
  814. X
  815. Xthats_all_folks:
  816. X    if (rslen > 1 && (bp - str->str_ptr < rslen || bcmp(bp - rslen, rs, rslen)))
  817. X    goto screamer;    /* go back to the fray */
  818. Xthats_really_all_folks:
  819. X    if (shortbuffered)
  820. X    cnt += shortbuffered;
  821. X    fp->_cnt = cnt;            /* put these back or we're in trouble */
  822. X    fp->_ptr = ptr;
  823. X    *bp = '\0';
  824. X    str->str_cur = bp - str->str_ptr;    /* set length */
  825. X
  826. X#else /* !STDSTDIO */    /* The big, slow, and stupid way */
  827. X
  828. X    {
  829. X    static char buf[8192];
  830. X    char * bpe = buf + sizeof(buf) - 3;
  831. X
  832. Xscreamer:
  833. X    bp = buf;
  834. X    while ((i = getc(fp)) != EOF && (*bp++ = i) != newline && bp < bpe) ;
  835. X
  836. X    *bp = '\0';
  837. X    if (append)
  838. X        str_cat(str, buf);
  839. X    else
  840. X        str_set(str, buf);
  841. X    if (i != EOF            /* joy */
  842. X        &&
  843. X        (i != newline
  844. X         ||
  845. X         (rslen > 1
  846. X          &&
  847. X          (str->str_cur < rslen
  848. X           ||
  849. X           bcmp(str->str_ptr + str->str_cur - rslen, rs, rslen)
  850. X          )
  851. X         )
  852. X        )
  853. X       )
  854. X    {
  855. X        append = -1;
  856. X        goto screamer;
  857. X    }
  858. X    }
  859. X
  860. X#endif /* STDSTDIO */
  861. X
  862. X    return str->str_cur - append ? str->str_ptr : Nullch;
  863. X}
  864. X
  865. XARG *
  866. Xparselist(str)
  867. XSTR *str;
  868. X{
  869. X    register CMD *cmd;
  870. X    register ARG *arg;
  871. X    CMD *oldcurcmd = curcmd;
  872. X    int oldperldb = perldb;
  873. X    int retval;
  874. X
  875. X    perldb = 0;
  876. X    str_sset(linestr,str);
  877. X    in_eval++;
  878. X    oldoldbufptr = oldbufptr = bufptr = str_get(linestr);
  879. X    bufend = bufptr + linestr->str_cur;
  880. X    if (++loop_ptr >= loop_max) {
  881. X        loop_max += 128;
  882. X        Renew(loop_stack, loop_max, struct loop);
  883. X    }
  884. X    loop_stack[loop_ptr].loop_label = "_EVAL_";
  885. X    loop_stack[loop_ptr].loop_sp = 0;
  886. X#ifdef DEBUGGING
  887. X    if (debug & 4) {
  888. X        deb("(Pushing label #%d _EVAL_)\n", loop_ptr);
  889. X    }
  890. X#endif
  891. X    if (setjmp(loop_stack[loop_ptr].loop_env)) {
  892. X    in_eval--;
  893. X    loop_ptr--;
  894. X    perldb = oldperldb;
  895. X    fatal("%s\n",stab_val(stabent("@",TRUE))->str_ptr);
  896. X    }
  897. X#ifdef DEBUGGING
  898. X    if (debug & 4) {
  899. X    char *tmps = loop_stack[loop_ptr].loop_label;
  900. X    deb("(Popping label #%d %s)\n",loop_ptr,
  901. X        tmps ? tmps : "" );
  902. X    }
  903. X#endif
  904. X    loop_ptr--;
  905. X    error_count = 0;
  906. X    curcmd = &compiling;
  907. X    curcmd->c_line = oldcurcmd->c_line;
  908. X    retval = yyparse();
  909. X    curcmd = oldcurcmd;
  910. X    perldb = oldperldb;
  911. X    in_eval--;
  912. X    if (retval || error_count)
  913. X    fatal("Invalid component in string or format");
  914. X    cmd = eval_root;
  915. X    arg = cmd->c_expr;
  916. X    if (cmd->c_type != C_EXPR || cmd->c_next || arg->arg_type != O_LIST)
  917. X    fatal("panic: error in parselist %d %x %d", cmd->c_type,
  918. X      cmd->c_next, arg ? arg->arg_type : -1);
  919. X    Safefree(cmd);
  920. X    eval_root = Nullcmd;
  921. X    return arg;
  922. X}
  923. X
  924. Xvoid
  925. Xintrpcompile(src)
  926. XSTR *src;
  927. X{
  928. X    register char *s = str_get(src);
  929. X    register char *send = s + src->str_cur;
  930. X    register STR *str;
  931. X    register char *t;
  932. X    STR *toparse;
  933. X    STRLEN len;
  934. X    register int brackets;
  935. X    register char *d;
  936. X    STAB *stab;
  937. X    char *checkpoint;
  938. X    int sawcase = 0;
  939. X
  940. X    toparse = Str_new(76,0);
  941. X    str = Str_new(77,0);
  942. X
  943. X    str_nset(str,"",0);
  944. X    str_nset(toparse,"",0);
  945. X    t = s;
  946. X    while (s < send) {
  947. X    if (*s == '\\' && s[1] && index("$@[{\\]}lLuUE",s[1])) {
  948. X        str_ncat(str, t, s - t);
  949. X        ++s;
  950. X        if (isalpha(*s)) {
  951. X        str_ncat(str, "$c", 2);
  952. X        sawcase = (*s != 'E');
  953. X        }
  954. X        else {
  955. X        if (*nointrp && s+1 < send)
  956. X            if (*s != '@' && (*s != '$' || index(nointrp,s[1])))
  957. X            str_ncat(str,s-1,1);
  958. X        str_ncat(str, "$b", 2);
  959. X        }
  960. X        str_ncat(str, s, 1);
  961. X        ++s;
  962. X        t = s;
  963. X    }
  964. X    else if ((*s == '@' || (*s == '$' && !index(nointrp,s[1]))) &&
  965. X      s+1 < send) {
  966. X        str_ncat(str,t,s-t);
  967. X        t = s;
  968. X        if (*s == '$' && s[1] == '#' && (isalpha(s[2]) || s[2] == '_'))
  969. X        s++;
  970. X        s = scanident(s,send,tokenbuf);
  971. X        if (*t == '@' &&
  972. X          (!(stab = stabent(tokenbuf,FALSE)) || 
  973. X         (*s == '{' ? !stab_xhash(stab) : !stab_xarray(stab)) )) {
  974. X        str_ncat(str,"@",1);
  975. X        s = ++t;
  976. X        continue;    /* grandfather @ from old scripts */
  977. X        }
  978. X        str_ncat(str,"$a",2);
  979. X        str_ncat(toparse,",",1);
  980. X        if (t[1] != '{' && (*s == '['  || *s == '{' /* }} */ ) &&
  981. X          (stab = stabent(tokenbuf,FALSE)) &&
  982. X          ((*s == '[') ? (stab_xarray(stab) != 0) : (stab_xhash(stab) != 0)) ) {
  983. X        brackets = 0;
  984. X        checkpoint = s;
  985. X        do {
  986. X            switch (*s) {
  987. X            case '[':
  988. X            if (s[-1] != '$')
  989. X                brackets++;
  990. X            break;
  991. X            case '{':
  992. X            brackets++;
  993. X            break;
  994. X            case ']':
  995. X            if (s[-1] != '$')
  996. X                brackets--;
  997. X            break;
  998. X            case '}':
  999. X            brackets--;
  1000. X            break;
  1001. X            case '\'':
  1002. X            case '"':
  1003. X            if (s[-1] != '$') {
  1004. X                s = cpytill(tokenbuf,s+1,send,*s,&len);
  1005. X                if (s >= send)
  1006. X                fatal("Unterminated string");
  1007. X            }
  1008. X            break;
  1009. X            }
  1010. X            s++;
  1011. X        } while (brackets > 0 && s < send);
  1012. X        if (s > send)
  1013. X            fatal("Unmatched brackets in string");
  1014. X        if (*nointrp) {        /* we're in a regular expression */
  1015. X            d = checkpoint;
  1016. X            if (*d == '{' && s[-1] == '}') {    /* maybe {n,m} */
  1017. X            ++d;
  1018. X            if (isdigit(*d)) {    /* matches /^{\d,?\d*}$/ */
  1019. X                if (*++d == ',')
  1020. X                ++d;
  1021. X                while (isdigit(*d))
  1022. X                d++;
  1023. X                if (d == s - 1)
  1024. X                s = checkpoint;        /* Is {n,m}! Backoff! */
  1025. X            }
  1026. X            }
  1027. X            else if (*d == '[' && s[-1] == ']') { /* char class? */
  1028. X            int weight = 2;        /* let's weigh the evidence */
  1029. X            char seen[256];
  1030. X            unsigned char un_char = 0, last_un_char;
  1031. X
  1032. X            Zero(seen,256,char);
  1033. X            *--s = '\0';
  1034. X            if (d[1] == '^')
  1035. X                weight += 150;
  1036. X            else if (d[1] == '$')
  1037. X                weight -= 3;
  1038. X            if (isdigit(d[1])) {
  1039. X                if (d[2]) {
  1040. X                if (isdigit(d[2]) && !d[3])
  1041. X                    weight -= 10;
  1042. X                }
  1043. X                else
  1044. X                weight -= 100;
  1045. X            }
  1046. X            for (d++; d < s; d++) {
  1047. X                last_un_char = un_char;
  1048. X                un_char = (unsigned char)*d;
  1049. X                switch (*d) {
  1050. X                case '&':
  1051. X                case '$':
  1052. X                weight -= seen[un_char] * 10;
  1053. X                if (isalpha(d[1]) || isdigit(d[1]) ||
  1054. X                  d[1] == '_') {
  1055. X                    d = scanident(d,s,tokenbuf);
  1056. X                    if (stabent(tokenbuf,FALSE))
  1057. X                    weight -= 100;
  1058. X                    else
  1059. X                    weight -= 10;
  1060. X                }
  1061. X                else if (*d == '$' && d[1] &&
  1062. X                  index("[#!%*<>()-=",d[1])) {
  1063. X                    if (!d[2] || /*{*/ index("])} =",d[2]))
  1064. X                    weight -= 10;
  1065. X                    else
  1066. X                    weight -= 1;
  1067. X                }
  1068. X                break;
  1069. X                case '\\':
  1070. X                un_char = 254;
  1071. X                if (d[1]) {
  1072. X                    if (index("wds",d[1]))
  1073. X                    weight += 100;
  1074. X                    else if (seen['\''] || seen['"'])
  1075. X                    weight += 1;
  1076. X                    else if (index("rnftb",d[1]))
  1077. X                    weight += 40;
  1078. X                    else if (isdigit(d[1])) {
  1079. X                    weight += 40;
  1080. X                    while (d[1] && isdigit(d[1]))
  1081. X                        d++;
  1082. X                    }
  1083. X                }
  1084. X                else
  1085. X                    weight += 100;
  1086. X                break;
  1087. X                case '-':
  1088. X                if (last_un_char < (unsigned char) d[1]
  1089. X                  || d[1] == '\\') {
  1090. X                    if (index("aA01! ",last_un_char))
  1091. X                    weight += 30;
  1092. X                    if (index("zZ79~",d[1]))
  1093. X                    weight += 30;
  1094. X                }
  1095. X                else
  1096. X                    weight -= 1;
  1097. X                default:
  1098. X                if (isalpha(*d) && d[1] && isalpha(d[1])) {
  1099. X                    bufptr = d;
  1100. X                    if (yylex() != WORD)
  1101. X                    weight -= 150;
  1102. X                    d = bufptr;
  1103. X                }
  1104. X                if (un_char == last_un_char + 1)
  1105. X                    weight += 5;
  1106. X                weight -= seen[un_char];
  1107. X                break;
  1108. X                }
  1109. X                seen[un_char]++;
  1110. X            }
  1111. X#ifdef DEBUGGING
  1112. X            if (debug & 512)
  1113. X                fprintf(stderr,"[%s] weight %d\n",
  1114. X                  checkpoint+1,weight);
  1115. X#endif
  1116. X            *s++ = ']';
  1117. X            if (weight >= 0)    /* probably a character class */
  1118. X                s = checkpoint;
  1119. X            }
  1120. X        }
  1121. X        }
  1122. X        if (*t == '@')
  1123. X        str_ncat(toparse, "join($\",", 8);
  1124. X        if (t[1] == '{' && s[-1] == '}') {
  1125. X        str_ncat(toparse, t, 1);
  1126. X        str_ncat(toparse, t+2, s - t - 3);
  1127. X        }
  1128. X        else
  1129. X        str_ncat(toparse, t, s - t);
  1130. X        if (*t == '@')
  1131. X        str_ncat(toparse, ")", 1);
  1132. X        t = s;
  1133. X    }
  1134. X    else
  1135. X        s++;
  1136. X    }
  1137. X    str_ncat(str,t,s-t);
  1138. X    if (sawcase)
  1139. X    str_ncat(str, "$cE", 3);
  1140. X    if (toparse->str_ptr && *toparse->str_ptr == ',') {
  1141. X    *toparse->str_ptr = '(';
  1142. X    str_ncat(toparse,",$$);",5);
  1143. X    str->str_u.str_args = parselist(toparse);
  1144. X    str->str_u.str_args->arg_len--;        /* ignore $$ reference */
  1145. X    }
  1146. X    else
  1147. X    str->str_u.str_args = Nullarg;
  1148. X    str_free(toparse);
  1149. X    str->str_pok |= SP_INTRP;
  1150. X    str->str_nok = 0;
  1151. X    str_replace(src,str);
  1152. X}
  1153. X
  1154. XSTR *
  1155. Xinterp(str,src,sp)
  1156. Xregister STR *str;
  1157. XSTR *src;
  1158. Xint sp;
  1159. X{
  1160. X    register char *s;
  1161. X    register char *t;
  1162. X    register char *send;
  1163. X    register STR **elem;
  1164. X    int docase = 0;
  1165. X    int l = 0;
  1166. X    int u = 0;
  1167. X    int L = 0;
  1168. X    int U = 0;
  1169. X
  1170. X    if (str == &str_undef)
  1171. X    return Nullstr;
  1172. X    if (!(src->str_pok & SP_INTRP)) {
  1173. X    int oldsave = savestack->ary_fill;
  1174. X
  1175. X    (void)savehptr(&curstash);
  1176. X    curstash = curcmd->c_stash;    /* so stabent knows right package */
  1177. X    intrpcompile(src);
  1178. X    restorelist(oldsave);
  1179. X    }
  1180. X    s = src->str_ptr;        /* assumed valid since str_pok set */
  1181. X    t = s;
  1182. X    send = s + src->str_cur;
  1183. X
  1184. X    if (src->str_u.str_args) {
  1185. X    (void)eval(src->str_u.str_args,G_ARRAY,sp);
  1186. X    /* Assuming we have correct # of args */
  1187. X    elem = stack->ary_array + sp;
  1188. X    }
  1189. X
  1190. X    str_nset(str,"",0);
  1191. X    while (s < send) {
  1192. X    if (*s == '$' && s+1 < send) {
  1193. X        if (s-t > 0)
  1194. X        str_ncat(str,t,s-t);
  1195. X        switch(*++s) {
  1196. X        case 'a':
  1197. X        str_scat(str,*++elem);
  1198. X        break;
  1199. X        case 'b':
  1200. X        str_ncat(str,++s,1);
  1201. X        break;
  1202. X        case 'c':
  1203. X        if (docase && str->str_cur >= docase) {
  1204. X            char *b = str->str_ptr + --docase;
  1205. X
  1206. X            if (L)
  1207. X            lcase(b, str->str_ptr + str->str_cur);
  1208. X            else if (U)
  1209. X            ucase(b, str->str_ptr + str->str_cur);
  1210. X
  1211. X            if (u)    /* note that l & u are independent of L & U */
  1212. X            ucase(b, b+1);
  1213. X            else if (l)
  1214. X            lcase(b, b+1);
  1215. X            l = u = 0;
  1216. X        }
  1217. X        docase = str->str_cur + 1;
  1218. X        switch (*++s) {
  1219. X        case 'u':
  1220. X            u = 1;
  1221. X            l = 0;
  1222. X            break;
  1223. X        case 'U':
  1224. X            U = 1;
  1225. X            L = 0;
  1226. X            break;
  1227. X        case 'l':
  1228. X            l = 1;
  1229. X            u = 0;
  1230. X            break;
  1231. X        case 'L':
  1232. X            L = 1;
  1233. X            U = 0;
  1234. X            break;
  1235. X        case 'E':
  1236. X            docase = L = U = l = u = 0;
  1237. X            break;
  1238. X        }
  1239. X        break;
  1240. X        }
  1241. X        t = ++s;
  1242. X    }
  1243. X    else
  1244. X        s++;
  1245. X    }
  1246. X    if (s-t > 0)
  1247. X    str_ncat(str,t,s-t);
  1248. X    return str;
  1249. X}
  1250. X
  1251. Xucase(s,send)
  1252. Xregister char *s;
  1253. Xregister char *send;
  1254. X{
  1255. X    while (s < send) {
  1256. X    if (isascii(*s) && islower(*s))
  1257. X        *s = toupper(*s);
  1258. X    s++;
  1259. X    }
  1260. X}
  1261. X
  1262. Xlcase(s,send)
  1263. Xregister char *s;
  1264. Xregister char *send;
  1265. X{
  1266. X    while (s < send) {
  1267. X    if (isascii(*s) && isupper(*s))
  1268. X        *s = tolower(*s);
  1269. X    s++;
  1270. X    }
  1271. X}
  1272. X
  1273. Xvoid
  1274. Xstr_inc(str)
  1275. Xregister STR *str;
  1276. X{
  1277. X    register char *d;
  1278. X
  1279. X    if (!str || str == &str_undef)
  1280. X    return;
  1281. X    if (str->str_nok) {
  1282. X    str->str_u.str_nval += 1.0;
  1283. X    str->str_pok = 0;
  1284. X    return;
  1285. X    }
  1286. X    if (!str->str_pok || !*str->str_ptr) {
  1287. X    str->str_u.str_nval = 1.0;
  1288. X    str->str_nok = 1;
  1289. X    str->str_pok = 0;
  1290. X    return;
  1291. X    }
  1292. X    d = str->str_ptr;
  1293. X    while (isalpha(*d)) d++;
  1294. X    while (isdigit(*d)) d++;
  1295. X    if (*d) {
  1296. X        str_numset(str,atof(str->str_ptr) + 1.0);  /* punt */
  1297. X    return;
  1298. X    }
  1299. X    d--;
  1300. X    while (d >= str->str_ptr) {
  1301. X    if (isdigit(*d)) {
  1302. X        if (++*d <= '9')
  1303. X        return;
  1304. X        *(d--) = '0';
  1305. X    }
  1306. X    else {
  1307. X        ++*d;
  1308. X        if (isalpha(*d))
  1309. X        return;
  1310. X        *(d--) -= 'z' - 'a' + 1;
  1311. X    }
  1312. X    }
  1313. X    /* oh,oh, the number grew */
  1314. X    STR_GROW(str, str->str_cur + 2);
  1315. X    str->str_cur++;
  1316. X    for (d = str->str_ptr + str->str_cur; d > str->str_ptr; d--)
  1317. X    *d = d[-1];
  1318. X    if (isdigit(d[1]))
  1319. X    *d = '1';
  1320. X    else
  1321. X    *d = d[1];
  1322. X}
  1323. X
  1324. Xvoid
  1325. Xstr_dec(str)
  1326. Xregister STR *str;
  1327. X{
  1328. X    if (!str || str == &str_undef)
  1329. X    return;
  1330. X    if (str->str_nok) {
  1331. X    str->str_u.str_nval -= 1.0;
  1332. X    str->str_pok = 0;
  1333. X    return;
  1334. X    }
  1335. X    if (!str->str_pok) {
  1336. X    str->str_u.str_nval = -1.0;
  1337. X    str->str_nok = 1;
  1338. X    return;
  1339. X    }
  1340. X    str_numset(str,atof(str->str_ptr) - 1.0);
  1341. X}
  1342. X
  1343. X/* Make a string that will exist for the duration of the expression
  1344. X * evaluation.  Actually, it may have to last longer than that, but
  1345. X * hopefully cmd_exec won't free it until it has been assigned to a
  1346. X * permanent location. */
  1347. X
  1348. Xstatic long tmps_size = -1;
  1349. X
  1350. XSTR *
  1351. Xstr_mortal(oldstr)
  1352. XSTR *oldstr;
  1353. X{
  1354. X    register STR *str = Str_new(78,0);
  1355. X
  1356. X    str_sset(str,oldstr);
  1357. X    if (++tmps_max > tmps_size) {
  1358. X    tmps_size = tmps_max;
  1359. X    if (!(tmps_size & 127)) {
  1360. X        if (tmps_size)
  1361. X        Renew(tmps_list, tmps_size + 128, STR*);
  1362. X        else
  1363. X        New(702,tmps_list, 128, STR*);
  1364. X    }
  1365. X    }
  1366. X    tmps_list[tmps_max] = str;
  1367. X    if (str->str_pok)
  1368. X    str->str_pok |= SP_TEMP;
  1369. X    return str;
  1370. X}
  1371. X
  1372. X/* same thing without the copying */
  1373. X
  1374. XSTR *
  1375. Xstr_2mortal(str)
  1376. Xregister STR *str;
  1377. X{
  1378. X    if (str == &str_undef)
  1379. X    return str;
  1380. X    if (++tmps_max > tmps_size) {
  1381. X    tmps_size = tmps_max;
  1382. X    if (!(tmps_size & 127)) {
  1383. X        if (tmps_size)
  1384. X        Renew(tmps_list, tmps_size + 128, STR*);
  1385. X        else
  1386. X        New(704,tmps_list, 128, STR*);
  1387. X    }
  1388. X    }
  1389. X    tmps_list[tmps_max] = str;
  1390. X    if (str->str_pok)
  1391. X    str->str_pok |= SP_TEMP;
  1392. X    return str;
  1393. X}
  1394. X
  1395. XSTR *
  1396. Xstr_make(s,len)
  1397. Xchar *s;
  1398. XSTRLEN len;
  1399. X{
  1400. X    register STR *str = Str_new(79,0);
  1401. X
  1402. X    if (!len)
  1403. X    len = strlen(s);
  1404. X    str_nset(str,s,len);
  1405. X    return str;
  1406. X}
  1407. X
  1408. XSTR *
  1409. Xstr_nmake(n)
  1410. Xdouble n;
  1411. X{
  1412. X    register STR *str = Str_new(80,0);
  1413. X
  1414. X    str_numset(str,n);
  1415. X    return str;
  1416. X}
  1417. X
  1418. X/* make an exact duplicate of old */
  1419. X
  1420. XSTR *
  1421. Xstr_smake(old)
  1422. Xregister STR *old;
  1423. X{
  1424. X    register STR *new = Str_new(81,0);
  1425. X
  1426. X    if (!old)
  1427. X    return Nullstr;
  1428. X    if (old->str_state == SS_FREE) {
  1429. X    warn("semi-panic: attempt to dup freed string");
  1430. X    return Nullstr;
  1431. X    }
  1432. X    if (old->str_state == SS_INCR && !(old->str_pok & 2))
  1433. X    Str_Grow(old,0);
  1434. X    if (new->str_ptr)
  1435. X    Safefree(new->str_ptr);
  1436. X    Copy(old,new,1,STR);
  1437. X    if (old->str_ptr) {
  1438. X    new->str_ptr = nsavestr(old->str_ptr,old->str_len);
  1439. X    new->str_pok &= ~SP_TEMP;
  1440. X    }
  1441. X    return new;
  1442. X}
  1443. X
  1444. Xstr_reset(s,stash)
  1445. Xregister char *s;
  1446. XHASH *stash;
  1447. X{
  1448. X    register HENT *entry;
  1449. X    register STAB *stab;
  1450. X    register STR *str;
  1451. X    register int i;
  1452. X    register SPAT *spat;
  1453. X    register int max;
  1454. X
  1455. X    if (!*s) {        /* reset ?? searches */
  1456. X    for (spat = stash->tbl_spatroot;
  1457. X      spat != Nullspat;
  1458. X      spat = spat->spat_next) {
  1459. X        spat->spat_flags &= ~SPAT_USED;
  1460. X    }
  1461. X    return;
  1462. X    }
  1463. X
  1464. X    /* reset variables */
  1465. X
  1466. X    if (!stash->tbl_array)
  1467. X    return;
  1468. X    while (*s) {
  1469. X    i = *s;
  1470. X    if (s[1] == '-') {
  1471. X        s += 2;
  1472. X    }
  1473. X    max = *s++;
  1474. X    for ( ; i <= max; i++) {
  1475. X        for (entry = stash->tbl_array[i];
  1476. X          entry;
  1477. X          entry = entry->hent_next) {
  1478. X        stab = (STAB*)entry->hent_val;
  1479. X        str = stab_val(stab);
  1480. X        str->str_cur = 0;
  1481. X        str->str_nok = 0;
  1482. X#ifdef TAINT
  1483. X        str->str_tainted = tainted;
  1484. X#endif
  1485. X        if (str->str_ptr != Nullch)
  1486. X            str->str_ptr[0] = '\0';
  1487. X        if (stab_xarray(stab)) {
  1488. X            aclear(stab_xarray(stab));
  1489. X        }
  1490. X        if (stab_xhash(stab)) {
  1491. X            hclear(stab_xhash(stab), FALSE);
  1492. X            if (stab == envstab)
  1493. X            environ[0] = Nullch;
  1494. X        }
  1495. X        }
  1496. X    }
  1497. X    }
  1498. X}
  1499. X
  1500. X#ifdef TAINT
  1501. Xtaintproper(s)
  1502. Xchar *s;
  1503. X{
  1504. X#ifdef DEBUGGING
  1505. X    if (debug & 2048)
  1506. X    fprintf(stderr,"%s %d %d %d\n",s,tainted,uid, euid);
  1507. X#endif
  1508. X    if (tainted && (!euid || euid != uid || egid != gid)) {
  1509. X    if (!unsafe)
  1510. X        fatal("%s", s);
  1511. X    else if (dowarn)
  1512. X        warn("%s", s);
  1513. X    }
  1514. X}
  1515. X
  1516. Xtaintenv()
  1517. X{
  1518. X    register STR *envstr;
  1519. X
  1520. X    envstr = hfetch(stab_hash(envstab),"PATH",4,FALSE);
  1521. X    if (envstr == &str_undef || envstr->str_tainted) {
  1522. X    tainted = 1;
  1523. X    if (envstr->str_tainted == 2)
  1524. X        taintproper("Insecure directory in PATH");
  1525. X    else
  1526. X        taintproper("Insecure PATH");
  1527. X    }
  1528. X    envstr = hfetch(stab_hash(envstab),"IFS",3,FALSE);
  1529. X    if (envstr != &str_undef && envstr->str_tainted) {
  1530. X    tainted = 1;
  1531. X    taintproper("Insecure IFS");
  1532. X    }
  1533. X}
  1534. X#endif /* TAINT */
  1535. !STUFFY!FUNK!
  1536. echo Extracting Copying
  1537. sed >Copying <<'!STUFFY!FUNK!' -e 's/X//'
  1538. X            GNU GENERAL PUBLIC LICENSE
  1539. X             Version 1, February 1989
  1540. X
  1541. X Copyright (C) 1989 Free Software Foundation, Inc.
  1542. X                    675 Mass Ave, Cambridge, MA 02139, USA
  1543. X Everyone is permitted to copy and distribute verbatim copies
  1544. X of this license document, but changing it is not allowed.
  1545. X
  1546. X                Preamble
  1547. X
  1548. X  The license agreements of most software companies try to keep users
  1549. Xat the mercy of those companies.  By contrast, our General Public
  1550. XLicense is intended to guarantee your freedom to share and change free
  1551. Xsoftware--to make sure the software is free for all its users.  The
  1552. XGeneral Public License applies to the Free Software Foundation's
  1553. Xsoftware and to any other program whose authors commit to using it.
  1554. XYou can use it for your programs, too.
  1555. X
  1556. X  When we speak of free software, we are referring to freedom, not
  1557. Xprice.  Specifically, the General Public License is designed to make
  1558. Xsure that you have the freedom to give away or sell copies of free
  1559. Xsoftware, that you receive source code or can get it if you want it,
  1560. Xthat you can change the software or use pieces of it in new free
  1561. Xprograms; and that you know you can do these things.
  1562. X
  1563. X  To protect your rights, we need to make restrictions that forbid
  1564. Xanyone to deny you these rights or to ask you to surrender the rights.
  1565. XThese restrictions translate to certain responsibilities for you if you
  1566. Xdistribute copies of the software, or if you modify it.
  1567. X
  1568. X  For example, if you distribute copies of a such a program, whether
  1569. Xgratis or for a fee, you must give the recipients all the rights that
  1570. Xyou have.  You must make sure that they, too, receive or can get the
  1571. Xsource code.  And you must tell them their rights.
  1572. X
  1573. X  We protect your rights with two steps: (1) copyright the software, and
  1574. X(2) offer you this license which gives you legal permission to copy,
  1575. Xdistribute and/or modify the software.
  1576. X
  1577. X  Also, for each author's protection and ours, we want to make certain
  1578. Xthat everyone understands that there is no warranty for this free
  1579. Xsoftware.  If the software is modified by someone else and passed on, we
  1580. Xwant its recipients to know that what they have is not the original, so
  1581. Xthat any problems introduced by others will not reflect on the original
  1582. Xauthors' reputations.
  1583. X
  1584. X  The precise terms and conditions for copying, distribution and
  1585. Xmodification follow.
  1586. X
  1587. X            GNU GENERAL PUBLIC LICENSE
  1588. X   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
  1589. X
  1590. X  0. This License Agreement applies to any program or other work which
  1591. Xcontains a notice placed by the copyright holder saying it may be
  1592. Xdistributed under the terms of this General Public License.  The
  1593. X"Program", below, refers to any such program or work, and a "work based
  1594. Xon the Program" means either the Program or any work containing the
  1595. XProgram or a portion of it, either verbatim or with modifications.  Each
  1596. Xlicensee is addressed as "you".
  1597. X
  1598. X  1. You may copy and distribute verbatim copies of the Program's source
  1599. Xcode as you receive it, in any medium, provided that you conspicuously and
  1600. Xappropriately publish on each copy an appropriate copyright notice and
  1601. Xdisclaimer of warranty; keep intact all the notices that refer to this
  1602. XGeneral Public License and to the absence of any warranty; and give any
  1603. Xother recipients of the Program a copy of this General Public License
  1604. Xalong with the Program.  You may charge a fee for the physical act of
  1605. Xtransferring a copy.
  1606. X
  1607. X  2. You may modify your copy or copies of the Program or any portion of
  1608. Xit, and copy and distribute such modifications under the terms of Paragraph
  1609. X1 above, provided that you also do the following:
  1610. X
  1611. X    a) cause the modified files to carry prominent notices stating that
  1612. X    you changed the files and the date of any change; and
  1613. X
  1614. X    b) cause the whole of any work that you distribute or publish, that
  1615. X    in whole or in part contains the Program or any part thereof, either
  1616. X    with or without modifications, to be licensed at no charge to all
  1617. X    third parties under the terms of this General Public License (except
  1618. X    that you may choose to grant warranty protection to some or all
  1619. X    third parties, at your option).
  1620. X
  1621. X    c) If the modified program normally reads commands interactively when
  1622. X    run, you must cause it, when started running for such interactive use
  1623. X    in the simplest and most usual way, to print or display an
  1624. X    announcement including an appropriate copyright notice and a notice
  1625. X    that there is no warranty (or else, saying that you provide a
  1626. X    warranty) and that users may redistribute the program under these
  1627. X    conditions, and telling the user how to view a copy of this General
  1628. X    Public License.
  1629. X
  1630. X    d) You may charge a fee for the physical act of transferring a
  1631. X    copy, and you may at your option offer warranty protection in
  1632. X    exchange for a fee.
  1633. X
  1634. XMere aggregation of another independent work with the Program (or its
  1635. Xderivative) on a volume of a storage or distribution medium does not bring
  1636. Xthe other work under the scope of these terms.
  1637. X
  1638. X  3. You may copy and distribute the Program (or a portion or derivative of
  1639. Xit, under Paragraph 2) in object code or executable form under the terms of
  1640. XParagraphs 1 and 2 above provided that you also do one of the following:
  1641. X
  1642. X    a) accompany it with the complete corresponding machine-readable
  1643. X    source code, which must be distributed under the terms of
  1644. X    Paragraphs 1 and 2 above; or,
  1645. X
  1646. X    b) accompany it with a written offer, valid for at least three
  1647. X    years, to give any third party free (except for a nominal charge
  1648. X    for the cost of distribution) a complete machine-readable copy of the
  1649. X    corresponding source code, to be distributed under the terms of
  1650. X    Paragraphs 1 and 2 above; or,
  1651. X
  1652. X    c) accompany it with the information you received as to where the
  1653. X    corresponding source code may be obtained.  (This alternative is
  1654. X    allowed only for noncommercial distribution and only if you
  1655. X    received the program in object code or executable form alone.)
  1656. X
  1657. XSource code for a work means the preferred form of the work for making
  1658. Xmodifications to it.  For an executable file, complete source code means
  1659. Xall the source code for all modules it contains; but, as a special
  1660. Xexception, it need not include source code for modules which are standard
  1661. Xlibraries that accompany the operating system on which the executable
  1662. Xfile runs, or for standard header files or definitions files that
  1663. Xaccompany that operating system.
  1664. X
  1665. X  4. You may not copy, modify, sublicense, distribute or transfer the
  1666. XProgram except as expressly provided under this General Public License.
  1667. XAny attempt otherwise to copy, modify, sublicense, distribute or transfer
  1668. Xthe Program is void, and will automatically terminate your rights to use
  1669. Xthe Program under this License.  However, parties who have received
  1670. Xcopies, or rights to use copies, from you under this General Public
  1671. XLicense will not have their licenses terminated so long as such parties
  1672. Xremain in full compliance.
  1673. X
  1674. X  5. By copying, distributing or modifying the Program (or any work based
  1675. Xon the Program) you indicate your acceptance of this license to do so,
  1676. Xand all its terms and conditions.
  1677. X
  1678. X  6. Each time you redistribute the Program (or any work based on the
  1679. XProgram), the recipient automatically receives a license from the original
  1680. Xlicensor to copy, distribute or modify the Program subject to these
  1681. Xterms and conditions.  You may not impose any further restrictions on the
  1682. Xrecipients' exercise of the rights granted herein.
  1683. X
  1684. X  7. The Free Software Foundation may publish revised and/or new versions
  1685. Xof the General Public License from time to time.  Such new versions will
  1686. Xbe similar in spirit to the present version, but may differ in detail to
  1687. Xaddress new problems or concerns.
  1688. X
  1689. XEach version is given a distinguishing version number.  If the Program
  1690. Xspecifies a version number of the license which applies to it and "any
  1691. Xlater version", you have the option of following the terms and conditions
  1692. Xeither of that version or of any later version published by the Free
  1693. XSoftware Foundation.  If the Program does not specify a version number of
  1694. Xthe license, you may choose any version ever published by the Free Software
  1695. XFoundation.
  1696. X
  1697. X  8. If you wish to incorporate parts of the Program into other free
  1698. Xprograms whose distribution conditions are different, write to the author
  1699. Xto ask for permission.  For software which is copyrighted by the Free
  1700. XSoftware Foundation, write to the Free Software Foundation; we sometimes
  1701. Xmake exceptions for this.  Our decision will be guided by the two goals
  1702. Xof preserving the free status of all derivatives of our free software and
  1703. Xof promoting the sharing and reuse of software generally.
  1704. X
  1705. X                NO WARRANTY
  1706. X
  1707. X  9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
  1708. XFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
  1709. XOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
  1710. XPROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
  1711. XOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  1712. XMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
  1713. XTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
  1714. XPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
  1715. XREPAIR OR CORRECTION.
  1716. X
  1717. X  10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
  1718. XWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
  1719. XREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
  1720. XINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
  1721. XOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
  1722. XTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
  1723. XYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
  1724. XPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
  1725. XPOSSIBILITY OF SUCH DAMAGES.
  1726. X
  1727. X             END OF TERMS AND CONDITIONS
  1728. X
  1729. X    Appendix: How to Apply These Terms to Your New Programs
  1730. X
  1731. X  If you develop a new program, and you want it to be of the greatest
  1732. Xpossible use to humanity, the best way to achieve this is to make it
  1733. Xfree software which everyone can redistribute and change under these
  1734. Xterms.
  1735. X
  1736. X  To do so, attach the following notices to the program.  It is safest to
  1737. Xattach them to the start of each source file to most effectively convey
  1738. Xthe exclusion of warranty; and each file should have at least the
  1739. X"copyright" line and a pointer to where the full notice is found.
  1740. X
  1741. X    <one line to give the program's name and a brief idea of what it does.>
  1742. X    Copyright (C) 19yy  <name of author>
  1743. X
  1744. X    This program is free software; you can redistribute it and/or modify
  1745. X    it under the terms of the GNU General Public License as published by
  1746. X    the Free Software Foundation; either version 1, or (at your option)
  1747. X    any later version.
  1748. X
  1749. X    This program is distributed in the hope that it will be useful,
  1750. X    but WITHOUT ANY WARRANTY; without even the implied warranty of
  1751. X    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1752. X    GNU General Public License for more details.
  1753. X
  1754. X    You should have received a copy of the GNU General Public License
  1755. X    along with this program; if not, write to the Free Software
  1756. X    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  1757. X
  1758. XAlso add information on how to contact you by electronic and paper mail.
  1759. X
  1760. XIf the program is interactive, make it output a short notice like this
  1761. Xwhen it starts in an interactive mode:
  1762. X
  1763. X    Gnomovision version 69, Copyright (C) 19xx name of author
  1764. X    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
  1765. X    This is free software, and you are welcome to redistribute it
  1766. X    under certain conditions; type `show c' for details.
  1767. X
  1768. XThe hypothetical commands `show w' and `show c' should show the
  1769. Xappropriate parts of the General Public License.  Of course, the
  1770. Xcommands you use may be called something other than `show w' and `show
  1771. Xc'; they could even be mouse-clicks or menu items--whatever suits your
  1772. Xprogram.
  1773. X
  1774. XYou should also get your employer (if you work as a programmer) or your
  1775. Xschool, if any, to sign a "copyright disclaimer" for the program, if
  1776. Xnecessary.  Here a sample; alter the names:
  1777. X
  1778. X  Yoyodyne, Inc., hereby disclaims all copyright interest in the
  1779. X  program `Gnomovision' (a program to direct compilers to make passes
  1780. X  at assemblers) written by James Hacker.
  1781. X
  1782. X  <signature of Ty Coon>, 1 April 1989
  1783. X  Ty Coon, President of Vice
  1784. X
  1785. XThat's all there is to it!
  1786. !STUFFY!FUNK!
  1787. echo Extracting t/cmd/switch.t
  1788. sed >t/cmd/switch.t <<'!STUFFY!FUNK!' -e 's/X//'
  1789. X#!./perl
  1790. X
  1791. X# $Header: switch.t,v 4.0 91/03/20 01:49:44 lwall Locked $
  1792. X
  1793. Xprint "1..18\n";
  1794. X
  1795. Xsub foo1 {
  1796. X    $_ = shift(@_);
  1797. X    $a = 0;
  1798. X    until ($a++) {
  1799. X    next if $_ eq 1;
  1800. X    next if $_ eq 2;
  1801. X    next if $_ eq 3;
  1802. X    next if $_ eq 4;
  1803. X    return 20;
  1804. X    }
  1805. X    continue {
  1806. X    return $_;
  1807. X    }
  1808. X}
  1809. X
  1810. Xprint do foo1(0) == 20 ? "ok 1\n" : "not ok 1\n";
  1811. Xprint do foo1(1) == 1 ? "ok 2\n" : "not ok 2\n";
  1812. Xprint do foo1(2) == 2 ? "ok 3\n" : "not ok 3\n";
  1813. Xprint do foo1(3) == 3 ? "ok 4\n" : "not ok 4\n";
  1814. Xprint do foo1(4) == 4 ? "ok 5\n" : "not ok 5\n";
  1815. Xprint do foo1(5) == 20 ? "ok 6\n" : "not ok 6\n";
  1816. X
  1817. Xsub foo2 {
  1818. X    $_ = shift(@_);
  1819. X    {
  1820. X    last if $_ == 1;
  1821. X    last if $_ == 2;
  1822. X    last if $_ == 3;
  1823. X    last if $_ == 4;
  1824. X    }
  1825. X    continue {
  1826. X    return 20;
  1827. X    }
  1828. X    return $_;
  1829. X}
  1830. X
  1831. Xprint do foo2(0) == 20 ? "ok 7\n" : "not ok 1\n";
  1832. Xprint do foo2(1) == 1 ? "ok 8\n" : "not ok 8\n";
  1833. Xprint do foo2(2) == 2 ? "ok 9\n" : "not ok 9\n";
  1834. Xprint do foo2(3) == 3 ? "ok 10\n" : "not ok 10\n";
  1835. Xprint do foo2(4) == 4 ? "ok 11\n" : "not ok 11\n";
  1836. Xprint do foo2(5) == 20 ? "ok 12\n" : "not ok 12\n";
  1837. X
  1838. Xsub foo3 {
  1839. X    $_ = shift(@_);
  1840. X    if (/^1/) {
  1841. X    return 1;
  1842. X    }
  1843. X    elsif (/^2/) {
  1844. X    return 2;
  1845. X    }
  1846. X    elsif (/^3/) {
  1847. X    return 3;
  1848. X    }
  1849. X    elsif (/^4/) {
  1850. X    return 4;
  1851. X    }
  1852. X    else {
  1853. X    return 20;
  1854. X    }
  1855. X    return 40;
  1856. X}
  1857. X
  1858. Xprint do foo3(0) == 20 ? "ok 13\n" : "not ok 13\n";
  1859. Xprint do foo3(1) == 1 ? "ok 14\n" : "not ok 14\n";
  1860. Xprint do foo3(2) == 2 ? "ok 15\n" : "not ok 15\n";
  1861. Xprint do foo3(3) == 3 ? "ok 16\n" : "not ok 16\n";
  1862. Xprint do foo3(4) == 4 ? "ok 17\n" : "not ok 17\n";
  1863. Xprint do foo3(5) == 20 ? "ok 18\n" : "not ok 18\n";
  1864. !STUFFY!FUNK!
  1865. echo " "
  1866. echo "End of kit 15 (of 36)"
  1867. cat /dev/null >kit15isdone
  1868. run=''
  1869. config=''
  1870. 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
  1871.     if test -f kit${iskit}isdone; then
  1872.     run="$run $iskit"
  1873.     else
  1874.     todo="$todo $iskit"
  1875.     fi
  1876. done
  1877. case $todo in
  1878.     '')
  1879.     echo "You have run all your kits.  Please read README and then type Configure."
  1880.     for combo in *:AA; do
  1881.         if test -f "$combo"; then
  1882.         realfile=`basename $combo :AA`
  1883.         cat $realfile:[A-Z][A-Z] >$realfile
  1884.         rm -rf $realfile:[A-Z][A-Z]
  1885.         fi
  1886.     done
  1887.     rm -rf kit*isdone
  1888.     chmod 755 Configure
  1889.     ;;
  1890.     *)  echo "You have run$run."
  1891.     echo "You still need to run$todo."
  1892.     ;;
  1893. esac
  1894. : Someone might mail this, so...
  1895. exit
  1896.  
  1897. exit 0 # Just in case...
  1898. -- 
  1899. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1900. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1901. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1902. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1903.