]> www.fi.muni.cz Git - evince.git/blob - backend/dvi/mdvi-lib/special.c
Include config.h. Bug #504721.
[evince.git] / backend / dvi / mdvi-lib / special.c
1 /*
2  * Copyright (C) 2000, Matias Atria
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include <config.h>
20 #include <ctype.h>
21 #include <string.h>
22
23 #include "mdvi.h"
24 #include "private.h"
25
26 #if defined(WITH_REGEX_SPECIALS) && defined(HAVE_REGEX_H)
27 #include <regex.h>
28 #endif
29
30 typedef struct _DviSpecial {
31         struct _DviSpecial *next;
32         struct _DviSpecial *prev;
33         char    *label;
34         char    *prefix;
35         size_t  plen;
36 #ifdef WITH_REGEX_SPECIALS
37         regex_t reg;
38         int     has_reg;
39 #endif
40         DviSpecialHandler handler;
41 } DviSpecial;
42         
43 static ListHead specials = {NULL, NULL, 0};
44
45 #define SPECIAL(x)      \
46         void x __PROTO((DviContext *, const char *, const char *))
47
48 static SPECIAL(sp_layer);
49 extern SPECIAL(epsf_special);
50 extern SPECIAL(do_color_special);
51
52 static struct {
53         char    *label;
54         char    *prefix;
55         char    *regex;
56         DviSpecialHandler handler;
57 } builtins[] = {
58         {"Layers", "layer", NULL, sp_layer},
59         {"EPSF", "psfile", NULL, epsf_special}
60 };
61 #define NSPECIALS       (sizeof(builtins) / sizeof(builtins[0]))
62 static int registered_builtins = 0;
63
64 static void register_builtin_specials(void)
65 {
66         int     i;
67
68         ASSERT(registered_builtins == 0);       
69         registered_builtins = 1;
70         for(i = 0; i < NSPECIALS; i++)
71                 mdvi_register_special(
72                         builtins[i].label,
73                         builtins[i].prefix,
74                         builtins[i].regex,
75                         builtins[i].handler,
76                         1 /* replace if exists */);
77 }
78
79 static DviSpecial *find_special_prefix(const char *prefix)
80 {
81         DviSpecial *sp;
82         
83         /* should have a hash table here, but I'm so lazy */
84         for(sp = (DviSpecial *)specials.head; sp; sp = sp->next) {
85                 if(STRCEQ(sp->prefix, prefix))
86                         break;
87         }
88         return sp;
89 }
90
91 int     mdvi_register_special(const char *label, const char *prefix, 
92         const char *regex, DviSpecialHandler handler, int replace)
93 {
94         DviSpecial *sp;
95         int     newsp = 0;
96
97         if(!registered_builtins)
98                 register_builtin_specials();
99
100         sp = find_special_prefix(prefix);
101         if(sp == NULL) {
102                 sp = xalloc(DviSpecial);
103                 sp->prefix = mdvi_strdup(prefix);
104                 newsp = 1;
105         } else if(!replace)
106                 return -1;
107         else {
108                 mdvi_free(sp->label);
109                 sp->label = NULL;
110         }
111
112 #ifdef WITH_REGEX_SPECIALS
113         if(!newsp && sp->has_reg) {
114                 regfree(&sp->reg);
115                 sp->has_reg = 0;
116         }
117         if(regex && regcomp(&sp->reg, regex, REG_NOSUB) != 0) {
118                 if(newsp) {
119                         mdvi_free(sp->prefix);
120                         mdvi_free(sp);
121                 }
122                 return -1;
123         }
124         sp->has_reg = (regex != NULL);
125 #endif
126         sp->handler = handler;
127         sp->label = mdvi_strdup(label);
128         sp->plen = strlen(prefix);
129         if(newsp)
130                 listh_prepend(&specials, LIST(sp));             
131         DEBUG((DBG_SPECIAL, 
132                 "New \\special handler `%s' with prefix `%s'\n", 
133                 label, prefix));
134         return 0;
135 }
136
137 int     mdvi_unregister_special(const char *prefix)
138 {
139         DviSpecial *sp;
140         
141         sp = find_special_prefix(prefix);       
142         if(sp == NULL)
143                 return -1;
144         mdvi_free(sp->prefix);
145 #ifdef WITH_REGEX_SPECIALS
146         if(sp->has_reg)
147                 regfree(&sp->reg);
148 #endif
149         listh_remove(&specials, LIST(sp));
150         mdvi_free(sp);
151         return 0;
152 }
153
154 #define IS_PREFIX_DELIMITER(x)  (strchr(" \t\n:=", (x)) != NULL)
155
156 int     mdvi_do_special(DviContext *dvi, char *string)
157 {
158         char    *prefix;
159         char    *ptr;   
160         DviSpecial *sp;
161
162         if(!registered_builtins) {
163         }
164
165         if(!string || !*string)
166                 return 0;
167
168         /* skip leading spaces */
169         while(*string && isspace(*string))
170                 string++;
171
172         DEBUG((DBG_SPECIAL, "Looking for a handler for `%s'\n", string));
173         
174         /* now try to find a match */
175         ptr = string;
176         for(sp = (DviSpecial *)specials.head; sp; sp = sp->next) {
177 #ifdef WITH_REGEX_SPECIALS
178                 if(sp->has_reg && !regexec(&sp->reg, ptr, 0, 0, 0))
179                         break;
180 #endif
181                 /* check the prefix */
182                 if(STRNCEQ(sp->prefix, ptr, sp->plen)) {
183                         ptr += sp->plen;
184                         break;
185                 }
186         }
187
188         if(sp == NULL) {
189                 DEBUG((DBG_SPECIAL, "None found\n"));
190                 return -1;
191         }
192
193         /* extract the prefix */
194         if(ptr == string) {
195                 prefix = NULL;
196                 DEBUG((DBG_SPECIAL, 
197                         "REGEX match with `%s' (arg `%s')\n",
198                         sp->label, ptr));
199         } else {
200                 if(*ptr) *ptr++ = 0;
201                 prefix = string;
202                 DEBUG((DBG_SPECIAL, 
203                         "PREFIX match with `%s' (prefix `%s', arg `%s')\n",
204                         sp->label, prefix, ptr));
205         }
206
207         /* invoke the handler */
208         sp->handler(dvi, prefix, ptr);
209
210         return 0;
211 }
212
213 void    mdvi_flush_specials(void)
214 {
215         DviSpecial *sp, *list;
216         
217         
218         for(list = (DviSpecial *)specials.head; (sp = list); ) {
219                 list = sp->next;
220                 if(sp->prefix) mdvi_free(sp->prefix);
221                 if(sp->label) mdvi_free(sp->label);
222 #ifdef WITH_REGEX_SPECIALS
223                 if(sp->has_reg)
224                         regfree(&sp->reg);
225 #endif
226                 mdvi_free(sp);
227         }
228         specials.head = NULL;
229         specials.tail = NULL;
230         specials.count = 0;
231 }
232
233 /* some builtin specials */
234
235 void    sp_layer(DviContext *dvi, const char *prefix, const char *arg)
236 {
237         if(STREQ("push", arg))
238                 dvi->curr_layer++;
239         else if(STREQ("pop", arg)) {
240                 if(dvi->curr_layer)
241                         dvi->curr_layer--;
242                 else
243                         warning(_("%s: tried to pop top level layer\n"),
244                                 dvi->filename);
245         } else if(STREQ("reset", arg))
246                 dvi->curr_layer = 0;
247         DEBUG((DBG_SPECIAL, "Layer level: %d\n", dvi->curr_layer));
248 }
249