Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
special.c
Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 
70  for(i = 0; i < NSPECIALS; i++)
72  builtins[i].label,
73  builtins[i].prefix,
74  builtins[i].regex,
75  builtins[i].handler,
76  1 /* replace if exists */);
77 }
78 
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 
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 
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 
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  mdvi_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