/* * Copyright 1998-2002 by Albert Cahalan; all rights resered. * This file may be used subject to the terms and conditions of the * GNU Library General Public License Version 2, or any later version * at your option, as published by the Free Software Foundation. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. */ #include <sys/types.h> #include <string.h> #include "procps.h" #include "escape.h" #include "readproc.h" // What it would be for a UTF-8 locale: // "Z-------------------------------" // "********************************" // "********************************" // "*******************************-" // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" Trailing UTF-8, and badness in 8-bit. // "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy" Trailing UTF-8, and safe in 8-bit. // "--222222222222222222222222222222" // ".333333333333.3.44444444555566--" The '.' means '3', with problem chars. // // Problems include non-shortest forms, UTF-16, and non-characters. // The 4-byte, 5-byte, and 6-byte sequences are full of trouble too. #if 0 /* sanitize a string, without the nice BSD library function: */ /* strvis(vis_args, k->ki_args, VIS_TAB | VIS_NL | VIS_NOSLASH) */ int octal_escape_str(char *restrict dst, const char *restrict src, size_t n) { unsigned char c; char d; size_t i; const char codes[] = "Z------abtnvfr-------------e----" " *******************************" /* better: do not print any space */ "****************************\\***" "*******************************-" "--------------------------------" "********************************" "********************************" "********************************"; for (i = 0; i < n;) { c = (unsigned char)*(src++); d = codes[c]; switch (d) { case 'Z': goto leave; case '*': i++; *(dst++) = c; break; case '-': if (i + 4 > n) goto leave; i += 4; *(dst++) = '\\'; *(dst++) = "01234567"[c >> 6]; *(dst++) = "01234567"[(c >> 3) & 07]; *(dst++) = "01234567"[c & 07]; break; default: if (i + 2 > n) goto leave; i += 2; *(dst++) = '\\'; *(dst++) = d; break; } } leave: *(dst++) = '\0'; return i; } #endif /* sanitize a string via one-way mangle */ int escape_str(char *restrict dst, const char *restrict src, int bufsize, int maxglyphs) { unsigned char c; int my_glyphs = 0; int my_bytes = 0; const char codes[] = "Z-------------------------------" "********************************" "********************************" "*******************************-" "--------------------------------" "********************************" "********************************" "********************************"; if (bufsize > maxglyphs + 1) bufsize = maxglyphs + 1; // FIXME: assumes 8-bit locale for (;;) { if (my_glyphs >= maxglyphs) break; if (my_bytes + 1 >= bufsize) break; c = (unsigned char)*(src++); if (!c) break; if (codes[c] == '-') c = '?'; my_glyphs++; my_bytes++; *(dst++) = c; } *(dst++) = '\0'; return my_bytes; // bytes of text, excluding the NUL } ///////////////////////////////////////////////// // escape an argv or environment string array // // bytes arg means sizeof(buf) int escape_strlist(char *restrict dst, const char *restrict const *restrict src, size_t bytes) { size_t i = 0; //if (!*src) { just never call this function without checking first // do something nice //} for (;;) { i += escape_str(dst + i, *src, bytes - i, bytes - i); // FIXME: byte/glyph if (bytes - i < 3) break; // need room for space, a character, and the NUL src++; if (!*src) break; // need something to print dst[i++] = ' '; } return i; // bytes of text, excluding the NUL } /////////////////////////////////////////////////// int escape_command(char *restrict const outbuf, const proc_t * restrict const pp, int bytes, int glyphs, unsigned flags) { int overhead = 1; // the trailing NUL int end = 0; if (bytes > glyphs + 1) bytes = glyphs + 1; // FIXME: assumes 8-bit locale if (flags & ESC_ARGS) { const char **lc = (const char **)pp->cmdline; if (lc && *lc) return escape_strlist(outbuf, lc, bytes); } if (flags & ESC_BRACKETS) { overhead += 2; } if (flags & ESC_DEFUNCT) { if (pp->state == 'Z') overhead += 10; // chars in " <defunct>" else flags &= ~ESC_DEFUNCT; } if (overhead >= bytes) { // if no room for even one byte of the command name // you'd damn well better have _some_ space outbuf[0] = '-'; outbuf[1] = '\0'; return 1; } if (flags & ESC_BRACKETS) { outbuf[end++] = '['; } end += escape_str(outbuf + end, pp->cmd, bytes - overhead, glyphs - overhead + 1); // Hmmm, do we want "[foo] <defunct>" or "[foo <defunct>]"? if (flags & ESC_BRACKETS) { outbuf[end++] = ']'; } if (flags & ESC_DEFUNCT) { memcpy(outbuf + end, " <defunct>", 10); end += 10; } outbuf[end] = '\0'; return end; // bytes or glyphs, not including the NUL }