static char SccsId[] = "@(#)chord.c	3.6\t Mar. 1995";
static char copyright[] = "Copyright 1991-1995 by Martin Leclerc & Mario Dorion";


#include "chord.h"

static FILE *source_fd;

char
	text_line[MAXLINE],	/* Lyrics Buffer */
	chord[MAXTOKEN],	/* Buffer for the name of the chord */
	title1[MAXLINE];	/* Holds the first title line */

char
	source[MAXTOKEN],
	directive[MAXLINE];	/* Buffer for the directive */

char
	i_input;		/* Input line pointer */

char
	mesgbuf[MAXTOKEN],
	*mesg,
	*text_font, *rt_text_font, *rc_text_font, 	/* font for text */
	*chord_font, *rt_chord_font, *rc_chord_font, 	/* font for chord */
	*mono_font = MONOSPACED_FONT,	/* non-proprotional font for tabs */
	*current_file,
	*chord_line[MAXLINE],
	*command_name;

int
	c,			/* Current character in input file */
	i_chord,		/* Index to 'chord' */
	i_directive,		/* Index to 'directive' */
	i_text, 		/* Index to 'text_line' */
	in_chord,		/* Booleans indicating parsing status */
	left_foot_even = -1,	 /* 0 for even page numbers on the right */
				/* 1 for even page numbers on the left */
	no_grid, rt_no_grid, rc_no_grid,
	page_label = 1,		/* physical page number */
	lpage_label = 1,	/* logical page number */
	i_chord_ov,		/* Overflow Booleans */
	pagination = 1,		/* virtual pages per physical pages */
	transpose = 0,		/* transposition value */
	vpos,			/* Current PostScript position, in points */
	col_vpos,		/* Beginning height of column, in points */
	min_col_vpos = TOP,	/* lowest colums ending */
	hpos,
	h_offset = 0, 		/* horizontal offset for multi-col output */
	start_of_chorus,	/* Vertical positions of the chorus */
	end_of_chorus,
	chord_size, rt_chord_size, rc_chord_size,  	/* font size for 'chord_font' */
	cur_text_size = 0,
	text_size, rt_text_size, rc_text_size,  	/* font size for 'text_font' */
	grid_size, rt_grid_size, rc_grid_size,
	n_pages = 1,		/* total physical page counter */
	v_pages = 1,		/* virtual pages */
	n_lines = 1,		/* line number in input file */
	max_columns = 1,	/* number of columns */
	n_columns = 0,		/* counter of columns */
	song_pages = 1,		/* song page counter */
	blank_space = 0;	/* consecutive blank line counter */

int 				/* BOOLEANS */
	number_all = FALSE,	/* number the first page (set with -p 1) */
	lyrics_only = FALSE,
	dump_only = FALSE,
	in_tab = FALSE,
	postscript_dump = FALSE,
	auto_space = FALSE,	/* applies lyrics_only when no chords */
	need_soc = FALSE,
	do_toc = FALSE,
	no_easy_grids = FALSE,
	i_directive_ov = FALSE,
	i_text_ov = FALSE,
	in_directive = FALSE,
	in_chordrc = FALSE,
	first_time_in_chordrc = TRUE,
	in_chorus = FALSE,
	has_directive = FALSE,
	has_chord = FALSE,
	title1_found = FALSE,
	number_logical = FALSE,
	debug_mode = FALSE;

float
	chord_inc,
	scale = 1.0,		/* Current scale factor */
	rotation = 0.0,		/* Current rotation */
	page_ratio = ((TOP+BOTTOM)/WIDTH);

extern int nb_chord, first_ptr;
extern struct chord_struct *so_chordtab;
extern struct toc_struct *so_toc ;

extern char *optarg;
extern int optind, opterr;


/* --------------------------------------------------------------------------------*/
void ps_fputc(fd, c)
FILE *fd;
int c;
        {
        if (c >128)
		{
               	fprintf (fd, "\\%o", c);
		}
        else 
		switch ((char)c)
		{
		case ')' :
               		fprintf (fd, "\\%c", c); break;
		case '(' :
               		fprintf (fd, "\\%c", c); break;
		case '\\' :
			fprintf (fd, "\\\\", c); break;
		default:
			fprintf (fd, "%c",c);
		}
        }
/* --------------------------------------------------------------------------------*/
void ps_fputs(fd, string)
FILE *fd;
char *string;
        {
        int i;

	/* sprintf (mesg, "ps_fputs:%s ",string); debug(mesg); */

        for (i= 0; string[i] != '\0'; i++)
                ps_fputc (fd, string[i]);

        }


/* --------------------------------------------------------------------------------*/
void ps_puts(string)
char *string;
	{
	ps_fputs(stdout, string);
	}
/* --------------------------------------------------------------------------------*/
void set_text_font(size)
int size;
	{
#define	MONO_SIZE_DECR	2	/* TABsize is smaller by this nb of points */
	if (( size != cur_text_size))
		{
		printf ("/TEXT_FONT { /%s findfont %d scalefont } def\n", text_font, size);
		re_encode (text_font);
		printf ("/MONO_FONT { /%s findfont %d scalefont } def\n",
			mono_font, size - MONO_SIZE_DECR);
		re_encode (mono_font);
		cur_text_size= size;
		/* sprintf(mesg, "Changing text size to %d", size); debug (mesg); */
		}
#undef MONO_SIZE_DECR
	}

/* --------------------------------------------------------------------------------*/
void use_text_font()
	{
	if (! in_tab) printf ("TEXT_FONT setfont\n");
	else printf ("MONO_FONT setfont\n");
	}
/* --------------------------------------------------------------------------------*/
void use_mono_font()
	{
	printf ("MONO_FONT setfont\n");
	}
/* --------------------------------------------------------------------------------*/
void do_translate(vert, horiz)
float vert, horiz;
	{
	printf ("%f %f translate\n", vert , horiz );
	debug ("changing translation");
	}
/* --------------------------------------------------------------------------------*/
void do_start_of_page()
/*logical page ! */
	{
	v_pages++;
	lpage_label++;

	if (v_pages == 1)
		{
		n_pages++;
		page_label++;
		printf ("%%%%Page: \"%d\" %d\n",n_pages, n_pages);
		printf ("%%%%BeginPageSetup\n");
		if (pagination > 1)
			{
			printf ("gsave\n");
			printf ("%f %f scale\n", scale, scale);
			printf ("%f rotate\n",rotation);
			}
		printf ("%%%%EndPageSetup\n");
		}

	if (pagination== 4)
		{
		if (v_pages== 1) do_translate(L_MARGIN, (TOP+BOTTOM)*1.05);
		else if (v_pages== 2) do_translate(WIDTH-L_MARGIN, 0.0);
		else if (v_pages== 3) do_translate(-(WIDTH-L_MARGIN), -TOP*1.05);
		else if (v_pages== 4) do_translate(WIDTH-L_MARGIN, 0.0);
		}

	if (pagination== 2)
		if (v_pages == 1)
			{
			do_translate (0.0, -(TOP+BOTTOM+L_MARGIN/scale));
			}
		else if (v_pages == 2)
			do_translate(WIDTH, 0.0);

	vpos = TOP;
	min_col_vpos = TOP;
	hpos= L_MARGIN;
	n_columns = 0;
	song_pages++;
	set_text_font(text_size); /*28/4/94 ML */
	if ( in_chorus )
		{
		start_of_chorus = vpos;
		}
	}

/* --------------------------------------------------------------------------------*/
void use_chord_font()
	{
	printf ("CHORD_FONT setfont\n");
	}

/* --------------------------------------------------------------------------------*/
void set_chord_font()
	{
	printf ("/CHORD_FONT { /%s findfont %d scalefont } def\n", chord_font, chord_size);
	re_encode (chord_font);
	}

/* --------------------------------------------------------------------------------*/
void do_help (command) 
char *command;
	{
	fprintf (stderr, "Usage: %s [options] file [file ...]\n", command);
	fprintf (stderr, "Options:\n");
	fprintf (stderr, "	-A                 : About CHORD...\n");
	fprintf (stderr, "	-a                 : Automatic single space lines without chords\n");
	fprintf (stderr, "	-c n               : Set chord size [9]\n");
	fprintf (stderr, "	-C postscript_font : Set chord font\n");
	fprintf (stderr, "	-D                 : Dumps chords definitions (PostScript)\n");
	fprintf (stderr, "	-d                 : Dumps chords definitions (Text)\n");
	fprintf (stderr, "	-G                 : Disable printing of chord grids\n");
	fprintf (stderr, "	-g                 : Don't print grids for builtin \"easy\" chords.\n");
	fprintf (stderr, "	-h                 : This message\n");
	fprintf (stderr, "	-i                 : Generates a table of contents\n");
	fprintf (stderr, "	-L                 : Even pages numbers on left\n");
	fprintf (stderr, "	-l                 : Only print lyrics\n");
	fprintf (stderr, "	-n                 : Number logical pages, not physical\n");
	fprintf (stderr, "	-o filename        : Saves the output to file\n");
	fprintf (stderr, "	-p n               : Starting page number [1]\n");
	fprintf (stderr, "	-s n               : Set chord grid size [30]\n");
	fprintf (stderr, "	-t n               : Set text size [12]\n");
	fprintf (stderr, "	-T postscript_font : Set text font\n");
	fprintf (stderr, "	-V                 : Print version and patchlevel\n");
	fprintf (stderr, "	-x n               : Transpose by 'n' half-tones\n");
	fprintf (stderr, "	-2                 : 2 pages per sheet\n");
	fprintf (stderr, "	-4                 : 4 pages per sheet\n");

	exit(0);
	}

/* --------------------------------------------------------------------------------*/
void do_about ()
	{
	printf("CHORD: A lyrics and chords formatting program.\n");
	printf("===== \n");
	printf("\n");;
	printf("CHORD will read an ASCII file containing the lyrics of one or many\n");
	printf("songs plus chord information. CHORD will then generate a photo-ready,\n");
	printf("professional looking, impress-your-friends sheet-music suitable for printing\n");
	printf("on your nearest PostScript printer.\n");
	printf("\n");
	printf("To learn more about CHORD, look for the man page or do \"chord -h\" for\n");
	printf("the list of options.\n");
	printf("\n");
	printf("			--0--\n");
	printf("\n");
	printf("Copyright (C) 1991-1993 by Martin Leclerc & Mario Dorion\n");
	printf("\n");
	printf("This program is free software; you can redistribute it and/or modify\n");
	printf("it under the terms of the GNU General Public License as published by\n");
	printf("the Free Software Foundation; either version 2 of the License, or\n");
	printf("(at your option) any later version.\n");
	printf("\n");
	printf("This program is distributed in the hope that it will be useful,\n");
	printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
	printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
	printf("GNU General Public License for more details.\n");
	printf("\n");
	printf("You should have received a copy of the GNU General Public License\n");
	printf("along with this program; if not, write to the Free Software\n");
	printf("Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n");
	printf("\n");
	printf("Send all questions, comments and bug reports to the original authors:\n");

		printf("	Martin.Leclerc@Sun.COM and Mario.Dorion@Sun.COM\n");
	printf("\n");
	}

/* --------------------------------------------------------------------------------*/
void do_comment(comment, style)
char 	*comment;
int	style;
	{
	if (comment == NULL)
		{
		error ("Null comment.");
		return;
		}
	for (; *comment == ' '; comment++); /* strip leading blanks */
	advance(blank_space);
	blank_space = 0;
	advance(text_size);
	text_line[i_text] = '\0';
	use_text_font();

	if (style == 1) {
		printf (".9  setgray\n");
		printf ("%d  setlinewidth\n", text_size);
		printf ("newpath\n");
		printf ("%d %d moveto\n", hpos - 2, vpos + text_size/2 - 2);
		printf ("(");
		ps_puts(comment);
		printf (" ) stringwidth rlineto\n");
		printf ("stroke\n");
		printf ("%d %d moveto\n", hpos, vpos);
		printf ("0  setgray\n");
		printf ("1 setlinewidth\n");
		printf ("(");
		ps_puts(comment);
		printf (") show\n");
	}
	else if (style == 2) {
		printf ("/");
		ps_puts (chord_font);
		printf (" findfont %d scalefont setfont\n",text_size);
		printf ("%d %d moveto\n", hpos, vpos);
		printf ("(");
		ps_puts(comment);
		printf (") show\n");
		use_text_font();
	}
	else if (style == 3) {
		printf ("newpath\n");
		printf ("%d %d moveto\n",hpos + 2, vpos - 2);
		printf ("(");
		ps_puts(comment);
		printf (") stringwidth /vdelta exch def /hdelta exch def\n");
		printf ("hdelta vdelta rlineto 0 %d rlineto hdelta neg 0 rlineto closepath\n",
				text_size);
		printf ("stroke\n");
		printf ("%d %d moveto\n", hpos, vpos);
		printf ("0  setgray\n");
		printf ("(");
		ps_puts(comment);
		printf (") show\n");
	}
	
	i_text = 0;
	}
/* --------------------------------------------------------------------------------*/
void do_chorus_line()
	{
	printf ("1  setlinewidth\n");
	printf ("newpath\n");
	printf ("%d %d moveto\n", hpos - 10, start_of_chorus);
	printf ("0 %d rlineto\n", -(start_of_chorus - end_of_chorus));
	printf ("closepath\n");
	printf ("stroke\n");
	}
/* --------------------------------------------------------------------------------*/
void do_chord (i_text, chord)
int i_text;
char *chord;
	{
	int j;
	struct chord_struct *ct_ptr;
	if ((transpose != 0) && (strcmp(toupper_str(chord), NO_CHORD_STR)))
		if (do_transpose (chord) != 0)
			{
			sprintf (mesg, "Don't know how to transpose [%s]", chord);
			error (mesg);
			}
			
	for (j= i_text; chord_line[j] != NULL; j++);
		
	if (j < MAXLINE)
		if (strcmp(toupper_str(chord), NO_CHORD_STR)) 
			{
			ct_ptr = add_to_chordtab(chord);
			chord_line[j] = ct_ptr->chord->chord_name;
			}
		else	chord_line[j] = NO_CHORD_STR;
	
	}

/* --------------------------------------------------------------------------------*/
void print_chord_line ()
	{
	int i, j;		/* Counter */
	
	printf ("/minhpos %d def\n", hpos);

	for (j= 0; j<MAXLINE; j++)
		{
		if (chord_line[j] != NULL )
			{
			use_text_font();

			printf ("(" ); 
			for (i= 0; (i<j) && (text_line[i] != '\0');
				ps_fputc (stdout,text_line[i++]));

			printf (") stringwidth  pop %d add \n", hpos);
			printf ("dup minhpos lt\n");
			printf ("     {pop minhpos} if\n");
			printf ("dup /minhpos exch (");
			ps_puts(chord_line[j]);
			printf (") stringwidth pop add def\n");
			printf ("%d moveto\n",vpos);


			use_chord_font();
			printf ("(");
			ps_puts(chord_line[j]);
			printf (") show\n");
		
			chord_line[j]= NULL;
			}
		}
	}

/* --------------------------------------------------------------------------------*/
void init_ps()
	{
	printf ("%%!PS-Adobe-1.0\n");
	printf ("%%%%Title: A song\n");
	printf ("%%%%Creator: Martin Leclerc & Mario Dorion\n");
	printf ("%%%%Pages: (atend)\n");
	printf ("%%%%BoundingBox: 5 5 605 787\n");
	printf ("%%%%EndComments\n");
	printf ("/inch {72 mul } def\n");

	print_re_encode();
	set_chord_font();
	set_text_font(text_size);
	do_init_grid_ps();

	printf ("%%%%EndProlog\n");

	printf ("%%%%Page: \"%d\" %d\n",n_pages, n_pages);
	printf ("%%%%BeginPageSetup\n");
	if (pagination > 1)
		{
		printf ("gsave\n");
		printf ("%f %f scale\n", scale, scale);
		printf ("%f rotate\n", rotation);
		}
	printf ("%%%%EndPageSetup\n");

	vpos = TOP;
	hpos = L_MARGIN;
	n_columns=0;

	if (pagination== 4)
		do_translate ( L_MARGIN, TOP+BOTTOM);
	else if (pagination== 2) 
		{
		do_translate (0.0, -(TOP+BOTTOM+L_MARGIN/scale));
		}
	}


/* --------------------------------------------------------------------------------*/
void do_page_numbering(pnum)
int pnum;
	{
	printf ("1  setlinewidth\n");
	printf ("0  setgray\n");
	printf ("newpath\n");
	printf ("%f %f 10 sub moveto\n", L_MARGIN, BOTTOM); 
	printf ("%f 0 rlineto\n", WIDTH - L_MARGIN * 2);
	printf ("stroke\n");

	set_text_font(DEF_TEXT_SIZE - 2);
	use_text_font();
	if (page_label % 2 == left_foot_even)  /* left side */
		{
		printf ("1 inch %f 3 div moveto\n", BOTTOM); 
		if (pagination == 2)
			printf ("-500 0 rmoveto\n");
		printf ("(Page %d)\n", pnum);
		}
	else                               /* right side */
		{ 
		printf ("(Page %d) dup stringwidth pop\n", pnum);
		printf ("%f exch sub 1 inch sub %f 3 div moveto\n",
			WIDTH, BOTTOM); 
		}
	printf ("show\n");
	}
/* --------------------------------------------------------------------------------*/
void do_end_of_phys_page()
/* physical */
	{
	/*debug ("end_of_phys_page");*/

	/* restore full page mode  if necessary */
	if (pagination > 1)
		printf ("grestore\n");

	if (! number_logical)
		{
		if (number_all) 
			do_page_numbering(page_label);
		else if (song_pages > 1)
			do_page_numbering(song_pages);
		}

	printf ("showpage\n");
	printf ("%%%%EndPage: \"%d\" %d\n",n_pages, n_pages);

	lpage_label += pagination-v_pages;
	}

/* --------------------------------------------------------------------------------*/
void do_end_of_page(force_physical)
int	force_physical;
/* Logical */
	{

	if ((song_pages > 1) && title1_found) 
		{
		set_text_font(DEF_TEXT_SIZE - 2);
		use_text_font();
		printf ("(");
		ps_puts(&title1[0]);
		printf (") dup stringwidth pop 2 div\n");
		printf ("%f 2 div exch sub %f 3 div moveto\n",
			WIDTH, BOTTOM);
		printf ("show\n");
		set_text_font(text_size);
		}

	if (number_logical)
		{
		if (number_all)
			do_page_numbering(lpage_label);
		else if (song_pages > 1)
			do_page_numbering(song_pages);
		}

	if ( in_chorus )
		{
		end_of_chorus = vpos;
		do_chorus_line();
		}

	if ((v_pages == pagination) || force_physical) 
		{
		do_end_of_phys_page();
		v_pages = 0;
		}
	n_columns = 0;
	min_col_vpos = TOP;
	col_vpos = TOP;
	}

/* --------------------------------------------------------------------------------*/
void do_end_of_column()
	{
	if (n_columns == (max_columns-1))
		{
		do_end_of_page(FALSE);
		do_start_of_page();
		}
	else
		{
		n_columns++;
		if (vpos < min_col_vpos )
			min_col_vpos = vpos;
		vpos = col_vpos;
		hpos = L_MARGIN + (n_columns * h_offset);
		}
	}
/* --------------------------------------------------------------------------------*/
void do_end_of_song()
{
	if ((! lyrics_only && ! no_grid)) 
		{
		if (min_col_vpos < vpos )
			vpos = min_col_vpos;
		draw_chords();
		}
	do_end_of_page(FALSE);
}
		 
/* --------------------------------------------------------------------------------*/
void set_sys_def()
	{
	text_size= DEF_TEXT_SIZE;
	chord_size= DEF_CHORD_SIZE;
	grid_size = DEF_GRID_SIZE;
	text_font = DEF_TEXT_FONT;
	chord_font = DEF_CHORD_FONT;
	text_font = DEF_TEXT_FONT;
	no_grid = FALSE;
	n_columns = 0;
	max_columns = 1;
	dummy_kcs.chord_name[0]='\0';
	}

/* --------------------------------------------------------------------------------*/
void set_rc_def()
	{
	if (rc_text_size != 0) text_size = rc_text_size;
	if (rc_chord_size != 0) chord_size =  rc_chord_size;
	if (rc_grid_size != 0) grid_size =  rc_grid_size;
	if (rc_no_grid != 0) no_grid =  rc_no_grid;
	if (rc_text_font != NULL) text_font =  rc_text_font;
	if (rc_chord_font != NULL) chord_font =  rc_chord_font;
	}

/* --------------------------------------------------------------------------------*/
void set_rt_def()
	{
	if (rt_text_size != 0) text_size = rt_text_size;
	if (rt_chord_size != 0) chord_size =  rt_chord_size;
	if (rt_grid_size != 0) grid_size =  rt_grid_size;
	if (rt_no_grid != 0) no_grid =  rt_no_grid;
	if (rt_text_font != NULL) text_font =  rt_text_font;
	if (rt_chord_font != NULL) chord_font =  rt_chord_font;
	}

/* --------------------------------------------------------------------------------*/
void init_values()
	{
	set_sys_def();
	set_rc_def();
	set_rt_def();
	}

/* --------------------------------------------------------------------------------*/
void do_new_song()
	{
	do_end_of_song();
	nb_chord= first_ptr= 0;
	song_pages = 0;
	in_tab = FALSE;
	strcpy (title1, "");
	do_start_of_page();

	/* reset default */
	init_values();
	clean_known_chords();
	clean_chordtab();

	set_text_font(text_size);
	}
/* --------------------------------------------------------------------------------*/
void advance(amount)
int amount;
	{
	vpos = vpos - amount;     /* Affect text positionning ! */
	if (vpos < BOTTOM )
		{
		/* do_end_of_page(FALSE); */
		do_end_of_column();
		/* do_start_of_page(); */
		}
	}

/* --------------------------------------------------------------------------------*/
void print_text_line()
	{
	int i;

	text_line[i_text] = '\0';

	for (i= 0; text_line[i] == ' '; i++);

	if (!((auto_space || in_tab)  && !has_chord))
		{
		advance(blank_space);
		blank_space = 0;
		advance (chord_size + 1);

		if ( ( text_line[i] != '\0' )
		  && ( vpos - text_size <= BOTTOM))
			advance (text_size);

		if (need_soc)
			{
			start_of_chorus = vpos + chord_size;
			need_soc = FALSE;
			}
		if ((! lyrics_only) && has_chord)
			print_chord_line();
		}

	if ( text_line[i] == '\0')
		{
		blank_space += text_size - 2;
		}
	else
		{
		advance (blank_space);
		blank_space = 0;
		advance (text_size - 1);
		if (need_soc)
			{
			start_of_chorus = vpos + text_size;
			need_soc = FALSE;
			}
		use_text_font();
		printf ("%d %d moveto\n", hpos, vpos);
		printf ("(");
		ps_puts(&text_line[0]);
		printf (") show\n");
		}

	i_text = 0;
	i_text_ov = FALSE;
	/* hpos = L_MARGIN; */
	has_chord = FALSE;
	}

/* --------------------------------------------------------------------------------*/
void do_title(title)
char	*title;
	{

	set_text_font (text_size+5);
	use_text_font();
	printf ("(");
	ps_puts(title);
	printf (") dup stringwidth pop 2 div\n");
	printf ("%f 2 div exch sub %d moveto\n", WIDTH, vpos);
	printf ("show\n");
	vpos = vpos - text_size - 5;
	/* skip blanks */
	while ( *title == ' ') title++;

	strcpy (&title1[0], title);
	title1_found = TRUE;
	set_text_font (text_size);
	if (do_toc && song_pages == 1)	/* generate index entry */
		add_title_to_toc(title, number_logical ? lpage_label : page_label);
	}
/* --------------------------------------------------------------------------------*/
void do_subtitle(sub_title)
char	*sub_title;
	{
	use_text_font();
	printf ("(");
	ps_puts(sub_title);
	printf (") dup stringwidth pop 2 div\n");
	printf ("%f 2 div exch sub %d moveto\n", WIDTH , vpos);
	printf ("show\n");
	vpos = vpos - text_size ;
	if (do_toc && song_pages == 1)
		add_subtitle_to_toc(sub_title);
	}
	

/* --------------------------------------------------------------------------------*/
void do_directive(directive)
char *directive;
	{
	int   i;
	char  *command, *comment;

	command= tolower_str(strtok(directive, ": "));

	if (!strcmp(command, "start_of_chorus") || !strcmp(command,"soc"))
		{
		/* start_of_chorus = vpos - blank_space; */
		need_soc = TRUE;
		in_chorus = TRUE;
		}
	else if (!strcmp (command, "end_of_chorus") || !strcmp(command, "eoc"))
		{
		if ( in_chorus )
			{
			end_of_chorus = vpos;
			do_chorus_line();
			in_chorus = FALSE;
			}
		else
			error ("Not in a chorus.");
		}
	else if (!strcmp (command, "textfont") || !strcmp (command, "tf"))
		{
		if (in_chordrc) rc_text_font = strtok(NULL, ": ");
		else		   text_font = strtok(NULL, ": ");
		}
	else if (!strcmp (command, "chordfont") || !strcmp (command, "cf"))
		{
		if (in_chordrc) rc_chord_font = strtok(NULL, ": ");
		else
			{
			chord_font = strtok(NULL, ": ");
			set_chord_font();
			}
		}
	else if (!strcmp (command, "chordsize") || !strcmp (command, "cs"))
		{
		i = atoi(strtok(NULL, ": "));
		if ( i == 0 )
			error ("invalid value for chord_size");
		else
			if (in_chordrc) rc_chord_size = i;
			else
				{
				chord_size = i;
				set_chord_font();
				}
		}
	else if (!strcmp (command, "textsize") || !strcmp (command, "ts"))
		{
		i = atoi(strtok(NULL, ": "));
		if ( i == 0 )
			error ("invalid value for text_size");
		else
			if (in_chordrc) rc_text_size = i;
			else
				{
				text_size = i;
				set_text_font (text_size);
				}
		}
	else if (!strcmp (command, "comment") || !strcmp (command, "c"))
		{
		comment = strtok(NULL, "\0");
		do_comment(comment, 1);
		}
	else if (!strcmp (command, "comment_italic") || !strcmp (command, "ci"))
		{
		comment = strtok(NULL, "\0");
		do_comment(comment, 2);
		}
	else if (!strcmp (command, "comment_box") || !strcmp (command, "cb"))
		{
		comment = strtok(NULL, "\0");
		do_comment(comment, 3);
		}
	else if (!strcmp(command, "new_song") || !strcmp(command,"ns"))
		{
		do_new_song();
		}
	else if (!strcmp(command, "title") || !strcmp(command,"t"))
		{
		do_title(strtok(NULL, "\0"));
		}  
	else if (!strcmp(command, "subtitle") || !strcmp(command,"st"))
		{
		do_subtitle(strtok(NULL, "\0"));
		}  
	else if (!strcmp(command, "define") || !strcmp(command,"d"))
		{
		do_define_chord();
		}  
	else if (!strcmp(command, "no_grid") || !strcmp(command,"ng"))
		{
		if (in_chordrc) rc_no_grid = TRUE;
		else 		   no_grid = TRUE;
		}
	else if (!strcmp(command, "grid") || !strcmp(command,"g"))
		{
		if (in_chordrc) rc_no_grid = FALSE;
		else 		   no_grid = FALSE;
		}
	else if (!strcmp(command, "new_page") || !strcmp(command,"np"))
		{
		do_end_of_page(FALSE);
		do_start_of_page();
		}
	else if (!strcmp(command, "start_of_tab") || !strcmp(command,"sot"))
		{
		if ( in_tab )
			error ("Already in a tablature !");
		else
			in_tab = TRUE;
		}
	else if (!strcmp(command, "end_of_tab") || !strcmp(command,"eot"))
		{
		if (! in_tab )
			error ("Not in a tablature !")	;
		else
			in_tab = FALSE;
		}
	else if (!strcmp(command, "column_break") || !strcmp(command,"colb"))
		{
		do_end_of_column();
		}
	else if (!strcmp(command, "columns") || !strcmp(command,"col"))
		{
		i = atoi(strtok(NULL, ": "));
		if ( i <= 1 )
			error ("invalid value for number of columns");
		else
			{
			max_columns = i;
			n_columns = 0;
			col_vpos = vpos;
			h_offset = (int)(( WIDTH - L_MARGIN) / max_columns);
			}
		}
	else if (!strcmp(command, "new_physical_page") || !strcmp(command,"npp"))
		{
		do_end_of_page(TRUE);
		do_start_of_page();
		}
	else
		{
		sprintf (mesg, "Invalid Directive : [%s]", command);
		error(mesg);
		has_directive = FALSE;
		}
	}

/* --------------------------------------------------------------------------------*/
void put_in_string(array, p_index, c, max_index, p_ov_flag)
char array[MAXLINE];
int *p_index;
int c;
int max_index;
int *p_ov_flag;
	{
	if (*p_index < max_index)
		array[(*p_index)++] = (char) c;
	else
		{
		if (!*p_ov_flag)
			{
			error ("Buffer Overflow");
			*p_ov_flag = TRUE;
			}
		}
	}
/* --------------------------------------------------------------------------------*/
void do_eol()
	{
	if ( in_directive )
		error ("Line ends while in a directive !"); 
	if ( in_chord)
		error ("Line ends while in a chord !"); 
	if (has_directive == FALSE)
		{
		if (in_chordrc) 
			{
			if (strcmp(text_line, "\0"))
				error("line is NOT a directive");
			}
		else if (! in_tab || ! lyrics_only)
			print_text_line();
			}
	else
		has_directive = FALSE;
	n_lines++;
	i_input = 0;
	in_directive = FALSE;
	in_chord = FALSE;
	i_text = 0;
	i_text_ov = FALSE;
	text_line[0]='\0';
	}
/* --------------------------------------------------------------------------------*/
void process_file(source_fd)
FILE *source_fd;
	{
	/*debug("start of process_file");*/

	n_lines = 0;

	while ( (c= getc(source_fd)) != EOF)
		{
		i_input++;
		switch ((char)c) {

		case '[':
			if (! in_tab) {
				if ( in_chord )
					error("Opening a chord within a chord!");
				else
					in_chord = TRUE;
				i_chord = 0;
			}
			else put_in_string(text_line, &i_text, c, MAXLINE, &i_text_ov);
			break;
		
		case ']':
			if (! in_tab) {
				if ( in_chord )
					{
					in_chord = FALSE;
					chord[i_chord]= '\0';
					do_chord(i_text, &chord[0]);
					has_chord = TRUE; 
					i_chord = 0;
					i_chord_ov = FALSE;
					}
				else
					error("']' found with no matching '['");
			}
			else put_in_string(text_line, &i_text, c, MAXLINE, &i_text_ov);
			break;
		
		case '{':
			in_directive = TRUE;
			i_directive = 0;
			has_directive = TRUE;
			break;

		case '}':
			if ( in_directive)
				{
				in_directive = FALSE;
				directive[i_directive]= '\0';
				for (; (c= getc(source_fd)) != '\n'; );
				i_input = 0;
				do_directive(&directive[0]);
				has_directive = FALSE;
				n_lines++;
				i_directive = 0;
				i_directive_ov = FALSE;
				}
			else
				error("'}' found with no matching '{'");
			break;

		case '\n':
			do_eol();
			break;
		case '(':
		case ')':
			if (in_directive)
				{
				put_in_string(directive, &i_directive, c, MAXTOKEN, &i_directive_ov);
				break;
				}
			else if (in_chord) /* allow parens in chord names */
				{
				put_in_string (chord, &i_chord, c, CHORD_NAME_SZ, &i_chord_ov);
				break;
				}
			else
				{
				put_in_string (text_line, &i_text, c, MAXLINE, &i_text_ov);
				break;
				}
	
	/* This case HAS to be the last before the default statement !!! */

		case '#':
			if (i_input == 1)
				{
				for (; (c= getc(source_fd)) != '\n'; );
				n_lines++;
				i_input = 0;
				break;
				}

		default :
			if (in_chord )
				{
				if ( c != ' ' )
					{
					put_in_string(chord, &i_chord, c, CHORD_NAME_SZ, &i_chord_ov);
					}
				}
			else if (in_directive)
				{
				put_in_string(directive, &i_directive, c, MAXTOKEN, &i_directive_ov);
				}
			else
				{
				put_in_string(text_line, &i_text, c, MAXLINE, &i_text_ov);
				}
			break;
			}
		}
	if (i_input != 0 ) do_eol();
	if (! in_chordrc) print_text_line();
	}

/* --------------------------------------------------------------------------------*/
/* read the file $HOME/.chordrc as a set of directive */
void read_chordrc()
	{
	char chordrc[MAXTOKEN];
	FILE *chordrc_fd;
	int n_lines_save;

	strcpy (chordrc, getenv ("HOME"));
	strcat (chordrc,"/.chordrc\0");
	current_file = chordrc;
	chordrc_fd = fopen (chordrc, "r");
	if (chordrc_fd != NULL)
		{
		n_lines_save= n_lines;
		n_lines= 1;
		in_chordrc = TRUE;
		process_file(chordrc_fd);
		in_chordrc = FALSE;
		n_lines= n_lines_save;
		fclose(chordrc_fd);
		}
	current_file = &source[0];
	first_time_in_chordrc = FALSE;
	}


/* --------------------------------------------------------------------------------*/
main(argc, argv)
int argc;
char **argv;
	{
	int c,i;

	mesg = mesgbuf;
/* Option Parsing */

	command_name= argv[0];

	while ((c = getopt(argc, argv, "aAc:C:dDgGhilLno:p:s:t:T:Vx:24")) != -1)
		switch (c) {

		case 'd':
			dump_only = TRUE;
			break;

		case 'D':
			dump_only = TRUE;
			postscript_dump = TRUE;
			break;

		case 'c':
			i = atoi (optarg);
			if ( i == 0 )
				error_rt("invalid value for chord_size");
			else
				rt_chord_size = i;
			break;

		case 'C':
			rt_chord_font = optarg;
			break;

		case 'h':
			do_help(argv[0]);
			break;

		case 't':
			i = atoi (optarg);
			if ( i == 0 )
				error_rt("invalid value for text_size");
			else
				rt_text_size= i;
			break;

		case 'T':
			rt_text_font = optarg;
			break;

		case 'x':
			i = atoi (optarg);
			if ( i == 0 )
				error_rt("invalid value for transposition");
			else
				transpose = i;
			break;

		case 's':
			i = atoi (optarg);
			if ( i == 0 )
				error_rt("invalid value for grid_size");
			else
				rt_grid_size = i;
			break;

		case 'g':
			no_easy_grids = TRUE;
			break;

		case 'G':
			rt_no_grid = TRUE;
			break;

		case 'l':
			lyrics_only= TRUE;
			break;

		case 'n':
			number_logical = TRUE;
			break;

		case 'V':
			print_version();
			exit(0);
			break;

		case '2':
			pagination= 2;
			scale = (WIDTH - L_MARGIN)/(TOP + BOTTOM);
			rotation= 90.0;
			break;

		case '4':
			pagination= 4;
			scale = ((WIDTH - L_MARGIN)/2.1)/(WIDTH - L_MARGIN);
			break;

		case 'i': /* generate in index */

			do_toc= TRUE;
			number_all = TRUE;
			break;

		case 'a':
			auto_space= TRUE;
			break;

		case 'p':
			i = atoi (optarg);
			if ( i == 0 )
				error_rt("invalid value for initial page number");
			else {
				page_label = i;
				number_all = TRUE;
			}
			break;

		case 'L':
			left_foot_even = 0;
			number_all= TRUE;
			break;

        	case 'o':
                	if ( freopen(optarg, "w", stdout) == NULL)
                        	{
                        	fprintf (stderr, "Unable to open \"%s\" for output\n", optarg);
                        	exit(1);
                        	}
	                break;

		case 'A':
			do_about();
			exit(0);
			break;

		case '?':
			do_help(argv[0]);
			break;
		}

/* Is there anything? */

	if (argc == 1)
		do_help(argv[0]);

/* Is there input? */

	if ((optind == argc) && isatty(0) && !dump_only)
	{
		fprintf (stderr, "Error: CHORD does not expect you to type the song on your keyboard.\n");
		fprintf (stderr, "Please either specify an input filename on the command line\n");
		fprintf (stderr, "or have the input redirected or piped in.\n");
		fprintf (stderr, "Exemples:\n");
		fprintf (stderr, "   %% chord my_song.cho > myfile.ps\n");
		fprintf (stderr, "   %% chord < mysong.cho > myfile.ps\n");
		fprintf (stderr, "Do \"chord -h\" to learn about CHORD's options\n");
		exit(1);
	}

/* Is there output? */

 	if (isatty(1) && (!dump_only || postscript_dump))  /* 1 == stdout  */
	{
		fprintf (stderr, "Error: CHORD will not send PostScript to your terminal.\n");
		fprintf (stderr, "Please either redirect (>) or pipe (|) the output.\n");
		fprintf (stderr, "Exemples:\n");
		fprintf (stderr, "   %% chord my_song.cho > myfile.ps\n");
		fprintf (stderr, "   %% chord my_song.cho | lpr\n");
		exit(1);
	}


/* File Processing */

	if (dump_only) 
	{
		dump_chords(postscript_dump);
		exit(0);
	}

	init_known_chords();
	read_chordrc();
	init_values();
	init_ps();

	chord_inc = chord_size * 1.5;

	for ( ; optind < argc; optind++ )
		{
		strcpy(source, argv[optind]);
		read_input_file(source, source_fd);
		if (optind < argc - 1)
			do_new_song();
		}


	do_end_of_song();
	 
	if (do_toc)	/* generate index  page */
		{
		build_ps_toc();
		do_end_of_page(FALSE);
		}

	if (v_pages != 0)
		{
		do_end_of_phys_page();
		}


	printf ("%%%%Trailer\n");
	printf ("%%%%Pages: %d 1\n", n_pages);
	printf ("%%%%EOF\n");

	exit (0);	
	return(0);
	}
