home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: Multimed / Multimed.zip / chord3_6.zip / chord / chord.c < prev    next >
C/C++ Source or Header  |  1995-04-25  |  33KB  |  1,346 lines

  1. static char SccsId[] = "@(#)chord.c    3.6\t Mar. 1995";
  2. static char copyright[] = "Copyright 1991-1995 by Martin Leclerc & Mario Dorion";
  3.  
  4.  
  5. #include "chord.h"
  6.  
  7. static FILE *source_fd;
  8.  
  9. char
  10.     text_line[MAXLINE],    /* Lyrics Buffer */
  11.     chord[MAXTOKEN],    /* Buffer for the name of the chord */
  12.     title1[MAXLINE];    /* Holds the first title line */
  13.  
  14. char
  15.     source[MAXTOKEN],
  16.     directive[MAXLINE];    /* Buffer for the directive */
  17.  
  18. char
  19.     i_input;        /* Input line pointer */
  20.  
  21. char
  22.     mesgbuf[MAXTOKEN],
  23.     *mesg,
  24.     *text_font, *rt_text_font, *rc_text_font,     /* font for text */
  25.     *chord_font, *rt_chord_font, *rc_chord_font,     /* font for chord */
  26.     *mono_font = MONOSPACED_FONT,    /* non-proprotional font for tabs */
  27.     *current_file,
  28.     *chord_line[MAXLINE],
  29.     *command_name;
  30.  
  31. int
  32.     c,            /* Current character in input file */
  33.     i_chord,        /* Index to 'chord' */
  34.     i_directive,        /* Index to 'directive' */
  35.     i_text,         /* Index to 'text_line' */
  36.     in_chord,        /* Booleans indicating parsing status */
  37.     left_foot_even = -1,     /* 0 for even page numbers on the right */
  38.                 /* 1 for even page numbers on the left */
  39.     no_grid, rt_no_grid, rc_no_grid,
  40.     page_label = 1,        /* physical page number */
  41.     lpage_label = 1,    /* logical page number */
  42.     i_chord_ov,        /* Overflow Booleans */
  43.     pagination = 1,        /* virtual pages per physical pages */
  44.     transpose = 0,        /* transposition value */
  45.     vpos,            /* Current PostScript position, in points */
  46.     col_vpos,        /* Beginning height of column, in points */
  47.     min_col_vpos = TOP,    /* lowest colums ending */
  48.     hpos,
  49.     h_offset = 0,         /* horizontal offset for multi-col output */
  50.     start_of_chorus,    /* Vertical positions of the chorus */
  51.     end_of_chorus,
  52.     chord_size, rt_chord_size, rc_chord_size,      /* font size for 'chord_font' */
  53.     cur_text_size = 0,
  54.     text_size, rt_text_size, rc_text_size,      /* font size for 'text_font' */
  55.     grid_size, rt_grid_size, rc_grid_size,
  56.     n_pages = 1,        /* total physical page counter */
  57.     v_pages = 1,        /* virtual pages */
  58.     n_lines = 1,        /* line number in input file */
  59.     max_columns = 1,    /* number of columns */
  60.     n_columns = 0,        /* counter of columns */
  61.     song_pages = 1,        /* song page counter */
  62.     blank_space = 0;    /* consecutive blank line counter */
  63.  
  64. int                 /* BOOLEANS */
  65.     number_all = FALSE,    /* number the first page (set with -p 1) */
  66.     lyrics_only = FALSE,
  67.     dump_only = FALSE,
  68.     in_tab = FALSE,
  69.     postscript_dump = FALSE,
  70.     auto_space = FALSE,    /* applies lyrics_only when no chords */
  71.     need_soc = FALSE,
  72.     do_toc = FALSE,
  73.     no_easy_grids = FALSE,
  74.     i_directive_ov = FALSE,
  75.     i_text_ov = FALSE,
  76.     in_directive = FALSE,
  77.     in_chordrc = FALSE,
  78.     first_time_in_chordrc = TRUE,
  79.     in_chorus = FALSE,
  80.     has_directive = FALSE,
  81.     has_chord = FALSE,
  82.     title1_found = FALSE,
  83.     number_logical = FALSE,
  84.     debug_mode = FALSE;
  85.  
  86. float
  87.     chord_inc,
  88.     scale = 1.0,        /* Current scale factor */
  89.     rotation = 0.0,        /* Current rotation */
  90.     page_ratio = ((TOP+BOTTOM)/WIDTH);
  91.  
  92. extern int nb_chord, first_ptr;
  93. extern struct chord_struct *so_chordtab;
  94. extern struct toc_struct *so_toc ;
  95.  
  96. extern char *optarg;
  97. extern int optind, opterr;
  98.  
  99.  
  100. /* --------------------------------------------------------------------------------*/
  101. void ps_fputc(fd, c)
  102. FILE *fd;
  103. int c;
  104.         {
  105.         if (c >128)
  106.         {
  107.                    fprintf (fd, "\\%o", c);
  108.         }
  109.         else 
  110.         switch ((char)c)
  111.         {
  112.         case ')' :
  113.                        fprintf (fd, "\\%c", c); break;
  114.         case '(' :
  115.                        fprintf (fd, "\\%c", c); break;
  116.         case '\\' :
  117.             fprintf (fd, "\\\\", c); break;
  118.         default:
  119.             fprintf (fd, "%c",c);
  120.         }
  121.         }
  122. /* --------------------------------------------------------------------------------*/
  123. void ps_fputs(fd, string)
  124. FILE *fd;
  125. char *string;
  126.         {
  127.         int i;
  128.  
  129.     /* sprintf (mesg, "ps_fputs:%s ",string); debug(mesg); */
  130.  
  131.         for (i= 0; string[i] != '\0'; i++)
  132.                 ps_fputc (fd, string[i]);
  133.  
  134.         }
  135.  
  136.  
  137. /* --------------------------------------------------------------------------------*/
  138. void ps_puts(string)
  139. char *string;
  140.     {
  141.     ps_fputs(stdout, string);
  142.     }
  143. /* --------------------------------------------------------------------------------*/
  144. void set_text_font(size)
  145. int size;
  146.     {
  147. #define    MONO_SIZE_DECR    2    /* TABsize is smaller by this nb of points */
  148.     if (( size != cur_text_size))
  149.         {
  150.         printf ("/TEXT_FONT { /%s findfont %d scalefont } def\n", text_font, size);
  151.         re_encode (text_font);
  152.         printf ("/MONO_FONT { /%s findfont %d scalefont } def\n",
  153.             mono_font, size - MONO_SIZE_DECR);
  154.         re_encode (mono_font);
  155.         cur_text_size= size;
  156.         /* sprintf(mesg, "Changing text size to %d", size); debug (mesg); */
  157.         }
  158. #undef MONO_SIZE_DECR
  159.     }
  160.  
  161. /* --------------------------------------------------------------------------------*/
  162. void use_text_font()
  163.     {
  164.     if (! in_tab) printf ("TEXT_FONT setfont\n");
  165.     else printf ("MONO_FONT setfont\n");
  166.     }
  167. /* --------------------------------------------------------------------------------*/
  168. void use_mono_font()
  169.     {
  170.     printf ("MONO_FONT setfont\n");
  171.     }
  172. /* --------------------------------------------------------------------------------*/
  173. void do_translate(vert, horiz)
  174. float vert, horiz;
  175.     {
  176.     printf ("%f %f translate\n", vert , horiz );
  177.     debug ("changing translation");
  178.     }
  179. /* --------------------------------------------------------------------------------*/
  180. void do_start_of_page()
  181. /*logical page ! */
  182.     {
  183.     v_pages++;
  184.     lpage_label++;
  185.  
  186.     if (v_pages == 1)
  187.         {
  188.         n_pages++;
  189.         page_label++;
  190.         printf ("%%%%Page: \"%d\" %d\n",n_pages, n_pages);
  191.         printf ("%%%%BeginPageSetup\n");
  192.         if (pagination > 1)
  193.             {
  194.             printf ("gsave\n");
  195.             printf ("%f %f scale\n", scale, scale);
  196.             printf ("%f rotate\n",rotation);
  197.             }
  198.         printf ("%%%%EndPageSetup\n");
  199.         }
  200.  
  201.     if (pagination== 4)
  202.         {
  203.         if (v_pages== 1) do_translate(L_MARGIN, (TOP+BOTTOM)*1.05);
  204.         else if (v_pages== 2) do_translate(WIDTH-L_MARGIN, 0.0);
  205.         else if (v_pages== 3) do_translate(-(WIDTH-L_MARGIN), -TOP*1.05);
  206.         else if (v_pages== 4) do_translate(WIDTH-L_MARGIN, 0.0);
  207.         }
  208.  
  209.     if (pagination== 2)
  210.         if (v_pages == 1)
  211.             {
  212.             do_translate (0.0, -(TOP+BOTTOM+L_MARGIN/scale));
  213.             }
  214.         else if (v_pages == 2)
  215.             do_translate(WIDTH, 0.0);
  216.  
  217.     vpos = TOP;
  218.     min_col_vpos = TOP;
  219.     hpos= L_MARGIN;
  220.     n_columns = 0;
  221.     song_pages++;
  222.     set_text_font(text_size); /*28/4/94 ML */
  223.     if ( in_chorus )
  224.         {
  225.         start_of_chorus = vpos;
  226.         }
  227.     }
  228.  
  229. /* --------------------------------------------------------------------------------*/
  230. void use_chord_font()
  231.     {
  232.     printf ("CHORD_FONT setfont\n");
  233.     }
  234.  
  235. /* --------------------------------------------------------------------------------*/
  236. void set_chord_font()
  237.     {
  238.     printf ("/CHORD_FONT { /%s findfont %d scalefont } def\n", chord_font, chord_size);
  239.     re_encode (chord_font);
  240.     }
  241.  
  242. /* --------------------------------------------------------------------------------*/
  243. void do_help (command) 
  244. char *command;
  245.     {
  246.     fprintf (stderr, "Usage: %s [options] file [file ...]\n", command);
  247.     fprintf (stderr, "Options:\n");
  248.     fprintf (stderr, "    -A                 : About CHORD...\n");
  249.     fprintf (stderr, "    -a                 : Automatic single space lines without chords\n");
  250.     fprintf (stderr, "    -c n               : Set chord size [9]\n");
  251.     fprintf (stderr, "    -C postscript_font : Set chord font\n");
  252.     fprintf (stderr, "    -D                 : Dumps chords definitions (PostScript)\n");
  253.     fprintf (stderr, "    -d                 : Dumps chords definitions (Text)\n");
  254.     fprintf (stderr, "    -G                 : Disable printing of chord grids\n");
  255.     fprintf (stderr, "    -g                 : Don't print grids for builtin \"easy\" chords.\n");
  256.     fprintf (stderr, "    -h                 : This message\n");
  257.     fprintf (stderr, "    -i                 : Generates a table of contents\n");
  258.     fprintf (stderr, "    -L                 : Even pages numbers on left\n");
  259.     fprintf (stderr, "    -l                 : Only print lyrics\n");
  260.     fprintf (stderr, "    -n                 : Number logical pages, not physical\n");
  261.     fprintf (stderr, "    -o filename        : Saves the output to file\n");
  262.     fprintf (stderr, "    -p n               : Starting page number [1]\n");
  263.     fprintf (stderr, "    -s n               : Set chord grid size [30]\n");
  264.     fprintf (stderr, "    -t n               : Set text size [12]\n");
  265.     fprintf (stderr, "    -T postscript_font : Set text font\n");
  266.     fprintf (stderr, "    -V                 : Print version and patchlevel\n");
  267.     fprintf (stderr, "    -x n               : Transpose by 'n' half-tones\n");
  268.     fprintf (stderr, "    -2                 : 2 pages per sheet\n");
  269.     fprintf (stderr, "    -4                 : 4 pages per sheet\n");
  270.  
  271.     exit(0);
  272.     }
  273.  
  274. /* --------------------------------------------------------------------------------*/
  275. void do_about ()
  276.     {
  277.     printf("CHORD: A lyrics and chords formatting program.\n");
  278.     printf("===== \n");
  279.     printf("\n");;
  280.     printf("CHORD will read an ASCII file containing the lyrics of one or many\n");
  281.     printf("songs plus chord information. CHORD will then generate a photo-ready,\n");
  282.     printf("professional looking, impress-your-friends sheet-music suitable for printing\n");
  283.     printf("on your nearest PostScript printer.\n");
  284.     printf("\n");
  285.     printf("To learn more about CHORD, look for the man page or do \"chord -h\" for\n");
  286.     printf("the list of options.\n");
  287.     printf("\n");
  288.     printf("            --0--\n");
  289.     printf("\n");
  290.     printf("Copyright (C) 1991-1993 by Martin Leclerc & Mario Dorion\n");
  291.     printf("\n");
  292.     printf("This program is free software; you can redistribute it and/or modify\n");
  293.     printf("it under the terms of the GNU General Public License as published by\n");
  294.     printf("the Free Software Foundation; either version 2 of the License, or\n");
  295.     printf("(at your option) any later version.\n");
  296.     printf("\n");
  297.     printf("This program is distributed in the hope that it will be useful,\n");
  298.     printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
  299.     printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
  300.     printf("GNU General Public License for more details.\n");
  301.     printf("\n");
  302.     printf("You should have received a copy of the GNU General Public License\n");
  303.     printf("along with this program; if not, write to the Free Software\n");
  304.     printf("Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n");
  305.     printf("\n");
  306.     printf("Send all questions, comments and bug reports to the original authors:\n");
  307.  
  308.         printf("    Martin.Leclerc@Sun.COM and Mario.Dorion@Sun.COM\n");
  309.     printf("\n");
  310.     }
  311.  
  312. /* --------------------------------------------------------------------------------*/
  313. void do_comment(comment, style)
  314. char     *comment;
  315. int    style;
  316.     {
  317.     if (comment == NULL)
  318.         {
  319.         error ("Null comment.");
  320.         return;
  321.         }
  322.     for (; *comment == ' '; comment++); /* strip leading blanks */
  323.     advance(blank_space);
  324.     blank_space = 0;
  325.     advance(text_size);
  326.     text_line[i_text] = '\0';
  327.     use_text_font();
  328.  
  329.     if (style == 1) {
  330.         printf (".9  setgray\n");
  331.         printf ("%d  setlinewidth\n", text_size);
  332.         printf ("newpath\n");
  333.         printf ("%d %d moveto\n", hpos - 2, vpos + text_size/2 - 2);
  334.         printf ("(");
  335.         ps_puts(comment);
  336.         printf (" ) stringwidth rlineto\n");
  337.         printf ("stroke\n");
  338.         printf ("%d %d moveto\n", hpos, vpos);
  339.         printf ("0  setgray\n");
  340.         printf ("1 setlinewidth\n");
  341.         printf ("(");
  342.         ps_puts(comment);
  343.         printf (") show\n");
  344.     }
  345.     else if (style == 2) {
  346.         printf ("/");
  347.         ps_puts (chord_font);
  348.         printf (" findfont %d scalefont setfont\n",text_size);
  349.         printf ("%d %d moveto\n", hpos, vpos);
  350.         printf ("(");
  351.         ps_puts(comment);
  352.         printf (") show\n");
  353.         use_text_font();
  354.     }
  355.     else if (style == 3) {
  356.         printf ("newpath\n");
  357.         printf ("%d %d moveto\n",hpos + 2, vpos - 2);
  358.         printf ("(");
  359.         ps_puts(comment);
  360.         printf (") stringwidth /vdelta exch def /hdelta exch def\n");
  361.         printf ("hdelta vdelta rlineto 0 %d rlineto hdelta neg 0 rlineto closepath\n",
  362.                 text_size);
  363.         printf ("stroke\n");
  364.         printf ("%d %d moveto\n", hpos, vpos);
  365.         printf ("0  setgray\n");
  366.         printf ("(");
  367.         ps_puts(comment);
  368.         printf (") show\n");
  369.     }
  370.     
  371.     i_text = 0;
  372.     }
  373. /* --------------------------------------------------------------------------------*/
  374. void do_chorus_line()
  375.     {
  376.     printf ("1  setlinewidth\n");
  377.     printf ("newpath\n");
  378.     printf ("%d %d moveto\n", hpos - 10, start_of_chorus);
  379.     printf ("0 %d rlineto\n", -(start_of_chorus - end_of_chorus));
  380.     printf ("closepath\n");
  381.     printf ("stroke\n");
  382.     }
  383. /* --------------------------------------------------------------------------------*/
  384. void do_chord (i_text, chord)
  385. int i_text;
  386. char *chord;
  387.     {
  388.     int j;
  389.     struct chord_struct *ct_ptr;
  390.     if ((transpose != 0) && (strcmp(toupper_str(chord), NO_CHORD_STR)))
  391.         if (do_transpose (chord) != 0)
  392.             {
  393.             sprintf (mesg, "Don't know how to transpose [%s]", chord);
  394.             error (mesg);
  395.             }
  396.             
  397.     for (j= i_text; chord_line[j] != NULL; j++);
  398.         
  399.     if (j < MAXLINE)
  400.         if (strcmp(toupper_str(chord), NO_CHORD_STR)) 
  401.             {
  402.             ct_ptr = add_to_chordtab(chord);
  403.             chord_line[j] = ct_ptr->chord->chord_name;
  404.             }
  405.         else    chord_line[j] = NO_CHORD_STR;
  406.     
  407.     }
  408.  
  409. /* --------------------------------------------------------------------------------*/
  410. void print_chord_line ()
  411.     {
  412.     int i, j;        /* Counter */
  413.     
  414.     printf ("/minhpos %d def\n", hpos);
  415.  
  416.     for (j= 0; j<MAXLINE; j++)
  417.         {
  418.         if (chord_line[j] != NULL )
  419.             {
  420.             use_text_font();
  421.  
  422.             printf ("(" ); 
  423.             for (i= 0; (i<j) && (text_line[i] != '\0');
  424.                 ps_fputc (stdout,text_line[i++]));
  425.  
  426.             printf (") stringwidth  pop %d add \n", hpos);
  427.             printf ("dup minhpos lt\n");
  428.             printf ("     {pop minhpos} if\n");
  429.             printf ("dup /minhpos exch (");
  430.             ps_puts(chord_line[j]);
  431.             printf (") stringwidth pop add def\n");
  432.             printf ("%d moveto\n",vpos);
  433.  
  434.  
  435.             use_chord_font();
  436.             printf ("(");
  437.             ps_puts(chord_line[j]);
  438.             printf (") show\n");
  439.         
  440.             chord_line[j]= NULL;
  441.             }
  442.         }
  443.     }
  444.  
  445. /* --------------------------------------------------------------------------------*/
  446. void init_ps()
  447.     {
  448.     printf ("%%!PS-Adobe-1.0\n");
  449.     printf ("%%%%Title: A song\n");
  450.     printf ("%%%%Creator: Martin Leclerc & Mario Dorion\n");
  451.     printf ("%%%%Pages: (atend)\n");
  452.     printf ("%%%%BoundingBox: 5 5 605 787\n");
  453.     printf ("%%%%EndComments\n");
  454.     printf ("/inch {72 mul } def\n");
  455.  
  456.     print_re_encode();
  457.     set_chord_font();
  458.     set_text_font(text_size);
  459.     do_init_grid_ps();
  460.  
  461.     printf ("%%%%EndProlog\n");
  462.  
  463.     printf ("%%%%Page: \"%d\" %d\n",n_pages, n_pages);
  464.     printf ("%%%%BeginPageSetup\n");
  465.     if (pagination > 1)
  466.         {
  467.         printf ("gsave\n");
  468.         printf ("%f %f scale\n", scale, scale);
  469.         printf ("%f rotate\n", rotation);
  470.         }
  471.     printf ("%%%%EndPageSetup\n");
  472.  
  473.     vpos = TOP;
  474.     hpos = L_MARGIN;
  475.     n_columns=0;
  476.  
  477.     if (pagination== 4)
  478.         do_translate ( L_MARGIN, TOP+BOTTOM);
  479.     else if (pagination== 2) 
  480.         {
  481.         do_translate (0.0, -(TOP+BOTTOM+L_MARGIN/scale));
  482.         }
  483.     }
  484.  
  485.  
  486. /* --------------------------------------------------------------------------------*/
  487. void do_page_numbering(pnum)
  488. int pnum;
  489.     {
  490.     printf ("1  setlinewidth\n");
  491.     printf ("0  setgray\n");
  492.     printf ("newpath\n");
  493.     printf ("%f %f 10 sub moveto\n", L_MARGIN, BOTTOM); 
  494.     printf ("%f 0 rlineto\n", WIDTH - L_MARGIN * 2);
  495.     printf ("stroke\n");
  496.  
  497.     set_text_font(DEF_TEXT_SIZE - 2);
  498.     use_text_font();
  499.     if (page_label % 2 == left_foot_even)  /* left side */
  500.         {
  501.         printf ("1 inch %f 3 div moveto\n", BOTTOM); 
  502.         if (pagination == 2)
  503.             printf ("-500 0 rmoveto\n");
  504.         printf ("(Page %d)\n", pnum);
  505.         }
  506.     else                               /* right side */
  507.         { 
  508.         printf ("(Page %d) dup stringwidth pop\n", pnum);
  509.         printf ("%f exch sub 1 inch sub %f 3 div moveto\n",
  510.             WIDTH, BOTTOM); 
  511.         }
  512.     printf ("show\n");
  513.     }
  514. /* --------------------------------------------------------------------------------*/
  515. void do_end_of_phys_page()
  516. /* physical */
  517.     {
  518.     /*debug ("end_of_phys_page");*/
  519.  
  520.     /* restore full page mode  if necessary */
  521.     if (pagination > 1)
  522.         printf ("grestore\n");
  523.  
  524.     if (! number_logical)
  525.         {
  526.         if (number_all) 
  527.             do_page_numbering(page_label);
  528.         else if (song_pages > 1)
  529.             do_page_numbering(song_pages);
  530.         }
  531.  
  532.     printf ("showpage\n");
  533.     printf ("%%%%EndPage: \"%d\" %d\n",n_pages, n_pages);
  534.  
  535.     lpage_label += pagination-v_pages;
  536.     }
  537.  
  538. /* --------------------------------------------------------------------------------*/
  539. void do_end_of_page(force_physical)
  540. int    force_physical;
  541. /* Logical */
  542.     {
  543.  
  544.     if ((song_pages > 1) && title1_found) 
  545.         {
  546.         set_text_font(DEF_TEXT_SIZE - 2);
  547.         use_text_font();
  548.         printf ("(");
  549.         ps_puts(&title1[0]);
  550.         printf (") dup stringwidth pop 2 div\n");
  551.         printf ("%f 2 div exch sub %f 3 div moveto\n",
  552.             WIDTH, BOTTOM);
  553.         printf ("show\n");
  554.         set_text_font(text_size);
  555.         }
  556.  
  557.     if (number_logical)
  558.         {
  559.         if (number_all)
  560.             do_page_numbering(lpage_label);
  561.         else if (song_pages > 1)
  562.             do_page_numbering(song_pages);
  563.         }
  564.  
  565.     if ( in_chorus )
  566.         {
  567.         end_of_chorus = vpos;
  568.         do_chorus_line();
  569.         }
  570.  
  571.     if ((v_pages == pagination) || force_physical) 
  572.         {
  573.         do_end_of_phys_page();
  574.         v_pages = 0;
  575.         }
  576.     n_columns = 0;
  577.     min_col_vpos = TOP;
  578.     col_vpos = TOP;
  579.     }
  580.  
  581. /* --------------------------------------------------------------------------------*/
  582. void do_end_of_column()
  583.     {
  584.     if (n_columns == (max_columns-1))
  585.         {
  586.         do_end_of_page(FALSE);
  587.         do_start_of_page();
  588.         }
  589.     else
  590.         {
  591.         n_columns++;
  592.         if (vpos < min_col_vpos )
  593.             min_col_vpos = vpos;
  594.         vpos = col_vpos;
  595.         hpos = L_MARGIN + (n_columns * h_offset);
  596.         }
  597.     }
  598. /* --------------------------------------------------------------------------------*/
  599. void do_end_of_song()
  600. {
  601.     if ((! lyrics_only && ! no_grid)) 
  602.         {
  603.         if (min_col_vpos < vpos )
  604.             vpos = min_col_vpos;
  605.         draw_chords();
  606.         }
  607.     do_end_of_page(FALSE);
  608. }
  609.          
  610. /* --------------------------------------------------------------------------------*/
  611. void set_sys_def()
  612.     {
  613.     text_size= DEF_TEXT_SIZE;
  614.     chord_size= DEF_CHORD_SIZE;
  615.     grid_size = DEF_GRID_SIZE;
  616.     text_font = DEF_TEXT_FONT;
  617.     chord_font = DEF_CHORD_FONT;
  618.     text_font = DEF_TEXT_FONT;
  619.     no_grid = FALSE;
  620.     n_columns = 0;
  621.     max_columns = 1;
  622.     dummy_kcs.chord_name[0]='\0';
  623.     }
  624.  
  625. /* --------------------------------------------------------------------------------*/
  626. void set_rc_def()
  627.     {
  628.     if (rc_text_size != 0) text_size = rc_text_size;
  629.     if (rc_chord_size != 0) chord_size =  rc_chord_size;
  630.     if (rc_grid_size != 0) grid_size =  rc_grid_size;
  631.     if (rc_no_grid != 0) no_grid =  rc_no_grid;
  632.     if (rc_text_font != NULL) text_font =  rc_text_font;
  633.     if (rc_chord_font != NULL) chord_font =  rc_chord_font;
  634.     }
  635.  
  636. /* --------------------------------------------------------------------------------*/
  637. void set_rt_def()
  638.     {
  639.     if (rt_text_size != 0) text_size = rt_text_size;
  640.     if (rt_chord_size != 0) chord_size =  rt_chord_size;
  641.     if (rt_grid_size != 0) grid_size =  rt_grid_size;
  642.     if (rt_no_grid != 0) no_grid =  rt_no_grid;
  643.     if (rt_text_font != NULL) text_font =  rt_text_font;
  644.     if (rt_chord_font != NULL) chord_font =  rt_chord_font;
  645.     }
  646.  
  647. /* --------------------------------------------------------------------------------*/
  648. void init_values()
  649.     {
  650.     set_sys_def();
  651.     set_rc_def();
  652.     set_rt_def();
  653.     }
  654.  
  655. /* --------------------------------------------------------------------------------*/
  656. void do_new_song()
  657.     {
  658.     do_end_of_song();
  659.     nb_chord= first_ptr= 0;
  660.     song_pages = 0;
  661.     in_tab = FALSE;
  662.     strcpy (title1, "");
  663.     do_start_of_page();
  664.  
  665.     /* reset default */
  666.     init_values();
  667.     clean_known_chords();
  668.     clean_chordtab();
  669.  
  670.     set_text_font(text_size);
  671.     }
  672. /* --------------------------------------------------------------------------------*/
  673. void advance(amount)
  674. int amount;
  675.     {
  676.     vpos = vpos - amount;     /* Affect text positionning ! */
  677.     if (vpos < BOTTOM )
  678.         {
  679.         /* do_end_of_page(FALSE); */
  680.         do_end_of_column();
  681.         /* do_start_of_page(); */
  682.         }
  683.     }
  684.  
  685. /* --------------------------------------------------------------------------------*/
  686. void print_text_line()
  687.     {
  688.     int i;
  689.  
  690.     text_line[i_text] = '\0';
  691.  
  692.     for (i= 0; text_line[i] == ' '; i++);
  693.  
  694.     if (!((auto_space || in_tab)  && !has_chord))
  695.         {
  696.         advance(blank_space);
  697.         blank_space = 0;
  698.         advance (chord_size + 1);
  699.  
  700.         if ( ( text_line[i] != '\0' )
  701.           && ( vpos - text_size <= BOTTOM))
  702.             advance (text_size);
  703.  
  704.         if (need_soc)
  705.             {
  706.             start_of_chorus = vpos + chord_size;
  707.             need_soc = FALSE;
  708.             }
  709.         if ((! lyrics_only) && has_chord)
  710.             print_chord_line();
  711.         }
  712.  
  713.     if ( text_line[i] == '\0')
  714.         {
  715.         blank_space += text_size - 2;
  716.         }
  717.     else
  718.         {
  719.         advance (blank_space);
  720.         blank_space = 0;
  721.         advance (text_size - 1);
  722.         if (need_soc)
  723.             {
  724.             start_of_chorus = vpos + text_size;
  725.             need_soc = FALSE;
  726.             }
  727.         use_text_font();
  728.         printf ("%d %d moveto\n", hpos, vpos);
  729.         printf ("(");
  730.         ps_puts(&text_line[0]);
  731.         printf (") show\n");
  732.         }
  733.  
  734.     i_text = 0;
  735.     i_text_ov = FALSE;
  736.     /* hpos = L_MARGIN; */
  737.     has_chord = FALSE;
  738.     }
  739.  
  740. /* --------------------------------------------------------------------------------*/
  741. void do_title(title)
  742. char    *title;
  743.     {
  744.  
  745.     set_text_font (text_size+5);
  746.     use_text_font();
  747.     printf ("(");
  748.     ps_puts(title);
  749.     printf (") dup stringwidth pop 2 div\n");
  750.     printf ("%f 2 div exch sub %d moveto\n", WIDTH, vpos);
  751.     printf ("show\n");
  752.     vpos = vpos - text_size - 5;
  753.     /* skip blanks */
  754.     while ( *title == ' ') title++;
  755.  
  756.     strcpy (&title1[0], title);
  757.     title1_found = TRUE;
  758.     set_text_font (text_size);
  759.     if (do_toc && song_pages == 1)    /* generate index entry */
  760.         add_title_to_toc(title, number_logical ? lpage_label : page_label);
  761.     }
  762. /* --------------------------------------------------------------------------------*/
  763. void do_subtitle(sub_title)
  764. char    *sub_title;
  765.     {
  766.     use_text_font();
  767.     printf ("(");
  768.     ps_puts(sub_title);
  769.     printf (") dup stringwidth pop 2 div\n");
  770.     printf ("%f 2 div exch sub %d moveto\n", WIDTH , vpos);
  771.     printf ("show\n");
  772.     vpos = vpos - text_size ;
  773.     if (do_toc && song_pages == 1)
  774.         add_subtitle_to_toc(sub_title);
  775.     }
  776.     
  777.  
  778. /* --------------------------------------------------------------------------------*/
  779. void do_directive(directive)
  780. char *directive;
  781.     {
  782.     int   i;
  783.     char  *command, *comment;
  784.  
  785.     command= tolower_str(strtok(directive, ": "));
  786.  
  787.     if (!strcmp(command, "start_of_chorus") || !strcmp(command,"soc"))
  788.         {
  789.         /* start_of_chorus = vpos - blank_space; */
  790.         need_soc = TRUE;
  791.         in_chorus = TRUE;
  792.         }
  793.     else if (!strcmp (command, "end_of_chorus") || !strcmp(command, "eoc"))
  794.         {
  795.         if ( in_chorus )
  796.             {
  797.             end_of_chorus = vpos;
  798.             do_chorus_line();
  799.             in_chorus = FALSE;
  800.             }
  801.         else
  802.             error ("Not in a chorus.");
  803.         }
  804.     else if (!strcmp (command, "textfont") || !strcmp (command, "tf"))
  805.         {
  806.         if (in_chordrc) rc_text_font = strtok(NULL, ": ");
  807.         else           text_font = strtok(NULL, ": ");
  808.         }
  809.     else if (!strcmp (command, "chordfont") || !strcmp (command, "cf"))
  810.         {
  811.         if (in_chordrc) rc_chord_font = strtok(NULL, ": ");
  812.         else
  813.             {
  814.             chord_font = strtok(NULL, ": ");
  815.             set_chord_font();
  816.             }
  817.         }
  818.     else if (!strcmp (command, "chordsize") || !strcmp (command, "cs"))
  819.         {
  820.         i = atoi(strtok(NULL, ": "));
  821.         if ( i == 0 )
  822.             error ("invalid value for chord_size");
  823.         else
  824.             if (in_chordrc) rc_chord_size = i;
  825.             else
  826.                 {
  827.                 chord_size = i;
  828.                 set_chord_font();
  829.                 }
  830.         }
  831.     else if (!strcmp (command, "textsize") || !strcmp (command, "ts"))
  832.         {
  833.         i = atoi(strtok(NULL, ": "));
  834.         if ( i == 0 )
  835.             error ("invalid value for text_size");
  836.         else
  837.             if (in_chordrc) rc_text_size = i;
  838.             else
  839.                 {
  840.                 text_size = i;
  841.                 set_text_font (text_size);
  842.                 }
  843.         }
  844.     else if (!strcmp (command, "comment") || !strcmp (command, "c"))
  845.         {
  846.         comment = strtok(NULL, "\0");
  847.         do_comment(comment, 1);
  848.         }
  849.     else if (!strcmp (command, "comment_italic") || !strcmp (command, "ci"))
  850.         {
  851.         comment = strtok(NULL, "\0");
  852.         do_comment(comment, 2);
  853.         }
  854.     else if (!strcmp (command, "comment_box") || !strcmp (command, "cb"))
  855.         {
  856.         comment = strtok(NULL, "\0");
  857.         do_comment(comment, 3);
  858.         }
  859.     else if (!strcmp(command, "new_song") || !strcmp(command,"ns"))
  860.         {
  861.         do_new_song();
  862.         }
  863.     else if (!strcmp(command, "title") || !strcmp(command,"t"))
  864.         {
  865.         do_title(strtok(NULL, "\0"));
  866.         }  
  867.     else if (!strcmp(command, "subtitle") || !strcmp(command,"st"))
  868.         {
  869.         do_subtitle(strtok(NULL, "\0"));
  870.         }  
  871.     else if (!strcmp(command, "define") || !strcmp(command,"d"))
  872.         {
  873.         do_define_chord();
  874.         }  
  875.     else if (!strcmp(command, "no_grid") || !strcmp(command,"ng"))
  876.         {
  877.         if (in_chordrc) rc_no_grid = TRUE;
  878.         else            no_grid = TRUE;
  879.         }
  880.     else if (!strcmp(command, "grid") || !strcmp(command,"g"))
  881.         {
  882.         if (in_chordrc) rc_no_grid = FALSE;
  883.         else            no_grid = FALSE;
  884.         }
  885.     else if (!strcmp(command, "new_page") || !strcmp(command,"np"))
  886.         {
  887.         do_end_of_page(FALSE);
  888.         do_start_of_page();
  889.         }
  890.     else if (!strcmp(command, "start_of_tab") || !strcmp(command,"sot"))
  891.         {
  892.         if ( in_tab )
  893.             error ("Already in a tablature !");
  894.         else
  895.             in_tab = TRUE;
  896.         }
  897.     else if (!strcmp(command, "end_of_tab") || !strcmp(command,"eot"))
  898.         {
  899.         if (! in_tab )
  900.             error ("Not in a tablature !")    ;
  901.         else
  902.             in_tab = FALSE;
  903.         }
  904.     else if (!strcmp(command, "column_break") || !strcmp(command,"colb"))
  905.         {
  906.         do_end_of_column();
  907.         }
  908.     else if (!strcmp(command, "columns") || !strcmp(command,"col"))
  909.         {
  910.         i = atoi(strtok(NULL, ": "));
  911.         if ( i <= 1 )
  912.             error ("invalid value for number of columns");
  913.         else
  914.             {
  915.             max_columns = i;
  916.             n_columns = 0;
  917.             col_vpos = vpos;
  918.             h_offset = (int)(( WIDTH - L_MARGIN) / max_columns);
  919.             }
  920.         }
  921.     else if (!strcmp(command, "new_physical_page") || !strcmp(command,"npp"))
  922.         {
  923.         do_end_of_page(TRUE);
  924.         do_start_of_page();
  925.         }
  926.     else
  927.         {
  928.         sprintf (mesg, "Invalid Directive : [%s]", command);
  929.         error(mesg);
  930.         has_directive = FALSE;
  931.         }
  932.     }
  933.  
  934. /* --------------------------------------------------------------------------------*/
  935. void put_in_string(array, p_index, c, max_index, p_ov_flag)
  936. char array[MAXLINE];
  937. int *p_index;
  938. int c;
  939. int max_index;
  940. int *p_ov_flag;
  941.     {
  942.     if (*p_index < max_index)
  943.         array[(*p_index)++] = (char) c;
  944.     else
  945.         {
  946.         if (!*p_ov_flag)
  947.             {
  948.             error ("Buffer Overflow");
  949.             *p_ov_flag = TRUE;
  950.             }
  951.         }
  952.     }
  953. /* --------------------------------------------------------------------------------*/
  954. void do_eol()
  955.     {
  956.     if ( in_directive )
  957.         error ("Line ends while in a directive !"); 
  958.     if ( in_chord)
  959.         error ("Line ends while in a chord !"); 
  960.     if (has_directive == FALSE)
  961.         {
  962.         if (in_chordrc) 
  963.             {
  964.             if (strcmp(text_line, "\0"))
  965.                 error("line is NOT a directive");
  966.             }
  967.         else if (! in_tab || ! lyrics_only)
  968.             print_text_line();
  969.             }
  970.     else
  971.         has_directive = FALSE;
  972.     n_lines++;
  973.     i_input = 0;
  974.     in_directive = FALSE;
  975.     in_chord = FALSE;
  976.     i_text = 0;
  977.     i_text_ov = FALSE;
  978.     text_line[0]='\0';
  979.     }
  980. /* --------------------------------------------------------------------------------*/
  981. void process_file(source_fd)
  982. FILE *source_fd;
  983.     {
  984.     /*debug("start of process_file");*/
  985.  
  986.     n_lines = 0;
  987.  
  988.     while ( (c= getc(source_fd)) != EOF)
  989.         {
  990.         i_input++;
  991.         switch ((char)c) {
  992.  
  993.         case '[':
  994.             if (! in_tab) {
  995.                 if ( in_chord )
  996.                     error("Opening a chord within a chord!");
  997.                 else
  998.                     in_chord = TRUE;
  999.                 i_chord = 0;
  1000.             }
  1001.             else put_in_string(text_line, &i_text, c, MAXLINE, &i_text_ov);
  1002.             break;
  1003.         
  1004.         case ']':
  1005.             if (! in_tab) {
  1006.                 if ( in_chord )
  1007.                     {
  1008.                     in_chord = FALSE;
  1009.                     chord[i_chord]= '\0';
  1010.                     do_chord(i_text, &chord[0]);
  1011.                     has_chord = TRUE; 
  1012.                     i_chord = 0;
  1013.                     i_chord_ov = FALSE;
  1014.                     }
  1015.                 else
  1016.                     error("']' found with no matching '['");
  1017.             }
  1018.             else put_in_string(text_line, &i_text, c, MAXLINE, &i_text_ov);
  1019.             break;
  1020.         
  1021.         case '{':
  1022.             in_directive = TRUE;
  1023.             i_directive = 0;
  1024.             has_directive = TRUE;
  1025.             break;
  1026.  
  1027.         case '}':
  1028.             if ( in_directive)
  1029.                 {
  1030.                 in_directive = FALSE;
  1031.                 directive[i_directive]= '\0';
  1032.                 for (; (c= getc(source_fd)) != '\n'; );
  1033.                 i_input = 0;
  1034.                 do_directive(&directive[0]);
  1035.                 has_directive = FALSE;
  1036.                 n_lines++;
  1037.                 i_directive = 0;
  1038.                 i_directive_ov = FALSE;
  1039.                 }
  1040.             else
  1041.                 error("'}' found with no matching '{'");
  1042.             break;
  1043.  
  1044.         case '\n':
  1045.             do_eol();
  1046.             break;
  1047.         case '(':
  1048.         case ')':
  1049.             if (in_directive)
  1050.                 {
  1051.                 put_in_string(directive, &i_directive, c, MAXTOKEN, &i_directive_ov);
  1052.                 break;
  1053.                 }
  1054.             else if (in_chord) /* allow parens in chord names */
  1055.                 {
  1056.                 put_in_string (chord, &i_chord, c, CHORD_NAME_SZ, &i_chord_ov);
  1057.                 break;
  1058.                 }
  1059.             else
  1060.                 {
  1061.                 put_in_string (text_line, &i_text, c, MAXLINE, &i_text_ov);
  1062.                 break;
  1063.                 }
  1064.     
  1065.     /* This case HAS to be the last before the default statement !!! */
  1066.  
  1067.         case '#':
  1068.             if (i_input == 1)
  1069.                 {
  1070.                 for (; (c= getc(source_fd)) != '\n'; );
  1071.                 n_lines++;
  1072.                 i_input = 0;
  1073.                 break;
  1074.                 }
  1075.  
  1076.         default :
  1077.             if (in_chord )
  1078.                 {
  1079.                 if ( c != ' ' )
  1080.                     {
  1081.                     put_in_string(chord, &i_chord, c, CHORD_NAME_SZ, &i_chord_ov);
  1082.                     }
  1083.                 }
  1084.             else if (in_directive)
  1085.                 {
  1086.                 put_in_string(directive, &i_directive, c, MAXTOKEN, &i_directive_ov);
  1087.                 }
  1088.             else
  1089.                 {
  1090.                 put_in_string(text_line, &i_text, c, MAXLINE, &i_text_ov);
  1091.                 }
  1092.             break;
  1093.             }
  1094.         }
  1095.     if (i_input != 0 ) do_eol();
  1096.     if (! in_chordrc) print_text_line();
  1097.     }
  1098.  
  1099. /* --------------------------------------------------------------------------------*/
  1100. /* read the file $HOME/.chordrc as a set of directive */
  1101. void read_chordrc()
  1102.     {
  1103.     char chordrc[MAXTOKEN];
  1104.     FILE *chordrc_fd;
  1105.     int n_lines_save;
  1106.  
  1107.     strcpy (chordrc, getenv ("HOME"));
  1108.     strcat (chordrc,"/.chordrc\0");
  1109.     current_file = chordrc;
  1110.     chordrc_fd = fopen (chordrc, "r");
  1111.     if (chordrc_fd != NULL)
  1112.         {
  1113.         n_lines_save= n_lines;
  1114.         n_lines= 1;
  1115.         in_chordrc = TRUE;
  1116.         process_file(chordrc_fd);
  1117.         in_chordrc = FALSE;
  1118.         n_lines= n_lines_save;
  1119.         fclose(chordrc_fd);
  1120.         }
  1121.     current_file = &source[0];
  1122.     first_time_in_chordrc = FALSE;
  1123.     }
  1124.  
  1125.  
  1126. /* --------------------------------------------------------------------------------*/
  1127. main(argc, argv)
  1128. int argc;
  1129. char **argv;
  1130.     {
  1131.     int c,i;
  1132.  
  1133.     mesg = mesgbuf;
  1134. /* Option Parsing */
  1135.  
  1136.     command_name= argv[0];
  1137.  
  1138.     while ((c = getopt(argc, argv, "aAc:C:dDgGhilLno:p:s:t:T:Vx:24")) != -1)
  1139.         switch (c) {
  1140.  
  1141.         case 'd':
  1142.             dump_only = TRUE;
  1143.             break;
  1144.  
  1145.         case 'D':
  1146.             dump_only = TRUE;
  1147.             postscript_dump = TRUE;
  1148.             break;
  1149.  
  1150.         case 'c':
  1151.             i = atoi (optarg);
  1152.             if ( i == 0 )
  1153.                 error_rt("invalid value for chord_size");
  1154.             else
  1155.                 rt_chord_size = i;
  1156.             break;
  1157.  
  1158.         case 'C':
  1159.             rt_chord_font = optarg;
  1160.             break;
  1161.  
  1162.         case 'h':
  1163.             do_help(argv[0]);
  1164.             break;
  1165.  
  1166.         case 't':
  1167.             i = atoi (optarg);
  1168.             if ( i == 0 )
  1169.                 error_rt("invalid value for text_size");
  1170.             else
  1171.                 rt_text_size= i;
  1172.             break;
  1173.  
  1174.         case 'T':
  1175.             rt_text_font = optarg;
  1176.             break;
  1177.  
  1178.         case 'x':
  1179.             i = atoi (optarg);
  1180.             if ( i == 0 )
  1181.                 error_rt("invalid value for transposition");
  1182.             else
  1183.                 transpose = i;
  1184.             break;
  1185.  
  1186.         case 's':
  1187.             i = atoi (optarg);
  1188.             if ( i == 0 )
  1189.                 error_rt("invalid value for grid_size");
  1190.             else
  1191.                 rt_grid_size = i;
  1192.             break;
  1193.  
  1194.         case 'g':
  1195.             no_easy_grids = TRUE;
  1196.             break;
  1197.  
  1198.         case 'G':
  1199.             rt_no_grid = TRUE;
  1200.             break;
  1201.  
  1202.         case 'l':
  1203.             lyrics_only= TRUE;
  1204.             break;
  1205.  
  1206.         case 'n':
  1207.             number_logical = TRUE;
  1208.             break;
  1209.  
  1210.         case 'V':
  1211.             print_version();
  1212.             exit(0);
  1213.             break;
  1214.  
  1215.         case '2':
  1216.             pagination= 2;
  1217.             scale = (WIDTH - L_MARGIN)/(TOP + BOTTOM);
  1218.             rotation= 90.0;
  1219.             break;
  1220.  
  1221.         case '4':
  1222.             pagination= 4;
  1223.             scale = ((WIDTH - L_MARGIN)/2.1)/(WIDTH - L_MARGIN);
  1224.             break;
  1225.  
  1226.         case 'i': /* generate in index */
  1227.  
  1228.             do_toc= TRUE;
  1229.             number_all = TRUE;
  1230.             break;
  1231.  
  1232.         case 'a':
  1233.             auto_space= TRUE;
  1234.             break;
  1235.  
  1236.         case 'p':
  1237.             i = atoi (optarg);
  1238.             if ( i == 0 )
  1239.                 error_rt("invalid value for initial page number");
  1240.             else {
  1241.                 page_label = i;
  1242.                 number_all = TRUE;
  1243.             }
  1244.             break;
  1245.  
  1246.         case 'L':
  1247.             left_foot_even = 0;
  1248.             number_all= TRUE;
  1249.             break;
  1250.  
  1251.             case 'o':
  1252.                     if ( freopen(optarg, "w", stdout) == NULL)
  1253.                             {
  1254.                             fprintf (stderr, "Unable to open \"%s\" for output\n", optarg);
  1255.                             exit(1);
  1256.                             }
  1257.                     break;
  1258.  
  1259.         case 'A':
  1260.             do_about();
  1261.             exit(0);
  1262.             break;
  1263.  
  1264.         case '?':
  1265.             do_help(argv[0]);
  1266.             break;
  1267.         }
  1268.  
  1269. /* Is there anything? */
  1270.  
  1271.     if (argc == 1)
  1272.         do_help(argv[0]);
  1273.  
  1274. /* Is there input? */
  1275.  
  1276.     if ((optind == argc) && isatty(0) && !dump_only)
  1277.     {
  1278.         fprintf (stderr, "Error: CHORD does not expect you to type the song on your keyboard.\n");
  1279.         fprintf (stderr, "Please either specify an input filename on the command line\n");
  1280.         fprintf (stderr, "or have the input redirected or piped in.\n");
  1281.         fprintf (stderr, "Exemples:\n");
  1282.         fprintf (stderr, "   %% chord my_song.cho > myfile.ps\n");
  1283.         fprintf (stderr, "   %% chord < mysong.cho > myfile.ps\n");
  1284.         fprintf (stderr, "Do \"chord -h\" to learn about CHORD's options\n");
  1285.         exit(1);
  1286.     }
  1287.  
  1288. /* Is there output? */
  1289.  
  1290.      if (isatty(1) && (!dump_only || postscript_dump))  /* 1 == stdout  */
  1291.     {
  1292.         fprintf (stderr, "Error: CHORD will not send PostScript to your terminal.\n");
  1293.         fprintf (stderr, "Please either redirect (>) or pipe (|) the output.\n");
  1294.         fprintf (stderr, "Exemples:\n");
  1295.         fprintf (stderr, "   %% chord my_song.cho > myfile.ps\n");
  1296.         fprintf (stderr, "   %% chord my_song.cho | lpr\n");
  1297.         exit(1);
  1298.     }
  1299.  
  1300.  
  1301. /* File Processing */
  1302.  
  1303.     if (dump_only) 
  1304.     {
  1305.         dump_chords(postscript_dump);
  1306.         exit(0);
  1307.     }
  1308.  
  1309.     init_known_chords();
  1310.     read_chordrc();
  1311.     init_values();
  1312.     init_ps();
  1313.  
  1314.     chord_inc = chord_size * 1.5;
  1315.  
  1316.     for ( ; optind < argc; optind++ )
  1317.         {
  1318.         strcpy(source, argv[optind]);
  1319.         read_input_file(source, source_fd);
  1320.         if (optind < argc - 1)
  1321.             do_new_song();
  1322.         }
  1323.  
  1324.  
  1325.     do_end_of_song();
  1326.      
  1327.     if (do_toc)    /* generate index  page */
  1328.         {
  1329.         build_ps_toc();
  1330.         do_end_of_page(FALSE);
  1331.         }
  1332.  
  1333.     if (v_pages != 0)
  1334.         {
  1335.         do_end_of_phys_page();
  1336.         }
  1337.  
  1338.  
  1339.     printf ("%%%%Trailer\n");
  1340.     printf ("%%%%Pages: %d 1\n", n_pages);
  1341.     printf ("%%%%EOF\n");
  1342.  
  1343.     exit (0);    
  1344.     return(0);
  1345.     }
  1346.