1/*
2 * sh.print.c: Primitive Output routines.
3 */
4/*-
5 * Copyright (c) 1980, 1991 The Regents of the University of California.
6 * 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. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32#include "sh.h"
33#include "ed.h"
34
35extern int Tty_eight_bit;
36
37int     lbuffed = 1;		/* true if line buffered */
38
39static	void	p2dig	(unsigned int);
40
41/*
42 * C Shell
43 */
44
45#if defined(BSDLIMIT) || defined(RLIMIT_CPU)
46void
47psecs(unsigned long l)
48{
49    int i;
50
51    i = (int) (l / 3600);
52    if (i) {
53	xprintf("%d:", i);
54	i = (int) (l % 3600);
55	p2dig(i / 60);
56	goto minsec;
57    }
58    i = (int) l;
59    xprintf("%d", i / 60);
60minsec:
61    i %= 60;
62    xprintf(":");
63    p2dig(i);
64}
65
66#endif
67
68void			/* PWP: print mm:ss.dd, l is in sec*100 */
69#ifdef BSDTIMES
70pcsecs(unsigned long l)
71#else /* BSDTIMES */
72# ifndef POSIX
73pcsecs(time_t l)
74# else /* POSIX */
75pcsecs(clock_t l)
76# endif /* POSIX */
77#endif /* BSDTIMES */
78{
79    int i;
80
81    i = (int) (l / 360000);
82    if (i) {
83	xprintf("%d:", i);
84	i = (int) ((l % 360000) / 100);
85	p2dig(i / 60);
86	goto minsec;
87    }
88    i = (int) (l / 100);
89    xprintf("%d", i / 60);
90minsec:
91    i %= 60;
92    xprintf(":");
93    p2dig(i);
94    xprintf(".");
95    p2dig((int) (l % 100));
96}
97
98static void
99p2dig(unsigned i)
100{
101
102    xprintf("%u%u", i / 10, i % 10);
103}
104
105char    linbuf[2048];		/* was 128 */
106char   *linp = linbuf;
107int    output_raw = 0;		/* PWP */
108int    xlate_cr   = 0;		/* HE */
109
110/* For cleanup_push() */
111void
112output_raw_restore(void *xorig)
113{
114    int *orig;
115
116    orig = xorig;
117    output_raw = *orig;
118}
119
120#ifdef WIDE_STRINGS
121void
122putwraw(Char c)
123{
124    char buf[MB_LEN_MAX];
125    size_t i, len;
126
127    len = one_wctomb(buf, c & CHAR);
128    for (i = 0; i < len; i++)
129	putraw((unsigned char)buf[i] | (c & ~CHAR));
130}
131
132void
133xputwchar(Char c)
134{
135    char buf[MB_LEN_MAX];
136    size_t i, len;
137
138    len = one_wctomb(buf, c & CHAR);
139    for (i = 0; i < len; i++)
140	xputchar((unsigned char)buf[i] | (c & ~CHAR));
141}
142#endif
143
144void
145xputchar(int c)
146{
147    int     atr;
148
149    atr = c & ATTRIBUTES & TRIM;
150    c &= CHAR | QUOTE;
151    if (!output_raw && (c & QUOTE) == 0) {
152	if (iscntrl(c) && (ASC(c) < 0x80 || MB_CUR_MAX == 1)) {
153	    if (c != '\t' && c != '\n'
154#ifdef COLORCAT
155	        && !(adrof(STRcolorcat) && c == CTL_ESC('\033'))
156#endif
157		&& (xlate_cr || c != '\r'))
158	    {
159		xputchar('^' | atr);
160		if (c == CTL_ESC('\177'))
161		    c = '?';
162		else
163		    /* Note: for IS_ASCII, this compiles to: c = c | 0100 */
164		    c = CTL_ESC(ASC(c)|0100);
165	    }
166	}
167	else if (!isprint(c) && (ASC(c) < 0x80 || MB_CUR_MAX == 1)) {
168	    xputchar('\\' | atr);
169	    xputchar((((c >> 6) & 7) + '0') | atr);
170	    xputchar((((c >> 3) & 7) + '0') | atr);
171	    c = (c & 7) + '0';
172	}
173	(void) putraw(c | atr);
174    }
175    else {
176	c &= TRIM;
177	if (haderr ? (didfds ? is2atty : isdiagatty) :
178	    (didfds ? is1atty : isoutatty))
179	    SetAttributes(c | atr);
180	(void) putpure(c);
181    }
182    if (lbuffed && (c & CHAR) == '\n')
183	flush();
184}
185
186int
187putraw(int c)
188{
189    if (haderr ? (didfds ? is2atty : isdiagatty) :
190	(didfds ? is1atty : isoutatty)) {
191	if (Tty_eight_bit == -1)
192	    ed_set_tty_eight_bit();
193	if (!Tty_eight_bit && (c & META)) {
194	    c = (c & ~META) | STANDOUT;
195	}
196	SetAttributes(c);
197    }
198    return putpure(c);
199}
200
201int
202putpure(int c)
203{
204    c &= CHAR;
205
206    *linp++ = (char) c;
207    if (linp >= &linbuf[sizeof linbuf - 10])
208	flush();
209    return (1);
210}
211
212void
213drainoline(void)
214{
215    linp = linbuf;
216}
217
218void
219flush(void)
220{
221    int unit, oldexitset = exitset;
222    static int interrupted = 0;
223
224    /* int lmode; */
225
226    if (linp == linbuf)
227	return;
228    if (GettingInput && !Tty_raw_mode && linp < &linbuf[sizeof linbuf - 10])
229	return;
230    if (handle_interrupt)
231       exitset = 1;
232
233    if (interrupted) {
234	interrupted = 0;
235	linp = linbuf;		/* avoid recursion as stderror calls flush */
236	if (handle_interrupt)
237	    fixerror();
238	else
239	    stderror(ERR_SILENT);
240    }
241    interrupted = 1;
242    if (haderr)
243	unit = didfds ? 2 : SHDIAG;
244    else
245	unit = didfds ? 1 : SHOUT;
246#ifdef COMMENT
247#ifdef TIOCLGET
248    if (didfds == 0 && ioctl(unit, TIOCLGET, (ioctl_t) & lmode) == 0 &&
249	lmode & LFLUSHO) {
250	lmode = LFLUSHO;
251	(void) ioctl(unit, TIOCLBIC, (ioclt_t) & lmode);
252	(void) xwrite(unit, "\n", 1);
253    }
254#endif
255#endif
256    if (xwrite(unit, linbuf, linp - linbuf) == -1)
257	switch (errno) {
258#ifdef EIO
259	/* We lost our tty */
260	case EIO:
261#endif
262#ifdef ENXIO
263	/*
264	 * Deal with Digital Unix 4.0D bogocity, returning ENXIO when
265	 * we lose our tty.
266	 */
267	case ENXIO:
268#endif
269	/*
270	 * IRIX 6.4 bogocity?
271	 */
272#ifdef ENOTTY
273	case ENOTTY:
274#endif
275#ifdef EBADF
276	case EBADF:
277#endif
278#ifdef ESTALE
279	/*
280	 * Lost our file descriptor, exit (IRIS4D)
281	 */
282	case ESTALE:
283#endif
284#ifdef ENOENT
285	/*
286	 * Deal with SoFS bogocity: returns ENOENT instead of ESTALE.
287	 */
288	case ENOENT:
289#endif
290	/*
291	 * Over our quota, writing the history file
292	 */
293#ifdef EDQUOT
294	case EDQUOT:
295#endif
296	/* Nothing to do, but die */
297	    if (handle_interrupt == 0)
298		xexit(1);
299	    /*FALLTHROUGH*/
300	default:
301	    if (handle_interrupt)
302		fixerror();
303	    else
304		stderror(ERR_SILENT);
305	    break;
306	}
307
308    exitset = oldexitset;
309    linp = linbuf;
310    interrupted = 0;
311}
312