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