home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 1 / FFMCD01.bin / useful / dist / gnu / textutils / textutils-1.6-amiga / src / fold.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-22  |  6.4 KB  |  294 lines

  1. /* fold -- wrap each input line to fit in specified width.
  2.    Copyright (C) 1991 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Written by David MacKenzie, djm@gnu.ai.mit.edu. */
  19.  
  20. /* Get isblank from GNU libc.  */
  21. #define _GNU_SOURCE
  22.  
  23. #include <stdio.h>
  24. #include <getopt.h>
  25. #include <sys/types.h>
  26. #include "system.h"
  27. #include "version.h"
  28.  
  29. char *xrealloc ();
  30. char *xmalloc ();
  31. void error ();
  32.  
  33. /* The name this program was run with. */
  34. char *program_name;
  35.  
  36. static int adjust_column ();
  37. static int fold_file ();
  38.  
  39. /* If nonzero, try to break on whitespace. */
  40. static int break_spaces;
  41.  
  42. /* If nonzero, count bytes, not column positions. */
  43. static int count_bytes;
  44.  
  45. /* If nonzero, at least one of the files we read was standard input. */
  46. static int have_read_stdin;
  47.  
  48. /* If non-zero, display usage information and exit.  */
  49. static int flag_help;
  50.  
  51. /* If non-zero, print the version on standard error.  */
  52. static int flag_version;
  53.  
  54. static struct option const longopts[] =
  55. {
  56.   {"bytes", no_argument, NULL, 'b'},
  57.   {"spaces", no_argument, NULL, 's'},
  58.   {"width", required_argument, NULL, 'w'},
  59.   {"help", no_argument, &flag_help, 1},
  60.   {"version", no_argument, &flag_version, 1},
  61.   {NULL, 0, NULL, 0}
  62. };
  63.  
  64. static void
  65. usage ()
  66. {
  67.   fprintf (stderr, "\
  68. Usage: %s [-bs] [-w width] [--bytes] [--spaces] [--width=width]\n\
  69.        [--help] [--version] [file...]\n",
  70.        program_name);
  71.   exit (1);
  72. }
  73.  
  74. void
  75. main (argc, argv)
  76.      int argc;
  77.      char **argv;
  78. {
  79.   int width = 80;
  80.   int i;
  81.   int optc;
  82.   int errs = 0;
  83.  
  84.   program_name = argv[0];
  85.   break_spaces = count_bytes = have_read_stdin = 0;
  86.  
  87.   /* Turn any numeric options into -w options.  */
  88.   for (i = 1; i < argc; i++)
  89.     {
  90.       if (argv[i][0] == '-' && ISDIGIT (argv[i][1]))
  91.     {
  92.       char *s;
  93.  
  94.       s = xmalloc (strlen (argv[i]) + 2);
  95.       s[0] = '-';
  96.       s[1] = 'w';
  97.       strcpy (s + 2, argv[i] + 1);
  98.       argv[i] = s;
  99.     }
  100.     }
  101.  
  102.   while ((optc = getopt_long (argc, argv, "bsw:", longopts, (int *) 0))
  103.      != EOF)
  104.     {
  105.       switch (optc)
  106.     {
  107.     case 0:
  108.       break;
  109.  
  110.     case 'b':        /* Count bytes rather than columns. */
  111.       count_bytes = 1;
  112.       break;
  113.  
  114.     case 's':        /* Break at word boundaries. */
  115.       break_spaces = 1;
  116.       break;
  117.  
  118.     case 'w':        /* Line width. */
  119.       width = atoi (optarg);
  120.       if (width < 1)
  121.         error (1, 0, "%s: invalid line width", optarg);
  122.       break;
  123.  
  124.     default:
  125.       usage ();
  126.     }
  127.     }
  128.  
  129.   if (flag_version)
  130.     {
  131.       fprintf (stderr, "%s\n", version_string);
  132.       exit (0);
  133.     }
  134.  
  135.   if (flag_help)
  136.     usage ();
  137.  
  138.   if (argc == optind)
  139.     errs |= fold_file ("-", width);
  140.   else
  141.     for (i = optind; i < argc; i++)
  142.       errs |= fold_file (argv[i], width);
  143.  
  144.   if (have_read_stdin && fclose (stdin) == EOF)
  145.     error (1, errno, "-");
  146.   if (fclose (stdout) == EOF)
  147.     error (1, errno, "write error");
  148.  
  149.   exit (errs);
  150. }
  151.  
  152. /* Fold file FILENAME, or standard input if FILENAME is "-",
  153.    to stdout, with maximum line length WIDTH.
  154.    Return 0 if successful, 1 if an error occurs. */
  155.  
  156. static int
  157. fold_file (filename, width)
  158.      char *filename;
  159.      int width;
  160. {
  161.   FILE *istream;
  162.   register int c;
  163.   int column = 0;        /* Screen column where next char will go. */
  164.   int offset_out = 0;        /* Index in `line_out' for next char. */
  165.   static char *line_out = NULL;
  166.   static size_t allocated_out = 0;
  167.  
  168.   if (!strcmp (filename, "-"))
  169.     {
  170.       istream = stdin;
  171.       have_read_stdin = 1;
  172.     }
  173.   else
  174.     istream = fopen (filename, "r");
  175.  
  176.   if (istream == NULL)
  177.     {
  178.       error (0, errno, "%s", filename);
  179.       return 1;
  180.     }
  181.  
  182.   while ((c = getc (istream)) != EOF)
  183.     {
  184.       if (offset_out + 1 >= allocated_out)
  185.     {
  186.       allocated_out += 1024;
  187.       line_out = xrealloc (line_out, allocated_out);
  188.     }
  189.       
  190.       if (c == '\n')
  191.     {
  192.       line_out[offset_out++] = c;
  193.       fwrite (line_out, sizeof (char), offset_out, stdout);
  194.       column = offset_out = 0;
  195.       continue;
  196.     }
  197.  
  198.     rescan:
  199.       column = adjust_column (column, c);
  200.  
  201.       if (column > width)
  202.     {
  203.       /* This character would make the line too long.
  204.          Print the line plus a newline, and make this character
  205.          start the next line. */
  206.       if (break_spaces)
  207.         {
  208.           /* Look for the last blank. */
  209.           int logical_end;
  210.  
  211.           for (logical_end = offset_out - 1; logical_end >= 0;
  212.            logical_end--)
  213.         if (ISBLANK (line_out[logical_end]))
  214.           break;
  215.           if (logical_end >= 0)
  216.         {
  217.           int i;
  218.  
  219.           /* Found a blank.  Don't output the part after it. */
  220.           logical_end++;
  221.           fwrite (line_out, sizeof (char), logical_end, stdout);
  222.           putchar ('\n');
  223.           /* Move the remainder to the beginning of the next line.
  224.              The areas being copied here might overlap. */
  225.           bcopy (line_out + logical_end, line_out,
  226.              offset_out - logical_end);
  227.           offset_out -= logical_end;
  228.           for (column = i = 0; i < offset_out; i++)
  229.             column = adjust_column (column, line_out[i]);
  230.           goto rescan;
  231.         }
  232.         }
  233.       line_out[offset_out++] = '\n';
  234.       fwrite (line_out, sizeof (char), offset_out, stdout);
  235.       column = offset_out = 0;
  236.       goto rescan;
  237.     }
  238.  
  239.       line_out[offset_out++] = c;
  240.     }
  241.  
  242.   if (offset_out)
  243.     fwrite (line_out, sizeof (char), offset_out, stdout);
  244.  
  245.   if (ferror (istream))
  246.     {
  247.       error (0, errno, "%s", filename);
  248.       if (strcmp (filename, "-"))
  249.     fclose (istream);
  250.       return 1;
  251.     }
  252.   if (strcmp (filename, "-") && fclose (istream) == EOF)
  253.     {
  254.       error (0, errno, "%s", filename);
  255.       return 1;
  256.     }
  257.  
  258.   if (ferror (stdout))
  259.     {
  260.       error (0, errno, "write error");
  261.       return 1;
  262.     }
  263.  
  264.   return 0;
  265. }
  266.  
  267. /* Assuming the current column is COLUMN, return the column that
  268.    printing C will move the cursor to.
  269.    The first column is 0. */
  270.  
  271. static int
  272. adjust_column (column, c)
  273.      int column;
  274.      char c;
  275. {
  276.   if (!count_bytes)
  277.     {
  278.       if (c == '\b')
  279.     {
  280.       if (column > 0)
  281.         column--;
  282.     }
  283.       else if (c == '\r')
  284.     column = 0;
  285.       else if (c == '\t')
  286.     column = column + 8 - column % 8;
  287.       else /* if (isprint (c)) */
  288.     column++;
  289.     }
  290.   else
  291.     column++;
  292.   return column;
  293. }
  294.