home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #27 / NN_1992_27.iso / spool / alt / sources / 2537 / buffer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-17  |  12.2 KB  |  705 lines

  1. /* 
  2.  * Copyright 1992 Peter da Silva
  3.  *
  4.  * Permission to use, copy, modify, and distribute this
  5.  * software and its documentation for any purpose and without
  6.  * fee is hereby granted, provided that the above copyright
  7.  * notice appear in all copies.  The author[s] make no representations
  8.  * about the suitability of this software for any purpose.
  9.  * It is provided "as is" without express or implied warranty.
  10.  */
  11.  
  12. /* Code to handle an editor buffer */
  13. #include <stdio.h>
  14.  
  15. char *malloc();
  16.  
  17. #define new(t,n) ((t *)malloc(n * sizeof (t)))
  18.  
  19. #define MAXBUFS 32
  20. #define MAXMARKS 32
  21.  
  22. typedef struct {
  23.     int body_length;    /* number of bytes of text in body */
  24.     int text_length;    /* number of bytes of text in body */
  25.     int gap;        /* start of gap */
  26.     int gapsize;        /* length of gap */
  27.     int mark[MAXMARKS];
  28.     int himark;
  29.     char *body;
  30. } buffer;
  31.  
  32. static buffer *buftab[MAXBUFS];
  33. static int hibuffer;
  34.  
  35. static char *lastroutine = "NONE";
  36.  
  37. #define mark2index(m) ((m)-1)
  38. #define index2mark(i) ((i)+1)
  39.  
  40. /* checkbuf(bufptr, buffer, name)
  41.  *
  42.  * Checks the integrity of a buffer structure. Called from each routine
  43.  * that resolves a buffer into a pointer to make sure the pointer is valid
  44.  * and the buffer hasn't been stepped on.
  45.  */
  46. checkbuf(b,i,n)
  47. buffer *b;
  48. char *n;
  49. {
  50.     if(b->body_length != b->text_length+b->gapsize) {
  51.         fprintf(stderr, "buffer(%d): Inconsistent sizes %d!=%d+%d\n",
  52.             i, b->body_length, b->text_length, b->gapsize);
  53.     } else if(b->gap < 0 || b->gap > b->text_length) {
  54.         fprintf(stderr, "buffer(%d): Gap out of range %d\n",
  55.             i, b->gap);
  56.     } else if(b->himark < 0 || b->himark > MAXMARKS) {
  57.         fprintf(stderr, "buffer(%d): Mark count out of range %d\n",
  58.             i, b->himark);
  59.     } else {
  60. #ifdef TEST
  61.         int index;
  62.  
  63.         for(index = 0; index < b->himark; index++) {
  64.             if(b->mark[index] < -1
  65.             || b->mark[index] > b->text_length) {
  66.                 fprintf(stderr,
  67.                     "buffer(%d): mark(%d) out of range %d\n",
  68.                     i, index2mark(index), b->mark[index]);
  69.                 break;
  70.             }
  71.         }
  72.         if(index == b->himark) {
  73.             lastroutine = n;
  74.             return;
  75.         }
  76. #else
  77.         lastroutine = n;
  78.         return;
  79. #endif
  80.     }
  81.     fprintf(stderr, "Error detected in %s called after %s\n",
  82.         n, lastroutine);
  83.     exit(-1);
  84. }
  85.  
  86. #define CHECK(b,i,n,f) \
  87.     buffer_error = invalid_buffer; \
  88.     if(i >= 0 && i < hibuffer) { \
  89.         b = buftab[i]; \
  90.         if(!b) return f; \
  91.     } else return f; \
  92.     checkbuf(b,i,n)
  93.  
  94. #define CHECKMARK(b,j,v) \
  95.     if(j < -1 || j > b->himark) { \
  96.         buffer_error = mark_range; \
  97.         return v; \
  98.     } else if(j > 0 && b->mark[mark2index(j)] == -1) { \
  99.         buffer_error = mark_unset; \
  100.         return v; \
  101.     }
  102.  
  103. static char *invalid_buffer = "Invalid buffer ID";
  104. static char *found_eof = "Beyond end of buffer";
  105. static char *found_bof = "Beyond beginning of buffer";
  106. static char *mark_range = "Mark out of range";
  107. static char *mark_unset = "Mark not set";
  108.  
  109. char *buffer_error;
  110.  
  111. int new_buffer()
  112. {
  113.     int i, index;
  114.  
  115.     for(i = 0; i < hibuffer; i++)
  116.         if(!buftab[i])
  117.             break;
  118.     if(i == hibuffer) {
  119.         if(hibuffer == MAXBUFS) {
  120.             buffer_error = "No more buffers";
  121.             return -1;
  122.         }
  123.         hibuffer++;
  124.     }
  125.     buftab[i] = new(buffer, 1);
  126.     if(!buftab[i]) {
  127.         buffer_error = "Memory allocation failure";
  128.         return -1;
  129.     }
  130.     buftab[i] -> body_length = 0;
  131.     buftab[i] -> text_length = 0;
  132.     buftab[i] -> gapsize = 0;
  133.     buftab[i] -> gap = 0;
  134.     for(index = 0; index < MAXMARKS; index++)
  135.         buftab[i] -> mark[index] = -1;
  136.     buftab[i] -> himark = 0;
  137.     buftab[i] -> body = (char *)0;
  138.  
  139.     return i;
  140. }
  141.  
  142. delete_buffer(i)
  143. int i;
  144. {
  145.     buffer *b;
  146.  
  147.     CHECK(b,i,"delete_buffer",-1);
  148.  
  149.     if(b->body) free(b->body);
  150.  
  151.     free(b);
  152.  
  153.     buftab[i] = 0;
  154.  
  155.     return 0;
  156. }
  157.  
  158. int new_mark(i, off)
  159. int i, off;
  160. {
  161.     int index;
  162.     buffer *b;
  163.  
  164.     CHECK(b,i,"new_mark",-1);
  165.  
  166.     if(off < 0 || off > b->text_length) {
  167.         buffer_error = mark_range;
  168.         return -1;
  169.     }
  170.  
  171.     for(index = 0; index < b->himark; index++)
  172.         if(b->mark[index] == -1)
  173.             break;
  174.     if(index == b->himark) {
  175.         if(b->himark == MAXBUFS) {
  176.             buffer_error = "No more marks";
  177.             return -1;
  178.         }
  179.         b->himark++;
  180.     }
  181.     b->mark[index] = off;
  182.  
  183.     return index2mark(index);
  184. }
  185.  
  186. int copy_mark(i, j)
  187. int i, j;
  188. {
  189.     int off;
  190.  
  191.     off = locate_mark(i, j);
  192.  
  193.     if(off == -1)
  194.         return -1;
  195.     else
  196.         return new_mark(i, off);
  197. }
  198.  
  199. delete_mark(i, j)
  200. int i;
  201. int j;
  202. {
  203.     buffer *b;
  204.  
  205.     CHECK(b,i,"delete_mark",-1);
  206.     CHECKMARK(b,j,-1);
  207.  
  208.     if(j <= 0) {
  209.         buffer_error = "Deleting fixed mark";
  210.         return -1;
  211.     }
  212.  
  213.     b->mark[mark2index(j)] = -1;
  214.  
  215.     return 0;
  216. }
  217.  
  218. move_mark(i, j, off)
  219. int i;
  220. int j;
  221. {
  222.     buffer *b;
  223.  
  224.     CHECK(b,i,"move_mark",-1);
  225.     CHECKMARK(b,j,-1);
  226.  
  227.     if(j <= 0) {
  228.         buffer_error = "Moving fixed mark";
  229.         return -1;
  230.     }
  231.  
  232.     off += b->mark[mark2index(j)];
  233.  
  234.     if(off > b->text_length) {
  235.         buffer_error = found_eof;
  236.         return -1;
  237.     }
  238.  
  239.     if(off < 0) {
  240.         buffer_error = found_bof;
  241.         return -1;
  242.     }
  243.  
  244.     b->mark[mark2index(j)] = off;
  245.  
  246.     return off;
  247. }
  248.  
  249. locate_mark(i, j)
  250. int i;
  251. int j;
  252. {
  253.     buffer *b;
  254.  
  255.     CHECK(b,i,"locate_mark",-1);
  256.     CHECKMARK(b,j,-1);
  257.  
  258.     if(j == -1)
  259.         return b->text_length;
  260.     else if(j == 0)
  261.         return 0;
  262.     else {
  263.         int off = b->mark[mark2index(j)];
  264. #ifndef TEST
  265.         if(off == -1)
  266.             buffer_error = "Mark not set";
  267.         else if(off < -1 || off > b->text_length) {
  268.             buffer_error = "Internal error: Bad mark";
  269.             return -1;
  270.         }
  271. #endif
  272.         return off;
  273.     }
  274. }
  275.  
  276. static safecopy(body, to, from, length)
  277. char *body;
  278. int to, from, length;
  279. {
  280.     int i;
  281.  
  282.     if(to>from)
  283.         for(i = 0; i < length; i++)
  284.             body[to+i] = body[from+i];
  285.     else
  286.         for(i = length-1; i>=0; i--)
  287.             body[to+i] = body[from+i];
  288. }
  289.  
  290. /* move_gap(buffer, gap_position)
  291.  *
  292.  * Moves the gap to the indicated position in the buffer. This does not change
  293.  * the logical structure of the buffer. It is most often used to move the gap
  294.  * to a mark for deletion or (if space allows) insertion. It's also used to
  295.  * move the gap out of range of a set of marks.
  296.  */
  297. static move_gap(i, newgap)
  298. int i;
  299. int newgap;
  300. {
  301.     buffer *b;
  302.  
  303.     CHECK(b,i,"move_gap",-1);
  304.  
  305.     if(newgap > b->gap) {
  306.         safecopy(b->body,
  307.              b->gap,    /* move to beginning of old gap */
  308.              b->gap+b->gapsize,    /* from end of old gap */
  309.              newgap-b->gap);
  310.     } else {
  311.         safecopy(b->body,
  312.              newgap+b->gapsize,    /* move to end of new gap */
  313.              newgap,    /* from beginning of new gap */
  314.              b->gap-newgap);
  315.     }
  316.     b->gap = newgap;
  317.  
  318.     return 0;
  319. }
  320.  
  321. /* expand_gap(buffer, space_needed, gap_position)
  322.  *
  323.  * Because the gap usually needs to be moved when it's expanded, I combine the
  324.  * two actions into a single expand_gap. This is more efficient for the common
  325.  * case, though it makes the code a little hard to follow.
  326.  *
  327.  * You are not expected to understand this.
  328.  *
  329.  * I've always wanted to say that. :->
  330.  *
  331.  * I probably need to put conditions on some more of the calls to memcpy to
  332.  * handle the case of the gap being at the beginning or end of the buffer.
  333.  * That's just an optimization, but what the heck.
  334.  */
  335. static expand_gap(i, newsize, newgap)
  336. int i;
  337. int newsize;
  338. int newgap;
  339. {
  340.     buffer *b;
  341.     char *newbody;
  342.     int newlength;
  343.  
  344.     CHECK(b,i,"expand_gap",-1);
  345.  
  346.     newlength = b->body_length + newsize;
  347.     newbody = malloc(newlength);
  348.     if(newbody)
  349.         newsize += b->gapsize;
  350.     else {
  351.         newlength = b->text_length + newsize;
  352.         newbody = malloc(newlength);
  353.     }
  354.  
  355.     if(!newbody) {
  356.         buffer_error = "Memory allocation failure";
  357.         return -1;
  358.     }
  359.  
  360.     /* Here there be tygers. If you change this code, sit down ahead of
  361.      * time and figure out EXACTLY what the individual moves do.
  362.      */
  363.     if(b->body) {
  364.         if(newgap < b->gap) {
  365.             memcpy(newbody, b->body, newgap);
  366.             memcpy(newbody+newgap+newsize, b->body+newgap,
  367.                 b->gap-newgap);
  368.             memcpy(newbody+newsize+b->gap,
  369.                 b->body+b->gap+b->gapsize,
  370.                 b->text_length-b->gap);
  371.         } else {
  372.             memcpy(newbody, b->body, b->gap);
  373.             if(newgap > b->gap) {
  374.                 memcpy(newbody+b->gap,
  375.                     b->body+b->gap+b->gapsize,
  376.                     newgap-b->gap);
  377.             }
  378.             memcpy(newbody+newgap+newsize,
  379.                 b->body+b->gapsize+newgap,
  380.                 b->text_length-newgap);
  381.         }
  382.  
  383.         free(b->body);
  384.     }
  385.  
  386.     b->body = newbody;
  387.     b->gap = newgap;
  388.     b->gapsize = newsize;
  389.     b->body_length = newlength;
  390.     b->text_length = newlength-newsize;
  391.  
  392.     return b->gapsize;
  393. }
  394.  
  395. char *text(i, m1, m2, length)
  396. int i;
  397. int m1, m2;
  398. int *length;
  399. {
  400.     buffer *b;
  401.     char *p;
  402.     int o1, o2;
  403.     int start;
  404.  
  405.     CHECK(b,i,"text",0);
  406.  
  407.     if ((o1 = locate_mark(i, m1)) == -1
  408.      || (o2 = locate_mark(i, m2)) == -1)
  409.         return 0;
  410.  
  411.     if(o2 < o1) {
  412.         int tmp = o2;
  413.         o2 = o1;
  414.         o1 = tmp;
  415.     }
  416.  
  417.     *length = o2 - o1;
  418.  
  419.     if(o1 < b->gap && o2 > b->gap)
  420.         move_gap(i, o2);
  421.  
  422.     start = o1;
  423.  
  424.     if(start > b->gap)
  425.         start += b->gapsize;
  426.  
  427.     return b->body + start;
  428. }
  429.  
  430. char *open_text(i, mark, length)
  431. int i;
  432. int mark;
  433. int length;
  434. {
  435.     buffer *b;
  436.     char *p;
  437.     int off;
  438.  
  439.     CHECK(b,i,"open_text",0);
  440.  
  441.     if ((off = locate_mark(i, mark)) == -1)
  442.         return 0;
  443.  
  444.     if(b->gapsize < length) {
  445.         if(expand_gap(i, length, off) < 0)
  446.             return 0;
  447.     }
  448.     else if(off != b->gap)
  449.         move_gap(i, off);
  450.  
  451.     return b->body + b->gap;
  452. }
  453.  
  454. close_text(i, length)
  455. int i;
  456. int length;
  457. {
  458.     buffer *b;
  459.  
  460.     CHECK(b,i,"close_text",-1);
  461.  
  462.     fix_marks(i, length);
  463.  
  464.     b->gap += length;
  465.     b->gapsize -= length;
  466.     b->text_length += length;
  467.     return length;
  468. }
  469.  
  470. copy_text(i, m1, m2, outbuf, length)
  471. int i;
  472. int m1, m2;
  473. char *outbuf;
  474. int length;
  475. {
  476.     char *p;
  477.     int delta;
  478.  
  479.     p = text(i, m1, m2, &delta);
  480.  
  481.     if(!p) return -1;
  482.  
  483.     if(delta > length) {
  484.         buffer_error = "Output string too short";
  485.         return -1;
  486.     }
  487.  
  488.     memcpy(outbuf, p, delta);
  489.  
  490.     return delta;
  491. }
  492.  
  493. cut_text(i, m1, m2, outbuf, length)
  494. int i;
  495. int m1, m2;
  496. char *outbuf;
  497. int length;
  498. {
  499.     if (copy_text(i, m1, m2, outbuf, length) >= 0)
  500.         return delete_text(i, m1, m2);
  501.  
  502.     return -1;
  503. }
  504.  
  505. /* fix_marks(buffer, length)
  506.  *
  507.  * This routine readjusts the marks after the gap when text has been added
  508.  * or removed. Marks are considered to be attached to text that follows, so
  509.  * marks right on the gap are moved. In the case of a deletion these marks
  510.  * (and any others in the portion of text that has been deleted) are removed.
  511.  */
  512. static fix_marks(i,length)
  513. int i;
  514. int length;
  515. {
  516.     buffer *b;
  517.     int index;
  518.  
  519.     CHECK(b,i,"fix_marks",-1);
  520.  
  521.     for(index = 0; index < b->himark; index++) {
  522.         if(b->mark[index] >= b->gap) {
  523.             b->mark[index] += length;
  524.             if(b->mark[index] < b->gap) {
  525.                 b->mark[index] = -1;
  526.             }
  527.         }
  528.     }
  529. }
  530.  
  531. insert_text(i, mark, text, length)
  532. int i;
  533. int mark;
  534. char *text;
  535. int length;
  536. {
  537.     char *p;
  538.  
  539.     p = open_text(i, mark, length);
  540.     if(!p) return -1;
  541.  
  542.     memcpy(p, text, length);
  543.  
  544.     close_text(i, length);
  545.  
  546.     return length;
  547. }
  548.  
  549. delete_text(i, m1, m2)
  550. int i;
  551. int m1, m2;
  552. {
  553.     buffer *b;
  554.     int o1, o2;
  555.     int length;
  556.  
  557.     CHECK(b,i,"delete_text",-1);
  558.  
  559.     if ((o1 = locate_mark(i, m1)) == -1
  560.      || (o2 = locate_mark(i, m2)) == -1)
  561.         return -1;
  562.  
  563.     if(o2 < o1) {
  564.         int tmp = o2;
  565.         o2 = o1;
  566.         o1 = tmp;
  567.         tmp = m2;
  568.         m2 = m1;
  569.         m1 = tmp;
  570.     }
  571.  
  572.     if(o2 == o1)
  573.         return 0;
  574.  
  575.     length = o2 - o1;
  576.  
  577.     if(o1 != b->gap) {
  578.         move_gap(i, o1);
  579.     }
  580.  
  581.     fix_marks(i, -length);
  582.  
  583.     b->gapsize += length;
  584.     b->text_length -= length;
  585.  
  586.     return length;
  587. }
  588.  
  589. int count_chars(i, m1, m2, c)
  590. int i;
  591. int m1, m2;
  592. char c;
  593. {
  594.     int length, count;
  595.     char *p;
  596.  
  597.     p = text(i, m1, m2, &length);
  598.  
  599.     count = 0;
  600.     while(length-- >  0)
  601.         if(*p++ == c)
  602.             count++;
  603.  
  604.     return count;
  605. }
  606.  
  607. #ifdef TEST
  608. static dputs(s, l)
  609. char *s;
  610. int l;
  611. {
  612.     while(l>0) {
  613.         char c = *s++;
  614.  
  615.         if(c & 0x80) {
  616.             printf("%");
  617.             c &= 0x7F;
  618.         }
  619.         if((c < ' ' || c > 127) && c != '\n') {
  620.             putchar('~');
  621.             c ^= '@';
  622.         }
  623.         if(c == '~' || c == '%')
  624.             putchar(c);
  625.         putchar(c);
  626.         l--;
  627.     }
  628. }
  629. #endif
  630.  
  631. buffer_debug(i)
  632. int i;
  633. {
  634.     buffer *b;
  635.     int index;
  636.  
  637.     CHECK(b,i,"buffer_debug",-1);
  638.  
  639.     printf("buffer(%d) length=%d/%d gap=%d gapsize=%d himark=%d\n",
  640.         i, b->body_length, b->text_length,
  641.            b->gap, b->gapsize, b->himark);
  642.     for(index = 0; index < b->himark; index++)
  643.         printf("\tmark(%d) = %d\n", index2mark(index), b->mark[index]);
  644. #ifdef TEST
  645.     if(b->body) {
  646.         printf("body = {");
  647.         dputs(b->body, b->gap);
  648.         printf("} GAP {");
  649.         dputs(b->body+b->gap+b->gapsize, b->text_length-b->gap);
  650.         printf("};\n");
  651.     }
  652. #endif
  653.     fflush(stdout);
  654. }
  655.  
  656. int search(i, m1, m2, pat)
  657. int i, m1, m2;
  658. char *pat;
  659. {
  660.     char *boyer_moore_search_compile();
  661.     char *boyer_moore_search_execute();
  662.     int patlen;
  663.     int worklen;
  664.     int new_mark;
  665.     char *compiled;
  666.     char *work;
  667.     int dummy;
  668.     char *found;
  669.  
  670.     patlen = strlen(pat);
  671.  
  672.     work = text(i, m1, m2, &worklen);
  673.     if(!work)
  674.         return -1;
  675.  
  676.     if(locate_mark(i, m1) < locate_mark(i, m2))
  677.         new_mark = copy_mark(i, m1);
  678.     else
  679.         new_mark = copy_mark(i, m2);
  680.  
  681.     if(new_mark <= 0)
  682.         return -1;
  683.  
  684.     compiled = boyer_moore_search_compile(pat, patlen);
  685.     if(!compiled) {
  686.         delete_mark(i, new_mark);
  687.         buffer_error = "Search string compile failed";
  688.         return -1;
  689.     }
  690.  
  691.     found = boyer_moore_search_execute(work, worklen, compiled, &dummy);
  692.  
  693.     free(compiled);
  694.  
  695.     if(!found) {
  696.         delete_mark(i, new_mark);
  697.         buffer_error = "Search string not found";
  698.         return 0;
  699.     }
  700.  
  701.     move_mark(i, new_mark, found - work);
  702.  
  703.     return new_mark;
  704. }
  705.