Add "Editor modelines"; Adjust whitespace as needed.
[metze/wireshark/wip.git] / epan / print_stream.c
1 /* print_stream.c
2  * Routines for print streams.
3  *
4  * Gilbert Ramirez <gram@alumni.rice.edu>
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25 #include "config.h"
26
27 #include <stdio.h>
28
29 #include <glib.h>
30
31 #include <epan/print_stream.h>
32
33 #include <epan/ps.h>
34
35 #include <wsutil/file_util.h>
36
37 static FILE *
38 open_print_dest(gboolean to_file, const char *dest)
39 {
40     FILE *fh;
41
42     /* Open the file or command for output */
43     if (to_file)
44         fh = ws_fopen(dest, "w");
45     else
46         fh = popen(dest, "w");
47
48     return fh;
49 }
50
51 static gboolean
52 close_print_dest(gboolean to_file, FILE *fh)
53 {
54     /* Close the file or command */
55     if (to_file)
56         return (fclose(fh) == 0);
57     else
58         return (pclose(fh) == 0);
59 }
60
61 /* Some formats need stuff at the beginning of the output */
62 gboolean
63 print_preamble(print_stream_t *self, gchar *filename, const char *version_string)
64 {
65     return self->ops->print_preamble ? (self->ops->print_preamble)(self, filename, version_string) : TRUE;
66 }
67
68 gboolean
69 print_line(print_stream_t *self, int indent, const char *line)
70 {
71     return (self->ops->print_line)(self, indent, line);
72 }
73
74 /* Insert bookmark */
75 gboolean
76 print_bookmark(print_stream_t *self, const gchar *name, const gchar *title)
77 {
78     return self->ops->print_bookmark ? (self->ops->print_bookmark)(self, name, title) : TRUE;
79 }
80
81 gboolean
82 new_page(print_stream_t *self)
83 {
84     return self->ops->new_page ? (self->ops->new_page)(self) : TRUE;
85 }
86
87 /* Some formats need stuff at the end of the output */
88 gboolean
89 print_finale(print_stream_t *self)
90 {
91     return self->ops->print_finale ? (self->ops->print_finale)(self) : TRUE;
92 }
93
94 gboolean
95 destroy_print_stream(print_stream_t *self)
96 {
97     return self->ops->destroy ? (self->ops->destroy)(self) : TRUE;
98 }
99
100 typedef struct {
101     gboolean  to_file;
102     FILE     *fh;
103 } output_text;
104
105 #define MAX_INDENT    160
106
107 static gboolean
108 print_line_text(print_stream_t *self, int indent, const char *line)
109 {
110     static char  spaces[MAX_INDENT];
111     size_t ret;
112
113     output_text *output = (output_text *)self->data;
114     unsigned int num_spaces;
115
116     /* should be space, if NUL -> initialize */
117     if (!spaces[0]) {
118         int i;
119
120         for (i = 0; i < MAX_INDENT; i++)
121             spaces[i] = ' ';
122     }
123
124     /* Prepare the tabs for printing, depending on tree level */
125     num_spaces = indent * 4;
126     if (num_spaces > MAX_INDENT)
127         num_spaces = MAX_INDENT;
128
129     ret = fwrite(spaces, 1, num_spaces, output->fh);
130     if (ret == num_spaces) {
131         fputs(line, output->fh);
132         putc('\n', output->fh);
133     }
134     return !ferror(output->fh);
135 }
136
137 static gboolean
138 new_page_text(print_stream_t *self)
139 {
140     output_text *output = (output_text *)self->data;
141
142     fputs("\f", output->fh);
143     return !ferror(output->fh);
144 }
145
146 static gboolean
147 destroy_text(print_stream_t *self)
148 {
149     output_text *output = (output_text *)self->data;
150     gboolean     ret;
151
152     ret = close_print_dest(output->to_file, output->fh);
153     g_free(output);
154     g_free(self);
155     return ret;
156 }
157
158 static const print_stream_ops_t print_text_ops = {
159     NULL,            /* preamble */
160     print_line_text,
161     NULL,            /* bookmark */
162     new_page_text,
163     NULL,            /* finale */
164     destroy_text
165 };
166
167 static print_stream_t *
168 print_stream_text_alloc(gboolean to_file, FILE *fh)
169 {
170     print_stream_t *stream;
171     output_text    *output;
172
173     output          = (output_text *)g_malloc(sizeof *output);
174     output->to_file = to_file;
175     output->fh      = fh;
176     stream          = (print_stream_t *)g_malloc(sizeof (print_stream_t));
177     stream->ops     = &print_text_ops;
178     stream->data    = output;
179
180     return stream;
181 }
182
183 print_stream_t *
184 print_stream_text_new(gboolean to_file, const char *dest)
185 {
186     FILE *fh;
187
188     fh = open_print_dest(to_file, dest);
189     if (fh == NULL)
190         return NULL;
191
192     return print_stream_text_alloc(to_file, fh);
193 }
194
195 print_stream_t *
196 print_stream_text_stdio_new(FILE *fh)
197 {
198     return print_stream_text_alloc(TRUE, fh);
199 }
200
201 typedef struct {
202     gboolean  to_file;
203     FILE     *fh;
204 } output_ps;
205
206 #define MAX_PS_LINE_LENGTH 256
207
208 static
209 void ps_clean_string(char *out, const char *in, int outbuf_size)
210 {
211     int  rd, wr;
212     char c;
213
214     if (in == NULL) {
215         out[0] = '\0';
216         return;
217     }
218
219     for (rd = 0, wr = 0 ; wr < outbuf_size; rd++, wr++ ) {
220         c = in[rd];
221         switch (c) {
222         case '(':
223         case ')':
224         case '\\':
225             out[wr] = '\\';
226             out[++wr] = c;
227             break;
228
229         default:
230             out[wr] = c;
231             break;
232         }
233
234         if (c == 0) {
235             break;
236         }
237     }
238 }
239
240 static gboolean
241 print_preamble_ps(print_stream_t *self, gchar *filename, const char *version_string)
242 {
243     output_ps *output = (output_ps *)self->data;
244     char       psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
245
246     print_ps_preamble(output->fh);
247
248     fputs("%% the page title\n", output->fh);
249     ps_clean_string(psbuffer, filename, MAX_PS_LINE_LENGTH);
250     fprintf(output->fh, "/ws_pagetitle (%s - Wireshark %s) def\n", psbuffer, version_string);
251     fputs("\n", output->fh);
252     return !ferror(output->fh);
253 }
254
255 static gboolean
256 print_line_ps(print_stream_t *self, int indent, const char *line)
257 {
258     output_ps *output = (output_ps *)self->data;
259     char       psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
260
261     ps_clean_string(psbuffer, line, MAX_PS_LINE_LENGTH);
262     fprintf(output->fh, "%d (%s) putline\n", indent, psbuffer);
263     return !ferror(output->fh);
264 }
265
266 static gboolean
267 print_bookmark_ps(print_stream_t *self, const gchar *name, const gchar *title)
268 {
269     output_ps *output = (output_ps *)self->data;
270     char       psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
271
272     /*
273      * See the Adobe "pdfmark reference":
274      *
275      *  http://partners.adobe.com/asn/acrobat/docs/pdfmark.pdf
276      *
277      * The pdfmark stuff tells code that turns PostScript into PDF
278      * things that it should do.
279      *
280      * The /OUT stuff creates a bookmark that goes to the
281      * destination with "name" as the name and "title" as the title.
282      *
283      * The "/DEST" creates the destination.
284      */
285     ps_clean_string(psbuffer, title, MAX_PS_LINE_LENGTH);
286     fprintf(output->fh, "[/Dest /%s /Title (%s)   /OUT pdfmark\n", name,
287           psbuffer);
288     fputs("[/View [/XYZ -4 currentpoint matrix currentmatrix matrix defaultmatrix\n",
289           output->fh);
290     fputs("matrix invertmatrix matrix concatmatrix transform exch pop 20 add null]\n",
291           output->fh);
292     fprintf(output->fh, "/Dest /%s /DEST pdfmark\n", name);
293     return !ferror(output->fh);
294 }
295
296 static gboolean
297 new_page_ps(print_stream_t *self)
298 {
299     output_ps *output = (output_ps *)self->data;
300
301     fputs("formfeed\n", output->fh);
302     return !ferror(output->fh);
303 }
304
305 static gboolean
306 print_finale_ps(print_stream_t *self)
307 {
308     output_ps *output = (output_ps *)self->data;
309
310     print_ps_finale(output->fh);
311     return !ferror(output->fh);
312 }
313
314 static gboolean
315 destroy_ps(print_stream_t *self)
316 {
317     output_ps *output = (output_ps *)self->data;
318     gboolean   ret;
319
320     ret = close_print_dest(output->to_file, output->fh);
321     g_free(output);
322     g_free(self);
323     return ret;
324 }
325
326 static const print_stream_ops_t print_ps_ops = {
327     print_preamble_ps,
328     print_line_ps,
329     print_bookmark_ps,
330     new_page_ps,
331     print_finale_ps,
332     destroy_ps
333 };
334
335 static print_stream_t *
336 print_stream_ps_alloc(gboolean to_file, FILE *fh)
337 {
338     print_stream_t *stream;
339     output_ps      *output;
340
341     output          = (output_ps *)g_malloc(sizeof *output);
342     output->to_file = to_file;
343     output->fh      = fh;
344     stream          = (print_stream_t *)g_malloc(sizeof (print_stream_t));
345     stream->ops     = &print_ps_ops;
346     stream->data    = output;
347
348     return stream;
349 }
350
351 print_stream_t *
352 print_stream_ps_new(gboolean to_file, const char *dest)
353 {
354     FILE *fh;
355
356     fh = open_print_dest(to_file, dest);
357     if (fh == NULL)
358         return NULL;
359
360     return print_stream_ps_alloc(to_file, fh);
361 }
362
363 print_stream_t *
364 print_stream_ps_stdio_new(FILE *fh)
365 {
366     return print_stream_ps_alloc(TRUE, fh);
367 }
368
369 /*
370  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
371  *
372  * Local variables:
373  * c-basic-offset: 4
374  * tab-width: 8
375  * indent-tabs-mode: nil
376  * End:
377  *
378  * vi: set shiftwidth=4 tabstop=8 expandtab:
379  * :indentSize=4:tabSize=8:noTabs=true:
380  */