home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume7 / nstrings.bsd / output.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-06-03  |  5.8 KB  |  243 lines

  1. static char * sccsid = "@(#)  output.c  (v6.5 5/19/89)";
  2. /*
  3.  * Output routines for 'strings'.
  4.  * We roll our own here, because stdio either expects NUL terminated
  5.  * strings, which we don't have, or tests for buffer overflow at each
  6.  * character. But we know how much characters will be added to the
  7.  * output block, so we can make do with two or three tests per sequence
  8.  * of printable characters.
  9.  *
  10.  * Sequences are stuffed into the output buffer, even temporarily when
  11.  * we could not decide what to do with them, yet had to remember the
  12.  * characters. When a temporary sequence is made permanent or a
  13.  * permanent sequence added, and the new length of data in the output
  14.  * buffer exceeds a threshold, it is output.
  15.  * If the buffer overflows in between it is extended with a call to
  16.  * realloc. This rarely ever happens, but if it happens, then
  17.  * you will rather have strings to be slowing down than dump core.
  18.  */
  19.  
  20. # include "strings.h"
  21.  
  22. /*
  23.  * The characters in out_buf until num_out_buf are already accepted.
  24.  * level points at the end of all characters in out_buf, even the
  25.  * temporarily saved ones.
  26.  * saved is the number of characters temporarily saved.
  27.  * Note that level and saved are not the same. If there are number before
  28.  * the sequences, then buf+num_out_buf+saved != level !!
  29.  * Note that sometimes I have to compute the number of characters between
  30.  * out_buf and level. I do this by subtracting the two pointers. I assume
  31.  * that the result is int or convertible to int, but I don't have the
  32.  * authority at hand to prove this.
  33.  */
  34. CHAR_TYPE * out_buf;
  35. int num_out_buf = 0;                /* numbers of chars in out_buf */
  36. CHAR_TYPE * level;
  37. int buf_len;
  38. int saved = 0;
  39.  
  40. extern int ind_offset;
  41. extern int ind_prefix;
  42. extern CHAR_TYPE buf[];
  43. extern LSEEK_TYPE offset;
  44. extern char * cur_file_name;
  45.  
  46. extern char * malloc ();
  47. extern char * realloc ();
  48.  
  49. init_output ()
  50. {
  51.     out_buf = (CHAR_TYPE *) malloc (sizeof (CHAR_TYPE) * OUT_BUF_LEN);
  52.     level = out_buf;
  53.     num_out_buf = 0;
  54.     buf_len = OUT_BUF_LEN;
  55. }
  56.  
  57. flush_output ()
  58. /*
  59.  * Num_out_buf characters from the buffer are written.
  60.  */
  61. {
  62.     if (num_out_buf > 0) {
  63. # ifdef DEBUG
  64.         fprintf (prot, "flush_output : write %d chars\n", num_out_buf);
  65. # endif
  66.         if (write (1, out_buf, num_out_buf) != num_out_buf) {
  67.             out ("PANIC : write error\n");
  68.             exit (1);
  69.         }
  70.         num_out_buf = 0;
  71.     }
  72.     level = out_buf;
  73. }
  74.  
  75. static
  76. make_room (n)
  77. register int n;
  78. /*
  79.  * Must reallocate.
  80.  * Buffer is enlarged by at least IN_BUF_LEN characters. The largest
  81.  * piece which has to be put into the buffer will be at most IN_BUF_LEN
  82.  * characters. If there is a sequence of puts, the buffer will be enlarged
  83.  * each time. This should happen very rarely.
  84.  */
  85. {
  86.     register int i;
  87. # ifdef DEBUG
  88.     fprintf (prot, "make_room :: REALLOC realloc called.\n");
  89.     fflush (prot);
  90. # endif
  91.     /*
  92.      * Level is a pointer into out_buf. We have to save it here and
  93.      * restore it later, because realloc might cause a copying of the
  94.      * contents of out_buf to a new address.
  95.      */
  96.     i = level - out_buf;
  97.     buf_len += n>IN_BUF_LEN?n:IN_BUF_LEN;
  98. # ifdef DEBUG
  99.     fprintf (prot, "make_room :: output buffer will be enlarged to %d\n", buf_len);
  100. # endif
  101.     out_buf = (CHAR_TYPE *) realloc (out_buf, (unsigned int)buf_len);
  102.     if (out_buf == NULL) {            /* panic */
  103.         (void)write (2, "REALLOC ERROR.\n", 15);
  104.         exit (1);
  105.     }
  106.     level = out_buf + i;
  107. }
  108.  
  109. void
  110. add_cur_file_name ()
  111. /*
  112.  * Only called if command line flag '-p' was specified.
  113.  * Add the name of the current input file to the output stream.
  114.  */
  115. {
  116.     register int i;
  117.  
  118.     if (cur_file_name == NULL)
  119.         return;
  120.     i = strlen (cur_file_name);
  121.     /*
  122.      * Is there space for (i+1) characters at the end of the output buffer?
  123.      * If not, flush it.
  124.      */
  125.     if ((int)(level - out_buf) + i + 1 > buf_len)
  126.         make_room (i+1);
  127.     FAST_COPY (cur_file_name, level, i);
  128.     level += i;
  129.     *level++ = ':';
  130. }
  131.  
  132. append (b1, b2, ind_perm)
  133. register CHAR_TYPE * b1, * b2;
  134. int ind_perm;
  135. /*
  136.  * Append a sequence permanently. Set the pointers.
  137.  * If there are more than THRESHOLD characters then write them.
  138.  */
  139. {
  140.     register int n;
  141.  
  142.     /*
  143.      * If the user wants it and this is the first part of a sequence,
  144.      * add name of current file as prefix.
  145.      */
  146.     if (ind_prefix && saved == 0)
  147.         add_cur_file_name ();
  148.     /*
  149.      * If there are no saved characters and the user wants offsets,
  150.      * then we have to add an offset first.
  151.      */
  152.     if (ind_offset && saved == 0)
  153.         output_offset (b1);
  154.     /*
  155.      * Is there enough space in out outbuf ?
  156.      */
  157.     n = b2 - b1;
  158.     if ((int)(level - out_buf) + n + 1 > buf_len)
  159.         make_room (n);
  160.     /*
  161.      * Copy the sequence. It may be empty, so don't forget to add a LF here.
  162.      */
  163.     if (n > 0) {
  164.         FAST_COPY (b1, level, n);
  165.         level += n;
  166.     }
  167.     if (ind_perm == 1) {
  168.         *level++ = '\n';
  169.         /*
  170.          * There may be some temporarily saved characters in out_buf. Make
  171.          * them permanent.
  172.          */
  173.         num_out_buf = level - out_buf;
  174.         /*
  175.          * If necessary, write.
  176.          */
  177.         if (num_out_buf > THRESHOLD)
  178.             flush_output ();
  179.         saved = 0;
  180.     } else
  181.         saved = n;
  182. }
  183.  
  184. output_offset (b1)
  185. CHAR_TYPE * b1;
  186. /*
  187.  * Convert n to its character representation in decimal and append this
  188.  * at the end of the output buffer.
  189.  * Normally we output 7 characters. If the number needs more we expand.
  190.  */
  191. {
  192.     register int i;
  193.     register long j;
  194.     register LSEEK_TYPE l;
  195.     CHAR_TYPE * b;
  196.  
  197.     l = offset + (int)(b1 - buf);
  198.     /*
  199.      * How many characters must we output ?
  200.      */
  201.     for (i = 7, j = 10000000L; l >= j; j *= 10, i++);
  202.  
  203.     /*
  204.      * Is there space for (i+1) characters at the end of the output buffer?
  205.      * If not, flush it.
  206.      */
  207.     if ((int)(level - out_buf) + i+1 > buf_len)
  208.         make_room (i+1);
  209.  
  210.     b = level;
  211.     level += i+1;
  212.  
  213.     b[i--] = ' ';
  214.     /*
  215.      * Convert the number.
  216.      */
  217.     do {
  218.         b[i--] = '0' + l % 10;
  219.         l /= 10;
  220.     } while (l != 0);
  221.     /*
  222.      * Add some blanks in front of number
  223.      */
  224.     for (; i >= 0; i--)
  225.         b [i] = ' ';
  226. }
  227.  
  228. # ifdef DEBUG
  229. out (s)
  230. {
  231.     fputc (s, stderr);
  232. }
  233. # else DEBUG
  234. /*
  235.  * The main program calls a routine called 'out'.
  236.  */
  237. out (s)
  238. register char * s;
  239. {
  240.     (void)write (2, s, strlen(s));
  241. }
  242. # endif DEBUG
  243.