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