xref: /minix3/bin/ed/io.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: io.c,v 1.10 2014/03/23 05:06:42 dholland Exp $	*/
27e81b07cSAndy Kosela 
37e81b07cSAndy Kosela /* io.c: This file contains the i/o routines for the ed line editor */
47e81b07cSAndy Kosela /*-
57e81b07cSAndy Kosela  * Copyright (c) 1993 Andrew Moore, Talke Studio.
67e81b07cSAndy Kosela  * All rights reserved.
77e81b07cSAndy Kosela  *
87e81b07cSAndy Kosela  * Redistribution and use in source and binary forms, with or without
97e81b07cSAndy Kosela  * modification, are permitted provided that the following conditions
107e81b07cSAndy Kosela  * are met:
117e81b07cSAndy Kosela  * 1. Redistributions of source code must retain the above copyright
127e81b07cSAndy Kosela  *    notice, this list of conditions and the following disclaimer.
137e81b07cSAndy Kosela  * 2. Redistributions in binary form must reproduce the above copyright
147e81b07cSAndy Kosela  *    notice, this list of conditions and the following disclaimer in the
157e81b07cSAndy Kosela  *    documentation and/or other materials provided with the distribution.
167e81b07cSAndy Kosela  *
177e81b07cSAndy Kosela  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
187e81b07cSAndy Kosela  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
197e81b07cSAndy Kosela  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
207e81b07cSAndy Kosela  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
217e81b07cSAndy Kosela  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
227e81b07cSAndy Kosela  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
237e81b07cSAndy Kosela  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
247e81b07cSAndy Kosela  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
257e81b07cSAndy Kosela  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
267e81b07cSAndy Kosela  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
277e81b07cSAndy Kosela  * SUCH DAMAGE.
287e81b07cSAndy Kosela  */
297e81b07cSAndy Kosela 
307e81b07cSAndy Kosela #include <sys/cdefs.h>
317e81b07cSAndy Kosela #ifndef lint
327e81b07cSAndy Kosela #if 0
337e81b07cSAndy Kosela static char *rcsid = "@(#)io.c,v 1.1 1994/02/01 00:34:41 alm Exp";
347e81b07cSAndy Kosela #else
35*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: io.c,v 1.10 2014/03/23 05:06:42 dholland Exp $");
367e81b07cSAndy Kosela #endif
377e81b07cSAndy Kosela #endif /* not lint */
387e81b07cSAndy Kosela 
397e81b07cSAndy Kosela #include "ed.h"
407e81b07cSAndy Kosela 
417e81b07cSAndy Kosela 
427e81b07cSAndy Kosela /* read_file: read a named file/pipe into the buffer; return line count */
437e81b07cSAndy Kosela long
read_file(char * fn,long n)447e81b07cSAndy Kosela read_file(char *fn, long n)
457e81b07cSAndy Kosela {
467e81b07cSAndy Kosela 	FILE *fp;
477e81b07cSAndy Kosela 	long size;
487e81b07cSAndy Kosela 
497e81b07cSAndy Kosela 
507e81b07cSAndy Kosela 	fp = (*fn == '!') ? popen(fn + 1, "r") : fopen(strip_escapes(fn), "r");
517e81b07cSAndy Kosela 	if (fp == NULL) {
527e81b07cSAndy Kosela 		fprintf(stderr, "%s: %s\n", fn, strerror(errno));
53*0a6a1f1dSLionel Sambuc 		seterrmsg("cannot open input file");
547e81b07cSAndy Kosela 		return ERR;
557e81b07cSAndy Kosela 	} else if ((size = read_stream(fp, n)) < 0)
567e81b07cSAndy Kosela 		return ERR;
577e81b07cSAndy Kosela 	 else if (((*fn == '!') ?  pclose(fp) : fclose(fp)) < 0) {
587e81b07cSAndy Kosela 		fprintf(stderr, "%s: %s\n", fn, strerror(errno));
59*0a6a1f1dSLionel Sambuc 		seterrmsg("cannot close input file");
607e81b07cSAndy Kosela 		return ERR;
617e81b07cSAndy Kosela 	}
627e81b07cSAndy Kosela 	if (!scripted)
637e81b07cSAndy Kosela 		fprintf(stderr, "%lu\n", size);
647e81b07cSAndy Kosela 	return current_addr - n;
657e81b07cSAndy Kosela }
667e81b07cSAndy Kosela 
677e81b07cSAndy Kosela 
687e81b07cSAndy Kosela char *sbuf;			/* file i/o buffer */
697e81b07cSAndy Kosela int sbufsz;			/* file i/o buffer size */
707e81b07cSAndy Kosela int newline_added;		/* if set, newline appended to input file */
717e81b07cSAndy Kosela 
727e81b07cSAndy Kosela /* read_stream: read a stream into the editor buffer; return status */
737e81b07cSAndy Kosela long
read_stream(FILE * fp,long n)747e81b07cSAndy Kosela read_stream(FILE *fp, long n)
757e81b07cSAndy Kosela {
767e81b07cSAndy Kosela 	line_t *lp = get_addressed_line_node(n);
777e81b07cSAndy Kosela 	undo_t *up = NULL;
787e81b07cSAndy Kosela 	unsigned long size = 0;
797e81b07cSAndy Kosela 	int o_newline_added = newline_added;
807e81b07cSAndy Kosela 	int o_isbinary = isbinary;
817e81b07cSAndy Kosela 	int appended = (n == addr_last);
827e81b07cSAndy Kosela 	int len;
837e81b07cSAndy Kosela 
847e81b07cSAndy Kosela 	isbinary = newline_added = 0;
857e81b07cSAndy Kosela 	if (des)
867e81b07cSAndy Kosela 		init_des_cipher();
877e81b07cSAndy Kosela 	for (current_addr = n; (len = get_stream_line(fp)) > 0; size += len) {
887e81b07cSAndy Kosela 		SPL1();
897e81b07cSAndy Kosela 		if (put_sbuf_line(sbuf) == NULL) {
907e81b07cSAndy Kosela 			SPL0();
917e81b07cSAndy Kosela 			return ERR;
927e81b07cSAndy Kosela 		}
937e81b07cSAndy Kosela 		lp = lp->q_forw;
947e81b07cSAndy Kosela 		if (up)
957e81b07cSAndy Kosela 			up->t = lp;
967e81b07cSAndy Kosela 		else if ((up = push_undo_stack(UADD, current_addr,
977e81b07cSAndy Kosela 		    current_addr)) == NULL) {
987e81b07cSAndy Kosela 			SPL0();
997e81b07cSAndy Kosela 			return ERR;
1007e81b07cSAndy Kosela 		}
1017e81b07cSAndy Kosela 		SPL0();
1027e81b07cSAndy Kosela 	}
1037e81b07cSAndy Kosela 	if (len < 0)
1047e81b07cSAndy Kosela 		return ERR;
1057e81b07cSAndy Kosela 	if (appended && size && o_isbinary && o_newline_added)
1067e81b07cSAndy Kosela 		fputs("newline inserted\n", stderr);
1077e81b07cSAndy Kosela 	else if (newline_added && (!appended || (!isbinary && !o_isbinary)))
1087e81b07cSAndy Kosela 		fputs("newline appended\n", stderr);
1097e81b07cSAndy Kosela 	if (isbinary && newline_added && !appended)
1107e81b07cSAndy Kosela 	    	size += 1;
1117e81b07cSAndy Kosela 	if (!size)
1127e81b07cSAndy Kosela 		newline_added = 1;
1137e81b07cSAndy Kosela 	newline_added = appended ? newline_added : o_newline_added;
1147e81b07cSAndy Kosela 	isbinary = isbinary | o_isbinary;
1157e81b07cSAndy Kosela 	if (des)
1167e81b07cSAndy Kosela 		size += 8 - size % 8;			/* adjust DES size */
1177e81b07cSAndy Kosela 	return size;
1187e81b07cSAndy Kosela }
1197e81b07cSAndy Kosela 
1207e81b07cSAndy Kosela 
1217e81b07cSAndy Kosela /* get_stream_line: read a line of text from a stream; return line length */
1227e81b07cSAndy Kosela int
get_stream_line(FILE * fp)1237e81b07cSAndy Kosela get_stream_line(FILE *fp)
1247e81b07cSAndy Kosela {
1257e81b07cSAndy Kosela 	int c;
1267e81b07cSAndy Kosela 	int i = 0;
1277e81b07cSAndy Kosela 
1287e81b07cSAndy Kosela 	while (((c = des ? get_des_char(fp) : getc(fp)) != EOF || (!feof(fp) &&
1297e81b07cSAndy Kosela 	    !ferror(fp))) && c != '\n') {
1307e81b07cSAndy Kosela 		REALLOC(sbuf, sbufsz, i + 1, ERR);
1317e81b07cSAndy Kosela 		if (!(sbuf[i++] = c))
1327e81b07cSAndy Kosela 			isbinary = 1;
1337e81b07cSAndy Kosela 	}
1347e81b07cSAndy Kosela 	REALLOC(sbuf, sbufsz, i + 2, ERR);
1357e81b07cSAndy Kosela 	if (c == '\n')
1367e81b07cSAndy Kosela 		sbuf[i++] = c;
1377e81b07cSAndy Kosela 	else if (ferror(fp)) {
1387e81b07cSAndy Kosela 		fprintf(stderr, "%s\n", strerror(errno));
139*0a6a1f1dSLionel Sambuc 		seterrmsg("cannot read input file");
1407e81b07cSAndy Kosela 		return ERR;
1417e81b07cSAndy Kosela 	} else if (i) {
1427e81b07cSAndy Kosela 		sbuf[i++] = '\n';
1437e81b07cSAndy Kosela 		newline_added = 1;
1447e81b07cSAndy Kosela 	}
1457e81b07cSAndy Kosela 	sbuf[i] = '\0';
1467e81b07cSAndy Kosela 	return (isbinary && newline_added && i) ? --i : i;
1477e81b07cSAndy Kosela }
1487e81b07cSAndy Kosela 
1497e81b07cSAndy Kosela 
1507e81b07cSAndy Kosela /* write_file: write a range of lines to a named file/pipe; return line count */
1517e81b07cSAndy Kosela long
write_file(const char * fn,const char * mode,long n,long m)1527e81b07cSAndy Kosela write_file(const char *fn, const char *mode, long n, long m)
1537e81b07cSAndy Kosela {
1547e81b07cSAndy Kosela 	FILE *fp;
1557e81b07cSAndy Kosela 	long size;
1567e81b07cSAndy Kosela 
1577e81b07cSAndy Kosela 	fp = (*fn == '!') ? popen(fn+1, "w") : fopen(strip_escapes(fn), mode);
1587e81b07cSAndy Kosela 	if (fp == NULL) {
1597e81b07cSAndy Kosela 		fprintf(stderr, "%s: %s\n", fn, strerror(errno));
160*0a6a1f1dSLionel Sambuc 		seterrmsg("cannot open output file");
1617e81b07cSAndy Kosela 		return ERR;
1627e81b07cSAndy Kosela 	} else if ((size = write_stream(fp, n, m)) < 0)
1637e81b07cSAndy Kosela 		return ERR;
1647e81b07cSAndy Kosela 	 else if (((*fn == '!') ?  pclose(fp) : fclose(fp)) < 0) {
1657e81b07cSAndy Kosela 		fprintf(stderr, "%s: %s\n", fn, strerror(errno));
166*0a6a1f1dSLionel Sambuc 		seterrmsg("cannot close output file");
1677e81b07cSAndy Kosela 		return ERR;
1687e81b07cSAndy Kosela 	}
1697e81b07cSAndy Kosela 	if (!scripted)
1707e81b07cSAndy Kosela 		fprintf(stderr, "%lu\n", size);
1717e81b07cSAndy Kosela 	return n ? m - n + 1 : 0;
1727e81b07cSAndy Kosela }
1737e81b07cSAndy Kosela 
1747e81b07cSAndy Kosela 
1757e81b07cSAndy Kosela /* write_stream: write a range of lines to a stream; return status */
1767e81b07cSAndy Kosela long
write_stream(FILE * fp,long n,long m)1777e81b07cSAndy Kosela write_stream(FILE *fp, long n, long m)
1787e81b07cSAndy Kosela {
1797e81b07cSAndy Kosela 	line_t *lp = get_addressed_line_node(n);
1807e81b07cSAndy Kosela 	unsigned long size = 0;
1817e81b07cSAndy Kosela 	char *s;
1827e81b07cSAndy Kosela 	int len;
1837e81b07cSAndy Kosela 
1847e81b07cSAndy Kosela 	if (des)
1857e81b07cSAndy Kosela 		init_des_cipher();
1867e81b07cSAndy Kosela 	for (; n && n <= m; n++, lp = lp->q_forw) {
1877e81b07cSAndy Kosela 		if ((s = get_sbuf_line(lp)) == NULL)
1887e81b07cSAndy Kosela 			return ERR;
1897e81b07cSAndy Kosela 		len = lp->len;
1907e81b07cSAndy Kosela 		if (n != addr_last || !isbinary || !newline_added)
1917e81b07cSAndy Kosela 			s[len++] = '\n';
1927e81b07cSAndy Kosela 		if (put_stream_line(fp, s, len) < 0)
1937e81b07cSAndy Kosela 			return ERR;
1947e81b07cSAndy Kosela 		size += len;
1957e81b07cSAndy Kosela 	}
1967e81b07cSAndy Kosela 	if (des) {
1977e81b07cSAndy Kosela 		flush_des_file(fp);			/* flush buffer */
1987e81b07cSAndy Kosela 		size += 8 - size % 8;			/* adjust DES size */
1997e81b07cSAndy Kosela 	}
2007e81b07cSAndy Kosela 	return size;
2017e81b07cSAndy Kosela }
2027e81b07cSAndy Kosela 
2037e81b07cSAndy Kosela 
2047e81b07cSAndy Kosela /* put_stream_line: write a line of text to a stream; return status */
2057e81b07cSAndy Kosela int
put_stream_line(FILE * fp,char * s,int len)2067e81b07cSAndy Kosela put_stream_line(FILE *fp, char *s, int len)
2077e81b07cSAndy Kosela {
2087e81b07cSAndy Kosela 	while (len--)
2097e81b07cSAndy Kosela 		if ((des ? put_des_char(*s++, fp) : fputc(*s++, fp)) < 0) {
2107e81b07cSAndy Kosela 			fprintf(stderr, "%s\n", strerror(errno));
211*0a6a1f1dSLionel Sambuc 			seterrmsg("cannot write file");
2127e81b07cSAndy Kosela 			return ERR;
2137e81b07cSAndy Kosela 		}
2147e81b07cSAndy Kosela 	return 0;
2157e81b07cSAndy Kosela }
2167e81b07cSAndy Kosela 
2177e81b07cSAndy Kosela /* get_extended_line: get a an extended line from stdin */
2187e81b07cSAndy Kosela char *
get_extended_line(int * sizep,int nonl)2197e81b07cSAndy Kosela get_extended_line(int *sizep, int nonl)
2207e81b07cSAndy Kosela {
2217e81b07cSAndy Kosela 	static char *cvbuf = NULL;		/* buffer */
2227e81b07cSAndy Kosela 	static int cvbufsz = 0;			/* buffer size */
2237e81b07cSAndy Kosela 
2247e81b07cSAndy Kosela 	int l, n;
2257e81b07cSAndy Kosela 	char *t = ibufp;
2267e81b07cSAndy Kosela 
2277e81b07cSAndy Kosela 	while (*t++ != '\n')
2287e81b07cSAndy Kosela 		;
2297e81b07cSAndy Kosela 	if ((l = t - ibufp) < 2 || !has_trailing_escape(ibufp, ibufp + l - 1)) {
2307e81b07cSAndy Kosela 		*sizep = l;
2317e81b07cSAndy Kosela 		return ibufp;
2327e81b07cSAndy Kosela 	}
2337e81b07cSAndy Kosela 	*sizep = -1;
2347e81b07cSAndy Kosela 	REALLOC(cvbuf, cvbufsz, l, NULL);
2357e81b07cSAndy Kosela 	memcpy(cvbuf, ibufp, l);
2367e81b07cSAndy Kosela 	*(cvbuf + --l - 1) = '\n'; 	/* strip trailing esc */
2377e81b07cSAndy Kosela 	if (nonl) l--; 			/* strip newline */
2387e81b07cSAndy Kosela 	for (;;) {
2397e81b07cSAndy Kosela 		if ((n = get_tty_line()) < 0)
2407e81b07cSAndy Kosela 			return NULL;
2417e81b07cSAndy Kosela 		else if (n == 0 || ibuf[n - 1] != '\n') {
242*0a6a1f1dSLionel Sambuc 			seterrmsg("unexpected end-of-file");
2437e81b07cSAndy Kosela 			return NULL;
2447e81b07cSAndy Kosela 		}
2457e81b07cSAndy Kosela 		REALLOC(cvbuf, cvbufsz, l + n, NULL);
2467e81b07cSAndy Kosela 		memcpy(cvbuf + l, ibuf, n);
2477e81b07cSAndy Kosela 		l += n;
2487e81b07cSAndy Kosela 		if (n < 2 || !has_trailing_escape(cvbuf, cvbuf + l - 1))
2497e81b07cSAndy Kosela 			break;
2507e81b07cSAndy Kosela 		*(cvbuf + --l - 1) = '\n'; 	/* strip trailing esc */
2517e81b07cSAndy Kosela 		if (nonl) l--; 			/* strip newline */
2527e81b07cSAndy Kosela 	}
2537e81b07cSAndy Kosela 	REALLOC(cvbuf, cvbufsz, l + 1, NULL);
2547e81b07cSAndy Kosela 	cvbuf[l] = '\0';
2557e81b07cSAndy Kosela 	*sizep = l;
2567e81b07cSAndy Kosela 	return cvbuf;
2577e81b07cSAndy Kosela }
2587e81b07cSAndy Kosela 
2597e81b07cSAndy Kosela 
2607e81b07cSAndy Kosela /* get_tty_line: read a line of text from stdin; return line length */
2617e81b07cSAndy Kosela int
get_tty_line(void)2627e81b07cSAndy Kosela get_tty_line(void)
2637e81b07cSAndy Kosela {
2647e81b07cSAndy Kosela 	int oi = 0;
2657e81b07cSAndy Kosela 	int i = 0;
2667e81b07cSAndy Kosela 	int c;
2677e81b07cSAndy Kosela 
2687e81b07cSAndy Kosela 	for (;;)
2697e81b07cSAndy Kosela 		switch (c = getchar()) {
2707e81b07cSAndy Kosela 		default:
2717e81b07cSAndy Kosela 			oi = 0;
2727e81b07cSAndy Kosela 			REALLOC(ibuf, ibufsz, i + 2, ERR);
2737e81b07cSAndy Kosela 			if (!(ibuf[i++] = c)) isbinary = 1;
2747e81b07cSAndy Kosela 			if (c != '\n')
2757e81b07cSAndy Kosela 				continue;
2767e81b07cSAndy Kosela 			lineno++;
2777e81b07cSAndy Kosela 			ibuf[i] = '\0';
2787e81b07cSAndy Kosela 			ibufp = ibuf;
2797e81b07cSAndy Kosela 			return i;
2807e81b07cSAndy Kosela 		case EOF:
2817e81b07cSAndy Kosela 			if (ferror(stdin)) {
2827e81b07cSAndy Kosela 				fprintf(stderr, "stdin: %s\n", strerror(errno));
283*0a6a1f1dSLionel Sambuc 				seterrmsg("cannot read stdin");
2847e81b07cSAndy Kosela 				clearerr(stdin);
2857e81b07cSAndy Kosela 				ibufp = NULL;
2867e81b07cSAndy Kosela 				return ERR;
2877e81b07cSAndy Kosela 			} else {
2887e81b07cSAndy Kosela 				clearerr(stdin);
2897e81b07cSAndy Kosela 				if (i != oi) {
2907e81b07cSAndy Kosela 					oi = i;
2917e81b07cSAndy Kosela 					continue;
2927e81b07cSAndy Kosela 				} else if (i)
2937e81b07cSAndy Kosela 					ibuf[i] = '\0';
2947e81b07cSAndy Kosela 				ibufp = ibuf;
2957e81b07cSAndy Kosela 				return i;
2967e81b07cSAndy Kosela 			}
2977e81b07cSAndy Kosela 		}
2987e81b07cSAndy Kosela }
2997e81b07cSAndy Kosela 
3007e81b07cSAndy Kosela 
3017e81b07cSAndy Kosela 
3027e81b07cSAndy Kosela #define ESCAPES "\a\b\f\n\r\t\v\\"
3037e81b07cSAndy Kosela #define ESCCHARS "abfnrtv\\"
3047e81b07cSAndy Kosela 
3057e81b07cSAndy Kosela /* put_tty_line: print text to stdout */
3067e81b07cSAndy Kosela int
put_tty_line(char * s,int l,long n,int gflag)3077e81b07cSAndy Kosela put_tty_line(char *s, int l, long n, int gflag)
3087e81b07cSAndy Kosela {
3097e81b07cSAndy Kosela 	int col = 0;
3107e81b07cSAndy Kosela 	char *cp;
3117e81b07cSAndy Kosela #ifndef BACKWARDS
3127e81b07cSAndy Kosela 	int lc = 0;
3137e81b07cSAndy Kosela #endif
3147e81b07cSAndy Kosela 
3157e81b07cSAndy Kosela 	if (gflag & GNP) {
3167e81b07cSAndy Kosela 		printf("%ld\t", n);
3177e81b07cSAndy Kosela 		col = 8;
3187e81b07cSAndy Kosela 	}
3197e81b07cSAndy Kosela 	for (; l--; s++) {
3207e81b07cSAndy Kosela 		if ((gflag & GLS) && ++col > cols) {
3217e81b07cSAndy Kosela 			fputs("\\\n", stdout);
3227e81b07cSAndy Kosela 			col = 1;
3237e81b07cSAndy Kosela #ifndef BACKWARDS
3247e81b07cSAndy Kosela 			if (!scripted && !isglobal && ++lc > rows) {
3257e81b07cSAndy Kosela 				lc = 0;
3267e81b07cSAndy Kosela 				fputs("Press <RETURN> to continue... ", stdout);
3277e81b07cSAndy Kosela 				fflush(stdout);
3287e81b07cSAndy Kosela 				if (get_tty_line() < 0)
3297e81b07cSAndy Kosela 					return ERR;
3307e81b07cSAndy Kosela 			}
3317e81b07cSAndy Kosela #endif
3327e81b07cSAndy Kosela 		}
3337e81b07cSAndy Kosela 		if (gflag & GLS) {
3347e81b07cSAndy Kosela 			if (31 < *s && *s < 127 && *s != '\\')
3357e81b07cSAndy Kosela 				putchar(*s);
3367e81b07cSAndy Kosela 			else {
3377e81b07cSAndy Kosela 				putchar('\\');
3387e81b07cSAndy Kosela 				col++;
3397e81b07cSAndy Kosela 				if (*s && (cp = strchr(ESCAPES, *s)) != NULL)
3407e81b07cSAndy Kosela 					putchar(ESCCHARS[cp - ESCAPES]);
3417e81b07cSAndy Kosela 				else {
3427e81b07cSAndy Kosela 					putchar((((unsigned char) *s & 0300) >> 6) + '0');
3437e81b07cSAndy Kosela 					putchar((((unsigned char) *s & 070) >> 3) + '0');
3447e81b07cSAndy Kosela 					putchar(((unsigned char) *s & 07) + '0');
3457e81b07cSAndy Kosela 					col += 2;
3467e81b07cSAndy Kosela 				}
3477e81b07cSAndy Kosela 			}
3487e81b07cSAndy Kosela 
3497e81b07cSAndy Kosela 		} else
3507e81b07cSAndy Kosela 			putchar(*s);
3517e81b07cSAndy Kosela 	}
3527e81b07cSAndy Kosela #ifndef BACKWARDS
3537e81b07cSAndy Kosela 	if (gflag & GLS)
3547e81b07cSAndy Kosela 		putchar('$');
3557e81b07cSAndy Kosela #endif
3567e81b07cSAndy Kosela 	putchar('\n');
3577e81b07cSAndy Kosela 	return 0;
3587e81b07cSAndy Kosela }
359