Updated with Tizen:Base source codes
[external/procps.git] / proc / escape.c
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 <stdio.h>
12 #include <sys/types.h>
13 #include <string.h>
14 #include "procps.h"
15 #include "escape.h"
16 #include "readproc.h"
17
18 #if (__GNU_LIBRARY__ >= 6)
19 # include <wchar.h>
20 # include <wctype.h>
21 # include <stdlib.h>  /* MB_CUR_MAX */
22 # include <ctype.h>
23 # include <langinfo.h>
24 #endif
25
26 #if (__GNU_LIBRARY__ >= 6)
27 static int escape_str_utf8(char *restrict dst, const char *restrict src, int bufsize, int *maxcells){
28   int my_cells = 0;
29   int my_bytes = 0;
30   mbstate_t s;
31   
32   memset(&s, 0, sizeof (s));
33   
34   for(;;) {
35     wchar_t wc;
36     int len = 0;
37           
38     if(my_cells >= *maxcells || my_bytes+1 >= bufsize) 
39       break;
40     
41     if (!(len = mbrtowc (&wc, src, MB_CUR_MAX, &s)))
42       /* 'str' contains \0 */
43       break;
44     
45     if (len < 0) {
46       /* invalid multibyte sequence -- zeroize state */
47       memset (&s, 0, sizeof (s));
48       *(dst++) = '?';
49       src++;
50       my_cells++; 
51       my_bytes++;
52
53     } else if (len==1) {
54       /* non-multibyte */
55       *(dst++) = isprint(*src) ? *src : '?';
56       src++;
57       my_cells++;
58       my_bytes++;
59       
60     } else if (!iswprint(wc)) {
61       /* multibyte - no printable */
62       *(dst++) = '?';
63       src+=len;
64       my_cells++;
65       my_bytes++; 
66     
67     } else {
68       /* multibyte - printable */       
69       int wlen = wcwidth(wc);
70
71       if (wlen==0) {
72         // invisible multibyte -- we don't ignore it, because some terminal 
73         // interpret it wrong and more safe is replace it with '?'
74         *(dst++) = '?';
75         src+=len;
76         my_cells++;
77         my_bytes++;
78       } else {
79         // multibyte - printable
80         // Got space?
81         if (my_cells+wlen > *maxcells || my_bytes+1+len >= bufsize) break;
82         // 0x9b is control byte for some terminals
83         if (memchr(src, 0x9B, len)) {
84           // unsafe multibyte
85           *(dst++) = '?';
86           src+=len;
87           my_cells++;
88           my_bytes++;
89         } else {
90           // safe multibyte
91           memcpy(dst, src, len);
92           my_cells += wlen;
93           dst += len;
94           my_bytes += len;
95           src += len;
96         }
97       }
98     }
99     //fprintf(stdout, "cells: %d\n", my_cells);
100   }
101   *(dst++) = '\0';
102
103   // fprintf(stderr, "maxcells: %d, my_cells; %d\n", *maxcells, my_cells);
104   
105   *maxcells -= my_cells;
106   return my_bytes;        // bytes of text, excluding the NUL
107 }
108
109 #endif /* __GNU_LIBRARY__  */
110
111 /* sanitize a string via one-way mangle */
112 int escape_str(char *restrict dst, const char *restrict src, int bufsize, int *maxcells){
113   unsigned char c;
114   int my_cells = 0;
115   int my_bytes = 0;
116   const char codes[] =
117   "Z-------------------------------"
118   "********************************"
119   "********************************"
120   "*******************************-"
121   "--------------------------------"
122   "********************************"
123   "********************************"
124   "********************************";
125   
126 #if (__GNU_LIBRARY__ >= 6)
127   static int utf_init=0;
128   
129   if(utf_init==0){
130      /* first call -- check if UTF stuff is usable */
131      char *enc = nl_langinfo(CODESET);
132      utf_init = enc && strcasecmp(enc, "UTF-8")==0 ? 1 : -1;
133   }
134   if (utf_init==1)
135      /* UTF8 locales */
136      return escape_str_utf8(dst, src, bufsize, maxcells);
137 #endif
138                   
139   if(bufsize > *maxcells+1) bufsize=*maxcells+1; // FIXME: assumes 8-bit locale
140
141   for(;;){
142     if(my_cells >= *maxcells || my_bytes+1 >= bufsize) 
143       break;
144     c = (unsigned char) *(src++);
145     if(!c) break;
146     if(codes[c]=='-') c='?';
147     my_cells++;
148     my_bytes++;
149     *(dst++) = c;
150   }
151   *(dst++) = '\0';
152   
153   *maxcells -= my_cells;
154   return my_bytes;        // bytes of text, excluding the NUL
155 }
156
157 /////////////////////////////////////////////////
158
159 // escape an argv or environment string array
160 //
161 // bytes arg means sizeof(buf)
162 int escape_strlist(char *restrict dst, const char *restrict const *restrict src, size_t bytes, int *cells){
163   size_t i = 0;
164
165   for(;;){
166     i += escape_str(dst+i, *src, bytes-i, cells);
167     if(bytes-i < 3) break;  // need room for space, a character, and the NUL
168     src++;
169     if(!*src) break;  // need something to print
170     if (*cells<=1) break;  // need room for printed size of text
171     dst[i++] = ' ';
172     --*cells;
173   }
174   return i;    // bytes, excluding the NUL
175 }
176
177 ///////////////////////////////////////////////////
178
179 int escape_command(char *restrict const outbuf, const proc_t *restrict const pp, int bytes, int *cells, unsigned flags){
180   int overhead = 0;
181   int end = 0;
182
183   if(flags & ESC_ARGS){
184     const char **lc = (const char**)pp->cmdline;
185     if(lc && *lc) return escape_strlist(outbuf, lc, bytes, cells);
186   }
187   if(flags & ESC_BRACKETS){
188     overhead += 2;
189   }
190   if(flags & ESC_DEFUNCT){
191     if(pp->state=='Z') overhead += 10;    // chars in " <defunct>"
192     else flags &= ~ESC_DEFUNCT;
193   }
194   if(overhead + 1 >= *cells){  // if no room for even one byte of the command name
195     // you'd damn well better have _some_ space
196 //    outbuf[0] = '-';  // Oct23
197     outbuf[1] = '\0';
198     return 1;
199   }
200   if(flags & ESC_BRACKETS){
201     outbuf[end++] = '[';
202   }
203   *cells -= overhead;
204   end += escape_str(outbuf+end, pp->cmd, bytes-overhead, cells);
205
206   // Hmmm, do we want "[foo] <defunct>" or "[foo <defunct>]"?
207   if(flags & ESC_BRACKETS){
208     outbuf[end++] = ']';
209   }
210   if(flags & ESC_DEFUNCT){
211     memcpy(outbuf+end, " <defunct>", 10);
212     end += 10;
213   }
214   outbuf[end] = '\0';
215   return end;  // bytes, not including the NUL
216 }