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
pagesel.c
Go to the documentation of this file.
1 /* pagesel.c -- Page selection mechanism */
2 /*
3  * Copyright (C) 2000, Matias Atria
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 #include <config.h>
21 #include <stdlib.h>
22 #include <ctype.h>
23 #include <string.h>
24 #include <limits.h>
25 
26 #include "mdvi.h"
27 #include "private.h"
28 
29 char *program_name = "page";
30 
31 struct _DviPageSpec {
33  int nranges;
34 };
35 
36 DviRange *mdvi_parse_range(const char *format, DviRange *limit, int *nitems, char **endptr)
37 {
38  int quoted;
39  int size;
40  int curr;
41  int done;
42  int lower;
43  int upper;
44  int type;
45  char * cp;
46  char * copy;
47  char * text;
48  DviRange one;
49  DviRange *range;
50 
51  quoted = (*format == '{');
52  if(quoted) format++;
53 
54  size = 0;
55  curr = 0;
56  range = NULL;
57  copy = mdvi_strdup(format);
58  done = 0;
59  lower = 0;
60  upper = 0;
61  type = MDVI_RANGE_UNBOUNDED;
62 
63  if(limit) {
64  switch(limit->type) {
65  case MDVI_RANGE_BOUNDED:
66  lower = limit->from;
67  upper = limit->to;
68  break;
69  case MDVI_RANGE_UPPER:
70  lower = INT_MIN;
71  upper = limit->to;
72  break;
73  case MDVI_RANGE_LOWER:
74  lower = limit->from;
75  upper = INT_MAX;
76  break;
78  lower = INT_MIN;
79  upper = INT_MAX;
80  break;
81  }
82  type = limit->type;
83  } else {
84  lower = INT_MIN;
85  upper = INT_MAX;
86  type = MDVI_RANGE_UNBOUNDED;
87  }
88  one.type = type;
89  one.from = lower;
90  one.to = upper;
91  one.step = 1;
92  for(cp = text = copy; !done; cp++) {
93  char *p;
94  int f, t, s;
95  int ch;
96  int this_type;
97  int lower_given = 0;
98  int upper_given = 0;
99 
100  if(*cp == 0 || *cp == '.' || (*cp == '}' && quoted))
101  done = 1;
102  else if(*cp != ',')
103  continue;
104 
105  if(text == cp)
106  continue;
107  ch = *cp;
108  *cp = 0;
109  f = lower;
110  t = upper;
111  s = 1;
112 
113  p = strchr(text, ':');
114  if(p) *p++ = 0;
115  if(*text) {
116  lower_given = 1;
117  f = strtol(text, NULL, 0);
118  }
119  if(p == NULL) {
120  if(lower_given) {
121  upper_given = 1;
122  t = f; s = 1;
123  }
124  goto finish;
125  }
126  text = p;
127  p = strchr(text, ':');
128  if(p) *p++ = 0;
129  if(*text) {
130  upper_given = 1;
131  t = strtol(text, NULL, 0);
132  }
133  if(p == NULL)
134  goto finish;
135  text = p;
136  if(*text)
137  s = strtol(text, NULL, 0);
138 finish:
139  if(lower_given && upper_given)
140  this_type = MDVI_RANGE_BOUNDED;
141  else if(lower_given) {
142  if(!RANGE_HAS_UPPER(type))
143  this_type = MDVI_RANGE_LOWER;
144  else
145  this_type = MDVI_RANGE_BOUNDED;
146  t = upper;
147  } else if(upper_given) {
148  if(RANGE_HAS_UPPER(one.type)) {
149  one.to++;
150  this_type = MDVI_RANGE_BOUNDED;
151  } else {
152  one.to = lower;
153  if(!RANGE_HAS_LOWER(type))
154  this_type = MDVI_RANGE_UPPER;
155  else
156  this_type = MDVI_RANGE_BOUNDED;
157  }
158  f = one.to;
159  } else {
160  this_type = type;
161  f = lower;
162  t = upper;
163  }
164  one.type = this_type;
165  one.to = t;
166  one.from = f;
167  one.step = s;
168 
169  if(curr == size) {
170  size += 8;
171  range = mdvi_realloc(range, size * sizeof(DviRange));
172  }
173  memcpy(&range[curr++], &one, sizeof(DviRange));
174  *cp = ch;
175  text = cp + 1;
176  }
177  if(done)
178  cp--;
179  if(quoted && *cp == '}')
180  cp++;
181  if(endptr)
182  *endptr = (char *)format + (cp - copy);
183  if(curr && curr < size)
184  range = mdvi_realloc(range, curr * sizeof(DviRange));
185  *nitems = curr;
186  mdvi_free(copy);
187  return range;
188 }
189 
190 DviPageSpec *mdvi_parse_page_spec(const char *format)
191 {
192  /*
193  * a page specification looks like this:
194  * '{'RANGE_SPEC'}' for a DVI spec
195  * '{'RANGE_SPEC'}' '.' ... for a TeX spec
196  */
197  DviPageSpec *spec;
198  DviRange *range;
199  int count;
200  int i;
201  char *ptr;
202 
203  spec = xnalloc(struct _DviPageSpec *, 11);
204  for(i = 0; i < 11; i++)
205  spec[i] = NULL;
206 
207  /* check what kind of spec we're parsing */
208  if(*format != '*') {
209  range = mdvi_parse_range(format, NULL, &count, &ptr);
210  if(ptr == format) {
211  if(range) mdvi_free(range);
212  mdvi_error(_("invalid page specification `%s'\n"), format);
213  return NULL;
214  }
215  } else
216  range = NULL;
217 
218  if(*format == 'D' || *format == 'd' || *ptr != '.')
219  i = 0;
220  else
221  i = 1;
222 
223  if(range) {
224  spec[i] = xalloc(struct _DviPageSpec);
225  spec[i]->ranges = range;
226  spec[i]->nranges = count;
227  } else
228  spec[i] = NULL;
229 
230  if(*ptr != '.') {
231  if(*ptr)
232  mdvi_warning(_("garbage after DVI page specification ignored\n"));
233  return spec;
234  }
235 
236  for(i++; *ptr == '.' && i <= 10; i++) {
237  ptr++;
238  if(*ptr == '*') {
239  ptr++;
240  range = NULL;
241  } else {
242  char *end;
243 
244  range = mdvi_parse_range(ptr, NULL, &count, &end);
245  if(end == ptr) {
246  if(range) mdvi_free(range);
247  range = NULL;
248  } else
249  ptr = end;
250  }
251  if(range != NULL) {
252  spec[i] = xalloc(struct _DviPageSpec);
253  spec[i]->ranges = range;
254  spec[i]->nranges = count;
255  } else
256  spec[i] = NULL;
257  }
258 
259  if(i > 10)
260  mdvi_warning(_("more than 10 counters in page specification\n"));
261  else if(*ptr)
262  mdvi_warning(_("garbage after TeX page specification ignored\n"));
263 
264  return spec;
265 }
266 
267 /* returns non-zero if the given page is included by `spec' */
268 int mdvi_page_selected(DviPageSpec *spec, PageNum page, int dvipage)
269 {
270  int i;
271  int not_found;
272 
273  if(spec == NULL)
274  return 1;
275  if(spec[0]) {
276  not_found = mdvi_in_range(spec[0]->ranges,
277  spec[0]->nranges, dvipage);
278  if(not_found < 0)
279  return 0;
280  }
281  for(i = 1; i <= 10; i++) {
282  if(spec[i] == NULL)
283  continue;
284  not_found = mdvi_in_range(spec[i]->ranges,
285  spec[i]->nranges, (int)page[i]);
286  if(not_found < 0)
287  return 0;
288  }
289  return 1;
290 }
291 
293 {
294  int i;
295 
296  for(i = 0; i < 11; i++)
297  if(spec[i]) {
298  mdvi_free(spec[i]->ranges);
299  mdvi_free(spec[i]);
300  }
301  mdvi_free(spec);
302 }
303 
304 int mdvi_in_range(DviRange *range, int nitems, int value)
305 {
306  DviRange *r;
307 
308  for(r = range; r < range + nitems; r++) {
309  int cond;
310 
311  switch(r->type) {
312  case MDVI_RANGE_BOUNDED:
313  if(value == r->from)
314  return (r - range);
315  if(r->step < 0)
316  cond = (value <= r->from) && (value >= r->to);
317  else
318  cond = (value <= r->to) && (value >= r->from);
319  if(cond && ((value - r->from) % r->step) == 0)
320  return (r - range);
321  break;
322  case MDVI_RANGE_LOWER:
323  if(value == r->from)
324  return (r - range);
325  if(r->step < 0)
326  cond = (value < r->from);
327  else
328  cond = (value > r->from);
329  if(cond && ((value - r->from) % r->step) == 0)
330  return (r - range);
331  break;
332  case MDVI_RANGE_UPPER:
333  if(value == r->to)
334  return (r - range);
335  if(r->step < 0)
336  cond = (value > r->to);
337  else
338  cond = (value < r->to);
339  if(cond && ((value - r->to) % r->step) == 0)
340  return (r - range);
341  break;
343  if((value % r->step) == 0)
344  return (r - range);
345  break;
346  }
347  }
348  return -1;
349 }
350 
351 int mdvi_range_length(DviRange *range, int nitems)
352 {
353  int count = 0;
354  DviRange *r;
355 
356  for(r = range; r < range + nitems; r++) {
357  int n;
358 
359  if(r->type != MDVI_RANGE_BOUNDED)
360  return -2;
361  n = (r->to - r->from) / r->step;
362  if(n < 0)
363  n = 0;
364  count += n + 1;
365  }
366  return count;
367 }
368 
369 #ifdef TEST
370 
371 void print_range(DviRange *range)
372 {
373  switch(range->type) {
374  case MDVI_RANGE_BOUNDED:
375  printf("From %d to %d, step %d\n",
376  range->from, range->to, range->step);
377  break;
378  case MDVI_RANGE_LOWER:
379  printf("From %d, step %d\n",
380  range->from, range->step);
381  break;
382  case MDVI_RANGE_UPPER:
383  printf("From %d, step -%d\n",
384  range->to, range->step);
385  break;
387  printf("From 0, step %d and %d\n",
388  range->step, -range->step);
389  break;
390  }
391 }
392 
393 int main()
394 {
395 #if 0
396  char buf[256];
397  DviRange limit;
398 
399  limit.from = 0;
400  limit.to = 100;
401  limit.step = 2;
402  limit.type = MDVI_RANGE_UNBOUNDED;
403  while(1) {
404  DviRange *range;
405  char *end;
406  int count;
407  int i;
408 
409  printf("Range> "); fflush(stdout);
410  if(fgets(buf, 256, stdin) == NULL)
411  break;
412  if(buf[strlen(buf)-1] == '\n')
413  buf[strlen(buf)-1] = 0;
414  if(buf[0] == 0)
415  continue;
416  end = NULL;
417  range = mdvi_parse_range(buf, &limit, &count, &end);
418  if(range == NULL) {
419  printf("range is empty\n");
420  continue;
421  }
422 
423  for(i = 0; i < count; i++) {
424  printf("Range %d (%d elements):\n",
425  i, mdvi_range_length(&range[i], 1));
426  print_range(&range[i]);
427  }
428  if(end && *end)
429  printf("Tail: [%s]\n", end);
430  printf("range has %d elements\n",
431  mdvi_range_length(range, count));
432 #if 1
433  while(1) {
434  int v;
435 
436  printf("Value: "); fflush(stdout);
437  if(fgets(buf, 256, stdin) == NULL)
438  break;
439  if(buf[strlen(buf)-1] == '\n')
440  buf[strlen(buf)-1] = 0;
441  if(buf[0] == 0)
442  break;
443  v = atoi(buf);
444  i = mdvi_in_range(range, count, v);
445  if(i == -1)
446  printf("%d not in range\n", v);
447  else {
448  printf("%d in range: ", v);
449  print_range(&range[i]);
450  }
451  }
452 #endif
453  if(range) mdvi_free(range);
454  }
455 #else
456  DviPageSpec *spec;
457  char buf[256];
458 
459  while(1) {
460  printf("Spec> "); fflush(stdout);
461  if(fgets(buf, 256, stdin) == NULL)
462  break;
463  if(buf[strlen(buf)-1] == '\n')
464  buf[strlen(buf)-1] = 0;
465  if(buf[0] == 0)
466  continue;
467  spec = mdvi_parse_page_spec(buf);
468  if(spec == NULL)
469  printf("no spec parsed\n");
470  else {
471  int i;
472 
473  printf("spec = ");
474  for(i = 0; i < 11; i++) {
475  printf("Counter %d:\n", i);
476  if(spec[i]) {
477  int k;
478 
479  for(k = 0; k < spec[i]->nranges; k++)
480  print_range(&spec[i]->ranges[k]);
481  } else
482  printf("\t*\n");
483  }
484  mdvi_free_page_spec(spec);
485  }
486  }
487 #endif
488  exit(0);
489 
490 }
491 #endif /* TEST */