1 /*
2 * tpdfview - src/tpdftoc.c
3 * Copyright (C) 2011 Sebastian 'tokkee' Harl <sh@tokkee.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
28 /*
29 * A tiny tool to display the TOC of PDF documents.
30 */
32 #if HAVE_CONFIG_H
33 # include "config.h"
34 #endif /* HAVE_CONFIG_H */
36 #include "tpdfv.h"
37 #include "tpdfv_features.h"
39 #if HAVE_LIBGEN_H
40 # include <libgen.h>
41 #else /* HAVE_LIBGEN_H */
42 # define basename(path) (path)
43 #endif /* ! HAVE_LIBGEN_H */
45 #include <assert.h>
47 #include <errno.h>
49 #include <stdio.h>
50 #include <stdlib.h>
52 #include <string.h>
54 #include <unistd.h>
56 #include <poppler.h>
58 static void
59 exit_usage(char *name, int status)
60 {
61 printf(
62 "Usage: %s [<options>] <filename>\n"
64 "\nA tiny PDF viewer - display the TOC of a PDF document.\n"
66 "\nOptions:\n"
67 " -h display this help and exit\n"
68 " -V display the version number and copyright\n"
70 "\ntpdfview "TPDFV_VERSION_STRING TPDFV_VERSION_EXTRA", "PACKAGE_URL"\n"
71 "Copyright (C) 2011 "PACKAGE_MAINTAINER"\n",
72 basename(name));
73 exit(status);
74 } /* exit_usage */
76 static void
77 exit_version(void)
78 {
79 printf("tpdfview version "TPDFV_VERSION_STRING TPDFV_VERSION_EXTRA", "
80 "built "BUILD_DATE"\n"
81 "Copyright (C) 2011 "PACKAGE_MAINTAINER"\n"
83 "\nThis is free software under the terms of the BSD license, see "
84 "the source for\ncopying conditions. There is NO WARRANTY; not "
85 "even for MERCHANTABILITY or\nFITNESS FOR A PARTICULAR "
86 "PURPOSE.\n");
87 exit(0);
88 } /* exit_version */
90 static void
91 walk_pdf_toc(PopplerDocument *doc, PopplerIndexIter *iter, int depth)
92 {
93 if (! iter)
94 return;
96 do {
97 PopplerAction *action;
98 PopplerDest *dest;
100 char *entry_title;
101 int entry_pagenum;
103 PopplerIndexIter *child;
105 int i;
107 action = poppler_index_iter_get_action(iter);
109 if (action->type != POPPLER_ACTION_GOTO_DEST) {
110 poppler_action_free(action);
111 return;
112 }
114 dest = ((PopplerActionGotoDest *)action)->dest;
115 entry_title = ((PopplerActionGotoDest *)action)->title;
116 entry_pagenum = dest->page_num;
118 if (dest->type == POPPLER_DEST_NAMED) {
119 dest = poppler_document_find_dest(doc, dest->named_dest);
120 if (dest) {
121 entry_pagenum = dest->page_num;
122 poppler_dest_free(dest);
123 dest = NULL;
124 }
125 }
127 for (i = 0; i < depth - 1; ++i)
128 printf(" ");
129 if (i < depth)
130 printf(" |- ");
131 printf("%s %i\n", entry_title, entry_pagenum);
133 poppler_action_free(action);
134 action = NULL;
136 child = poppler_index_iter_get_child(iter);
137 if (! child)
138 continue;
140 walk_pdf_toc(doc, child, depth + 1);
141 poppler_index_iter_free(child);
142 } while (poppler_index_iter_next(iter));
143 } /* walk_pdf_index */
145 int
146 main(int argc, char **argv)
147 {
148 PopplerDocument *doc;
149 PopplerIndexIter *iter;
150 GError *err = NULL;
152 char *filename;
154 g_type_init();
156 while (42) {
157 int opt = getopt(argc, argv, "hV");
159 if (-1 == opt)
160 break;
162 switch (opt) {
163 case 'h':
164 exit_usage(argv[0], 0);
165 break;
166 case 'V':
167 exit_version();
168 break;
169 default:
170 exit_usage(argv[0], 1);
171 }
172 }
174 if (argc - optind != 1) {
175 fprintf(stderr, "%s: missing filename\n", argv[0]);
176 exit_usage(argv[0], 1);
177 }
179 /* XXX: move this into libtpdfv as well. */
180 if (strstr(argv[optind], "://"))
181 filename = strdup(argv[optind]);
182 else {
183 size_t len = strlen("file://") + strlen(argv[optind]);
184 filename = (char *)malloc(len + 1);
185 if (filename) {
186 *filename = '\0';
187 strncat(filename, "file://", len);
188 strncat(filename, argv[optind], len - strlen("file://"));
189 }
190 }
192 if (! filename) {
193 char errbuf[1024];
194 strerror_r(errno, errbuf, sizeof(errbuf));
195 fprintf(stderr, "Failed to allocate string: %s.\n", errbuf);
196 return 1;
197 }
199 doc = poppler_document_new_from_file(filename,
200 /* password = */ NULL, &err);
201 if (! doc) {
202 fprintf(stderr, "Failed to open PDF: %s.\n", err->message);
203 return 1;
204 }
206 iter = poppler_index_iter_new(doc);
207 if (! iter) {
208 /* no index */
209 return 0;
210 }
212 walk_pdf_toc(doc, iter, 0);
214 poppler_index_iter_free(iter);
215 free(filename);
216 return 0;
217 } /* main */
219 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */