/* * abc2ps: a program to typeset tunes written in abc format using PostScript * Copyright (C) 1996,1997 Michael Methfessel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * The author can be contacted as follows: * * Michael Methfessel * msm@ihp-ffo.de * Institute for Semiconductor Physics, PO Box 409, * D-15204 Frankfurt (Oder), Germany * * Modified by Jean-François Moine, 1998 * mailto:Jean-Francois.Moine@bst.bsf.alcatel.fr * * Modified by John Atchley, 1999-2000 * mailto:john@guitarnut.com */ /* Main program abc2ps.c */ #include #include #include #include #include #include #ifdef _MSVC #include #endif #include "abc2ps.h" /* ----- global variables ------- */ int db=DEBUG_LV; /* debug control */ struct ISTRUCT info,default_info; struct SYMBOL *sym; /* (points to the symbols of the current voice) */ struct FORMAT sfmt; /* format after initialization */ struct FORMAT dfmt; /* format at start of tune */ struct FORMAT cfmt; /* current format for output */ char fontnames[50][STRLFMT]; /* list of needed fonts */ int nfontnames; char mbf[501]; /* mini-buffer for one line */ float bposy; /* current position in buffered data */ int use_buffer; /* 1 if lines are being accumulated */ char *text[NTEXT]; /* pool for history, words, etc. lines */ int text_type[NTEXT]; /* type of each text line */ int ntext; /* number of text lines */ int FixEols; /* Fix line breaks in source files when 1 */ char page_init[201]; /* initialization string after page break */ int do_mode; /* control whether to do index or output */ int linenum; /* current line number in input file */ int tunenum; /* number of current tune */ int tnum1,tnum2; int numtitle; /* how many titles were read */ int nsym; /* number of symbols in line */ int pagenum; /* current page in output file */ int xrefnum; /* xref number of current tune */ int bagpipe; /* switch for HP mode */ int within_tune, within_block; /* where we are in the file */ int do_this_tune; /* are we typesetting the current one ? */ float posx,posy; /* overall scale, position on page */ int transpose; int insert_btype,insert_num; /* needed to split bars across lines */ int vb, verbose; /* verbosity, global and within tune */ int in_page=0; /* switches modified by flags: */ int gmode; /* switch for glue treatment */ int include_xrefs; /* to include xref numbers in title */ int one_per_page; /* new page for each tune ? */ int pagenumbers; /* write page numbers ? */ int write_history; /* write history and notes ? */ int interactive; /* interactive mode ? */ int help_me; /* need help ? */ int select_all; /* select all tunes ? */ int epsf; /* for EPSF postscript output */ int choose_outname; /* 1 names outfile w. title/fnam */ int break_continues; /* ignore continuations ? */ int search_field0; /* default search field */ char in_file[MAXINF][STRL1]; /* list of input file names */ int ninf; /* number of input file names */ char outf[STRL1]; /* output file name */ char infostr[STRL1]; /* title string in PS file */ int file_open; /* for output file */ int file_initialized; /* for output file */ FILE *fout; /* for output file */ int nepsf; /* counter for epsf output files */ char sel_str[MAXINF][STRL1]; /* list of selector strings */ int s_field[MAXINF]; /* type of selection for each file */ int psel[MAXINF]; /* pointers from files to selectors */ static int do_interactive(char *bbb); static BOOL ConvertEol(char *AbcFile) { FILE *in, *out; int i; char c, lastc = '\0'; BOOL LastWasEOL = FALSE, Completed; char *BkFile; if (vb > 0) printf("Converting line breaks in [%s]...\n", AbcFile); BkFile = (char *)malloc(strlen(AbcFile) + 8); if (!BkFile) return FALSE; strcpy(BkFile, AbcFile); strcat(BkFile, "~"); remove(BkFile); if (rename(AbcFile, BkFile)) return FALSE; /* The file has been renamed with a "~" extension. */ if (vb > 0) printf(" ...file has been backed up to [%s]...\n", BkFile); in = fopen(BkFile, "rb"); if (!in) return FALSE; out = fopen(AbcFile, "wt"); if (!out) { fclose(in); return FALSE; } /* Files are open, copy, correcting linebreaks for this platform */ do { i = getc(in); if (i == EOF) break; c = i; if ((c == 13) || (c == 10) || (c == '\n')) { if (LastWasEOL && (c != lastc)) { /* drop this character in the bit bucket. */ LastWasEOL = FALSE; } else { LastWasEOL = TRUE; /* convert character to platform linefeed sequence */ i = putc('\n', out); if (i == EOF) break; } } else { LastWasEOL=FALSE; i = putc(c, out); if (i == EOF) break; } lastc = c; } while (i != EOF); Completed = feof(in); fclose(out); fclose(in); free(BkFile); if ((vb > 0) && Completed) printf(" ...conversion completed.\n"); return Completed; } /* ----- start of main ------ */ int main(int argc, char *argv[]) { char bbb[501], ext[41]; char xref_str[STRL1], pat[30][STRL1]; int isel, j, npat, search_field, i; FILE *fin; /* input file */ char *p, *pf, chrtime[32]; time_t ltime; struct tm *stime; const char cMonths[12][12] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; /* --------- Clear the "^text" FIFO objects. ---------- */ /* [JSA] */ tFIFO *Fifo, *HdFifo, *ChdFifo; int v; for (v = 0; v < MAXVOICE; v++) { Fifo = &voice_tb[v].TextDecs; HdFifo = &voice_tb[v].TextHdDecs; ChdFifo = &voice_tb[v].Chords; for (i = 0; i < MAXSTRDECO; i++) { Fifo->strings[i] = HdFifo->strings[i] = ChdFifo->strings[i] = NULL; } Fifo->inidx = Fifo->outidx = HdFifo->inidx = HdFifo->outidx = 0; ChdFifo->inidx = Fifo->outidx = 0; } /* ----- set default options and parse arguments ----- */ init_ops(1); if (parse_args(argc, argv) != 0) exit(1); if (interactive || (do_mode==DO_OUTPUT)) printf("This is jaabc2ps, version " VERSION " (%s)\n", VDATE); /* ----- set the page format ----- */ nfontnames=0; if (!set_page_format()) exit(3); if (help_me==2) { print_format(cfmt); exit(0); } /* ----- help printout ----- */ if (argc<=1) help_me=1; if (help_me==1) { write_help(); exit(0); } if (ninf==0 && !interactive) rx("No input file specified", ""); isel = psel[ninf-1]; search_field0 = s_field[isel]; /* default for interactive mode */ if (epsf) cutext(outf); /* ----- initialize ----- */ voice_tb[0].sym = malloc(MAXSYMS * sizeof(struct SYMBOL)); voice_tb[0].name = ""; sym = voice_tb[0].sym; zero_sym(); pagenum=0; transpose=0; tunenum=tnum1=tnum2=0; verbose=0; file_open=file_initialized=0; nepsf=0; bposy=0; posx=cfmt.leftmargin; posy=cfmt.pageheight-cfmt.topmargin; page_init[0] = '\0'; bbb[0] = '\0'; for (j=0;jtm_mon], stime->tm_mday, stime->tm_year + 1900); if (dfmt.tWatermarkText[0]) strcat(dfmt.tWatermarkText, "/"); strcat(dfmt.tWatermarkText, chrtime); } } else { dfmt.tWatermarkText[0] = '\0'; } /* ...[JSA] */ strcpy(infostr, in_file[j]); if (do_mode==DO_INDEX) { printf("%s:\n", in_file[j]); do_index(fin,xref_str,npat,pat,select_all,search_field); } else { if (!epsf) { strext(outf, "ps"); if (choose_outname) { strcpy(outf, in_file[j]); strext(outf, "ps"); } open_output_file(outf, in_file[j]); } printf("%s: ", in_file[j]); if ((vb>=3) || interactive) printf("\n"); process_file(fin,fout, xref_str, npat, pat, select_all, search_field); printf("\n"); } } if (!interactive) break; } if (!interactive && (do_mode==DO_INDEX)) printf("Selected %d title%s of %d\n", tnum1, tnum1==1?"":"s", tnum2); close_output_file(); /* [JSA] 05/00 text decorations */ /* free any strings that weren't popped from the FIFO buffer. */ for (i = 0; i < MAXVOICE; i++) { for (j = 0; j < MAXSTRDECO; j++) { if (voice_tb[i].TextDecs.strings[j]) { free(voice_tb[i].TextDecs.strings[j]); voice_tb[i].TextDecs.strings[j] = NULL; } if (voice_tb[i].TextHdDecs.strings[j]) { free(voice_tb[i].TextHdDecs.strings[j]); voice_tb[i].TextHdDecs.strings[j] = NULL; } if (voice_tb[i].Chords.strings[j]) { free(voice_tb[i].Chords.strings[j]); voice_tb[i].Chords.strings[j] = NULL; } } voice_tb[i].TextDecs.inidx = voice_tb[i].TextDecs.outidx = 0; voice_tb[i].TextHdDecs.inidx = voice_tb[i].TextHdDecs.outidx = 0; voice_tb[i].Chords.inidx = voice_tb[i].Chords.outidx = 0; } /* back to your regularly scheduled programming */ return 0; } static char *safe_gets(char s[], int sz) { char *rv; rv = fgets(s, sz, stdin); if (rv) { /* gets strips the trailing newline, fgets doesn't */ /* we have to strip it correctly on all platforms */ /* We're actually stripping all trailing whitespace */ /* but that's okay in this application. */ while (isspace(s[strlen(s) - 1])) s[strlen(s) - 1] = '\0'; } return rv; } static int do_interactive(char *bbb) { char aaa[501], ccc[501]; char *urgv[100]; int j, urgc; for (;;) { printf("\nSelect tunes: "); /* Michael was using gets() here and it was NOT a problem as it */ /* was used. But since the darn GCC linker shouted a dire- */ /* sounding warning each time the program was built, I replaced */ /* the function so I wouldn't be inundated with "but GCC says" */ /* e-mails ;-) */ /* TODO: Ironically, interactive mode isn't working anyway! */ safe_gets(aaa, 500); if (isblankstr(aaa)) return -1; sscanf(aaa,"%s",ccc); if (ccc[0]=='?') { printf("%s\n", bbb); continue; } if (ccc[0]=='*') { strcat(bbb,strchr(aaa,'*')+1); strcpy(aaa,bbb); printf("%s\n", aaa); } if (ccc[0]=='!') { bbb[0] = '\0'; for (j=0;j