Annotation of src/usr.bin/fold/fold.c, Revision 1.17
1.17 ! deraadt 1: /* $OpenBSD: fold.c,v 1.16 2015/10/05 06:26:33 deraadt Exp $ */
1.1 deraadt 2: /* $NetBSD: fold.c,v 1.6 1995/09/01 01:42:44 jtc Exp $ */
3:
4: /*-
5: * Copyright (c) 1990, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * This code is derived from software contributed to Berkeley by
9: * Kevin Ruddy.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
1.7 millert 19: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35:
36: #include <stdio.h>
37: #include <stdlib.h>
38: #include <string.h>
39: #include <unistd.h>
1.13 millert 40: #include <ctype.h>
1.1 deraadt 41: #include <err.h>
1.11 tedu 42: #include <limits.h>
1.1 deraadt 43:
44: #define DEFLINEWIDTH 80
45:
1.15 tedu 46: static void fold(unsigned int);
47: static unsigned int new_column_position(unsigned int, int);
1.13 millert 48: static __dead void usage(void);
1.1 deraadt 49: int count_bytes = 0;
50: int split_words = 0;
51:
52: int
1.8 deraadt 53: main(int argc, char *argv[])
1.1 deraadt 54: {
1.15 tedu 55: int ch, lastch, newarg, prevoptind;
56: unsigned int width;
1.11 tedu 57: const char *errstr;
1.1 deraadt 58:
1.17 ! deraadt 59: if (pledge("stdio rpath", NULL) == -1)
! 60: err(1, "pledge");
1.16 deraadt 61:
1.13 millert 62: width = 0;
63: lastch = '\0';
64: prevoptind = 1;
65: newarg = 1;
66: while ((ch = getopt(argc, argv, "0123456789bsw:")) != -1) {
1.1 deraadt 67: switch (ch) {
68: case 'b':
69: count_bytes = 1;
70: break;
71: case 's':
72: split_words = 1;
73: break;
74: case 'w':
1.15 tedu 75: width = strtonum(optarg, 1, UINT_MAX, &errstr);
1.11 tedu 76: if (errstr != NULL)
77: errx(1, "illegal width value, %s: %s", errstr,
78: optarg);
1.1 deraadt 79: break;
80: case '0': case '1': case '2': case '3': case '4':
81: case '5': case '6': case '7': case '8': case '9':
1.13 millert 82: if (newarg)
83: width = 0;
84: else if (!isdigit(lastch))
85: usage();
1.15 tedu 86: if (width > UINT_MAX / 10 - 1)
1.13 millert 87: errx(1, "illegal width value, too large");
88: width = (width * 10) + (ch - '0');
89: if (width < 1)
90: errx(1, "illegal width value, too small");
1.1 deraadt 91: break;
92: default:
1.13 millert 93: usage();
1.1 deraadt 94: }
1.13 millert 95: lastch = ch;
96: newarg = optind != prevoptind;
97: prevoptind = optind;
98: }
1.1 deraadt 99: argv += optind;
100: argc -= optind;
101:
1.13 millert 102: if (width == 0)
1.1 deraadt 103: width = DEFLINEWIDTH;
104:
1.16 deraadt 105: if (!*argv) {
1.17 ! deraadt 106: if (pledge("stdio", NULL) == -1)
! 107: err(1, "pledge");
1.1 deraadt 108: fold(width);
1.16 deraadt 109: } else {
110: for (; *argv; ++argv) {
111: if (!freopen(*argv, "r", stdin))
112: err(1, "%s", *argv);
113: /* NOTREACHED */
114: else
115: fold(width);
116: }
117: }
1.1 deraadt 118: exit(0);
119: }
120:
121: /*
122: * Fold the contents of standard input to fit within WIDTH columns
123: * (or bytes) and write to standard output.
124: *
125: * If split_words is set, split the line at the last space character
126: * on the line. This flag necessitates storing the line in a buffer
127: * until the current column > width, or a newline or EOF is read.
128: *
129: * The buffer can grow larger than WIDTH due to backspaces and carriage
130: * returns embedded in the input stream.
131: */
132: static void
1.15 tedu 133: fold(unsigned int width)
1.1 deraadt 134: {
135: static char *buf = NULL;
136: static int buf_max = 0;
1.15 tedu 137: int ch;
138: unsigned int col, indx;
1.1 deraadt 139:
140: col = indx = 0;
141: while ((ch = getchar()) != EOF) {
142: if (ch == '\n') {
143: if (indx != 0)
1.6 deraadt 144: fwrite(buf, 1, indx, stdout);
1.1 deraadt 145: putchar('\n');
146: col = indx = 0;
147: continue;
148: }
149:
1.6 deraadt 150: col = new_column_position(col, ch);
1.1 deraadt 151: if (col > width) {
1.15 tedu 152: unsigned int i, last_space;
1.1 deraadt 153:
154: if (split_words) {
155: for (i = 0, last_space = -1; i < indx; i++)
1.6 deraadt 156: if(buf[i] == ' ')
157: last_space = i;
1.1 deraadt 158: }
159:
160: if (split_words && last_space != -1) {
161: last_space++;
162:
1.6 deraadt 163: fwrite(buf, 1, last_space, stdout);
164: memmove(buf, buf+last_space, indx-last_space);
1.1 deraadt 165:
166: indx -= last_space;
167: col = 0;
168: for (i = 0; i < indx; i++) {
1.6 deraadt 169: col = new_column_position(col, buf[i]);
1.1 deraadt 170: }
171: } else {
1.6 deraadt 172: fwrite(buf, 1, indx, stdout);
1.1 deraadt 173: col = indx = 0;
174: }
175: putchar('\n');
176:
177: /* calculate the column position for the next line. */
1.6 deraadt 178: col = new_column_position(col, ch);
1.1 deraadt 179: }
180:
181: if (indx + 1 > buf_max) {
1.10 tedu 182: int newmax = buf_max + 2048;
183: char *newbuf;
184:
1.1 deraadt 185: /* Allocate buffer in LINE_MAX increments */
1.10 tedu 186: if ((newbuf = realloc(buf, newmax)) == NULL) {
1.6 deraadt 187: err(1, NULL);
1.1 deraadt 188: /* NOTREACHED */
189: }
1.10 tedu 190: buf = newbuf;
191: buf_max = newmax;
1.1 deraadt 192: }
193: buf[indx++] = ch;
194: }
195:
196: if (indx != 0)
1.6 deraadt 197: fwrite(buf, 1, indx, stdout);
1.1 deraadt 198: }
199:
200: /*
201: * calculate the column position
202: */
1.15 tedu 203: static unsigned int
204: new_column_position(unsigned int col, int ch)
1.1 deraadt 205: {
206: if (!count_bytes) {
207: switch (ch) {
208: case '\b':
209: if (col > 0)
210: --col;
211: break;
212: case '\r':
213: col = 0;
214: break;
215: case '\t':
216: col = (col + 8) & ~7;
217: break;
218: default:
219: ++col;
220: break;
221: }
222: } else {
223: ++col;
224: }
225:
226: return col;
1.13 millert 227: }
228:
229: static __dead void
230: usage(void)
231: {
232: (void)fprintf(stderr, "usage: fold [-bs] [-w width] [file ...]\n");
233: exit(1);
1.1 deraadt 234: }