home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume21 / strsed / part02 < prev    next >
Encoding:
Internet Message Format  |  1990-03-22  |  29.4 KB

  1. Subject:  v21i029:  String function to do sed(1)/tr(1) manipulations, Part02/03
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 81c6c86a 826ca0a9 06506c2c 354caeec
  5.  
  6. Submitted-by: Terry Jones <terry@pcsbst.pcs.com>
  7. Posting-number: Volume 21, Issue 29
  8. Archive-name: strsed/part02
  9.  
  10. #!/bin/sh
  11. # this is part 2 of a multipart archive
  12. # do not concatenate these parts, unpack them in order with /bin/sh
  13. # file strsed.c continued
  14. #
  15. CurArch=2
  16. if test ! -r s2_seq_.tmp
  17. then echo "Please unpack part 1 first!"
  18.      exit 1; fi
  19. ( read Scheck
  20.   if test "$Scheck" != $CurArch
  21.   then echo "Please unpack part $Scheck next!"
  22.        exit 1;
  23.   else exit 0; fi
  24. ) < s2_seq_.tmp || exit 1
  25. echo "x - Continuing file strsed.c"
  26. sed 's/^X//' << 'SHAR_EOF' >> strsed.c
  27. X                    more_space(1);
  28. X                    new_str[new_pos++] = *tmp++;
  29. X                }
  30. X            }
  31. X
  32. X            /*
  33. X             * Move forward over the matched text.
  34. X             *
  35. X             */
  36. X            str += regs.end[0];
  37. X            str_len -= regs.end[0];
  38. X        }
  39. X    } while (global && match != -1 && *str);
  40. X
  41. X    /*
  42. X     * Copy the final portion of the string. This is the section that
  43. X     * was not matched (and hence which remains unchanged) by the last
  44. X     * match. Then we head off home.
  45. X     *
  46. X     */
  47. X    more_space(str_len);
  48. X    (void) strcpy(new_str + new_pos, str);
  49. X    RETURN(new_str);
  50. X}
  51. X
  52. X#define DIGIT(x) (isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
  53. X
  54. Xstatic char *
  55. Xbackslash_eliminate(str, type, who)
  56. Xchar *str;
  57. Xint type;
  58. Xint who;
  59. X{
  60. X    /*
  61. X     * Remove backslashes from the strings. Turn \040 etc. into a single
  62. X     * character (we allow eight bit values). Currently NUL is not
  63. X     * allowed.
  64. X     *
  65. X     * Turn "\n" and "\t" into '\n' and '\t' characters. Etc.
  66. X     *
  67. X     * The string may grow slightly here. Under normal circumstances
  68. X     * it will stay the same length or get shorter. It is only in the 
  69. X     * case where we have to turn {a-z}{A-Z} into \0{a-z}{A-Z} that
  70. X     * we add two chars. This only happens when we are doing a REPLACEMENT.
  71. X     * So we can't overwrite str, and we have to 
  72. X     * malloc. Sad, but the only ways I could find around it (at this
  73. X     * late stage) were really gross. I allowed an extra 
  74. X     * 100 bytes which should cover most idiotic behaviour.
  75. X     * I count the extra space and exit nicely if they do do something
  76. X     * extremely silly.
  77. X     *
  78. X     * 'i' is an index into new_str.
  79. X     *
  80. X     * 'type' tells us how to interpret escaped characters.
  81. X     *
  82. X     * type = REGEX 
  83. X     *        if the pattern is a regular expression. If it is then
  84. X     *        we leave escaped things alone (except for \n and \t and 
  85. X     *        friends).
  86. X     *
  87. X     * type = REPLACEMENT
  88. X     *        if this is a replacement pattern. In this case we change
  89. X     *        \( and \) to ( and ), but leave \1 etc alone as they are
  90. X     *        register references. - becomes a metacharacter between
  91. X     *        { and }.
  92. X     *
  93. X     * type = NORMAL
  94. X     *        We do \n and \t elimination, as well as \040 etc, plus
  95. X     *        all other characters that we find quoted we unquote.
  96. X     *        type = NORMAL when we do a backslash elimination on the
  97. X     *        string argument to strsed.
  98. X     *
  99. X     * who tells us where to tell mem where to stick the new string.
  100. X     *
  101. X     * \{m,n\} syntax (see ed(1)) is not supported.
  102. X     *
  103. X     */
  104. X
  105. X    static char *mem();
  106. X    char *new_str;
  107. X    int extra = 100;
  108. X    int seenlb = 0;
  109. X    register int i = 0;
  110. X    register int seenbs = 0;
  111. X    int first_half = 0;
  112. X
  113. X    if (type == REPLACEMENT){
  114. X    if (!(new_str = mem(who, strlen(str) + 1 + extra))){
  115. X        return 0;
  116. X    }
  117. X    }
  118. X    else{
  119. X    new_str = str;
  120. X    }
  121. X
  122. X    while (*str){
  123. X        if (seenbs){
  124. X            seenbs = 0;
  125. X            switch (*str){
  126. X                case '\\':{
  127. X                    new_str[i++] = '\\';
  128. X                    str++;
  129. X                    break;
  130. X                }
  131. X
  132. X                case '-':{
  133. X                    if (seenlb){
  134. X                        /* Keep it quoted. */
  135. X                        new_str[i++] = '\\';
  136. X                    }
  137. X                    new_str[i++] = '-';
  138. X                    str++;
  139. X                    break;
  140. X                }
  141. X
  142. X                case '}':{
  143. X                    if (seenlb){
  144. X                        /* Keep it quoted. */
  145. X                        new_str[i++] = '\\';
  146. X                    }
  147. X                    new_str[i++] = '}';
  148. X                    str++;
  149. X                    break;
  150. X                }
  151. X
  152. X                case 'n':{
  153. X                    new_str[i++] = '\n';
  154. X                    str++;
  155. X                    break;
  156. X                }
  157. X
  158. X                case 't':{
  159. X                    new_str[i++] = '\t';
  160. X                    str++;
  161. X                    break;
  162. X                }
  163. X
  164. X                case 's':{
  165. X                    new_str[i++] = ' ';
  166. X                    str++;
  167. X                    break;
  168. X                }
  169. X
  170. X                case 'r':{
  171. X                    new_str[i++] = '\r';
  172. X                    str++;
  173. X                    break;
  174. X                }
  175. X
  176. X                case 'f':{
  177. X                    new_str[i++] = '\f';
  178. X                    str++;
  179. X                    break;
  180. X                }
  181. X
  182. X                case 'b':{
  183. X                    new_str[i++] = '\b';
  184. X                    str++;
  185. X                    break;
  186. X                }
  187. X
  188. X                case 'v':{
  189. X                    new_str[i++] = '\13';
  190. X                    str++;
  191. X                    break;
  192. X                }
  193. X
  194. X                case 'z':{
  195. X                    str++;
  196. X                    break;
  197. X                }
  198. X
  199. X                case '0': case '1': case '2': case '3': case '4':
  200. X                case '5': case '6': case '7': case '8': case '9':{
  201. X
  202. X                    char val;
  203. X
  204. X                    /*
  205. X                     * Three digit octal constant.
  206. X                     *
  207. X                     */
  208. X                    if (*str >= '0' && *str <= '3' && 
  209. X                        *(str + 1) >= '0' && *(str + 1) <= '7' &&
  210. X                        *(str + 2) >= '0' && *(str + 2) <= '7'){
  211. X
  212. X                        val = (DIGIT(*str) << 6) + 
  213. X                              (DIGIT(*(str + 1)) << 3) + 
  214. X                               DIGIT(*(str + 2));
  215. X
  216. X                        if (!val){
  217. X                            /*
  218. X                             * NUL is not allowed.
  219. X                             */
  220. X                            return 0;
  221. X                        }
  222. X
  223. X                        new_str[i++] = val;
  224. X                        str += 3;
  225. X                        break;
  226. X                    }
  227. X
  228. X                    /*
  229. X                     * One or two digit hex constant.
  230. X                     * If two are there they will both be taken.
  231. X                     * Use \z to split them up if this is not wanted.
  232. X                     *
  233. X                     */
  234. X                    if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X') && isxdigit(*(str + 2))){
  235. X                        val = DIGIT(*(str + 2));
  236. X                        if (isxdigit(*(str + 3))){
  237. X                            val = (val << 4) + DIGIT(*(str + 3));
  238. X                            str += 4;
  239. X                        }
  240. X                        else{
  241. X                            str += 3;
  242. X                        }
  243. X
  244. X                        if (!val){
  245. X                            return 0;
  246. X                        }
  247. X
  248. X                        new_str[i++] = val;
  249. X                        break;
  250. X                    }
  251. X
  252. X                    /*
  253. X                     * Two or three decimal digits.
  254. X                     * (One decimal digit is taken as either a register reference
  255. X                     * or as a decimal digit if NORMAL is true below.)
  256. X                     *
  257. X                     */
  258. X                    if (isdigit(*(str + 1))){
  259. X                        val = DIGIT(*str) * 10 + DIGIT(*(str + 1));
  260. X                        if (isdigit(*(str + 2))){
  261. X                            val = 10 * val + DIGIT(*(str + 2));
  262. X                            str += 3;
  263. X                        }
  264. X                        else{
  265. X                            str += 2;
  266. X                        }
  267. X
  268. X                        if (!val){
  269. X                            return 0;
  270. X                        }
  271. X
  272. X                        new_str[i++] = val;
  273. X                        break;
  274. X                    }
  275. X
  276. X                    /*
  277. X                     * A register reference or else a single decimal digit if this
  278. X                     * is a normal string..
  279. X                     *
  280. X                     * Emit \4 (etc) if we are not NORMAL (unless the digit is a 0 
  281. X                     * and we are processing an r.e. This is because \0 makes no 
  282. X                     * sense in an r.e., only in a replacement. If we do have \0 
  283. X                     * and it is an r.e. we return.)
  284. X                     *
  285. X                     */
  286. X                    if (*str == '0' && type == REGEX){
  287. X                        return 0;
  288. X                    }
  289. X
  290. X                    if (type == NORMAL){
  291. X                        if (!(val = DIGIT(*str))){
  292. X                            return 0;
  293. X                        }
  294. X                        new_str[i++] = val;
  295. X                        str++;
  296. X                    }
  297. X                    else{
  298. X                        new_str[i++] = '\\';
  299. X                        new_str[i++] = *str++;
  300. X                    }
  301. X                    break;
  302. X                }
  303. X
  304. X                default:{
  305. X                    if (type == REGEX){
  306. X                        new_str[i++] = '\\';
  307. X                    }
  308. X                    new_str[i++] = *str++;
  309. X                    break;
  310. X                }
  311. X            }
  312. X        }
  313. X        else{
  314. X            if (*str == '\\'){
  315. X                seenbs = 1;
  316. X                str++;
  317. X            }
  318. X            else if (type == REPLACEMENT && *str == '}'){
  319. X                if (*(str + 1) == '{' && first_half){
  320. X                    new_str[i++] = *str++;
  321. X                    new_str[i++] = *str++;
  322. X            first_half = 0;
  323. X                }
  324. X                else{
  325. X                    seenlb = 0;
  326. X                    new_str[i++] = *str++;
  327. X                }
  328. X            }
  329. X            else if (type == REPLACEMENT && !seenlb && *str == '{'){
  330. X                /*
  331. X                 * Within { and }, \- should be left as such. So we can differentiate
  332. X                 * between s/fred/\-/ and s/fred/{\-a-z}{+A-Z}
  333. X                 *
  334. X                 * We stick in a "\0" here in the case that \X has not just been
  335. X                 * seen. (X = 0..9) Which is to say, {a-z}{A-Z} defaults to 
  336. X                 * \0{a-z}{A-Z}
  337. X                 *
  338. X                 */
  339. X
  340. X                seenlb = 1;
  341. X        first_half = 1;
  342. X
  343. X                if (i < 2 || new_str[i - 2] != '\\' || !(new_str[i - 1] >= '0' && new_str[i - 1] <= '9')){
  344. X                    if ((extra -= 2) < 0){
  345. X                        /* ran out of extra room. */
  346. X                        return 0;
  347. X                    }
  348. X                    new_str[i++] = '\\';
  349. X                    new_str[i++] = '0';
  350. X                }
  351. X                new_str[i++] = *str++;
  352. X            }
  353. X            else{
  354. X                /* 
  355. X                 * A normal char.
  356. X                 *
  357. X                 */
  358. X                new_str[i++] = *str++;
  359. X            }
  360. X        }
  361. X    }
  362. X
  363. X    if (seenbs){
  364. X        /*
  365. X         * The final character was a '\'. Ignore it.
  366. X         *
  367. X         */
  368. X    }
  369. X
  370. X    new_str[i] = '\0';
  371. X    return new_str;
  372. X}
  373. X
  374. Xstatic char *
  375. Xbuild_map(s, map)
  376. Xchar *s;
  377. Xchar *map;
  378. X{
  379. X    /*
  380. X     * Produce a mapping table for the given transliteration.
  381. X     * We are passed something that looks like "{a-z}{A-Z}"
  382. X     * Look out for \ chars, these are used to quote } and -.
  383. X     *
  384. X     * Return a pointer to the char after the closing }.
  385. X     * We cannot clobber s.
  386. X     *
  387. X     * The building of maps is somewhat optimised.
  388. X     * If the string is the same as the last one we were 
  389. X     * called with then we don't do anything. It would be better
  390. X     * to remember all the transliterations we have seen, in
  391. X     * order (because in a global substitution we will
  392. X     * apply them in the same order repeatedly) and then we
  393. X     * could do the minimum amount of building. This is a 
  394. X     * compromise because it is a fairly safe bet that there will 
  395. X     * not be more than one transliteration done.
  396. X     *
  397. X     */
  398. X
  399. X    char *in;
  400. X    char *out;
  401. X    char *str;
  402. X    char *tmp;
  403. X    char c;
  404. X    static char *mem();
  405. X    static char nextch();
  406. X    int i = 0;
  407. X    int range_count = 0;
  408. X    int seenbs = 0;
  409. X    static char *last = 0;
  410. X    static int last_len;
  411. X
  412. X    if (!s){
  413. X        return 0;
  414. X    }
  415. X
  416. X    if (last && !strncmp(s, last, last_len)){
  417. X        /* Re-use the map. */
  418. X        return s + last_len;
  419. X    }
  420. X    else{
  421. X    /*
  422. X     * Make a copy of s in both 'last' and 'str'
  423. X     */
  424. X    int len = strlen(s) + 1;
  425. X        if (!(str = mem(MEM_MAP, len)) || !(last = mem(MEM_MAP_SAVE, len))){
  426. X            return 0;
  427. X        }
  428. X    str[0] = last[0] = '\0';
  429. X    strcat(str, s);
  430. X    strcat(last, s);
  431. X    }
  432. X
  433. X    tmp = str + 1;
  434. X    in = str;
  435. X
  436. X    while (*tmp){
  437. X        if (seenbs){
  438. X            if (*tmp == '-'){
  439. X                /* 
  440. X                 * Keep the \ before a - since this is the range
  441. X                 * separating metacharacter. We don't keep } quoted,
  442. X                 * we just put it in. Then it is passed as a normal
  443. X                 * char (no longer a metachar) to nextch().
  444. X                 *
  445. X                 */
  446. X                str[i++] = '\\';
  447. X            }
  448. X            str[i++] = *tmp++;
  449. X            seenbs = 0;
  450. X        }
  451. X        else{
  452. X            if (*tmp == '\\'){
  453. X                seenbs = 1;
  454. X                tmp++;
  455. X            }
  456. X            else if (*tmp == '}'){
  457. X                if (!range_count){
  458. X                    /* seen first range. */
  459. X                    range_count = 1;
  460. X                    str[i++] = '\0';
  461. X                    tmp++;
  462. X                    while (*tmp == ' ' || *tmp == '\t'){
  463. X                        tmp++;
  464. X                    }
  465. X                    if (*tmp != '{'){
  466. X                        return 0;
  467. X                    }
  468. X                    out = str + i;
  469. X                    tmp++;
  470. X                }
  471. X                else{
  472. X                    /* seen both ranges. */
  473. X                    str[i++] = '\0';
  474. X                    tmp++;
  475. X                    range_count = 2; 
  476. X                    break;
  477. X                }
  478. X            }
  479. X            else{
  480. X                /* A plain defenceless character. */
  481. X                str[i++] = *tmp++;
  482. X            }
  483. X        }
  484. X    }
  485. X
  486. X    if (range_count != 2){
  487. X        return 0;
  488. X    }
  489. X
  490. X    last_len = tmp - str;
  491. X
  492. X    /*
  493. X     * Now 'out' and 'in' both point to character ranges.
  494. X     * These will look something like "A-Z" but may be 
  495. X     * more complicated and have {} and - in them elsewhere.
  496. X     *
  497. X     */
  498. X    
  499. X    for (i = 0; i < 1 << BYTEWIDTH; i++){
  500. X        map[i] = i;
  501. X    }
  502. X
  503. X    /*
  504. X     * Ready the range expanding function.
  505. X     *
  506. X     */
  507. X    (void) nextch(in, 0);
  508. X    (void) nextch(out, 1);
  509. X
  510. X    /*
  511. X     * For each char in 'in', assign it a value in
  512. X     * 'map' corresponding to the next char in 'out'.
  513. X     *
  514. X     */
  515. X
  516. X    while ((c = nextch(0, 0))){
  517. X        map[c] = nextch(0, 1);
  518. X    }
  519. X
  520. X    return tmp;
  521. X}
  522. X
  523. Xstatic char
  524. Xnextch(str, who)
  525. Xchar *str;
  526. Xint who;
  527. X{
  528. X    /*
  529. X     * Given a range like {a-z0237-9}
  530. X     * return successive characters from the range on
  531. X     * successive calls. The first call (when str != 0)
  532. X     * sets things up.
  533. X     *
  534. X     * We must handle strange things like
  535. X     * {a-b-c-z}            = {a-z}
  536. X     * and {z-l-a}          = {z-a}
  537. X     * and {f-f-f-f-h}      = {f-h}
  538. X     * and {a-z-f-h-y-d-b}  = {a-b}
  539. X     *
  540. X     * and so on.
  541. X     *
  542. X     * This function will remember two strings and will return
  543. X     * the next charcter in the range specified by 'who'. This
  544. X     * makes the building of the transliteration table above
  545. X     * a trivial loop.
  546. X     *
  547. X     * I can't be bothered to comment this as much as it
  548. X     * deserves right now... 8-)
  549. X     *
  550. X     */
  551. X
  552. X    static char *what[2] = {0, 0};
  553. X    static char last[2] = {0, 0};
  554. X    static int increment[2];
  555. X    static int pos[2];
  556. X
  557. X    if (who < 0 || who > 1){
  558. X        return 0;
  559. X    }
  560. X
  561. X    if (str){
  562. X        /* Set up for this string. */
  563. X        what[who] = str;
  564. X        pos[who] = 0;
  565. X        return 1;
  566. X    }
  567. X    else if (!what[who]){
  568. X        return 0;
  569. X    }
  570. X
  571. X    if (!pos[who] && what[who][0] == '-'){
  572. X        return 0;
  573. X    }
  574. X
  575. X    switch (what[who][pos[who]]){
  576. X        
  577. X        case '-':{
  578. X            /* we're in mid-range. */
  579. X            last[who] += increment[who];
  580. X            if (what[who][pos[who] + 1] == last[who]){
  581. X                pos[who] += 2;
  582. X            }
  583. X            return last[who];
  584. X        }
  585. X
  586. X        case '\0':{
  587. X            /* 
  588. X             * We've finished. Keep on returning the
  589. X             * last thing you saw if who = 1.
  590. X             */
  591. X            if (who){
  592. X                return last[1];
  593. X            }
  594. X            return 0;
  595. X        }
  596. X
  597. X        /* FALLTHROUGH */
  598. X        case '\\':{
  599. X            pos[who]++;
  600. X        }
  601. X
  602. X        default:{
  603. X            last[who] = what[who][pos[who]++];
  604. X            /*
  605. X             * If we have reached a '-' then this is the start of a
  606. X             * range. Keep on moving forward until we see a sensible 
  607. X             * end of range character. Then set up increment so that
  608. X             * we do the right thing next time round. We leave pos
  609. X             * pointing at the '-' sign.
  610. X             *
  611. X             */
  612. X
  613. X            while (what[who][pos[who]] == '-'){
  614. X                int inc = 1;
  615. X                if (what[who][pos[who] + inc] == '\\'){
  616. X                    inc++;
  617. X                }
  618. X                if (!what[who][pos[who] + inc]){
  619. X                    return 0;
  620. X                }
  621. X                if (what[who][pos[who] + inc + 1] == '-'){
  622. X                    pos[who] += inc + 1;
  623. X                    continue;
  624. X                }
  625. X                increment[who] = what[who][pos[who] + inc] - last[who];
  626. X                if (!increment[who]){
  627. X                    pos[who] += 2;
  628. X                    continue;
  629. X                }
  630. X                if (increment[who] > 0){
  631. X                    increment[who] = 1;
  632. X                    break;
  633. X                }
  634. X                else if (increment[who] < 0){
  635. X                    increment[who] = -1;
  636. X                    break;
  637. X                }
  638. X            }
  639. X            return last[who];
  640. X        }
  641. X    }
  642. X}
  643. X
  644. Xstatic char *
  645. Xmem(who, size)
  646. Xint who;
  647. Xint size;
  648. X{
  649. X    /*
  650. X     * Get 'size' bytes of memeory one way or another.
  651. X     *
  652. X     * The 'mem_slots' array holds currently allocated hunks.
  653. X     * If we can use one that's already in use then do so, otherwise
  654. X     * try and find a hunk not in use somewhere else in the table.
  655. X     * As a last resort call malloc. All a bit specialised and
  656. X     * not too clear. Seems to works fine though.
  657. X     */
  658. X    
  659. X    static void mem_save();
  660. X
  661. X    if (who < 0 || who >= MEM_SLOTS){
  662. X    return 0;
  663. X    }
  664. X    
  665. X    if (mem_slots[who].used){
  666. X    /*
  667. X     * There is already something here. Either move/free it or
  668. X     * return it if it is already big enough to hold this request.
  669. X     */
  670. X    if (mem_slots[who].size >= size){
  671. X        /* It is already big enough. */
  672. X        return mem_slots[who].s;
  673. X    }
  674. X    else{
  675. X        mem_save(who);
  676. X    }
  677. X    }
  678. X    else{
  679. X    /*
  680. X     * The slot was not in use. Check to see if there is space
  681. X     * allocated here already that we can use. If there is and
  682. X     * we can, use it, if there is and it's not big enough try to
  683. X     * save it. if there isn't then try to find it in another free slot,
  684. X     * otherwise don't worry, the malloc below will get us some.
  685. X     */
  686. X    if (mem_slots[who].s && mem_slots[who].size >= size){
  687. X        /* We'll take it. */
  688. X        mem_slots[who].used = 1;
  689. X        return mem_slots[who].s;
  690. X    }
  691. X    
  692. X    if (mem_slots[who].s){
  693. X        mem_save(who);
  694. X    }
  695. X    else{
  696. X        static int mem_find();
  697. X        int x = mem_find(size);
  698. X        if (x != -1){
  699. X        mem_slots[who].s = mem_slots[x].s;
  700. X        mem_slots[who].size = mem_slots[x].size;
  701. X        mem_slots[who].used = 1;
  702. X        mem_slots[x].s = (char *)0;
  703. X        return mem_slots[who].s;
  704. X        }
  705. X    }
  706. X    }
  707. X    
  708. X    /*
  709. X     * Have to use malloc 8-(
  710. X     */
  711. X
  712. X    if (!(mem_slots[who].s = malloc((unsigned)size))){
  713. X    return 0;
  714. X    }
  715. X    mem_slots[who].size = size;
  716. X    mem_slots[who].used = 1;
  717. X    
  718. X    return mem_slots[who].s;
  719. X}
  720. X
  721. Xstatic int
  722. Xmem_find(size)
  723. Xint size;
  724. X{
  725. X    /*
  726. X     * See if we can find an unused but allocated slot with 'size' 
  727. X     * (or more) space available. Return the index, or -1 if not.
  728. X     */
  729. X     
  730. X    register int i;
  731. X    
  732. X    for (i = 0; i < MEM_SLOTS; i++){
  733. X    if (!mem_slots[i].used && mem_slots[i].s && mem_slots[i].size >= size){
  734. X        return i;
  735. X    }
  736. X    }
  737. X    return -1;
  738. X}
  739. X
  740. Xstatic void
  741. Xmem_save(x)
  742. Xint x;
  743. X{
  744. X    /*
  745. X     * There is some memory in mem_slots[x] and we try to save it rather
  746. X     * than free it. In order we try to
  747. X     *
  748. X     * 1) put it in an unused slot that has no allocation.
  749. X     * 2) put it in an unused slot that has an allocation smaller than x's
  750. X     * 3) free it since there are no free slots and all the full ones are bigger.
  751. X     *
  752. X     */
  753. X
  754. X    register int i;
  755. X    register int saved = 0;
  756. X    
  757. X    /*
  758. X     * First we try to find somewhere unused and with no present allocation.
  759. X     */
  760. X    for (i = 0; i < MEM_SLOTS; i++){
  761. X    if (!mem_slots[i].used && !mem_slots[i].s){
  762. X        saved = 1;
  763. X        mem_slots[i].s = mem_slots[x].s;
  764. X        mem_slots[i].size = mem_slots[x].size;
  765. X        mem_slots[i].used = 0;
  766. X        break;
  767. X    }
  768. X    }
  769. X    
  770. X    /*
  771. X     * No luck yet. Try for a place that is not being used but which has
  772. X     * space allocated, and which is smaller than us (and all other such spots). 
  773. X     * Pick on the smallest, yeah.
  774. X     */
  775. X    if (!saved){
  776. X    register int small = -1;
  777. X    register int small_val = 1000000;
  778. X    for (i = 0; i < MEM_SLOTS; i++){
  779. X        if (!mem_slots[i].used && mem_slots[i].size < mem_slots[x].size && mem_slots[i].size < small_val){
  780. X        small_val = mem_slots[i].size;
  781. X        small = i;
  782. X        }
  783. X    }
  784. X    
  785. X    if (small != -1){
  786. X        saved = 1;
  787. X        /* We got one, now clobber it... */
  788. X        free(mem_slots[small].s);
  789. X        /* and move on in. */
  790. X        mem_slots[small].s = mem_slots[x].s;
  791. X        mem_slots[small].size = mem_slots[x].size;
  792. X        mem_slots[small].used = 0;
  793. X    }
  794. X    }
  795. X    
  796. X    if (!saved){
  797. X    /* Have to toss it away. */
  798. X    free(mem_slots[x].s);
  799. X    }
  800. X}
  801. X
  802. Xstatic void
  803. Xmem_init()
  804. X{
  805. X    /*
  806. X     * Clear all the memory slots.
  807. X     */
  808. X
  809. X    register int i;
  810. X    
  811. X    for (i = 0; i < MEM_SLOTS; i++){
  812. X    mem_slots[i].s = (char *)0;
  813. X    mem_slots[i].used = 0;
  814. X    }
  815. X}
  816. X
  817. Xstatic void
  818. Xmem_free(except)
  819. Xchar *except;
  820. X{
  821. X    /*
  822. X     * "Clear out" all the memory slots. Actually we do no freeing since
  823. X     * we may well be called again. We just mark the slots as unused. Next
  824. X     * time round they might be useful - the addresses and sizes are still there.
  825. X     *
  826. X     * For the slot (if any) whose address is 'except', we actually set the
  827. X     * address to 0. This is done because we are called ONLY from the macro
  828. X     * RETURN() in strsed() and we intend to return the value in 'except'.
  829. X     * Once this is done, strsed should (in theory) have no knowledge at all
  830. X     * of the address it passed back last time. That way we won't clobber it
  831. X     * and cause all sorts of nasty problems.
  832. X     */
  833. X
  834. X    register int i;
  835. X    
  836. X    for (i = 0; i < MEM_SLOTS; i++){
  837. X    mem_slots[i].used = 0;
  838. X    if (mem_slots[i].s == except){
  839. X        mem_slots[i].s = (char *)0;
  840. X        mem_slots[i].size = 0;
  841. X    }
  842. X    } 
  843. X}
  844. X
  845. SHAR_EOF
  846. echo "File strsed.c is complete"
  847. chmod 0644 strsed.c || echo "restore of strsed.c fails"
  848. set `wc -c strsed.c`;Sum=$1
  849. if test "$Sum" != "36532"
  850. then echo original size 36532, current size $Sum;fi
  851. echo "x - extracting Makefile (Text)"
  852. sed 's/^X//' << 'SHAR_EOF' > Makefile &&
  853. X#
  854. X# Makefile for strsed
  855. X#
  856. X
  857. X#
  858. X# Use gcc if you have it...
  859. X# (The MIPS cc produces a regex.o which dumps core).
  860. X#
  861. X
  862. X#CC = cc
  863. X
  864. XCC = gcc
  865. XCFLAGS = -O
  866. X
  867. X
  868. Xall : check
  869. X
  870. Xcheck : check1 check2
  871. X    cat examples1 | ./check1
  872. X    cat examples2 | ./check2
  873. X
  874. Xcheck1 : strsed.o regex.o check1.o
  875. X    $(CC) $(CFLAGS) -o check1 strsed.o regex.o check1.o
  876. X
  877. Xcheck2 : strsed.o regex.o check2.o
  878. X    $(CC) $(CFLAGS) -o check2 strsed.o regex.o check2.o
  879. X
  880. Xstrsed.o : regex.h
  881. Xregex.o : regex.h
  882. X
  883. Xclean :
  884. X    rm -f check?.o
  885. X
  886. Xclobber : clean
  887. X    rm -f strsed.o check[12] MANIFEST
  888. SHAR_EOF
  889. chmod 0644 Makefile || echo "restore of Makefile fails"
  890. set `wc -c Makefile`;Sum=$1
  891. if test "$Sum" != "526"
  892. then echo original size 526, current size $Sum;fi
  893. echo "x - extracting check1.c (Text)"
  894. sed 's/^X//' << 'SHAR_EOF' > check1.c &&
  895. X#include <stdio.h>
  896. X
  897. Xint
  898. Xmain()
  899. X{
  900. X    /*
  901. X     * Check simple searching.
  902. X     *
  903. X     * Input consists of sets of three lines containing
  904. X     *
  905. X     *      text
  906. X     *      pattern
  907. X     *      expected new text
  908. X     *
  909. X     * See the file examples1
  910. X     *
  911. X     */
  912. X
  913. X    extern int strcmp();
  914. X    extern char *strsed();
  915. X
  916. X    char text[1024];
  917. X    char pat[1024];
  918. X    char ans[1024];
  919. X    register char *result;
  920. X    register int testno = 0;
  921. X    int error = 0;
  922. X
  923. X    while (gets(text) && gets(pat) && gets(ans)){
  924. X        testno++;
  925. X        result = strsed(text, pat, 0);
  926. X        if (strcmp(ans, result)){
  927. X            error = 1;
  928. X            printf("WARNING (test %d)... strsed(%s, %s) returns '%s'\nExpected '%s'\n", 
  929. X                testno, text, pat, result, ans);
  930. X            fflush(stdout);
  931. X        }
  932. X    }
  933. X
  934. X    if (!error){
  935. X        printf("Substitution and transliteration tests passed successfully.\n");
  936. X    }
  937. X
  938. X    return 0;
  939. X}
  940. SHAR_EOF
  941. chmod 0644 check1.c || echo "restore of check1.c fails"
  942. set `wc -c check1.c`;Sum=$1
  943. if test "$Sum" != "775"
  944. then echo original size 775, current size $Sum;fi
  945. echo "x - extracting check2.c (Text)"
  946. sed 's/^X//' << 'SHAR_EOF' > check2.c &&
  947. X#include <stdio.h>
  948. X
  949. Xint
  950. Xmain()
  951. X{
  952. X    /*
  953. X     * Check simple searching.
  954. X     *
  955. X     * Input consists of sets of four lines containing
  956. X     *
  957. X     *      text
  958. X     *      pattern
  959. X     *      expected start of match
  960. X     *      expected end of match
  961. X     *
  962. X     * See the file examples2
  963. X     *
  964. X     */
  965. X
  966. X    extern int atoi();
  967. X    extern char *strsed();
  968. X
  969. X    char text[1024];
  970. X    char pat[1024];
  971. X    char ans1[10];
  972. X    char ans2[10];
  973. X    int range[2];
  974. X    int low;
  975. X    int high;
  976. X    register int testno = 0;
  977. X    int error = 0;
  978. X
  979. X    while (gets(text) && gets(pat) && gets(ans1) && gets(ans2)){
  980. X        testno++;
  981. X        strsed(text, pat, range);
  982. X        low = atoi(ans1);
  983. X        high = atoi(ans2);
  984. X        if (low != range[0] || high != range[1]){
  985. X            error = 1;
  986. X            printf("WARNING (test %d)... strsed(%s, %s) returns range %d-%d (Expected %d-%d)\n", 
  987. X                testno, text, pat, range[0], range[1], low, high);
  988. X            fflush(stdout);
  989. X        }
  990. X    }
  991. X
  992. X    if (!error){
  993. X        printf("Searching tests passed successfully.\n");
  994. X    }
  995. X
  996. X    return 0;
  997. X}
  998. SHAR_EOF
  999. chmod 0644 check2.c || echo "restore of check2.c fails"
  1000. set `wc -c check2.c`;Sum=$1
  1001. if test "$Sum" != "907"
  1002. then echo original size 907, current size $Sum;fi
  1003. echo "x - extracting examples1 (Text)"
  1004. sed 's/^X//' << 'SHAR_EOF' > examples1 &&
  1005. Xabcdef
  1006. Xs/bx?m?m?m?1?2?3?c/BC/
  1007. XaBCdef
  1008. Xabcdef
  1009. Xs/bx?c/BC/
  1010. XaBCdef
  1011. X/initial/slash
  1012. X/^\///
  1013. Xinitial/slash
  1014. Xfunny ranges
  1015. X/.*/{n-a-\--\040-\0xd-\d-n}{1-\x-\--\--p-7-1}/
  1016. Xfu11y ra1ges
  1017. Xfunny ranges
  1018. X/.*/{n-a-\--\040-\0xd-\d-n}{1-\x-\--\--p-7-4}/
  1019. Xfu11y ra1ges
  1020. Xfunny ranges
  1021. X/.*/{r-a-\--\040-\0xd-\d-u}{1-\x-\--\--p-7-4}/
  1022. Xf4nny 1ange2
  1023. Xfunny ranges
  1024. X/.*/{r-a-\--\d-u}{1-\x-\--\--p-7-4}/
  1025. Xf4nny 1ange2
  1026. Xfunny ranges
  1027. X/.*/{r-a-l-d-u}{1-x-p-7-4}/
  1028. Xf4nny 1ange2
  1029. Xfunny ranges
  1030. X/.*/{a-f-c}{1-9}/
  1031. Xfunny r1nges
  1032. Xhere we go
  1033. X/.*/{e}{\}}/
  1034. Xh}r} w} go
  1035. Xhere we go
  1036. X/.*/{e}{\-}/
  1037. Xh-r- w- go
  1038. Xhere we go
  1039. X/.*/{hre}{{\}\-}/
  1040. X{-}- w- go
  1041. X  this is a line  
  1042. Xg/\([\t\s]*\)\(.\)\([^\t\s]*\)/\1\2{a-z}{A-Z}\3/
  1043. X  This Is A Line  
  1044. Xjooooneees         waaaassss     heeeerrrrrreeeee
  1045. Xg/\([a-z\s]\)\1+/\1/
  1046. Xjones was here
  1047. Xtry an inverse range
  1048. Xg/[^e]/X/
  1049. XXXXXXXXXXXeXXeXXXXXe
  1050. Xtry an inverse range
  1051. Xg/[^a-z]/X/
  1052. XtryXanXinverseXrange
  1053. Xcapitalise    first       letters of    words, preserving whitespace
  1054. Xg/\([\t\s]*\)\(.\)\([a-z]*\)/\1\2{a-z}{A-Z}\3/
  1055. XCapitalise    First       Letters Of    Words, Preserving Whitespace
  1056. Xthis is a test of squeezing
  1057. Xg/\([a-z]\)\1*/\1/
  1058. Xthis is a test of squezing
  1059. Xjooooneees         waaaassss     heeeerrrrrreeeee
  1060. Xg/\([a-z\s]\)\1*/\1/
  1061. Xjones was here
  1062. Xmary had a little lamb
  1063. X/\(.*\) \(h.*\) \(a.*\)/"\0" becomes "\1{a-z}{A-Z} fucked \3{a-z}{A-C-E-XYZ}"/
  1064. X"mary had a little lamb" becomes "MARY fucked A LITTLE LAMB"
  1065. Xmary had a little lamb
  1066. X/\(.*\) \(.*\) \(.*\)/"\0" becomes "\1{a-z}{A-Z} fucked \3{a-z}{A-C-E-XYZ}"/
  1067. X"mary had a little lamb" becomes "MARY HAD A fucked LAMB"
  1068. Xmary had a little lamb
  1069. X/\(mary \(had\).*\)/{a-z}{A-Z}\1{had}{sex}/
  1070. XMARY HAD A LITTLE LAMBmery sex e little lemb
  1071. Xjones
  1072. Xg/ones/{a-c-f-n-qr-v-z}{A-J-Z}/
  1073. XjONES
  1074. Xa string an a another a ay?
  1075. Xg/a/{a-a-a-a-a-a-a-a-a-a-a-a}{X-X-X-X-Z}/
  1076. XX string Xn X Xnother X Xy?
  1077. Xa string an a another a ay?
  1078. X/.*/{a-a-a-a-a-a-a-a-a-a-a-ast}{X-X-X-X-Z}/
  1079. XX YZring Xn X XnoZher X Xy?
  1080. Xfred
  1081. X/\(.*\)/\1\s\1{a-z}{A-Z}\s\1{fred}{0123}\sjoe/
  1082. Xfred FRED 0123 joe
  1083. Xjordan k. hubbard
  1084. Xg/r/{a-z}{R}/
  1085. XjoRdan k. hubbaRd
  1086. Xjordan k. hubbard
  1087. Xg/r/{a-z}{A-Z}/
  1088. XjoRdan k. hubbaRd
  1089. Xjordan k. hubbard
  1090. Xg/r/R/
  1091. XjoRdan k. hubbaRd
  1092. Xterry jones was here
  1093. Xs/.*/{a-z}{A-Z}/
  1094. XTERRY JONES WAS HERE
  1095. Xfred he's dead
  1096. Xs/.* \(.*\) .*/\1{a-z}{1-9}/
  1097. X85'9
  1098. Xthis is a test line
  1099. Xg/\(.\)./{a-z}{A-Z}/
  1100. XTHIS IS A TEST LINe
  1101. Xthis is a test line
  1102. Xg/\(.\)./\1{a-z}{A-Z}/
  1103. XTI SATS Ie
  1104. Xthis is a test line
  1105. Xg/\(.\)\(.\)/\1{a-z}{A-Z}\2/
  1106. XThIs iS A TeSt lIne
  1107. Xthis is a test linex
  1108. Xg/\(.\)\(.\)/\1{a-z}{A-Z}\2/
  1109. SHAR_EOF
  1110. echo "End of part 2"
  1111. echo "File examples1 is continued in part 3"
  1112. echo "3" > s2_seq_.tmp
  1113. exit 0
  1114.  
  1115.