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