1 /*----------------------------------------------------------------------*
2  * File:	misc.C
3  *----------------------------------------------------------------------*
4  *
5  * All portions of code are copyright by their respective author/s.
6  * Copyright (c) 1996      mj olesen <olesen@me.QueensU.CA> Queen's Univ at Kingston
7  * Copyright (c) 1997,1998 Oezguer Kesim <kesim@math.fu-berlin.de>
8  * Copyright (c) 1998-2000 Geoff Wing <gcw@pobox.com>
9  * Copyright (c) 2003-2006 Marc Lehmann <schmorp@schmorp.de>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  *----------------------------------------------------------------------*/
25 
26 #include "../config.h"		/* NECESSARY */
27 #include "rxvt.h"		/* NECESSARY */
28 
29 #include <new>
30 
31 // alas new/delete cannot be specified as inline in C++11 (see 17.6.4.6)
32 void *
new(size_t s)33 operator new (size_t s)
34 {
35   return rxvt_malloc (s);
36 }
37 
38 void
delete(void * p)39 operator delete (void *p) noexcept
40 {
41   free (p);
42 }
43 
44 char *
rxvt_wcstombs(const wchar_t * str,int len)45 rxvt_wcstombs (const wchar_t *str, int len)
46 {
47   if (len < 0) len = wcslen (str);
48 
49   mbstate mbs;
50   char *r = (char *)rxvt_malloc (len * MB_CUR_MAX + 1);
51 
52   char *dst = r;
53   while (len--)
54     {
55       ssize_t l = wcrtomb (dst, *str++, mbs);
56 
57       if (l < 0)
58         {
59           *dst++ = '?';
60           wcrtomb (0, 0, mbs); // reset undefined state
61         }
62       else
63         dst += l;
64     }
65 
66   *dst++ = 0;
67 
68   return (char *)rxvt_realloc (r, dst - r);
69 }
70 
71 wchar_t *
rxvt_mbstowcs(const char * str,int len)72 rxvt_mbstowcs (const char *str, int len)
73 {
74   if (len < 0) len = strlen (str);
75 
76   wchar_t *r = (wchar_t *)rxvt_malloc ((len + 1) * sizeof (wchar_t));
77 
78   if ((ssize_t)mbstowcs (r, str, len + 1) < 0)
79     *r = 0;
80 
81   return r;
82 }
83 
84 char *
rxvt_wcstoutf8(const wchar_t * str,int len)85 rxvt_wcstoutf8 (const wchar_t *str, int len)
86 {
87   if (len < 0) len = wcslen (str);
88 
89   char *r = (char *)rxvt_malloc (len * 4 + 1);
90   char *p = r;
91 
92   while (len--)
93     {
94       unicode_t w = *str++ & UNICODE_MASK;
95 
96       if      (w < 0x000080)
97         *p++ = w;
98       else if (w < 0x000800)
99         *p++ = 0xc0 | ( w >>  6),
100         *p++ = 0x80 | ( w        & 0x3f);
101       else if (w < 0x010000)
102         *p++ = 0xe0 | ( w >> 12),
103         *p++ = 0x80 | ((w >>  6) & 0x3f),
104         *p++ = 0x80 | ( w        & 0x3f);
105       else if (w < 0x110000)
106         *p++ = 0xf0 | ( w >> 18),
107         *p++ = 0x80 | ((w >> 12) & 0x3f),
108         *p++ = 0x80 | ((w >>  6) & 0x3f),
109         *p++ = 0x80 | ( w        & 0x3f);
110       else
111         *p++ = '?';
112     }
113 
114   *p++ = 0;
115 
116   return (char *)rxvt_realloc (r, p - r);
117 }
118 
119 wchar_t *
rxvt_utf8towcs(const char * str,int len)120 rxvt_utf8towcs (const char *str, int len)
121 {
122   if (len < 0) len = strlen (str);
123 
124   wchar_t *r = (wchar_t *)rxvt_malloc ((len + 1) * sizeof (wchar_t)),
125           *p = r;
126 
127   unsigned char *s = (unsigned char *)str,
128                 *e = s + len;
129 
130   for (;;)
131     {
132       len = e - s;
133 
134       if (len == 0)
135         break;
136       else if (s[0] < 0x80)
137         *p++ = *s++;
138       else if (len >= 2
139                && s[0] >= 0xc2 && s[0] <= 0xdf
140                && (s[1] & 0xc0) == 0x80)
141         {
142           *p++ = ((s[0] & 0x1f) << 6)
143                |  (s[1] & 0x3f);
144           s += 2;
145         }
146       else if (len >= 3
147                && (   (s[0] == 0xe0                 && s[1] >= 0xa0 && s[1] <= 0xbf)
148                    || (s[0] >= 0xe1 && s[0] <= 0xec && s[1] >= 0x80 && s[1] <= 0xbf)
149                    || (s[0] == 0xed                 && s[1] >= 0x80 && s[1] <= 0x9f)
150                    || (s[0] >= 0xee && s[0] <= 0xef && s[1] >= 0x80 && s[1] <= 0xbf)
151                   )
152                && (s[2] & 0xc0) == 0x80)
153         {
154           *p++ = ((s[0] & 0x0f) << 12)
155                | ((s[1] & 0x3f) <<  6)
156                |  (s[2] & 0x3f);
157           s += 3;
158         }
159       else if (len >= 4
160                && (   (s[0] == 0xf0                 && s[1] >= 0x90 && s[1] <= 0xbf)
161                    || (s[0] >= 0xf1 && s[0] <= 0xf3 && s[1] >= 0x80 && s[1] <= 0xbf)
162                    || (s[0] == 0xf4                 && s[1] >= 0x80 && s[1] <= 0x8f)
163                   )
164                && (s[2] & 0xc0) == 0x80
165                && (s[3] & 0xc0) == 0x80)
166         {
167           *p++ = ((s[0] & 0x07) << 18)
168                | ((s[1] & 0x3f) << 12)
169                | ((s[2] & 0x3f) <<  6)
170                |  (s[3] & 0x3f);
171           s += 4;
172         }
173       else
174         {
175           *p++ = 0xfffd;
176           s++;
177         }
178     }
179 
180   *p = 0;
181 
182   return r;
183 }
184 
185 const char *
rxvt_basename(const char * str)186 rxvt_basename (const char *str) noexcept
187 {
188   const char *base = strrchr (str, '/');
189 
190   return base ? base + 1 : str;
191 }
192 
193 /*
194  * Print an error message
195  */
196 void
rxvt_vlog(const char * fmt,va_list arg_ptr)197 rxvt_vlog (const char *fmt, va_list arg_ptr) noexcept
198 {
199   char msg[1024];
200 
201   vsnprintf (msg, sizeof msg, fmt, arg_ptr);
202 
203   if (GET_R && GET_R->log_hook)
204     (*GET_R->log_hook) (msg);
205   else
206     write (STDOUT_FILENO, msg, strlen (msg));
207 }
208 
209 void
rxvt_log(const char * fmt,...)210 rxvt_log (const char *fmt,...) noexcept
211 {
212   va_list arg_ptr;
213 
214   va_start (arg_ptr, fmt);
215   rxvt_vlog (fmt, arg_ptr);
216   va_end (arg_ptr);
217 }
218 
219 /*
220  * Print an error message
221  */
222 void
rxvt_warn(const char * fmt,...)223 rxvt_warn (const char *fmt,...) noexcept
224 {
225   va_list arg_ptr;
226 
227   rxvt_log ("%s: ", RESNAME);
228 
229   va_start (arg_ptr, fmt);
230   rxvt_vlog (fmt, arg_ptr);
231   va_end (arg_ptr);
232 }
233 
234 void
rxvt_fatal(const char * fmt,...)235 rxvt_fatal (const char *fmt,...)
236 {
237   va_list arg_ptr;
238 
239   rxvt_log ("%s: ", RESNAME);
240 
241   va_start (arg_ptr, fmt);
242   rxvt_vlog (fmt, arg_ptr);
243   va_end (arg_ptr);
244 
245   rxvt_exit_failure ();
246 }
247 
248 void
rxvt_exit_failure()249 rxvt_exit_failure ()
250 {
251   static class rxvt_failure_exception rxvt_failure_exception;
252   throw (rxvt_failure_exception);
253 }
254 
255 /*
256  * remove leading/trailing space in place.
257  */
258 char *
rxvt_strtrim(char * str)259 rxvt_strtrim (char *str) noexcept
260 {
261   char *r, *s;
262 
263   if (!str || !*str)		/* shortcut */
264     return str;
265 
266   /* skip leading spaces */
267   for (s = str; *s && isspace (*s); s++) ;
268 
269   /* goto end of string */
270   r = s + strlen (s) - 1;
271 
272   /* dump return and other trailing whitespace */
273   while (r > s && isspace (*r))
274     r--;
275 
276   memmove (str, s, r + 1 - s);
277   str[r + 1 - s] = 0;
278 
279   return str;
280 }
281 
282 /*
283  * Split a string into an array based on the given delimiter, stripping leading and
284  * trailing spaces from each entry.  Empty strings are properly returned
285  */
286 char **
rxvt_strsplit(char delim,const char * str)287 rxvt_strsplit (char delim, const char *str) noexcept
288 {
289   int l, n;
290   char *s, *t;
291   char **ret;
292 
293   s = strdup (str ? str : "");
294 
295   for (n = 1, t = s; *t; t++)
296     if (*t == delim)
297       n++;
298 
299   ret = (char **)malloc ((n + 1) * sizeof (char *));
300   ret[n] = NULL;
301 
302   for (l = 0, t = s; l < n; l++)
303     {
304       for (; *t && *t != delim; t++)
305         ;
306       *t = '\0';
307       ret[l] = s;
308       rxvt_strtrim (ret[l]);
309       s = ++t;
310     }
311 
312   return ret;
313 }
314 
315 void *
rxvt_malloc(size_t size)316 rxvt_malloc (size_t size)
317 {
318   void *p = malloc (size);
319 
320   if (!p)
321     rxvt_fatal ("memory allocation failure. aborting.\n");
322 
323   return p;
324 }
325 
326 void *
rxvt_calloc(size_t number,size_t size)327 rxvt_calloc (size_t number, size_t size)
328 {
329   void *p = calloc (number, size);
330 
331   if (!p)
332     rxvt_fatal ("memory allocation failure. aborting.\n");
333 
334   return p;
335 }
336 
337 void *
rxvt_realloc(void * ptr,size_t size)338 rxvt_realloc (void *ptr, size_t size)
339 {
340   void *p = realloc (ptr, size);
341 
342   if (!p)
343     rxvt_fatal ("memory allocation failure. aborting.\n");
344 
345   return p;
346 }
347 
348 KeySym
rxvt_XKeycodeToKeysym(Display * dpy,KeyCode code,int index)349 rxvt_XKeycodeToKeysym (Display *dpy, KeyCode code, int index)
350 {
351   int size;
352   KeySym *mapping = XGetKeyboardMapping (dpy, code, 1, &size);
353   KeySym keysym = IN_RANGE_EXC (index, 0, size) ? mapping[index] : NoSymbol;
354   XFree (mapping);
355   return keysym;
356 }
357