Sun, 21 Dec 2003 23:52:11 +0000
fix svn:keywords property
eric@49 | 1 | /* |
eric@125 | 2 | * tumble: build a PDF file from image files |
eric@49 | 3 | * |
eric@49 | 4 | * Semantic routines for spec file parser |
eric@139 | 5 | * $Id: semantics.c,v 1.23 2003/03/19 07:39:55 eric Exp $ |
eric@49 | 6 | * Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com> |
eric@49 | 7 | * |
eric@49 | 8 | * This program is free software; you can redistribute it and/or modify |
eric@49 | 9 | * it under the terms of the GNU General Public License version 2 as |
eric@49 | 10 | * published by the Free Software Foundation. Note that permission is |
eric@49 | 11 | * not granted to redistribute this program under the terms of any |
eric@49 | 12 | * other version of the General Public License. |
eric@49 | 13 | * |
eric@49 | 14 | * This program is distributed in the hope that it will be useful, |
eric@49 | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
eric@49 | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
eric@49 | 17 | * GNU General Public License for more details. |
eric@49 | 18 | * |
eric@49 | 19 | * You should have received a copy of the GNU General Public License |
eric@49 | 20 | * along with this program; if not, write to the Free Software |
eric@104 | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA |
eric@104 | 22 | */ |
eric@49 | 23 | |
eric@49 | 24 | |
eric@48 | 25 | #include <stdbool.h> |
eric@48 | 26 | #include <stdint.h> |
eric@18 | 27 | #include <stdlib.h> |
eric@18 | 28 | #include <string.h> |
eric@16 | 29 | #include <stdio.h> |
eric@16 | 30 | |
eric@18 | 31 | #include "semantics.h" |
eric@160 | 32 | |
eric@160 | 33 | #ifdef CTL_LANG |
eric@16 | 34 | #include "parser.tab.h" |
eric@160 | 35 | #endif |
eric@160 | 36 | |
eric@125 | 37 | #include "tumble.h" |
eric@16 | 38 | |
eric@16 | 39 | |
eric@22 | 40 | typedef struct |
eric@22 | 41 | { |
eric@48 | 42 | bool has_page_size; |
eric@32 | 43 | page_size_t page_size; |
eric@22 | 44 | |
eric@48 | 45 | bool has_rotation; |
eric@22 | 46 | int rotation; |
eric@22 | 47 | |
eric@48 | 48 | bool has_crop; |
eric@22 | 49 | crop_t crop; |
eric@22 | 50 | } input_modifiers_t; |
eric@22 | 51 | |
eric@22 | 52 | |
eric@22 | 53 | typedef struct input_context_t |
eric@22 | 54 | { |
eric@22 | 55 | struct input_context_t *parent; |
eric@22 | 56 | struct input_context_t *next; |
eric@22 | 57 | |
eric@22 | 58 | int image_count; /* how many pages reference this context, |
eric@22 | 59 | including those from subcontexts */ |
eric@22 | 60 | |
eric@22 | 61 | char *input_file; |
eric@22 | 62 | |
eric@22 | 63 | input_modifiers_t modifiers [INPUT_MODIFIER_TYPE_COUNT]; |
eric@22 | 64 | } input_context_t; |
eric@22 | 65 | |
eric@22 | 66 | |
eric@22 | 67 | typedef struct input_image_t |
eric@22 | 68 | { |
eric@22 | 69 | struct input_image_t *next; |
eric@22 | 70 | input_context_t *input_context; |
eric@22 | 71 | range_t range; |
eric@22 | 72 | } input_image_t; |
eric@22 | 73 | |
eric@22 | 74 | |
eric@22 | 75 | typedef struct output_context_t |
eric@22 | 76 | { |
eric@22 | 77 | struct output_context_t *parent; |
eric@22 | 78 | struct output_context_t *next; |
eric@22 | 79 | |
eric@22 | 80 | int page_count; /* how many pages reference this context, |
eric@22 | 81 | including those from subcontexts */ |
eric@22 | 82 | |
eric@22 | 83 | char *output_file; |
eric@30 | 84 | pdf_file_attributes_t file_attributes; |
eric@30 | 85 | |
eric@22 | 86 | bookmark_t *first_bookmark; |
eric@22 | 87 | bookmark_t *last_bookmark; |
eric@25 | 88 | |
eric@48 | 89 | bool has_page_label; |
eric@25 | 90 | page_label_t page_label; |
eric@22 | 91 | } output_context_t; |
eric@22 | 92 | |
eric@22 | 93 | |
eric@22 | 94 | typedef struct output_page_t |
eric@22 | 95 | { |
eric@22 | 96 | struct output_page_t *next; |
eric@22 | 97 | output_context_t *output_context; |
eric@22 | 98 | range_t range; |
eric@22 | 99 | bookmark_t *bookmark_list; |
eric@22 | 100 | } output_page_t; |
eric@22 | 101 | |
eric@22 | 102 | |
eric@36 | 103 | #undef SEMANTIC_DEBUG |
eric@36 | 104 | |
eric@19 | 105 | #ifdef SEMANTIC_DEBUG |
eric@19 | 106 | #define SDBG(x) printf x |
eric@19 | 107 | #else |
eric@19 | 108 | #define SDBG(x) |
eric@19 | 109 | #endif |
eric@19 | 110 | |
eric@19 | 111 | |
eric@16 | 112 | FILE *yyin; |
eric@16 | 113 | int line; /* line number in spec file */ |
eric@16 | 114 | |
eric@24 | 115 | int bookmark_level; |
eric@16 | 116 | |
eric@20 | 117 | input_context_t *first_input_context; |
eric@20 | 118 | input_context_t *last_input_context; |
eric@20 | 119 | |
eric@20 | 120 | input_modifier_type_t current_modifier_context; |
eric@18 | 121 | |
eric@20 | 122 | input_image_t *first_input_image; |
eric@20 | 123 | input_image_t *last_input_image; |
eric@18 | 124 | |
eric@20 | 125 | output_context_t *first_output_context; |
eric@20 | 126 | output_context_t *last_output_context; |
eric@20 | 127 | |
eric@20 | 128 | output_page_t *first_output_page; |
eric@20 | 129 | output_page_t *last_output_page; |
eric@16 | 130 | |
eric@16 | 131 | |
eric@19 | 132 | void input_push_context (void) |
eric@16 | 133 | { |
eric@18 | 134 | input_context_t *new_input_context; |
eric@18 | 135 | |
eric@18 | 136 | new_input_context = malloc (sizeof (input_context_t)); |
eric@18 | 137 | if (! new_input_context) |
eric@18 | 138 | { |
eric@20 | 139 | fprintf (stderr, "failed to malloc an input context\n"); |
eric@18 | 140 | return; |
eric@18 | 141 | } |
eric@18 | 142 | |
eric@20 | 143 | if (last_input_context) |
eric@18 | 144 | { |
eric@20 | 145 | memcpy (new_input_context, last_input_context, sizeof (input_context_t)); |
eric@20 | 146 | new_input_context->image_count = 0; |
eric@18 | 147 | } |
eric@18 | 148 | else |
eric@20 | 149 | { |
eric@20 | 150 | memset (new_input_context, 0, sizeof (input_context_t)); |
eric@20 | 151 | first_input_context = new_input_context; |
eric@20 | 152 | } |
eric@18 | 153 | |
eric@20 | 154 | new_input_context->parent = last_input_context; |
eric@20 | 155 | last_input_context = new_input_context; |
eric@16 | 156 | }; |
eric@16 | 157 | |
eric@16 | 158 | void input_pop_context (void) |
eric@16 | 159 | { |
eric@20 | 160 | if (! last_input_context) |
eric@18 | 161 | { |
eric@18 | 162 | fprintf (stderr, "failed to pop an input context\n"); |
eric@18 | 163 | return; |
eric@18 | 164 | } |
eric@18 | 165 | |
eric@20 | 166 | last_input_context = last_input_context->parent; |
eric@16 | 167 | }; |
eric@16 | 168 | |
eric@19 | 169 | void input_set_modifier_context (input_modifier_type_t type) |
eric@19 | 170 | { |
eric@19 | 171 | current_modifier_context = type; |
eric@19 | 172 | #ifdef SEMANTIC_DEBUG |
eric@19 | 173 | SDBG(("modifier type ")); |
eric@19 | 174 | switch (type) |
eric@19 | 175 | { |
eric@19 | 176 | case INPUT_MODIFIER_ALL: SDBG(("all")); break; |
eric@19 | 177 | case INPUT_MODIFIER_ODD: SDBG(("odd")); break; |
eric@19 | 178 | case INPUT_MODIFIER_EVEN: SDBG(("even")); break; |
eric@19 | 179 | default: SDBG(("unknown %d", type)); |
eric@19 | 180 | } |
eric@19 | 181 | SDBG(("\n")); |
eric@19 | 182 | #endif /* SEMANTIC_DEBUG */ |
eric@19 | 183 | } |
eric@19 | 184 | |
eric@22 | 185 | static void input_clone (void) |
eric@20 | 186 | { |
eric@20 | 187 | input_context_t *new_input_context; |
eric@20 | 188 | |
eric@20 | 189 | if (! last_input_context->image_count) |
eric@20 | 190 | return; |
eric@20 | 191 | |
eric@20 | 192 | new_input_context = malloc (sizeof (input_context_t)); |
eric@20 | 193 | if (! new_input_context) |
eric@20 | 194 | { |
eric@20 | 195 | fprintf (stderr, "failed to malloc an input context\n"); |
eric@20 | 196 | return; |
eric@20 | 197 | } |
eric@20 | 198 | |
eric@20 | 199 | memcpy (new_input_context, last_input_context, sizeof (input_context_t)); |
eric@20 | 200 | new_input_context->image_count = 0; |
eric@20 | 201 | last_input_context->next = new_input_context; |
eric@45 | 202 | last_input_context = new_input_context; |
eric@20 | 203 | } |
eric@20 | 204 | |
eric@16 | 205 | void input_set_file (char *name) |
eric@16 | 206 | { |
eric@20 | 207 | input_clone (); |
eric@20 | 208 | last_input_context->input_file = name; |
eric@16 | 209 | }; |
eric@16 | 210 | |
eric@19 | 211 | void input_set_rotation (int rotation) |
eric@19 | 212 | { |
eric@20 | 213 | last_input_context->modifiers [current_modifier_context].has_rotation = 1; |
eric@20 | 214 | last_input_context->modifiers [current_modifier_context].rotation = rotation; |
eric@19 | 215 | SDBG(("rotation %d\n", rotation)); |
eric@19 | 216 | } |
eric@19 | 217 | |
eric@32 | 218 | void input_set_page_size (page_size_t size) |
eric@32 | 219 | { |
eric@32 | 220 | last_input_context->modifiers [current_modifier_context].has_page_size = 1; |
eric@32 | 221 | last_input_context->modifiers [current_modifier_context].page_size = size; |
eric@32 | 222 | SDBG(("page size %f, %f\n", size.width, size.height)); |
eric@32 | 223 | } |
eric@32 | 224 | |
eric@22 | 225 | static void increment_input_image_count (int count) |
eric@16 | 226 | { |
eric@20 | 227 | input_context_t *context; |
eric@20 | 228 | |
eric@20 | 229 | for (context = last_input_context; context; context = context->parent) |
eric@20 | 230 | context->image_count += count; |
eric@20 | 231 | } |
eric@20 | 232 | |
eric@20 | 233 | void input_images (range_t range) |
eric@20 | 234 | { |
eric@20 | 235 | input_image_t *new_image; |
eric@20 | 236 | int count = ((range.last - range.first) + 1); |
eric@20 | 237 | |
eric@19 | 238 | #ifdef SEMANTIC_DEBUG |
eric@20 | 239 | if (range.first == range.last) |
eric@20 | 240 | SDBG(("image %d\n", range.first)); |
eric@16 | 241 | else |
eric@20 | 242 | SDBG(("images %d..%d\n", range.first, range.last)); |
eric@19 | 243 | #endif /* SEMANTIC_DEBUG */ |
eric@20 | 244 | |
eric@20 | 245 | new_image = calloc (1, sizeof (input_image_t)); |
eric@20 | 246 | if (! new_image) |
eric@20 | 247 | { |
eric@20 | 248 | fprintf (stderr, "failed to malloc an input image struct\n"); |
eric@20 | 249 | return; |
eric@20 | 250 | } |
eric@20 | 251 | if (first_input_image) |
eric@20 | 252 | { |
eric@20 | 253 | last_input_image->next = new_image; |
eric@20 | 254 | last_input_image = new_image; |
eric@20 | 255 | } |
eric@20 | 256 | else |
eric@20 | 257 | { |
eric@20 | 258 | first_input_image = last_input_image = new_image; |
eric@20 | 259 | } |
eric@20 | 260 | new_image->range = range; |
eric@20 | 261 | new_image->input_context = last_input_context; |
eric@20 | 262 | increment_input_image_count (count); |
eric@16 | 263 | } |
eric@16 | 264 | |
eric@18 | 265 | |
eric@18 | 266 | void output_push_context (void) |
eric@18 | 267 | { |
eric@20 | 268 | output_context_t *new_output_context; |
eric@20 | 269 | |
eric@20 | 270 | new_output_context = malloc (sizeof (output_context_t)); |
eric@20 | 271 | if (! new_output_context) |
eric@20 | 272 | { |
eric@20 | 273 | fprintf (stderr, "failed to malloc an output context\n"); |
eric@20 | 274 | return; |
eric@20 | 275 | } |
eric@20 | 276 | |
eric@20 | 277 | if (last_output_context) |
eric@20 | 278 | { |
eric@20 | 279 | memcpy (new_output_context, last_output_context, sizeof (output_context_t)); |
eric@20 | 280 | new_output_context->page_count = 0; |
eric@21 | 281 | new_output_context->first_bookmark = NULL; |
eric@21 | 282 | new_output_context->last_bookmark = NULL; |
eric@20 | 283 | } |
eric@20 | 284 | else |
eric@20 | 285 | { |
eric@20 | 286 | memset (new_output_context, 0, sizeof (output_context_t)); |
eric@20 | 287 | first_output_context = new_output_context; |
eric@20 | 288 | } |
eric@20 | 289 | |
eric@20 | 290 | new_output_context->parent = last_output_context; |
eric@20 | 291 | last_output_context = new_output_context; |
eric@18 | 292 | }; |
eric@18 | 293 | |
eric@20 | 294 | void output_pop_context (void) |
eric@20 | 295 | { |
eric@20 | 296 | if (! last_output_context) |
eric@20 | 297 | { |
eric@20 | 298 | fprintf (stderr, "failed to pop an output context\n"); |
eric@20 | 299 | return; |
eric@20 | 300 | } |
eric@20 | 301 | |
eric@20 | 302 | last_output_context = last_output_context->parent; |
eric@20 | 303 | }; |
eric@20 | 304 | |
eric@22 | 305 | static void output_clone (void) |
eric@20 | 306 | { |
eric@20 | 307 | output_context_t *new_output_context; |
eric@20 | 308 | |
eric@20 | 309 | if (! last_output_context->page_count) |
eric@20 | 310 | return; |
eric@20 | 311 | |
eric@20 | 312 | new_output_context = malloc (sizeof (output_context_t)); |
eric@20 | 313 | if (! new_output_context) |
eric@20 | 314 | { |
eric@20 | 315 | fprintf (stderr, "failed to malloc an output context\n"); |
eric@20 | 316 | return; |
eric@20 | 317 | } |
eric@20 | 318 | |
eric@20 | 319 | memcpy (new_output_context, last_output_context, sizeof (output_context_t)); |
eric@20 | 320 | new_output_context->page_count = 0; |
eric@20 | 321 | last_output_context->next = new_output_context; |
eric@20 | 322 | } |
eric@20 | 323 | |
eric@16 | 324 | void output_set_file (char *name) |
eric@16 | 325 | { |
eric@20 | 326 | output_clone (); |
eric@20 | 327 | last_output_context->output_file = name; |
eric@30 | 328 | last_output_context->file_attributes.author = NULL; |
eric@30 | 329 | last_output_context->file_attributes.creator = NULL; |
eric@30 | 330 | last_output_context->file_attributes.title = NULL; |
eric@30 | 331 | last_output_context->file_attributes.subject = NULL; |
eric@30 | 332 | last_output_context->file_attributes.keywords = NULL; |
eric@16 | 333 | }; |
eric@16 | 334 | |
eric@30 | 335 | void output_set_author (char *author) |
eric@30 | 336 | { |
eric@30 | 337 | last_output_context->file_attributes.author = author; |
eric@30 | 338 | } |
eric@30 | 339 | |
eric@30 | 340 | void output_set_creator (char *creator) |
eric@30 | 341 | { |
eric@30 | 342 | last_output_context->file_attributes.creator = creator; |
eric@30 | 343 | } |
eric@30 | 344 | |
eric@30 | 345 | void output_set_title (char *title) |
eric@30 | 346 | { |
eric@30 | 347 | last_output_context->file_attributes.title = title; |
eric@30 | 348 | } |
eric@30 | 349 | |
eric@30 | 350 | void output_set_subject (char *subject) |
eric@30 | 351 | { |
eric@30 | 352 | last_output_context->file_attributes.subject = subject; |
eric@30 | 353 | } |
eric@30 | 354 | |
eric@30 | 355 | void output_set_keywords (char *keywords) |
eric@30 | 356 | { |
eric@30 | 357 | last_output_context->file_attributes.keywords = keywords; |
eric@30 | 358 | } |
eric@30 | 359 | |
eric@20 | 360 | void output_set_bookmark (char *name) |
eric@16 | 361 | { |
eric@20 | 362 | bookmark_t *new_bookmark; |
eric@20 | 363 | |
eric@20 | 364 | /* As the language is defined (parser.y), a bookmark can only appear |
eric@20 | 365 | at the beginning of a context! */ |
eric@20 | 366 | if (last_output_context->page_count) |
eric@20 | 367 | { |
eric@20 | 368 | fprintf (stderr, "internal error, bookmark not at beginning of context\n"); |
eric@20 | 369 | exit (2); |
eric@20 | 370 | } |
eric@20 | 371 | |
eric@20 | 372 | new_bookmark = calloc (1, sizeof (bookmark_t)); |
eric@20 | 373 | if (! new_bookmark) |
eric@20 | 374 | { |
eric@20 | 375 | fprintf (stderr, "failed to calloc a bookmark\n"); |
eric@20 | 376 | return; |
eric@20 | 377 | } |
eric@20 | 378 | |
eric@24 | 379 | new_bookmark->level = bookmark_level; |
eric@20 | 380 | new_bookmark->name = name; |
eric@20 | 381 | if (last_output_context->first_bookmark) |
eric@20 | 382 | last_output_context->last_bookmark->next = new_bookmark; |
eric@20 | 383 | else |
eric@20 | 384 | last_output_context->first_bookmark = new_bookmark; |
eric@20 | 385 | last_output_context->last_bookmark = new_bookmark; |
eric@20 | 386 | } |
eric@20 | 387 | |
eric@25 | 388 | void output_set_page_label (page_label_t label) |
eric@20 | 389 | { |
eric@20 | 390 | output_clone (); |
eric@25 | 391 | last_output_context->has_page_label = 1; |
eric@25 | 392 | last_output_context->page_label = label; |
eric@20 | 393 | } |
eric@20 | 394 | |
eric@22 | 395 | static void increment_output_page_count (int count) |
eric@20 | 396 | { |
eric@20 | 397 | output_context_t *context; |
eric@20 | 398 | |
eric@20 | 399 | for (context = last_output_context; context; context = context->parent) |
eric@20 | 400 | context->page_count += count; |
eric@20 | 401 | } |
eric@20 | 402 | |
eric@21 | 403 | |
eric@20 | 404 | void output_pages (range_t range) |
eric@20 | 405 | { |
eric@20 | 406 | output_page_t *new_page; |
eric@21 | 407 | output_context_t *context; |
eric@20 | 408 | int count = ((range.last - range.first) + 1); |
eric@20 | 409 | |
eric@19 | 410 | #ifdef SEMANTIC_DEBUG |
eric@20 | 411 | if (range.first == range.last) |
eric@20 | 412 | SDBG(("page %d\n", range.first)); |
eric@16 | 413 | else |
eric@20 | 414 | SDBG(("pages %d..%d\n", range.first, range.last)); |
eric@19 | 415 | #endif /* SEMANTIC_DEBUG */ |
eric@20 | 416 | |
eric@20 | 417 | new_page = calloc (1, sizeof (output_page_t)); |
eric@20 | 418 | if (! new_page) |
eric@20 | 419 | { |
eric@20 | 420 | fprintf (stderr, "failed to malloc an output page struct\n"); |
eric@20 | 421 | return; |
eric@20 | 422 | } |
eric@20 | 423 | if (first_output_page) |
eric@20 | 424 | { |
eric@20 | 425 | last_output_page->next = new_page; |
eric@20 | 426 | last_output_page = new_page; |
eric@20 | 427 | } |
eric@20 | 428 | else |
eric@20 | 429 | { |
eric@20 | 430 | first_output_page = last_output_page = new_page; |
eric@20 | 431 | } |
eric@20 | 432 | new_page->range = range; |
eric@20 | 433 | new_page->output_context = last_output_context; |
eric@20 | 434 | |
eric@21 | 435 | /* transfer bookmarks from context(s) to page */ |
eric@21 | 436 | for (context = last_output_context; context; context = context->parent) |
eric@21 | 437 | if (context->first_bookmark) |
eric@21 | 438 | { |
eric@21 | 439 | context->last_bookmark->next = new_page->bookmark_list; |
eric@21 | 440 | new_page->bookmark_list = context->first_bookmark; |
eric@21 | 441 | context->first_bookmark = NULL; |
eric@21 | 442 | context->last_bookmark = NULL; |
eric@21 | 443 | } |
eric@20 | 444 | |
eric@20 | 445 | increment_output_page_count (count); |
eric@16 | 446 | } |
eric@16 | 447 | |
eric@16 | 448 | |
eric@16 | 449 | void yyerror (char *s) |
eric@16 | 450 | { |
eric@16 | 451 | fprintf (stderr, "%d: %s\n", line, s); |
eric@16 | 452 | } |
eric@16 | 453 | |
eric@16 | 454 | |
eric@55 | 455 | static char *get_input_filename (input_context_t *context) |
eric@20 | 456 | { |
eric@20 | 457 | for (; context; context = context->parent) |
eric@20 | 458 | if (context->input_file) |
eric@20 | 459 | return (context->input_file); |
eric@20 | 460 | fprintf (stderr, "no input file name found\n"); |
eric@20 | 461 | exit (2); |
eric@20 | 462 | } |
eric@20 | 463 | |
eric@48 | 464 | static bool get_input_rotation (input_context_t *context, |
eric@48 | 465 | input_modifier_type_t type, |
eric@48 | 466 | int *rotation) |
eric@20 | 467 | { |
eric@20 | 468 | for (; context; context = context->parent) |
eric@20 | 469 | { |
eric@20 | 470 | if (context->modifiers [type].has_rotation) |
eric@32 | 471 | { |
eric@32 | 472 | * rotation = context->modifiers [type].rotation; |
eric@32 | 473 | return (1); |
eric@32 | 474 | } |
eric@20 | 475 | if (context->modifiers [INPUT_MODIFIER_ALL].has_rotation) |
eric@32 | 476 | { |
eric@32 | 477 | * rotation = context->modifiers [INPUT_MODIFIER_ALL].rotation; |
eric@32 | 478 | return (1); |
eric@32 | 479 | } |
eric@32 | 480 | } |
eric@32 | 481 | return (0); /* default */ |
eric@32 | 482 | } |
eric@32 | 483 | |
eric@48 | 484 | static bool get_input_page_size (input_context_t *context, |
eric@48 | 485 | input_modifier_type_t type, |
eric@48 | 486 | page_size_t *page_size) |
eric@32 | 487 | { |
eric@32 | 488 | for (; context; context = context->parent) |
eric@32 | 489 | { |
eric@32 | 490 | if (context->modifiers [type].has_page_size) |
eric@32 | 491 | { |
eric@32 | 492 | * page_size = context->modifiers [type].page_size; |
eric@32 | 493 | return (1); |
eric@32 | 494 | } |
eric@32 | 495 | if (context->modifiers [INPUT_MODIFIER_ALL].has_page_size) |
eric@32 | 496 | { |
eric@32 | 497 | * page_size = context->modifiers [INPUT_MODIFIER_ALL].page_size; |
eric@32 | 498 | return (1); |
eric@32 | 499 | } |
eric@20 | 500 | } |
eric@20 | 501 | return (0); /* default */ |
eric@20 | 502 | } |
eric@20 | 503 | |
eric@55 | 504 | static char *get_output_filename (output_context_t *context) |
eric@20 | 505 | { |
eric@20 | 506 | for (; context; context = context->parent) |
eric@20 | 507 | if (context->output_file) |
eric@20 | 508 | return (context->output_file); |
eric@30 | 509 | fprintf (stderr, "no output file found\n"); |
eric@30 | 510 | exit (2); |
eric@30 | 511 | } |
eric@30 | 512 | |
eric@30 | 513 | static pdf_file_attributes_t *get_output_file_attributes (output_context_t *context) |
eric@30 | 514 | { |
eric@30 | 515 | for (; context; context = context->parent) |
eric@30 | 516 | if (context->output_file) |
eric@30 | 517 | return (& context->file_attributes); |
eric@30 | 518 | fprintf (stderr, "no output file found\n"); |
eric@20 | 519 | exit (2); |
eric@20 | 520 | } |
eric@20 | 521 | |
eric@25 | 522 | static page_label_t *get_output_page_label (output_context_t *context) |
eric@20 | 523 | { |
eric@20 | 524 | for (; context; context = context->parent) |
eric@25 | 525 | if (context->has_page_label) |
eric@25 | 526 | return (& context->page_label); |
eric@20 | 527 | return (NULL); /* default */ |
eric@20 | 528 | } |
eric@20 | 529 | |
eric@20 | 530 | |
eric@20 | 531 | #ifdef SEMANTIC_DEBUG |
eric@20 | 532 | void dump_input_tree (void) |
eric@20 | 533 | { |
eric@20 | 534 | input_image_t *image; |
eric@20 | 535 | int i; |
eric@20 | 536 | |
eric@20 | 537 | printf ("input images:\n"); |
eric@20 | 538 | for (image = first_input_image; image; image = image->next) |
eric@20 | 539 | for (i = image->range.first; i <= image->range.last; i++) |
eric@20 | 540 | { |
eric@20 | 541 | input_modifier_type_t parity = (i % 2) ? INPUT_MODIFIER_ODD : INPUT_MODIFIER_EVEN; |
eric@48 | 542 | bool has_rotation, has_page_size; |
eric@32 | 543 | int rotation; |
eric@32 | 544 | page_size_t page_size; |
eric@32 | 545 | |
eric@32 | 546 | has_rotation = get_input_rotation (image->input_context, |
eric@32 | 547 | parity, |
eric@32 | 548 | & rotation); |
eric@32 | 549 | has_page_size = get_input_page_size (image->input_context, |
eric@32 | 550 | parity, |
eric@32 | 551 | & page_size); |
eric@32 | 552 | printf ("file '%s' image %d", |
eric@55 | 553 | get_input_filename (image->input_context), |
eric@32 | 554 | i); |
eric@32 | 555 | if (has_rotation) |
eric@32 | 556 | printf (" rotation %d", rotation); |
eric@32 | 557 | if (has_page_size) |
eric@32 | 558 | printf (" size %f, %f", page_size.width, page_size.height); |
eric@32 | 559 | printf ("\n"); |
eric@45 | 560 | printf ("context: %08x\n", image->input_context); |
eric@20 | 561 | } |
eric@20 | 562 | } |
eric@20 | 563 | |
eric@20 | 564 | void dump_output_tree (void) |
eric@20 | 565 | { |
eric@20 | 566 | int i; |
eric@20 | 567 | output_page_t *page; |
eric@20 | 568 | bookmark_t *bookmark; |
eric@20 | 569 | |
eric@20 | 570 | printf ("output pages:\n"); |
eric@20 | 571 | for (page = first_output_page; page; page = page->next) |
eric@20 | 572 | { |
eric@20 | 573 | if (page->bookmark_list) |
eric@20 | 574 | { |
eric@20 | 575 | for (bookmark = page->bookmark_list; bookmark; bookmark = bookmark->next) |
eric@25 | 576 | printf ("bookmark %d \"%s\"\n", bookmark->level, bookmark->name); |
eric@20 | 577 | } |
eric@20 | 578 | for (i = page->range.first; i <= page->range.last; i++) |
eric@20 | 579 | { |
eric@25 | 580 | page_label_t *label = get_output_page_label (page->output_context); |
eric@55 | 581 | printf ("file \"%s\" ", get_output_filename (page->output_context)); |
eric@25 | 582 | if (label) |
eric@25 | 583 | { |
eric@25 | 584 | printf ("label "); |
eric@25 | 585 | if (label->prefix) |
eric@25 | 586 | printf ("\"%s\" ", label->prefix); |
eric@25 | 587 | if (label->style) |
eric@25 | 588 | printf ("'%c' ", label->style); |
eric@25 | 589 | } |
eric@20 | 590 | printf ("page %d\n", i); |
eric@20 | 591 | } |
eric@20 | 592 | } |
eric@20 | 593 | } |
eric@20 | 594 | #endif /* SEMANTIC_DEBUG */ |
eric@20 | 595 | |
eric@25 | 596 | |
eric@25 | 597 | static inline int range_count (range_t range) |
eric@25 | 598 | { |
eric@25 | 599 | return ((range.last - range.first) + 1); |
eric@25 | 600 | } |
eric@25 | 601 | |
eric@25 | 602 | |
eric@160 | 603 | #ifdef CTL_LANG |
eric@134 | 604 | bool parse_control_file (char *fn) |
eric@16 | 605 | { |
eric@48 | 606 | bool result = 0; |
eric@16 | 607 | |
eric@16 | 608 | yyin = fopen (fn, "r"); |
eric@16 | 609 | if (! yyin) |
eric@16 | 610 | { |
eric@16 | 611 | fprintf (stderr, "can't open spec file '%s'\n", fn); |
eric@16 | 612 | goto fail; |
eric@16 | 613 | } |
eric@16 | 614 | |
eric@16 | 615 | line = 1; |
eric@16 | 616 | |
eric@20 | 617 | input_push_context (); /* create root input context */ |
eric@20 | 618 | input_push_context (); /* create inital input context */ |
eric@20 | 619 | |
eric@20 | 620 | output_push_context (); /* create root output context */ |
eric@18 | 621 | output_push_context (); /* create initial output context */ |
eric@18 | 622 | |
eric@16 | 623 | yyparse (); |
eric@16 | 624 | |
eric@20 | 625 | if (first_input_context->image_count != first_output_context->page_count) |
eric@18 | 626 | { |
eric@20 | 627 | fprintf (stderr, "input image count %d != output page count %d\n", |
eric@20 | 628 | first_input_context->image_count, |
eric@20 | 629 | first_output_context->page_count); |
eric@18 | 630 | goto fail; |
eric@18 | 631 | } |
eric@18 | 632 | |
eric@20 | 633 | fprintf (stderr, "%d pages specified\n", first_input_context->image_count); |
eric@18 | 634 | |
eric@16 | 635 | result = 1; |
eric@16 | 636 | |
eric@20 | 637 | #ifdef SEMANTIC_DEBUG |
eric@20 | 638 | dump_input_tree (); |
eric@20 | 639 | dump_output_tree (); |
eric@20 | 640 | #endif /* SEMANTIC_DEBUG */ |
eric@20 | 641 | |
eric@16 | 642 | fail: |
eric@16 | 643 | if (yyin) |
eric@16 | 644 | fclose (yyin); |
eric@16 | 645 | |
eric@16 | 646 | return (result); |
eric@16 | 647 | } |
eric@26 | 648 | |
eric@26 | 649 | |
eric@134 | 650 | bool process_controls (void) |
eric@26 | 651 | { |
eric@26 | 652 | input_image_t *image = NULL; |
eric@26 | 653 | output_page_t *page = NULL; |
eric@26 | 654 | int i = 0; |
eric@26 | 655 | int p = 0; |
eric@26 | 656 | int page_index = 0; |
eric@26 | 657 | input_attributes_t input_attributes; |
eric@26 | 658 | input_modifier_type_t parity; |
eric@26 | 659 | page_label_t *page_label; |
eric@26 | 660 | |
eric@26 | 661 | for (;;) |
eric@26 | 662 | { |
eric@26 | 663 | if ((! image) || (i >= range_count (image->range))) |
eric@26 | 664 | { |
eric@55 | 665 | char *input_fn; |
eric@26 | 666 | if (image) |
eric@26 | 667 | image = image->next; |
eric@26 | 668 | else |
eric@26 | 669 | image = first_input_image; |
eric@26 | 670 | if (! image) |
eric@55 | 671 | return (1); /* done */ |
eric@26 | 672 | i = 0; |
eric@55 | 673 | input_fn = get_input_filename (image->input_context); |
eric@55 | 674 | if (verbose) |
eric@139 | 675 | fprintf (stderr, "opening input file '%s'\n", input_fn); |
eric@139 | 676 | if (! open_input_file (input_fn)) |
eric@55 | 677 | { |
eric@139 | 678 | fprintf (stderr, "error opening input file '%s'\n", input_fn); |
eric@55 | 679 | return (0); |
eric@55 | 680 | } |
eric@26 | 681 | } |
eric@26 | 682 | |
eric@26 | 683 | if ((! page) || (p >= range_count (page->range))) |
eric@26 | 684 | { |
eric@55 | 685 | char *output_fn; |
eric@26 | 686 | if (page) |
eric@26 | 687 | page = page->next; |
eric@26 | 688 | else |
eric@26 | 689 | page = first_output_page; |
eric@26 | 690 | p = 0; |
eric@55 | 691 | output_fn = get_output_filename (page->output_context); |
eric@55 | 692 | if (verbose) |
eric@55 | 693 | fprintf (stderr, "opening PDF file '%s'\n", output_fn); |
eric@55 | 694 | if (! open_pdf_output_file (output_fn, |
eric@30 | 695 | get_output_file_attributes (page->output_context))) |
eric@55 | 696 | { |
eric@55 | 697 | fprintf (stderr, "error opening PDF file '%s'\n", output_fn); |
eric@55 | 698 | return (0); |
eric@55 | 699 | } |
eric@26 | 700 | } |
eric@26 | 701 | |
eric@26 | 702 | parity = ((image->range.first + i) % 2) ? INPUT_MODIFIER_ODD : INPUT_MODIFIER_EVEN; |
eric@26 | 703 | |
eric@26 | 704 | memset (& input_attributes, 0, sizeof (input_attributes)); |
eric@32 | 705 | |
eric@32 | 706 | input_attributes.rotation = 0; |
eric@32 | 707 | input_attributes.has_rotation = get_input_rotation (image->input_context, |
eric@32 | 708 | parity, |
eric@32 | 709 | & input_attributes.rotation); |
eric@32 | 710 | |
eric@32 | 711 | input_attributes.has_page_size = get_input_page_size (image->input_context, |
eric@32 | 712 | parity, |
eric@32 | 713 | & input_attributes.page_size); |
eric@26 | 714 | |
eric@55 | 715 | if (verbose) |
eric@55 | 716 | fprintf (stderr, "processing image %d\n", image->range.first + i); |
eric@131 | 717 | |
eric@131 | 718 | if (p) |
eric@131 | 719 | page_label = NULL; |
eric@131 | 720 | else |
eric@131 | 721 | { |
eric@131 | 722 | page_label = get_output_page_label (page->output_context); |
eric@131 | 723 | if (page_label) |
eric@131 | 724 | { |
eric@131 | 725 | page_label->page_index = page_index; |
eric@131 | 726 | page_label->base = page->range.first; |
eric@131 | 727 | page_label->count = range_count (page->range); |
eric@131 | 728 | } |
eric@131 | 729 | } |
eric@131 | 730 | |
eric@49 | 731 | if (! process_page (image->range.first + i, |
eric@49 | 732 | input_attributes, |
eric@131 | 733 | p ? NULL : page->bookmark_list, |
eric@131 | 734 | page_label)) |
eric@55 | 735 | { |
eric@55 | 736 | fprintf (stderr, "error processing image %d\n", image->range.first + i); |
eric@55 | 737 | return (0); |
eric@55 | 738 | } |
eric@26 | 739 | i++; |
eric@26 | 740 | p++; |
eric@26 | 741 | page_index++; |
eric@26 | 742 | } |
eric@26 | 743 | } |
eric@160 | 744 | #endif /* CTL_LANG */ |