/*****************************************************************************/ /** Copyright 1988 by Evans & Sutherland Computer Corporation, **/ /** Salt Lake City, Utah **/ /** Portions Copyright 1989 by the Massachusetts Institute of Technology **/ /** Cambridge, Massachusetts **/ /** **/ /** All Rights Reserved **/ /** **/ /** Permission to use, copy, modify, and distribute this software and **/ /** its documentation for any purpose and without fee is hereby **/ /** granted, provided that the above copyright notice appear in all **/ /** copies and that both that copyright notice and this permis- **/ /** sion notice appear in supporting documentation, and that the **/ /** names of Evans & Sutherland and M.I.T. not be used in advertising **/ /** in publicity pertaining to distribution of the software without **/ /** specific, written prior permission. **/ /** **/ /** EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD **/ /** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/ /** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND OR **/ /** M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/ /** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/ /** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/ /** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/ /** OR PERFORMANCE OF THIS SOFTWARE. **/ /*****************************************************************************/ /********************************************************************** * * $XConsortium: list.c,v 1.20 91/01/09 17:13:30 rws Exp $ * * TWM code to deal with the name lists for the NoTitle list and * the AutoRaise list * * 11-Apr-88 Tom LaStrange Initial Version. * **********************************************************************/ /* * Stolen from TVTWM pl11, updated it to conform to the POSIX 1003.2 * regex spec, backported VTWM 5.3's internal wildcarding code, and * made it work without regex support. * * D. J. Hawkey Jr. - 10/20/01 */ #include #include #ifndef NO_REGEX_SUPPORT #include #include #endif #include "twm.h" #include "screen.h" #include "list.h" #include "gram.h" #define REGCOMP_FLAGS (REG_EXTENDED | REG_NOSUB) #define strdup Strdup /* avoid conflict with system header files */ extern char *strdup(char *); struct name_list_struct { name_list *next; /* pointer to the next name */ char *name; /* the name of the window */ #ifndef NO_REGEX_SUPPORT regex_t re; /* compile only once */ #else char re; /* not used */ #endif short type; /* what type of match */ Atom property; /* if (type == property) */ char *ptr; /* list dependent data */ }; #ifndef NO_REGEX_SUPPORT static char buffer[256]; #endif int match(); /*********************************************************************** * * Wrappers to allow code to step through a list * ***********************************************************************/ name_list * next_entry(list) name_list *list; { return (list->next); } char * contents_of_entry(list) name_list *list; { return (list->ptr); } /**********************************************************************/ #ifdef DEBUG static void printNameList(name, nptr) char *name; name_list *nptr; { printf("printNameList(): %s=[", name); while (nptr) { printf(" '%s':%d", nptr->name, nptr->type); nptr = nptr->next; } printf(" ]\n"); } #endif /*********************************************************************** * * Procedure: * AddToList - add a window name to the appropriate list * * Inputs: * list - the address of the pointer to the head of a list * name - a pointer to the name of the window * type - a bitmask of what to match against * property- a window propery to match against * ptr - pointer to list dependent data * * Special Considerations * If the list does not use the ptr value, a non-null value * should be placed in it. LookInList returns this ptr value * and procedures calling LookInList will check for a non-null * return value as an indication of success. * *********************************************************************** */ void AddToList(list_head, name, type, /*property, */ptr) name_list **list_head; char *name; short type; /* Atom property; */ char *ptr; { Atom property = None; name_list *nptr; if (!list_head) return; /* ignore empty inserts */ nptr = (name_list *)malloc(sizeof(name_list)); if (nptr == NULL) { fprintf (stderr, "%s: unable to allocate %d bytes for name_list\n", ProgramName, sizeof(name_list)); Done(); } #if 0 while (*list_head) list_head = &((*list_head)->next); nptr->next = NULL; #else nptr->next = *list_head; #endif nptr->name = (char *)strdup(name); if (type & LTYPE_HOST) { nptr->type = (type & ~LTYPE_HOST) | LTYPE_PROPERTY; nptr->property = XA_WM_CLIENT_MACHINE; } else { nptr->type = type; nptr->property = property; } nptr->ptr = (ptr == NULL) ? (char *)TRUE : ptr; *list_head = nptr; } /********************************************************************\ * * * New LookInList code by RJC. * * * * Since we want to be able to look for multiple matches (eg, to * * check which relevant icon regions are on the screen), the basic * * procedure is now MultiLookInList and uses a (pseudo-)continuation * * to keep track of where it is. * * * * LookInList is a trivial specialisation of that. * * * * Also, we now allow regular expressions in lists, so here we use * * Henry Spencer's regular expression code. It is possible that we * * should pre-compile all the regular expressions for maximum * * speed. * * * \********************************************************************/ int MatchName(name, pattern, compiled, type) char *name; char *pattern; #ifndef NO_REGEX_SUPPORT regex_t *compiled; #else char *compiled; #endif short type; { #ifdef DEBUG fprintf(stderr, "MatchName(): compare '%s' with '%s'\n", name, pattern); #endif if (type & LTYPE_ANYTHING) return (0); if (type & LTYPE_REGEXP) { #ifndef NO_REGEX_SUPPORT regex_t re; int result; if ((result = regcomp(&re, pattern, REGCOMP_FLAGS)) != 0) { regerror(result, &re, buffer, sizeof(buffer)); regfree(&re); fprintf(stderr, "%s: (1) regcomp(\"%s\") error: %s\n", ProgramName, pattern, buffer); return (result); } result = regexec(&re, name, 0, NULL, 0); regfree(&re); return (result); #else fprintf(stderr, "%s: (1) no support for regcomp(\"%s\")\n", ProgramName, pattern); return (1); #endif } if (type & LTYPE_C_REGEXP) { #ifndef NO_REGEX_SUPPORT return (regexec(compiled, name, 0, NULL, 0)); #else fprintf(stderr, "%s: no support for regexec(\"%s\")\n", ProgramName, name); return (1); #endif } if (type & LTYPE_STRING) return (match(pattern, name)); fprintf(stderr, "%s: bad list type (%d) comparing \"%s\" with \"%s\"\n", ProgramName, type, name, pattern); return (1); } static char * MultiLookInList(list_head, name, class, /*win, */continuation) name_list *list_head; char *name; XClassHint *class; /* Window win; */ name_list **continuation; { name_list *nptr; #if 0 Window win = None; #endif #ifdef DEBUG fprintf(stderr, "MultiLookInList(): looking for '%s'\n", name); #endif for (nptr = list_head ; nptr ; nptr = nptr->next) { /* pre-compile and cache the regex_t */ if (nptr->type & LTYPE_REGEXP) { #ifndef NO_REGEX_SUPPORT int result; if ((result = regcomp(&nptr->re, nptr->name, REGCOMP_FLAGS)) != 0) { regerror(result, &nptr->re, buffer, sizeof(buffer)); regfree(&nptr->re); fprintf(stderr, "%s: (2) regcomp(\"%s\") error: %s\n", ProgramName, nptr->name, buffer); nptr->type |= LTYPE_NOTHING; } else nptr->type |= LTYPE_C_REGEXP; #else fprintf(stderr, "%s: (2) no support for regcomp(\"%s\")\n", ProgramName, nptr->name); nptr->type |= LTYPE_NOTHING; #endif nptr->type &= ~LTYPE_REGEXP; } if (nptr->type & LTYPE_NOTHING) continue; /* skip illegal entry */ if (nptr->type & LTYPE_ANYTHING) { *continuation = nptr->next; return (nptr->ptr); } if (nptr->type & LTYPE_NAME) if (MatchName(name, nptr->name, &nptr->re, nptr->type) == 0) { *continuation = nptr->next; return (nptr->ptr); } if (class) { if (nptr->type & LTYPE_RES_NAME) if (MatchName(class->res_name, nptr->name, &nptr->re, nptr->type) == 0) { *continuation = nptr->next; return (nptr->ptr); } if (nptr->type & LTYPE_RES_CLASS) if (MatchName(class->res_class, nptr->name, &nptr->re, nptr->type) == 0) { *continuation = nptr->next; return (nptr->ptr); } } #if 0 if (win && (nptr->type & LTYPE_PROPERTY)) { char *s = GetPropertyString(win, nptr->property); if (s && MatchName(s, nptr->name, &nptr->re, nptr->type) == 0) { free(s); *continuation = nptr->next; return (nptr->ptr); } if (s) free(s); } #endif } *continuation = NULL; return (NULL); } char * LookInList(list_head, name, class/*, win*/) name_list *list_head; char *name; XClassHint *class; /* Window win; */ { #if 0 name_list *nptr; #endif name_list *rest; char *return_name = MultiLookInList(list_head, name, class, /*win, */&rest); #if 0 if ((Scr->ListRings == TRUE) && (return_name != NULL) && (list_head->next != NULL)) { /* To implement a ring on the linked list where we cant change the */ /* list_head, use a simple unlink/link-at-end alg. unless you need */ /* to move the first link. In that case swap the contents of the */ /* first link with the contents of the second then proceed as */ /* normal. */ name_list *tmp_namelist; if (list_head->ptr == return_name) { char *tmp_name; short tmp_type; char *tmp_ptr; tmp_name = list_head->name; tmp_type = list_head->type; tmp_ptr = list_head->ptr; list_head->name = list_head->next->name; list_head->type = list_head->next->type; list_head->ptr = list_head->next->ptr; list_head->next->name = tmp_name; list_head->next->type = tmp_type; list_head->next->ptr = tmp_ptr; } for (nptr = list_head; nptr->next != NULL; nptr = nptr->next) { if (nptr->next->ptr == return_name) break; } if (nptr->next->next != NULL) { tmp_namelist = nptr->next; nptr->next = nptr->next->next; for (nptr = nptr->next; nptr->next != NULL; nptr = nptr->next); nptr->next = tmp_namelist; nptr->next->next = NULL; } } #endif return (return_name); } #if 0 static char * MultiLookInNameList(list_head, name, continuation) name_list *list_head; char *name; name_list **continuation; { return (MultiLookInList(list_head, name, NULL, /*None, */continuation)); } #endif char * LookInNameList(list_head, name) name_list *list_head; char *name; { return (MultiLookInList(list_head, name, NULL, /*None, */&list_head)); } /*********************************************************************** * * Procedure: * GetColorFromList - look through a list for a window name, or class * * Returned Value: * TRUE if the name was found * FALSE if the name was not found * * Inputs: * list - a pointer to the head of a list * name - a pointer to the name to look for * class - a pointer to the class to look for * * Outputs: * ptr - fill in the list value if the name was found * *********************************************************************** */ int GetColorFromList(list_head, name, class, /*win, */ptr) name_list *list_head; char *name; XClassHint *class; /* Window win; */ Pixel *ptr; { int save; char *val = LookInList(list_head, name, class/*, win*/); if (val) { save = Scr->FirstTime; Scr->FirstTime = TRUE; GetColor(Scr->Monochrome, ptr, val); Scr->FirstTime = save; return (TRUE); } return (FALSE); } /*********************************************************************** * * Procedure: * FreeList - free up a list * *********************************************************************** */ void FreeList(list) name_list **list; { name_list *nptr; name_list *tmp; for (nptr = *list; nptr != NULL; ) { tmp = nptr->next; #ifndef NO_REGEX_SUPPORT if (nptr->type & LTYPE_C_REGEXP) regfree(&nptr->re); #endif free(nptr->name); free((char *) nptr); nptr = tmp; } *list = NULL; } /*********************************************************************** * * MSDOS-ish, Unix-ish, VTWM 5.3 wildcard support * **********************************************************************/ #if 0 static int is_pattern(p) char *p; { while (*p) { switch (*p++) { case '?': case '*': case '[': return (TRUE); case '\\': if (!*p++) return (FALSE); } } return (FALSE); } #endif #define ABORT 2 static int regex_match(); static int regex_match_after_star(p, t) char *p, *t; { register int match; register int nextp; while ((*p == '?') || (*p == '*')) { if (*p == '?') if (!*t++) return (ABORT); p++; } if (!*p) return (TRUE); nextp = *p; if (nextp == '\\') nextp = p[1]; match = FALSE; while (match == FALSE) { if (nextp == *t || nextp == '[') match = regex_match(p, t); if (!*t++) match = ABORT; } return (match); } static int regex_match(p, t) char *p, *t; { register char range_start, range_end; int invert; int member_match; int loop; for (; *p; p++, t++) { if (!*t) return ((*p == '*' && *++p == '\0') ? TRUE : ABORT); switch (*p) { case '?': break; case '*': return (regex_match_after_star(p, t)); case '[': { p++; invert = FALSE; if (*p == '!' || *p == '^') { invert = TRUE; p++; } if (*p == ']') return (ABORT); member_match = FALSE; loop = TRUE; while (loop) { if (*p == ']') { loop = FALSE; continue; } if (*p == '\\') range_start = range_end = *++p; else range_start = range_end = *p; if (!range_start) return (ABORT); if (*++p == '-') { range_end = *++p; if (range_end == '\0' || range_end == ']') return (ABORT); if (range_end == '\\') range_end = *++p; p++; } if (range_start < range_end) { if (*t >= range_start && *t <= range_end) { member_match = TRUE; loop = FALSE; } } else { if (*t >= range_end && *t <= range_start) { member_match = TRUE; loop = FALSE; } } } if ((invert && member_match) || !(invert || member_match)) return (FALSE); if (member_match) { while (*p != ']') { if (!*p) return (ABORT); if (*p == '\\') p++; p++; } } break; } case '\\': p++; default: if (*p != *t) return (FALSE); } } return (!*t); } int match(p, t) char *p, *t; { if ((p == NULL) || (t == NULL)) return (TRUE); return ((regex_match(p, t) == TRUE) ? FALSE : TRUE); }