* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <ctype.h>
-#include <langinfo.h>
#include <limits.h>
#include <stdio.h>
-#include <stdlib.h> /* MB_CUR_MAX */
#include <string.h>
-#include <wchar.h>
-#include <wctype.h>
-#include <sys/types.h>
#include "escape.h"
#include "readproc.h"
-#define SECURE_ESCAPE_ARGS(dst, bytes, cells) do { \
+#define SECURE_ESCAPE_ARGS(dst, bytes) do { \
if ((bytes) <= 0) return 0; \
*(dst) = '\0'; \
if ((bytes) >= INT_MAX) return 0; \
- if ((cells) >= INT_MAX) return 0; \
- if ((cells) <= 0) return 0; \
} while (0)
-static int escape_str_utf8 (char *dst, const char *src, int bufsize, int *maxcells) {
- int my_cells = 0;
- int my_bytes = 0;
- mbstate_t s;
+int escape_str (unsigned char *dst, const unsigned char *src, int bufsize) {
+ int i, n;
- SECURE_ESCAPE_ARGS(dst, bufsize, *maxcells);
+ SECURE_ESCAPE_ARGS(dst, bufsize);
- memset(&s, 0, sizeof (s));
-
- for(;;) {
- wchar_t wc;
- int len = 0;
-
- if(my_cells >= *maxcells || my_bytes+1 >= bufsize)
- break;
-
- if (!(len = mbrtowc (&wc, src, MB_CUR_MAX, &s)))
- /* 'str' contains \0 */
- break;
-
- if (len < 0) {
- /* invalid multibyte sequence -- zeroize state */
- memset (&s, 0, sizeof (s));
- *(dst++) = '?';
- src++;
- my_cells++;
- my_bytes++;
-
- } else if (len==1) {
- /* non-multibyte */
- *(dst++) = isprint(*src) ? *src : '?';
- src++;
- my_cells++;
- my_bytes++;
-
- } else if (!iswprint(wc)) {
- /* multibyte - no printable */
- *(dst++) = '?';
- src+=len;
- my_cells++;
- my_bytes++;
-
- } else {
- /* multibyte - maybe, kinda "printable" */
- int wlen = wcwidth(wc);
- // Got space?
- if (wlen > *maxcells-my_cells || len >= bufsize-(my_bytes+1)) break;
- // safe multibyte
- memcpy(dst, src, len);
- dst += len;
- src += len;
- my_bytes += len;
- if (wlen > 0) my_cells += wlen;
- }
- //fprintf(stdout, "cells: %d\n", my_cells);
- }
- *dst = '\0';
-
- // fprintf(stderr, "maxcells: %d, my_cells; %d\n", *maxcells, my_cells);
-
- *maxcells -= my_cells;
- return my_bytes; // bytes of text, excluding the NUL
-}
-
-
-/* sanitize a string via one-way mangle */
-int escape_str (char *dst, const char *src, int bufsize, int *maxcells) {
- unsigned char c;
- int my_cells = 0;
- int my_bytes = 0;
- const char codes[] =
- "Z..............................."
- "||||||||||||||||||||||||||||||||"
- "||||||||||||||||||||||||||||||||"
- "|||||||||||||||||||||||||||||||."
- "????????????????????????????????"
- "????????????????????????????????"
- "????????????????????????????????"
- "????????????????????????????????";
-
- static int utf_init=0;
-
- if(utf_init==0){
- /* first call -- check if UTF stuff is usable */
- char *enc = nl_langinfo(CODESET);
- utf_init = enc && strcasecmp(enc, "UTF-8")==0 ? 1 : -1;
- }
- if (utf_init==1 && MB_CUR_MAX>1) {
- /* UTF8 locales */
- return escape_str_utf8(dst, src, bufsize, maxcells);
- }
-
- SECURE_ESCAPE_ARGS(dst, bufsize, *maxcells);
-
- if(bufsize > *maxcells+1) bufsize=*maxcells+1; // FIXME: assumes 8-bit locale
-
- for(;;){
- if(my_cells >= *maxcells || my_bytes+1 >= bufsize)
- break;
- c = (unsigned char) *(src++);
- if(!c) break;
- if(codes[c]!='|') c=codes[c];
- my_cells++;
- my_bytes++;
- *(dst++) = c;
+ n = snprintf(dst, bufsize, "%s", src);
+ if (n < 0) {
+ *dst = '\0';
+ return 0;
}
- *dst = '\0';
-
- *maxcells -= my_cells;
- return my_bytes; // bytes of text, excluding the NUL
-}
+ if (n >= bufsize) n = bufsize-1;
-/////////////////////////////////////////////////
+ // control chars, especially tabs, create alignment problems for ps & top ...
+ for (i = 0; i < n; i++)
+ if (dst[i] < 0x20 || dst[i] == 0x7f)
+ dst[i] = '?';
-// escape an argv or environment string array
-//
-// bytes arg means sizeof(buf)
-static int escape_strlist (char *dst, const char **src, size_t bytes, int *cells) {
- size_t i = 0;
-
- for(;;){
- i += escape_str(dst+i, *src, bytes-i, cells);
- if(bytes-i < 3) break; // need room for space, a character, and the NUL
- src++;
- if(!*src) break; // need something to print
- if (*cells<=1) break; // need room for printed size of text
- dst[i++] = ' ';
- --*cells;
- }
- return i; // bytes, excluding the NUL
+ return n;
}
-///////////////////////////////////////////////////
-int escape_command (char *const outbuf, const proc_t *pp, int bytes, int *cells, unsigned flags) {
+int escape_command (unsigned char *outbuf, const proc_t *pp, int bytes, unsigned flags) {
int overhead = 0;
int end = 0;
- if(flags & ESC_ARGS){
- const char **lc = (const char**)pp->cmdline;
- if(lc && *lc) return escape_strlist(outbuf, lc, bytes, cells);
- }
if(flags & ESC_BRACKETS){
overhead += 2;
}
if(pp->state=='Z') overhead += 10; // chars in " <defunct>"
else flags &= ~ESC_DEFUNCT;
}
- if(overhead + 1 >= *cells || // if no room for even one byte of the command name
- overhead + 1 >= bytes){
+ if(overhead + 1 >= bytes){ // if no room for even one byte of the command name
outbuf[0] = '\0';
return 0;
}
if(flags & ESC_BRACKETS){
outbuf[end++] = '[';
}
- *cells -= overhead;
- end += escape_str(outbuf+end, pp->cmd, bytes-overhead, cells);
+ end += escape_str(outbuf+end, pp->cmd, bytes-overhead);
// Hmmm, do we want "[foo] <defunct>" or "[foo <defunct>]"?
if(flags & ESC_BRACKETS){
static int fill_cgroup_cvt (const char* directory, proc_t *restrict p) {
#define vMAX ( MAX_BUFSZ - (int)(dst - dst_buffer) )
char *src, *dst, *grp, *eob, *name;
- int tot, x, whackable_int = MAX_BUFSZ, len;
+ int tot, x, len;
*(dst = dst_buffer) = '\0'; // empty destination
tot = read_unvectored(src_buffer, MAX_BUFSZ, directory, "cgroup", '\0');
len = snprintf(dst, vMAX, "%s", (dst > dst_buffer) ? "," : "");
if (len < 0 || len >= vMAX) break;
dst += len;
- dst += escape_str(dst, grp, vMAX, &whackable_int);
+ dst += escape_str(dst, grp, vMAX);
}
if (!(p->cgroup = strdup(dst_buffer[0] ? dst_buffer : "-")))
return 1;
// valid proc_t.cmdline pointer.
static int fill_cmdline_cvt (const char* directory, proc_t *restrict p) {
#define uFLG ( ESC_BRACKETS | ESC_DEFUNCT )
- int whackable_int = MAX_BUFSZ;
-
if (read_unvectored(src_buffer, MAX_BUFSZ, directory, "cmdline", ' '))
- escape_str(dst_buffer, src_buffer, MAX_BUFSZ, &whackable_int);
+ escape_str(dst_buffer, src_buffer, MAX_BUFSZ);
else
- escape_command(dst_buffer, p, MAX_BUFSZ, &whackable_int, uFLG);
+ escape_command(dst_buffer, p, MAX_BUFSZ, uFLG);
p->cmdline = strdup(dst_buffer[0] ? dst_buffer : "?");
if (!p->cmdline)
return 1;
// This routine reads an 'environ' for the designated proc_t and
// guarantees the caller a valid proc_t.environ pointer.
static int fill_environ_cvt (const char* directory, proc_t *restrict p) {
- int whackable_int = MAX_BUFSZ;
-
dst_buffer[0] = '\0';
if (read_unvectored(src_buffer, MAX_BUFSZ, directory, "environ", ' '))
- escape_str(dst_buffer, src_buffer, MAX_BUFSZ, &whackable_int);
+ escape_str(dst_buffer, src_buffer, MAX_BUFSZ);
p->environ = strdup(dst_buffer[0] ? dst_buffer : "-");
if (!p->environ)
return 1;