ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/misc.C
Revision: 1.8
Committed: Fri Feb 27 02:52:51 2004 UTC (20 years, 3 months ago) by pcg
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_0
Changes since 1.7: +10 -7 lines
Log Message:
*** empty log message ***

File Contents

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