home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume1 / vstr < prev    next >
Internet Message Format  |  1986-11-30  |  37KB

  1. Date: Sat, 1 Jun 85 00:45:01 pdt
  2. From: decvax!decwrl!greipa!jordan (Jordan K. Hubbard)
  3. To: decvax!genrad!john, genrad!john
  4.  
  5. # This is a shell archive.  Remove anything before this line,
  6. # then unpack it by saving it in a file and typing "sh file".
  7. #
  8. # Wrapped by greipa!jordan on Fri May 31 02:15:19 PDT 1985
  9. # Contents:  Makefile OPERATION README examp.c v_alloc.c v_append.c v_clear.c
  10. #    v_cursor.c v_debug.c v_delete.c v_find.c v_free.c v_get.c v_move.c
  11. #    v_put.c v_rewind.c v_string.c v_utils.c vstr.h vstr.man
  12.  
  13. echo x - Makefile
  14. sed 's/^@//' > "Makefile" <<'@//E*O*F Makefile//'
  15. # Makefile for vstr package, 04/16/85 Jordan K. Hubbard
  16.  
  17. INC=/usr/include/local
  18. LIB=/usr/lib
  19. OBJS=    v_put.o v_get.o v_alloc.o v_debug.o v_rewind.o v_append.o v_utils.o\
  20.         v_string.o v_delete.o v_move.o v_cursor.o v_free.o v_clear.o v_find.o
  21.  
  22. INCS=vstr.h
  23.  
  24. @.c.o:
  25.     cc -O -c $<
  26.  
  27. libvstr.a: $(OBJS)
  28.     ar r libvstr.a $(OBJS)
  29.     ranlib libvstr.a
  30.  
  31. $(OBJS): $(INCS)
  32.  
  33. install: libvstr.a
  34.     cp libvstr.a $(LIB)
  35.     cp $(INCS) $(INC)
  36.     cp vstr.man /usr/man/manl/vstr.l
  37.     ranlib $(LIB)/libvstr.a
  38. @//E*O*F Makefile//
  39. chmod u=rw,g=r,o=r Makefile
  40.  
  41. echo x - OPERATION
  42. sed 's/^@//' > "OPERATION" <<'@//E*O*F OPERATION//'
  43. The operation of this package is fairly straightforward. A "virtual string"
  44. (actually, I should have called it a "dynamic" string , but it was too late
  45. as I didn't want to have to change all those 'v's to 'd's..) Is nothing
  46. more than a linked list of 'units', each containing a previous and next
  47. (unit) pointer, a data area and a length word.
  48.  
  49. The header block allocated by new_vstr contains a head and tail pointer that
  50. points to the first and last units in the 'chain'. This makes it easy to
  51. to 'rewind' and 'append' the string. Also in the header block is the 'unit'
  52. size for that particular vstr. A variable unit size is necessary so that
  53. v-strings can be 'tuned' for various applications. A larger unit size can
  54. save an appreciable amount of space on machines where ints and pointers
  55. are 32 bits (here I have a 10 byte overhead for each unit).
  56. However, if massive editing is being done, or the expected data is small,
  57. smaller units pay off. Memory conscious folks should see the footnote at
  58. the end of this file.
  59.  
  60. Finally, and probably most important, is a 'cursor'. The cursor is nothing
  61. more that a structure containing a unit pointer and an offset into it.
  62. The cursor 'points' nowhere when the string is first created, then moves 
  63. as characters are added to the string. The cursor will always point
  64. to one of three locations when the string contains text:
  65.  
  66. 1)    In the 'rewound' state, the cursor points to the first unit in
  67.     the chain with an offset of -1 (not on any character).
  68.  
  69. 2)    In the 'appended' state, the cursor will point at the last unit
  70.     with an offset equal to the number of characters in the last unit.
  71.     Since arrays start at zero, this puts it 'off the end' of the data
  72.     area for that unit, not on any character.
  73.  
  74. 3)    After a 'get', 'put', 'find' etc. operation, the cursor will point to the
  75.     character affected by the last operation. If one had just done a 'get'
  76.     for instance, the cursor would point to the character just gotten.
  77.  
  78.  
  79. There are also other operations can make use of 'cursors' that the
  80. user allocates himself. They are described in the manual page.
  81.  
  82. One might ask why I put a length word in each unit instead of just
  83. null terminating it. Well, in a word, it's a lot faster when calculating
  84. the length of the string (which I seem to do a lot) and memory is
  85. cheap on this machine. This is another area in which I welcome feedback.
  86.  
  87. One last small thing, I got kind of carried away with the 'debugging'
  88. features. I found them rather useful for tracing the code as I debugged
  89. it. You might wish to look at some of the 'wrapper' defines in vstr.h
  90. and the code in v_debug.c (if the 'id' stack confuses you, just think
  91. about nested procedure calls). It's all kind of crude, but effective.
  92. It's also quite usable elsewhere. Please don't flame me for my
  93. handling of 'variable' arguments. A lot of people don't have varargs
  94. and I'm certainly not going to vax-kludge it (doesn't work on pyramids
  95. anyway).
  96.  
  97. Footnote:
  98.  
  99. * For people that DON'T have a lot of memory, you might want to consider
  100. the following (people wishing to create very large vstr's might also look
  101. into it). Look at the define called LENTYPE in vstr.h. As shipped, it
  102. is defined as a short (16 bits on my machine). This allows me to
  103. create and index fairly large units (useful when I slurp in something
  104. like the termcap file). Some people may find a limit of 127 adequate
  105. and can change it to a signed char (must be signed). Inversely, some
  106. may wish to make this an int.
  107. @//E*O*F OPERATION//
  108. chmod u=rw,g=r,o=r OPERATION
  109.  
  110. echo x - README
  111. sed 's/^@//' > "README" <<'@//E*O*F README//'
  112. You might want to edit the makefile to put the library and include file
  113. somewhere else. Currently it's set for /usr/lib and /usr/include/local,
  114. respectivly. The manual page automatically tries to go in /usr/man/manl,
  115. you may want to change this as well.
  116.  
  117. This program has not really been used at all, I'm releasing it 
  118. mainly to get some feedback on it (this is not to say that it doesn't
  119. work, there are no KNOWN bugs..). There are two inconsistancies
  120. in the find and delete commands that might raise some ire, see the
  121. documentation.
  122.  
  123. You will probably want to edit vstr.h to suit your tastes, read OPERATION
  124. for some more vaguely useful information.
  125.  
  126. There's also a very crude test driver called examp.c.. It wasn't written,
  127. it just grew.. I include it only so that you may do some rudimentary testing
  128. if you wish to take the easy way out. No documentation, no support, if
  129. it was a child I'd disown it. You figure it out.
  130.  
  131. Please mail any bugs/flames to me so that I may improve the code (the package,
  132. not examp.c).
  133.  
  134. I'm also interested in any uses made of it, I haven't figured out
  135. any myself [ :-) ]... This package can be redistributed and used
  136. freely with appropriate credit. I am quite curious about the ways
  137. you may find to use it, any mail/interesting code describing
  138. this would be appreciated.
  139.  
  140.  
  141. Future plans include block operations, compaction on the fly, regular
  142. expression searches (currently not included due to the differences
  143. in SysV and 4.2 regex(p) code) and any speedups I can think of.
  144.  
  145. Suggestions gratefully accepted.
  146.  
  147.  
  148.  
  149. Jordan Hubbard
  150. May 30th, 1985.
  151. {decwrl, dual, pesnta}!greipa!jordan
  152. @//E*O*F README//
  153. chmod u=rw,g=r,o=r README
  154.  
  155. echo x - examp.c
  156. sed 's/^@//' > "examp.c" <<'@//E*O*F examp.c//'
  157. #include "vstr.h"
  158. #include <stdio.h>
  159. #include <ctype.h>
  160.  
  161. int i;
  162.  
  163. eatnl() {
  164.     register char ch;
  165.     register int foundnum;
  166.  
  167.     while ((ch = getchar()) != '\n')
  168.         if (isdigit(ch) || ch == '-') {
  169.             ungetc(ch, stdin);
  170.             scanf("%d", &i);
  171.             foundnum = 1;
  172.         }
  173.     if (!foundnum)
  174.         i = 0;
  175. }
  176.  
  177. main() {
  178.         register p_vstr testv = 0;
  179.         register char *st, fname[40];
  180.         char ch;
  181.         struct cursor save;
  182.         int going = 1, mode = FWD, cnt, chr;
  183.         register FILE *fp;
  184.  
  185.         while (going) {
  186.             printf("Command> ");
  187.             ch = getchar();
  188.             if (ch == '\n') {
  189.                 eatnl();
  190.                 continue;
  191.             }
  192.             eatnl();
  193.             switch (ch) {
  194.  
  195.                 case 'p':
  196.                     while ((ch = getchar()) != '~') {
  197.                         v_put(testv, ch, mode);
  198.                         if (mode == HERE)
  199.                             break;
  200.                     }
  201.                     eatnl();
  202.                     break;
  203.  
  204.                 case 'g':
  205.                     if (mode == INS) {
  206.                         printf("Now in FWD mode\n");
  207.                         mode = FWD;
  208.                     }
  209.                     while ((ch = v_get(testv, mode)) !=
  210.                       (mode == FWD ? ATEND : ATBEG)) {
  211.                         putchar(ch);
  212.                         if (mode == HERE)
  213.                             break;
  214.                     }
  215.                     printf("*END*\n");
  216.                     break;
  217.  
  218.                 case 's':
  219.                     v_savecursor(testv, &save);
  220.                     printf("saved\n");
  221.                     break;
  222.  
  223.                 case 'r':
  224.                     v_setcursor(testv, &save);
  225.                     printf("restored\n");
  226.                     break;
  227.  
  228.                 case 'S':
  229.                     v_show(testv);
  230.                     break;
  231.  
  232.                 case 'm':
  233.                     if (i < 0)
  234.                         i = v_move(testv, BACK, -i);
  235.                     else
  236.                         i = v_move(testv, FWD, i);
  237.                     printf("Moved %d positions\n", i);
  238.                     break;
  239.  
  240.                 case 'd':
  241.                     printf("Deleted %d chars\n", v_delete(testv, i));
  242.                     break;
  243.  
  244.                 case 'q':
  245.                     going = 0;
  246.                     break;
  247.  
  248.                 case 'f':
  249.                     v_free(testv);
  250.                     testv = 0;
  251.                     break;
  252.  
  253.                 case 'n':
  254.                     testv = new_vstr(i);
  255.                     printf("Address is %x\n", testv);
  256.                     break;
  257.  
  258.                 case 'c':
  259.                     v_clear(testv, END);
  260.                     break;
  261.  
  262.                 case 'R':
  263.                     v_rewind(testv);
  264.                     printf("Rewound\n");
  265.                     break;
  266.  
  267.                 case 'A':
  268.                     v_append(testv);
  269.                     printf("Appended\n");
  270.                     break;
  271.  
  272.                 case 'M':
  273.                     switch(i) {
  274.  
  275.                         case 0:
  276.                             mode = FWD;
  277.                             printf("Forward\n");
  278.                             break;
  279.  
  280.                         case 1:
  281.                             mode = BACK;
  282.                             printf("Back\n");
  283.                             break;
  284.  
  285.                         case 2:
  286.                             mode = HERE;
  287.                             printf("Here\n");
  288.                             break;
  289.  
  290.                         case 3:
  291.                             mode = INS;
  292.                             printf("Insert\n");
  293.                             break;
  294.  
  295.                         default:
  296.                             printf("Unknown mode. Set to forward\n");
  297.                             mode = FWD;
  298.                             break;
  299.                     }
  300.                 break;
  301.  
  302.                 case '>':
  303.                     cnt = 0;
  304.                     printf("To file name: ");
  305.                     scanf("%s", fname);
  306.                     eatnl();
  307.                     fp = fopen(fname, "w");
  308.                     if (!fp) {
  309.                         printf("Can't open %s for writing\n", fname);
  310.                         continue;
  311.                     }
  312.                     while ((ch = v_get(testv, mode)) !=
  313.                       (mode == FWD ? ATEND : ATBEG)) {
  314.                         fputc(ch, fp);
  315.                         cnt++;
  316.                         if (mode == HERE)
  317.                             break;
  318.                     }
  319.                     printf("%d chars written\n", cnt);
  320.                     fclose(fp);
  321.                     break;
  322.  
  323.                 case '<':
  324.                     cnt = 0;
  325.                     printf("From file name: ");
  326.                     scanf("%s", fname);
  327.                     eatnl();
  328.                     fp = fopen(fname, "r");
  329.                     if (!fp) {
  330.                         printf("Can't open %s for writing\n", fname);
  331.                         continue;
  332.                     }
  333.                     while((chr = fgetc(fp)) != EOF) {
  334.                         cnt++;
  335.                         v_put(testv, chr, FWD);
  336.                     }
  337.                     fclose(fp);
  338.                     printf("%d chars read, length of vstr is now %d\n",
  339.                       cnt, v_length(testv, BEG));
  340.                     break;
  341.  
  342.                 case '/':
  343.                     /* look ma, no statement */
  344.                     {
  345.                         register p_cursor cp;
  346.  
  347.                     printf("Search for char: ");
  348.                     scanf("%c", &ch);
  349.                     if (cp = v_find(testv, ch)) {
  350.                         printf("Found.\n");
  351.                         v_setcursor(testv, cp);
  352.                     }
  353.                     } /* yuk. So I'm too lazy to declare my locals earlier.
  354.                         this is just a lousy test program.
  355.                         What do you want from me? Style? */
  356.                     break;
  357.  
  358.                 default:
  359.                     printf("Unknown command: %c.\n", ch);
  360.             }
  361.     }
  362. }
  363. @//E*O*F examp.c//
  364. chmod u=rw,g=r,o=r examp.c
  365.  
  366. echo x - v_alloc.c
  367. sed 's/^@//' > "v_alloc.c" <<'@//E*O*F v_alloc.c//'
  368. /*
  369.  * V_ALLOC Version 1.0, 4/16/85
  370.  * Jordan K. Hubbard
  371.  */
  372.  
  373. #include "vstr.h"
  374.  
  375. IMPORT char *malloc();
  376.  
  377. ROUTINE p_unit new_unit(v)
  378. register p_vstr v;
  379. {
  380.     register p_unit tmp;
  381.  
  382.     entry(new_unit)
  383.  
  384.     tmp = (p_unit)malloc(sizeof *tmp);
  385.     if (!tmp)
  386.         freak_out(M_NOSPACE);
  387.     tmp->next = tmp->prev = NIL;
  388.     tmp->len = 0;
  389.     tmp->data = malloc(v->unit_size);
  390.     if (!tmp->data)
  391.         freak_out(M_NOSPACE);
  392.     ret(tmp)
  393. }
  394.  
  395. ROUTINE p_vstr new_vstr(i)
  396. register int i;
  397. {
  398.     register p_vstr tmp;
  399.  
  400.     entry(new_vstr)
  401.  
  402.     tmp = (p_vstr)malloc(sizeof *tmp);
  403.     if (!tmp)
  404.         freak_out(M_NOSPACE);
  405.     tmp->head = tmp->tail = tmp->cur.here = NIL;
  406.     tmp->cur.u_pos = -1;
  407.     tmp->unit_size = i;
  408.     ret(tmp)
  409. }
  410. @//E*O*F v_alloc.c//
  411. chmod u=rw,g=r,o=r v_alloc.c
  412.  
  413. echo x - v_append.c
  414. sed 's/^@//' > "v_append.c" <<'@//E*O*F v_append.c//'
  415. #include "vstr.h"
  416.  
  417. ROUTINE void v_append(v)
  418. register p_vstr v;
  419. {
  420.     entry(v_append)
  421.  
  422.     v->cur.here = v->tail;
  423.     v->cur.u_pos = v->cur.here->len;
  424.     end
  425. }
  426. @//E*O*F v_append.c//
  427. chmod u=rw,g=r,o=r v_append.c
  428.  
  429. echo x - v_clear.c
  430. sed 's/^@//' > "v_clear.c" <<'@//E*O*F v_clear.c//'
  431. #include "vstr.h"
  432.  
  433. ROUTINE void v_clear(v, how)
  434. register p_vstr v;
  435. register int how;
  436. {
  437.     register p_unit temp;
  438.  
  439.     entry(v_clear)
  440.  
  441.     if (!v && !v->head)
  442.         end
  443.     if (how == END) {
  444.         temp = v->cur.here;
  445.         if (v->cur.u_pos) {
  446.             temp->len = v->cur.u_pos;
  447.             temp = temp->next;
  448.         }
  449.     }
  450.     else
  451.         temp = v->head;
  452.     while (temp) {
  453.         free(temp);
  454.         temp = temp->next;
  455.     }
  456.     v->head = v->tail = v->cur.here = 0;
  457.     v->cur.u_pos = -1;
  458.     end
  459. }
  460. @//E*O*F v_clear.c//
  461. chmod u=rw,g=r,o=r v_clear.c
  462.  
  463. echo x - v_cursor.c
  464. sed 's/^@//' > "v_cursor.c" <<'@//E*O*F v_cursor.c//'
  465. #include "vstr.h"
  466.  
  467. ROUTINE p_cursor v_savecursor(v, c)
  468. register p_vstr v;
  469. register p_cursor c;
  470. {
  471.     entry(v_savecursor)
  472.  
  473.     c->here = v->cur.here;
  474.     c->u_pos = v->cur.u_pos;
  475. #ifdef DEBUG
  476. yelp("saving cursor at unit %x, pos %d\n", c->here, c->u_pos);
  477. #endif
  478.     ret(c)
  479. }
  480.  
  481. ROUTINE void v_setcursor(v, c)
  482. register p_vstr v;
  483. register p_cursor c;
  484. {
  485.     entry(v_setcursor)
  486.  
  487.     v->cur.here = c->here;
  488.     v->cur.u_pos = c->u_pos;
  489. #ifdef DEBUG
  490. yelp("setting cursor to unit %u, pos %d\n", c->here, c->u_pos);
  491. #endif
  492.     end
  493. }
  494.  
  495. ROUTINE void v_copycursor(c1, c2)
  496. register p_cursor c1, c2;
  497. {
  498.     entry(v_copycursor)
  499.  
  500.     c1->here = c2->here;
  501.     c1->u_pos = c2->u_pos;
  502.     end
  503. }
  504.  
  505. ROUTINE int v_span(c1, c2)
  506. register p_cursor c1, c2;
  507. {
  508.     register int cnt = 0;
  509.     register p_unit tmp = c1->here;
  510.  
  511.     entry(v_span)
  512.  
  513.     while (tmp && (tmp != c2->here)) {
  514.         cnt += tmp->len;
  515.         tmp = tmp->next;
  516.     }
  517.     if (tmp)
  518.         cnt += c2->u_pos;
  519.     ret(cnt)
  520. }
  521. @//E*O*F v_cursor.c//
  522. chmod u=rw,g=r,o=r v_cursor.c
  523.  
  524. echo x - v_debug.c
  525. sed 's/^@//' > "v_debug.c" <<'@//E*O*F v_debug.c//'
  526. /*
  527.  * V_DEBUG Version 1.0 4/16/85
  528.  * Jordan K. Hubbard
  529.  */
  530.  
  531. #include "vstr.h"
  532. #include <stdio.h>
  533.  
  534. #define PUSH    1
  535. #define POP        2
  536. #define LOOK    3
  537.  
  538. #ifdef DEBUG
  539. char *id();
  540.  
  541. ROUTINE void yelp(fmt, p1, p2, p3, p4, p5, p6)
  542. register char *fmt;
  543. register unsigned char *p1, *p2, *p3, *p4, *p5, *p6;
  544. {
  545.     fprintf(stderr, "DEBUG: [%s] ", id(0, LOOK));
  546.     fprintf(stderr, fmt, p1, p2, p3, p4, p5, p6);
  547.     return;
  548. }
  549.  
  550. ROUTINE char *id(s, mode)
  551. register char *s;
  552. register int mode;
  553. {
  554.     /* if we get more than 50 subroutine levels deep, something's wrong */
  555.     /* with our program anyway (or we've taken modular programming too far!) */
  556.     static char *stack[50];
  557.     static int pointer = 0;
  558.     
  559.     switch (mode) {
  560.  
  561.         case PUSH:
  562.             stack[pointer++] = s;
  563.             if (pointer == 50) {
  564.                 yelp("stack overflow in id!\n");
  565.                 exit(1);
  566.             }
  567.             break;
  568.  
  569.         case POP:
  570.             if (pointer - 1 < 0) {
  571.                 yelp("stack underflow in id!\n");
  572.                 exit(1);
  573.             }
  574.             return(stack[--pointer]);
  575.             break;
  576.  
  577.         case LOOK:
  578.             if (pointer - 1 < 0) {
  579.                 yelp("empty stack for 'look' in id!\n");
  580.                 exit(1);
  581.             }
  582.             return(stack[pointer - 1]);
  583.             break;
  584.     }
  585. }
  586.  
  587. ROUTINE void _end()
  588. {
  589.     yelp("Exiting with no returned value\n");
  590.     id(0, POP);
  591.     return;
  592. }
  593.  
  594. ROUTINE void _entry(s)
  595. register char *s;
  596. {
  597.     id(s, PUSH);
  598.     yelp("Entering\n");
  599.     return;
  600. }
  601.  
  602. ROUTINE void _ret(l)
  603. unsigned char *l;
  604. {
  605.     yelp("Exiting with %u (hex: %x)\n", l, l);
  606.     id(0, POP);
  607.     return;
  608. }
  609.  
  610. #else
  611.  
  612. EXPORT char *_Curr_rtn;
  613.  
  614. #endif
  615.  
  616. /* Makes character 'visible' by turning it into a printable control */
  617. /* character if it is one or its octal \nnn form if it is greater than */
  618. /* the upper limit for printable ascii */
  619.  
  620. ROUTINE char *visible(ch)
  621. register char ch;
  622. {
  623.     static char buf[5];
  624.  
  625.     entry(visible)
  626.  
  627.     buf[0] = '\0';
  628.     if (ch < 32) {
  629.         buf[0] = '^';
  630.         ch += 64;
  631.     }
  632.     if (ch > 31 && ch < 127) {
  633.         if (buf[0]) {
  634.             buf[1] = ch;
  635.             buf[2] = '\0';
  636.         }
  637.         else {
  638.             buf[0] = ch;
  639.             buf[1] = '\0';
  640.         }
  641.     }
  642.     else if (ch > 126) {
  643.         sprintf(buf, "\\%03o", ch);
  644.         buf[4] = '\0';
  645.     }
  646.     ret(buf)
  647. }
  648.  
  649. ROUTINE void v_show(v)
  650. register p_vstr v;
  651. {
  652.     register p_unit temp;
  653.     register int n_units = 0, n_chars = 0, l;
  654.     register int n_funits = 0;
  655.  
  656.     entry(v_show)
  657.  
  658.     if (!v) {
  659.         fprintf(stderr, "v_show: vstr is NIL\n");
  660.         end
  661.     }
  662.     fprintf(stderr, "Debugging information for vstr at %X\n", v);
  663.     fprintf(stderr, "Head is at %X, Tail at %X\n", v->head, v->tail);
  664.     fprintf(stderr, "Unit size is %d\n", v->unit_size);
  665.     fprintf(stderr, "Cursor points to unit %X, position %d\n\n",
  666.       v->cur.here, v->cur.u_pos);
  667.     temp = v->head;
  668.     while (temp) {
  669.         fprintf(stderr, "prev     unit     next\n");
  670.         fprintf(stderr, "(%X) <= [%X] => (%X)   ", temp->prev, temp,
  671.           temp->next);
  672.         if (temp == v->head)
  673.             fprintf(stderr, "HEAD  ");
  674.         if (temp == v->tail)
  675.             fprintf(stderr, "TAIL  ");
  676.         fprintf(stderr, "#%d\n", n_units);
  677.         fprintf(stderr, "\tLength = %d", temp->len);
  678.         if (temp->len) {
  679.             n_chars += temp->len;
  680.             fprintf(stderr, "  Data = '");
  681.             for (l = 0; l < temp->len; l++)
  682.                 fprintf(stderr, "%s", visible(temp->data[l]));
  683.             fprintf(stderr, "'\n\n");
  684.             if (temp->len == v->unit_size)
  685.                 n_funits++;
  686.         }
  687.         else
  688.             fprintf(stderr, "\n\n");
  689.         temp = temp->next;
  690.         n_units++;
  691.     }
  692.     fprintf(stderr, "\n\nTotal: %d characters in %d units. %d full, %d not.\n",
  693.         n_chars, n_units, n_funits, n_units - n_funits);
  694.     end
  695. }
  696.  
  697. ROUTINE void freak_out(fmt, p1, p2, p3, p4, p5, p6)
  698. register char *fmt;
  699. register int p1, p2, p3, p4, p5, p6;
  700. {
  701. #ifdef DEBUG
  702.     fprintf(stderr, "%s: ", id(0, LOOK));
  703. #else
  704.     fprintf(stderr, "%s: ", _Curr_rtn);
  705. #endif
  706.     fprintf(stderr, fmt, p1, p2, p3, p4, p5, p6);
  707.     exit(1);
  708. }
  709. @//E*O*F v_debug.c//
  710. chmod u=rw,g=r,o=r v_debug.c
  711.  
  712. echo x - v_delete.c
  713. sed 's/^@//' > "v_delete.c" <<'@//E*O*F v_delete.c//'
  714. #include "vstr.h"
  715.  
  716. ROUTINE int v_delete(v, cnt)
  717. register p_vstr v;
  718. register int cnt;
  719. {
  720.     register p_unit temp;
  721.     register int actual = 0, n;
  722.  
  723.     entry(v_delete)
  724.  
  725.     if (!cnt)
  726.         end
  727.     while (cnt) {
  728.         temp = v->cur.here;
  729.         n = temp->len - v->cur.u_pos;
  730.         if (!n) {
  731.             if (!temp->next)
  732.                 ret(actual)
  733.             else {
  734.                 v->cur.here = temp->next;
  735.                 v->cur.u_pos = 0;
  736.             }
  737.             continue;
  738.         }
  739.         if (n <= cnt) {
  740.             if (!v->cur.u_pos) {
  741.                 cnt -= temp->len;
  742.                 actual += temp->len;
  743.                 linkout(v, temp);
  744.                 if (v->cur.here == temp->prev)
  745.                     cnt = 0;
  746.             }
  747.             else {
  748.                 temp->len -= n;
  749.                 cnt -= n;
  750.                 actual += n;
  751.                 if (temp->next) {
  752.                     v->cur.here = temp->next;
  753.                     v->cur.u_pos = 0;
  754.                 }
  755.                 else
  756.                     cnt = 0;
  757.             }
  758.         }
  759.         else {
  760.             strncpy(temp->data + v->cur.u_pos,
  761.                 temp->data + v->cur.u_pos + cnt, n);
  762.             temp->len -= cnt;
  763.             actual += cnt;
  764.             cnt = 0;
  765.         }
  766.     }
  767.     ret(actual)
  768. }
  769. @//E*O*F v_delete.c//
  770. chmod u=rw,g=r,o=r v_delete.c
  771.  
  772. echo x - v_find.c
  773. sed 's/^@//' > "v_find.c" <<'@//E*O*F v_find.c//'
  774. #include "vstr.h"
  775.  
  776. ROUTINE p_cursor v_find(v, ch, dir)
  777. register p_vstr v;
  778. register char ch;
  779. register int dir;
  780. {
  781.     static struct cursor found;
  782.     struct cursor save;
  783.     register int i;
  784.  
  785.     entry(v_find)
  786.  
  787.     if (dir != FWD && dir != BACK)
  788.         freak_out("called with bad mode (not BACK or FWD)\n");
  789.     v_savecursor(v, &save);
  790.     while ((i = v_get(v, dir)) != (dir == FWD ? ATEND : ATBEG))
  791.         if (i == ch) {
  792.             v_savecursor(v, &found);
  793.             v_setcursor(v, &save);
  794.             ret(&found)
  795.         }
  796.     v_setcursor(v, &save);
  797.     ret(0)
  798. }
  799. @//E*O*F v_find.c//
  800. chmod u=rw,g=r,o=r v_find.c
  801.  
  802. echo x - v_free.c
  803. sed 's/^@//' > "v_free.c" <<'@//E*O*F v_free.c//'
  804. #include "vstr.h"
  805.  
  806. ROUTINE void v_free(v)
  807. register p_vstr v;
  808. {
  809.     register p_unit temp;
  810.  
  811.     entry(v_free)
  812.  
  813.     if (!v)
  814.         freak_out(M_NILVSTR);
  815.     temp = v->head;
  816.     while (temp) {
  817.         free(temp);
  818.         temp = temp->next;
  819.     }
  820.     free(v);
  821.     end
  822. }
  823. @//E*O*F v_free.c//
  824. chmod u=rw,g=r,o=r v_free.c
  825.  
  826. echo x - v_get.c
  827. sed 's/^@//' > "v_get.c" <<'@//E*O*F v_get.c//'
  828. /*
  829.  * V_GET Version 1.0, 4/16/85
  830.  * Jordan K. Hubbard
  831.  */
  832.  
  833. #include "vstr.h"
  834.  
  835. ROUTINE int v_get(v, mode)
  836. register p_vstr v;
  837. register int mode;
  838. {
  839.     register int i;
  840.  
  841.     entry(v_get)
  842.  
  843. #ifdef DEBUG
  844. yelp("called with vstr at %x, mode = %d\n", v, mode);
  845. #endif
  846.     if (!v)
  847.         freak_out(M_NILVSTR);
  848.     if (!v->head)
  849.         ret((mode == BACK) ? ATBEG : ATEND)
  850.     switch(mode) {
  851.  
  852.         case FWD:
  853.             if (v_move(v, FWD, 1) == ATEND)
  854.                 ret(ATEND)
  855.             i = (int)v->cur.here->data[v->cur.u_pos];
  856.             break;
  857.  
  858.         case BACK:
  859.             if (v_move(v, BACK, 1) == ATBEG)
  860.                 ret(ATBEG)
  861.             i = (int)v->cur.here->data[v->cur.u_pos];
  862.             break;
  863.  
  864.         case HERE:
  865.             if (IS_BACK(v))
  866.                 ret(ATEND)
  867.             i = (int)v->cur.here->data[v->cur.u_pos];
  868.             break;
  869.     }
  870.     ret(i)
  871. }
  872. @//E*O*F v_get.c//
  873. chmod u=rw,g=r,o=r v_get.c
  874.  
  875. echo x - v_move.c
  876. sed 's/^@//' > "v_move.c" <<'@//E*O*F v_move.c//'
  877. #include "vstr.h"
  878.  
  879. ROUTINE int v_move(v, dir, cnt)
  880. register p_vstr v;
  881. register int dir, cnt;
  882. {
  883.     register int actual = 0;
  884.  
  885.     entry(v_move)
  886.  
  887. #ifdef DEBUG
  888. yelp("called with vstr at %x, count of %d, direction = %d\n", v, cnt, dir);
  889. #endif
  890.     if (!cnt)
  891.         ret(0)
  892.     switch (dir) {
  893.  
  894.         case FWD:
  895.             while (cnt && !IS_BACK(v)) {
  896.                 if (++v->cur.u_pos >= v->cur.here->len)
  897.                     if (!(v->cur.here = v->cur.here->next)) {
  898.                         v->cur.here = v->tail;
  899.                         v->cur.u_pos = v->tail->len;
  900.                         break;
  901.                     }
  902.                     else
  903.                         v->cur.u_pos = 0;
  904.                 cnt--;
  905.                 actual++;
  906.             }
  907.             break;
  908.  
  909.         case BACK:
  910.             while (cnt && !IS_FRONT(v)) {
  911.                 if (--v->cur.u_pos < 0)
  912.                     if (!(v->cur.here = v->cur.here->prev)) {
  913.                         v->cur.here = v->head;
  914.                         v->cur.u_pos = -1;
  915.                         break;
  916.                     }
  917.                     else
  918.                         v->cur.u_pos = v->cur.here->len - 1;
  919.                 actual++;
  920.                 cnt--;
  921.             }
  922.             break;
  923.     }
  924.     if (!actual)
  925.         ret((dir == FWD) ? ATEND : ATBEG)
  926.     else
  927.         ret(actual)
  928. }
  929. @//E*O*F v_move.c//
  930. chmod u=rw,g=r,o=r v_move.c
  931.  
  932. echo x - v_put.c
  933. sed 's/^@//' > "v_put.c" <<'@//E*O*F v_put.c//'
  934. /*
  935.  *  V_PUT Version 1.0, 4/16/85
  936.  * Jordan K. Hubbard
  937.  */
  938.  
  939. #include "vstr.h"
  940.  
  941. IMPORT p_unit linkin();
  942.  
  943. ROUTINE void v_put(v, c, mode)
  944. register p_vstr v;
  945. register char c;
  946. register int mode;
  947. {
  948.     register int n;
  949.  
  950.     entry(v_put)
  951.  
  952. #ifdef DEBUG
  953. yelp("called with vstr at %x, char = %c, mode = %d\n", v, c, mode);
  954. if (!v->head)
  955.     yelp("vstr is cleared\n");
  956. #endif
  957.     if (!v)
  958.         freak_out(M_NILVSTR);
  959.     if (!v->head) {
  960.         v->head = v->tail = v->cur.here = new_unit(v);
  961.         v->cur.u_pos = -1;
  962.     }
  963.  
  964.     /*
  965.      * The awful nasty evil label here is so that some cases can mung
  966.      * around with the text and then change the mode and goto. It's
  967.      * crude, but it seems better that a recursive function call.. Look
  968.      * at the 'END' or 'BEG' case and you'll see what I mean..
  969.      */
  970. sw:    switch(mode) {
  971.  
  972.         case FWD:
  973.             if (v_move(v, FWD, 1) == ATEND) {
  974.                 if (v->cur.here->len < v->unit_size) {
  975.                     v->cur.here->data[v->cur.here->len] = c;
  976.                     v->cur.u_pos++;
  977.                 }
  978.                 else {
  979.                     v->cur.here = v->tail = linkin(v, FWD);
  980.                     *(v->cur.here->data) = c;
  981.                     v->cur.u_pos = 0;
  982.                 }
  983.             }
  984.             else
  985.                 v->cur.here->data[v->cur.u_pos] = c;
  986.             if (v->cur.here->len <= v->cur.u_pos)
  987.                 v->cur.here->len++;
  988.             break;
  989.  
  990.         case BACK:
  991.             if (v_move(v, BACK, 1) == ATBEG) {
  992.                 if (v->cur.here->len < v->unit_size) {
  993.                     shift(v->cur.here, 0);
  994.                     *(v->cur.here->data) = c;
  995.                     v->cur.u_pos = 0;
  996.                 }
  997.                 else {
  998.                     v->cur.here = v->head = linkin(v, BACK);
  999.                     v->cur.here->len = 1;
  1000.                     v->cur.u_pos = 0;
  1001.                     *(v->cur.here->data) = c;
  1002.                 }
  1003.             }
  1004.             else
  1005.                 v->cur.here->data[v->cur.u_pos] = c;
  1006.             break;
  1007.  
  1008.         case HERE:
  1009.             if (IS_BACK(v))
  1010.                 end;
  1011.             v->cur.here->data[v->cur.u_pos] = c;
  1012.             break;
  1013.  
  1014.         case BEG:
  1015.             v_rewind(v);
  1016.             mode = BACK;
  1017.             goto sw;
  1018.             break;
  1019.  
  1020.         case END:
  1021.             v_append(v);
  1022.             mode = FWD;
  1023.             goto sw;
  1024.             break;
  1025.  
  1026.         case INS:
  1027.             /*
  1028.              * If we're at the end, then this isn't really an insert.
  1029.              * I know it's kludge, but I don't wanna rewrite the append
  1030.              * code!
  1031.              */
  1032.             if (v_move(v, FWD, 1) == ATEND) {
  1033.                 mode = FWD;
  1034.                 goto sw;
  1035.             }
  1036.             if (v->cur.here->len < v->unit_size) {
  1037.                 if (v->cur.u_pos < v->cur.here->len) 
  1038.                     shift(v->cur.here, v->cur.u_pos);
  1039.                 else 
  1040.                     v->cur.here->len++;
  1041.             }
  1042.             else if (!ripple(v)) {
  1043.                 linkin(v, FWD);
  1044.                 ripple(v);
  1045.             }
  1046.             v->cur.here->data[v->cur.u_pos] = c;
  1047.             break;
  1048.  
  1049.         default:
  1050.             freak_out("Bad mode passed, mode = %d, char = %d\n", mode, c);
  1051.             break;
  1052.     }
  1053.     end
  1054. }
  1055. @//E*O*F v_put.c//
  1056. chmod u=rw,g=r,o=r v_put.c
  1057.  
  1058. echo x - v_rewind.c
  1059. sed 's/^@//' > "v_rewind.c" <<'@//E*O*F v_rewind.c//'
  1060. #include "vstr.h"
  1061.  
  1062. ROUTINE void v_rewind(v)
  1063. register p_vstr v;
  1064. {
  1065.     entry(v_rewind)
  1066.  
  1067.     v->cur.here = v->head;
  1068.     v->cur.u_pos = -1;
  1069.     end
  1070. }
  1071. @//E*O*F v_rewind.c//
  1072. chmod u=rw,g=r,o=r v_rewind.c
  1073.  
  1074. echo x - v_string.c
  1075. sed 's/^@//' > "v_string.c" <<'@//E*O*F v_string.c//'
  1076. #include "vstr.h"
  1077.  
  1078. IMPORT char *malloc();
  1079.  
  1080. ROUTINE void v_stov(s, v)
  1081. register char *s;
  1082. register p_vstr v;
  1083. {
  1084.     register int i, l;
  1085.  
  1086.     entry(v_stov)
  1087.  
  1088.     l = strlen(s);
  1089. #ifdef DEBUG
  1090. yelp("Putting string at %x, length of %d into vstr at %x\n", s, l, v);
  1091. #endif
  1092.     for (i = 0; i < l; i++)
  1093.         v_put(v, s[i], FWD);
  1094.     end
  1095. }
  1096.  
  1097. ROUTINE char *v_vtos(v)
  1098. register p_vstr v;
  1099. {
  1100.     register char *s;
  1101.     register i = 0;
  1102.     register char ch;
  1103.  
  1104.     entry(v_vtos)
  1105.  
  1106.     s = malloc(v_length(v, HERE) + 1);
  1107. #ifdef DEBUG
  1108. yelp("making string at %x, %d chars long for vstr at %x", s, v_length(v, HERE) +
  1109.   1, v);
  1110. #endif
  1111.     if (!s)
  1112.         freak_out(M_NOSPACE);
  1113.     while ((ch = v_get(v, FWD)) != ATEND)
  1114.         s[i++] = ch;
  1115.     s[i] = '\0';
  1116.     ret(s)
  1117. }
  1118.  
  1119. ROUTINE char *v_nvtos(v, n)
  1120. register p_vstr v;
  1121. register int n;
  1122. {
  1123.     register char *s;
  1124.     register i = 0;
  1125.     register char ch;
  1126.  
  1127.     entry(v_nvtos)
  1128.  
  1129.     s = malloc(n + 1);
  1130. #ifdef DEBUG
  1131. yelp("making string at %x, %d chars long for vstr at %x", s, n + 1, v);
  1132. #endif
  1133.     if (!s)
  1134.         freak_out(M_NOSPACE);
  1135.     while ((ch = v_get(v, FWD)) != ATEND && n) {
  1136.         s[i++] = ch;
  1137.         n--;
  1138.     }
  1139.     s[i] = '\0';
  1140.     ret(s)
  1141. }
  1142. @//E*O*F v_string.c//
  1143. chmod u=rw,g=r,o=r v_string.c
  1144.  
  1145. echo x - v_utils.c
  1146. sed 's/^@//' > "v_utils.c" <<'@//E*O*F v_utils.c//'
  1147. #include "vstr.h"
  1148. #include <stdio.h>
  1149.  
  1150. ROUTINE p_unit linkin(v, mode)
  1151. register p_vstr v;
  1152. register int mode;
  1153. {
  1154.     register p_unit temp, p1, u = v->cur.here;
  1155.  
  1156.     entry(linkin)
  1157.  
  1158. #ifdef DEBUG
  1159. yelp("called with vstr at %x, mode = %d\n", v, mode);
  1160. #endif
  1161.     switch(mode) {
  1162.  
  1163.         case FWD:
  1164.             temp = new_unit(v);
  1165.             p1 = u->next;
  1166.             temp->prev = u;
  1167.             u->next = temp;
  1168.             temp->next = p1;
  1169.             if (p1)
  1170.                 p1->prev = temp;
  1171.             break;
  1172.  
  1173.         case BACK:
  1174.             temp = new_unit(v);
  1175.             p1 = u->prev;
  1176.             temp->next = u;
  1177.             u->prev = temp;
  1178.             temp->prev = p1;
  1179.             if (p1)
  1180.                 p1->next = temp;
  1181.             break;
  1182.  
  1183.         default:
  1184.             freak_out("passed weird mode %d\n", mode);
  1185.             end
  1186.             break;
  1187.     }
  1188.     ret(temp)
  1189. }
  1190.  
  1191. ROUTINE void linkout(v, u)
  1192. register p_vstr v;
  1193. register p_unit u;
  1194. {
  1195.     register p_unit p1, p2;
  1196.  
  1197.     entry(linkout)
  1198.  
  1199. #ifdef DEBUG
  1200. yelp("linking out unit at %x from vstr at %x\n", u, v);
  1201. #endif
  1202.     p1 = u->prev;
  1203.     p2 = u->next;
  1204.     if (p1)
  1205.         p1->next = p2;
  1206.     else
  1207.         v->head = p2;
  1208.     if (p2)
  1209.         p2->prev = p1;
  1210.     else
  1211.         v->tail = p1;
  1212.     if (p2) {
  1213.         v->cur.here = p2;
  1214.         v->cur.u_pos = 0;
  1215.     }
  1216.     else {
  1217.         v->cur.here = p1;
  1218.         v->cur.u_pos = (p1 ? p1->len : 0);
  1219.     }
  1220.     free(u);
  1221.     end
  1222. }
  1223.  
  1224. ROUTINE void shift(u, pos)
  1225. register p_unit u;
  1226. register int pos;
  1227. {
  1228.     register int i = u->len;
  1229.  
  1230.     entry(shift)
  1231.  
  1232. #ifdef DEBUG
  1233. yelp("shifting from %d to %d in unit at %x\n", i, pos, u);
  1234. #endif
  1235.     if (!i)
  1236.         freak_out("passed an empty unit at %u\n", u);
  1237.     while(i != pos) {
  1238.         u->data[i] = u->data[i - 1];
  1239.         i--;
  1240.     }
  1241.     u->len++;
  1242.     end
  1243. }
  1244.  
  1245. ROUTINE boolean ripple(v)
  1246. register p_vstr v;
  1247. {
  1248.     struct cursor pos;
  1249.     register int i = COST, p;
  1250.     register p_unit tmp = v->cur.here;
  1251.     register p_unit dest_u = tmp;
  1252.     register int dest_p = v->cur.u_pos;
  1253.     
  1254.     entry(ripple)
  1255.  
  1256.     /* Scan for a hole */
  1257.     pos.here = 0;
  1258.     while (i--) {
  1259.         if (!tmp->next) {
  1260.             v->tail = tmp->next = new_unit(v);
  1261.             tmp->next->prev = tmp;
  1262.             pos.here = tmp->next;
  1263.             pos.u_pos = 0;
  1264. #ifdef DEBUG
  1265. yelp("found end while scanning, linked in unit at %x\n", pos.here);
  1266. #endif
  1267.             break;
  1268.         }
  1269.         else if (tmp->len < v->unit_size) {
  1270.             pos.u_pos = tmp->len;
  1271.             pos.here = tmp;
  1272. #ifdef DEBUG
  1273. yelp("Found hole at %x(%d)\n", pos.here, pos.u_pos);
  1274. #endif
  1275.             break;
  1276.         }
  1277.         else
  1278.             tmp = tmp->next;
  1279.     }
  1280.     if (!pos.here)
  1281.         ret(0)
  1282.     pos.here->len++;
  1283. #ifdef DEBUG
  1284. yelp("rippling from %x(%d) to %x(%d)\n", pos.here, pos.u_pos, dest_u, dest_p);
  1285. #endif
  1286.     while (!(pos.here == dest_u && pos.u_pos == dest_p)) {
  1287.         if (!pos.u_pos) {
  1288.             tmp = pos.here->prev;
  1289.             pos.u_pos = tmp->len - 1;
  1290.             *(pos.here->data) = tmp->data[pos.u_pos];
  1291.             pos.here = tmp;
  1292.         }
  1293.         else {
  1294.             pos.here->data[pos.u_pos] = pos.here->data[pos.u_pos - 1];
  1295.             pos.u_pos--;
  1296.         }
  1297.     }
  1298.     ret(1)
  1299. }
  1300.  
  1301. ROUTINE int v_length(v, how)
  1302. register p_vstr v;
  1303. register int how;
  1304. {
  1305.     register int i = 0;
  1306.     register p_unit temp;
  1307.  
  1308.     entry(v_length)
  1309.  
  1310. #ifdef DEBUG
  1311. yelp("Getting length for vstr at %x, how = %d\n", v, how);
  1312. #endif
  1313.     if (!v || !v->head)
  1314.         ret(0)
  1315.     switch(how) {
  1316.  
  1317.         case HERE:
  1318.             temp = v->head;
  1319.             while (temp) {
  1320.                 i += temp->len;
  1321.                 temp = temp->next;
  1322.             }
  1323.             break;
  1324.  
  1325.         case BEG:
  1326.             if (IS_FRONT(v))
  1327.                 break;
  1328.             temp = v->cur.here;
  1329.             if (v->cur.u_pos < temp->len) {
  1330.                 i = v->cur.u_pos + 1;
  1331.                 temp = temp->prev;
  1332.             }
  1333.             while(temp) {
  1334.                 i += temp->len;
  1335.                 temp = temp->prev;
  1336.             }
  1337.             break;
  1338.  
  1339.         case END:
  1340.             if (IS_BACK(v))
  1341.                 break;
  1342.             temp = v->cur.here;
  1343.             i = temp->len - v->cur.u_pos;
  1344.             while (temp) {
  1345.                 i += temp->len;
  1346.                 temp = temp->next;
  1347.             } 
  1348.             break;
  1349.     }
  1350.     ret(i)
  1351. }
  1352. @//E*O*F v_utils.c//
  1353. chmod u=rw,g=r,o=r v_utils.c
  1354.  
  1355. echo x - vstr.h
  1356. sed 's/^@//' > "vstr.h" <<'@//E*O*F vstr.h//'
  1357. /* The number of units to scan ahead for holes when inserting characters */
  1358. /* (as opposed to just creating a new unit). Scanning isn't so */
  1359. /* much overhead as is copying characters to the hole, so it's best not */
  1360. /* to define COST too large unless you're using large units and/or doing */
  1361. /* a fair number of deletions. Perhaps some more clever way of doing */
  1362. /* insertions will be implemented some day. (I welcome any suggestions) */
  1363.  
  1364. #define COST 4
  1365.  
  1366. /* To turn on routine tracing and general annoying messages #define
  1367.  * DEBUG, as usual. Modify _end(), _entry() and _ret() for more advanced
  1368.  * debugging.
  1369.  */
  1370.  
  1371. /* #define DEBUG 1  */
  1372.  
  1373. /*
  1374.  * Define this to be the type of variable you want to store the length
  1375.  * and index variables in. Read OPERATION for more details..
  1376.  */
  1377.  
  1378. #define LENTYPE short
  1379.  
  1380. #ifdef DEBUG
  1381.  
  1382. #define entry(s) _entry("s");
  1383. #define ret(s) { _ret(s); return(s); }
  1384. #define end { _end(); return; }
  1385.  
  1386. #else
  1387.  
  1388. #define entry(s) _Curr_rtn = "s";
  1389. #define ret(s) return(s);
  1390. #define end return;
  1391.  
  1392. #endif
  1393.  
  1394. /*
  1395.  * utility macros
  1396.  */
  1397.  
  1398. #define IMPORT extern
  1399. #define EXPORT
  1400. #define ROUTINE
  1401. #define forever for(;;)
  1402. #define IS_FRONT(v) (v->cur.here == v->head && v->cur.u_pos == -1)
  1403. #define IS_BACK(v) (v->cur.here == v->tail \
  1404.  && (v->cur.u_pos == v->cur.here->len))
  1405.  
  1406. typedef unsigned char boolean;
  1407.  
  1408. /*
  1409.  * messages/error codes/constants
  1410.  */
  1411.  
  1412. #define M_NOSPACE "out of memory/arena corrupted\n"
  1413. #define M_NILVSTR "null virtual string passed\n"
  1414.  
  1415. #define ATEND        -1
  1416. #define ATBEG        -2
  1417.  
  1418. #define NIL        0
  1419. #define BACK    1
  1420. #define FWD        2
  1421. #define HERE    3
  1422. #define BEG        4
  1423. #define END        5
  1424. #define INS        6
  1425.  
  1426. /*
  1427.  * declarations
  1428.  */
  1429.  
  1430. struct unit {
  1431.     struct unit *prev, *next;
  1432.     LENTYPE len;
  1433.     char *data;
  1434. };
  1435.  
  1436. typedef struct unit *p_unit;
  1437.  
  1438. struct cursor {
  1439.     struct unit *here;
  1440.     LENTYPE u_pos;
  1441. };
  1442.  
  1443. typedef struct cursor *p_cursor;
  1444.  
  1445. struct vstr {
  1446.     p_unit head, tail;
  1447.     LENTYPE unit_size;
  1448.     struct cursor cur;
  1449. };
  1450.  
  1451. typedef struct vstr *p_vstr;
  1452.  
  1453. #ifndef DEBUG
  1454. IMPORT char *_Curr_rtn;
  1455. #endif
  1456.  
  1457. IMPORT char *v_nvtos();
  1458. IMPORT char *v_vtos();
  1459. IMPORT int v_delete();
  1460. IMPORT int v_get();
  1461. IMPORT int v_length();
  1462. IMPORT int v_move();
  1463. IMPORT int v_span();
  1464. IMPORT p_cursor v_find();
  1465. IMPORT p_cursor v_savecursor();
  1466. IMPORT p_unit new_unit();
  1467. IMPORT p_vstr new_vstr();
  1468. IMPORT void freak_out();
  1469. IMPORT void v_append();
  1470. IMPORT void v_clear();
  1471. IMPORT void v_copycursor();
  1472. IMPORT void v_free();
  1473. IMPORT void v_put();
  1474. IMPORT void v_rewind();
  1475. IMPORT void v_setcursor();
  1476. IMPORT void v_show();
  1477. IMPORT void v_stov();
  1478. @//E*O*F vstr.h//
  1479. chmod u=rw,g=r,o=r vstr.h
  1480.  
  1481. echo x - vstr.man
  1482. sed 's/^@//' > "vstr.man" <<'@//E*O*F vstr.man//'
  1483. @.TH STRING 3-ucb
  1484. @.SH NAME
  1485.  
  1486. new_vstr, v_append, v_clear, v_copycursor, v_delete, v_find, v_free, v_get,
  1487. v_length, v_move, v_vtos, v_nvtos, v_put, v_rewind, v_savecursor, v_setcursor,
  1488. v_show, v_span, v_stov
  1489.  
  1490. \-virtual string operations
  1491.  
  1492. @.SH ORIGIN
  1493. 4.2BSD
  1494. @.SH SYNOPSIS
  1495. @.nf
  1496. @.B p_vstr new_vstr(unitsize)
  1497. @.B int unitsize;
  1498. @.PP
  1499. @.B void v_append(v)
  1500. @.B p_vstr v;
  1501. @.PP
  1502. @.B void v_clear(v, how)
  1503. @.B p_vstr v;
  1504. @.B int how;
  1505. @.PP
  1506. @.B void v_copycursor(c1, c2)
  1507. @.B p_cursor c1, c2;
  1508. @.PP
  1509. @.B int v_delete(v, cnt)
  1510. @.B p_vstr v;
  1511. @.B int cnt;
  1512. @.PP
  1513. @.B int v_find(v, ch, dir)
  1514. @.B p_vstr v;
  1515. @.B char ch;
  1516. @.B int dir;
  1517. @.PP
  1518. @.B void v_free(v)
  1519. @.B p_vstr v;
  1520. @.PP
  1521. @.B int v_get(v, mode)
  1522. @.B p_vstr v;
  1523. @.B int mode;
  1524. @.PP
  1525. @.B int v_length(v, how)
  1526. @.B p_vstr v;
  1527. @.B int how;
  1528. @.PP
  1529. @.B char *vtos(v)
  1530. @.B p_vstr v;
  1531. @.PP
  1532. @.B char *nvtos(v, n)
  1533. @.B p_vstr v;
  1534. @.B int n;
  1535. @.PP
  1536. @.B void v_put(v, ch, mode)
  1537. @.B p_vstr v;
  1538. @.B char ch;
  1539. @.B int mode;
  1540. @.PP
  1541. @.B void v_rewind(v)
  1542. @.B p_vstr v;
  1543. @.PP
  1544. @.B void v_setcursor(v, c)
  1545. @.B p_vstr v;
  1546. @.B p_cursor c;
  1547. @.PP
  1548. @.B p_cursor v_savecursor(v, c)
  1549. @.B p_vstr v;
  1550. @.B p_cursor c;
  1551. @.PP
  1552. @.B void v_show(v)
  1553. @.B p_vstr v;
  1554. @.PP
  1555. @.B int v_span(c1, c2)
  1556. @.B p_cursor c1, c2;
  1557. @.PP
  1558. @.B void v_stov(s, v)
  1559. @.B char *s;
  1560. @.B p_vstr v;
  1561. @.PP
  1562. @.fi
  1563. @.SH DESCRIPTION
  1564. These functions allow the creation and manipulation of 'virtual' strings.
  1565. That is, strings that expand and contract as characters are added or deleted.
  1566. Unlike conventional strings, virtual strings have 'cursors' that can be
  1567. moved around in the string determining where operations will take place.
  1568. @.PP
  1569. @.I new_vstr
  1570. allocates space for a new virtual string header and returns a pointer
  1571. to it. Subsequent memory allocations will be in
  1572. @.I unitsize
  1573. byte chunks..
  1574. @.PP
  1575. @.I v_append
  1576. moves the cursor to the last (append) position in string
  1577. @.I v.
  1578. @.PP
  1579. @.I v_clear
  1580. deletes characters from string
  1581. @.I v
  1582. in one of two ways. If
  1583. @.I how
  1584. is set to the constant 'END' then text is deleted from the cursor
  1585. position to the end of the string. If set to anything else, the entire
  1586. string is deleted.
  1587. @.PP
  1588. @.I v_copycursor
  1589. copies the contents of cursor
  1590. @.I c2
  1591. to
  1592. @.I c1.
  1593. @.PP
  1594. @.I v_delete
  1595. deletes
  1596. @.I cnt
  1597. characters from
  1598. @.I v
  1599. starting at the
  1600. @.I current
  1601. cursor position until
  1602. @.I cnt
  1603. is exhausted or the end of the string is hit. Does not move the cursor
  1604. (Characters slide over from the right). Returns the number of characters
  1605. actually deleted.
  1606. @.PP
  1607. @.I v_find
  1608. searches through string
  1609. @.I v
  1610. for char
  1611. @.I ch
  1612. in direction
  1613. @.I dir
  1614. until found, or end is hit. If found, a pointer to a cursor is returned
  1615. containing the location of the found character. Since this cursor
  1616. is declared as a local static in
  1617. @.I v_find,
  1618. care must be taken to save the contents in an auxiliary cursor if the
  1619. contents are to be preserved across subsequent
  1620. @.I v_find
  1621. calls.
  1622. @.PP
  1623. @.I v_free
  1624. deallocates all space used by string
  1625. @.IR v.
  1626. @.PP
  1627. @.I v_get
  1628. gets a character from
  1629. @.I v
  1630. in the following ways depending on
  1631. @.I mode.
  1632. If
  1633. @.I mode
  1634. is the constant 'HERE' the character at the cursor is returned. Otherwise
  1635. a character is returned after moving cursor one position in direction
  1636. @.I mode
  1637. (BACK or FWD).
  1638. Returns the constant ATBEG or ATEND if the cursor cannot be moved
  1639. backwards or forward (the string is rewound or appended).
  1640. @.PP
  1641. @.I v_length
  1642. returns number of characters in string
  1643. @.I v
  1644. in one of three ways, depending on the value of
  1645. @.IR how.
  1646. If
  1647. @.I how
  1648. is the constant 'HERE', then the total number of characters is returned.
  1649. If
  1650. @.I how
  1651. is the constant 'BEG', then the number of characters from the current
  1652. cursor position to the beginning of the string is returned.
  1653. Finally, if
  1654. @.I how
  1655. is the constant 'END', then the number of characters from the current
  1656. cursor position to the end of the string is returned.
  1657. (easy enough..)
  1658. @.PP
  1659. @.I v_vtos
  1660. slurps up characters from the current cursor position in string
  1661. @.I v
  1662. to the end. Returns a malloc'd string containing them.
  1663. @.PP
  1664. @.IR v_nvtos
  1665. is like
  1666. @.I vtos
  1667. but only slurps (at most)
  1668. @.I n
  1669. characters.
  1670. @.PP
  1671. @.I v_put
  1672. places character
  1673. @.I ch
  1674. in string
  1675. @.I v
  1676. depending on the value of
  1677. @.I mode.
  1678. If
  1679. @.I mode
  1680. is 'HERE', the character is placed
  1681. at the cursor position without moving. If set to 'BACK' or 'FWD, it
  1682. moves backwards or forward and places the character. If mode is 'INS',
  1683. then the character is inserted after the cursor position and
  1684. the cursor is moved forward onto the inserted character.
  1685. @.PP
  1686. @.I v_rewind
  1687. moves the cursor in string
  1688. to the beginning (rewound) position in string
  1689. @.I v.
  1690. @.PP
  1691. @.I v_setcursor
  1692. sets the cursor in
  1693. @.I v
  1694. to the contents of the cursor
  1695. @.I c.
  1696. @.PP
  1697. @.I v_savecursor
  1698. copies the cursor in
  1699. @.I v
  1700. to the cursor
  1701. @.I c.
  1702. The address of cursor
  1703. @.I c
  1704. is returned.
  1705. @.PP
  1706. @.I v_show
  1707. is mostly for debugging. It displays the header contents of
  1708. @.I v
  1709. and shows the structure and contents of the linked list. Some types
  1710. of list corruption are also detected and flagged. Kind of cute, but of
  1711. limited use.
  1712. @.PP
  1713. @.I v_span
  1714. returns the number of characters between cursor
  1715. @.I c1
  1716. and
  1717. @.I c2.
  1718. The characters under the cursors are included. This function is
  1719. useful in computing counts for
  1720. @.I v_delete, v_move, v_nvtos
  1721. ect.  If one is clever, certain block operations between cursors can be
  1722. done with the aid of this call.
  1723. @.PP
  1724. @.I v_stov
  1725. puts string
  1726. @.I s
  1727. into
  1728. @.I v
  1729. at the current cursor position. String is added in a forward direction.
  1730. @.PP
  1731. @.SH BUGS
  1732. @.I v_find
  1733. returns the cursor position of the found character. If a subsequent
  1734. @.I v_get
  1735. or
  1736. @.I v_put
  1737. is done, you'll get the
  1738. @.I next
  1739. character since they both advance the cursor before returning a character.
  1740. This is not really a bug, but potentially confusing.
  1741. @.I v_delete
  1742. also acts on the current cursor position, rather that moving then
  1743. deleting. Another potential confuser. (Unless you're using it with
  1744. @.I v_find)
  1745. @.LP
  1746. @//E*O*F vstr.man//
  1747. chmod u=rw,g=r,o=r vstr.man
  1748.  
  1749. echo Inspecting for damage in transit...
  1750. temp=/tmp/shar$$; dtemp=/tmp/.shar$$
  1751. trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
  1752. cat > $temp <<\!!!
  1753.       23      55     472 Makefile
  1754.       64     631    3461 OPERATION
  1755.       40     273    1612 README
  1756.      206     449    3670 examp.c
  1757.       42      83     656 v_alloc.c
  1758.       11      18     148 v_append.c
  1759.       29      65     419 v_clear.c
  1760.       56     125     884 v_cursor.c
  1761.      183     538    3551 v_debug.c
  1762.       55     129     877 v_delete.c
  1763.       25      74     495 v_find.c
  1764.       19      30     224 v_free.c
  1765.       44      93     708 v_get.c
  1766.       52     123     928 v_move.c
  1767.      121     335    2405 v_put.c
  1768.       11      18     134 v_rewind.c
  1769.       66     185    1061 v_string.c
  1770.      205     505    3360 v_utils.c
  1771.      121     376    2464 vstr.h
  1772.      263    1009    5594 vstr.man
  1773.     1636    5114   33123 total
  1774. !!!
  1775. wc  Makefile OPERATION README examp.c v_alloc.c v_append.c v_clear.c v_cursor.c v_debug.c v_delete.c v_find.c v_free.c v_get.c v_move.c v_put.c v_rewind.c v_string.c v_utils.c vstr.h vstr.man | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
  1776. if [ -s $dtemp ]
  1777. then echo "Ouch [diff of wc output]:" ; cat $dtemp
  1778. else echo "No problems found."
  1779. fi
  1780. exit 0
  1781.  
  1782.