LCOV - code coverage report
Current view: top level - src - fold.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 115 118 97.5 %
Date: 2018-01-30 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /* fold -- wrap each input line to fit in specified width.
       2             :    Copyright (C) 91, 1995-2006 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 3 of the License, or
       7             :    (at your option) 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, see <http://www.gnu.org/licenses/>.  */
      16             : 
      17             : /* Written by David MacKenzie, djm@gnu.ai.mit.edu. */
      18             : 
      19             : #include <config.h>
      20             : 
      21             : #include <stdio.h>
      22             : #include <getopt.h>
      23             : #include <sys/types.h>
      24             : 
      25             : #include "system.h"
      26             : #include "error.h"
      27             : #include "quote.h"
      28             : #include "xstrtol.h"
      29             : 
      30             : #define TAB_WIDTH 8
      31             : 
      32             : /* The official name of this program (e.g., no `g' prefix).  */
      33             : #define PROGRAM_NAME "fold"
      34             : 
      35             : #define AUTHORS "David MacKenzie"
      36             : 
      37             : /* The name this program was run with. */
      38             : char *program_name;
      39             : 
      40             : /* If nonzero, try to break on whitespace. */
      41             : static bool break_spaces;
      42             : 
      43             : /* If nonzero, count bytes, not column positions. */
      44             : static bool count_bytes;
      45             : 
      46             : /* If nonzero, at least one of the files we read was standard input. */
      47             : static bool have_read_stdin;
      48             : 
      49             : static char const shortopts[] = "bsw:0::1::2::3::4::5::6::7::8::9::";
      50             : 
      51             : static struct option const longopts[] =
      52             : {
      53             :   {"bytes", no_argument, NULL, 'b'},
      54             :   {"spaces", no_argument, NULL, 's'},
      55             :   {"width", required_argument, NULL, 'w'},
      56             :   {GETOPT_HELP_OPTION_DECL},
      57             :   {GETOPT_VERSION_OPTION_DECL},
      58             :   {NULL, 0, NULL, 0}
      59             : };
      60             : 
      61             : void
      62           9 : usage (int status)
      63             : {
      64           9 :   if (status != EXIT_SUCCESS)
      65           8 :     fprintf (stderr, _("Try `%s --help' for more information.\n"),
      66             :              program_name);
      67             :   else
      68             :     {
      69           1 :       printf (_("\
      70             : Usage: %s [OPTION]... [FILE]...\n\
      71             : "),
      72             :               program_name);
      73           1 :       fputs (_("\
      74             : Wrap input lines in each FILE (standard input by default), writing to\n\
      75             : standard output.\n\
      76             : \n\
      77             : "), stdout);
      78           1 :       fputs (_("\
      79             : Mandatory arguments to long options are mandatory for short options too.\n\
      80             : "), stdout);
      81           1 :       fputs (_("\
      82             :   -b, --bytes         count bytes rather than columns\n\
      83             :   -s, --spaces        break at spaces\n\
      84             :   -w, --width=WIDTH   use WIDTH columns instead of 80\n\
      85             : "), stdout);
      86           1 :       fputs (HELP_OPTION_DESCRIPTION, stdout);
      87           1 :       fputs (VERSION_OPTION_DESCRIPTION, stdout);
      88           1 :       emit_bug_reporting_address ();
      89             :     }
      90           9 :   exit (status);
      91             : }
      92             : 
      93             : /* Assuming the current column is COLUMN, return the column that
      94             :    printing C will move the cursor to.
      95             :    The first column is 0. */
      96             : 
      97             : static size_t
      98          26 : adjust_column (size_t column, char c)
      99             : {
     100          26 :   if (!count_bytes)
     101             :     {
     102          22 :       if (c == '\b')
     103             :         {
     104           4 :           if (column > 0)
     105           1 :             column--;
     106             :         }
     107          18 :       else if (c == '\r')
     108           2 :         column = 0;
     109          16 :       else if (c == '\t')
     110          15 :         column += TAB_WIDTH - column % TAB_WIDTH;
     111             :       else /* if (isprint (c)) */
     112           1 :         column++;
     113             :     }
     114             :   else
     115           4 :     column++;
     116          26 :   return column;
     117             : }
     118             : 
     119             : /* Fold file FILENAME, or standard input if FILENAME is "-",
     120             :    to stdout, with maximum line length WIDTH.
     121             :    Return true if successful.  */
     122             : 
     123             : static bool
     124          65 : fold_file (char const *filename, size_t width)
     125             : {
     126             :   FILE *istream;
     127             :   int c;
     128          65 :   size_t column = 0;            /* Screen column where next char will go. */
     129          65 :   size_t offset_out = 0;        /* Index in `line_out' for next char. */
     130             :   static char *line_out = NULL;
     131             :   static size_t allocated_out = 0;
     132             :   int saved_errno;
     133             : 
     134          65 :   if (STREQ (filename, "-"))
     135             :     {
     136          44 :       istream = stdin;
     137          44 :       have_read_stdin = true;
     138             :     }
     139             :   else
     140          21 :     istream = fopen (filename, "r");
     141             : 
     142          65 :   if (istream == NULL)
     143             :     {
     144          12 :       error (0, errno, "%s", filename);
     145          12 :       return false;
     146             :     }
     147             : 
     148         418 :   while ((c = getc (istream)) != EOF)
     149             :     {
     150         312 :       if (offset_out + 1 >= allocated_out)
     151          37 :         line_out = X2REALLOC (line_out, &allocated_out);
     152             : 
     153         312 :       if (c == '\n')
     154             :         {
     155         293 :           line_out[offset_out++] = c;
     156         293 :           fwrite (line_out, sizeof (char), offset_out, stdout);
     157         293 :           column = offset_out = 0;
     158         293 :           continue;
     159             :         }
     160             : 
     161          19 :     rescan:
     162          25 :       column = adjust_column (column, c);
     163             : 
     164          25 :       if (column > width)
     165             :         {
     166             :           /* This character would make the line too long.
     167             :              Print the line plus a newline, and make this character
     168             :              start the next line. */
     169          15 :           if (break_spaces)
     170             :             {
     171           9 :               bool found_blank = false;
     172           9 :               size_t logical_end = offset_out;
     173             : 
     174             :               /* Look for the last blank. */
     175          21 :               while (logical_end)
     176             :                 {
     177           5 :                   --logical_end;
     178           5 :                   if (isblank (to_uchar (line_out[logical_end])))
     179             :                     {
     180           2 :                       found_blank = true;
     181           2 :                       break;
     182             :                     }
     183             :                 }
     184             : 
     185           9 :               if (found_blank)
     186             :                 {
     187             :                   size_t i;
     188             : 
     189             :                   /* Found a blank.  Don't output the part after it. */
     190           2 :                   logical_end++;
     191           2 :                   fwrite (line_out, sizeof (char), (size_t) logical_end,
     192             :                           stdout);
     193           2 :                   putchar ('\n');
     194             :                   /* Move the remainder to the beginning of the next line.
     195             :                      The areas being copied here might overlap. */
     196           2 :                   memmove (line_out, line_out + logical_end,
     197             :                            offset_out - logical_end);
     198           2 :                   offset_out -= logical_end;
     199           3 :                   for (column = i = 0; i < offset_out; i++)
     200           1 :                     column = adjust_column (column, line_out[i]);
     201           2 :                   goto rescan;
     202             :                 }
     203             :             }
     204             : 
     205          13 :           if (offset_out == 0)
     206             :             {
     207           9 :               line_out[offset_out++] = c;
     208           9 :               continue;
     209             :             }
     210             : 
     211           4 :           line_out[offset_out++] = '\n';
     212           4 :           fwrite (line_out, sizeof (char), (size_t) offset_out, stdout);
     213           4 :           column = offset_out = 0;
     214           4 :           goto rescan;
     215             :         }
     216             : 
     217          10 :       line_out[offset_out++] = c;
     218             :     }
     219             : 
     220          53 :   saved_errno = errno;
     221             : 
     222          53 :   if (offset_out)
     223           1 :     fwrite (line_out, sizeof (char), (size_t) offset_out, stdout);
     224             : 
     225          53 :   if (ferror (istream))
     226             :     {
     227           7 :       error (0, saved_errno, "%s", filename);
     228           7 :       if (!STREQ (filename, "-"))
     229           7 :         fclose (istream);
     230           7 :       return false;
     231             :     }
     232          46 :   if (!STREQ (filename, "-") && fclose (istream) == EOF)
     233             :     {
     234           0 :       error (0, errno, "%s", filename);
     235           0 :       return false;
     236             :     }
     237             : 
     238          46 :   return true;
     239             : }
     240             : 
     241             : int
     242          79 : main (int argc, char **argv)
     243             : {
     244          79 :   size_t width = 80;
     245             :   int i;
     246             :   int optc;
     247             :   bool ok;
     248             : 
     249             :   initialize_main (&argc, &argv);
     250          79 :   program_name = argv[0];
     251          79 :   setlocale (LC_ALL, "");
     252             :   bindtextdomain (PACKAGE, LOCALEDIR);
     253             :   textdomain (PACKAGE);
     254             : 
     255          79 :   atexit (close_stdout);
     256             : 
     257          79 :   break_spaces = count_bytes = have_read_stdin = false;
     258             : 
     259         185 :   while ((optc = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1)
     260             :     {
     261             :       char optargbuf[2];
     262             : 
     263          60 :       switch (optc)
     264             :         {
     265           9 :         case 'b':               /* Count bytes rather than columns. */
     266           9 :           count_bytes = true;
     267           9 :           break;
     268             : 
     269           7 :         case 's':               /* Break at word boundaries. */
     270           7 :           break_spaces = true;
     271           7 :           break;
     272             : 
     273          10 :         case '0': case '1': case '2': case '3': case '4':
     274             :         case '5': case '6': case '7': case '8': case '9':
     275          10 :           if (optarg)
     276           7 :             optarg--;
     277             :           else
     278             :             {
     279           3 :               optargbuf[0] = optc;
     280           3 :               optargbuf[1] = '\0';
     281           3 :               optarg = optargbuf;
     282             :             }
     283             :           /* Fall through.  */
     284             :         case 'w':               /* Line width. */
     285             :           {
     286             :             unsigned long int tmp_ulong;
     287          45 :             if (! (xstrtoul (optarg, NULL, 10, &tmp_ulong, "") == LONGINT_OK
     288          12 :                    && 0 < tmp_ulong && tmp_ulong < SIZE_MAX - TAB_WIDTH))
     289          23 :               error (EXIT_FAILURE, 0,
     290             :                      _("invalid number of columns: %s"), quote (optarg));
     291          11 :             width = tmp_ulong;
     292             :           }
     293          11 :           break;
     294             : 
     295           1 :         case_GETOPT_HELP_CHAR;
     296             : 
     297           1 :         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
     298             : 
     299           8 :         default:
     300           8 :           usage (EXIT_FAILURE);
     301             :         }
     302             :     }
     303             : 
     304          46 :   if (argc == optind)
     305          14 :     ok = fold_file ("-", width);
     306             :   else
     307             :     {
     308          32 :       ok = true;
     309          83 :       for (i = optind; i < argc; i++)
     310          51 :         ok &= fold_file (argv[i], width);
     311             :     }
     312             : 
     313          46 :   if (have_read_stdin && fclose (stdin) == EOF)
     314           0 :     error (EXIT_FAILURE, errno, "-");
     315             : 
     316          46 :   exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
     317             : }

Generated by: LCOV version 1.10