ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/misc.C
Revision: 1.27
Committed: Wed Feb 16 21:37:10 2005 UTC (19 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-5_5, rel-5_4, rel-5_7, rel-5_3, rel-5_2
Changes since 1.26: +0 -15 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 pcg 1.1 /*--------------------------------*-C-*---------------------------------*
2 pcg 1.13 * File: misc.C
3 pcg 1.1 *----------------------------------------------------------------------*
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 pcg 1.8 * Copyright (c) 2003-2004 Marc Lehmann <pcg@goof.com>
10 pcg 1.1 *
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 2 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 pcg 1.3 char *
30 pcg 1.10 rxvt_wcstombs (const wchar_t *str, int len)
31     {
32 root 1.19 if (len < 0) len = wcslen (str);
33    
34 pcg 1.10 mbstate mbs;
35     char *r = (char *)rxvt_malloc (len * MB_CUR_MAX + 1);
36    
37     char *dst = r;
38     while (len--)
39     {
40 root 1.24 ssize_t l = wcrtomb (dst, *str++, mbs);
41 pcg 1.10 if (l < 0)
42     *dst++ = '?';
43     else
44     dst += l;
45     }
46    
47     *dst++ = 0;
48    
49 root 1.24 return (char *)rxvt_realloc (r, dst - r);
50 pcg 1.10 }
51    
52 root 1.19 wchar_t *
53     rxvt_mbstowcs (const char *str, int len)
54     {
55     if (len < 0) len = strlen (str);
56    
57     wchar_t *r = (wchar_t *)rxvt_malloc ((len + 1) * sizeof (wchar_t));
58    
59 root 1.24 if ((ssize_t)mbstowcs (r, str, len + 1) < 0)
60 root 1.19 *r = 0;
61    
62     return r;
63     }
64    
65     char *
66     rxvt_wcstoutf8 (const wchar_t *str, int len)
67     {
68     if (len < 0) len = wcslen (str);
69    
70     char *r = (char *)rxvt_malloc (len * 4 + 1);
71     char *p = r;
72    
73     while (len--)
74     {
75 root 1.22 unicode_t w = *str++ & UNICODE_MASK;
76 root 1.19
77     if (w < 0x000080)
78     *p++ = w;
79     else if (w < 0x000800)
80     *p++ = 0xc0 | ( w >> 6),
81     *p++ = 0x80 | ( w & 0x3f);
82     else if (w < 0x010000)
83     *p++ = 0xe0 | ( w >> 12 ),
84     *p++ = 0x80 | ((w >> 6) & 0x3f),
85     *p++ = 0x80 | ( w & 0x3f);
86     else if (w < 0x110000)
87     *p++ = 0xf0 | ( w >> 18),
88     *p++ = 0x80 | ((w >> 12) & 0x3f),
89     *p++ = 0x80 | ((w >> 6) & 0x3f),
90     *p++ = 0x80 | ( w & 0x3f);
91     else
92     *p++ = '?';
93     }
94    
95 root 1.24 *p++ = 0;
96 root 1.19
97 root 1.24 return (char *)rxvt_realloc (r, p - r);
98 root 1.19 }
99    
100     wchar_t *
101     rxvt_utf8towcs (const char *str, int len)
102     {
103     if (len < 0) len = strlen (str);
104    
105 root 1.21 wchar_t *r = (wchar_t *)rxvt_malloc ((len + 1) * sizeof (wchar_t)),
106     *p = r;
107 root 1.19
108 root 1.21 unsigned char *s = (unsigned char *)str,
109     *e = s + len;
110 root 1.19
111 root 1.21 for (;;)
112 root 1.19 {
113 root 1.21 len = e - s;
114    
115     if (len == 0)
116     break;
117     else if (s[0] < 0x80)
118     *p++ = *s++;
119     else if (len >= 2
120 root 1.19 && s[0] >= 0xc2 && s[0] <= 0xdf
121     && (s[1] & 0xc0) == 0x80)
122     {
123     *p++ = ((s[0] & 0x1f) << 6)
124     | (s[1] & 0x3f);
125 root 1.21 s += 2;
126 root 1.19 }
127 root 1.21 else if (len >= 3
128 root 1.19 && ( (s[0] == 0xe0 && s[1] >= 0xa0 && s[1] <= 0xbf)
129     || (s[0] >= 0xe1 && s[0] <= 0xec && s[1] >= 0x80 && s[1] <= 0xbf)
130     || (s[0] == 0xed && s[1] >= 0x80 && s[1] <= 0x9f)
131     || (s[0] >= 0xee && s[0] <= 0xef && s[1] >= 0x80 && s[1] <= 0xbf)
132     )
133     && (s[2] & 0xc0) == 0x80)
134     {
135     *p++ = ((s[0] & 0x0f) << 12)
136     | ((s[1] & 0x3f) << 6)
137     | (s[2] & 0x3f);
138 root 1.21 s += 3;
139 root 1.19 }
140 root 1.21 else if (len >= 4
141 root 1.19 && ( (s[0] == 0xf0 && s[1] >= 0x90 && s[1] <= 0xbf)
142     || (s[0] >= 0xf1 && s[0] <= 0xf3 && s[1] >= 0x80 && s[1] <= 0xbf)
143     || (s[0] == 0xf4 && s[1] >= 0x80 && s[1] <= 0x8f)
144     )
145     && (s[2] & 0xc0) == 0x80
146     && (s[3] & 0xc0) == 0x80)
147     {
148     *p++ = ((s[0] & 0x07) << 18)
149     | ((s[1] & 0x3f) << 12)
150     | ((s[2] & 0x3f) << 6)
151     | (s[3] & 0x3f);
152 root 1.21 s += 4;
153 root 1.19 }
154     else
155     {
156     *p++ = 0xfffd;
157 root 1.21 s++;
158 root 1.19 }
159     }
160    
161     *p = 0;
162    
163     return r;
164     }
165    
166 pcg 1.10 char *
167 pcg 1.3 rxvt_strdup (const char *str)
168     {
169     return str ? strdup (str) : 0;
170     }
171    
172 pcg 1.8 char *
173 pcg 1.7 rxvt_r_basename (const char *str)
174 pcg 1.1 {
175 root 1.15 char *base = strrchr (str, '/');
176 pcg 1.1
177 pcg 1.7 return (char *) (base ? base + 1 : str);
178 pcg 1.1 }
179    
180     /*
181     * Print an error message
182     */
183     void
184 pcg 1.12 rxvt_vlog (const char *fmt, va_list arg_ptr)
185     {
186     char msg[1024];
187    
188     vsnprintf (msg, sizeof msg, fmt, arg_ptr);
189    
190     if (GET_R && GET_R->log_hook)
191     (*GET_R->log_hook) (msg);
192     else
193     write (STDOUT_FILENO, msg, strlen (msg));
194     }
195    
196     void
197     rxvt_log (const char *fmt,...)
198 pcg 1.1 {
199 pcg 1.8 va_list arg_ptr;
200 pcg 1.1
201 pcg 1.7 va_start (arg_ptr, fmt);
202 pcg 1.12 rxvt_vlog (fmt, arg_ptr);
203 pcg 1.7 va_end (arg_ptr);
204 pcg 1.1 }
205    
206     /*
207 pcg 1.12 * Print an error message
208     */
209     void
210     rxvt_warn (const char *fmt,...)
211     {
212     va_list arg_ptr;
213    
214     rxvt_log ("%s: ", RESNAME);
215    
216     va_start (arg_ptr, fmt);
217     rxvt_vlog (fmt, arg_ptr);
218     va_end (arg_ptr);
219     }
220    
221     void
222     rxvt_fatal (const char *fmt,...)
223     {
224     va_list arg_ptr;
225    
226     rxvt_log ("%s: ", RESNAME);
227    
228     va_start (arg_ptr, fmt);
229     rxvt_vlog (fmt, arg_ptr);
230     va_end (arg_ptr);
231    
232     rxvt_exit_failure ();
233     }
234    
235     class rxvt_failure_exception rxvt_failure_exception;
236    
237     void
238     rxvt_exit_failure ()
239     {
240     throw (rxvt_failure_exception);
241     }
242    
243     /*
244 pcg 1.1 * check that the first characters of S1 match S2
245     *
246     * No Match
247     * return: 0
248     * Match
249 root 1.15 * return: strlen (S2)
250 pcg 1.1 */
251     int
252 pcg 1.7 rxvt_Str_match (const char *s1, const char *s2)
253 pcg 1.1 {
254 root 1.15 int n = strlen (s2);
255 pcg 1.1
256 root 1.15 return ((strncmp (s1, s2, n) == 0) ? n : 0);
257 pcg 1.1 }
258    
259 pcg 1.8 const char *
260 pcg 1.7 rxvt_Str_skip_space (const char *str)
261 pcg 1.1 {
262 pcg 1.5 if (str)
263 pcg 1.7 while (*str && isspace (*str))
264 pcg 1.5 str++;
265 pcg 1.8
266 pcg 1.5 return str;
267 pcg 1.1 }
268    
269     /*
270     * remove leading/trailing space and strip-off leading/trailing quotes.
271     * in place.
272     */
273     char *
274 pcg 1.7 rxvt_Str_trim (char *str)
275 pcg 1.1 {
276 pcg 1.8 char *r, *s;
277 pcg 1.1
278 pcg 1.5 if (!str || !*str) /* shortcut */
279     return str;
280 pcg 1.1
281 pcg 1.5 /* skip leading spaces */
282 pcg 1.7 for (s = str; *s && isspace (*s); s++) ;
283 root 1.25
284 pcg 1.5 /* goto end of string */
285 root 1.25 r = s + strlen (s) - 1;
286    
287     /* dump return and other trailing whitespace */
288     while (r > s && isspace (*r))
289     r--;
290    
291     #if 0
292 pcg 1.5 /* skip matching leading/trailing quotes */
293     if (*s == '"' && *r == '"' && n > 1)
294     {
295     s++;
296     n -= 2;
297 pcg 1.1 }
298 root 1.25 #endif
299 pcg 1.8
300 root 1.25 memmove (str, s, r + 1 - s);
301     str[r + 1 - s] = 0;
302 pcg 1.1
303 pcg 1.5 return str;
304 pcg 1.1 }
305    
306     /*
307     * in-place interpretation of string:
308     *
309     * backslash-escaped: "\a\b\E\e\n\r\t", "\octal"
310     * Ctrl chars: ^@ .. ^_, ^?
311     *
312     * Emacs-style: "M-" prefix
313     *
314     * Also,
315     * "M-x" prefixed strings, append "\r" if needed
316     * "\E]" prefixed strings (XTerm escape sequence) append ST if needed
317     *
318     * returns the converted string length
319     */
320     int
321 pcg 1.7 rxvt_Str_escaped (char *str)
322 pcg 1.1 {
323 pcg 1.5 char ch, *s, *d;
324     int i, num, append = 0;
325 pcg 1.1
326 pcg 1.5 if (!str || !*str)
327     return 0;
328 pcg 1.1
329 pcg 1.5 d = s = str;
330 pcg 1.1
331 pcg 1.5 if (*s == 'M' && s[1] == '-')
332     {
333     /* Emacs convenience, replace leading `M-..' with `\E..' */
334     *d++ = C0_ESC;
335     s += 2;
336 pcg 1.7 if (toupper (*s) == 'X')
337 pcg 1.5 /* append carriage-return for `M-xcommand' */
338 pcg 1.7 for (*d++ = 'x', append = '\r', s++; isspace (*s); s++) ;
339 pcg 1.1 }
340 pcg 1.5 for (; (ch = *s++);)
341     {
342     if (ch == '\\')
343     {
344     ch = *s++;
345     if (ch >= '0' && ch <= '7')
346     { /* octal */
347     num = ch - '0';
348     for (i = 0; i < 2; i++, s++)
349     {
350     ch = *s;
351     if (ch < '0' || ch > '7')
352     break;
353     num = num * 8 + ch - '0';
354     }
355     ch = (char)num;
356     }
357     else if (ch == 'a')
358     ch = C0_BEL; /* bell */
359     else if (ch == 'b')
360     ch = C0_BS; /* backspace */
361     else if (ch == 'E' || ch == 'e')
362     ch = C0_ESC; /* escape */
363     else if (ch == 'n')
364     ch = '\n'; /* newline */
365     else if (ch == 'r')
366     ch = '\r'; /* carriage-return */
367     else if (ch == 't')
368     ch = C0_HT; /* tab */
369     }
370     else if (ch == '^')
371     {
372     ch = *s++;
373 pcg 1.7 ch = toupper (ch);
374 pcg 1.5 ch = (ch == '?' ? 127 : (ch - '@'));
375     }
376     *d++ = ch;
377 pcg 1.1 }
378    
379 pcg 1.5 /* ESC] is an XTerm escape sequence, must be terminated */
380     if (*str == '\0' && str[1] == C0_ESC && str[2] == ']')
381     append = CHAR_ST;
382    
383     /* add trailing character as required */
384     if (append && d[-1] != append)
385     *d++ = append;
386     *d = '\0';
387 pcg 1.1
388 pcg 1.5 return (d - str);
389 pcg 1.1 }
390    
391     /*
392     * Split a comma-separated string into an array, stripping leading and
393 root 1.25 * trailing spaces from each entry. Empty strings are properly returned
394 pcg 1.1 * Caller should free each entry and array when done
395     */
396     char **
397 pcg 1.7 rxvt_splitcommastring (const char *cs)
398 pcg 1.1 {
399 pcg 1.5 int l, n, p;
400     const char *s, *t;
401     char **ret;
402    
403     if ((s = cs) == NULL)
404     s = "";
405    
406     for (n = 1, t = s; *t; t++)
407     if (*t == ',')
408     n++;
409 root 1.25
410 pcg 1.7 ret = (char **)malloc ((n + 1) * sizeof (char *));
411 pcg 1.5 ret[n] = NULL;
412    
413     for (l = 0, t = s; l < n; l++)
414     {
415     for ( ; *t && *t != ','; t++) ;
416     p = t - s;
417 pcg 1.7 ret[l] = (char *)malloc (p + 1);
418     strncpy (ret[l], s, p);
419 pcg 1.5 ret[l][p] = '\0';
420 pcg 1.7 rxvt_Str_trim (ret[l]);
421 pcg 1.5 s = ++t;
422 pcg 1.1 }
423 root 1.25
424 pcg 1.5 return ret;
425 pcg 1.1 }
426    
427 root 1.16 void
428     rxvt_freecommastring (char **cs)
429     {
430     for (int i = 0; cs[i]; ++i)
431     free (cs[i]);
432    
433     free (cs);
434     }
435    
436 pcg 1.1 /*----------------------------------------------------------------------*
437     * file searching
438     */
439    
440     /* #define DEBUG_SEARCH_PATH */
441    
442     #if defined (XPM_BACKGROUND) || (MENUBAR_MAX)
443     /*
444     * search for FILE in the current working directory, and within the
445     * colon-delimited PATHLIST, adding the file extension EXT if required.
446     *
447     * FILE is either semi-colon or zero terminated
448     */
449     char *
450 pcg 1.7 rxvt_File_search_path (const char *pathlist, const char *file, const char *ext)
451 pcg 1.1 {
452 pcg 1.5 int maxpath, len;
453     const char *p, *path;
454     char name[256];
455    
456 pcg 1.7 if (!access (file, R_OK)) /* found (plain name) in current directory */
457 root 1.15 return strdup (file);
458 pcg 1.5
459     /* semi-colon delimited */
460 root 1.15 if ((p = strchr (file, ';')))
461 pcg 1.5 len = (p - file);
462     else
463 root 1.15 len = strlen (file);
464 pcg 1.1
465     #ifdef DEBUG_SEARCH_PATH
466 pcg 1.7 getcwd (name, sizeof (name));
467     fprintf (stderr, "pwd: \"%s\"\n", name);
468     fprintf (stderr, "find: \"%.*s\"\n", len, file);
469 pcg 1.1 #endif
470    
471 pcg 1.5 /* leave room for an extra '/' and trailing '\0' */
472 root 1.15 maxpath = sizeof (name) - (len + (ext ? strlen (ext) : 0) + 2);
473 pcg 1.5 if (maxpath <= 0)
474     return NULL;
475    
476     /* check if we can find it now */
477 root 1.15 strncpy (name, file, len);
478 pcg 1.5 name[len] = '\0';
479    
480 pcg 1.7 if (!access (name, R_OK))
481 root 1.15 return strdup (name);
482 pcg 1.5 if (ext)
483     {
484 root 1.15 strcat (name, ext);
485 pcg 1.7 if (!access (name, R_OK))
486 root 1.15 return strdup (name);
487 pcg 1.1 }
488 pcg 1.5 for (path = pathlist; path != NULL && *path != '\0'; path = p)
489     {
490     int n;
491    
492     /* colon delimited */
493 root 1.15 if ((p = strchr (path, ':')) == NULL)
494     p = strchr (path, '\0');
495 pcg 1.5
496     n = (p - path);
497     if (*p != '\0')
498     p++;
499    
500     if (n > 0 && n <= maxpath)
501     {
502 root 1.15 strncpy (name, path, n);
503 pcg 1.5 if (name[n - 1] != '/')
504     name[n++] = '/';
505     name[n] = '\0';
506 root 1.15 strncat (name, file, len);
507 pcg 1.5
508 pcg 1.7 if (!access (name, R_OK))
509 root 1.15 return strdup (name);
510 pcg 1.5 if (ext)
511     {
512 root 1.15 strcat (name, ext);
513 pcg 1.7 if (!access (name, R_OK))
514 root 1.15 return strdup (name);
515 pcg 1.5 }
516     }
517 pcg 1.1 }
518 pcg 1.5 return NULL;
519 pcg 1.1 }
520    
521     char *
522 pcg 1.7 rxvt_File_find (const char *file, const char *ext, const char *path)
523 pcg 1.1 {
524 pcg 1.5 char *f;
525 pcg 1.1
526 pcg 1.5 if (file == NULL || *file == '\0')
527     return NULL;
528 pcg 1.1
529 pcg 1.5 /* search environment variables here too */
530 pcg 1.7 if ((f = rxvt_File_search_path (path, file, ext)) == NULL)
531 pcg 1.1 #ifdef PATH_ENV
532 pcg 1.7 if ((f = rxvt_File_search_path (getenv (PATH_ENV), file, ext)) == NULL)
533 pcg 1.1 #endif
534 pcg 1.7 f = rxvt_File_search_path (getenv ("PATH"), file, ext);
535 pcg 1.1
536     #ifdef DEBUG_SEARCH_PATH
537 pcg 1.5 if (f)
538 pcg 1.7 fprintf (stderr, "found: \"%s\"\n", f);
539 pcg 1.1 #endif
540    
541 pcg 1.5 return f;
542 pcg 1.1 }
543     #endif /* defined (XPM_BACKGROUND) || (MENUBAR_MAX) */
544    
545     /*----------------------------------------------------------------------*
546     * miscellaneous drawing routines
547     */
548    
549     /*
550     * Draw top/left and bottom/right border shadows around windows
551     */
552     #if defined(RXVT_SCROLLBAR) || defined(MENUBAR)
553     void
554 pcg 1.7 rxvt_Draw_Shadow (Display *display, Window win, GC topShadow, GC botShadow, int x, int y, int w, int h)
555 pcg 1.1 {
556 pcg 1.5 int shadow;
557 pcg 1.1
558 pcg 1.5 shadow = (w == 0 || h == 0) ? 1 : SHADOW;
559     w += x - 1;
560     h += y - 1;
561     for (; shadow-- > 0; x++, y++, w--, h--)
562     {
563 pcg 1.7 XDrawLine (display, win, topShadow, x, y, w, y);
564     XDrawLine (display, win, topShadow, x, y, x, h);
565     XDrawLine (display, win, botShadow, w, h, w, y + 1);
566     XDrawLine (display, win, botShadow, w, h, x + 1, h);
567 pcg 1.1 }
568     }
569     #endif
570    
571     /* button shapes */
572     #ifdef MENUBAR
573     void
574 pcg 1.7 rxvt_Draw_Triangle (Display *display, Window win, GC topShadow, GC botShadow, int x, int y, int w, int type)
575 pcg 1.1 {
576 pcg 1.5 switch (type)
577     {
578     case 'r': /* right triangle */
579 pcg 1.7 XDrawLine (display, win, topShadow, x, y, x, y + w);
580     XDrawLine (display, win, topShadow, x, y, x + w, y + w / 2);
581     XDrawLine (display, win, botShadow, x, y + w, x + w, y + w / 2);
582 pcg 1.5 break;
583    
584     case 'l': /* left triangle */
585 pcg 1.7 XDrawLine (display, win, botShadow, x + w, y + w, x + w, y);
586     XDrawLine (display, win, botShadow, x + w, y + w, x, y + w / 2);
587     XDrawLine (display, win, topShadow, x, y + w / 2, x + w, y);
588 pcg 1.5 break;
589    
590     case 'd': /* down triangle */
591 pcg 1.7 XDrawLine (display, win, topShadow, x, y, x + w / 2, y + w);
592     XDrawLine (display, win, topShadow, x, y, x + w, y);
593     XDrawLine (display, win, botShadow, x + w, y, x + w / 2, y + w);
594 pcg 1.5 break;
595    
596     case 'u': /* up triangle */
597 pcg 1.7 XDrawLine (display, win, botShadow, x + w, y + w, x + w / 2, y);
598     XDrawLine (display, win, botShadow, x + w, y + w, x, y + w);
599     XDrawLine (display, win, topShadow, x, y + w, x + w / 2, y);
600 pcg 1.5 break;
601 pcg 1.1 #if 0
602 pcg 1.5 case 's': /* square */
603 pcg 1.7 XDrawLine (display, win, topShadow, x + w, y, x, y);
604     XDrawLine (display, win, topShadow, x, y, x, y + w);
605     XDrawLine (display, win, botShadow, x, y + w, x + w, y + w);
606     XDrawLine (display, win, botShadow, x + w, y + w, x + w, y);
607 pcg 1.5 break;
608 pcg 1.1 #endif
609 pcg 1.5
610 pcg 1.1 }
611     }
612     #endif
613     /*----------------------- end-of-file (C source) -----------------------*/