19b50d902SRodney W. Grimes /*- 29b50d902SRodney W. Grimes * Copyright (c) 1990, 1993, 1994 39b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 49b50d902SRodney W. Grimes * 59b50d902SRodney W. Grimes * This code is derived from software contributed to Berkeley by 69b50d902SRodney W. Grimes * Michael Rendell of the Memorial University of Newfoundland. 79b50d902SRodney W. Grimes * 89b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 99b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 109b50d902SRodney W. Grimes * are met: 119b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 129b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 139b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 149b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 159b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 169b50d902SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 179b50d902SRodney W. Grimes * must display the following acknowledgement: 189b50d902SRodney W. Grimes * This product includes software developed by the University of 199b50d902SRodney W. Grimes * California, Berkeley and its contributors. 209b50d902SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 219b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 229b50d902SRodney W. Grimes * without specific prior written permission. 239b50d902SRodney W. Grimes * 249b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 259b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 269b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 279b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 289b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 299b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 309b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 319b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 329b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 339b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 349b50d902SRodney W. Grimes * SUCH DAMAGE. 359b50d902SRodney W. Grimes */ 369b50d902SRodney W. Grimes 379b50d902SRodney W. Grimes #ifndef lint 389b50d902SRodney W. Grimes static char copyright[] = 399b50d902SRodney W. Grimes "@(#) Copyright (c) 1990, 1993, 1994\n\ 409b50d902SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 419b50d902SRodney W. Grimes #endif /* not lint */ 429b50d902SRodney W. Grimes 439b50d902SRodney W. Grimes #ifndef lint 44df3f5d9dSPeter Wemm static char sccsid[] = "@(#)col.c 8.5 (Berkeley) 5/4/95"; 459b50d902SRodney W. Grimes #endif /* not lint */ 469b50d902SRodney W. Grimes 479b50d902SRodney W. Grimes #include <ctype.h> 489b50d902SRodney W. Grimes #include <err.h> 499b50d902SRodney W. Grimes #include <string.h> 509b50d902SRodney W. Grimes #include <stdio.h> 519b50d902SRodney W. Grimes #include <stdlib.h> 52df3f5d9dSPeter Wemm #include <unistd.h> 538bbd9072SAndrey A. Chernov #include <locale.h> 549b50d902SRodney W. Grimes 559b50d902SRodney W. Grimes #define BS '\b' /* backspace */ 569b50d902SRodney W. Grimes #define TAB '\t' /* tab */ 579b50d902SRodney W. Grimes #define SPACE ' ' /* space */ 589b50d902SRodney W. Grimes #define NL '\n' /* newline */ 599b50d902SRodney W. Grimes #define CR '\r' /* carriage return */ 609b50d902SRodney W. Grimes #define ESC '\033' /* escape */ 619b50d902SRodney W. Grimes #define SI '\017' /* shift in to normal character set */ 629b50d902SRodney W. Grimes #define SO '\016' /* shift out to alternate character set */ 639b50d902SRodney W. Grimes #define VT '\013' /* vertical tab (aka reverse line feed) */ 649b50d902SRodney W. Grimes #define RLF '\007' /* ESC-07 reverse line feed */ 659b50d902SRodney W. Grimes #define RHLF '\010' /* ESC-010 reverse half-line feed */ 669b50d902SRodney W. Grimes #define FHLF '\011' /* ESC-011 forward half-line feed */ 679b50d902SRodney W. Grimes 689b50d902SRodney W. Grimes /* build up at least this many lines before flushing them out */ 699b50d902SRodney W. Grimes #define BUFFER_MARGIN 32 709b50d902SRodney W. Grimes 719b50d902SRodney W. Grimes typedef char CSET; 729b50d902SRodney W. Grimes 739b50d902SRodney W. Grimes typedef struct char_str { 749b50d902SRodney W. Grimes #define CS_NORMAL 1 759b50d902SRodney W. Grimes #define CS_ALTERNATE 2 769b50d902SRodney W. Grimes short c_column; /* column character is in */ 779b50d902SRodney W. Grimes CSET c_set; /* character set (currently only 2) */ 789b50d902SRodney W. Grimes char c_char; /* character in question */ 799b50d902SRodney W. Grimes } CHAR; 809b50d902SRodney W. Grimes 819b50d902SRodney W. Grimes typedef struct line_str LINE; 829b50d902SRodney W. Grimes struct line_str { 839b50d902SRodney W. Grimes CHAR *l_line; /* characters on the line */ 849b50d902SRodney W. Grimes LINE *l_prev; /* previous line */ 859b50d902SRodney W. Grimes LINE *l_next; /* next line */ 869b50d902SRodney W. Grimes int l_lsize; /* allocated sizeof l_line */ 879b50d902SRodney W. Grimes int l_line_len; /* strlen(l_line) */ 889b50d902SRodney W. Grimes int l_needs_sort; /* set if chars went in out of order */ 899b50d902SRodney W. Grimes int l_max_col; /* max column in the line */ 909b50d902SRodney W. Grimes }; 919b50d902SRodney W. Grimes 929b50d902SRodney W. Grimes LINE *alloc_line __P((void)); 939b50d902SRodney W. Grimes void dowarn __P((int)); 949b50d902SRodney W. Grimes void flush_line __P((LINE *)); 959b50d902SRodney W. Grimes void flush_lines __P((int)); 969b50d902SRodney W. Grimes void flush_blanks __P((void)); 979b50d902SRodney W. Grimes void free_line __P((LINE *)); 989b50d902SRodney W. Grimes void usage __P((void)); 999b50d902SRodney W. Grimes void wrerr __P((void)); 1009b50d902SRodney W. Grimes void *xmalloc __P((void *, size_t)); 1019b50d902SRodney W. Grimes 1029b50d902SRodney W. Grimes CSET last_set; /* char_set of last char printed */ 1039b50d902SRodney W. Grimes LINE *lines; 1049b50d902SRodney W. Grimes int compress_spaces; /* if doing space -> tab conversion */ 1059b50d902SRodney W. Grimes int fine; /* if `fine' resolution (half lines) */ 1069b50d902SRodney W. Grimes int max_bufd_lines; /* max # lines to keep in memory */ 1079b50d902SRodney W. Grimes int nblank_lines; /* # blanks after last flushed line */ 1089b50d902SRodney W. Grimes int no_backspaces; /* if not to output any backspaces */ 1099b50d902SRodney W. Grimes 1109b50d902SRodney W. Grimes #define PUTC(ch) \ 111f746e67cSBruce Evans do { \ 1129b50d902SRodney W. Grimes if (putchar(ch) == EOF) \ 113f746e67cSBruce Evans wrerr(); \ 114f746e67cSBruce Evans } while (0) 1159b50d902SRodney W. Grimes 1169b50d902SRodney W. Grimes int 1179b50d902SRodney W. Grimes main(argc, argv) 1189b50d902SRodney W. Grimes int argc; 1199b50d902SRodney W. Grimes char **argv; 1209b50d902SRodney W. Grimes { 1219b50d902SRodney W. Grimes int ch; 1229b50d902SRodney W. Grimes CHAR *c; 1239b50d902SRodney W. Grimes CSET cur_set; /* current character set */ 1249b50d902SRodney W. Grimes LINE *l; /* current line */ 1259b50d902SRodney W. Grimes int extra_lines; /* # of lines above first line */ 1269b50d902SRodney W. Grimes int cur_col; /* current column */ 1279b50d902SRodney W. Grimes int cur_line; /* line number of current position */ 1289b50d902SRodney W. Grimes int max_line; /* max value of cur_line */ 1299b50d902SRodney W. Grimes int this_line; /* line l points to */ 1309b50d902SRodney W. Grimes int nflushd_lines; /* number of lines that were flushed */ 1319b50d902SRodney W. Grimes int adjust, opt, warned; 1329b50d902SRodney W. Grimes 1338bbd9072SAndrey A. Chernov (void) setlocale(LC_CTYPE, ""); 1348bbd9072SAndrey A. Chernov 1359b50d902SRodney W. Grimes max_bufd_lines = 128; 1369b50d902SRodney W. Grimes compress_spaces = 1; /* compress spaces into tabs */ 1379b50d902SRodney W. Grimes while ((opt = getopt(argc, argv, "bfhl:x")) != EOF) 1389b50d902SRodney W. Grimes switch (opt) { 1399b50d902SRodney W. Grimes case 'b': /* do not output backspaces */ 1409b50d902SRodney W. Grimes no_backspaces = 1; 1419b50d902SRodney W. Grimes break; 1429b50d902SRodney W. Grimes case 'f': /* allow half forward line feeds */ 1439b50d902SRodney W. Grimes fine = 1; 1449b50d902SRodney W. Grimes break; 1459b50d902SRodney W. Grimes case 'h': /* compress spaces into tabs */ 1469b50d902SRodney W. Grimes compress_spaces = 1; 1479b50d902SRodney W. Grimes break; 1489b50d902SRodney W. Grimes case 'l': /* buffered line count */ 1499b50d902SRodney W. Grimes if ((max_bufd_lines = atoi(optarg)) <= 0) { 1509b50d902SRodney W. Grimes (void)fprintf(stderr, 1519b50d902SRodney W. Grimes "col: bad -l argument %s.\n", optarg); 1529b50d902SRodney W. Grimes exit(1); 1539b50d902SRodney W. Grimes } 1549b50d902SRodney W. Grimes break; 1559b50d902SRodney W. Grimes case 'x': /* do not compress spaces into tabs */ 1569b50d902SRodney W. Grimes compress_spaces = 0; 1579b50d902SRodney W. Grimes break; 1589b50d902SRodney W. Grimes case '?': 1599b50d902SRodney W. Grimes default: 1609b50d902SRodney W. Grimes usage(); 1619b50d902SRodney W. Grimes } 1629b50d902SRodney W. Grimes 1639b50d902SRodney W. Grimes if (optind != argc) 1649b50d902SRodney W. Grimes usage(); 1659b50d902SRodney W. Grimes 1669b50d902SRodney W. Grimes /* this value is in half lines */ 1679b50d902SRodney W. Grimes max_bufd_lines *= 2; 1689b50d902SRodney W. Grimes 1699b50d902SRodney W. Grimes adjust = cur_col = extra_lines = warned = 0; 1709b50d902SRodney W. Grimes cur_line = max_line = nflushd_lines = this_line = 0; 1719b50d902SRodney W. Grimes cur_set = last_set = CS_NORMAL; 1729b50d902SRodney W. Grimes lines = l = alloc_line(); 1739b50d902SRodney W. Grimes 1749b50d902SRodney W. Grimes while ((ch = getchar()) != EOF) { 1759b50d902SRodney W. Grimes if (!isgraph(ch)) { 1769b50d902SRodney W. Grimes switch (ch) { 1779b50d902SRodney W. Grimes case BS: /* can't go back further */ 1789b50d902SRodney W. Grimes if (cur_col == 0) 1799b50d902SRodney W. Grimes continue; 1809b50d902SRodney W. Grimes --cur_col; 1819b50d902SRodney W. Grimes continue; 1829b50d902SRodney W. Grimes case CR: 1839b50d902SRodney W. Grimes cur_col = 0; 1849b50d902SRodney W. Grimes continue; 1859b50d902SRodney W. Grimes case ESC: /* just ignore EOF */ 1869b50d902SRodney W. Grimes switch(getchar()) { 1879b50d902SRodney W. Grimes case RLF: 1889b50d902SRodney W. Grimes cur_line -= 2; 1899b50d902SRodney W. Grimes break; 1909b50d902SRodney W. Grimes case RHLF: 1919b50d902SRodney W. Grimes cur_line--; 1929b50d902SRodney W. Grimes break; 1939b50d902SRodney W. Grimes case FHLF: 1949b50d902SRodney W. Grimes cur_line++; 1959b50d902SRodney W. Grimes if (cur_line > max_line) 1969b50d902SRodney W. Grimes max_line = cur_line; 1979b50d902SRodney W. Grimes } 1989b50d902SRodney W. Grimes continue; 1999b50d902SRodney W. Grimes case NL: 2009b50d902SRodney W. Grimes cur_line += 2; 2019b50d902SRodney W. Grimes if (cur_line > max_line) 2029b50d902SRodney W. Grimes max_line = cur_line; 2039b50d902SRodney W. Grimes cur_col = 0; 2049b50d902SRodney W. Grimes continue; 2059b50d902SRodney W. Grimes case SPACE: 2069b50d902SRodney W. Grimes ++cur_col; 2079b50d902SRodney W. Grimes continue; 2089b50d902SRodney W. Grimes case SI: 2099b50d902SRodney W. Grimes cur_set = CS_NORMAL; 2109b50d902SRodney W. Grimes continue; 2119b50d902SRodney W. Grimes case SO: 2129b50d902SRodney W. Grimes cur_set = CS_ALTERNATE; 2139b50d902SRodney W. Grimes continue; 2149b50d902SRodney W. Grimes case TAB: /* adjust column */ 2159b50d902SRodney W. Grimes cur_col |= 7; 2169b50d902SRodney W. Grimes ++cur_col; 2179b50d902SRodney W. Grimes continue; 2189b50d902SRodney W. Grimes case VT: 2199b50d902SRodney W. Grimes cur_line -= 2; 2209b50d902SRodney W. Grimes continue; 2219b50d902SRodney W. Grimes } 2229b50d902SRodney W. Grimes continue; 2239b50d902SRodney W. Grimes } 2249b50d902SRodney W. Grimes 2259b50d902SRodney W. Grimes /* Must stuff ch in a line - are we at the right one? */ 2269b50d902SRodney W. Grimes if (cur_line != this_line - adjust) { 2279b50d902SRodney W. Grimes LINE *lnew; 2289b50d902SRodney W. Grimes int nmove; 2299b50d902SRodney W. Grimes 2309b50d902SRodney W. Grimes adjust = 0; 2319b50d902SRodney W. Grimes nmove = cur_line - this_line; 2329b50d902SRodney W. Grimes if (!fine) { 2339b50d902SRodney W. Grimes /* round up to next line */ 2349b50d902SRodney W. Grimes if (cur_line & 1) { 2359b50d902SRodney W. Grimes adjust = 1; 2369b50d902SRodney W. Grimes nmove++; 2379b50d902SRodney W. Grimes } 2389b50d902SRodney W. Grimes } 2399b50d902SRodney W. Grimes if (nmove < 0) { 2409b50d902SRodney W. Grimes for (; nmove < 0 && l->l_prev; nmove++) 2419b50d902SRodney W. Grimes l = l->l_prev; 2429b50d902SRodney W. Grimes if (nmove) { 2439b50d902SRodney W. Grimes if (nflushd_lines == 0) { 2449b50d902SRodney W. Grimes /* 2459b50d902SRodney W. Grimes * Allow backup past first 2469b50d902SRodney W. Grimes * line if nothing has been 2479b50d902SRodney W. Grimes * flushed yet. 2489b50d902SRodney W. Grimes */ 2499b50d902SRodney W. Grimes for (; nmove < 0; nmove++) { 2509b50d902SRodney W. Grimes lnew = alloc_line(); 2519b50d902SRodney W. Grimes l->l_prev = lnew; 2529b50d902SRodney W. Grimes lnew->l_next = l; 2539b50d902SRodney W. Grimes l = lines = lnew; 2549b50d902SRodney W. Grimes extra_lines++; 2559b50d902SRodney W. Grimes } 2569b50d902SRodney W. Grimes } else { 2579b50d902SRodney W. Grimes if (!warned++) 2589b50d902SRodney W. Grimes dowarn(cur_line); 2599b50d902SRodney W. Grimes cur_line -= nmove; 2609b50d902SRodney W. Grimes } 2619b50d902SRodney W. Grimes } 2629b50d902SRodney W. Grimes } else { 2639b50d902SRodney W. Grimes /* may need to allocate here */ 2649b50d902SRodney W. Grimes for (; nmove > 0 && l->l_next; nmove--) 2659b50d902SRodney W. Grimes l = l->l_next; 2669b50d902SRodney W. Grimes for (; nmove > 0; nmove--) { 2679b50d902SRodney W. Grimes lnew = alloc_line(); 2689b50d902SRodney W. Grimes lnew->l_prev = l; 2699b50d902SRodney W. Grimes l->l_next = lnew; 2709b50d902SRodney W. Grimes l = lnew; 2719b50d902SRodney W. Grimes } 2729b50d902SRodney W. Grimes } 2739b50d902SRodney W. Grimes this_line = cur_line + adjust; 2749b50d902SRodney W. Grimes nmove = this_line - nflushd_lines; 2759b50d902SRodney W. Grimes if (nmove >= max_bufd_lines + BUFFER_MARGIN) { 2769b50d902SRodney W. Grimes nflushd_lines += nmove - max_bufd_lines; 2779b50d902SRodney W. Grimes flush_lines(nmove - max_bufd_lines); 2789b50d902SRodney W. Grimes } 2799b50d902SRodney W. Grimes } 2809b50d902SRodney W. Grimes /* grow line's buffer? */ 2819b50d902SRodney W. Grimes if (l->l_line_len + 1 >= l->l_lsize) { 2829b50d902SRodney W. Grimes int need; 2839b50d902SRodney W. Grimes 2849b50d902SRodney W. Grimes need = l->l_lsize ? l->l_lsize * 2 : 90; 2859b50d902SRodney W. Grimes l->l_line = (CHAR *)xmalloc((void *) l->l_line, 2869b50d902SRodney W. Grimes (unsigned) need * sizeof(CHAR)); 2879b50d902SRodney W. Grimes l->l_lsize = need; 2889b50d902SRodney W. Grimes } 2899b50d902SRodney W. Grimes c = &l->l_line[l->l_line_len++]; 2909b50d902SRodney W. Grimes c->c_char = ch; 2919b50d902SRodney W. Grimes c->c_set = cur_set; 2929b50d902SRodney W. Grimes c->c_column = cur_col; 2939b50d902SRodney W. Grimes /* 2949b50d902SRodney W. Grimes * If things are put in out of order, they will need sorting 2959b50d902SRodney W. Grimes * when it is flushed. 2969b50d902SRodney W. Grimes */ 2979b50d902SRodney W. Grimes if (cur_col < l->l_max_col) 2989b50d902SRodney W. Grimes l->l_needs_sort = 1; 2999b50d902SRodney W. Grimes else 3009b50d902SRodney W. Grimes l->l_max_col = cur_col; 3019b50d902SRodney W. Grimes cur_col++; 3029b50d902SRodney W. Grimes } 303df3f5d9dSPeter Wemm if (max_line == 0) 304df3f5d9dSPeter Wemm exit(0); /* no lines, so just exit */ 305df3f5d9dSPeter Wemm 3069b50d902SRodney W. Grimes /* goto the last line that had a character on it */ 3079b50d902SRodney W. Grimes for (; l->l_next; l = l->l_next) 3089b50d902SRodney W. Grimes this_line++; 3099b50d902SRodney W. Grimes flush_lines(this_line - nflushd_lines + extra_lines + 1); 3109b50d902SRodney W. Grimes 3119b50d902SRodney W. Grimes /* make sure we leave things in a sane state */ 3129b50d902SRodney W. Grimes if (last_set != CS_NORMAL) 3139b50d902SRodney W. Grimes PUTC('\017'); 3149b50d902SRodney W. Grimes 3159b50d902SRodney W. Grimes /* flush out the last few blank lines */ 3169b50d902SRodney W. Grimes nblank_lines = max_line - this_line; 3179b50d902SRodney W. Grimes if (max_line & 1) 3189b50d902SRodney W. Grimes nblank_lines++; 3199b50d902SRodney W. Grimes else if (!nblank_lines) 3209b50d902SRodney W. Grimes /* missing a \n on the last line? */ 3219b50d902SRodney W. Grimes nblank_lines = 2; 3229b50d902SRodney W. Grimes flush_blanks(); 3239b50d902SRodney W. Grimes exit(0); 3249b50d902SRodney W. Grimes } 3259b50d902SRodney W. Grimes 3269b50d902SRodney W. Grimes void 3279b50d902SRodney W. Grimes flush_lines(nflush) 3289b50d902SRodney W. Grimes int nflush; 3299b50d902SRodney W. Grimes { 3309b50d902SRodney W. Grimes LINE *l; 3319b50d902SRodney W. Grimes 3329b50d902SRodney W. Grimes while (--nflush >= 0) { 3339b50d902SRodney W. Grimes l = lines; 3349b50d902SRodney W. Grimes lines = l->l_next; 3359b50d902SRodney W. Grimes if (l->l_line) { 3369b50d902SRodney W. Grimes flush_blanks(); 3379b50d902SRodney W. Grimes flush_line(l); 3389b50d902SRodney W. Grimes } 3399b50d902SRodney W. Grimes nblank_lines++; 3409b50d902SRodney W. Grimes if (l->l_line) 3419b50d902SRodney W. Grimes (void)free((void *)l->l_line); 3429b50d902SRodney W. Grimes free_line(l); 3439b50d902SRodney W. Grimes } 3449b50d902SRodney W. Grimes if (lines) 3459b50d902SRodney W. Grimes lines->l_prev = NULL; 3469b50d902SRodney W. Grimes } 3479b50d902SRodney W. Grimes 3489b50d902SRodney W. Grimes /* 3499b50d902SRodney W. Grimes * Print a number of newline/half newlines. If fine flag is set, nblank_lines 3509b50d902SRodney W. Grimes * is the number of half line feeds, otherwise it is the number of whole line 3519b50d902SRodney W. Grimes * feeds. 3529b50d902SRodney W. Grimes */ 3539b50d902SRodney W. Grimes void 3549b50d902SRodney W. Grimes flush_blanks() 3559b50d902SRodney W. Grimes { 3569b50d902SRodney W. Grimes int half, i, nb; 3579b50d902SRodney W. Grimes 3589b50d902SRodney W. Grimes half = 0; 3599b50d902SRodney W. Grimes nb = nblank_lines; 3609b50d902SRodney W. Grimes if (nb & 1) { 3619b50d902SRodney W. Grimes if (fine) 3629b50d902SRodney W. Grimes half = 1; 3639b50d902SRodney W. Grimes else 3649b50d902SRodney W. Grimes nb++; 3659b50d902SRodney W. Grimes } 3669b50d902SRodney W. Grimes nb /= 2; 3679b50d902SRodney W. Grimes for (i = nb; --i >= 0;) 3689b50d902SRodney W. Grimes PUTC('\n'); 3699b50d902SRodney W. Grimes if (half) { 3709b50d902SRodney W. Grimes PUTC('\033'); 3719b50d902SRodney W. Grimes PUTC('9'); 3729b50d902SRodney W. Grimes if (!nb) 3739b50d902SRodney W. Grimes PUTC('\r'); 3749b50d902SRodney W. Grimes } 3759b50d902SRodney W. Grimes nblank_lines = 0; 3769b50d902SRodney W. Grimes } 3779b50d902SRodney W. Grimes 3789b50d902SRodney W. Grimes /* 3799b50d902SRodney W. Grimes * Write a line to stdout taking care of space to tab conversion (-h flag) 3809b50d902SRodney W. Grimes * and character set shifts. 3819b50d902SRodney W. Grimes */ 3829b50d902SRodney W. Grimes void 3839b50d902SRodney W. Grimes flush_line(l) 3849b50d902SRodney W. Grimes LINE *l; 3859b50d902SRodney W. Grimes { 3869b50d902SRodney W. Grimes CHAR *c, *endc; 3879b50d902SRodney W. Grimes int nchars, last_col, this_col; 3889b50d902SRodney W. Grimes 3899b50d902SRodney W. Grimes last_col = 0; 3909b50d902SRodney W. Grimes nchars = l->l_line_len; 3919b50d902SRodney W. Grimes 3929b50d902SRodney W. Grimes if (l->l_needs_sort) { 3939b50d902SRodney W. Grimes static CHAR *sorted; 3949b50d902SRodney W. Grimes static int count_size, *count, i, save, sorted_size, tot; 3959b50d902SRodney W. Grimes 3969b50d902SRodney W. Grimes /* 3979b50d902SRodney W. Grimes * Do an O(n) sort on l->l_line by column being careful to 3989b50d902SRodney W. Grimes * preserve the order of characters in the same column. 3999b50d902SRodney W. Grimes */ 4009b50d902SRodney W. Grimes if (l->l_lsize > sorted_size) { 4019b50d902SRodney W. Grimes sorted_size = l->l_lsize; 4029b50d902SRodney W. Grimes sorted = (CHAR *)xmalloc((void *)sorted, 4039b50d902SRodney W. Grimes (unsigned)sizeof(CHAR) * sorted_size); 4049b50d902SRodney W. Grimes } 4059b50d902SRodney W. Grimes if (l->l_max_col >= count_size) { 4069b50d902SRodney W. Grimes count_size = l->l_max_col + 1; 4079b50d902SRodney W. Grimes count = (int *)xmalloc((void *)count, 4089b50d902SRodney W. Grimes (unsigned)sizeof(int) * count_size); 4099b50d902SRodney W. Grimes } 4109b50d902SRodney W. Grimes memset((char *)count, 0, sizeof(int) * l->l_max_col + 1); 4119b50d902SRodney W. Grimes for (i = nchars, c = l->l_line; --i >= 0; c++) 4129b50d902SRodney W. Grimes count[c->c_column]++; 4139b50d902SRodney W. Grimes 4149b50d902SRodney W. Grimes /* 4159b50d902SRodney W. Grimes * calculate running total (shifted down by 1) to use as 4169b50d902SRodney W. Grimes * indices into new line. 4179b50d902SRodney W. Grimes */ 4189b50d902SRodney W. Grimes for (tot = 0, i = 0; i <= l->l_max_col; i++) { 4199b50d902SRodney W. Grimes save = count[i]; 4209b50d902SRodney W. Grimes count[i] = tot; 4219b50d902SRodney W. Grimes tot += save; 4229b50d902SRodney W. Grimes } 4239b50d902SRodney W. Grimes 4249b50d902SRodney W. Grimes for (i = nchars, c = l->l_line; --i >= 0; c++) 4259b50d902SRodney W. Grimes sorted[count[c->c_column]++] = *c; 4269b50d902SRodney W. Grimes c = sorted; 4279b50d902SRodney W. Grimes } else 4289b50d902SRodney W. Grimes c = l->l_line; 4299b50d902SRodney W. Grimes while (nchars > 0) { 4309b50d902SRodney W. Grimes this_col = c->c_column; 4319b50d902SRodney W. Grimes endc = c; 4329b50d902SRodney W. Grimes do { 4339b50d902SRodney W. Grimes ++endc; 4349b50d902SRodney W. Grimes } while (--nchars > 0 && this_col == endc->c_column); 4359b50d902SRodney W. Grimes 4369b50d902SRodney W. Grimes /* if -b only print last character */ 4379b50d902SRodney W. Grimes if (no_backspaces) 4389b50d902SRodney W. Grimes c = endc - 1; 4399b50d902SRodney W. Grimes 4409b50d902SRodney W. Grimes if (this_col > last_col) { 4419b50d902SRodney W. Grimes int nspace = this_col - last_col; 4429b50d902SRodney W. Grimes 4439b50d902SRodney W. Grimes if (compress_spaces && nspace > 1) { 444f746e67cSBruce Evans while (1) { 445f746e67cSBruce Evans int tab_col, tab_size;; 4469b50d902SRodney W. Grimes 447f746e67cSBruce Evans tab_col = (last_col + 8) & ~7; 448f746e67cSBruce Evans if (tab_col > this_col) 449f746e67cSBruce Evans break; 450f746e67cSBruce Evans tab_size = tab_col - last_col; 451f746e67cSBruce Evans if (tab_size == 1) 452f746e67cSBruce Evans PUTC(' '); 453f746e67cSBruce Evans else 4549b50d902SRodney W. Grimes PUTC('\t'); 455f746e67cSBruce Evans nspace -= tab_size; 456f746e67cSBruce Evans last_col = tab_col; 457f746e67cSBruce Evans } 4589b50d902SRodney W. Grimes } 4599b50d902SRodney W. Grimes while (--nspace >= 0) 4609b50d902SRodney W. Grimes PUTC(' '); 4619b50d902SRodney W. Grimes last_col = this_col; 4629b50d902SRodney W. Grimes } 4639b50d902SRodney W. Grimes last_col++; 4649b50d902SRodney W. Grimes 4659b50d902SRodney W. Grimes for (;;) { 4669b50d902SRodney W. Grimes if (c->c_set != last_set) { 4679b50d902SRodney W. Grimes switch (c->c_set) { 4689b50d902SRodney W. Grimes case CS_NORMAL: 4699b50d902SRodney W. Grimes PUTC('\017'); 4709b50d902SRodney W. Grimes break; 4719b50d902SRodney W. Grimes case CS_ALTERNATE: 4729b50d902SRodney W. Grimes PUTC('\016'); 4739b50d902SRodney W. Grimes } 4749b50d902SRodney W. Grimes last_set = c->c_set; 4759b50d902SRodney W. Grimes } 4769b50d902SRodney W. Grimes PUTC(c->c_char); 4779b50d902SRodney W. Grimes if (++c >= endc) 4789b50d902SRodney W. Grimes break; 4799b50d902SRodney W. Grimes PUTC('\b'); 4809b50d902SRodney W. Grimes } 4819b50d902SRodney W. Grimes } 4829b50d902SRodney W. Grimes } 4839b50d902SRodney W. Grimes 4849b50d902SRodney W. Grimes #define NALLOC 64 4859b50d902SRodney W. Grimes 4869b50d902SRodney W. Grimes static LINE *line_freelist; 4879b50d902SRodney W. Grimes 4889b50d902SRodney W. Grimes LINE * 4899b50d902SRodney W. Grimes alloc_line() 4909b50d902SRodney W. Grimes { 4919b50d902SRodney W. Grimes LINE *l; 4929b50d902SRodney W. Grimes int i; 4939b50d902SRodney W. Grimes 4949b50d902SRodney W. Grimes if (!line_freelist) { 4959b50d902SRodney W. Grimes l = (LINE *)xmalloc((void *)NULL, sizeof(LINE) * NALLOC); 4969b50d902SRodney W. Grimes line_freelist = l; 4979b50d902SRodney W. Grimes for (i = 1; i < NALLOC; i++, l++) 4989b50d902SRodney W. Grimes l->l_next = l + 1; 4999b50d902SRodney W. Grimes l->l_next = NULL; 5009b50d902SRodney W. Grimes } 5019b50d902SRodney W. Grimes l = line_freelist; 5029b50d902SRodney W. Grimes line_freelist = l->l_next; 5039b50d902SRodney W. Grimes 5049b50d902SRodney W. Grimes memset(l, 0, sizeof(LINE)); 5059b50d902SRodney W. Grimes return (l); 5069b50d902SRodney W. Grimes } 5079b50d902SRodney W. Grimes 5089b50d902SRodney W. Grimes void 5099b50d902SRodney W. Grimes free_line(l) 5109b50d902SRodney W. Grimes LINE *l; 5119b50d902SRodney W. Grimes { 5129b50d902SRodney W. Grimes 5139b50d902SRodney W. Grimes l->l_next = line_freelist; 5149b50d902SRodney W. Grimes line_freelist = l; 5159b50d902SRodney W. Grimes } 5169b50d902SRodney W. Grimes 5179b50d902SRodney W. Grimes void * 5189b50d902SRodney W. Grimes xmalloc(p, size) 5199b50d902SRodney W. Grimes void *p; 5209b50d902SRodney W. Grimes size_t size; 5219b50d902SRodney W. Grimes { 5229b50d902SRodney W. Grimes 5239b50d902SRodney W. Grimes if (!(p = (void *)realloc(p, size))) 5249b50d902SRodney W. Grimes err(1, NULL); 5259b50d902SRodney W. Grimes return (p); 5269b50d902SRodney W. Grimes } 5279b50d902SRodney W. Grimes 5289b50d902SRodney W. Grimes void 5299b50d902SRodney W. Grimes usage() 5309b50d902SRodney W. Grimes { 5319b50d902SRodney W. Grimes 5329b50d902SRodney W. Grimes (void)fprintf(stderr, "usage: col [-bfx] [-l nline]\n"); 5339b50d902SRodney W. Grimes exit(1); 5349b50d902SRodney W. Grimes } 5359b50d902SRodney W. Grimes 5369b50d902SRodney W. Grimes void 5379b50d902SRodney W. Grimes wrerr() 5389b50d902SRodney W. Grimes { 5399b50d902SRodney W. Grimes 5409b50d902SRodney W. Grimes (void)fprintf(stderr, "col: write error.\n"); 5419b50d902SRodney W. Grimes exit(1); 5429b50d902SRodney W. Grimes } 5439b50d902SRodney W. Grimes 5449b50d902SRodney W. Grimes void 5459b50d902SRodney W. Grimes dowarn(line) 5469b50d902SRodney W. Grimes int line; 5479b50d902SRodney W. Grimes { 5489b50d902SRodney W. Grimes 5499b50d902SRodney W. Grimes warnx("warning: can't back up %s", 5509b50d902SRodney W. Grimes line < 0 ? "past first line" : "-- line already flushed"); 5519b50d902SRodney W. Grimes } 552