2
Copyright (c) 1996-2006 Han The Thanh, <thanh@pdftex.org>
4
This file is part of pdfTeX.
6
pdfTeX is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or
9
(at your option) any later version.
11
pdfTeX is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with pdfTeX; if not, write to the Free Software
18
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
$Id: utils.c 1013 2008-02-14 00:09:02Z oneiros $
3
Copyright 1996-2006 Han The Thanh <thanh@pdftex.org>
4
Copyright 2006-2008 Taco Hoekwater <taco@luatex.org>
6
This file is part of LuaTeX.
8
LuaTeX is free software; you can redistribute it and/or modify it under
9
the terms of the GNU General Public License as published by the Free
10
Software Foundation; either version 2 of the License, or (at your
11
option) any later version.
13
LuaTeX is distributed in the hope that it will be useful, but WITHOUT
14
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16
License for more details.
18
You should have received a copy of the GNU General Public License along
19
with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
21
#include "openbsd-compat.h"
22
#ifdef HAVE_ASPRINTF /* asprintf is not defined in openbsd-compat.h, but in stdio.h */
23
27
#include "sys/types.h"
24
28
#ifndef __MINGW32__
29
# include "sysexits.h"
27
#define EX_SOFTWARE 70
31
# define EX_SOFTWARE 70
30
34
#include <kpathsea/c-proto.h>
159
void pdf_puts (const char *s)
163
void pdf_puts(const char *s)
161
pdfroom (strlen (s) + 1);
165
pdfroom(strlen(s) + 1);
163
167
pdf_buf[pdf_ptr++] = *s++;
166
__attribute__ ((format (printf, 1, 2)))
167
void pdf_printf (const char *fmt, ...)
170
__attribute__ ((format(printf, 1, 2)))
171
void pdf_printf(const char *fmt, ...)
170
va_start (args, fmt);
171
vsnprintf (print_buf, PRINTF_BUF_SIZE, fmt, args);
172
pdf_puts (print_buf);
175
vsnprintf(print_buf, PRINTF_BUF_SIZE, fmt, args);
176
strnumber maketexstring (const char *s)
180
strnumber maketexstring(const char *s)
178
if (s == NULL || *s == 0)
179
return get_nullstr ();
180
return maketexlstring(s,strlen(s));
182
if (s == NULL || *s == 0)
183
return get_nullstr();
184
return maketexlstring(s, strlen(s));
183
strnumber maketexlstring (const char *s, size_t l)
187
strnumber maketexlstring(const char *s, size_t l)
185
189
if (s == NULL || l == 0)
186
return get_nullstr ();
187
check_pool_overflow (pool_ptr + l);
190
return get_nullstr();
191
check_pool_overflow(pool_ptr + l);
189
193
str_pool[pool_ptr++] = *s++;
190
last_tex_string = make_string ();
194
last_tex_string = make_string();
191
195
return last_tex_string;
195
199
/* print a C string through TeX */
197
print_string (char *j) {
200
void print_string(char *j)
204
208
/* append a C string to a TeX string */
206
append_string (char *s) {
207
if (s == NULL || *s == 0)
209
check_buf (pool_ptr + strlen(s), pool_size);
211
str_pool[pool_ptr++] = *s++;
209
void append_string(char *s)
211
if (s == NULL || *s == 0)
213
check_buf(pool_ptr + strlen(s), pool_size);
215
str_pool[pool_ptr++] = *s++;
215
__attribute__ ((format (printf, 1, 2)))
216
void tex_printf (const char *fmt, ...)
219
__attribute__ ((format(printf, 1, 2)))
220
void tex_printf(const char *fmt, ...)
219
va_start (args, fmt);
220
vsnprintf (print_buf, PRINTF_BUF_SIZE, fmt, args);
221
print_string (print_buf);
224
vsnprintf(print_buf, PRINTF_BUF_SIZE, fmt, args);
225
print_string(print_buf);
226
230
/* Helper for pdftex_fail. */
227
static void safe_print (const char *str)
231
static void safe_print(const char *str)
230
234
for (c = str; *c; ++c)
234
void remove_pdffile (void)
238
void remove_pdffile(void)
236
240
if (!kpathsea_debug && output_file_name && !fixed_pdf_draftmode) {
237
xfclose (pdf_file, makecstring (output_file_name));
238
remove (makecstring (output_file_name));
241
xfclose(pdf_file, makecstring(output_file_name));
242
remove(makecstring(output_file_name));
247
251
The output format of this fuction must be the same as pdf_error in
250
__attribute__ ((noreturn, format (printf, 1, 2)))
251
void pdftex_fail (const char *fmt, ...)
254
__attribute__ ((noreturn, format(printf, 1, 2)))
255
void pdftex_fail(const char *fmt, ...)
254
va_start (args, fmt);
256
safe_print ("!luaTeX error");
260
safe_print("!luaTeX error");
257
261
if (cur_file_name) {
258
safe_print (" (file ");
259
safe_print (cur_file_name);
262
safe_print(" (file ");
263
safe_print(cur_file_name);
263
vsnprintf (print_buf, PRINTF_BUF_SIZE, fmt, args);
264
safe_print (print_buf);
267
vsnprintf(print_buf, PRINTF_BUF_SIZE, fmt, args);
268
safe_print(print_buf);
267
271
remove_pdffile();
268
safe_print (" ==> Fatal error occurred, no output PDF file produced!");
272
safe_print(" ==> Fatal error occurred, no output PDF file produced!");
270
274
if (kpathsea_debug) {
277
281
/* The output format of this fuction must be the same as pdf_warn in
280
__attribute__ ((format (printf, 1, 2)))
281
void pdftex_warn (const char *fmt, ...)
284
__attribute__ ((format(printf, 1, 2)))
285
void pdftex_warn(const char *fmt, ...)
284
va_start (args, fmt);
286
tex_printf ("luaTeX warning");
290
tex_printf("luaTeX warning");
287
291
if (cur_file_name)
288
tex_printf (" (file %s)", cur_file_name);
290
vsnprintf (print_buf, PRINTF_BUF_SIZE, fmt, args);
291
print_string (print_buf);
297
void tex_error(char *msg, char **hlp) {
298
strnumber aa = 0,bb = 0,cc = 0,dd = 0,ee = 0;
302
if (k>0) aa =maketexstring(hlp[0]);
303
if (k>1) bb =maketexstring(hlp[1]);
304
if (k>2) cc =maketexstring(hlp[2]);
305
if (k>3) dd =maketexstring(hlp[3]);
306
if (k>4) ee =maketexstring(hlp[4]);
308
do_print_err(maketexstring(msg));
309
flush_str(last_tex_string);
312
case 1: dohelp1(aa); break;
313
case 2: dohelp2(aa,bb); break;
314
case 3: dohelp3(aa,bb,cc); break;
315
case 4: dohelp4(aa,bb,cc,dd); break;
316
case 5: dohelp5(aa,bb,cc,dd,ee); break;
320
if (ee) flush_str(ee);
321
if (dd) flush_str(dd);
322
if (cc) flush_str(cc);
323
if (bb) flush_str(bb);
324
if (aa) flush_str(aa);
328
void garbage_warning (void)
330
pdftex_warn ("dangling objects discarded, no output file produced.");
334
char *makecstring (integer s) {
336
return makeclstring(s,&l);
340
char *makeclstring (integer s, int *len)
292
tex_printf(" (file %s)", cur_file_name);
294
vsnprintf(print_buf, PRINTF_BUF_SIZE, fmt, args);
295
print_string(print_buf);
301
void tex_error(char *msg, char **hlp)
303
strnumber aa = 0, bb = 0, cc = 0, dd = 0, ee = 0;
305
while (hlp[k] != NULL)
308
aa = maketexstring(hlp[0]);
310
bb = maketexstring(hlp[1]);
312
cc = maketexstring(hlp[2]);
314
dd = maketexstring(hlp[3]);
316
ee = maketexstring(hlp[4]);
318
do_print_err(maketexstring(msg));
319
flush_str(last_tex_string);
323
case 1: dohelp1(aa); break;
324
case 2: dohelp2(aa, bb); break;
325
case 3: dohelp3(aa, bb, cc); break;
326
case 4: dohelp4(aa, bb, cc, dd); break;
327
case 5: dohelp5(aa, bb, cc, dd, ee); break;
345
void garbage_warning(void)
347
pdftex_warn("dangling objects discarded, no output file produced.");
351
char *makecstring(integer s)
354
return makeclstring(s, &l);
358
char *makeclstring(integer s, int *len)
342
360
static char *cstrbuf = NULL;
344
362
static int allocsize;
345
363
int allocgrow, i, l;
348
l = str_start[s + 1] - str_start[s];
350
check_buf (l + 1, MAX_CSTRING_LEN);
351
if (cstrbuf == NULL) {
353
cstrbuf = xmallocarray (char, allocsize);
354
} else if (l + 1 > allocsize) {
355
allocgrow = allocsize * 0.2;
356
if (l + 1 - allocgrow > allocsize)
358
else if (allocsize < MAX_CSTRING_LEN - allocgrow)
359
allocsize += allocgrow;
361
allocsize = MAX_CSTRING_LEN;
362
cstrbuf = xreallocarray (cstrbuf, char, allocsize);
365
for (i = 0; i < l; i++)
366
*p++ = str_pool[i + str_start[s]];
366
l = str_start[s + 1] - str_start[s];
368
check_buf(l + 1, MAX_CSTRING_LEN);
369
if (cstrbuf == NULL) {
371
cstrbuf = xmallocarray(char, allocsize);
372
} else if (l + 1 > allocsize) {
373
allocgrow = allocsize * 0.2;
374
if (l + 1 - allocgrow > allocsize)
376
else if (allocsize < MAX_CSTRING_LEN - allocgrow)
377
allocsize += allocgrow;
379
allocsize = MAX_CSTRING_LEN;
380
cstrbuf = xreallocarray(cstrbuf, char, allocsize);
383
for (i = 0; i < l; i++)
384
*p++ = str_pool[i + str_start[s]];
369
if (cstrbuf == NULL) {
371
cstrbuf = xmallocarray (char, allocsize);
377
} else if (s <= 0x7FF ) {
378
cstrbuf[0] = 0xC0 + (s / 0x40);
379
cstrbuf[1] = 0x80 + (s % 0x40);
382
} else if (s <= 0xFFFF ) {
383
cstrbuf[0] = 0xE0 + (s / 0x1000);
384
cstrbuf[1] = 0x80 + ((s % 0x1000) / 0x40);
385
cstrbuf[2] = 0x80 + ((s % 0x1000) % 0x40);
390
cstrbuf[0] = s-0x10FF00;
394
cstrbuf[0] = 0xF0 + (s / 0x40000);
395
cstrbuf[1] = 0x80 + ((s % 0x40000) / 0x1000);
396
cstrbuf[2] = 0x80 + (((s % 0x40000) % 0x1000) / 0x40);
397
cstrbuf[3] = 0x80 + (((s % 0x40000) % 0x1000) % 0x40);
387
if (cstrbuf == NULL) {
389
cstrbuf = xmallocarray(char, allocsize);
395
} else if (s <= 0x7FF) {
396
cstrbuf[0] = 0xC0 + (s / 0x40);
397
cstrbuf[1] = 0x80 + (s % 0x40);
400
} else if (s <= 0xFFFF) {
401
cstrbuf[0] = 0xE0 + (s / 0x1000);
402
cstrbuf[1] = 0x80 + ((s % 0x1000) / 0x40);
403
cstrbuf[2] = 0x80 + ((s % 0x1000) % 0x40);
408
cstrbuf[0] = s - 0x10FF00;
412
cstrbuf[0] = 0xF0 + (s / 0x40000);
413
cstrbuf[1] = 0x80 + ((s % 0x40000) / 0x1000);
414
cstrbuf[2] = 0x80 + (((s % 0x40000) % 0x1000) / 0x40);
415
cstrbuf[3] = 0x80 + (((s % 0x40000) % 0x1000) % 0x40);
406
void set_job_id (int year, int month, int day, int time)
424
void set_job_id(int year, int month, int day, int time)
408
426
char *name_string, *format_string, *s;
412
430
if (job_id_string != NULL)
415
name_string = xstrdup (makecstring (job_name));
416
format_string = xstrdup (makecstring (format_ident));
433
name_string = xstrdup(makecstring(job_name));
434
format_string = xstrdup(makecstring(format_ident));
417
435
slen = SMALL_BUF_SIZE +
418
strlen (name_string) +
419
strlen (format_string) +
420
strlen (ptexbanner) +
421
strlen (versionstring) + strlen (kpathsea_version_string);
422
s = xtalloc (slen, char);
436
strlen(name_string) +
437
strlen(format_string) +
439
strlen(versionstring) + strlen(kpathsea_version_string);
440
s = xtalloc(slen, char);
423
441
/* The Web2c version string starts with a space. */
424
i = snprintf (s, slen,
425
"%.4d/%.2d/%.2d %.2d:%.2d %s %s %s%s %s",
426
year, month, day, time / 60, time % 60,
427
name_string, format_string, ptexbanner,
428
versionstring, kpathsea_version_string);
429
check_nprintf(i,slen);
430
job_id_string = xstrdup (s);
433
xfree (format_string);
436
int get_build_revision (void) {
438
if(sscanf (BUILD_REVISION,"$Revision: %d $", &revision)) {
444
void make_pdftex_banner (void)
442
i = snprintf(s, slen,
443
"%.4d/%.2d/%.2d %.2d:%.2d %s %s %s%s %s",
444
year, month, day, time / 60, time % 60,
445
name_string, format_string, ptexbanner,
446
versionstring, kpathsea_version_string);
447
check_nprintf(i, slen);
448
job_id_string = xstrdup(s);
451
xfree(format_string);
454
void make_pdftex_banner(void)
446
456
static boolean pdftexbanner_init = false;
451
461
if (pdftexbanner_init)
454
464
slen = SMALL_BUF_SIZE +
455
strlen (ptexbanner) +
456
strlen (versionstring) + strlen (kpathsea_version_string);
457
s = xtalloc (slen, char);
466
strlen(versionstring) + strlen(kpathsea_version_string);
467
s = xtalloc(slen, char);
458
468
/* The Web2c version string starts with a space. */
459
i = snprintf (s, slen,
460
"%s%s %s", ptexbanner, versionstring, kpathsea_version_string);
461
check_nprintf (i, slen);
462
pdftex_banner = maketexstring (s);
469
i = snprintf(s, slen,
470
"%s%s %s", ptexbanner, versionstring, kpathsea_version_string);
471
check_nprintf(i, slen);
472
pdftex_banner = maketexstring(s);
464
474
pdftexbanner_init = true;
467
strnumber get_resname_prefix (void)
477
strnumber get_resname_prefix(void)
469
479
/* static char name_str[] = */
470
480
/* "!\"$&'*+,-.0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\" */
474
484
char prefix[7]; /* make a tag of 6 chars long */
475
485
unsigned long crc;
477
size_t base = strlen (name_str);
478
crc = crc32 (0L, Z_NULL, 0);
479
crc = crc32 (crc, (Bytef *) job_id_string, strlen (job_id_string));
487
size_t base = strlen(name_str);
488
crc = crc32(0L, Z_NULL, 0);
489
crc = crc32(crc, (Bytef *) job_id_string, strlen(job_id_string));
480
490
for (i = 0; i < 6; i++) {
481
491
prefix[i] = name_str[crc % base];
485
return maketexstring (prefix);
495
return maketexstring(prefix);
488
size_t xfwrite (void *ptr, size_t size, size_t nmemb, FILE * stream)
498
size_t xfwrite(void *ptr, size_t size, size_t nmemb, FILE * stream)
490
if (fwrite (ptr, size, nmemb, stream) != nmemb)
491
pdftex_fail ("fwrite() failed");
500
if (fwrite(ptr, size, nmemb, stream) != nmemb)
501
pdftex_fail("fwrite() failed");
495
int xfflush (FILE * stream)
505
int xfflush(FILE * stream)
497
if (fflush (stream) != 0)
498
pdftex_fail ("fflush() failed");
507
if (fflush(stream) != 0)
508
pdftex_fail("fflush() failed");
502
int xgetc (FILE * stream)
512
int xgetc(FILE * stream)
504
int c = getc (stream);
514
int c = getc(stream);
505
515
if (c < 0 && c != EOF)
506
pdftex_fail ("getc() failed");
516
pdftex_fail("getc() failed");
510
int xputc (int c, FILE * stream)
520
int xputc(int c, FILE * stream)
512
int i = putc (c, stream);
522
int i = putc(c, stream);
514
pdftex_fail ("putc() failed");
524
pdftex_fail("putc() failed");
518
void write_stream_length (integer length, integer offset)
528
void write_stream_length(integer length, integer offset)
520
530
if (jobname_cstr == NULL)
521
jobname_cstr = xstrdup (makecstring (job_name));
522
if (fixed_pdf_draftmode == 0) {
523
xfseek (pdf_file, offset, SEEK_SET, jobname_cstr);
524
fprintf (pdf_file, "%li", (long int) length);
525
xfseek (pdf_file, pdfoffset (), SEEK_SET, jobname_cstr);
531
jobname_cstr = xstrdup(makecstring(job_name));
532
if (fixed_pdf_draftmode == 0) {
533
xfseek(pdf_file, offset, SEEK_SET, jobname_cstr);
534
fprintf(pdf_file, "%li", (long int) length);
535
xfseek(pdf_file, pdfoffset(), SEEK_SET, jobname_cstr);
529
scaled ext_xn_over_d (scaled x, scaled n, scaled d)
539
scaled ext_xn_over_d(scaled x, scaled n, scaled d)
531
541
double r = (((double) x) * ((double) n)) / ((double) d);
532
542
if (r > DBL_EPSILON)
869
880
/* get the time */
872
strftime (time_str, sizeof (time_str), "%Y%m%dT%H%M%SZ", gmtime (&t));
873
md5_append (&state, (const md5_byte_t *) time_str, size);
882
size = strftime(time_str, sizeof(time_str), "%Y%m%dT%H%M%SZ", gmtime(&t));
883
md5_append(&state, (const md5_byte_t *) time_str, size);
874
884
/* get the file name */
875
if (getcwd (pwd, sizeof (pwd)) == NULL)
876
pdftex_fail ("getcwd() failed (path too long?)");
877
file_name = makecstring (filename);
878
md5_append (&state, (const md5_byte_t *) pwd, strlen (pwd));
879
md5_append (&state, (const md5_byte_t *) "/", 1);
880
md5_append (&state, (const md5_byte_t *) file_name, strlen (file_name));
885
if (getcwd(pwd, sizeof(pwd)) == NULL)
886
pdftex_fail("getcwd() failed (path too long?)");
887
file_name = makecstring(filename);
888
md5_append(&state, (const md5_byte_t *) pwd, strlen(pwd));
889
md5_append(&state, (const md5_byte_t *) "/", 1);
890
md5_append(&state, (const md5_byte_t *) file_name, strlen(file_name));
882
md5_finish (&state, digest);
892
md5_finish(&state, digest);
883
893
/* write the IDs */
884
convertStringToHexString ((char *) digest, id, 16);
885
pdf_printf ("/ID [<%s> <%s>]", id, id);
894
convertStringToHexString((char *) digest, id, 16);
895
pdf_printf("/ID [<%s> <%s>]", id, id);
888
898
/* Print the /CreationDate entry.
1707
1713
|scaled_out| is the number of scaled points corresponding to that.
1710
scaled divide_scaled (scaled s, scaled m, integer dd) {
1724
pdf_error(maketexstring("arithmetic"), maketexstring("divided by zero"));
1725
} else if (m >= (max_integer / 10)) {
1726
pdf_error(maketexstring("arithmetic"), maketexstring("number too big"));
1730
for (i = 1;i<=(int)dd;i++) {
1731
q = 10*q + (10*r) / m;
1739
/* set up the value of q, in scaled points */
1741
case 0: scaled_out = sign*(s - r); break;
1742
case 1: scaled_out = sign*(s - (r/10)); break;
1743
case 2: scaled_out = sign*(s - (r/100)); break;
1744
case 3: scaled_out = sign*(s - (r/1000)); break;
1745
case 4: scaled_out = sign*(s - (r/10000)); break;
1746
case 5: scaled_out = sign*(s - (r/100000)); break;
1747
case 6: scaled_out = sign*(s - (r/1000000)); break;
1748
case 7: scaled_out = sign*(s - (r/10000000)); break;
1749
case 8: scaled_out = sign*(s - (r/100000000)); break;
1750
case 9: scaled_out = sign*(s - (r/1000000000)); break;
1716
scaled divide_scaled(scaled s, scaled m, integer dd)
1731
pdf_error(maketexstring("arithmetic"),
1732
maketexstring("divided by zero"));
1733
} else if (m >= (max_integer / 10)) {
1734
pdf_error(maketexstring("arithmetic"), maketexstring("number too big"));
1738
for (i = 1; i <= (int) dd; i++) {
1739
q = 10 * q + (10 * r) / m;
1747
/* set up the value of q, in scaled points */
1750
case 0: scaled_out = sign * (s - r); break;
1751
case 1: scaled_out = sign * (s - (r / 10)); break;
1752
case 2: scaled_out = sign * (s - (r / 100)); break;
1753
case 3: scaled_out = sign * (s - (r / 1000)); break;
1754
case 4: scaled_out = sign * (s - (r / 10000)); break;
1755
case 5: scaled_out = sign * (s - (r / 100000)); break;
1756
case 6: scaled_out = sign * (s - (r / 1000000)); break;
1757
case 7: scaled_out = sign * (s - (r / 10000000)); break;
1758
case 8: scaled_out = sign * (s - (r / 100000000)); break;
1759
case 9: scaled_out = sign * (s - (r / 1000000000)); break;
1758
1768
* routine is only used by the pdf backend, not for typesetting.
1762
divide_scaled_n (double sd, double md, double n) {
1763
int d = (int)(sd/md*n+0.5);
1764
scaled_out = (int)(d/n*md);
1771
scaled divide_scaled_n(double sd, double md, double n)
1773
int d = (int) (sd / md * n + 0.5);
1774
scaled_out = (int) (d / n * md);
1769
1779
/* C print interface */
1771
void tprint (char *s) {
1776
void tprint_nl (char *s) {
1781
#define escape_char_code 45 /* escape character for token output */
1782
#define int_par(a) zeqtb[static_int_base+(a)].cint /* an integer parameter */
1781
void tprint(char *s)
1787
void tprint_nl(char *s)
1793
#define escape_char_code 45 /* escape character for token output */
1794
#define int_par(a) zeqtb[static_int_base+(a)].cint /* an integer parameter */
1783
1795
#define escape_char int_par(escape_char_code)
1785
void tprint_esc(char *s) { /* prints escape character, then |s| */
1786
int c=-1; /* the escape character code */
1795
void tconfusion(char *s) {
1796
confusion(maketexstring(s));
1797
void tprint_esc(char *s)
1798
{ /* prints escape character, then |s| */
1799
int c = -1; /* the escape character code */
1800
if (zeqtb != NULL) {
1808
void tconfusion(char *s)
1810
confusion(maketexstring(s));
1813
/**********************************************************************/
1814
/* Page diversions */
1817
# define PAGES_TREE_KIDSMAX 3
1819
# define PAGES_TREE_KIDSMAX 6
1822
static struct avl_table *divert_list_tree = NULL;
1824
typedef struct pages_entry_ {
1825
integer objnum; /* object number of this /Pages object */
1826
integer number_of_pages; /* total number of all pages below */
1827
integer number_of_kids; /* number of direct kid objects */
1828
integer kids[PAGES_TREE_KIDSMAX]; /* array of kid object numbers */
1829
struct pages_entry_ *next;
1832
typedef struct divert_list_entry_ {
1836
} divert_list_entry;
1838
static int comp_divert_list_entry(const void *pa, const void *pb, void *p)
1840
if (((const divert_list_entry *) pa)->divnum >
1841
((const divert_list_entry *) pb)->divnum)
1843
if (((const divert_list_entry *) pa)->divnum <
1844
((const divert_list_entry *) pb)->divnum)
1849
static pages_entry *new_pages_entry()
1853
p = xtalloc(1, pages_entry);
1854
p->number_of_pages = p->number_of_kids = 0;
1855
for (i = 0; i < PAGES_TREE_KIDSMAX; i++)
1858
pdf_create_obj(0, 0);
1859
p->objnum = obj_ptr;
1863
static divert_list_entry *new_divert_list_entry()
1865
divert_list_entry *d;
1866
d = xtalloc(1, divert_list_entry);
1867
d->first = d->last = NULL;
1871
static void ensure_list_tree()
1873
if (divert_list_tree == NULL) {
1875
avl_create(comp_divert_list_entry, NULL, &avl_xallocator);
1876
assert(divert_list_tree != NULL);
1880
static divert_list_entry *get_divert_list(integer divnum)
1882
divert_list_entry *d, tmp;
1884
tmp.divnum = divnum;
1885
d = (divert_list_entry *) avl_find(divert_list_tree, &tmp);
1887
d = new_divert_list_entry();
1889
aa = avl_probe(divert_list_tree, d);
1895
/* pdf_do_page_divert() returns the current /Parent object number */
1897
integer pdf_do_page_divert(integer objnum, integer divnum)
1899
divert_list_entry *d;
1903
struct avl_traverser t;
1906
// initialize the tree
1908
// make sure we have a list for this diversion
1909
d = get_divert_list(divnum);
1910
if (d->first == NULL || d->last->number_of_kids == PAGES_TREE_KIDSMAX) {
1911
// append a new pages_entry
1912
p = new_pages_entry();
1913
if (d->first == NULL)
1920
p->kids[p->number_of_kids++] = objnum;
1921
p->number_of_pages++;
1924
avl_t_init(&t, divert_list_tree);
1925
for (d = avl_t_first(&t, divert_list_tree); d != NULL; d = avl_t_next(&t)) {
1926
printf("===== D-LIST %d: ", d->divnum);
1927
for (q = d->first; q != NULL; q = q->next) {
1928
printf("P=%d NK=%d (", q->objnum, q->number_of_kids);
1929
for (i = 0; i < q->number_of_kids; i++)
1930
printf("%d ", q->kids[i]);
1940
static void movelist(divert_list_entry * d, divert_list_entry * dto)
1942
if (d != NULL && d->first != NULL && d->divnum != dto->divnum) { /* no undivert of empty list or into self */
1943
if (dto->first == NULL)
1944
dto->first = d->first;
1946
dto->last->next = d->first;
1947
dto->last = d->last;
1948
d->first = d->last = NULL; /* one could as well remove this divert_list_entry */
1952
/* undivert from diversion <divnum> into diversion <curdivnum> */
1954
void pdf_do_page_undivert(integer divnum, integer curdivnum)
1956
divert_list_entry *d, *dto, tmp;
1957
struct avl_traverser t;
1962
// initialize the tree
1964
// find the diversion <curdivnum> list where diversion <divnum> should go
1965
dto = get_divert_list(curdivnum);
1966
if (divnum == 0) { /* 0 = special case: undivert _all_ lists */
1967
avl_t_init(&t, divert_list_tree);
1968
for (d = avl_t_first(&t, divert_list_tree); d != NULL;
1972
tmp.divnum = divnum;
1973
d = (divert_list_entry *) avl_find(divert_list_tree, &tmp);
1978
avl_t_init(&t, divert_list_tree);
1979
for (d = avl_t_first(&t, divert_list_tree); d != NULL; d = avl_t_next(&t)) {
1980
printf("===== U-LIST %d: ", d->divnum);
1981
for (p = d->first; p != NULL; p = p->next) {
1982
printf("P=%d NK=%d (", p->objnum, p->number_of_kids);
1983
for (i = 0; i < p->number_of_kids; i++)
1984
printf("%d ", p->kids[i]);
1993
/* write a /Pages object */
1995
static void write_pages(pages_entry * p, int parent)
1999
pdf_begin_dict(p->objnum, 1);
2000
pdf_printf("/Type /Pages\n");
2001
if (parent == 0) /* it's root */
2002
print_pdf_pages_attr();
2004
pdf_printf("/Parent %d 0 R\n", parent);
2005
pdf_printf("/Count %d\n/Kids [", (int)p->number_of_pages);
2006
for (i = 0; i < p->number_of_kids; i++)
2007
pdf_printf("%d 0 R ", (int)p->kids[i]);
2008
remove_last_space();
2013
/* loop over all /Pages objects, output them, create their parents,
2014
* recursing bottom up, return the /Pages root object number */
2016
static integer output_pages_list(pages_entry * pe)
2018
pages_entry *p, *q, *r;
2020
if (pe->next == NULL) { /* everything fits into one pages_entry */
2021
write_pages(pe, 0); /* --> /Pages root found */
2024
q = r = new_pages_entry(); /* one level higher needed */
2025
for (p = pe; p != NULL; p = p->next) {
2026
if (q->number_of_kids == PAGES_TREE_KIDSMAX) {
2027
q->next = new_pages_entry();
2030
q->kids[q->number_of_kids++] = p->objnum;
2031
q->number_of_pages += p->number_of_pages;
2032
write_pages(p, q->objnum);
2034
return output_pages_list(r); /* recurse through next higher level */
2037
integer output_pages_tree()
2039
divert_list_entry *d;
2040
pdf_do_page_undivert(0, 0); /* concatenate all diversions into diversion 0 */
2041
d = get_divert_list(0); /* get diversion 0 */
2042
return output_pages_list(d->first);