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