2002-02-02 04:17:29 +05:30
|
|
|
/*
|
2012-03-02 17:59:36 +05:30
|
|
|
* escape.c - printing handling
|
|
|
|
* Copyright 1998-2002 by Albert Cahalan
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
2002-02-02 04:17:29 +05:30
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2012-03-02 17:59:36 +05:30
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
2004-11-05 02:20:59 +05:30
|
|
|
#include <stdio.h>
|
2002-02-02 04:17:29 +05:30
|
|
|
#include <sys/types.h>
|
2002-12-21 16:04:50 +05:30
|
|
|
#include <string.h>
|
1970-01-01 05:30:00 +05:30
|
|
|
#include <limits.h>
|
2002-12-21 16:04:50 +05:30
|
|
|
#include "procps.h"
|
|
|
|
#include "escape.h"
|
|
|
|
#include "readproc.h"
|
2021-04-24 02:23:39 +05:30
|
|
|
#include "nls.h"
|
2002-02-02 04:17:29 +05:30
|
|
|
|
2008-09-09 07:36:52 +05:30
|
|
|
#if (__GNU_LIBRARY__ >= 6) && (!defined(__UCLIBC__) || defined(__UCLIBC_HAS_WCHAR__))
|
2004-11-05 02:20:59 +05:30
|
|
|
# include <wchar.h>
|
|
|
|
# include <wctype.h>
|
|
|
|
# include <stdlib.h> /* MB_CUR_MAX */
|
|
|
|
# include <ctype.h>
|
|
|
|
#endif
|
2002-12-21 16:04:50 +05:30
|
|
|
|
1970-01-01 05:30:00 +05:30
|
|
|
#define SECURE_ESCAPE_ARGS(dst, bytes, cells) 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)
|
|
|
|
|
2020-12-31 11:30:00 +05:30
|
|
|
static const unsigned char ESC_tab[] = {
|
|
|
|
"@..............................."
|
|
|
|
"||||||||||||||||||||||||||||||||"
|
|
|
|
"||||||||||||||||||||||||||||||||"
|
|
|
|
"|||||||||||||||||||||||||||||||."
|
|
|
|
"????????????????????????????????"
|
|
|
|
"????????????????????????????????"
|
|
|
|
"????????????????????????????????"
|
|
|
|
"????????????????????????????????"
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2008-09-09 07:36:52 +05:30
|
|
|
#if (__GNU_LIBRARY__ >= 6) && (!defined(__UCLIBC__) || defined(__UCLIBC_HAS_WCHAR__))
|
2020-12-31 11:30:00 +05:30
|
|
|
|
2004-11-05 02:20:59 +05:30
|
|
|
static int escape_str_utf8(char *restrict dst, const char *restrict src, int bufsize, int *maxcells){
|
|
|
|
int my_cells = 0;
|
|
|
|
int my_bytes = 0;
|
|
|
|
mbstate_t s;
|
2013-03-31 10:30:00 +05:30
|
|
|
|
1970-01-01 05:30:00 +05:30
|
|
|
SECURE_ESCAPE_ARGS(dst, bufsize, *maxcells);
|
|
|
|
|
2004-11-05 02:20:59 +05:30
|
|
|
memset(&s, 0, sizeof (s));
|
2013-03-31 10:30:00 +05:30
|
|
|
|
2004-11-05 02:20:59 +05:30
|
|
|
for(;;) {
|
|
|
|
wchar_t wc;
|
|
|
|
int len = 0;
|
2013-03-31 10:30:00 +05:30
|
|
|
|
2013-03-11 11:30:00 +05:30
|
|
|
if(my_cells >= *maxcells || my_bytes+1 >= bufsize)
|
2002-02-02 04:17:29 +05:30
|
|
|
break;
|
2013-03-31 10:30:00 +05:30
|
|
|
|
2004-11-05 02:20:59 +05:30
|
|
|
if (!(len = mbrtowc (&wc, src, MB_CUR_MAX, &s)))
|
|
|
|
/* 'str' contains \0 */
|
2002-02-02 04:17:29 +05:30
|
|
|
break;
|
2013-03-31 10:30:00 +05:30
|
|
|
|
2004-11-05 02:20:59 +05:30
|
|
|
if (len < 0) {
|
|
|
|
/* invalid multibyte sequence -- zeroize state */
|
|
|
|
memset (&s, 0, sizeof (s));
|
|
|
|
*(dst++) = '?';
|
|
|
|
src++;
|
2013-03-11 11:30:00 +05:30
|
|
|
my_cells++;
|
2004-11-05 02:20:59 +05:30
|
|
|
my_bytes++;
|
|
|
|
|
2016-08-20 10:30:00 +05:30
|
|
|
} else if (len==1) {
|
|
|
|
/* non-multibyte */
|
|
|
|
*(dst++) = isprint(*src) ? *src : '?';
|
|
|
|
src++;
|
|
|
|
my_cells++;
|
|
|
|
my_bytes++;
|
|
|
|
|
2004-11-05 02:20:59 +05:30
|
|
|
} else if (!iswprint(wc)) {
|
|
|
|
/* multibyte - no printable */
|
|
|
|
*(dst++) = '?';
|
|
|
|
src+=len;
|
|
|
|
my_cells++;
|
2013-03-11 11:30:00 +05:30
|
|
|
my_bytes++;
|
2013-03-31 10:30:00 +05:30
|
|
|
|
2004-11-05 02:20:59 +05:30
|
|
|
} else {
|
2020-06-18 10:30:00 +05:30
|
|
|
/* multibyte - maybe, kinda "printable" */
|
2004-11-05 02:20:59 +05:30
|
|
|
int wlen = wcwidth(wc);
|
2020-06-18 10:30:00 +05:30
|
|
|
// 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;
|
2002-02-02 04:17:29 +05:30
|
|
|
}
|
2004-11-05 02:20:59 +05:30
|
|
|
//fprintf(stdout, "cells: %d\n", my_cells);
|
2002-02-02 04:17:29 +05:30
|
|
|
}
|
2011-05-18 14:03:44 +05:30
|
|
|
*dst = '\0';
|
2004-11-05 02:20:59 +05:30
|
|
|
|
|
|
|
// fprintf(stderr, "maxcells: %d, my_cells; %d\n", *maxcells, my_cells);
|
2013-03-31 10:30:00 +05:30
|
|
|
|
2004-11-05 02:20:59 +05:30
|
|
|
*maxcells -= my_cells;
|
|
|
|
return my_bytes; // bytes of text, excluding the NUL
|
2002-02-02 04:17:29 +05:30
|
|
|
}
|
2004-11-05 02:20:59 +05:30
|
|
|
#endif /* __GNU_LIBRARY__ */
|
2002-02-02 04:17:29 +05:30
|
|
|
|
2020-12-31 11:30:00 +05:30
|
|
|
|
2002-02-02 04:17:29 +05:30
|
|
|
/* sanitize a string via one-way mangle */
|
2004-11-05 02:20:59 +05:30
|
|
|
int escape_str(char *restrict dst, const char *restrict src, int bufsize, int *maxcells){
|
2002-02-02 04:17:29 +05:30
|
|
|
unsigned char c;
|
2004-11-05 02:20:59 +05:30
|
|
|
int my_cells = 0;
|
2002-12-21 18:37:53 +05:30
|
|
|
int my_bytes = 0;
|
2013-03-31 10:30:00 +05:30
|
|
|
|
2008-09-09 07:36:52 +05:30
|
|
|
#if (__GNU_LIBRARY__ >= 6) && (!defined(__UCLIBC__) || defined(__UCLIBC_HAS_WCHAR__))
|
2004-11-05 02:20:59 +05:30
|
|
|
static int utf_init=0;
|
2013-03-31 10:30:00 +05:30
|
|
|
|
2004-11-05 02:20:59 +05:30
|
|
|
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;
|
|
|
|
}
|
2011-05-18 14:03:44 +05:30
|
|
|
if (utf_init==1 && MB_CUR_MAX>1) {
|
2004-11-05 02:20:59 +05:30
|
|
|
/* UTF8 locales */
|
|
|
|
return escape_str_utf8(dst, src, bufsize, maxcells);
|
2011-05-18 14:03:44 +05:30
|
|
|
}
|
2004-11-05 02:20:59 +05:30
|
|
|
#endif
|
2013-03-31 10:30:00 +05:30
|
|
|
|
1970-01-01 05:30:00 +05:30
|
|
|
SECURE_ESCAPE_ARGS(dst, bufsize, *maxcells);
|
2004-11-05 02:20:59 +05:30
|
|
|
if(bufsize > *maxcells+1) bufsize=*maxcells+1; // FIXME: assumes 8-bit locale
|
2002-12-21 18:37:53 +05:30
|
|
|
|
|
|
|
for(;;){
|
2013-03-11 11:30:00 +05:30
|
|
|
if(my_cells >= *maxcells || my_bytes+1 >= bufsize)
|
2004-11-05 02:20:59 +05:30
|
|
|
break;
|
2002-02-02 04:17:29 +05:30
|
|
|
c = (unsigned char) *(src++);
|
2002-12-21 18:37:53 +05:30
|
|
|
if(!c) break;
|
2020-12-31 11:30:00 +05:30
|
|
|
if(ESC_tab[c]!='|') c=ESC_tab[c];
|
2004-11-05 02:20:59 +05:30
|
|
|
my_cells++;
|
2002-12-21 18:37:53 +05:30
|
|
|
my_bytes++;
|
|
|
|
*(dst++) = c;
|
2002-02-02 04:17:29 +05:30
|
|
|
}
|
2011-05-18 14:03:44 +05:30
|
|
|
*dst = '\0';
|
2013-03-31 10:30:00 +05:30
|
|
|
|
2004-11-05 02:20:59 +05:30
|
|
|
*maxcells -= my_cells;
|
2002-12-21 18:37:53 +05:30
|
|
|
return my_bytes; // bytes of text, excluding the NUL
|
2002-02-02 04:17:29 +05:30
|
|
|
}
|
|
|
|
|
2002-12-21 16:04:50 +05:30
|
|
|
/////////////////////////////////////////////////
|
2002-02-02 04:17:29 +05:30
|
|
|
|
2002-12-21 16:04:50 +05:30
|
|
|
// escape an argv or environment string array
|
|
|
|
//
|
|
|
|
// bytes arg means sizeof(buf)
|
2011-10-10 02:15:59 +05:30
|
|
|
int escape_strlist(char *restrict dst, char *restrict const *restrict src, size_t bytes, int *cells){
|
2002-02-02 04:17:29 +05:30
|
|
|
size_t i = 0;
|
2002-12-21 16:04:50 +05:30
|
|
|
|
1970-01-01 05:30:00 +05:30
|
|
|
SECURE_ESCAPE_ARGS(dst, bytes, *cells);
|
|
|
|
|
2002-12-21 16:04:50 +05:30
|
|
|
for(;;){
|
2004-11-05 02:20:59 +05:30
|
|
|
i += escape_str(dst+i, *src, bytes-i, cells);
|
2002-12-21 16:04:50 +05:30
|
|
|
if(bytes-i < 3) break; // need room for space, a character, and the NUL
|
2002-02-02 04:17:29 +05:30
|
|
|
src++;
|
2002-12-21 16:04:50 +05:30
|
|
|
if(!*src) break; // need something to print
|
2004-11-05 02:20:59 +05:30
|
|
|
if (*cells<=1) break; // need room for printed size of text
|
2002-12-21 16:04:50 +05:30
|
|
|
dst[i++] = ' ';
|
2004-11-05 02:20:59 +05:30
|
|
|
--*cells;
|
2002-02-02 04:17:29 +05:30
|
|
|
}
|
2004-11-05 02:20:59 +05:30
|
|
|
return i; // bytes, excluding the NUL
|
2002-12-21 16:04:50 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////
|
|
|
|
|
2004-11-05 02:20:59 +05:30
|
|
|
int escape_command(char *restrict const outbuf, const proc_t *restrict const pp, int bytes, int *cells, unsigned flags){
|
2004-07-15 06:47:15 +05:30
|
|
|
int overhead = 0;
|
2002-12-21 16:04:50 +05:30
|
|
|
int end = 0;
|
|
|
|
|
1970-01-01 05:30:00 +05:30
|
|
|
SECURE_ESCAPE_ARGS(outbuf, bytes, *cells);
|
|
|
|
|
2002-12-21 16:04:50 +05:30
|
|
|
if(flags & ESC_ARGS){
|
2011-10-10 02:15:59 +05:30
|
|
|
char **lc = (char**)pp->cmdline;
|
2004-11-05 02:20:59 +05:30
|
|
|
if(lc && *lc) return escape_strlist(outbuf, lc, bytes, cells);
|
2002-12-21 16:04:50 +05:30
|
|
|
}
|
|
|
|
if(flags & ESC_BRACKETS){
|
|
|
|
overhead += 2;
|
|
|
|
}
|
|
|
|
if(flags & ESC_DEFUNCT){
|
|
|
|
if(pp->state=='Z') overhead += 10; // chars in " <defunct>"
|
|
|
|
else flags &= ~ESC_DEFUNCT;
|
|
|
|
}
|
1970-01-01 05:30:00 +05:30
|
|
|
if(overhead + 1 >= *cells || // if no room for even one byte of the command name
|
|
|
|
overhead + 1 >= bytes){
|
|
|
|
outbuf[0] = '\0';
|
|
|
|
return 0;
|
2002-12-21 16:04:50 +05:30
|
|
|
}
|
|
|
|
if(flags & ESC_BRACKETS){
|
|
|
|
outbuf[end++] = '[';
|
|
|
|
}
|
2004-11-05 02:20:59 +05:30
|
|
|
*cells -= overhead;
|
|
|
|
end += escape_str(outbuf+end, pp->cmd, bytes-overhead, cells);
|
2002-12-21 16:04:50 +05:30
|
|
|
|
|
|
|
// 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';
|
2004-11-05 02:20:59 +05:30
|
|
|
return end; // bytes, not including the NUL
|
2002-02-02 04:17:29 +05:30
|
|
|
}
|
2011-05-18 14:03:44 +05:30
|
|
|
|
|
|
|
/////////////////////////////////////////////////
|
|
|
|
|
2020-12-26 11:30:00 +05:30
|
|
|
// copy a string, but 'escape' any control characters
|
2011-05-18 14:03:44 +05:30
|
|
|
// using the traditional escape.h calling conventions
|
|
|
|
int escaped_copy(char *restrict dst, const char *restrict src, int bufsize, int *maxroom){
|
2020-12-31 11:30:00 +05:30
|
|
|
static int utf_sw = 0;
|
2020-12-26 11:30:00 +05:30
|
|
|
int i, n;
|
2020-12-31 11:30:00 +05:30
|
|
|
char c;
|
1970-01-01 05:30:00 +05:30
|
|
|
|
2020-12-31 11:30:00 +05:30
|
|
|
if(utf_sw == 0){
|
|
|
|
char *enc = nl_langinfo(CODESET);
|
|
|
|
utf_sw = enc && strcasecmp(enc, "UTF-8")==0 ? 1 : -1;
|
|
|
|
}
|
1970-01-01 05:30:00 +05:30
|
|
|
SECURE_ESCAPE_ARGS(dst, bufsize, *maxroom);
|
2011-05-18 14:03:44 +05:30
|
|
|
if (bufsize > *maxroom+1) bufsize = *maxroom+1;
|
1970-01-01 05:30:00 +05:30
|
|
|
|
2011-05-18 14:03:44 +05:30
|
|
|
n = snprintf(dst, bufsize, "%s", src);
|
1970-01-01 05:30:00 +05:30
|
|
|
if (n < 0) {
|
|
|
|
*dst = '\0';
|
|
|
|
return 0;
|
|
|
|
}
|
2011-05-18 14:03:44 +05:30
|
|
|
if (n >= bufsize) n = bufsize-1;
|
2020-12-26 11:30:00 +05:30
|
|
|
|
2020-12-31 11:30:00 +05:30
|
|
|
if (utf_sw < 0) {
|
|
|
|
// if bad locale, replace the non-printing stuff
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
if ((c = ESC_tab[(unsigned char)dst[i]]) != '|')
|
|
|
|
dst[i] = c;
|
|
|
|
} else {
|
|
|
|
// or eliminate those non-printing control chars
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
if ((unsigned char)dst[i] < 0x20 || dst[i] == 0x7f)
|
|
|
|
dst[i] = '?';
|
|
|
|
}
|
2011-05-18 14:03:44 +05:30
|
|
|
*maxroom -= n;
|
|
|
|
return n;
|
|
|
|
}
|