/* * Formatting functions. * * This file is part of abcm2ps. * * Copyright (C) 1998-2007 Jean-François Moine * Adapted from abc2ps, 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. */ #include #include #include #include #include #include "abcparse.h" #include "abc2ps.h" struct FORMAT cfmt; /* current format for output */ char font_enc[MAXFONTS]; /* font encoding */ static char def_font_enc[MAXFONTS]; /* default font encoding */ static char *fontnames[MAXFONTS]; /* list of font names */ static char used_font[MAXFONTS]; /* used fonts */ static int nfontnames; static float staffwidth; /* format table */ static struct format { char *name; void *v; char type; #define FORMAT_I 0 /* int */ #define FORMAT_R 1 /* float */ #define FORMAT_F 2 /* font spec */ #define FORMAT_U 3 /* float with unit */ #define FORMAT_B 4 /* boolean */ #define FORMAT_S 5 /* string */ char subtype; /* special cases - see code */ short lock; } format_tb[] = { {"abc2pscompat", &cfmt.abc2pscompat, FORMAT_B, 0}, {"alignbars", &cfmt.alignbars, FORMAT_I, 0}, {"aligncomposer", &cfmt.aligncomposer, FORMAT_I, 0}, {"autoclef", &cfmt.autoclef, FORMAT_B, 0}, {"annotationfont", &cfmt.font_tb[ANNOTATIONFONT], FORMAT_F, 0}, {"barsperstaff", &cfmt.barsperstaff, FORMAT_I, 0}, {"botmargin", &cfmt.botmargin, FORMAT_U, 0}, {"bstemdown", &cfmt.bstemdown, FORMAT_B, 0}, {"combinevoices", &cfmt.combinevoices, FORMAT_B, 0}, {"comball", &cfmt.comball, FORMAT_B, 0}, {"composerfont", &cfmt.font_tb[COMPOSERFONT], FORMAT_F, 0}, {"composerspace", &cfmt.composerspace, FORMAT_U, 0}, {"contbarnb", &cfmt.contbarnb, FORMAT_B, 0}, {"continueall", &cfmt.continueall, FORMAT_B, 0}, {"dateformat", &cfmt.dateformat, FORMAT_S, 0}, {"dynalign", &cfmt.dynalign, FORMAT_B, 0}, {"encoding", &cfmt.encoding, FORMAT_I, 1}, {"exprabove", &cfmt.exprabove, FORMAT_B, 0}, {"exprbelow", &cfmt.exprbelow, FORMAT_B, 0}, {"footer", &cfmt.footer, FORMAT_S, 0}, {"footerfont", &cfmt.font_tb[FOOTERFONT], FORMAT_F, 0}, {"freegchord", &cfmt.freegchord, FORMAT_B, 0}, {"flatbeams", &cfmt.flatbeams, FORMAT_B, 0}, {"gchordbox", &cfmt.gchordbox, FORMAT_B, 0}, {"gchordfont", &cfmt.font_tb[GCHORDFONT], FORMAT_F, 3}, {"graceslurs", &cfmt.graceslurs, FORMAT_B, 0}, {"gracespace", &cfmt.gracespace, FORMAT_I, 5}, {"header", &cfmt.header, FORMAT_S, 0}, {"headerfont", &cfmt.font_tb[HEADERFONT], FORMAT_F, 0}, {"historyfont", &cfmt.font_tb[HISTORYFONT], FORMAT_F, 0}, {"hyphencont", &cfmt.hyphencont, FORMAT_B, 0}, {"indent", &cfmt.indent, FORMAT_U, 0}, {"infofont", &cfmt.font_tb[INFOFONT], FORMAT_F, 0}, {"infoline", &cfmt.infoline, FORMAT_B, 0}, {"infospace", &cfmt.infospace, FORMAT_U, 0}, {"landscape", &cfmt.landscape, FORMAT_B, 0}, {"leftmargin", &cfmt.leftmargin, FORMAT_U, 0}, {"lineskipfac", &cfmt.lineskipfac, FORMAT_R, 0}, {"maxshrink", &cfmt.maxshrink, FORMAT_R, 0}, {"maxstaffsep", &cfmt.maxstaffsep, FORMAT_U, 0}, {"maxsysstaffsep", &cfmt.maxsysstaffsep, FORMAT_U, 0}, {"measurebox", &cfmt.measurebox, FORMAT_B, 0}, {"measurefirst", &cfmt.measurefirst, FORMAT_I, 2}, {"measurefont", &cfmt.font_tb[MEASUREFONT], FORMAT_F, 2}, {"measurenb", &cfmt.measurenb, FORMAT_I, 0}, {"musiconly", &cfmt.musiconly, FORMAT_B, 0}, {"musicspace", &cfmt.musicspace, FORMAT_U, 0}, {"notespacingfactor", &cfmt.notespacingfactor, FORMAT_R, 1}, {"oneperpage", &cfmt.oneperpage, FORMAT_B, 0}, {"pageheight", &cfmt.pageheight, FORMAT_U, 0}, {"pagewidth", &cfmt.pagewidth, FORMAT_U, 0}, {"parskipfac", &cfmt.parskipfac, FORMAT_R, 0}, {"partsbox", &cfmt.partsbox, FORMAT_B, 0}, {"partsfont", &cfmt.font_tb[PARTSFONT], FORMAT_F, 1}, {"partsspace", &cfmt.partsspace, FORMAT_U, 0}, {"printparts", &cfmt.printparts, FORMAT_B, 0}, {"printtempo", &cfmt.printtempo, FORMAT_B, 0}, {"repeatfont", &cfmt.font_tb[REPEATFONT], FORMAT_F, 0}, {"rightmargin", &cfmt.rightmargin, FORMAT_U, 0}, {"scale", &cfmt.scale, FORMAT_R, 0}, {"setdefl", &cfmt.setdefl, FORMAT_B, 0}, {"setfont-1", &cfmt.font_tb[1], FORMAT_F, 0}, {"setfont-2", &cfmt.font_tb[2], FORMAT_F, 0}, {"setfont-3", &cfmt.font_tb[3], FORMAT_F, 0}, {"setfont-4", &cfmt.font_tb[4], FORMAT_F, 0}, #if FONT_UMAX!=5 # error Bad number of user fonts #endif {"shifthnote", &cfmt.shiftunisson, FORMAT_B, 0}, /*to remove*/ {"shiftunisson", &cfmt.shiftunisson, FORMAT_B, 0}, {"slurheight", &cfmt.slurheight, FORMAT_R, 0}, {"splittune", &cfmt.splittune, FORMAT_B, 0}, {"squarebreve", &cfmt.squarebreve, FORMAT_B, 0}, {"staffnonote", &cfmt.staffnonote, FORMAT_B, 0}, {"staffsep", &cfmt.staffsep, FORMAT_U, 0}, {"staffwidth", &staffwidth, FORMAT_U, 1}, {"stemheight", &cfmt.stemheight, FORMAT_R, 0}, {"straightflags", &cfmt.straightflags, FORMAT_B, 0}, {"stretchlast", &cfmt.stretchlast, FORMAT_B, 0}, {"stretchstaff", &cfmt.stretchstaff, FORMAT_B, 0}, {"subtitlefont", &cfmt.font_tb[SUBTITLEFONT], FORMAT_F, 0}, {"subtitlespace", &cfmt.subtitlespace, FORMAT_U, 0}, {"sysstaffsep", &cfmt.sysstaffsep, FORMAT_U, 0}, {"tempofont", &cfmt.font_tb[TEMPOFONT], FORMAT_F, 0}, {"textfont", &cfmt.font_tb[TEXTFONT], FORMAT_F, 0}, {"textoption", &cfmt.textoption, FORMAT_I, 4}, {"textspace", &cfmt.textspace, FORMAT_U, 0}, {"titlecaps", &cfmt.titlecaps, FORMAT_B, 0}, {"titlefont", &cfmt.font_tb[TITLEFONT], FORMAT_F, 0}, {"titleformat", &cfmt.titleformat, FORMAT_S, 0}, {"titleleft", &cfmt.titleleft, FORMAT_B, 0}, {"titlespace", &cfmt.titlespace, FORMAT_U, 0}, {"titletrim", &cfmt.titletrim, FORMAT_B, 0}, {"timewarn", &cfmt.timewarn, FORMAT_B, 0}, {"topmargin", &cfmt.topmargin, FORMAT_U, 0}, {"topspace", &cfmt.topspace, FORMAT_U, 0}, {"tuplets", &cfmt.tuplets, FORMAT_I, 3}, {"vocalabove", &cfmt.vocalabove, FORMAT_B, 0}, {"vocalfont", &cfmt.font_tb[VOCALFONT], FORMAT_F, 0}, {"vocalspace", &cfmt.vocalspace, FORMAT_U, 0}, {"voicefont", &cfmt.font_tb[VOICEFONT], FORMAT_F, 0}, {"withxrefs", &cfmt.withxrefs, FORMAT_B, 0}, {"wordsfont", &cfmt.font_tb[WORDSFONT], FORMAT_F, 0}, {"wordsspace", &cfmt.wordsspace, FORMAT_U, 0}, {"writehistory", &cfmt.writehistory, FORMAT_B, 0}, {0, 0, 0, 0} /* end of table */ }; static char *enc_name[20] = { "us-ascii", /* 0 */ "iso-8859-1", /* 1 */ "iso-8859-2", /* 2 */ "iso-8859-3", /* 3 */ "iso-8859-4", /* 4 */ "iso-8859-9", /* 5 (Latin5) */ "iso-8859-10", /* 6 (Latin6) */ "native", /* 7 = ENC_NATIVE */ #if 0 "utf-8", /* 8 */ #endif }; /* -- search a font and add it if not yet defined -- */ static int get_font(char *fname, int encoding) { int fnum; /* get or set the default encoding */ for (fnum = nfontnames; --fnum >= 0; ) if (strcmp(fname, fontnames[fnum]) == 0) { if (encoding < 0) encoding = def_font_enc[fnum]; if (encoding == font_enc[fnum]) return fnum; /* font found */ } for ( ; --fnum >= 0; ) if (strcmp(fname, fontnames[fnum]) == 0 && encoding == font_enc[fnum]) return fnum; /* add the font */ if (nfontnames >= MAXFONTS) { error(1, 0, "Too many fonts"); return 0; } if (file_initialized) error(1, 0, "Cannot have a new font when the output file is opened"); fnum = nfontnames++; fontnames[fnum] = strdup(fname); if (encoding < 0) encoding = cfmt.encoding; font_enc[fnum] = encoding; return fnum; } /* -- set a dynamic font -- */ static int dfont_set(struct FONTSPEC *f) { int i; for (i = FONT_DYN; i < cfmt.ndfont; i++) { if (cfmt.font_tb[i].fnum == f->fnum && cfmt.font_tb[i].size == f->size) return i; } if (i >= FONT_MAX - 1) { error(1, 0, "Too many dynamic fonts"); return FONT_MAX - 1; } memcpy(&cfmt.font_tb[i], f, sizeof cfmt.font_tb[0]); cfmt.ndfont = i + 1; return i; } /* -- define a font -- */ static void fontspec(struct FONTSPEC *f, char *name, int encoding, float size) { if (name != 0) f->fnum = get_font(name, encoding); else name = fontnames[f->fnum]; f->size = size; f->swfac = size; if (strncmp(name, "Times", 5) == 0) { if (strcmp(name, "Times-Bold") == 0) f->swfac *= 1.05; } else if (strcmp(name, "Helvetica-Bold") == 0) f->swfac *= 1.15; else if (strncmp(name, "Helvetica", 9) == 0 || strncmp(name, "Palatino", 8) == 0) f->swfac *= 1.10; else if (strncmp(name, "Courier", 7) == 0) f->swfac *= 1.35; else f->swfac *= 1.2; /* unknown font */ if (f == &cfmt.font_tb[GCHORDFONT]) cfmt.gcf = dfont_set(f); else if (f == &cfmt.font_tb[ANNOTATIONFONT]) cfmt.anf = dfont_set(f); else if (f == &cfmt.font_tb[VOCALFONT]) cfmt.vof = dfont_set(f); } /* -- output the encodings -- */ void define_encodings(void) { int i, enc; enc = 0; for (i = 0; i < nfontnames; i++) { if (used_font[i]) enc |= 1 << font_enc[i]; } for (i = 0; ; i++) { if (enc == 0) break; if (enc & 1) define_encoding(i, enc_name[i]); enc >>= 1; } } /* -- output the font definitions with their encodings -- */ void define_fonts(void) { int i; for (i = 0; i < nfontnames; i++) { if (used_font[i]) define_font(fontnames[i], i, font_enc[i]); } } /* -- mark the used fonts -- */ void make_font_list(void) { struct FORMAT *f; f = &cfmt; used_font[f->font_tb[ANNOTATIONFONT].fnum] = 1; used_font[f->font_tb[COMPOSERFONT].fnum] = 1; used_font[f->font_tb[FOOTERFONT].fnum] = 1; used_font[f->font_tb[GCHORDFONT].fnum] = 1; used_font[f->font_tb[HEADERFONT].fnum] = 1; used_font[f->font_tb[HISTORYFONT].fnum] = 1; used_font[f->font_tb[INFOFONT].fnum] = 1; used_font[f->font_tb[MEASUREFONT].fnum] = 1; used_font[f->font_tb[PARTSFONT].fnum] = 1; used_font[f->font_tb[REPEATFONT].fnum] = 1; used_font[f->font_tb[SUBTITLEFONT].fnum] = 1; used_font[f->font_tb[TEMPOFONT].fnum] = 1; used_font[f->font_tb[TEXTFONT].fnum] = 1; used_font[f->font_tb[TITLEFONT].fnum] = 1; used_font[f->font_tb[VOCALFONT].fnum] = 1; used_font[f->font_tb[VOICEFONT].fnum] = 1; used_font[f->font_tb[WORDSFONT].fnum] = 1; } /* -- set the name an information header type -- */ /* the argument is * [ ] * this information is kept in the 'I' information */ static void set_infoname(char *p) { struct SYMBOL *s, *prev; if (*p == 'I') return; s = info['I' - 'A']; prev = 0; while (s != 0) { if (s->as.text[0] == *p) break; prev = s; s = s->next; } if (p[1] == '\0') { /* if delete */ if (s != 0) { if ((prev->next = s->next) != 0) prev->next->prev = prev; } return; } if (s == 0) { s = (struct SYMBOL *) getarena(sizeof *s); memset(s, 0, sizeof *s); if (prev == 0) info['I' - 'A'] = s; else { prev->next = s; s->prev = prev; } } s->as.text = (char *) getarena(strlen(p) + 1); strcpy(s->as.text, p); } /* -- set the default format -- */ void set_format(void) { struct FORMAT *f; f = &cfmt; memset(f, 0, sizeof *f); f->pageheight = PAGEHEIGHT; f->pagewidth = PAGEWIDTH; f->leftmargin = MARGIN; f->rightmargin = MARGIN; f->topmargin = 1.0 CM; f->botmargin = 1.0 CM; f->topspace = 0.8 CM; f->titlespace = 0.2 CM; f->subtitlespace = 0.1 CM; f->composerspace = 0.2 CM; f->musicspace = 0.2 CM; f->partsspace = 0.3 CM; f->staffsep = 46.0 PT; f->sysstaffsep = 34.0 PT; f->maxstaffsep = 2000.0 PT; f->maxsysstaffsep = 2000.0 PT; f->vocalspace = 23.0 PT; f->textspace = 0.5 CM; f->scale = 0.75; f->slurheight = 1.0; f->maxshrink = 0.65; f->stretchstaff = 1; f->graceslurs = 1; f->lineskipfac = 1.1; f->parskipfac = 0.4; f->measurenb = -1; f->measurefirst = 1; f->autoclef = 1; f->dynalign = 1; f->printparts = 1; f->printtempo = 1; f->staffnonote = 1; f->titletrim = 1; f->aligncomposer = A_RIGHT; f->notespacingfactor = 1.414; f->stemheight = STEM; f->dateformat = strdup("\\%b \\%e, \\%Y \\%H:\\%M"); f->gracespace = (65 << 16) | (80 << 8) | 120; /* left-inside-right - unit 1/10 pt */ f->textoption = T_LEFT; f->ndfont = FONT_DYN; fontspec(&f->font_tb[ANNOTATIONFONT], "Helvetica", 0, 12.0); fontspec(&f->font_tb[COMPOSERFONT], "Times-Italic", 0, 14.0); fontspec(&f->font_tb[FOOTERFONT], "Times-Roman", 0, 12.0); /* not scaled */ fontspec(&f->font_tb[GCHORDFONT], "Helvetica", 0, 12.0); fontspec(&f->font_tb[HEADERFONT], "Times-Roman", 0, 12.0); /* not scaled */ fontspec(&f->font_tb[HISTORYFONT], "Times-Roman", 0, 16.0); fontspec(&f->font_tb[INFOFONT], "Times-Italic", 0, 14.0); /* same as composer by default */ fontspec(&f->font_tb[MEASUREFONT], "Times-Italic", 0, 14.0); fontspec(&f->font_tb[PARTSFONT], "Times-Roman", 0, 15.0); fontspec(&f->font_tb[REPEATFONT], "Times-Roman", 0, 13.0); fontspec(&f->font_tb[SUBTITLEFONT], "Times-Roman", 0, 16.0); fontspec(&f->font_tb[TEMPOFONT], "Times-Bold", 0, 15.0); fontspec(&f->font_tb[TEXTFONT], "Times-Roman", 0, 16.0); fontspec(&f->font_tb[TITLEFONT], "Times-Roman", 0, 20.0); fontspec(&f->font_tb[VOCALFONT], "Times-Bold", 0, 13.0); fontspec(&f->font_tb[VOICEFONT], "Times-Bold", 0, 13.0); fontspec(&f->font_tb[WORDSFONT], "Times-Roman", 0, 16.0); set_infoname("R \"Rhythm: \""); set_infoname("B \"Book: \""); set_infoname("S \"Source: \""); set_infoname("D \"Discography: \""); set_infoname("N \"Notes: \""); set_infoname("Z \"Transcription: \""); set_infoname("H \"History: \""); } /* -- print the current format -- */ void print_format(void) { struct format *fd; static char yn[2][5]={"no","yes"}; for (fd = format_tb; fd->name; fd++) { printf(" %-13s ", fd->name); switch (fd->type) { case FORMAT_I: switch (fd->subtype) { default: printf("%d\n", *((int *) fd->v)); break; case 1: /* encoding */ printf("%s\n", enc_name[*((int *) fd->v)]); break; case 3: /* tuplets */ printf("%d %d %d\n", cfmt.tuplets >> 8, (cfmt.tuplets >> 4) & 0x0f, cfmt.tuplets & 0x0f); break; case 5: /* gracespace */ printf("%d.%d %d.%d %d.%d\n", (cfmt.gracespace >> 16) / 10, (cfmt.gracespace >> 16) % 10, ((cfmt.gracespace >> 8) & 0xff) / 10, ((cfmt.gracespace >> 8) & 0xff) % 10, (cfmt.gracespace & 0xff) / 10, (cfmt.gracespace & 0xff) % 10); break; } break; case FORMAT_R: printf("%.2f\n", *((float *) fd->v)); break; case FORMAT_F: { struct FONTSPEC *s; s = (struct FONTSPEC *) fd->v; printf("%s", fontnames[s->fnum]); if (font_enc[s->fnum] != cfmt.encoding) printf(" %s", enc_name[(unsigned) font_enc[s->fnum]]); printf(" %.1f", s->size); if ((fd->subtype == 1 && cfmt.partsbox) || (fd->subtype == 2 && cfmt.measurebox) || (fd->subtype == 3 && cfmt.gchordbox)) printf(" box"); printf("\n"); break; } case FORMAT_U: if (fd->subtype == 0) printf("%.2fcm\n", *((float *) fd->v) / (1 CM)); else printf("%.2fcm\n", (cfmt.pagewidth - cfmt.leftmargin - cfmt.rightmargin) / (1 CM)); break; case FORMAT_B: printf("%s\n", yn[*((int *) fd->v)]); break; case FORMAT_S: printf("\"%s\"\n", *((char **) fd->v) != 0 ? *((char **) fd->v) : ""); break; } } } /* -- get an encoding -- */ static int get_encoding(char *p) { int l; char **e; l = 0; while (p[l] != '\0' && !isspace((unsigned char) p[l])) l++; if (strncasecmp(p, "ASCII", l) == 0) /* backward compatibility */ return 0; e = enc_name; for (;;) { if (strncmp(p, *e, l) == 0) break; e++; if (*e == 0 || e >= &enc_name[sizeof enc_name]) { if (e >= &enc_name[sizeof enc_name - 1]) { error(1, 0, "Too many encodings"); return 0; } *e = (char *) malloc(l + 1); strncpy(*e, p, l); (*e)[l] = '\0'; } } return e - enc_name; } /* -- get the option for text -- */ int get_textopt(char *p) { int option; option = T_LEFT; if (*p == '\0' || strncmp(p, "obeylines", 9) == 0) ; else if (strncmp(p, "align", 5) == 0 || strncmp(p, "justify", 7) == 0) option = T_JUSTIFY; else if (strncmp(p, "ragged", 6) == 0 || strncmp(p, "fill", 4) == 0) option = T_FILL; else if (strncmp(p, "center", 6) == 0) option = T_CENTER; else if (strncmp(p, "skip", 4) == 0) option = T_SKIP; else if (strncmp(p, "right", 5) == 0) option = T_RIGHT; else option = -1; return option; } /* -- get a boolean value -- */ static int g_logv(char *p) { switch (*p) { case 0: case '1': case 'y': case 'Y': case 't': case 'T': return 1; case '0': case 'n': case 'N': case 'f': case 'F': break; default: fprintf(stderr, "++++ Unknown logical '%s' - false assumed\n", p); break; } return 0; } /* -- get a float variable, no units -- */ static float g_fltv(char *p) { return atof(p); } /* -- get a font specifier -- */ static void g_fspc(char *p, struct FONTSPEC *f) { char fname[80]; int encoding; float fsize; p = get_str(fname, p, sizeof fname); if (!isdigit((unsigned char) *p)) { if (*p == '*') encoding = font_enc[f->fnum]; else encoding = get_encoding(p); while (*p != '\0' && !isspace((unsigned char) *p)) p++; while (isspace((unsigned char) *p)) p++; } else encoding = -1; fsize = *p != '\0' && *p != '*' ? g_fltv(p) : f->size; fontspec(f, strcmp(fname, "*") != 0 ? fname : 0, encoding, fsize); if (!file_initialized) used_font[f->fnum] = 1; if (f - cfmt.font_tb == outft) outft = -1; } /* -- parse a format line -- */ void interpret_fmt_line(char *w, /* keyword */ char *p, /* argument */ int lock) { struct format *fd; switch (w[0]) { case 'b': if (strcmp(w, "barnumbers") == 0) w = "measurenb"; break; case 'd': if (strcmp(w, "deco") == 0) { deco_add(p); return; } break; case 'f': if (strcmp(w, "font") == 0) { int fnum, encoding; char fname[80]; p = get_str(fname, p, sizeof fname); if (*p == '\0') encoding = cfmt.encoding; else encoding = get_encoding(p); fnum = get_font(fname, encoding); def_font_enc[fnum] = encoding; used_font[fnum] = 1; return; } if (strcmp(w, "format") == 0) { if (read_fmt_file(p) < 0) error(1, 0, "No such format file '%s'", p); return; } break; case 'i': if (strcmp(w, "infoname") == 0) { if (*p < 'A' || *p > 'Z') { error(1, 0, "Bad info type '%c' in %%%%infoname", *p); return; } set_infoname(p); return; } break; case 'p': if (strcmp(w, "postscript") == 0) { if (!file_initialized) user_ps_add(p); return; } } for (fd = format_tb; fd->name; fd++) if (strcmp(w, fd->name) == 0) break; if (fd->name == 0) return; if (fd->lock && !lock) return; fd->lock |= lock; switch (fd->type) { case FORMAT_I: if (fd->subtype == 3) { /* tuplets */ unsigned i1, i2, i3; if (sscanf(p, "%d %d %d", &i1, &i2, &i3) != 3 || i1 > 2 || i2 > 2 || i3 > 2) { error(1, 0, "Bad 'tuplets' values '%s' - ignored", p); return; } cfmt.tuplets = (i1 << 8) | (i2 << 4) | i3; break; } if (fd->subtype == 5) { /* gracespace */ unsigned i1, i2, i3; float f1, f2, f3; if (sscanf(p, "%f %f %f", &f1, &f2, &f3) != 3 || f1 > 256 || f2 > 256 || f3 > 256) { error(1, 0, "Bad 'gracespace' values '%s' - ignored", p); return; } i1 = f2 * 10; i2 = f2 * 10; i3 = f3 * 10; cfmt.gracespace = (i1 << 16) | (i2 << 8) | i3; break; } if (fd->subtype == 1 && !isdigit(*p)) /* 'encoding' */ cfmt.encoding = get_encoding(p); else if (fd->subtype == 4 && !isdigit(*p)) /* 'textoption' */ cfmt.textoption = get_textopt(p); else sscanf(p, "%d", (int *) fd->v); switch (fd->subtype) { case 1: if (isdigit(*p) && (unsigned) cfmt.encoding > MAXENC) { error(1, 0, "Bad encoding value %d - reset to 0", cfmt.encoding); cfmt.encoding = 0; } else { int i; for (i = 0; i < nfontnames; i++) { if (font_enc[i] == 0) def_font_enc[i] = font_enc[i] = cfmt.encoding; } } break; case 2: nbar = nbar_rep = cfmt.measurefirst; break; case 4: if (cfmt.textoption < 0) { error(1, 0, "Bad 'textoption' value '%s'", p); cfmt.textoption = T_LEFT; } break; } break; case FORMAT_R: *((float *) fd->v) = g_fltv(p); if (fd->subtype == 1) { /* note spacing factor */ int i; float w; if (cfmt.notespacingfactor <= 0) { fprintf(stderr, "Bad value for 'notespacingfactor'\n"); cfmt.notespacingfactor = 1; break; } i = C_XFLAGS; /* crotchet index */ w = space_tb[i]; for ( ; --i >= 0; ) { w /= cfmt.notespacingfactor; space_tb[i] = w; } i = C_XFLAGS; w = space_tb[i]; for ( ; ++i < NFLAGS_SZ; ) { w *= cfmt.notespacingfactor; space_tb[i] = w; } } break; case FORMAT_F: { int b; g_fspc(p, (struct FONTSPEC *) fd->v); b = strstr(p, "box") != 0; switch (fd->subtype) { case 1: cfmt.partsbox = b; break; case 2: cfmt.measurebox = b; break; case 3: cfmt.gchordbox = b; break; } break; } case FORMAT_U: *((float *) fd->v) = scan_u(p); if (fd->subtype == 1) { float rmargin; rmargin = (cfmt.landscape ? cfmt.pageheight : cfmt.pagewidth) - staffwidth - cfmt.leftmargin; if (rmargin < 0) fprintf(stderr, "'staffwidth' too big\n"); cfmt.rightmargin = rmargin; } break; case FORMAT_B: *((int *) fd->v) = g_logv(p); break; case FORMAT_S: { int l; if (*((char **) fd->v) != 0) /* !!no static allocation!! */ free(*((char **) fd->v)); l = strlen(p) + 1; *((char **) fd->v) = malloc(l); if (*p == '"') get_str(*((char **) fd->v), p, l); else strcpy(*((char **) fd->v), p); break; } } } /* -- remove the spaces and comments of a format line -- */ static char *clean_line(char *p) { int i; char c, *q; while (isspace((unsigned char) *p)) p++; q = p; i = 0; for (;;) { if ((c = *p++) == '%') { if (i > 0 && p[-2] != '\\') c = '\0'; } if (c == '\0') { p--; break; } i++; } while (--i > 0) { c = *--p; if (!isspace((unsigned char) c)) { p[1] = '\0'; break; } } return q; } /* -- lock a format -- */ void lock_fmt(void *fmt) { struct format *fd; for (fd = format_tb; fd->name; fd++) if (fd->v == fmt) break; if (fd->name == 0) return; fd->lock = 1; } /* -- open a file for reading -- */ FILE *open_file(char *fn, /* file name */ char *ext, /* file type */ char *rfn) /* real file name */ { FILE *fp; char *p; int l; strcpy(rfn, fn); if ((fp = fopen(rfn, "r")) != 0) return fp; strext(rfn, ext); if ((fp = fopen(rfn, "r")) != 0) return fp; if (in_fname != 0 && (p = strrchr(in_fname, DIRSEP)) != 0) { l = p - in_fname + 1; strncpy(rfn, in_fname, l); strcpy(&rfn[l], fn); if ((fp = fopen(rfn, "r")) != 0) return fp; strext(&rfn[l], ext); if ((fp = fopen(rfn, "r")) != 0) return fp; } if (*styd == '\0') return 0; sprintf(rfn, "%s%c%s", styd, DIRSEP, fn); if ((fp = fopen(rfn, "r")) != 0) return fp; strext(rfn, ext); if ((fp = fopen(rfn, "r")) != 0) return fp; return 0; } /* -- read a format file -- */ int read_fmt_file(char *fn) { FILE *fp; char line[BSIZE], *p, *q; line[0] = '\001'; if ((fp = open_file(fn, "fmt", &line[1])) == 0) return -1; if (strcmp(&line[strlen(line) - 3], ".ps") == 0) { if (!file_initialized) user_ps_add(line); fclose(fp); return 0; } for (;;) { p = line; if (!fgets(p, sizeof line, fp)) break; p = clean_line(p); if (*p == '\0') continue; if (strcmp(p, "beginps") == 0) { for (;;) { p = line; if (!fgets(p, sizeof line, fp)) break; #if 1 p[strlen(p) - 1] = '\0'; #else p = clean_line(p); #endif if (*p == '\0') continue; if (strcmp(p, "endps") == 0) break; if (!file_initialized) user_ps_add(p); } continue; } if (strcmp(p, "end") == 0) break; q = p; while (*p != '\0' && !isspace((unsigned char) *p)) p++; if (*p != '\0') { *p++ = '\0'; while (isspace((unsigned char) *p)) p++; } interpret_fmt_line(q, p, 0); } fclose(fp); return 0; } /* -- start a new font -- */ void set_font(int ft) { int fnum; struct FONTSPEC *f, *f2; if (ft == outft) return; f = &cfmt.font_tb[ft]; f2 = &cfmt.font_tb[outft]; outft = ft; if (f->fnum == f2->fnum && f->size == f2->size) return; fnum = f->fnum; if (!used_font[fnum]) { error(1, 0, "Font \"%s\" not predefined; using first in list", fontnames[fnum]); fnum = 0; } if (f->size == 0) error(0, 0, "Font \"%s\" with a null size", fontnames[fnum]); PUT2("%.1f F%d ", f->size, fnum); }