Code

tpdftoc: Added a simple tool to display a PDF's TOC.
[tpdfview.git] / src / tpdftoc.c
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)
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 : */