/*****************************************************************************/
/** 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 <stdio.h>
#include <X11/Xatom.h>
#ifndef NO_REGEX_SUPPORT
#include <sys/types.h>
#include <regex.h>
#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);
}
syntax highlighted by Code2HTML, v. 0.9.1