Deleted Added
full compact
io.c (22988) io.c (27963)
1/* io.c: This file contains the i/o routines for the ed line editor */
2/*-
3 * Copyright (c) 1993 Andrew Moore, Talke Studio.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
1/* io.c: This file contains the i/o routines for the ed line editor */
2/*-
3 * Copyright (c) 1993 Andrew Moore, Talke Studio.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $Id$
28 */
29
30#ifndef lint
26 */
27
28#ifndef lint
29#if 0
31static char * const rcsid = "@(#)io.c,v 1.1 1994/02/01 00:34:41 alm Exp";
30static char * const rcsid = "@(#)io.c,v 1.1 1994/02/01 00:34:41 alm Exp";
31#else
32static char * const rcsid =
33 "$Id: io.c,v 1.8 1997/02/22 14:03:16 peter Exp $";
34#endif
32#endif /* not lint */
33
34#include "ed.h"
35
36
37extern int scripted;
38
39/* read_file: read a named file/pipe into the buffer; return line count */
40long
41read_file(fn, n)
42 char *fn;
43 long n;
44{
45 FILE *fp;
46 long size;
47
48
49 fp = (*fn == '!') ? popen(fn + 1, "r") : fopen(strip_escapes(fn), "r");
50 if (fp == NULL) {
51 fprintf(stderr, "%s: %s\n", fn, strerror(errno));
52 sprintf(errmsg, "cannot open input file");
53 return ERR;
54 } else if ((size = read_stream(fp, n)) < 0)
55 return ERR;
56 else if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) {
57 fprintf(stderr, "%s: %s\n", fn, strerror(errno));
58 sprintf(errmsg, "cannot close input file");
59 return ERR;
60 }
61 fprintf(stdout, !scripted ? "%lu\n" : "", size);
62 return current_addr - n;
63}
64
65
66extern int des;
67
68char *sbuf; /* file i/o buffer */
69int sbufsz; /* file i/o buffer size */
70int newline_added; /* if set, newline appended to input file */
71
72/* read_stream: read a stream into the editor buffer; return status */
73long
74read_stream(fp, n)
75 FILE *fp;
76 long n;
77{
78 line_t *lp = get_addressed_line_node(n);
79 undo_t *up = NULL;
80 unsigned long size = 0;
81 int o_newline_added = newline_added;
82 int o_isbinary = isbinary;
83 int appended = (n == addr_last);
84 int len;
85
86 isbinary = newline_added = 0;
87 if (des)
88 init_des_cipher();
89 for (current_addr = n; (len = get_stream_line(fp)) > 0; size += len) {
90 SPL1();
91 if (put_sbuf_line(sbuf) == NULL) {
92 SPL0();
93 return ERR;
94 }
95 lp = lp->q_forw;
96 if (up)
97 up->t = lp;
98 else if ((up = push_undo_stack(UADD, current_addr,
99 current_addr)) == NULL) {
100 SPL0();
101 return ERR;
102 }
103 SPL0();
104 }
105 if (len < 0)
106 return ERR;
107 if (appended && size && o_isbinary && o_newline_added)
108 fputs("newline inserted\n", stderr);
109 else if (newline_added && (!appended || (!isbinary && !o_isbinary)))
110 fputs("newline appended\n", stderr);
111 if (isbinary && newline_added && !appended)
112 size += 1;
113 if (!size)
114 newline_added = 1;
115 newline_added = appended ? newline_added : o_newline_added;
116 isbinary = isbinary | o_isbinary;
117 if (des)
118 size += 8 - size % 8; /* adjust DES size */
119 return size;
120}
121
122
123/* get_stream_line: read a line of text from a stream; return line length */
124int
125get_stream_line(fp)
126 FILE *fp;
127{
128 register int c;
129 register int i = 0;
130
131 while (((c = des ? get_des_char(fp) : getc(fp)) != EOF || (!feof(fp) &&
132 !ferror(fp))) && c != '\n') {
133 REALLOC(sbuf, sbufsz, i + 1, ERR);
134 if (!(sbuf[i++] = c))
135 isbinary = 1;
136 }
137 REALLOC(sbuf, sbufsz, i + 2, ERR);
138 if (c == '\n')
139 sbuf[i++] = c;
140 else if (ferror(fp)) {
141 fprintf(stderr, "%s\n", strerror(errno));
142 sprintf(errmsg, "cannot read input file");
143 return ERR;
144 } else if (i) {
145 sbuf[i++] = '\n';
146 newline_added = 1;
147 }
148 sbuf[i] = '\0';
149 return (isbinary && newline_added && i) ? --i : i;
150}
151
152
153/* write_file: write a range of lines to a named file/pipe; return line count */
154long
155write_file(fn, mode, n, m)
156 char *fn;
157 char *mode;
158 long n;
159 long m;
160{
161 FILE *fp;
162 long size;
163
164 fp = (*fn == '!') ? popen(fn+1, "w") : fopen(strip_escapes(fn), mode);
165 if (fp == NULL) {
166 fprintf(stderr, "%s: %s\n", fn, strerror(errno));
167 sprintf(errmsg, "cannot open output file");
168 return ERR;
169 } else if ((size = write_stream(fp, n, m)) < 0)
170 return ERR;
171 else if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) {
172 fprintf(stderr, "%s: %s\n", fn, strerror(errno));
173 sprintf(errmsg, "cannot close output file");
174 return ERR;
175 }
176 fprintf(stdout, !scripted ? "%lu\n" : "", size);
177 return n ? m - n + 1 : 0;
178}
179
180
181/* write_stream: write a range of lines to a stream; return status */
182long
183write_stream(fp, n, m)
184 FILE *fp;
185 long n;
186 long m;
187{
188 line_t *lp = get_addressed_line_node(n);
189 unsigned long size = 0;
190 char *s;
191 int len;
192
193 if (des)
194 init_des_cipher();
195 for (; n && n <= m; n++, lp = lp->q_forw) {
196 if ((s = get_sbuf_line(lp)) == NULL)
197 return ERR;
198 len = lp->len;
199 if (n != addr_last || !isbinary || !newline_added)
200 s[len++] = '\n';
201 if (put_stream_line(fp, s, len) < 0)
202 return ERR;
203 size += len;
204 }
205 if (des) {
206 flush_des_file(fp); /* flush buffer */
207 size += 8 - size % 8; /* adjust DES size */
208 }
209 return size;
210}
211
212
213/* put_stream_line: write a line of text to a stream; return status */
214int
215put_stream_line(fp, s, len)
216 FILE *fp;
217 char *s;
218 int len;
219{
220 while (len--)
221 if ((des ? put_des_char(*s++, fp) : fputc(*s++, fp)) < 0) {
222 fprintf(stderr, "%s\n", strerror(errno));
223 sprintf(errmsg, "cannot write file");
224 return ERR;
225 }
226 return 0;
227}
228
229/* get_extended_line: get a an extended line from stdin */
230char *
231get_extended_line(sizep, nonl)
232 int *sizep;
233 int nonl;
234{
235 static char *cvbuf = NULL; /* buffer */
236 static int cvbufsz = 0; /* buffer size */
237
238 int l, n;
239 char *t = ibufp;
240
241 while (*t++ != '\n')
242 ;
243 if ((l = t - ibufp) < 2 || !has_trailing_escape(ibufp, ibufp + l - 1)) {
244 *sizep = l;
245 return ibufp;
246 }
247 *sizep = -1;
248 REALLOC(cvbuf, cvbufsz, l, NULL);
249 memcpy(cvbuf, ibufp, l);
250 *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */
251 if (nonl) l--; /* strip newline */
252 for (;;) {
253 if ((n = get_tty_line()) < 0)
254 return NULL;
255 else if (n == 0 || ibuf[n - 1] != '\n') {
256 sprintf(errmsg, "unexpected end-of-file");
257 return NULL;
258 }
259 REALLOC(cvbuf, cvbufsz, l + n, NULL);
260 memcpy(cvbuf + l, ibuf, n);
261 l += n;
262 if (n < 2 || !has_trailing_escape(cvbuf, cvbuf + l - 1))
263 break;
264 *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */
265 if (nonl) l--; /* strip newline */
266 }
267 REALLOC(cvbuf, cvbufsz, l + 1, NULL);
268 cvbuf[l] = '\0';
269 *sizep = l;
270 return cvbuf;
271}
272
273
274/* get_tty_line: read a line of text from stdin; return line length */
275int
276get_tty_line()
277{
278 register int oi = 0;
279 register int i = 0;
280 int c;
281
282 for (;;)
283 switch (c = getchar()) {
284 default:
285 oi = 0;
286 REALLOC(ibuf, ibufsz, i + 2, ERR);
287 if (!(ibuf[i++] = c)) isbinary = 1;
288 if (c != '\n')
289 continue;
290 lineno++;
291 ibuf[i] = '\0';
292 ibufp = ibuf;
293 return i;
294 case EOF:
295 if (ferror(stdin)) {
296 fprintf(stderr, "stdin: %s\n", strerror(errno));
297 sprintf(errmsg, "cannot read stdin");
298 clearerr(stdin);
299 ibufp = NULL;
300 return ERR;
301 } else {
302 clearerr(stdin);
303 if (i != oi) {
304 oi = i;
305 continue;
306 } else if (i)
307 ibuf[i] = '\0';
308 ibufp = ibuf;
309 return i;
310 }
311 }
312}
313
314
315
316#define ESCAPES "\a\b\f\n\r\t\v\\"
317#define ESCCHARS "abfnrtv\\"
318
319extern int rows;
320extern int cols;
321
322/* put_tty_line: print text to stdout */
323int
324put_tty_line(s, l, n, gflag)
325 char *s;
326 int l;
327 long n;
328 int gflag;
329{
330 int col = 0;
331 int lc = 0;
332 char *cp;
333
334 if (gflag & GNP) {
335 printf("%ld\t", n);
336 col = 8;
337 }
338 for (; l--; s++) {
339 if ((gflag & GLS) && ++col > cols) {
340 fputs("\\\n", stdout);
341 col = 1;
342#ifndef BACKWARDS
343 if (!scripted && !isglobal && ++lc > rows) {
344 lc = 0;
345 fputs("Press <RETURN> to continue... ", stdout);
346 fflush(stdout);
347 if (get_tty_line() < 0)
348 return ERR;
349 }
350#endif
351 }
352 if (gflag & GLS) {
353 if (31 < *s && *s < 127 && *s != '\\')
354 putchar(*s);
355 else {
356 putchar('\\');
357 col++;
358 if (*s && (cp = strchr(ESCAPES, *s)) != NULL)
359 putchar(ESCCHARS[cp - ESCAPES]);
360 else {
361 putchar((((unsigned char) *s & 0300) >> 6) + '0');
362 putchar((((unsigned char) *s & 070) >> 3) + '0');
363 putchar(((unsigned char) *s & 07) + '0');
364 col += 2;
365 }
366 }
367
368 } else
369 putchar(*s);
370 }
371#ifndef BACKWARDS
372 if (gflag & GLS)
373 putchar('$');
374#endif
375 putchar('\n');
376 return 0;
377}
35#endif /* not lint */
36
37#include "ed.h"
38
39
40extern int scripted;
41
42/* read_file: read a named file/pipe into the buffer; return line count */
43long
44read_file(fn, n)
45 char *fn;
46 long n;
47{
48 FILE *fp;
49 long size;
50
51
52 fp = (*fn == '!') ? popen(fn + 1, "r") : fopen(strip_escapes(fn), "r");
53 if (fp == NULL) {
54 fprintf(stderr, "%s: %s\n", fn, strerror(errno));
55 sprintf(errmsg, "cannot open input file");
56 return ERR;
57 } else if ((size = read_stream(fp, n)) < 0)
58 return ERR;
59 else if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) {
60 fprintf(stderr, "%s: %s\n", fn, strerror(errno));
61 sprintf(errmsg, "cannot close input file");
62 return ERR;
63 }
64 fprintf(stdout, !scripted ? "%lu\n" : "", size);
65 return current_addr - n;
66}
67
68
69extern int des;
70
71char *sbuf; /* file i/o buffer */
72int sbufsz; /* file i/o buffer size */
73int newline_added; /* if set, newline appended to input file */
74
75/* read_stream: read a stream into the editor buffer; return status */
76long
77read_stream(fp, n)
78 FILE *fp;
79 long n;
80{
81 line_t *lp = get_addressed_line_node(n);
82 undo_t *up = NULL;
83 unsigned long size = 0;
84 int o_newline_added = newline_added;
85 int o_isbinary = isbinary;
86 int appended = (n == addr_last);
87 int len;
88
89 isbinary = newline_added = 0;
90 if (des)
91 init_des_cipher();
92 for (current_addr = n; (len = get_stream_line(fp)) > 0; size += len) {
93 SPL1();
94 if (put_sbuf_line(sbuf) == NULL) {
95 SPL0();
96 return ERR;
97 }
98 lp = lp->q_forw;
99 if (up)
100 up->t = lp;
101 else if ((up = push_undo_stack(UADD, current_addr,
102 current_addr)) == NULL) {
103 SPL0();
104 return ERR;
105 }
106 SPL0();
107 }
108 if (len < 0)
109 return ERR;
110 if (appended && size && o_isbinary && o_newline_added)
111 fputs("newline inserted\n", stderr);
112 else if (newline_added && (!appended || (!isbinary && !o_isbinary)))
113 fputs("newline appended\n", stderr);
114 if (isbinary && newline_added && !appended)
115 size += 1;
116 if (!size)
117 newline_added = 1;
118 newline_added = appended ? newline_added : o_newline_added;
119 isbinary = isbinary | o_isbinary;
120 if (des)
121 size += 8 - size % 8; /* adjust DES size */
122 return size;
123}
124
125
126/* get_stream_line: read a line of text from a stream; return line length */
127int
128get_stream_line(fp)
129 FILE *fp;
130{
131 register int c;
132 register int i = 0;
133
134 while (((c = des ? get_des_char(fp) : getc(fp)) != EOF || (!feof(fp) &&
135 !ferror(fp))) && c != '\n') {
136 REALLOC(sbuf, sbufsz, i + 1, ERR);
137 if (!(sbuf[i++] = c))
138 isbinary = 1;
139 }
140 REALLOC(sbuf, sbufsz, i + 2, ERR);
141 if (c == '\n')
142 sbuf[i++] = c;
143 else if (ferror(fp)) {
144 fprintf(stderr, "%s\n", strerror(errno));
145 sprintf(errmsg, "cannot read input file");
146 return ERR;
147 } else if (i) {
148 sbuf[i++] = '\n';
149 newline_added = 1;
150 }
151 sbuf[i] = '\0';
152 return (isbinary && newline_added && i) ? --i : i;
153}
154
155
156/* write_file: write a range of lines to a named file/pipe; return line count */
157long
158write_file(fn, mode, n, m)
159 char *fn;
160 char *mode;
161 long n;
162 long m;
163{
164 FILE *fp;
165 long size;
166
167 fp = (*fn == '!') ? popen(fn+1, "w") : fopen(strip_escapes(fn), mode);
168 if (fp == NULL) {
169 fprintf(stderr, "%s: %s\n", fn, strerror(errno));
170 sprintf(errmsg, "cannot open output file");
171 return ERR;
172 } else if ((size = write_stream(fp, n, m)) < 0)
173 return ERR;
174 else if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) {
175 fprintf(stderr, "%s: %s\n", fn, strerror(errno));
176 sprintf(errmsg, "cannot close output file");
177 return ERR;
178 }
179 fprintf(stdout, !scripted ? "%lu\n" : "", size);
180 return n ? m - n + 1 : 0;
181}
182
183
184/* write_stream: write a range of lines to a stream; return status */
185long
186write_stream(fp, n, m)
187 FILE *fp;
188 long n;
189 long m;
190{
191 line_t *lp = get_addressed_line_node(n);
192 unsigned long size = 0;
193 char *s;
194 int len;
195
196 if (des)
197 init_des_cipher();
198 for (; n && n <= m; n++, lp = lp->q_forw) {
199 if ((s = get_sbuf_line(lp)) == NULL)
200 return ERR;
201 len = lp->len;
202 if (n != addr_last || !isbinary || !newline_added)
203 s[len++] = '\n';
204 if (put_stream_line(fp, s, len) < 0)
205 return ERR;
206 size += len;
207 }
208 if (des) {
209 flush_des_file(fp); /* flush buffer */
210 size += 8 - size % 8; /* adjust DES size */
211 }
212 return size;
213}
214
215
216/* put_stream_line: write a line of text to a stream; return status */
217int
218put_stream_line(fp, s, len)
219 FILE *fp;
220 char *s;
221 int len;
222{
223 while (len--)
224 if ((des ? put_des_char(*s++, fp) : fputc(*s++, fp)) < 0) {
225 fprintf(stderr, "%s\n", strerror(errno));
226 sprintf(errmsg, "cannot write file");
227 return ERR;
228 }
229 return 0;
230}
231
232/* get_extended_line: get a an extended line from stdin */
233char *
234get_extended_line(sizep, nonl)
235 int *sizep;
236 int nonl;
237{
238 static char *cvbuf = NULL; /* buffer */
239 static int cvbufsz = 0; /* buffer size */
240
241 int l, n;
242 char *t = ibufp;
243
244 while (*t++ != '\n')
245 ;
246 if ((l = t - ibufp) < 2 || !has_trailing_escape(ibufp, ibufp + l - 1)) {
247 *sizep = l;
248 return ibufp;
249 }
250 *sizep = -1;
251 REALLOC(cvbuf, cvbufsz, l, NULL);
252 memcpy(cvbuf, ibufp, l);
253 *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */
254 if (nonl) l--; /* strip newline */
255 for (;;) {
256 if ((n = get_tty_line()) < 0)
257 return NULL;
258 else if (n == 0 || ibuf[n - 1] != '\n') {
259 sprintf(errmsg, "unexpected end-of-file");
260 return NULL;
261 }
262 REALLOC(cvbuf, cvbufsz, l + n, NULL);
263 memcpy(cvbuf + l, ibuf, n);
264 l += n;
265 if (n < 2 || !has_trailing_escape(cvbuf, cvbuf + l - 1))
266 break;
267 *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */
268 if (nonl) l--; /* strip newline */
269 }
270 REALLOC(cvbuf, cvbufsz, l + 1, NULL);
271 cvbuf[l] = '\0';
272 *sizep = l;
273 return cvbuf;
274}
275
276
277/* get_tty_line: read a line of text from stdin; return line length */
278int
279get_tty_line()
280{
281 register int oi = 0;
282 register int i = 0;
283 int c;
284
285 for (;;)
286 switch (c = getchar()) {
287 default:
288 oi = 0;
289 REALLOC(ibuf, ibufsz, i + 2, ERR);
290 if (!(ibuf[i++] = c)) isbinary = 1;
291 if (c != '\n')
292 continue;
293 lineno++;
294 ibuf[i] = '\0';
295 ibufp = ibuf;
296 return i;
297 case EOF:
298 if (ferror(stdin)) {
299 fprintf(stderr, "stdin: %s\n", strerror(errno));
300 sprintf(errmsg, "cannot read stdin");
301 clearerr(stdin);
302 ibufp = NULL;
303 return ERR;
304 } else {
305 clearerr(stdin);
306 if (i != oi) {
307 oi = i;
308 continue;
309 } else if (i)
310 ibuf[i] = '\0';
311 ibufp = ibuf;
312 return i;
313 }
314 }
315}
316
317
318
319#define ESCAPES "\a\b\f\n\r\t\v\\"
320#define ESCCHARS "abfnrtv\\"
321
322extern int rows;
323extern int cols;
324
325/* put_tty_line: print text to stdout */
326int
327put_tty_line(s, l, n, gflag)
328 char *s;
329 int l;
330 long n;
331 int gflag;
332{
333 int col = 0;
334 int lc = 0;
335 char *cp;
336
337 if (gflag & GNP) {
338 printf("%ld\t", n);
339 col = 8;
340 }
341 for (; l--; s++) {
342 if ((gflag & GLS) && ++col > cols) {
343 fputs("\\\n", stdout);
344 col = 1;
345#ifndef BACKWARDS
346 if (!scripted && !isglobal && ++lc > rows) {
347 lc = 0;
348 fputs("Press <RETURN> to continue... ", stdout);
349 fflush(stdout);
350 if (get_tty_line() < 0)
351 return ERR;
352 }
353#endif
354 }
355 if (gflag & GLS) {
356 if (31 < *s && *s < 127 && *s != '\\')
357 putchar(*s);
358 else {
359 putchar('\\');
360 col++;
361 if (*s && (cp = strchr(ESCAPES, *s)) != NULL)
362 putchar(ESCCHARS[cp - ESCAPES]);
363 else {
364 putchar((((unsigned char) *s & 0300) >> 6) + '0');
365 putchar((((unsigned char) *s & 070) >> 3) + '0');
366 putchar(((unsigned char) *s & 07) + '0');
367 col += 2;
368 }
369 }
370
371 } else
372 putchar(*s);
373 }
374#ifndef BACKWARDS
375 if (gflag & GLS)
376 putchar('$');
377#endif
378 putchar('\n');
379 return 0;
380}