/*
* 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
}