*** empty log message ***
[dana/urxvt.git] / src / misc.C
1 /*--------------------------------*-C-*---------------------------------*
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  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  *----------------------------------------------------------------------*/
24
25 #include "../config.h"          /* NECESSARY */
26 #include "rxvt.h"               /* NECESSARY */
27 #include "misc.intpro"          /* PROTOS for internal routines */
28
29 /* EXTPROTO */
30 char *
31 rxvt_strdup (const char *str)
32 {
33   return str ? strdup (str) : 0;
34 }
35
36 /* EXTPROTO */
37 char           *
38 rxvt_r_basename(const char *str)
39 {
40   char           *base = STRRCHR(str, '/');
41
42   return (char *)(base ? base + 1 : str);
43 }
44
45 /*
46  * Print an error message
47  */
48 /* EXTPROTO */
49 void
50 rxvt_print_error(const char *fmt,...)
51 {
52   va_list         arg_ptr;
53
54   va_start(arg_ptr, fmt);
55   fprintf(stderr, APL_NAME ": ");
56   vfprintf(stderr, fmt, arg_ptr);
57   fprintf(stderr, "\n");
58   va_end(arg_ptr);
59 }
60
61 /*
62  * check that the first characters of S1 match S2
63  *
64  * No Match
65  *      return: 0
66  * Match
67  *      return: STRLEN (S2)
68  */
69 /* EXTPROTO */
70 int
71 rxvt_Str_match(const char *s1, const char *s2)
72 {
73   int             n = STRLEN(s2);
74
75   return ((STRNCMP(s1, s2, n) == 0) ? n : 0);
76 }
77
78 /* EXTPROTO */
79 const char     *
80 rxvt_Str_skip_space(const char *str)
81 {
82   if (str)
83     while (*str && isspace(*str))
84       str++;
85   return str;
86 }
87
88 /*
89  * remove leading/trailing space and strip-off leading/trailing quotes.
90  * in place.
91  */
92 /* EXTPROTO */
93 char           *
94 rxvt_Str_trim(char *str)
95 {
96   char           *r, *s;
97   int             n;
98
99   if (!str || !*str)            /* shortcut */
100     return str;
101
102   /* skip leading spaces */
103   for (s = str; *s && isspace(*s); s++) ;
104   /* goto end of string */
105   for (n = 0, r = s; *r++; n++) ;
106   r -= 2;
107   /* dump return */
108   if (n > 0 && *r == '\n')
109     n--, r--;
110   /* backtrack along trailing spaces */
111   for (; n > 0 && isspace(*r); r--, n--) ;
112   /* skip matching leading/trailing quotes */
113   if (*s == '"' && *r == '"' && n > 1)
114     {
115       s++;
116       n -= 2;
117     }
118   /* copy back over: forwards copy */
119   for (r = str; n; n--)
120     *r++ = *s++;
121   *r = '\0';
122
123   return str;
124 }
125
126 /*
127  * in-place interpretation of string:
128  *
129  *      backslash-escaped:      "\a\b\E\e\n\r\t", "\octal"
130  *      Ctrl chars:     ^@ .. ^_, ^?
131  *
132  *      Emacs-style:    "M-" prefix
133  *
134  * Also,
135  *      "M-x" prefixed strings, append "\r" if needed
136  *      "\E]" prefixed strings (XTerm escape sequence) append ST if needed
137  *
138  * returns the converted string length
139  */
140 /* EXTPROTO */
141 int
142 rxvt_Str_escaped(char *str)
143 {
144   char            ch, *s, *d;
145   int             i, num, append = 0;
146
147   if (!str || !*str)
148     return 0;
149
150   d = s = str;
151
152   if (*s == 'M' && s[1] == '-')
153     {
154       /* Emacs convenience, replace leading `M-..' with `\E..' */
155       *d++ = C0_ESC;
156       s += 2;
157       if (toupper(*s) == 'X')
158         /* append carriage-return for `M-xcommand' */
159         for (*d++ = 'x', append = '\r', s++; isspace(*s); s++) ;
160     }
161   for (; (ch = *s++);)
162     {
163       if (ch == '\\')
164         {
165           ch = *s++;
166           if (ch >= '0' && ch <= '7')
167             {   /* octal */
168               num = ch - '0';
169               for (i = 0; i < 2; i++, s++)
170                 {
171                   ch = *s;
172                   if (ch < '0' || ch > '7')
173                     break;
174                   num = num * 8 + ch - '0';
175                 }
176               ch = (char)num;
177             }
178           else if (ch == 'a')
179             ch = C0_BEL;        /* bell */
180           else if (ch == 'b')
181             ch = C0_BS; /* backspace */
182           else if (ch == 'E' || ch == 'e')
183             ch = C0_ESC;        /* escape */
184           else if (ch == 'n')
185             ch = '\n';  /* newline */
186           else if (ch == 'r')
187             ch = '\r';  /* carriage-return */
188           else if (ch == 't')
189             ch = C0_HT; /* tab */
190         }
191       else if (ch == '^')
192         {
193           ch = *s++;
194           ch = toupper(ch);
195           ch = (ch == '?' ? 127 : (ch - '@'));
196         }
197       *d++ = ch;
198     }
199
200   /* ESC] is an XTerm escape sequence, must be terminated */
201   if (*str == '\0' && str[1] == C0_ESC && str[2] == ']')
202     append = CHAR_ST;
203
204   /* add trailing character as required */
205   if (append && d[-1] != append)
206     *d++ = append;
207   *d = '\0';
208
209   return (d - str);
210 }
211
212 /*
213  * Split a comma-separated string into an array, stripping leading and
214  * trailing spaces (and paired quotes) from each entry.  Empty strings
215  * are properly returned
216  * Caller should free each entry and array when done
217  */
218 /* EXTPROTO */
219 char          **
220 rxvt_splitcommastring(const char *cs)
221 {
222   int             l, n, p;
223   const char     *s, *t;
224   char          **ret;
225
226   if ((s = cs) == NULL)
227     s = "";
228
229   for (n = 1, t = s; *t; t++)
230     if (*t == ',')
231       n++;
232   ret = (char **)malloc((n + 1) * sizeof(char *));
233   ret[n] = NULL;
234
235   for (l = 0, t = s; l < n; l++)
236     {
237       for ( ; *t && *t != ','; t++) ;
238       p = t - s;
239       ret[l] = (char *)malloc(p + 1);
240       strncpy(ret[l], s, p);
241       ret[l][p] = '\0';
242       rxvt_Str_trim(ret[l]);
243       s = ++t;
244     }
245   return ret;
246 }
247
248 /*----------------------------------------------------------------------*
249  * file searching
250  */
251
252 /* #define DEBUG_SEARCH_PATH */
253
254 #if defined (XPM_BACKGROUND) || (MENUBAR_MAX)
255 /*
256  * search for FILE in the current working directory, and within the
257  * colon-delimited PATHLIST, adding the file extension EXT if required.
258  *
259  * FILE is either semi-colon or zero terminated
260  */
261 /* INTPROTO */
262 char           *
263 rxvt_File_search_path(const char *pathlist, const char *file, const char *ext)
264 {
265   int             maxpath, len;
266   const char     *p, *path;
267   char            name[256];
268
269   if (!access(file, R_OK))      /* found (plain name) in current directory */
270     return STRDUP(file);
271
272   /* semi-colon delimited */
273   if ((p = STRCHR(file, ';')))
274     len = (p - file);
275   else
276     len = STRLEN(file);
277
278 #ifdef DEBUG_SEARCH_PATH
279   getcwd(name, sizeof(name));
280   fprintf(stderr, "pwd: \"%s\"\n", name);
281   fprintf(stderr, "find: \"%.*s\"\n", len, file);
282 #endif
283
284   /* leave room for an extra '/' and trailing '\0' */
285   maxpath = sizeof(name) - (len + (ext ? STRLEN(ext) : 0) + 2);
286   if (maxpath <= 0)
287     return NULL;
288
289   /* check if we can find it now */
290   STRNCPY(name, file, len);
291   name[len] = '\0';
292
293   if (!access(name, R_OK))
294     return STRDUP(name);
295   if (ext)
296     {
297       STRCAT(name, ext);
298       if (!access(name, R_OK))
299         return STRDUP(name);
300     }
301   for (path = pathlist; path != NULL && *path != '\0'; path = p)
302     {
303       int             n;
304
305       /* colon delimited */
306       if ((p = STRCHR(path, ':')) == NULL)
307         p = STRCHR(path, '\0');
308
309       n = (p - path);
310       if (*p != '\0')
311         p++;
312
313       if (n > 0 && n <= maxpath)
314         {
315           STRNCPY(name, path, n);
316           if (name[n - 1] != '/')
317             name[n++] = '/';
318           name[n] = '\0';
319           STRNCAT(name, file, len);
320
321           if (!access(name, R_OK))
322             return STRDUP(name);
323           if (ext)
324             {
325               STRCAT(name, ext);
326               if (!access(name, R_OK))
327                 return STRDUP(name);
328             }
329         }
330     }
331   return NULL;
332 }
333
334 /* EXTPROTO */
335 char           *
336 rxvt_File_find(const char *file, const char *ext, const char *path)
337 {
338   char           *f;
339
340   if (file == NULL || *file == '\0')
341     return NULL;
342
343   /* search environment variables here too */
344   if ((f = rxvt_File_search_path(path, file, ext)) == NULL)
345 #ifdef PATH_ENV
346     if ((f = rxvt_File_search_path(getenv(PATH_ENV), file, ext)) == NULL)
347 #endif
348       f = rxvt_File_search_path(getenv("PATH"), file, ext);
349
350 #ifdef DEBUG_SEARCH_PATH
351   if (f)
352     fprintf(stderr, "found: \"%s\"\n", f);
353 #endif
354
355   return f;
356 }
357 #endif                          /* defined (XPM_BACKGROUND) || (MENUBAR_MAX) */
358
359 /*----------------------------------------------------------------------*
360  * miscellaneous drawing routines
361  */
362
363 /*
364  * Draw top/left and bottom/right border shadows around windows
365  */
366 #if defined(RXVT_SCROLLBAR) || defined(MENUBAR)
367 /* EXTPROTO */
368 void
369 rxvt_Draw_Shadow(Display *display, Window win, GC topShadow, GC botShadow, int x, int y, int w, int h)
370 {
371   int             shadow;
372
373   shadow = (w == 0 || h == 0) ? 1 : SHADOW;
374   w += x - 1;
375   h += y - 1;
376   for (; shadow-- > 0; x++, y++, w--, h--)
377     {
378       XDrawLine(display, win, topShadow, x, y, w, y);
379       XDrawLine(display, win, topShadow, x, y, x, h);
380       XDrawLine(display, win, botShadow, w, h, w, y + 1);
381       XDrawLine(display, win, botShadow, w, h, x + 1, h);
382     }
383 }
384 #endif
385
386 /* button shapes */
387 #ifdef MENUBAR
388 /* EXTPROTO */
389 void
390 rxvt_Draw_Triangle(Display *display, Window win, GC topShadow, GC botShadow, int x, int y, int w, int type)
391 {
392   switch (type)
393     {
394       case 'r':                 /* right triangle */
395         XDrawLine(display, win, topShadow, x, y, x, y + w);
396         XDrawLine(display, win, topShadow, x, y, x + w, y + w / 2);
397         XDrawLine(display, win, botShadow, x, y + w, x + w, y + w / 2);
398         break;
399
400       case 'l':                 /* left triangle */
401         XDrawLine(display, win, botShadow, x + w, y + w, x + w, y);
402         XDrawLine(display, win, botShadow, x + w, y + w, x, y + w / 2);
403         XDrawLine(display, win, topShadow, x, y + w / 2, x + w, y);
404         break;
405
406       case 'd':                 /* down triangle */
407         XDrawLine(display, win, topShadow, x, y, x + w / 2, y + w);
408         XDrawLine(display, win, topShadow, x, y, x + w, y);
409         XDrawLine(display, win, botShadow, x + w, y, x + w / 2, y + w);
410         break;
411
412       case 'u':                 /* up triangle */
413         XDrawLine(display, win, botShadow, x + w, y + w, x + w / 2, y);
414         XDrawLine(display, win, botShadow, x + w, y + w, x, y + w);
415         XDrawLine(display, win, topShadow, x, y + w, x + w / 2, y);
416         break;
417 #if 0
418       case 's':                 /* square */
419         XDrawLine(display, win, topShadow, x + w, y, x, y);
420         XDrawLine(display, win, topShadow, x, y, x, y + w);
421         XDrawLine(display, win, botShadow, x, y + w, x + w, y + w);
422         XDrawLine(display, win, botShadow, x + w, y + w, x + w, y);
423         break;
424 #endif
425
426     }
427 }
428 #endif
429 /*----------------------- end-of-file (C source) -----------------------*/