chiark / gitweb /
Import vtwm_5.4.7.orig.tar.gz
[vtwm.git] / list.c
1 /*****************************************************************************/
2 /**       Copyright 1988 by Evans & Sutherland Computer Corporation,        **/
3 /**                          Salt Lake City, Utah                           **/
4 /**  Portions Copyright 1989 by the Massachusetts Institute of Technology   **/
5 /**                        Cambridge, Massachusetts                         **/
6 /**                                                                         **/
7 /**                           All Rights Reserved                           **/
8 /**                                                                         **/
9 /**    Permission to use, copy, modify, and distribute this software and    **/
10 /**    its documentation  for  any  purpose  and  without  fee is hereby    **/
11 /**    granted, provided that the above copyright notice appear  in  all    **/
12 /**    copies and that both  that  copyright  notice  and  this  permis-    **/
13 /**    sion  notice appear in supporting  documentation,  and  that  the    **/
14 /**    names of Evans & Sutherland and M.I.T. not be used in advertising    **/
15 /**    in publicity pertaining to distribution of the  software  without    **/
16 /**    specific, written prior permission.                                  **/
17 /**                                                                         **/
18 /**    EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD    **/
19 /**    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-    **/
20 /**    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND OR    **/
21 /**    M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-    **/
22 /**    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA    **/
23 /**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
24 /**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
25 /**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
26 /*****************************************************************************/
27
28
29 /**********************************************************************
30  *
31  * $XConsortium: list.c,v 1.20 91/01/09 17:13:30 rws Exp $
32  *
33  * TWM code to deal with the name lists for the NoTitle list and
34  * the AutoRaise list
35  *
36  * 11-Apr-88 Tom LaStrange        Initial Version.
37  *
38  **********************************************************************/
39
40 /*
41  * Stolen from TVTWM pl11, updated it to conform to the POSIX 1003.2
42  * regex spec, backported VTWM 5.3's internal wildcarding code, and
43  * made it work without regex support.
44  *
45  * D. J. Hawkey Jr. - 10/20/01
46  */
47
48 #include <stdio.h>
49 #include <X11/Xatom.h>
50
51 #ifndef NO_REGEX_SUPPORT
52 #include <sys/types.h>
53 #include <regex.h>
54 #endif
55
56 #include "twm.h"
57 #include "screen.h"
58 #include "list.h"
59 #include "gram.h"
60
61 #define REGCOMP_FLAGS           (REG_EXTENDED | REG_NOSUB)
62
63 #define strdup Strdup /* avoid conflict with system header files */
64 extern char *strdup(char *);
65
66 struct name_list_struct
67 {
68     name_list *next;            /* pointer to the next name */
69     char *name;                 /* the name of the window */
70 #ifndef NO_REGEX_SUPPORT
71     regex_t re;                 /* compile only once */
72 #else
73     char re;                    /* not used */
74 #endif
75     short type;                 /* what type of match */
76     Atom property;              /* if (type == property) */
77     char *ptr;                  /* list dependent data */
78 };
79
80 #ifndef NO_REGEX_SUPPORT
81 static char buffer[256];
82 #endif
83
84 int match();
85
86 /***********************************************************************
87  *
88  * Wrappers to allow code to step through a list
89  *
90  ***********************************************************************/
91
92 name_list *
93 next_entry(list)
94 name_list *list;
95 {
96     return (list->next);
97 }
98
99 char *
100 contents_of_entry(list)
101 name_list *list;
102 {
103     return (list->ptr);
104 }
105
106 /**********************************************************************/
107
108 #ifdef DEBUG
109 static void
110 printNameList(name, nptr)
111 char *name;
112 name_list *nptr;
113 {
114     printf("printNameList(): %s=[", name);
115
116     while (nptr)
117     {
118         printf(" '%s':%d", nptr->name, nptr->type);
119         nptr = nptr->next;
120     }
121
122     printf(" ]\n");
123 }
124 #endif
125
126 /***********************************************************************
127  *
128  *  Procedure:
129  *      AddToList - add a window name to the appropriate list
130  *
131  *  Inputs:
132  *      list    - the address of the pointer to the head of a list
133  *      name    - a pointer to the name of the window 
134  *      type    - a bitmask of what to match against
135  *      property- a window propery to match against
136  *      ptr     - pointer to list dependent data
137  *
138  *  Special Considerations
139  *      If the list does not use the ptr value, a non-null value 
140  *      should be placed in it.  LookInList returns this ptr value
141  *      and procedures calling LookInList will check for a non-null 
142  *      return value as an indication of success.
143  *
144  ***********************************************************************
145  */
146
147 void
148 AddToList(list_head, name, type, /*property, */ptr)
149 name_list **list_head;
150 char *name;
151 short type;
152 /* Atom property; */
153 char *ptr;
154 {
155     Atom property = None;
156     name_list *nptr;
157
158     if (!list_head) return;     /* ignore empty inserts */
159
160     nptr = (name_list *)malloc(sizeof(name_list));
161     if (nptr == NULL)
162     {
163         fprintf (stderr, "%s: unable to allocate %d bytes for name_list\n",
164                  ProgramName, sizeof(name_list));
165         Done();
166     }
167
168 #if 0
169     while (*list_head)
170         list_head = &((*list_head)->next);
171
172     nptr->next = NULL;
173 #else
174     nptr->next = *list_head;
175 #endif
176
177     nptr->name = (char *)strdup(name);
178     if (type & LTYPE_HOST)
179     {
180         nptr->type = (type & ~LTYPE_HOST) | LTYPE_PROPERTY;
181         nptr->property = XA_WM_CLIENT_MACHINE;
182     }
183     else
184     {
185         nptr->type = type;
186         nptr->property = property;
187     }
188     nptr->ptr = (ptr == NULL) ? (char *)TRUE : ptr;
189
190     *list_head = nptr;
191 }    
192
193  /********************************************************************\
194  *                                                                    *
195  * New LookInList code by RJC.                                        *
196  *                                                                    *
197  * Since we want to be able to look for multiple matches (eg, to      *
198  * check which relevant icon regions are on the screen), the basic    *
199  * procedure is now MultiLookInList and uses a (pseudo-)continuation  *
200  * to keep track of where it is.                                      *
201  *                                                                    *
202  * LookInList is a trivial specialisation of that.                    *
203  *                                                                    *
204  * Also, we now allow regular expressions in lists, so here we use    *
205  * Henry Spencer's regular expression code.  It is possible that we   *
206  * should pre-compile all the regular expressions for maximum         *
207  * speed.                                                             *
208  *                                                                    *
209  \********************************************************************/
210
211 int
212 MatchName(name, pattern, compiled, type)
213 char *name;
214 char *pattern;
215 #ifndef NO_REGEX_SUPPORT
216 regex_t *compiled;
217 #else
218 char *compiled;
219 #endif
220 short type;
221 {
222 #ifdef DEBUG
223     fprintf(stderr, "MatchName(): compare '%s' with '%s'\n", name, pattern);
224 #endif
225
226     if (type & LTYPE_ANYTHING)
227         return (0);
228
229     if (type & LTYPE_REGEXP)
230     {
231 #ifndef NO_REGEX_SUPPORT
232         regex_t re;
233         int result;
234
235         if ((result = regcomp(&re, pattern, REGCOMP_FLAGS)) != 0)
236         {
237             regerror(result, &re, buffer, sizeof(buffer));
238             regfree(&re);
239
240             fprintf(stderr, "%s: (1) regcomp(\"%s\") error: %s\n",
241                         ProgramName, pattern, buffer);
242             return (result);
243         }
244
245         result = regexec(&re, name, 0, NULL, 0);
246         regfree(&re);
247
248         return (result);
249 #else
250         fprintf(stderr, "%s: (1) no support for regcomp(\"%s\")\n",
251                         ProgramName, pattern);
252         return (1);
253 #endif
254     }
255
256     if (type & LTYPE_C_REGEXP)
257     {
258 #ifndef NO_REGEX_SUPPORT
259         return (regexec(compiled, name, 0, NULL, 0));
260 #else
261         fprintf(stderr, "%s: no support for regexec(\"%s\")\n",
262                 ProgramName, name);
263         return (1);
264 #endif
265     }
266
267     if (type & LTYPE_STRING)
268         return (match(pattern, name));
269
270     fprintf(stderr, "%s: bad list type (%d) comparing \"%s\" with \"%s\"\n",
271                 ProgramName, type, name, pattern);
272     return (1);
273 }
274
275 static char *
276 MultiLookInList(list_head, name, class, /*win, */continuation)
277 name_list *list_head;
278 char *name;
279 XClassHint *class;
280 /* Window win; */
281 name_list **continuation;
282 {
283     name_list *nptr;
284 #if 0
285     Window win = None;
286 #endif
287
288 #ifdef DEBUG
289     fprintf(stderr, "MultiLookInList(): looking for '%s'\n", name);
290 #endif
291
292     for (nptr = list_head ; nptr ; nptr = nptr->next)
293     {
294         /* pre-compile and cache the regex_t */
295         if (nptr->type & LTYPE_REGEXP)
296         {
297 #ifndef NO_REGEX_SUPPORT
298             int result;
299
300             if ((result = regcomp(&nptr->re, nptr->name, REGCOMP_FLAGS)) != 0)
301             {
302                 regerror(result, &nptr->re, buffer, sizeof(buffer));
303                 regfree(&nptr->re);
304
305                 fprintf(stderr, "%s: (2) regcomp(\"%s\") error: %s\n",
306                                 ProgramName, nptr->name, buffer);
307
308                 nptr->type |= LTYPE_NOTHING;
309             }
310             else
311                 nptr->type |= LTYPE_C_REGEXP;
312 #else
313             fprintf(stderr, "%s: (2) no support for regcomp(\"%s\")\n",
314                         ProgramName, nptr->name);
315
316             nptr->type |= LTYPE_NOTHING;
317 #endif
318
319             nptr->type &= ~LTYPE_REGEXP;
320         }
321
322         if (nptr->type & LTYPE_NOTHING) 
323             continue;                           /* skip illegal entry */
324
325         if (nptr->type & LTYPE_ANYTHING)
326         {
327             *continuation = nptr->next;
328             return (nptr->ptr);
329         }
330
331         if (nptr->type & LTYPE_NAME)
332             if (MatchName(name, nptr->name, &nptr->re, nptr->type) == 0)
333             {
334                 *continuation = nptr->next;
335                 return (nptr->ptr);
336             }
337
338         if (class)
339         {
340             if (nptr->type & LTYPE_RES_NAME)
341                 if (MatchName(class->res_name, nptr->name, &nptr->re,
342                                 nptr->type) == 0)
343                 {
344                     *continuation = nptr->next;
345                     return (nptr->ptr);
346                 }
347
348             if (nptr->type & LTYPE_RES_CLASS)
349                 if (MatchName(class->res_class, nptr->name, &nptr->re,
350                                 nptr->type) == 0)
351                 {
352                     *continuation = nptr->next;
353                     return (nptr->ptr);
354                 }
355         }
356
357 #if 0
358         if (win && (nptr->type & LTYPE_PROPERTY))
359         {
360             char *s = GetPropertyString(win, nptr->property);
361
362             if (s && MatchName(s, nptr->name, &nptr->re, nptr->type) == 0)
363             {
364                 free(s);
365
366                 *continuation = nptr->next;
367                 return (nptr->ptr);
368             }
369
370             if (s) free(s);
371         }
372 #endif
373     }
374
375     *continuation = NULL;
376     return (NULL);
377 }
378
379 char *
380 LookInList(list_head, name, class/*, win*/)
381 name_list *list_head;
382 char *name;
383 XClassHint *class;
384 /* Window win; */
385 {
386 #if 0
387     name_list *nptr;
388 #endif
389     name_list *rest;
390     char *return_name = MultiLookInList(list_head, name, class, /*win, */&rest);
391
392 #if 0
393     if ((Scr->ListRings == TRUE) && (return_name != NULL)
394         && (list_head->next != NULL)) 
395     {
396         /* To implement a ring on the linked list where we cant change the */
397         /* list_head, use a simple unlink/link-at-end alg. unless you need */
398         /* to move the first link.   In that case swap the contents of the */
399         /* first link with the contents of the second then proceed as */
400         /* normal.  */
401         name_list *tmp_namelist;
402         
403         if (list_head->ptr == return_name)
404         {
405             char *tmp_name;
406             short tmp_type;
407             char *tmp_ptr;
408             
409             tmp_name = list_head->name;
410             tmp_type = list_head->type;
411             tmp_ptr = list_head->ptr;
412             
413             list_head->name = list_head->next->name;
414             list_head->type = list_head->next->type;
415             list_head->ptr = list_head->next->ptr;
416             
417             list_head->next->name = tmp_name;
418             list_head->next->type = tmp_type;
419             list_head->next->ptr = tmp_ptr;
420         }
421         
422         for (nptr = list_head; nptr->next != NULL; nptr = nptr->next)
423         {
424             if (nptr->next->ptr == return_name)
425               break;
426         }
427         
428         if (nptr->next->next != NULL)
429         {
430             tmp_namelist = nptr->next;
431             nptr->next = nptr->next->next;
432             
433             for (nptr = nptr->next; nptr->next != NULL; nptr = nptr->next);
434             nptr->next = tmp_namelist;
435             nptr->next->next = NULL;
436         }
437     }
438 #endif
439     
440     return (return_name);
441 }
442
443 #if 0
444 static char *
445 MultiLookInNameList(list_head, name, continuation)
446 name_list *list_head;
447 char *name;
448 name_list **continuation;
449 {
450     return (MultiLookInList(list_head, name, NULL, /*None, */continuation));
451 }
452 #endif
453
454 char *
455 LookInNameList(list_head, name)
456 name_list *list_head;
457 char *name;
458 {
459     return (MultiLookInList(list_head, name, NULL, /*None, */&list_head));
460 }
461
462 /***********************************************************************
463  *
464  *  Procedure:
465  *      GetColorFromList - look through a list for a window name, or class
466  *
467  *  Returned Value:
468  *      TRUE if the name was found
469  *      FALSE if the name was not found
470  *
471  *  Inputs:
472  *      list    - a pointer to the head of a list
473  *      name    - a pointer to the name to look for
474  *      class   - a pointer to the class to look for
475  *
476  *  Outputs:
477  *      ptr     - fill in the list value if the name was found
478  *
479  ***********************************************************************
480  */
481
482 int GetColorFromList(list_head, name, class, /*win, */ptr)
483 name_list *list_head;
484 char *name;
485 XClassHint *class;
486 /* Window win; */
487 Pixel *ptr;
488 {
489     int save;
490     char *val = LookInList(list_head, name, class/*, win*/);
491
492     if (val)
493     {
494         save = Scr->FirstTime;
495         Scr->FirstTime = TRUE;
496         GetColor(Scr->Monochrome, ptr, val);
497         Scr->FirstTime = save;
498
499         return (TRUE);
500     }
501
502     return (FALSE);
503 }
504
505 /***********************************************************************
506  *
507  *  Procedure:
508  *      FreeList - free up a list
509  *
510  ***********************************************************************
511  */
512
513 void FreeList(list)
514 name_list **list;
515 {
516     name_list *nptr;
517     name_list *tmp;
518
519     for (nptr = *list; nptr != NULL; )
520     {
521         tmp = nptr->next;
522
523 #ifndef NO_REGEX_SUPPORT
524         if (nptr->type & LTYPE_C_REGEXP)
525             regfree(&nptr->re);
526 #endif
527         free(nptr->name);
528         free((char *) nptr);
529
530         nptr = tmp;
531     }
532
533     *list = NULL;
534 }
535
536 /***********************************************************************
537  *
538  * MSDOS-ish, Unix-ish, VTWM 5.3 wildcard support
539  *
540  **********************************************************************/
541
542 #if 0
543 static int is_pattern(p)
544 char *p;
545 {
546     while (*p)
547     {
548         switch (*p++)
549         {
550             case '?':
551             case '*':
552             case '[':
553                 return (TRUE);
554             case '\\':
555                 if (!*p++) return (FALSE);
556         }
557     }
558
559     return (FALSE);
560 }
561 #endif
562
563 #define ABORT 2
564
565 static int regex_match();
566
567 static int regex_match_after_star(p, t)
568 char *p, *t;
569 {
570     register int match;
571     register int nextp;
572
573     while ((*p == '?') || (*p == '*'))
574     {
575         if (*p == '?')
576             if (!*t++) return (ABORT);
577
578         p++;
579     }
580     if (!*p) return (TRUE);
581
582     nextp = *p;
583     if (nextp == '\\') nextp = p[1];
584
585     match = FALSE;
586     while (match == FALSE)
587     {
588         if (nextp == *t || nextp == '[')
589             match = regex_match(p, t);
590
591         if (!*t++) match = ABORT;
592     }
593
594     return (match);
595 }
596
597 static int regex_match(p, t)
598 char *p, *t;
599 {
600     register char range_start, range_end;
601     int invert;
602     int member_match;
603     int loop;
604
605     for (; *p; p++, t++)
606     {
607         if (!*t) return ((*p == '*' && *++p == '\0') ? TRUE : ABORT);
608
609         switch (*p)
610         {
611             case '?':
612                 break;
613             case '*':
614                 return (regex_match_after_star(p, t));
615             case '[':
616             {
617                 p++;
618                 invert = FALSE;
619                 if (*p == '!' || *p == '^')
620                 {
621                     invert = TRUE;
622                     p++;
623                 }
624
625                 if (*p == ']') return (ABORT);
626
627                 member_match = FALSE;
628                 loop = TRUE;
629                 while (loop)
630                 {
631                     if (*p == ']')
632                     {
633                         loop = FALSE;
634                         continue;
635                     }
636
637                     if (*p == '\\')
638                         range_start = range_end = *++p;
639                     else
640                         range_start = range_end = *p;
641                     if (!range_start) return (ABORT);
642
643                     if (*++p == '-')
644                     {
645                         range_end = *++p;
646                         if (range_end == '\0' || range_end == ']')
647                             return (ABORT);
648
649                         if (range_end == '\\')
650                             range_end = *++p;
651                         p++;
652                     }
653
654                     if (range_start < range_end)
655                     {
656                         if (*t >= range_start && *t <= range_end)
657                         {
658                             member_match = TRUE;
659                             loop = FALSE;
660                         }
661                     }
662                     else
663                     {
664                         if (*t >= range_end && *t <= range_start)
665                         {
666                             member_match = TRUE;
667                             loop = FALSE;
668                         }
669                     }
670                 }
671
672                 if ((invert && member_match) || !(invert || member_match))
673                     return (FALSE);
674
675                 if (member_match)
676                 {
677                     while (*p != ']')
678                     {
679                         if (!*p) return (ABORT);
680
681                         if (*p == '\\') p++;
682                         p++;
683                     }
684                 }
685                 break;
686             }
687             case '\\':
688                 p++;
689
690             default:
691                 if (*p != *t) return (FALSE);
692         }
693     }
694
695     return (!*t);
696 }
697
698 int match(p, t)
699 char *p, *t;
700 {
701     if ((p == NULL) || (t == NULL)) return (TRUE);
702
703     return ((regex_match(p, t) == TRUE) ? FALSE : TRUE);
704 }