1 /*
2  * Copyright 1998-2002 by Albert Cahalan; all rights resered.
3  * This file may be used subject to the terms and conditions of the
4  * GNU Library General Public License Version 2, or any later version
5  * at your option, as published by the Free Software Foundation.
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU Library General Public License for more details.
10  */
11 #include <sys/types.h>
12 #include <string.h>
13 #include "procps.h"
14 #include "escape.h"
15 #include "readproc.h"
16 
17 // What it would be for a UTF-8 locale:
18 // "Z-------------------------------"
19 // "********************************"
20 // "********************************"
21 // "*******************************-"
22 // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"  Trailing UTF-8, and badness in 8-bit.
23 // "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"  Trailing UTF-8, and safe in 8-bit.
24 // "--222222222222222222222222222222"
25 // ".333333333333.3.44444444555566--"  The '.' means '3', with problem chars.
26 //
27 // Problems include non-shortest forms, UTF-16, and non-characters.
28 // The 4-byte, 5-byte, and 6-byte sequences are full of trouble too.
29 
30 #if 0
31 /* sanitize a string, without the nice BSD library function:     */
32 /* strvis(vis_args, k->ki_args, VIS_TAB | VIS_NL | VIS_NOSLASH)  */
33 int octal_escape_str(char *restrict dst, const char *restrict src, size_t n)
34 {
35 	unsigned char c;
36 	char d;
37 	size_t i;
38 	const char codes[] = "Z------abtnvfr-------------e----" " *******************************"	/* better: do not print any space */
39 	    "****************************\\***"
40 	    "*******************************-"
41 	    "--------------------------------"
42 	    "********************************"
43 	    "********************************"
44 	    "********************************";
45 	for (i = 0; i < n;) {
46 		c = (unsigned char)*(src++);
47 		d = codes[c];
48 		switch (d) {
49 		case 'Z':
50 			goto leave;
51 		case '*':
52 			i++;
53 			*(dst++) = c;
54 			break;
55 		case '-':
56 			if (i + 4 > n)
57 				goto leave;
58 			i += 4;
59 			*(dst++) = '\\';
60 			*(dst++) = "01234567"[c >> 6];
61 			*(dst++) = "01234567"[(c >> 3) & 07];
62 			*(dst++) = "01234567"[c & 07];
63 			break;
64 		default:
65 			if (i + 2 > n)
66 				goto leave;
67 			i += 2;
68 			*(dst++) = '\\';
69 			*(dst++) = d;
70 			break;
71 		}
72 	}
73 leave:
74 	*(dst++) = '\0';
75 	return i;
76 }
77 #endif
78 
79 /* sanitize a string via one-way mangle */
escape_str(char * restrict dst,const char * restrict src,int bufsize,int maxglyphs)80 int escape_str(char *restrict dst, const char *restrict src, int bufsize,
81 	       int maxglyphs)
82 {
83 	unsigned char c;
84 	int my_glyphs = 0;
85 	int my_bytes = 0;
86 	const char codes[] =
87 	    "Z-------------------------------"
88 	    "********************************"
89 	    "********************************"
90 	    "*******************************-"
91 	    "--------------------------------"
92 	    "********************************"
93 	    "********************************"
94 	    "********************************";
95 
96 	if (bufsize > maxglyphs + 1)
97 		bufsize = maxglyphs + 1;	// FIXME: assumes 8-bit locale
98 
99 	for (;;) {
100 		if (my_glyphs >= maxglyphs)
101 			break;
102 		if (my_bytes + 1 >= bufsize)
103 			break;
104 		c = (unsigned char)*(src++);
105 		if (!c)
106 			break;
107 		if (codes[c] == '-')
108 			c = '?';
109 		my_glyphs++;
110 		my_bytes++;
111 		*(dst++) = c;
112 	}
113 	*(dst++) = '\0';
114 	return my_bytes;	// bytes of text, excluding the NUL
115 }
116 
117 /////////////////////////////////////////////////
118 
119 // escape an argv or environment string array
120 //
121 // bytes arg means sizeof(buf)
escape_strlist(char * restrict dst,const char * restrict const * restrict src,size_t bytes)122 int escape_strlist(char *restrict dst, const char *restrict const *restrict src,
123 		   size_t bytes)
124 {
125 	size_t i = 0;
126 
127 //if (!*src) {        just never call this function without checking first
128 //  do something nice
129 //}
130 
131 	for (;;) {
132 		i += escape_str(dst + i, *src, bytes - i, bytes - i);	// FIXME: byte/glyph
133 		if (bytes - i < 3)
134 			break;	// need room for space, a character, and the NUL
135 		src++;
136 		if (!*src)
137 			break;	// need something to print
138 		dst[i++] = ' ';
139 	}
140 	return i;		// bytes of text, excluding the NUL
141 }
142 
143 ///////////////////////////////////////////////////
144 
escape_command(char * restrict const outbuf,const proc_t * restrict const pp,int bytes,int glyphs,unsigned flags)145 int escape_command(char *restrict const outbuf,
146 		   const proc_t * restrict const pp, int bytes, int glyphs,
147 		   unsigned flags)
148 {
149 	int overhead = 1;	// the trailing NUL
150 	int end = 0;
151 
152 	if (bytes > glyphs + 1)
153 		bytes = glyphs + 1;	// FIXME: assumes 8-bit locale
154 
155 	if (flags & ESC_ARGS) {
156 		const char **lc = (const char **)pp->cmdline;
157 		if (lc && *lc)
158 			return escape_strlist(outbuf, lc, bytes);
159 	}
160 	if (flags & ESC_BRACKETS) {
161 		overhead += 2;
162 	}
163 	if (flags & ESC_DEFUNCT) {
164 		if (pp->state == 'Z')
165 			overhead += 10;	// chars in " <defunct>"
166 		else
167 			flags &= ~ESC_DEFUNCT;
168 	}
169 	if (overhead >= bytes) {	// if no room for even one byte of the command name
170 		// you'd damn well better have _some_ space
171 		outbuf[0] = '-';
172 		outbuf[1] = '\0';
173 		return 1;
174 	}
175 	if (flags & ESC_BRACKETS) {
176 		outbuf[end++] = '[';
177 	}
178 	end +=
179 	    escape_str(outbuf + end, pp->cmd, bytes - overhead,
180 		       glyphs - overhead + 1);
181 
182 	// Hmmm, do we want "[foo] <defunct>" or "[foo <defunct>]"?
183 	if (flags & ESC_BRACKETS) {
184 		outbuf[end++] = ']';
185 	}
186 	if (flags & ESC_DEFUNCT) {
187 		memcpy(outbuf + end, " <defunct>", 10);
188 		end += 10;
189 	}
190 
191 	outbuf[end] = '\0';
192 	return end;		// bytes or glyphs, not including the NUL
193 }
194