1 /*
2 * generate.c -- Input files and pretty printing.
3 *
4 * Copyright (c) 1995-99 Akim Demaille, Miguel Santana
5 */
6
7 /*
8 * This file is part of a2ps.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * 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; see the file COPYING. If not, write to
22 * the Free Software Foundation, 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
24 */
25
26 #include "main.h"
27
28 extern int isdir PARAMS ((const char *path));
29
30 /* Name of the file in which the tmp sample file is stored. */
31 char *sample_tmpname = NULL;
32
33 /*
34 * What kind of treatement should be applied
35 */
36 enum style_kind_e
37 {
38 no_style, binary, sshparser, unprintable, delegate
39 };
40
41 static enum style_kind_e
string_to_style_kind(const char * string)42 string_to_style_kind (const char * string)
43 {
44 if (strequ (string, "binary"))
45 return binary;
46 else if (strequ (string, "UNPRINTABLE"))
47 return unprintable;
48 else if (strequ (string, "plain"))
49 return no_style;
50 else if (strequ (string, "delegate"))
51 return delegate;
52 return sshparser;
53 }
54 /************************************************************************/
55 /* The inputs */
56 /************************************************************************/
57 static buffer_t *
input_new(uchar * name)58 input_new (uchar * name)
59 {
60 NEW (buffer_t, res);
61 struct file_job * file_job;
62 struct stat statbuf; /* to get file modification time */
63 struct tm *tm;
64
65 a2ps_open_input_session (job, name);
66 file_job = CURRENT_FILE (job);
67
68 /* Retrieve file modification date and hour */
69 if (IS_EMPTY(name) || ustrequ (name, "-"))
70 {
71 file_job->is_stdin = true;
72 file_job->name = job->stdin_filename;
73 /* Create the buffer in charge of stdin */
74 buffer_stream_set (res, stdin, end_of_line);
75 /* Ask it to make a sample of the file. */
76 tempname_ensure (sample_tmpname);
77 buffer_sample_get (res, sample_tmpname);
78 }
79 else
80 {
81 FILE * input_stream;
82 /* This is a true file (not stdin) */
83 file_job->is_stdin = false;
84
85 /* Printing a file given by its path */
86 if (isdir ((char *) name))
87 {
88 error (0, 0, _("`%s' is a directory"), quotearg ((char *) name));
89 file_job->printable = false;
90 }
91
92 file_job->name = (uchar *) name;
93 if ((input_stream = fopen ((char *) name, "r")) == NULL)
94 {
95 error (0, errno,
96 _("cannot open file `%s'"), quotearg ((char *) name));
97 file_job->printable = false;
98 }
99 else if (stat ((char *) name, &statbuf) == -1)
100 {
101 error (0, errno, _("cannot get informations on file `%s'"),
102 quotearg ((char *) name));
103 file_job->printable = false;
104 }
105 else
106 {
107 time_t tim = statbuf.st_mtime;
108 tm = localtime (&tim);
109 memcpy (&(file_job->mod_tm), tm, sizeof (*tm));
110 }
111 /* Create the buffer in charge of the input stream */
112 buffer_stream_set (res, input_stream, end_of_line);
113 }
114
115
116 /*
117 * What should be done out of this file?
118 * Find the command associated to that file
119 * - UNPRINTABLE for unprintable
120 * - requested style sheet key
121 * - style sheet key
122 */
123 if (!file_job->printable)
124 file_job->type = "UNPRINTABLE";
125 else if (!IS_EMPTY (style_request))
126 file_job->type = style_request;
127 else
128 file_job->type = get_command (file_job->name,
129 (sample_tmpname
130 ? (uchar *) sample_tmpname
131 : file_job->name));
132
133 /* Remove the sample file */
134 if (sample_tmpname)
135 unlink (sample_tmpname);
136 return res;
137 }
138
139 static void
input_end(buffer_t * buffer)140 input_end (buffer_t * buffer)
141 {
142 if (buffer->stream && buffer->stream!= stdin)
143 fclose (buffer->stream);
144 buffer_release (buffer);
145 free (buffer);
146
147 a2ps_close_input_session (job);
148 }
149
150 /************************************************************************/
151 /* The producers */
152 /************************************************************************/
153 /*
154 * Make on message on what we did
155 */
156 static void
msg_file_pages_printed(a2ps_job * Job,const char * stylename)157 msg_file_pages_printed (a2ps_job * Job, const char * stylename)
158 {
159 int sheets;
160
161 sheets = CURRENT_FILE (Job)->sheets;
162 if (Job->duplex)
163 sheets = (sheets + 1) / 2;
164
165 if (CURRENT_FILE (Job)->pages == 1)
166 /* 1 page on 1 sheet */
167 message (msg_report2,
168 (stderr, _("[%s (%s): 1 page on 1 sheet]\n"),
169 CURRENT_FILE (Job)->name,
170 stylename));
171 else if (sheets == 1)
172 /* several pages on 1 sheet */
173 message (msg_report2,
174 (stderr, _("[%s (%s): %d pages on 1 sheet]\n"),
175 CURRENT_FILE (Job)->name,
176 stylename,
177 CURRENT_FILE (Job)->pages));
178 else
179 /* several sheets */
180 message (msg_report2,
181 (stderr, _("[%s (%s): %d pages on %d sheets]\n"),
182 CURRENT_FILE (Job)->name,
183 stylename,
184 CURRENT_FILE (Job)-> pages,
185 sheets));
186 }
187
188 /*
189 * Total printed
190 */
191 void
msg_job_pages_printed(a2ps_job * Job)192 msg_job_pages_printed (a2ps_job * Job)
193 {
194 int sheets;
195 uchar *ucp;
196
197 sheets = Job->sheets;
198 if (Job->duplex)
199 sheets = (sheets + 1) / 2;
200
201 /* Make a nice message to tell where the output is sent */
202 ucp = a2ps_destination_to_string (Job);
203
204 /* Report the pages */
205 if (Job->pages == 1)
206 /* 1 page on 1 sheet "sent to the default printer" etc. */
207 message (msg_report1,
208 (stderr, _("[Total: 1 page on 1 sheet] %s\n"), ucp));
209 else if (sheets == 1)
210 /* several pages on 1 sheet */
211 message (msg_report1,
212 (stderr, _("[Total: %d pages on 1 sheet] %s\n"),
213 Job->pages, ucp));
214 else
215 /* several sheets */
216 message (msg_report1,
217 (stderr, _("[Total: %d pages on %d sheets] %s\n"),
218 Job-> pages, sheets, ucp));
219
220 /* Report the number of lines that were too long. */
221 if (macro_meta_sequence_get (Job, "cfg.wrapped")
222 && Job->lines_folded)
223 {
224 if (Job->lines_folded == 1)
225 message (msg_report1,
226 (stderr, _("[1 line wrapped]\n")));
227 else
228 message (msg_report1,
229 (stderr, _("[%d lines wrapped]\n"),
230 Job->lines_folded));
231 }
232
233 free (ucp);
234 }
235 /*
236 * Total printed
237 */
238 void
msg_nothing_printed(void)239 msg_nothing_printed (void)
240 {
241 message (msg_report1,
242 (stderr, _("[No output produced]\n")));
243 }
244
245 void
print_toc(const uchar * name,const uchar * value,int * native_jobs)246 print_toc (const uchar * name, const uchar * value, int * native_jobs)
247 {
248 buffer_t toc_buffer;
249 uchar * toc_content;
250
251 /* Create a entry for the toc, as if it were a regular file */
252 a2ps_open_input_session (job, xustrdup (name));
253 /* But it is not a regular file: we need to be able to know
254 * that it is indeed a toc, so that --pages=toc can be honored */
255 CURRENT_FILE (job)->is_toc = true;
256
257 austrcpy (toc_content,
258 expand_user_string (job, CURRENT_FILE (job),
259 name, value));
260 buffer_string_set (&toc_buffer, toc_content, end_of_line);
261
262 /* We typeset it with PreScript */
263 ssh_print_postscript (job, &toc_buffer, get_style_sheet ("pre"));
264 (*native_jobs)++;
265
266 a2ps_close_input_session (job);
267 }
268
269 /*
270 * Called by the main loop.
271 * The file to print is the last of the darray job->jobs.
272 * Return true if was a success, false otherwise
273 */
274 void
print(uchar * filename,int * native_jobs,int * delegated_jobs)275 print (uchar * filename, int * native_jobs, int * delegated_jobs)
276 {
277 char buf[512];
278 struct delegation * contract = NULL;
279 struct style_sheet * sheet;
280 buffer_t * input_buffer;
281 enum style_kind_e style_kind;
282 struct file_job * file_job;
283
284 /*
285 * First, open that file and get info about it
286 * It may seem useless in some cases (e.g. the file will be delegated)
287 * but it ensures that readbility, and stat can be correctly done.
288 */
289 input_buffer = input_new (filename);
290
291 /* Get the file_job _after_ it has been created by input_new */
292 file_job = CURRENT_FILE (job);
293
294 if (delegate_p
295 && (contract =
296 get_subcontract (file_job->type,
297 output_format_to_key (job->output_format))))
298 style_kind = delegate;
299 else
300 style_kind = string_to_style_kind (file_job->type);
301
302 message (msg_file,
303 (stderr, "Getting ready to print file `%s', with command `%s'\n",
304 file_job->name, file_job->type));
305
306 /*
307 * Then do it
308 */
309 switch (style_kind)
310 {
311 case delegate:
312 /* In ps generation, we must begin a new page */
313 page_flush (job);
314 sprintf (buf, _("%s, delegated to %s"),
315 file_job->type, contract->name);
316 if (subcontract (file_job, input_buffer, contract))
317 {
318 (*delegated_jobs)++;
319 msg_file_pages_printed (job, buf);
320 }
321 else
322 message (msg_report2, (stderr, _("[%s (%s): failed. Ignored]\n"),
323 file_job->name, buf));
324 break;
325
326 case unprintable:
327 /* The job will not be processed correctly */
328 message (msg_report2,
329 (stderr,
330 _("[%s (unprintable): ignored]\n"), file_job->name));
331 break;
332
333 case binary:
334 if (job->print_binaries)
335 goto plain_print;
336
337 message (msg_report2,
338 (stderr,
339 _("[%s (binary): ignored]\n"), file_job->name));
340 break;
341
342 case sshparser:
343 /* If highlight_level == none, don't */
344 if (highlight_level == 0)
345 goto plain_print;
346 sheet = get_style_sheet (file_job->type);
347 if (!sheet)
348 goto plain_print;
349
350 buffer_set_lower_case (input_buffer,
351 sheet->sensitiveness == case_insensitive);
352 ssh_print_postscript (job, input_buffer, sheet);
353 msg_file_pages_printed (job, (const char *) sheet->name);
354 (*native_jobs)++;
355 break;
356
357 plain_print:
358 case no_style:
359 plain_print_postscript (job, input_buffer);
360 msg_file_pages_printed (job, _("plain"));
361 (*native_jobs)++;
362 break;
363 }
364
365 input_end (input_buffer);
366 }
367
368 /*
369 * Called by the main loop.
370 * Almost like the above `PRINT' function, but just reports the guesses.
371 * This is a dirty hack of sth OK in 4.11
372 */
373 void
guess(uchar * filename)374 guess (uchar * filename)
375 {
376 buffer_t * buffer;
377 struct file_job * file_job;
378
379 buffer = input_new (filename);
380 file_job = CURRENT_FILE (job);
381 printf ("[%s (%s)]\n", file_job->name, file_job->type);
382
383 /* Close the files, free, and close the input session */
384 if (buffer->stream && buffer->stream != stdin)
385 fclose (buffer->stream);
386 }
387