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 * Copyright 1992 Claude Lecommandeur.
8 */
9
10/**********************************************************************
11 *
12 * $XConsortium: list.c,v 1.20 91/01/09 17:13:30 rws Exp $
13 *
14 * TWM code to deal with the name lists for the NoTitle list and
15 * the AutoRaise list
16 *
17 * 11-Apr-88 Tom LaStrange        Initial Version.
18 *
19 * Do the necessary modification to be integrated in ctwm.
20 * Can no longer be used for the standard twm.
21 *
22 * 22-April-92 Claude Lecommandeur.
23 *
24 *
25 **********************************************************************/
26
27#include "ctwm.h"
28
29#include <stdio.h>
30#include <stdlib.h>
31
32#include "ctwm_shutdown.h"
33#include "screen.h"
34#include "list.h"
35#include "util.h"
36#include "parse.h"
37
38#ifdef USE_SYS_REGEX
39# include <regex.h>
40#endif /* USE_SYS_REGEX */
41
42
43
44/***********************************************************************
45 *
46 *  Procedure:
47 *      AddToList - add a window name to the appropriate list
48 *
49 *  Inputs:
50 *      list    - the address of the pointer to the head of a list
51 *      name    - a pointer to the name of the window
52 *      ptr     - pointer to list dependent data
53 *
54 *  Special Considerations
55 *      If the list does not use the ptr value, a non-null value
56 *      should be placed in it.  LookInList returns this ptr value
57 *      and procedures calling LookInList will check for a non-null
58 *      return value as an indication of success.
59 *
60 ***********************************************************************
61 */
62
63void AddToList(name_list **list_head, const char *name, void *ptr)
64{
65	name_list *nptr;
66
67	if(!list_head) {
68		return;        /* ignore empty inserts */
69	}
70
71	nptr = malloc(sizeof(name_list));
72	if(nptr == NULL) {
73		fprintf(stderr, "unable to allocate %lu bytes for name_list\n",
74		        (unsigned long) sizeof(name_list));
75		DoShutdown();
76	}
77
78	nptr->next = *list_head;
79	nptr->name = strdup(name);
80	nptr->ptr = (ptr == NULL) ? (char *)1 : ptr;
81	*list_head = nptr;
82}
83
84/***********************************************************************
85 *
86 *  Procedure:
87 *      LookInList - look through a list for a window name, or class
88 *
89 *  Returned Value:
90 *      the ptr field of the list structure or NULL if the name
91 *      or class was not found in the list
92 *
93 *  Inputs:
94 *      list    - a pointer to the head of a list
95 *      name    - a pointer to the name to look for
96 *      class   - a pointer to the class to look for
97 *
98 ***********************************************************************
99 */
100
101void *LookInList(name_list *list_head, const char *name, XClassHint *class)
102{
103	name_list *nptr;
104
105	/* look for the name first */
106	for(nptr = list_head; nptr != NULL; nptr = nptr->next) {
107		if(match(nptr->name, name)) {
108			return (nptr->ptr);
109		}
110	}
111
112	if(class) {
113		/* look for the res_name next */
114		for(nptr = list_head; nptr != NULL; nptr = nptr->next) {
115			if(match(nptr->name, class->res_name)) {
116				return (nptr->ptr);
117			}
118		}
119
120		/* finally look for the res_class */
121		for(nptr = list_head; nptr != NULL; nptr = nptr->next) {
122			if(match(nptr->name, class->res_class)) {
123				return (nptr->ptr);
124			}
125		}
126	}
127	return (NULL);
128}
129
130void *LookInNameList(name_list *list_head, const char *name)
131{
132	return (LookInList(list_head, name, NULL));
133}
134
135void *LookInListWin(name_list *list_head, TwmWindow *twin)
136{
137	return LookInList(list_head, twin->name, &(twin->class));
138}
139
140bool IsInList(name_list *list_head, TwmWindow *twin)
141{
142	return (bool)LookInList(list_head, twin->name, &(twin->class));
143}
144
145void *LookPatternInList(name_list *list_head, const char *name,
146                        XClassHint *class)
147{
148	name_list *nptr;
149
150	for(nptr = list_head; nptr != NULL; nptr = nptr->next)
151		if(match(nptr->name, name)) {
152			return (nptr->name);
153		}
154
155	if(class) {
156		for(nptr = list_head; nptr != NULL; nptr = nptr->next)
157			if(match(nptr->name, class->res_name)) {
158				return (nptr->name);
159			}
160
161		for(nptr = list_head; nptr != NULL; nptr = nptr->next)
162			if(match(nptr->name, class->res_class)) {
163				return (nptr->name);
164			}
165	}
166	return (NULL);
167}
168
169void *LookPatternInNameList(name_list *list_head, const char *name)
170{
171	return (LookPatternInList(list_head, name, NULL));
172}
173
174/***********************************************************************
175 *
176 *  Procedure:
177 *      GetColorFromList - look through a list for a window name, or class
178 *
179 *  Returned Value:
180 *      true  if the name was found
181 *      false if the name was not found
182 *
183 *  Inputs:
184 *      list    - a pointer to the head of a list
185 *      name    - a pointer to the name to look for
186 *      class   - a pointer to the class to look for
187 *
188 *  Outputs:
189 *      ptr     - fill in the list value if the name was found
190 *
191 ***********************************************************************
192 */
193
194bool GetColorFromList(name_list *list_head, char *name,
195                      XClassHint *class, Pixel *ptr)
196{
197	bool save;
198	name_list *nptr;
199
200	for(nptr = list_head; nptr != NULL; nptr = nptr->next)
201		if(match(nptr->name, name)) {
202			save = Scr->FirstTime;
203			Scr->FirstTime = true;
204			GetColor(Scr->Monochrome, ptr, nptr->ptr);
205			Scr->FirstTime = save;
206			return true;
207		}
208
209	if(class) {
210		for(nptr = list_head; nptr != NULL; nptr = nptr->next)
211			if(match(nptr->name, class->res_name)) {
212				save = Scr->FirstTime;
213				Scr->FirstTime = true;
214				GetColor(Scr->Monochrome, ptr, nptr->ptr);
215				Scr->FirstTime = save;
216				return true;
217			}
218
219		for(nptr = list_head; nptr != NULL; nptr = nptr->next)
220			if(match(nptr->name, class->res_class)) {
221				save = Scr->FirstTime;
222				Scr->FirstTime = true;
223				GetColor(Scr->Monochrome, ptr, nptr->ptr);
224				Scr->FirstTime = save;
225				return true;
226			}
227	}
228	return false;
229}
230
231/***********************************************************************
232 *
233 *  Procedure:
234 *      FreeList - free up a list
235 *
236 ***********************************************************************
237 */
238
239void FreeList(name_list **list)
240{
241	name_list *nptr;
242	name_list *tmp;
243
244	for(nptr = *list; nptr != NULL;) {
245		tmp = nptr->next;
246		free(nptr->name);
247		free(nptr);
248		nptr = tmp;
249	}
250	*list = NULL;
251}
252
253#ifdef USE_SYS_REGEX
254
255bool match(const char *pattern, const char *string)
256{
257	regex_t preg;
258	int error;
259
260	if((pattern == NULL) || (string == NULL)) {
261		return false;
262	}
263	error = regcomp(&preg, pattern, REG_EXTENDED | REG_NOSUB);
264	if(error != 0) {
265		char buf [256];
266		regerror(error, &preg, buf, sizeof buf);
267		fprintf(stderr, "%s : %s\n", buf, pattern);
268		return false;
269	}
270	error = regexec(&preg, string, 5, 0, 0);
271	regfree(&preg);
272	if(error == 0) {
273		return true;
274	}
275	return false;
276}
277
278#else
279
280
281
282int regex_match(const char *p, const char *t);
283int regex_match_after_star(const char *p, const char *t);
284
285#if 0                           /* appears not to be used anywhere */
286static int is_pattern(char *p)
287{
288	while(*p) {
289		switch(*p++) {
290			case '?':
291			case '*':
292			case '[':
293				return TRUE;
294			case '\\':
295				if(!*p++) {
296					return FALSE;
297				}
298		}
299	}
300	return FALSE;
301}
302#endif
303
304#define ABORT 2
305
306int regex_match(const char *p, const char *t)
307{
308	char range_start, range_end;
309	int invert;
310	int member_match;
311	int loop;
312
313	for(; *p; p++, t++) {
314		if(!*t) {
315			return (*p == '*' && *++p == '\0') ? TRUE : ABORT;
316		}
317		switch(*p) {
318			case '?':
319				break;
320			case '*':
321				return regex_match_after_star(p, t);
322			case '[': {
323				p++;
324				invert = FALSE;
325				if(*p == '!' || *p == '^') {
326					invert = TRUE;
327					p++;
328				}
329				if(*p == ']') {
330					return ABORT;
331				}
332				member_match = FALSE;
333				loop = TRUE;
334				while(loop) {
335					if(*p == ']') {
336						loop = FALSE;
337						continue;
338					}
339					if(*p == '\\') {
340						range_start = range_end = *++p;
341					}
342					else {
343						range_start = range_end = *p;
344					}
345					if(!range_start) {
346						return ABORT;
347					}
348					if(*++p == '-') {
349						range_end = *++p;
350						if(range_end == '\0' || range_end == ']') {
351							return ABORT;
352						}
353						if(range_end == '\\') {
354							range_end = *++p;
355						}
356						p++;
357					}
358					if(range_start < range_end) {
359						if(*t >= range_start && *t <= range_end) {
360							member_match = TRUE;
361							loop = FALSE;
362						}
363					}
364					else {
365						if(*t >= range_end && *t <= range_start) {
366							member_match = TRUE;
367							loop = FALSE;
368						}
369					}
370				}
371				if((invert && member_match) || !(invert || member_match)) {
372					return (FALSE);
373				}
374				if(member_match) {
375					while(*p != ']') {
376						if(!*p) {
377							return (ABORT);
378						}
379						if(*p == '\\') {
380							p++;
381						}
382						p++;
383					}
384				}
385				break;
386			}
387			case '\\':
388				p++;
389
390			default:
391				if(*p != *t) {
392					return (FALSE);
393				}
394		}
395	}
396	return (!*t);
397}
398
399int regex_match_after_star(const char *p, const char *t)
400{
401	int mat;
402	int nextp;
403
404	while((*p == '?') || (*p == '*')) {
405		if(*p == '?') {
406			if(!*t++) {
407				return ABORT;
408			}
409		}
410		p++;
411	}
412	if(!*p) {
413		return TRUE;
414	}
415
416	nextp = *p;
417	if(nextp == '\\') {
418		nextp = p[1];
419	}
420
421	mat = FALSE;
422	while(mat == FALSE) {
423		if(nextp == *t || nextp == '[') {
424			mat = regex_match(p, t);
425		}
426		if(!*t++) {
427			mat = ABORT;
428		}
429	}
430	return (mat);
431}
432
433int match(const char *p, const char *t)
434{
435	if((p == NULL) || (t == NULL)) {
436		return (FALSE);
437	}
438	return ((regex_match(p, t) == TRUE) ? TRUE : FALSE);
439}
440
441#endif
442
443
444
445
446