3
* routines for the postscript generation
5
* Copyright (c) 1988-1993 Miguel Santana
6
* Copyright (c) 1995-1999 Akim Demaille, Miguel Santana
10
* This file is part of a2ps.
12
* This program is free software; you can redistribute it and/or modify
13
* it under the terms of the GNU General Public License as published by
14
* the Free Software Foundation; either version 2, or (at your option)
17
* This program is distributed in the hope that it will be useful,
18
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
* GNU General Public License for more details.
22
* You should have received a copy of the GNU General Public License
23
* along with this program; see the file COPYING. If not, write to
24
* the Free Software Foundation, 59 Temple Place - Suite 330,
25
* Boston, MA 02111-1307, USA.
29
* $Id: psgen.c,v 1.82 1998/03/02 15:37:45 demaille Exp $
32
#include "a2ps.h" /* most global variables */
35
#include "routines.h" /* general interest routines */
36
#include "output.h" /* Diverted outputs */
47
#define PRINT_HEADER \
48
(!IS_EMPTY(job->header))
50
#define PRINT_FOOTER \
51
(!IS_EMPTY(job->footer) \
52
|| !IS_EMPTY(job->left_footer) \
53
|| !IS_EMPTY(job->right_footer))
56
(!IS_EMPTY(job->center_title) \
57
|| !IS_EMPTY(job->left_title) \
58
|| !IS_EMPTY(job->right_title))
60
/* Width in characters for line prefix */
61
#define prefix_size (job->numbering ? 5 : 0)
63
/* Is this the first page for the current file? */
64
#define is_first_page \
65
((job->pages - CURRENT_FILE (job)->first_page) > 1)
67
#define jdiv job->divertion
69
/* return the max of two >-comparable stuff */
70
#define A2_MAX(X,Y) (((X) > (Y)) ? (X) : (Y))
73
/****************************************************************/
74
/* Formating help routines */
75
/****************************************************************/
77
* Print a char in a form accepted by postscript printers.
78
* Returns number of columns used (on the output) to print the char.
81
ps_escape_char (a2ps_job * job, uchar c, uchar * res)
85
/* The number of columns used must be calculated here because of the
86
* \ before non-ascii chars, and (, ), and \ itself */
88
/* Printable and 7bit clean caracters */
89
if (' ' <= c && c < 0177) {
90
if (c == '(' || c == ')' || c == '\\')
96
/* Printable, but not 7bit clean caracters */
97
if (encoding_char_exists (job->encoding, job->status->face, c)
98
&& ((0177 < c) || (c < 040))) {
99
sprintf ((char *)res, "%s\\%o", res, c);
103
/* We are dealing with a non-printing character */
104
job->status->nonprinting_chars++;
106
/* We do this in here for speed. We could have first escaped, then
107
consider the new string as the string to ps-escape. */
108
switch (job->unprintable_format) {
110
sprintf ((char *) res, "\\\\%03o", c);
114
sprintf ((char *) res, "\\\\x%02x", c);
136
if (c == '(' || c == ')' || c == '\\')
139
} else if (c == 0177) {
143
if (c == '(' || c == ')' || c == '\\')
161
if (c == '(' || c == ')' || c == '\\')
164
} else if (c == 0177) {
168
if (c == '(' || c == ')' || c == '\\')
180
* Print a string in a form accepted by postscript printers.
183
ps_escape_string (a2ps_job * job, uchar * string, uchar * res)
188
for (i = 0 ; i < ustrlen (string) ; i++)
189
delta_column += ps_escape_char (job, string[i], res);
195
* Output the formated marker.
198
output_marker (a2ps_job * job, const char * kind, uchar * marker)
203
cp = expand_user_string (job, CURRENT_FILE (job),
204
(const uchar *) kind, marker);
206
for (i = 0 ; cp[i] ; i++) {
209
output_delayed_int (jdiv, &(CURRENT_FILE (job)->last_page));
211
case FILE_LAST_SHEET:
212
output_delayed_int (jdiv, &(CURRENT_FILE (job)->last_sheet));
215
output_delayed_int (jdiv, &(CURRENT_FILE (job)->pages));
218
output_delayed_int (jdiv, &(CURRENT_FILE (job)->sheets));
221
output_delayed_int (jdiv, &(CURRENT_FILE (job)->lines));
224
output_delayed_int (jdiv, &job->pages);
227
output_delayed_int (jdiv, &job->sheets);
230
output_delayed_int (jdiv, &job->total_files);
234
ps_escape_char (job, cp[i], buf);
235
output (jdiv, (char *) buf);
241
/****************************************************************/
242
/* Dealing with the encodings */
243
/****************************************************************/
245
* Change the current encoding
248
ps_set_encoding (a2ps_job * job, struct encoding * enc)
250
set_encoding (job, enc);
251
job->status->opened_encoding = enc;
252
output (jdiv, "%sdict begin\n", encoding_get_key (enc));
256
ps_end_encoding (a2ps_job * job)
258
if (job->status->opened_encoding)
259
output (jdiv, "end %% of %sdict\n",
260
encoding_get_key (job->status->opened_encoding));
261
set_encoding (job, NULL);
262
job->status->opened_encoding = NULL;
266
* Switch of encoding while we are _not_ in the body. E.g., we
267
* are dealing with the headers.
269
* We want to save the previous encoding, because, say we
270
* were printing -X latin1, we have switched to latin2 dynamically.
271
* Right now, we need to change page,
272
* so we are using back latin1, but we must remember of latin2
273
* for the following page.
276
ps_internal_switch_encoding (a2ps_job * job, struct encoding * enc)
278
if (job->encoding != enc) {
279
/* If there are no dictionary opened yet, it is because we are
280
* changing of dict outside the text body (e.g. even before
281
* the first output char). In this case, do not open a
282
* ps dict: it is not time yet.
284
if (job->status->opened_encoding) {
285
ps_end_encoding (job);
286
ps_set_encoding (job, enc);
288
ps_end_encoding (job);
289
set_encoding (job, enc);
291
/* Make sure to re-declare the font */
292
job->status->face_declared = false;
297
* Switch the encoding during the print process (ie. from
298
* within the body of the text)
299
* We have to take care of closing the line currently being printed
300
* and restore the state, i.e. opening a string to print.
303
ps_switch_encoding (a2ps_job * job, struct encoding * enc)
305
if (job->encoding != enc)
307
if (!job->status->start_line) {
308
if (!job->status->face_declared)
309
output (jdiv, ") %s\n", face_eo_ps (job->status->face));
311
output (jdiv, ") S\n");
313
ps_internal_switch_encoding (job, enc);
314
job->saved_encoding = enc;
315
if (!job->status->start_line)
316
output_char (jdiv, '(');
321
ps_push_encoding (a2ps_job * job, struct encoding * enc)
323
job->saved_encoding = job->encoding;
324
ps_internal_switch_encoding (job, enc);
328
ps_pop_encoding (a2ps_job * job)
330
ps_internal_switch_encoding (job, job->saved_encoding);
333
/****************************************************************/
334
/* Printing a physical page */
335
/****************************************************************/
337
* Print the prolog necessary for printing each physical page.
338
* Adobe convention for page independence is enforced through this routine.
339
* Note that is may called for a second time on a single sheet if two
340
* different files are printed on the same sheet.
343
page_begin (a2ps_job * job)
347
if (print_page (job, job->pages))
350
/* The number of pages has not been updated yet: add 1 */
351
CURRENT_FILE (job)->top_page = CURRENT_FILE (job)->pages + 1;
353
* Getting ready to delay the page label
354
* This means to build a new string handler, store it, and fill it later
355
* We do this because one would like to have all the information on
356
* what is on the current page before making the page label.
358
if (!output_is_to_void (jdiv))
360
output (jdiv, "%%%%Page: (");
361
job->status->page_label = XMALLOC (uchar *, 1);
362
output_delayed_string (jdiv, job->status->page_label);
363
output (jdiv, ") %d\n", job->sheets);
366
/* Reinitialize state variables for each new sheet */
367
output (jdiv, "%%%%BeginPageSetup\n");
368
output (jdiv, "/pagesave save def\n");
370
/* Shift front side sheets */
372
&& (job->duplex == simplex || (job->sheets % 2)))
373
output (jdiv, "%d 0 translate\n", job->margin);
375
if (job->orientation == landscape)
376
output (jdiv, "sh 0 translate 90 rotate\n");
378
output (jdiv, "%%%%EndPageSetup\n");
382
%% Display the bounding box\n\
393
/* Set the encoding */
394
ps_set_encoding (job, job->requested_encoding);
396
/* water marks (only once per sheet) */
397
if (!IS_EMPTY(job->water))
399
output_char (jdiv, '(');
400
output_marker (job, "water mark", job->water);
403
((float) atan2 ((double) job->medium->w - job->margin,
404
(double) job->medium->h)
405
/ 3.14159265 * 180));
408
/* Move to the lower left point of the drawable area */
409
output (jdiv, "gsave\n");
410
output (jdiv, "llx lly %d add translate\n",
411
PRINT_FOOTER * HEADERS_H);
412
/* Set the encoding */
413
ps_internal_switch_encoding (job, job->saved_encoding);
416
/* The job on the page is over: puts the headers and footers,
417
* then print the physical page.
420
page_end (a2ps_job * job)
422
/* The page label has been divertered (through a handler).
423
* Fill that handler with the correct page label value
425
*(job->status->page_label) =
426
xustrdup (expand_user_string (job, CURRENT_FILE (job),
427
(const uchar *) "Page label",
428
job->status->page_label_format));
430
output (jdiv, "grestore\n");
432
/* All the headers should be written using the requested encoding */
433
ps_push_encoding (job, job->requested_encoding);
435
/* Print the right header */
437
output_char (jdiv, '(');
438
output_marker (job, "right header", job->header);
439
output (jdiv, ") rhead\n");
442
/* Print the center footer.
443
* Use dynamic markers in priority
446
if (!IS_EMPTY(job->footer)) {
447
output_char (jdiv, '(');
448
output_marker (job, "center footer", job->footer);
451
output (jdiv, "() ");
453
/* Print the right footer */
454
if (!IS_EMPTY(job->right_footer)) {
455
output_char (jdiv, '(');
456
output_marker (job, "right footer", job->right_footer);
459
output (jdiv, "() ");
461
/* Print the left footer */
462
if (!IS_EMPTY(job->left_footer)) {
463
output_char (jdiv, '(');
464
output_marker (job, "left footer", job->left_footer);
468
output (jdiv, "() ");
469
output (jdiv, "footer\n");
472
/* Close the current encoding */
473
ps_end_encoding (job);
475
output (jdiv, "pagesave restore\n");
476
output (jdiv, "showpage\n");
481
/****************************************************************/
482
/* Printing a virtual page */
483
/****************************************************************/
485
* Prints page header and page border and
486
* initializes printing of the file lines.
489
virtual_begin (a2ps_job * job)
493
if (print_page (job, job->pages)) {
494
output_to_void (jdiv, false);
497
output_to_void (jdiv, true);
500
/* We test to one, since it has just been incremented above */
501
if (job->virtual == 1)
505
ps_set_encoding (job, job->saved_encoding);
507
file_job_synchronize_pages (job);
508
file_job_synchronize_sheets (job);
510
output (jdiv, "/v %d store\n", job->virtual - 1);
511
output (jdiv, "/x0 x v get %f add sx cw mul add store\n",
512
SIDE_MARGIN_RATIO * job->fontsize * 0.6);
513
output (jdiv, "/y0 y v get bfs %s sub store\n",
514
PRINT_TITLE ? "th add" : "");
515
output (jdiv, "x0 y0 moveto\n");
519
* Adds a sheet number to the page (footnote) and prints the formatted
520
* page (physical impression). Activated at the end of each source page.
523
virtual_end (a2ps_job * job)
526
* Print the titles with the option-given encoding
528
/* Draw the header and its content */
530
ps_push_encoding (job, job->requested_encoding);
531
if (!IS_EMPTY(job->center_title)) {
532
output_char (jdiv, '(');
533
output_marker (job, "center title", job->center_title);
536
output (jdiv, "() ");
538
if (!IS_EMPTY(job->right_title)) {
539
output_char (jdiv, '(');
540
output_marker (job, "right title", job->right_title);
543
output (jdiv, "() ");
545
if (!IS_EMPTY(job->left_title)) {
546
output_char (jdiv, '(');
547
output_marker (job, "left title", job->left_title);
550
output (jdiv, "() ");
552
output (jdiv, "title\n");
553
ps_pop_encoding (job);
557
output (jdiv, "border\n");
559
if (job->virtual == (job->columns * job->rows))
562
job->status->line = 0;
565
/* Issue an empty virtual (used for file alignment). */
568
virtual_empty_output (a2ps_job *job)
570
/* Let's use a hidden option which lets choose between an empty
571
virtual (with headers etc.), or nothing printed at all. */
572
if (macro_meta_sequence_get (job, VAR_OPT_VIRTUAL_FORCE))
579
/* Just increase the virtual number, that's enough. */
582
if (job->virtual == (job->columns * job->rows))
588
* Flush the (physical) page, ready for new page
590
* -- at the end of the whole job
591
* -- at the end of a page
592
* -- when a fresh page is required (eg, when after an a2ps
593
* generated ps page arrives a delegated ps file)
596
page_flush (a2ps_job * job)
598
/* Everything that follows _must_ be dumped */
599
output_to_void (job->divertion, false);
601
/* If the sheet has not been printed, flush it */
602
if (job->virtual != 0)
606
/* Output an empty page (used for instance to align files.
607
No page should be waiting (issue flushes before). */
610
page_empty_output (a2ps_job *job)
613
file_job_synchronize_sheets (job);
614
output (jdiv, "%%%%Page: (*) %d\n", job->sheets);
615
output (jdiv, "%% Empty Page\n");
616
output (jdiv, "showpage\n");
620
sheet_flush (a2ps_job *job)
624
/* Need an empty back side? */
625
if ((job->duplex == duplex || job->duplex == tumble)
626
&& (job->sheets % 2) != 0)
627
page_empty_output (job);
631
* Make sure this a new sheet.
632
* No DSC is done on the new page. This is used when delegated
633
* ps file is inlined.
636
require_fresh_page (a2ps_job * job)
638
/* If this is not a blank sheet, end it */
639
if (job->virtual != 0)
640
/* The clean up _must_ be done */
644
/****************************************************************/
645
/* Service routines */
646
/****************************************************************/
648
* Test if we have a binary file.
650
* Printing binary files is not very useful. We stop printing
651
* if we detect one of these files. Our heuristic to detect them:
652
* if 40% characters are non-printing characters,
653
* the file is a binary file. (40% is taken from the case of a2ps istself).
656
check_binary_file (a2ps_job * job)
658
if (job->status->chars > 120)
660
if (!job->print_binaries
661
&& (job->status->nonprinting_chars*100 / job->status->chars) >= 40)
662
error (1, 0, _("`%s' is a binary file, printing aborted"),
663
CURRENT_FILE (job)->name);
668
end_of_line (struct a2ps_job * job)
670
if (!job->status->face_declared) {
671
output (jdiv, ") %s n\n", face_eo_ps (job->status->face));
672
job->status->face_declared = true;
674
output (jdiv, ") N\n");
676
job->status->column = 0;
681
(job->status->line >= job->status->linesperpage)
683
#define line_full (job->status->wx > job->status->wxperline)
686
* Fold a line too long.
689
fold_line (struct a2ps_job * job, enum face_e new_face)
697
job->status->face_declared = false ;
701
output (jdiv, "0 T (");
705
/* This is a new line, hence we can consider that there is no
706
need to close the current font: just consider it is the new
707
font, but not declared. */
708
output_char (jdiv, '(');
709
job->status->face_declared &= (job->status->face
711
job->status->face = new_face;
719
ps_print_char (a2ps_job * job, int c, enum face_e new_face)
722
* Preprocessing (before printing):
723
* - TABs expansion (see interpret option)
724
* - FF and BS interpretation
725
* - replace non printable characters by a space or a char sequence
727
* ^X for ascii codes < 0x20 (X = [@, A, B, ...])
729
* M-c for ascii codes > 0x3f
730
* - prefix parents and backslash ['(', ')', '\'] by backslash
731
* (escape character in postcript)
733
if (job->status->is_in_cut
735
/* FIXME: May be some day, using a more flexible scheme
737
&& (c != encodings[job->encoding].new_line))*/
740
job->status->is_in_cut = false;
742
/* Start a new line ? */
743
if (job->status->start_line)
745
if (job->status->start_page)
747
/* only if there is something to print! */
749
job->status->start_page = false ;
750
/* This is the first line of a new page, hence we need (page
751
* independance) to repeat the current font */
752
job->status->face = new_face;
753
job->status->face_declared = false;
757
if (CURRENT_FILE (job)->lines % job->numbering == 0)
758
output (jdiv, "(%d) # (", CURRENT_FILE (job)->lines);
760
output (jdiv, "0 T (");
763
output_char (jdiv, '(');
767
/* This is a new line, but not the first in the page */
770
if (CURRENT_FILE (job)->lines % job->numbering == 0)
771
output (jdiv, "(%d) # (", CURRENT_FILE (job)->lines);
773
output (jdiv, "0 T (");
777
/* This is a new line, hence we can consider that there is
778
no need to close the current font: just consider it is
779
the new font, but not declared. */
780
output_char (jdiv, '(');
781
/* Why the hell did I do this? */
782
/* FIXME: This is suppresed because of the changes of encoding */
783
job->status->face_declared = (job->status->face_declared
784
&& (job->status->face == new_face));
785
job->status->face = new_face;
788
job->status->start_line = false;
792
* Interpret each character
794
* One of the tricky stuff is that we want to avoid uncessary
795
* Changes of font. For instance, I see no point in
796
* Updating the font right before a \n.
799
case '\f': /* Form feed */
803
/* Close current line */
804
if (!job->status->start_line)
807
job->status->start_line = true;
809
/* start a new page ? */
810
if (job->status->start_page)
814
/* Close current page and begin another */
816
job->status->start_page = true;
821
/* Now the primary eol is \n. It is up to a2ps-prog to change the
824
case '\r': /* One of these is just a plain character */
825
if (c != encodings[job->encoding].new_line)
828
(CURRENT_FILE (job))->lines++;
829
job->status->start_line = true;
834
job->status->start_page = true ;
842
/* Is this a new font? */
843
if (job->status->face != new_face) {
844
if (!job->status->face_declared)
845
output (jdiv, ") %s\n(", face_eo_ps (job->status->face));
847
output (jdiv, ") S\n(");
848
job->status->face = new_face;
849
job->status->face_declared = false;
852
/* Tabs are interpreted but we want to go to the same
853
* column as if the font were Courier
855
job->status->column =
856
(A2_MAX(job->status->wx / COURIER_WX, job->status->column)
857
/ job->tabsize + 1) * job->tabsize;
858
job->status->wx = job->status->column * COURIER_WX;
861
fold_line (job, new_face);
863
job->status->is_in_cut = true;
867
/* Make sure that the font is given */
868
if (!job->status->face_declared) {
869
output (jdiv, ") %s", face_eo_ps(job->status->face));
870
job->status->face_declared = true;
872
output (jdiv, ") S");
873
output (jdiv, " %d T (", job->status->column);
882
/* Is this a new font? */
883
if (job->status->face != new_face) {
884
if (!job->status->face_declared)
885
output (jdiv, ") %s\n(", face_eo_ps (job->status->face));
887
output (jdiv, ") S\n(");
888
job->status->face = new_face;
889
job->status->face_declared = false;
892
nchars = ps_escape_char (job, c, buf);
893
job->status->wx += char_WX (job, c);
894
job->status->column += nchars;
897
fold_line (job, new_face);
898
job->status->column = nchars;
899
job->status->wx = char_WX (job, c);
901
job->status->is_in_cut = true;
905
output (jdiv, "%s", buf);
906
job->status->chars++;
913
* Print the content of a C string \0 terminated
916
ps_print_string (a2ps_job * job, uchar * string, enum face_e face)
919
ps_print_char (job, *(string++), face);
923
* Print the N first chars in BUFFER
926
ps_print_buffer (a2ps_job * job,
927
const uchar * buffer,
928
size_t start, size_t end,
932
for (i = start ; i < end ; i++)
933
ps_print_char (job, buffer [i], face);
936
/* Handling the input sessions in an output session, i.e., typically
939
/* A new file will be printed. */
942
ps_begin_file (a2ps_job *job)
944
/* Reinitialize the ps status */
945
initialize_ps_status (job->status);
947
/* Alignment is not needed for the first file. */
948
if (job->jobs->len == 0)
951
switch (job->file_align)
953
case file_align_virtual:
957
case file_align_rank:
958
/* Issue virtual until we are in a new rank. */
960
int alignment = job->madir == madir_rows ? job->columns : job->rows;
961
while (job->pages % alignment != 0)
962
virtual_empty_output (job);
966
case file_align_page:
967
/* End the page if needed. */
971
case file_align_sheet:
972
/* End the sheet if needed. */
977
/* job->file_align is a number. We must issue as many pages as
978
needed to have a page number which is a multiple of
979
FILE_ALIGN plus one. */
981
while ((job->sheets) % job->file_align != 0)
982
page_empty_output (job);
988
ps_end_file (a2ps_job *job)
990
/* If a line was not finished, close it.
991
* Typically, no \n at end of file */
992
if (!job->status->start_line)
994
if (!job->status->face_declared)
995
output (jdiv, ") %s\n", face_eo_ps (job->status->face));
997
output (jdiv, ") S\n");
999
if (!job->status->start_page)
1002
/* Set the number of pages/sheets printed */
1003
file_job_synchronize_pages (job);
1004
file_job_synchronize_sheets (job);
1006
/* If we don't want to print binaries, complain and quit */
1007
check_binary_file (job);