(root)/
util-linux-2.39/
text-utils/
colcrt.c
       1  /*
       2   * Copyright (C) 2016 Sami Kerola <kerolasa@iki.fi>
       3   * Copyright (C) 2016 Karel Zak <kzak@redhat.com>
       4   *
       5   * Copyright (c) 1980, 1993
       6   *	The Regents of the University of California.  All rights reserved.
       7   *
       8   * Redistribution and use in source and binary forms, with or without
       9   * modification, are permitted provided that the following conditions
      10   * are met:
      11   * 1. Redistributions of source code must retain the above copyright
      12   *    notice, this list of conditions and the following disclaimer.
      13   * 2. Redistributions in binary form must reproduce the above copyright
      14   *    notice, this list of conditions and the following disclaimer in the
      15   *    documentation and/or other materials provided with the distribution.
      16   * 3. All advertising materials mentioning features or use of this software
      17   *    must display the following acknowledgement:
      18   *	This product includes software developed by the University of
      19   *	California, Berkeley and its contributors.
      20   * 4. Neither the name of the University nor the names of its contributors
      21   *    may be used to endorse or promote products derived from this software
      22   *    without specific prior written permission.
      23   *
      24   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      25   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      26   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      27   * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      28   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      29   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      30   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      31   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      32   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      33   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      34   * SUCH DAMAGE.
      35   */
      36  
      37  /*
      38   * 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
      39   *	added Native Language Support
      40   * 1999-09-19 Bruno Haible <haible@clisp.cons.org>
      41   *	modified to work correctly in multi-byte locales
      42   */
      43  
      44  #include <stdio.h>
      45  #include <stdlib.h>
      46  #include <getopt.h>
      47  
      48  #include "nls.h"
      49  #include "c.h"
      50  #include "widechar.h"
      51  #include "closestream.h"
      52  
      53  /*
      54   * colcrt - replaces col for crts with new nroff esp. when using tbl.
      55   * Bill Joy UCB July 14, 1977
      56   *
      57   * This filter uses the up and down sequences generated by the new
      58   * nroff when used with tbl and by \u \d and \r.
      59   * General overstriking doesn't work correctly.
      60   * Underlining is split onto multiple lines, etc.
      61   *
      62   * Option - suppresses all underlining.
      63   * Option -2 forces printing of all half lines.
      64   */
      65  
      66  enum { OUTPUT_COLS = 132 };
      67  
      68  struct colcrt_control {
      69  	FILE		*f;
      70  	wchar_t		line[OUTPUT_COLS + 1];
      71  	wchar_t		line_under[OUTPUT_COLS + 1];
      72  	unsigned int	print_nl:1,
      73  			need_line_under:1,
      74  			no_underlining:1,
      75  			half_lines:1;
      76  };
      77  
      78  static void __attribute__((__noreturn__)) usage(void)
      79  {
      80  	FILE *out = stdout;
      81  	fputs(USAGE_HEADER, out);
      82  	fprintf(out, _(" %s [options] [<file>...]\n"), program_invocation_short_name);
      83  
      84  	fputs(USAGE_SEPARATOR, out);
      85  	fputs(_("Filter nroff output for CRT previewing.\n"), out);
      86  
      87  	fputs(USAGE_OPTIONS, out);
      88  	fputs(_(" -,  --no-underlining    suppress all underlining\n"), out);
      89  	fputs(_(" -2, --half-lines        print all half-lines\n"), out);
      90  
      91  	fputs(USAGE_SEPARATOR, out);
      92  	printf(USAGE_HELP_OPTIONS(25));
      93  
      94  	printf(USAGE_MAN_TAIL("colcrt(1)"));
      95  
      96  	exit(EXIT_SUCCESS);
      97  }
      98  
      99  static void trim_trailing_spaces(wchar_t *s)
     100  {
     101  	size_t size;
     102  	wchar_t *end;
     103  
     104  	size = wcslen(s);
     105  	if (!size)
     106  		return;
     107  	end = s + size - 1;
     108  	while (s <= end && iswspace(*end))
     109  		end--;
     110  	*(end + 1) = L'\0';
     111  }
     112  
     113  
     114  static void output_lines(struct colcrt_control *ctl, int col)
     115  {
     116  	/* first line */
     117  	trim_trailing_spaces(ctl->line);
     118  	fputws(ctl->line, stdout);
     119  
     120  	if (ctl->print_nl)
     121  		fputwc(L'\n', stdout);
     122  	if (!ctl->half_lines && !ctl->no_underlining)
     123  		ctl->print_nl = 0;
     124  
     125  	wmemset(ctl->line, L'\0', OUTPUT_COLS);
     126  
     127  	/* second line */
     128  	if (ctl->need_line_under) {
     129  		ctl->need_line_under = 0;
     130  		ctl->line_under[col] = L'\0';
     131  		trim_trailing_spaces(ctl->line_under);
     132  		fputws(ctl->line_under, stdout);
     133  		fputwc(L'\n', stdout);
     134  		wmemset(ctl->line_under, L' ', OUTPUT_COLS);
     135  
     136  	} else if (ctl->half_lines && 0 < col)
     137  		fputwc(L'\n', stdout);
     138  }
     139  
     140  static int rubchars(struct colcrt_control *ctl, int col, int n)
     141  {
     142  	while (0 < n && 0 < col) {
     143  		ctl->line[col] = L'\0';
     144  		ctl->line_under[col] = L' ';
     145  		n--;
     146  		col--;
     147  	}
     148  	return col;
     149  }
     150  
     151  static void colcrt(struct colcrt_control *ctl)
     152  {
     153  	int col;
     154  	wint_t c = 0;
     155  	long old_pos;
     156  
     157  	ctl->print_nl = 1;
     158  	if (ctl->half_lines)
     159  		fputwc(L'\n', stdout);
     160  
     161  	for (col = 0; /* nothing */; col++) {
     162  		if (OUTPUT_COLS - 1 < col) {
     163  			output_lines(ctl, col);
     164  			errno = 0;
     165  			old_pos = ftell(ctl->f);
     166  
     167  			while (getwc(ctl->f) != L'\n') {
     168  				long new_pos;
     169  
     170  				if (ferror(ctl->f) || feof(ctl->f))
     171  					return;
     172  				new_pos = ftell(ctl->f);
     173  				if (old_pos == new_pos) {
     174  					if (fseek(ctl->f, 1, SEEK_CUR) < 1)
     175  						return;
     176  				} else
     177  					old_pos = new_pos;
     178  			}
     179  			col = -1;
     180  			continue;
     181  		}
     182  		c = getwc(ctl->f);
     183  		switch (c) {
     184  		case 033:	/* ESC */
     185  			c = getwc(ctl->f);
     186  			if (c == L'8') {
     187  				col = rubchars(ctl, col, 1);
     188  				continue;
     189  			}
     190  			if (c == L'7') {
     191  				col = rubchars(ctl, col, 2);
     192  				continue;
     193  			}
     194  			continue;
     195  		case WEOF:
     196  			ctl->print_nl = 0;
     197  			output_lines(ctl, col);
     198  			return;
     199  		case L'\n':
     200  			output_lines(ctl, col);
     201  			col = -1;
     202  			continue;
     203  		case L'\t':
     204  			for (/* nothing */; col % 8 && col < OUTPUT_COLS; col++) {
     205  				ctl->line[col] = L' ';
     206  			}
     207  			col--;
     208  			continue;
     209  		case L'_':
     210  			ctl->line[col] = L' ';
     211  			if (!ctl->no_underlining) {
     212  				ctl->need_line_under = 1;
     213  				ctl->line_under[col] = L'-';
     214  			}
     215  			continue;
     216  		default:
     217  			if (!iswprint(c)) {
     218  				col--;
     219  				continue;
     220  			}
     221  			ctl->print_nl = 1;
     222  			ctl->line[col] = c;
     223  		}
     224  	}
     225  }
     226  
     227  int main(int argc, char **argv)
     228  {
     229  	struct colcrt_control ctl = { NULL };
     230  	int opt;
     231  	enum { NO_UL_OPTION = CHAR_MAX + 1 };
     232  
     233  	static const struct option longopts[] = {
     234  		{"no-underlining", no_argument, NULL, NO_UL_OPTION},
     235  		{"half-lines", no_argument, NULL, '2'},
     236  		{"version", no_argument, NULL, 'V'},
     237  		{"help", no_argument, NULL, 'h'},
     238  		{NULL, 0, NULL, 0}
     239  	};
     240  
     241  	setlocale(LC_ALL, "");
     242  	bindtextdomain(PACKAGE, LOCALEDIR);
     243  	textdomain(PACKAGE);
     244  	close_stdout_atexit();
     245  
     246  	/* Take care of lonely hyphen option. */
     247  	for (opt = 0; opt < argc; opt++) {
     248  		if (argv[opt][0] == '-' && argv[opt][1] == '\0') {
     249  			ctl.no_underlining = 1;
     250  			argc--;
     251  			memmove(argv + opt, argv + opt + 1,
     252  				sizeof(char *) * (argc - opt));
     253  			opt--;
     254  		}
     255  	}
     256  
     257  	while ((opt = getopt_long(argc, argv, "2Vh", longopts, NULL)) != -1) {
     258  		switch (opt) {
     259  		case NO_UL_OPTION:
     260  			ctl.no_underlining = 1;
     261  			break;
     262  		case '2':
     263  			ctl.half_lines = 1;
     264  			break;
     265  
     266  		case 'V':
     267  			print_version(EXIT_SUCCESS);
     268  		case 'h':
     269  			usage();
     270  		default:
     271  			errtryhelp(EXIT_FAILURE);
     272  		}
     273  	}
     274  
     275  	argc -= optind;
     276  	argv += optind;
     277  
     278  	do {
     279  		wmemset(ctl.line, L'\0', OUTPUT_COLS);
     280  		wmemset(ctl.line_under, L' ', OUTPUT_COLS);
     281  
     282  		if (argc > 0) {
     283  			if (!(ctl.f = fopen(*argv, "r")))
     284  				err(EXIT_FAILURE, _("cannot open %s"), *argv);
     285  			argc--;
     286  			argv++;
     287  		} else
     288  			ctl.f = stdin;
     289  
     290  		colcrt(&ctl);
     291  		if (ctl.f != stdin)
     292  			fclose(ctl.f);
     293  	} while (argc > 0);
     294  
     295  	return EXIT_SUCCESS;
     296  }