2 * Copyright (C) 2000, Matias Atria
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #if defined(WITH_REGEX_SPECIALS) && defined(HAVE_REGEX_H)
29 typedef struct _DviSpecial {
30 struct _DviSpecial *next;
31 struct _DviSpecial *prev;
35 #ifdef WITH_REGEX_SPECIALS
39 DviSpecialHandler handler;
42 static ListHead specials = {NULL, NULL, 0};
45 void x __PROTO((DviContext *, const char *, const char *))
47 static SPECIAL(sp_layer);
48 extern SPECIAL(epsf_special);
49 extern SPECIAL(do_color_special);
55 DviSpecialHandler handler;
57 {"Layers", "layer", NULL, sp_layer},
58 {"EPSF", "psfile", NULL, epsf_special}
60 #define NSPECIALS (sizeof(builtins) / sizeof(builtins[0]))
61 static int registered_builtins = 0;
63 static void register_builtin_specials(void)
67 ASSERT(registered_builtins == 0);
68 for(i = 0; i < NSPECIALS; i++)
69 mdvi_register_special(
74 1 /* replace if exists */);
75 registered_builtins = 1;
78 static DviSpecial *find_special_prefix(const char *prefix)
82 /* should have a hash table here, but I'm so lazy */
83 for(sp = (DviSpecial *)specials.head; sp; sp = sp->next) {
84 if(STRCEQ(sp->prefix, prefix))
90 int mdvi_register_special(const char *label, const char *prefix,
91 const char *regex, DviSpecialHandler handler, int replace)
96 if(!registered_builtins)
97 register_builtin_specials();
99 sp = find_special_prefix(prefix);
101 sp = xalloc(DviSpecial);
102 sp->prefix = mdvi_strdup(prefix);
107 mdvi_free(sp->label);
111 #ifdef WITH_REGEX_SPECIALS
112 if(!newsp && sp->has_reg) {
116 if(regex && regcomp(&sp->reg, regex, REG_NOSUB) != 0) {
118 mdvi_free(sp->prefix);
123 sp->has_reg = (regex != NULL);
125 sp->handler = handler;
126 sp->label = mdvi_strdup(label);
127 sp->plen = strlen(prefix);
129 listh_prepend(&specials, LIST(sp));
131 "New \\special handler `%s' with prefix `%s'\n",
136 int mdvi_unregister_special(const char *prefix)
140 sp = find_special_prefix(prefix);
143 mdvi_free(sp->prefix);
144 #ifdef WITH_REGEX_SPECIALS
148 listh_remove(&specials, LIST(sp));
153 #define IS_PREFIX_DELIMITER(x) (strchr(" \t\n:=", (x)) != NULL)
155 int mdvi_do_special(DviContext *dvi, char *string)
161 if(!registered_builtins) {
164 if(!string || !*string)
167 /* skip leading spaces */
168 while(*string && isspace(*string))
171 DEBUG((DBG_SPECIAL, "Looking for a handler for `%s'\n", string));
173 /* now try to find a match */
175 for(sp = (DviSpecial *)specials.head; sp; sp = sp->next) {
176 #ifdef WITH_REGEX_SPECIALS
177 if(sp->has_reg && !regexec(&sp->reg, ptr, 0, 0, 0))
180 /* check the prefix */
181 if(STRNCEQ(sp->prefix, ptr, sp->plen)) {
188 DEBUG((DBG_SPECIAL, "None found\n"));
192 /* extract the prefix */
196 "REGEX match with `%s' (arg `%s')\n",
202 "PREFIX match with `%s' (prefix `%s', arg `%s')\n",
203 sp->label, prefix, ptr));
206 /* invoke the handler */
207 sp->handler(dvi, prefix, ptr);
212 void mdvi_flush_specials(void)
214 DviSpecial *sp, *list;
217 for(list = (DviSpecial *)specials.head; (sp = list); ) {
219 if(sp->prefix) mdvi_free(sp->prefix);
220 if(sp->label) mdvi_free(sp->label);
221 #ifdef WITH_REGEX_SPECIALS
227 specials.head = NULL;
228 specials.tail = NULL;
232 /* some builtin specials */
234 void sp_layer(DviContext *dvi, const char *prefix, const char *arg)
236 if(STREQ("push", arg))
238 else if(STREQ("pop", arg)) {
242 warning(_("%s: tried to pop top level layer\n"),
244 } else if(STREQ("reset", arg))
246 DEBUG((DBG_SPECIAL, "Layer level: %d\n", dvi->curr_layer));