|
|
1.1 root 1: /*
2: * c.c
3: * 9/23/91
4: * Usage: c [ -lN ] [ -wN ] [ -012 ]
5: * Columnize from stdin to stdout.
6: */
7:
8: #include <stdio.h>
9:
10: #define VERSION "1.3"
11:
12: extern char *getenv();
13:
14: #define NAV 6 /* max # environmental args */
15:
16: typedef struct line {
17: struct line *l_next;
18: char *l_line;
19: } LINE;
20:
21: /* Forward. */
22: char *item();
23: char *sel0();
24: char *sel1();
25: char *sel2();
26: void nomem();
27: void fatal();
28:
29: /* Globals. */
30: int fieldmax; /* # columns of widest field */
31: int length; /* # lines down page */
32: LINE *lhead; /* head of LINE list */
33: LINE *ltail; /* tail of LINE list */
34: int nacross; /* # fields across page */
35: int ndown; /* # fields down page */
36: int nfields; /* # fields read from input */
37: int npp; /* # fields per page */
38: char *(*select)() = sel1; /* selector function */
39: char *usage = "\nUsage: c [ -lN ] [ -wN ] [ -012 ]";
40: int width = 80; /* # columns across page */
41:
42: main(argc, argv) int argc; char *argv[];
43: {
44: char obuf[BUFSIZ], av[NAV];
45:
46: envargs(av);
47: setflags(av);
48: setflags(&argv[1]);
49: setbuf(stdout, obuf);
50: input();
51: output();
52: exit(0);
53: }
54:
55: setflags(av) register char **av;
56: {
57:
58: for (; *av; ++av) {
59: if (av[0][0] != '-')
60: fatal("%s is not an option%s", av[0], usage);
61: switch (av[0][1]) {
62: case '0':
63: select = sel0;
64: break;
65: case '1':
66: select = sel1;
67: break;
68: case '2':
69: select = sel2;
70: break;
71: case 'w':
72: width = atoi(&av[0][2]);
73: break;
74: case 'l':
75: length = atoi(&av[0][2]);
76: break;
77: case 'V':
78: fprintf(stderr, "c: V%s\n", VERSION);
79: break;
80: default:
81: fatal("bad option %s%s", av[0], usage);
82: }
83: }
84: }
85:
86: input()
87: {
88: register LINE *lp;
89: register i;
90: char lbuf[BUFSIZ];
91:
92: while ((i=getline(lbuf)) >= 0) {
93: lp = malloc(sizeof *lp);
94: if (lp == NULL)
95: nomem();
96: if (lhead)
97: ltail->l_next = lp;
98: else
99: lhead = lp;
100: ltail = lp;
101: lp->l_next = NULL;
102: if (i) {
103: lp->l_line = malloc(i+1);
104: if (lp->l_line == NULL)
105: nomem();
106: strcpy(lp->l_line, lbuf);
107: }
108: else
109: lp->l_line = NULL;
110: ++nfields;
111: }
112:
113: ++fieldmax;
114: }
115:
116: output()
117: {
118: register int i, j;
119:
120: nacross = (width+1) / fieldmax;
121: if (nacross <= 0)
122: nacross = 1;
123: if (length != 0)
124: npp = length * nacross;
125: ndown = (nfields + nacross - 1) / nacross;
126: for (i = 0; i < ndown; ++i) {
127: for (j = 0; j < nacross; ++j)
128: putline((*select)(i, j));
129: putline((char *)0);
130: }
131:
132: fclose(stdout);
133: }
134:
135:
136: getline(lbuf) char lbuf[];
137: {
138: register char *p;
139: register int col, xcol;
140: int c;
141:
142: p = lbuf;
143: col = 0;
144: xcol = 0;
145:
146: for (; ;) {
147: switch (c = getchar()) {
148: case EOF:
149: return (-1);
150: case '\n':
151: break;
152: case ' ':
153: ++xcol;
154: continue;
155: case '\t':
156: xcol = (xcol|7) + 1;
157: continue;
158: case '\b':
159: if (xcol > col)
160: --xcol;
161: else if (col) {
162: --col;
163: --xcol;
164: *p++ = c;
165: }
166: continue;
167: default:
168: while (col < xcol) {
169: *p++ = ' ';
170: ++col;
171: }
172: *p++ = c;
173: ++col;
174: ++xcol;
175: continue;
176: }
177: break;
178: }
179:
180: if (col > fieldmax)
181: fieldmax = col;
182: *p = '\0';
183: return (p - lbuf);
184: }
185:
186: putline(lbuf) char *lbuf;
187: {
188: register c;
189: register char *p;
190: static col,
191: xcol;
192:
193: p = lbuf;
194: if (p == NULL) {
195: col = 0;
196: xcol = 0;
197: putchar('\n');
198: return;
199: }
200:
201: while (c = *p++)
202: switch (c) {
203: case ' ':
204: ++xcol;
205: break;
206: case '\b':
207: --col;
208: --xcol;
209: putchar(c);
210: break;
211: default:
212: while ((col|7)+1 <= xcol) {
213: putchar('\t');
214: col = (col|7) + 1;
215: }
216: while (col < xcol) {
217: putchar(' ');
218: ++col;
219: }
220: putchar(c);
221: ++col;
222: ++xcol;
223: break;
224: }
225:
226: xcol += fieldmax - xcol%fieldmax;
227: }
228:
229: char *
230: item(n) int n;
231: {
232: register LINE *lp;
233: register int m;
234:
235: for (m = 0, lp = lhead; lp; lp = lp->l_next)
236: if (++m > n)
237: return (lp->l_line ? lp->l_line : "");
238: return "";
239: }
240:
241: /*
242: * Across each row, then on to next row.
243: */
244: char *
245: sel0(i, j) int i, j;
246: {
247: return item(i*nacross + j);
248: }
249:
250: /*
251: * Down each column, then on to next column.
252: * Leave spaces in last column.
253: */
254: char *
255: sel1(i, j) int i, j;
256: {
257: register int page, rows, line;
258:
259: if (length == 0)
260: return item(i + j*ndown);
261: page = i / length; /* page number */
262: line = i % length; /* line on page */
263: if (page == (ndown-1)/length)
264: rows = ((ndown-1)%length) + 1; /* rows on last page */
265: else
266: rows = length; /* rows on full page */
267: return item(page * npp + line + j * rows);
268: }
269:
270: /*
271: * Down each column, then on to next column.
272: * Leave spaces in last row.
273: */
274: char *
275: sel2(i, j) int i, j;
276: {
277: register int ncols, page, line, adjust;
278:
279: if (i * nacross + j >= nfields)
280: return "";
281: ncols = nfields % nacross; /* columns in incomplete last line */
282: adjust = (j > ncols) ? ncols : j; /* last line adjust */
283: if (length == 0)
284: return item(i /* n on prev. lines this col. */
285: + j*(ndown-1) /* n on prev. cols. */
286: + adjust); /* n on last line */
287: page = i / length; /* page number */
288: line = i % length; /* line on page */
289: if (page != (ndown-1)/length) /* not last page */
290: return item(page * npp + line + j * length);
291: else /* last page */
292: return item(page * npp /* n on prev. pages. */
293: + line /* n on prev. lines this col. */
294: + j*((ndown-1)%length) /* n on prev. cols. */
295: + adjust); /* n on last line */
296: }
297:
298: envargs(av) char **av;
299: {
300: register fl;
301: register char *p;
302: register char **ap;
303:
304: ap = av;
305: *ap = NULL;
306: if ((p=getenv("C")) == NULL)
307: return;
308:
309: fl = 0;
310: while (*p)
311: switch (*p++) {
312: case '\t':
313: case '\n':
314: case ' ':
315: fl = 0;
316: p[-1] = '\0';
317: break;
318: default:
319: if (fl)
320: break;
321: if (ap >= &av[NAV-1])
322: fatal("too many environmental arguments");
323: *ap++ = &p[-1];
324: ++fl;
325: break;
326: }
327:
328: *ap = NULL;
329: }
330:
331: void
332: nomem()
333: {
334:
335: fatal("out of memory");
336: }
337:
338: void
339: fatal(arg0)
340: char *arg0;
341: {
342:
343: fflush(stdout);
344: fprintf(stderr, "c: %r\n", &arg0);
345: exit(1);
346: }
347:
348: /* end of c.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.