void flush_lines(int nflush) { LINE *l; while (--nflush >= 0) { l = lines; lines = l->l_next; if (l->l_line) { flush_blanks(); flush_line(l); } nblank_lines++; if (l->l_line) (void)free((void *)l->l_line); free_line(l); } if (lines) lines->l_prev = NULL; }
int main(int argc, char **argv) { wint_t ch; CHAR *c; CSET cur_set; /* current character set */ LINE *l; /* current line */ int extra_lines; /* # of lines above first line */ int cur_col; /* current column */ int cur_line; /* line number of current position */ int max_line; /* max value of cur_line */ int this_line; /* line l points to */ int nflushd_lines; /* number of lines that were flushed */ int adjust, opt, warned, width; (void)setlocale(LC_CTYPE, ""); max_bufd_lines = 128; compress_spaces = 1; /* compress spaces into tabs */ while ((opt = getopt(argc, argv, "bfhl:px")) != -1) switch (opt) { case 'b': /* do not output backspaces */ no_backspaces = 1; break; case 'f': /* allow half forward line feeds */ fine = 1; break; case 'h': /* compress spaces into tabs */ compress_spaces = 1; break; case 'l': /* buffered line count */ if ((max_bufd_lines = atoi(optarg)) <= 0) errx(1, "bad -l argument %s", optarg); break; case 'p': /* pass unknown control sequences */ pass_unknown_seqs = 1; break; case 'x': /* do not compress spaces into tabs */ compress_spaces = 0; break; case '?': default: usage(); } if (optind != argc) usage(); /* this value is in half lines */ max_bufd_lines *= 2; adjust = cur_col = extra_lines = warned = 0; cur_line = max_line = nflushd_lines = this_line = 0; cur_set = last_set = CS_NORMAL; lines = l = alloc_line(); while ((ch = getwchar()) != WEOF) { if (!iswgraph(ch)) { switch (ch) { case BS: /* can't go back further */ if (cur_col == 0) continue; --cur_col; continue; case CR: cur_col = 0; continue; case ESC: /* just ignore EOF */ switch(getwchar()) { case RLF: cur_line -= 2; break; case RHLF: cur_line--; break; case FHLF: cur_line++; if (cur_line > max_line) max_line = cur_line; } continue; case NL: cur_line += 2; if (cur_line > max_line) max_line = cur_line; cur_col = 0; continue; case SPACE: ++cur_col; continue; case SI: cur_set = CS_NORMAL; continue; case SO: cur_set = CS_ALTERNATE; continue; case TAB: /* adjust column */ cur_col |= 7; ++cur_col; continue; case VT: cur_line -= 2; continue; } if (iswspace(ch)) { if ((width = wcwidth(ch)) > 0) cur_col += width; continue; } if (!pass_unknown_seqs) continue; } /* Must stuff ch in a line - are we at the right one? */ if (cur_line != this_line - adjust) { LINE *lnew; int nmove; adjust = 0; nmove = cur_line - this_line; if (!fine) { /* round up to next line */ if (cur_line & 1) { adjust = 1; nmove++; } } if (nmove < 0) { for (; nmove < 0 && l->l_prev; nmove++) l = l->l_prev; if (nmove) { if (nflushd_lines == 0) { /* * Allow backup past first * line if nothing has been * flushed yet. */ for (; nmove < 0; nmove++) { lnew = alloc_line(); l->l_prev = lnew; lnew->l_next = l; l = lines = lnew; extra_lines++; } } else { if (!warned++) dowarn(cur_line); cur_line -= nmove; } } } else { /* may need to allocate here */ for (; nmove > 0 && l->l_next; nmove--) l = l->l_next; for (; nmove > 0; nmove--) { lnew = alloc_line(); lnew->l_prev = l; l->l_next = lnew; l = lnew; } } this_line = cur_line + adjust; nmove = this_line - nflushd_lines; if (nmove >= max_bufd_lines + BUFFER_MARGIN) { nflushd_lines += nmove - max_bufd_lines; flush_lines(nmove - max_bufd_lines); } } /* grow line's buffer? */ if (l->l_line_len + 1 >= l->l_lsize) { int need; need = l->l_lsize ? l->l_lsize * 2 : 90; if ((l->l_line = realloc(l->l_line, (unsigned)need * sizeof(CHAR))) == NULL) err(1, (char *)NULL); l->l_lsize = need; } c = &l->l_line[l->l_line_len++]; c->c_char = ch; c->c_set = cur_set; c->c_column = cur_col; c->c_width = wcwidth(ch); /* * If things are put in out of order, they will need sorting * when it is flushed. */ if (cur_col < l->l_max_col) l->l_needs_sort = 1; else l->l_max_col = cur_col; if (c->c_width > 0) cur_col += c->c_width; } if (ferror(stdin)) err(1, NULL); if (max_line == 0) exit(0); /* no lines, so just exit */ /* goto the last line that had a character on it */ for (; l->l_next; l = l->l_next) this_line++; flush_lines(this_line - nflushd_lines + extra_lines + 1); /* make sure we leave things in a sane state */ if (last_set != CS_NORMAL) PUTC('\017'); /* flush out the last few blank lines */ nblank_lines = max_line - this_line; if (max_line & 1) nblank_lines++; else if (!nblank_lines) /* missing a \n on the last line? */ nblank_lines = 2; flush_blanks(); exit(0); }