]> www.fi.muni.cz Git - evince.git/blob - backend/dvi/mdvi-lib/pagesel.c
Update FSF address everywhere.
[evince.git] / backend / dvi / mdvi-lib / pagesel.c
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 {
32         DviRange *ranges;
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;
77                         case MDVI_RANGE_UNBOUNDED:
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
292 void    mdvi_free_page_spec(DviPageSpec *spec)
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;
342                 case MDVI_RANGE_UNBOUNDED:
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;
386         case MDVI_RANGE_UNBOUNDED:
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 */