ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/misc.C
Revision: 1.26
Committed: Wed Feb 16 20:32:05 2005 UTC (19 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.25: +0 -1 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 root 1.15 /* INTPROTO */
173 pcg 1.8 char *
174 pcg 1.7 rxvt_r_basename (const char *str)
175 pcg 1.1 {
176 root 1.15 char *base = strrchr (str, '/');
177 pcg 1.1
178 pcg 1.7 return (char *) (base ? base + 1 : str);
179 pcg 1.1 }
180    
181     /*
182     * Print an error message
183     */
184 root 1.15 /* INTPROTO */
185 pcg 1.1 void
186 pcg 1.12 rxvt_vlog (const char *fmt, va_list arg_ptr)
187     {
188     char msg[1024];
189    
190     vsnprintf (msg, sizeof msg, fmt, arg_ptr);
191    
192     if (GET_R && GET_R->log_hook)
193     (*GET_R->log_hook) (msg);
194     else
195     write (STDOUT_FILENO, msg, strlen (msg));
196     }
197    
198 root 1.15 /* INTPROTO */
199 pcg 1.12 void
200     rxvt_log (const char *fmt,...)
201 pcg 1.1 {
202 pcg 1.8 va_list arg_ptr;
203 pcg 1.1
204 pcg 1.7 va_start (arg_ptr, fmt);
205 pcg 1.12 rxvt_vlog (fmt, arg_ptr);
206 pcg 1.7 va_end (arg_ptr);
207 pcg 1.1 }
208    
209     /*
210 pcg 1.12 * Print an error message
211     */
212 root 1.15 /* INTPROTO */
213 pcg 1.12 void
214     rxvt_warn (const char *fmt,...)
215     {
216     va_list arg_ptr;
217    
218     rxvt_log ("%s: ", RESNAME);
219    
220     va_start (arg_ptr, fmt);
221     rxvt_vlog (fmt, arg_ptr);
222     va_end (arg_ptr);
223     }
224    
225 root 1.15 /* INTPROTO */
226 pcg 1.12 void
227     rxvt_fatal (const char *fmt,...)
228     {
229     va_list arg_ptr;
230    
231     rxvt_log ("%s: ", RESNAME);
232    
233     va_start (arg_ptr, fmt);
234     rxvt_vlog (fmt, arg_ptr);
235     va_end (arg_ptr);
236    
237     rxvt_exit_failure ();
238     }
239    
240     class rxvt_failure_exception rxvt_failure_exception;
241    
242 root 1.15 /* INTPROTO */
243 pcg 1.12 void
244     rxvt_exit_failure ()
245     {
246     throw (rxvt_failure_exception);
247     }
248    
249     /*
250 pcg 1.1 * check that the first characters of S1 match S2
251     *
252     * No Match
253     * return: 0
254     * Match
255 root 1.15 * return: strlen (S2)
256 pcg 1.1 */
257 root 1.15 /* INTPROTO */
258 pcg 1.1 int
259 pcg 1.7 rxvt_Str_match (const char *s1, const char *s2)
260 pcg 1.1 {
261 root 1.15 int n = strlen (s2);
262 pcg 1.1
263 root 1.15 return ((strncmp (s1, s2, n) == 0) ? n : 0);
264 pcg 1.1 }
265    
266 root 1.15 /* INTPROTO */
267 pcg 1.8 const char *
268 pcg 1.7 rxvt_Str_skip_space (const char *str)
269 pcg 1.1 {
270 pcg 1.5 if (str)
271 pcg 1.7 while (*str && isspace (*str))
272 pcg 1.5 str++;
273 pcg 1.8
274 pcg 1.5 return str;
275 pcg 1.1 }
276    
277     /*
278     * remove leading/trailing space and strip-off leading/trailing quotes.
279     * in place.
280     */
281 root 1.15 /* INTPROTO */
282 pcg 1.1 char *
283 pcg 1.7 rxvt_Str_trim (char *str)
284 pcg 1.1 {
285 pcg 1.8 char *r, *s;
286 pcg 1.1
287 pcg 1.5 if (!str || !*str) /* shortcut */
288     return str;
289 pcg 1.1
290 pcg 1.5 /* skip leading spaces */
291 pcg 1.7 for (s = str; *s && isspace (*s); s++) ;
292 root 1.25
293 pcg 1.5 /* goto end of string */
294 root 1.25 r = s + strlen (s) - 1;
295    
296     /* dump return and other trailing whitespace */
297     while (r > s && isspace (*r))
298     r--;
299    
300     #if 0
301 pcg 1.5 /* skip matching leading/trailing quotes */
302     if (*s == '"' && *r == '"' && n > 1)
303     {
304     s++;
305     n -= 2;
306 pcg 1.1 }
307 root 1.25 #endif
308 pcg 1.8
309 root 1.25 memmove (str, s, r + 1 - s);
310     str[r + 1 - s] = 0;
311 pcg 1.1
312 pcg 1.5 return str;
313 pcg 1.1 }
314    
315     /*
316     * in-place interpretation of string:
317     *
318     * backslash-escaped: "\a\b\E\e\n\r\t", "\octal"
319     * Ctrl chars: ^@ .. ^_, ^?
320     *
321     * Emacs-style: "M-" prefix
322     *
323     * Also,
324     * "M-x" prefixed strings, append "\r" if needed
325     * "\E]" prefixed strings (XTerm escape sequence) append ST if needed
326     *
327     * returns the converted string length
328     */
329 root 1.15 /* INTPROTO */
330 pcg 1.1 int
331 pcg 1.7 rxvt_Str_escaped (char *str)
332 pcg 1.1 {
333 pcg 1.5 char ch, *s, *d;
334     int i, num, append = 0;
335 pcg 1.1
336 pcg 1.5 if (!str || !*str)
337     return 0;
338 pcg 1.1
339 pcg 1.5 d = s = str;
340 pcg 1.1
341 pcg 1.5 if (*s == 'M' && s[1] == '-')
342     {
343     /* Emacs convenience, replace leading `M-..' with `\E..' */
344     *d++ = C0_ESC;
345     s += 2;
346 pcg 1.7 if (toupper (*s) == 'X')
347 pcg 1.5 /* append carriage-return for `M-xcommand' */
348 pcg 1.7 for (*d++ = 'x', append = '\r', s++; isspace (*s); s++) ;
349 pcg 1.1 }
350 pcg 1.5 for (; (ch = *s++);)
351     {
352     if (ch == '\\')
353     {
354     ch = *s++;
355     if (ch >= '0' && ch <= '7')
356     { /* octal */
357     num = ch - '0';
358     for (i = 0; i < 2; i++, s++)
359     {
360     ch = *s;
361     if (ch < '0' || ch > '7')
362     break;
363     num = num * 8 + ch - '0';
364     }
365     ch = (char)num;
366     }
367     else if (ch == 'a')
368     ch = C0_BEL; /* bell */
369     else if (ch == 'b')
370     ch = C0_BS; /* backspace */
371     else if (ch == 'E' || ch == 'e')
372     ch = C0_ESC; /* escape */
373     else if (ch == 'n')
374     ch = '\n'; /* newline */
375     else if (ch == 'r')
376     ch = '\r'; /* carriage-return */
377     else if (ch == 't')
378     ch = C0_HT; /* tab */
379     }
380     else if (ch == '^')
381     {
382     ch = *s++;
383 pcg 1.7 ch = toupper (ch);
384 pcg 1.5 ch = (ch == '?' ? 127 : (ch - '@'));
385     }
386     *d++ = ch;
387 pcg 1.1 }
388    
389 pcg 1.5 /* ESC] is an XTerm escape sequence, must be terminated */
390     if (*str == '\0' && str[1] == C0_ESC && str[2] == ']')
391     append = CHAR_ST;
392    
393     /* add trailing character as required */
394     if (append && d[-1] != append)
395     *d++ = append;
396     *d = '\0';
397 pcg 1.1
398 pcg 1.5 return (d - str);
399 pcg 1.1 }
400    
401     /*
402     * Split a comma-separated string into an array, stripping leading and
403 root 1.25 * trailing spaces from each entry. Empty strings are properly returned
404 pcg 1.1 * Caller should free each entry and array when done
405     */
406 root 1.15 /* INTPROTO */
407 pcg 1.1 char **
408 pcg 1.7 rxvt_splitcommastring (const char *cs)
409 pcg 1.1 {
410 pcg 1.5 int l, n, p;
411     const char *s, *t;
412     char **ret;
413    
414     if ((s = cs) == NULL)
415     s = "";
416    
417     for (n = 1, t = s; *t; t++)
418     if (*t == ',')
419     n++;
420 root 1.25
421 pcg 1.7 ret = (char **)malloc ((n + 1) * sizeof (char *));
422 pcg 1.5 ret[n] = NULL;
423    
424     for (l = 0, t = s; l < n; l++)
425     {
426     for ( ; *t && *t != ','; t++) ;
427     p = t - s;
428 pcg 1.7 ret[l] = (char *)malloc (p + 1);
429     strncpy (ret[l], s, p);
430 pcg 1.5 ret[l][p] = '\0';
431 pcg 1.7 rxvt_Str_trim (ret[l]);
432 pcg 1.5 s = ++t;
433 pcg 1.1 }
434 root 1.25
435 pcg 1.5 return ret;
436 pcg 1.1 }
437    
438 root 1.16 void
439     rxvt_freecommastring (char **cs)
440     {
441     for (int i = 0; cs[i]; ++i)
442     free (cs[i]);
443    
444     free (cs);
445     }
446    
447 pcg 1.1 /*----------------------------------------------------------------------*
448     * file searching
449     */
450    
451     /* #define DEBUG_SEARCH_PATH */
452    
453     #if defined (XPM_BACKGROUND) || (MENUBAR_MAX)
454     /*
455     * search for FILE in the current working directory, and within the
456     * colon-delimited PATHLIST, adding the file extension EXT if required.
457     *
458     * FILE is either semi-colon or zero terminated
459     */
460     /* INTPROTO */
461     char *
462 pcg 1.7 rxvt_File_search_path (const char *pathlist, const char *file, const char *ext)
463 pcg 1.1 {
464 pcg 1.5 int maxpath, len;
465     const char *p, *path;
466     char name[256];
467    
468 pcg 1.7 if (!access (file, R_OK)) /* found (plain name) in current directory */
469 root 1.15 return strdup (file);
470 pcg 1.5
471     /* semi-colon delimited */
472 root 1.15 if ((p = strchr (file, ';')))
473 pcg 1.5 len = (p - file);
474     else
475 root 1.15 len = strlen (file);
476 pcg 1.1
477     #ifdef DEBUG_SEARCH_PATH
478 pcg 1.7 getcwd (name, sizeof (name));
479     fprintf (stderr, "pwd: \"%s\"\n", name);
480     fprintf (stderr, "find: \"%.*s\"\n", len, file);
481 pcg 1.1 #endif
482    
483 pcg 1.5 /* leave room for an extra '/' and trailing '\0' */
484 root 1.15 maxpath = sizeof (name) - (len + (ext ? strlen (ext) : 0) + 2);
485 pcg 1.5 if (maxpath <= 0)
486     return NULL;
487    
488     /* check if we can find it now */
489 root 1.15 strncpy (name, file, len);
490 pcg 1.5 name[len] = '\0';
491    
492 pcg 1.7 if (!access (name, R_OK))
493 root 1.15 return strdup (name);
494 pcg 1.5 if (ext)
495     {
496 root 1.15 strcat (name, ext);
497 pcg 1.7 if (!access (name, R_OK))
498 root 1.15 return strdup (name);
499 pcg 1.1 }
500 pcg 1.5 for (path = pathlist; path != NULL && *path != '\0'; path = p)
501     {
502     int n;
503    
504     /* colon delimited */
505 root 1.15 if ((p = strchr (path, ':')) == NULL)
506     p = strchr (path, '\0');
507 pcg 1.5
508     n = (p - path);
509     if (*p != '\0')
510     p++;
511    
512     if (n > 0 && n <= maxpath)
513     {
514 root 1.15 strncpy (name, path, n);
515 pcg 1.5 if (name[n - 1] != '/')
516     name[n++] = '/';
517     name[n] = '\0';
518 root 1.15 strncat (name, file, len);
519 pcg 1.5
520 pcg 1.7 if (!access (name, R_OK))
521 root 1.15 return strdup (name);
522 pcg 1.5 if (ext)
523     {
524 root 1.15 strcat (name, ext);
525 pcg 1.7 if (!access (name, R_OK))
526 root 1.15 return strdup (name);
527 pcg 1.5 }
528     }
529 pcg 1.1 }
530 pcg 1.5 return NULL;
531 pcg 1.1 }
532    
533 root 1.15 /* INTPROTO */
534 pcg 1.1 char *
535 pcg 1.7 rxvt_File_find (const char *file, const char *ext, const char *path)
536 pcg 1.1 {
537 pcg 1.5 char *f;
538 pcg 1.1
539 pcg 1.5 if (file == NULL || *file == '\0')
540     return NULL;
541 pcg 1.1
542 pcg 1.5 /* search environment variables here too */
543 pcg 1.7 if ((f = rxvt_File_search_path (path, file, ext)) == NULL)
544 pcg 1.1 #ifdef PATH_ENV
545 pcg 1.7 if ((f = rxvt_File_search_path (getenv (PATH_ENV), file, ext)) == NULL)
546 pcg 1.1 #endif
547 pcg 1.7 f = rxvt_File_search_path (getenv ("PATH"), file, ext);
548 pcg 1.1
549     #ifdef DEBUG_SEARCH_PATH
550 pcg 1.5 if (f)
551 pcg 1.7 fprintf (stderr, "found: \"%s\"\n", f);
552 pcg 1.1 #endif
553    
554 pcg 1.5 return f;
555 pcg 1.1 }
556     #endif /* defined (XPM_BACKGROUND) || (MENUBAR_MAX) */
557    
558     /*----------------------------------------------------------------------*
559     * miscellaneous drawing routines
560     */
561    
562     /*
563     * Draw top/left and bottom/right border shadows around windows
564     */
565     #if defined(RXVT_SCROLLBAR) || defined(MENUBAR)
566 root 1.15 /* INTPROTO */
567 pcg 1.1 void
568 pcg 1.7 rxvt_Draw_Shadow (Display *display, Window win, GC topShadow, GC botShadow, int x, int y, int w, int h)
569 pcg 1.1 {
570 pcg 1.5 int shadow;
571 pcg 1.1
572 pcg 1.5 shadow = (w == 0 || h == 0) ? 1 : SHADOW;
573     w += x - 1;
574     h += y - 1;
575     for (; shadow-- > 0; x++, y++, w--, h--)
576     {
577 pcg 1.7 XDrawLine (display, win, topShadow, x, y, w, y);
578     XDrawLine (display, win, topShadow, x, y, x, h);
579     XDrawLine (display, win, botShadow, w, h, w, y + 1);
580     XDrawLine (display, win, botShadow, w, h, x + 1, h);
581 pcg 1.1 }
582     }
583     #endif
584    
585     /* button shapes */
586     #ifdef MENUBAR
587 root 1.15 /* INTPROTO */
588 pcg 1.1 void
589 pcg 1.7 rxvt_Draw_Triangle (Display *display, Window win, GC topShadow, GC botShadow, int x, int y, int w, int type)
590 pcg 1.1 {
591 pcg 1.5 switch (type)
592     {
593     case 'r': /* right triangle */
594 pcg 1.7 XDrawLine (display, win, topShadow, x, y, x, y + w);
595     XDrawLine (display, win, topShadow, x, y, x + w, y + w / 2);
596     XDrawLine (display, win, botShadow, x, y + w, x + w, y + w / 2);
597 pcg 1.5 break;
598    
599     case 'l': /* left triangle */
600 pcg 1.7 XDrawLine (display, win, botShadow, x + w, y + w, x + w, y);
601     XDrawLine (display, win, botShadow, x + w, y + w, x, y + w / 2);
602     XDrawLine (display, win, topShadow, x, y + w / 2, x + w, y);
603 pcg 1.5 break;
604    
605     case 'd': /* down triangle */
606 pcg 1.7 XDrawLine (display, win, topShadow, x, y, x + w / 2, y + w);
607     XDrawLine (display, win, topShadow, x, y, x + w, y);
608     XDrawLine (display, win, botShadow, x + w, y, x + w / 2, y + w);
609 pcg 1.5 break;
610    
611     case 'u': /* up triangle */
612 pcg 1.7 XDrawLine (display, win, botShadow, x + w, y + w, x + w / 2, y);
613     XDrawLine (display, win, botShadow, x + w, y + w, x, y + w);
614     XDrawLine (display, win, topShadow, x, y + w, x + w / 2, y);
615 pcg 1.5 break;
616 pcg 1.1 #if 0
617 pcg 1.5 case 's': /* square */
618 pcg 1.7 XDrawLine (display, win, topShadow, x + w, y, x, y);
619     XDrawLine (display, win, topShadow, x, y, x, y + w);
620     XDrawLine (display, win, botShadow, x, y + w, x + w, y + w);
621     XDrawLine (display, win, botShadow, x + w, y + w, x + w, y);
622 pcg 1.5 break;
623 pcg 1.1 #endif
624 pcg 1.5
625 pcg 1.1 }
626     }
627     #endif
628     /*----------------------- end-of-file (C source) -----------------------*/