2 /* Copyright (c) 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006 by Arkkra Enterprises */
3 /* All rights reserved */
5 /* This file contains functions for dealing with symbol tables.
6 * There is a symbol table that maps the names of location variables
7 * to the addresses of their array of coordinate info,
8 * a symbol table to map headshape names to the list of shapes,
9 * a table to map time signatures to beamstyle and/or timeunit values,
10 * and a symbol table to map grid names to definitions of the grids.
11 * Symbol names are hashed for fast lookup.
19 /* shapes for quarter and shorter, half, whole, double whole */
20 #define MAX_SHAPE_DURS (4)
22 #define MAX_STEM_DIRS (2)
24 /* First index of headchar and headfont is based on stem direction;
25 * also index of ystem_off. */
26 #define STEMINDEX(stemdir) ( (stemdir) == UP ? 0 : 1 )
27 /* Second index of headchar and headfont is based on basictime */
28 #define HCDUR(basictime) ( (basictime) > 2 ? 0 : 3 - (basictime) )
29 /* First index of Nhead_map */
30 #define FONTINDEX(font) (font - FONT_MUSIC)
31 /* Second index of Nhead_map */
32 #define CHARINDEX(ch) (ch - FIRST_CHAR)
35 /* We give each headshape instance a unique index number,
36 * as a compact way to refer to it. */
39 /* This says what notehead characters to use for this shape.
40 * The first dimension is for stem direction, the second for
41 * duration (quarter and shorter, half, whole, double whole).
43 char headchar
[MAX_STEM_DIRS
][MAX_SHAPE_DURS
];
44 /* This array parallels the notehead array, saying which music
45 * font the character is in. */
46 char headfont
[MAX_STEM_DIRS
][MAX_SHAPE_DURS
];
49 /* How many "headshape" entries we allow. This must be small enough to
50 * fit in the number of bits allowed for shape indexes in GRPSYL and NOTE.
51 * Entry 0 isn't used since we need an "unknown" value.
53 #define MAX_SHAPE_ENTRIES (32)
55 /* These are the predefined headshape entries. Users can define more.
56 * We define them here using the same syntax as user would, so we can
57 * use the same code to add to our internal table. */
59 char *clan_name
; /* name for the set of shapes */
60 char *member_names
; /* The names of the 4 shapes in the set */
61 } Predef_shape_names
[] = {
62 { "norm", "4n 2n 1n dblwhole" },
63 { "x", "xnote diamond diamond dwhdiamond" },
64 { "allx", "xnote xnote xnote xnote" },
65 { "diam", "filldiamond diamond diamond dwhdiamond" },
66 { "blank", "blankhead blankhead blankhead blankhead" },
67 { "righttri", "u?fillrighttriangle u?righttriangle u?righttriangle u?dwhrighttriangle" },
68 { "isostri", "fillisostriangle isostriangle isostriangle dwhisostriangle" },
69 { "rect", "fillrectangle rectangle rectangle dwhrectangle" },
70 { "pie", "fillpiewedge piewedge piewedge dwhpiewedge" },
71 { "semicirc", "fillsemicircle semicircle semicircle dwhsemicircle" },
72 { "allslash", "fillslashhead fillslashhead fillslashhead fillslashhead" },
73 { "slash", "fillslashhead slashhead slashhead dwhslashhead" },
77 /* Information about characters that are allowed to be noteheads */
79 char ch
; /* code number 32-127 */
80 char font
; /* FONT_MUSIC* */
81 float ystem_off
[MAX_STEM_DIRS
]; /* stepsizes from y to end stem */
84 /* Predefined note head music characters and their attributes. */
88 } Predef_headinfo
[] = {
89 { "dblwhole", { C_DBLWHOLE
, FONT_MUSIC
, { 0.0, 0.0 } } },
90 { "1n", { C_1N
, FONT_MUSIC
, { 0.0, 0.0 } } },
91 { "2n", { C_2N
, FONT_MUSIC
, { 0.25, -0.25 } } },
92 { "4n", { C_4N
, FONT_MUSIC
, { 0.25, -0.25 } } },
93 { "xnote", { C_XNOTE
, FONT_MUSIC
, { 1.0, -1.0 } } },
94 { "dwhdiamond", { C_DWHDIAMOND
, FONT_MUSIC
, { 0.0, 0.0 } } },
95 { "diamond", { C_DIAMOND
, FONT_MUSIC
, { 0.0, 0.0 } } },
96 { "filldiamond", { C_FILLDIAMOND
, FONT_MUSIC
, { 0.0, 0.0 } } },
97 { "dwhrighttriangle", { C_DWHRIGHTTRIANGLE
, FONT_MUSIC2
, { 0.0, 0.0 } } },
98 { "righttriangle", { C_RIGHTTRIANGLE
, FONT_MUSIC2
, { 0.0, 0.9 } } },
99 { "fillrighttriangle",{ C_FILLRIGHTTRIANGLE
, FONT_MUSIC2
, { 0.0, 0.9 } } },
100 { "udwhrighttriangle",{ C_UDWHRIGHTTRIANGLE
, FONT_MUSIC2
, { 0.0, 0.9 } } },
101 { "urighttriangle", { C_URIGHTTRIANGLE
, FONT_MUSIC2
, { -0.9, 0.0 } } },
102 { "ufillrighttriangle",{ C_UFILLRIGHTTRIANGLE
,FONT_MUSIC2
, { -0.9, 0.0 } } },
103 { "dwhrectangle", { C_DWHRECTANGLE
, FONT_MUSIC2
, { -0.9, 0.0 } } },
104 { "rectangle", { C_RECTANGLE
, FONT_MUSIC2
, { 0.0, 0.0 } } },
105 { "fillrectangle", { C_FILLRECTANGLE
, FONT_MUSIC2
, { 0.0, 0.0 } } },
106 { "dwhisostriangle", { C_DWHISOSTRIANGLE
, FONT_MUSIC2
, { -0.8, -0.8 } } },
107 { "isostriangle", { C_ISOSTRIANGLE
, FONT_MUSIC2
, { -0.8, -0.8 } } },
108 { "fillisostriangle", { C_FILLISOSTRIANGLE
, FONT_MUSIC2
, { -0.8, -0.8 } } },
109 { "dwhpiewedge", { C_DWHPIEWEDGE
, FONT_MUSIC2
, { 0.1, 0.2 } } },
110 { "piewedge", { C_PIEWEDGE
, FONT_MUSIC2
, { 0.1, 0.2 } } },
111 { "fillpiewedge", { C_FILLPIEWEDGE
, FONT_MUSIC2
, { 0.1, 0.2 } } },
112 { "dwhsemicircle", { C_DWHSEMICIRCLE
, FONT_MUSIC2
, { 0.8, 0.8 } } },
113 { "semicircle", { C_SEMICIRCLE
, FONT_MUSIC2
, { 0.8, 0.8 } } },
114 { "fillsemicircle", { C_FILLSEMICIRCLE
, FONT_MUSIC2
, { 0.8, 0.8 } } },
115 { "blankhead", { C_BLANKHEAD
, FONT_MUSIC2
, { 0.0, 0.0 } } },
116 { "slashhead", { C_SLASHHEAD
, FONT_MUSIC2
, { 1.8, -1.8 } } },
117 { "fillslashhead", { C_FILLSLASHHEAD
, FONT_MUSIC2
, { 1.8, -1.8 } } },
118 { "dwhslashhead", { C_DWHSLASHHEAD
, FONT_MUSIC2
, { 1.8, -1.8 } } },
119 { 0, { 0, 0, { 0.0, 0.0 } } }
123 * This struct provides a mapping from a time signature to all the
124 * beamstyle and timeunit values to be associated with that time signature.
126 * The [0][0] entry is used for the C_SCORE value.
127 * The entries [0][1] through [0][MAXVOICES+1] are unused.
128 * The [s][0] entries are used for C_STAFF values where 1 <= s <= MAXSTAFFS
129 * The [s][v] entries are used for C_VOICE values where 1 <= s <= MAXSTAFFS
130 * and 1 <= v <= MAXVOICES
131 * There will be one of these allocated for each time signature used in the
132 * input, if and only if the user also specified at least one beamstyle
133 * or timeunit while that time signature was in effect.
136 struct SSV
*beamstyle_table
[MAXSTAFFS
+1][MAXVOICES
+1];
137 struct SSV
*timeunit_table
[MAXSTAFFS
+1][MAXVOICES
+1];
141 /* information about a symbol: its name and current value.
142 * This is used for location tags, chord grids, headshapes, and time signatures.
143 * Note that in the case of location tags,
144 * if the same name is used in a later measure, just the coordlist_p will
145 * change, and when the symbol table is queried for the value of a symbol,
146 * it will get the current value for that symbol */
150 float *coordlist_p
; /* when used for location tags, this is
151 * where its AX, RX, etc values are */
152 struct GRID
*grid_p
; /* when used for grids */
153 struct HDSHAPEINFO
*shapeinfo_p
;/* when used for headshapes */
154 struct HEADINFO
*noteinfo_p
; /* when used for note head info */
155 /* Info about beamstyles and/or timeunits associated with
156 * the time signature given by the symname. */
157 struct SSVTABLES
*ssvtables_p
;
159 struct Sym
*next
; /* for collision chain off hash table */
162 /* symbol hash table size-- if this changes, hash() has to change accordingly */
163 #define SYMTBLSIZE (128)
165 /* this is the symbol table for location tags */
166 static struct Sym
*Tag_table
[SYMTBLSIZE
];
168 /* this is the symbol table for guitar grids. It is malloc-ed at runtime
170 static struct Sym
**Grid_table
;
172 /* This is the symbol table for headshapes */
173 static struct Sym
*Shape_table
[SYMTBLSIZE
];
175 /* This maps headshape indexes to the corresponding info.
176 * Element 0 is unused, since index 0 means "unknown" shape.
178 static struct Sym
*Shape_map
[MAX_SHAPE_ENTRIES
];
179 /* How many Shape_map entries are actually used */
180 static short Shape_entries
= 0;
182 /* This is the symbol table for noteheads, to get stem offsets */
183 static struct Sym
*Nhead_table
[SYMTBLSIZE
];
185 /* This maps notehead character codes to the stem offset info */
186 static struct HEADINFO
*Nhead_map
[NUM_MFONTS
][CHARS_IN_FONT
];
188 /* This is used to remember what beamstyle and/or timeunit values were
189 * associated with time signatures. This is really only needed during parse,
190 * and then only if user specifies beamstyle or timeunit somewhere.
192 static struct Sym
*Time_map
[SYMTBLSIZE
];
194 /* Internal name for tag used to store the virtual _win coords for blocks */
195 char Blockwin
[] = "~blockwin";
196 /* This points to where in the symbol table
197 * to save the pointer to the coord array for blocks.
198 * Having this pointer is a speed optimization,
199 * to save us from having to look it up every time. */
200 float **Blockcoord_p_p
;
203 /* static functions */
204 static struct GRID
*parse_grid
P((char *griddef
));
205 static struct Sym
*add2tbl
P((char *symname
, struct Sym
**table
));
206 static struct Sym
*findSym
P((char *symname
, struct Sym
**table
));
207 static int hash
P((char *string
));
208 static int coordhash
P((float *key
));
209 static void rep_ref
P((float **old_ref_p_p
, float **new_ref_p_p
));
210 static void delete_coord
P((float *coord_p
));
211 static int is_valid_notehead
P((int ch
, int font
));
212 static void add_head
P((char *name
, struct HEADINFO
*info_p
));
215 /* size of Coordinfo hash table. Should be prime */
216 #define COORDTBLSIZE (271)
218 static struct COORD_INFO
*Coord_table
[COORDTBLSIZE
];
221 /* Add predefined values to the symbol tables */
230 addsym("_page", _Page
, CT_BUILTIN
);
231 addsym("_cur", _Cur
, CT_BUILTIN
);
233 /* Blocks each have their own virtual _win,
234 * so we put a placeholder in the symbol table
235 * and save a pointer to its tag's coord pointer.
236 * Then we can update the coords via set_win_coords().
238 addsym(Blockwin
, 0, CT_BUILTIN
);
239 sym_p
= findSym(Blockwin
, Tag_table
);
241 pfatal("couldn't find %s coord right after inserting it!",
244 Blockcoord_p_p
= &(sym_p
->val
.coordlist_p
);
246 /* Put the predefined notehead shapes into table. */
247 for (i
= 0; Predef_headinfo
[i
].name
!= 0; i
++) {
248 add_head(Predef_headinfo
[i
].name
, &(Predef_headinfo
[i
].info
));
251 /* Put the predefined head shapes in the shapes table */
252 for (i
= 0; Predef_shape_names
[i
].clan_name
!= 0; i
++) {
253 add_shape(Predef_shape_names
[i
].clan_name
,
254 Predef_shape_names
[i
].member_names
);
259 /* add a symbol to the table if not already there and fill in its coordlist_p
260 * in symbol table. */
263 addsym(symname
, coordlist_p
, coordtype
)
265 char *symname
; /* what to add to table */
266 float *coordlist_p
; /* set of 13 coordinates associated with symbol */
267 int coordtype
; /* CT_BAR, CT_GRPSYL, etc */
270 struct Sym
*sym_p
; /* pointer to info about symbol in hash tbl */
273 debug(4, "addsym(symname=%s coordlist_p=0x%lx, coordtype=%d)",
274 symname
, coordlist_p
, coordtype
);
276 /* find in symbol table or add if not yet there */
277 sym_p
= add2tbl(symname
, Tag_table
);
279 /* fill in coordlist pointer */
280 sym_p
->val
.coordlist_p
= coordlist_p
;
282 /* put entry in coord table */
283 add_coord(coordlist_p
, coordtype
);
287 /* add a symbol to the specified hash table */
290 add2tbl(symname
, table
)
292 char *symname
; /* what to add */
293 struct Sym
**table
; /* which table to add to */
297 int h
; /* hash number of symbol */
299 if ((sym_p
= findSym(symname
, table
)) == (struct Sym
*) 0) {
301 /* not in list before. Add it */
302 MALLOC(Sym
, sym_p
, 1);
303 MALLOCA(char, sym_p
->symname
, strlen(symname
) + 1);
304 (void) strcpy(sym_p
->symname
, symname
);
307 /* link onto front of list off hash table */
308 sym_p
->next
= table
[h
];
315 /* given a symbol name, return pointer to its symbol table entry, or NULL
319 findSym(symname
, table
)
321 char *symname
; /* which symbol to look for */
322 struct Sym
**table
; /* which table to look in */
325 struct Sym
*sym_p
; /* symbol info currently being checked
326 * for match with symname */
327 int h
; /* hash number */
331 /* go down the linked list (of hash collisions) off the table
332 * searching for match */
333 for (sym_p
= table
[h
]; sym_p
!= (struct Sym
*) 0;
334 sym_p
= sym_p
->next
) {
335 if (strcmp(sym_p
->symname
, symname
) == 0) {
339 return((struct Sym
*) 0);
343 /* For top/bot/top2/bot2/block we temporarily set the ~blockwin tag to point
344 * to the appropriate blockhead's coord array. Before doing a set_win for
345 * any of those, this function should be called to set things up, and
346 * it should be called again afterwards with 0 to mark we are no longer
351 set_win_coord(coord_p
)
356 *Blockcoord_p_p
= coord_p
;
360 /* Given a tag name, return its value (a pointer to the coordinate array
361 * containing the AX, AY, etc of the variable).
362 * If the tag is not found, an error is printed and 0 is returned.
363 * If the ref_p_p is non-null,
364 * save that value as something that references the tag. That way if the
365 * tag gives moved somewhere else, we can update all the references.
366 * If referencing the value of a coord that can never move (a builtin coord
367 * like _win), ref_p_p may be null.
371 symval(symname
, ref_p_p
)
373 char *symname
; /* which symbol to look up */
374 float **ref_p_p
; /* address of reference to the tag */
377 struct Sym
*sym_p
; /* symbol info currently being checked */
380 /* _win is a special case: its actual symbol depends on context */
381 if (strcmp(symname
, "_win") == 0) {
382 /* If we're inside a block, use its coord,
383 * else use the global _Win */
384 if (*Blockcoord_p_p
!= 0) {
385 return(*Blockcoord_p_p
);
392 /* find the symbol table entry */
393 if ((sym_p
= findSym(symname
, Tag_table
)) != (struct Sym
*) 0) {
394 if (sym_p
->val
.coordlist_p
!= (float *) 0) {
395 /* save reference information */
397 struct COORD_INFO
*coordinfo_p
;
398 struct COORD_REF
*ref_p
;
399 CALLOC(COORD_REF
, ref_p
, 1);
400 ref_p
->ref_p_p
= ref_p_p
;
401 /* link onto reference list */
402 coordinfo_p
= find_coord(sym_p
->val
.coordlist_p
);
403 ref_p
->next
= coordinfo_p
->ref_list_p
;
404 coordinfo_p
->ref_list_p
= ref_p
;
406 return(sym_p
->val
.coordlist_p
);
410 /* whoops! not in table */
411 l_yyerror(Curr_filename
, yylineno
,
412 "reference to uninitialized location tag '%s'",
418 /* add item to grid table if not already there. */
421 add_grid(name
, griddef
)
423 char *name
; /* chord name */
424 char *griddef
; /* user's definition of the grid */
427 char *internal_name
; /* internal format name */
428 char *grid_name
; /* permanent copy of internal_name */
429 char *symname
; /* ASCII-ized name */
430 char *key
; /* permanent copy of symname, key into hash tbl */
435 /* if table doesn't exist yet, create it */
436 if (Grid_table
== 0) {
439 MALLOCA(struct Sym
*, Grid_table
, SYMTBLSIZE
);
440 for (g
= 0; g
< SYMTBLSIZE
; g
++) {
445 /* Do all the transforms to get into internal form with
446 * accidentals as music characters. For historical reasons,
447 * this has to be done in several steps, in just the right order. */
448 internal_name
= modify_chstr(name
, TM_CHORD
);
449 internal_name
= fix_string(internal_name
, Score
.font
, Score
.size
,
450 Curr_filename
, yylineno
);
451 /* convert accidentals, then convert to all ASCII */
452 grid_name
= tranchstr(internal_name
, -1);
453 symname
= ascii_str(grid_name
, YES
, NO
, TM_CHORD
);
455 if (strlen(symname
) == 0) {
456 yyerror("empty grid name not allowed");
460 if ((sym_p
= findSym(symname
, Grid_table
)) != 0) {
461 l_warning(Curr_filename
, yylineno
,
462 "duplicate definition of grid for '%s', discarding previous",
464 /* discard old definition, use new one */
465 if (sym_p
->val
.grid_p
!= 0) {
466 if (sym_p
->val
.grid_p
->name
!= 0) {
467 FREE(sym_p
->val
.grid_p
->name
);
469 FREE(sym_p
->val
.grid_p
);
470 sym_p
->val
.grid_p
= 0;
472 key
= sym_p
->symname
;
475 /* make permanent copy of key */
476 MALLOCA(char, key
, strlen(symname
) + 1);
477 (void) strcpy(key
, symname
);
480 if ((grid_p
= parse_grid(griddef
)) != 0) {
481 /* it's good, so put in hash table */
482 sym_p
= add2tbl(key
, Grid_table
);
484 /* fill in the name and grid pointer */
485 grid_p
->name
= grid_name
;
486 sym_p
->val
.grid_p
= grid_p
;;
488 /* buffer--2 digits and a space for each string, plus null */
489 char fretlist
[3 * MAXTABLINES
+ 1];
491 for (f
= 0; f
< grid_p
->numstr
; f
++) {
492 (void) sprintf(fretlist
+ 3 * f
, "%3d",
493 grid_p
->positions
[f
]);
495 fretlist
[sizeof(fretlist
) - 1] = '\0';
496 debug(4, "added grid '%s' key '%s' with %d strings: %s curve %d to %d",
498 grid_p
->numstr
, fretlist
,
499 grid_p
->curvel
, grid_p
->curver
);
505 /* take the user's grid definition, like "2 (3 1) o x -"
506 * and populate a GRID struct with the info. If not parse-able,
512 char *griddef
; /* user's definition of the grid */
515 struct GRID
*grid_p
; /* the malloc-ed grid to populate & return */
519 MALLOC(GRID
, grid_p
, 1);
521 grid_p
->curvel
= grid_p
->curver
= 0;
523 /* the +2 is to skip the font/size bytes */
524 for (griddef
+= 2; *griddef
!= '\0' && error
== NO
; griddef
++) {
525 /* init to something illegal */
528 while (*griddef
== ' ' || *griddef
== '\t') {
531 if (*griddef
== '\0') {
535 if ( isdigit(*griddef
) ) {
536 value
= *griddef
- '0';
537 if (isdigit(*(griddef
+1))) {
540 value
+= *griddef
- '0';
543 yyerror("fret of zero not allowed; use 'o' for open or '-' for nothing");
547 else if (*griddef
== '(') {
548 if (grid_p
->curvel
!= 0) {
549 yyerror("only one '(' allowed in grid definition");
553 grid_p
->curvel
= grid_p
->numstr
+ 1;
556 else if (*griddef
== ')') {
557 if (grid_p
->curver
!= 0) {
558 yyerror("only one ')' allowed in grid definition");
561 else if (grid_p
->curvel
== 0) {
562 yyerror("missing '(' in grid definition");
565 else if (grid_p
->curvel
== grid_p
->numstr
) {
566 yyerror("curve in grid definition must encompass more than one string");
570 grid_p
->curver
= grid_p
->numstr
;
573 else if (*griddef
== 'o') {
576 else if (*griddef
== 'x') {
579 else if (*griddef
== '-') {
583 yyerror("invalid grid specification");
589 /* We found a fret value (not parentheses).
590 * Next better be white space sort of thing */
593 if (c
!= ' ' && c
!= '\t' && c
!= '(' && c
!= ')'
595 yyerror("missing white space in grid specification");
598 else if (grid_p
->numstr
< MAXTABLINES
) {
599 /* all is well; save info for current string */
600 grid_p
->positions
[grid_p
->numstr
] = value
;
604 yyerror("too many strings in grid specification");
610 if (error
== NO
&& grid_p
->curvel
!= 0 && grid_p
->curver
== 0) {
611 yyerror("missing ')' in grid specification");
615 if (grid_p
->numstr
< 1) {
616 yyerror("grid must include at least one string");
620 /* every curve must have at least one real fret in it */
621 if (grid_p
->curvel
!= 0) {
623 /* the -1 is because curves start at 1, but positions at 0 */
624 for (s
= grid_p
->curvel
- 1; s
<= grid_p
->curver
- 1; s
++) {
625 if (grid_p
->positions
[s
] > 0) {
629 if (s
== grid_p
->curver
) {
630 yyerror("grid curve must include at least one fret number, not just x, o, and -");
644 /* Locate a named GRID in the grid hash table. Returns 0 if not found,
645 * else pointer to desired GRID. */
650 char *name
; /* find GRID with this chord name */
658 if (Grid_table
== 0) {
659 /* no grids defined */
660 return((struct GRID
*) 0);
663 ascii_name
= ascii_str(name
, YES
, NO
, TM_CHORD
);
664 /* Chord names in STUFF have a space padding at the end of them
665 * unless they are in a box or circle, so strip that off for matching
666 * the name. We store the grid name without the space, because for
667 * grid printing, we want the name centered without end padding. */
668 length
= strlen(ascii_name
);
669 first_char
= ((int)*(name
+2)) & 0xff;
670 if (first_char
!= STR_BOX
&& first_char
!= STR_CIR
671 && ascii_name
[length
-1] == ' ') {
672 ascii_name
[length
-1] = '\0';
676 sym_p
= findSym(ascii_name
, Grid_table
);
678 return (sym_p ? sym_p
->val
.grid_p
: 0);
682 /* Function to iterate through all the GRIDs. First time, call it with
683 * argument of zero, and it returns the first GRID it finds. To walk
684 * through the list, call it repeatedly, each time passing the GRID
685 * you got the last time. When you get back a zero, the list is done.
686 * Restrictions: you must either call with zero or the last one you got.
687 * You can't remember some previous value and use that to try to jump
688 * to elsewhere on the list, or have multiple walks going on at once.
689 * Caller should assume values are returned in arbitrary order.
698 static int tbl_index
= -1;
699 static struct Sym
*last_sym_p
= 0; /* remember where we were the
700 * last time we were called */
703 /* starting at beginning */
707 else if (last_sym_p
== 0 || grid_p
!= last_sym_p
->val
.grid_p
) {
708 pfatal("nextgrid called incorrectly");
711 /* if there is another on the current collision chain, use that */
712 if (last_sym_p
!= 0) {
713 last_sym_p
= last_sym_p
->next
;
716 /* if none, either if just starting, or if ran off the end
717 * of a collision chain, find next chain. */
718 if (last_sym_p
== 0) {
719 for (tbl_index
++; tbl_index
< SYMTBLSIZE
; tbl_index
++) {
720 if (Grid_table
[tbl_index
] != 0) {
721 /* found a populated chain */
722 last_sym_p
= Grid_table
[tbl_index
];
728 return(last_sym_p
== 0 ?
0 : last_sym_p
->val
.grid_p
);
732 /* return a hash number from a string. XOR the bytes together */
737 char *string
; /* hash this string */
740 int h
; /* hash number */
742 for (h
= 0; *string
!= '\0'; string
++) {
745 /* return hash number between 0 and 127 */
750 /* add entry to COORD_INFO table */
753 add_coord(coordlist_p
, coordtype
)
755 float *coordlist_p
; /* address of set of 13 coordinates to add to tbl */
756 int coordtype
; /* CT_GRPSYL, etc */
759 struct COORD_INFO
*new_p
; /* space for saving coord info */
760 int h
; /* hash number */
763 /* if not already in table, add it */
764 if (find_coord(coordlist_p
) == (struct COORD_INFO
*) 0) {
766 /* get space, fill in coord type, and link into hash table */
767 CALLOC(COORD_INFO
, new_p
, 1);
769 new_p
->coordlist_p
= coordlist_p
;
770 new_p
->flags
= (short) coordtype
;
772 h
= coordhash(coordlist_p
);
773 new_p
->next
= Coord_table
[h
];
774 Coord_table
[h
] = new_p
;
779 /* Given an address of an array of floats (a coordinate array), return a hash
780 * number, which is modulo of the Coord_table table size */
785 float *key
; /* hash this number */
788 return ((int) ( (unsigned long) key
% COORDTBLSIZE
));
792 /* Given a coordinate (pointer to array of floats), return the location of
793 * the info about it in the Coord_table, or 0 if not in table */
798 float *key
; /* look up this key in hash table */
801 int h
; /* hash number */
802 struct COORD_INFO
*c_p
;
805 /* search hash table for matching entry */
807 for (c_p
= Coord_table
[h
]; c_p
!= (struct COORD_INFO
*) 0;
809 if (key
== c_p
->coordlist_p
) {
813 return( (struct COORD_INFO
*) 0);
817 /* Given an existing INPCOORD, and a new INPCOORD that is to replace it,
818 * adjust any tag references (hor_p or vert_p) to point to the new one. */
821 rep_inpcoord(old_inpcoord_p
, new_inpcoord_p
)
823 struct INPCOORD
*old_inpcoord_p
;
824 struct INPCOORD
*new_inpcoord_p
;
827 rep_ref( &(old_inpcoord_p
->hor_p
), &(new_inpcoord_p
->hor_p
) );
828 rep_ref( &(old_inpcoord_p
->vert_p
), &(new_inpcoord_p
->vert_p
) );
832 /* Given an existing reference to a tag in an INPCOORD, replace that
833 * reference with the new reference. This is for when transferring a
834 * temporary INPCOORD to a permanent one.
838 rep_ref(old_ref_p_p
, new_ref_p_p
)
844 struct COORD_INFO
*coordinfo_p
;
845 struct COORD_REF
*ref_p
;
847 if (*old_ref_p_p
== 0) {
848 /* This can happen if user references uninitialized tag.
849 * We already give error message elsewhere for that. */
852 if (*new_ref_p_p
== 0) {
853 pfatal("attempt to replace tag reference with null.");
857 /* Find this information about the coordinate */
858 if ((coordinfo_p
= find_coord(*old_ref_p_p
)) == 0) {
859 /* Must have been earlier user error. */
863 /* Find any references matching the old and update them.
864 * Really should be only one, but seems safer to check all.
866 for (ref_p
= coordinfo_p
->ref_list_p
; ref_p
!= 0; ref_p
= ref_p
->next
) {
867 if (ref_p
->ref_p_p
== old_ref_p_p
) {
868 ref_p
->ref_p_p
= new_ref_p_p
;
874 /* Given an existing coord array address and an address it is being moved to,
875 * update all references to the old to point to the new, and update our
876 * hash table to insert the old and delete the old.
880 upd_ref(oldcoord_p
, newcoord_p
)
886 struct COORD_INFO
*coordinfo_p
; /* existing info about oldcoord_p */
887 struct COORD_INFO
*newcoordinfo_p
; /* for info about newcoord_p */
888 struct COORD_REF
*ref_p
; /* for walking through ref list */
890 if ((coordinfo_p
= find_coord(oldcoord_p
)) == 0) {
891 /* apparently no tags associated with this coord array */
894 /* update all the references to the tag with the new value */
895 for (ref_p
= coordinfo_p
->ref_list_p
; ref_p
!= 0; ref_p
= ref_p
->next
) {
896 *(ref_p
->ref_p_p
) = newcoord_p
;
899 /* Now need to create new entry for the new coord, and delete old */
900 add_coord(newcoord_p
, coordinfo_p
->flags
);
901 /* Append reference list to new coord info */
902 if ((newcoordinfo_p
= find_coord(newcoord_p
)) != 0) {
903 /* Should always get here; the 'if' is to just paranoia
904 * to be sure to avoid null pointer deference. */
905 /* If coord already existed before, because one coord is
906 * being combined with another, we want to concatenate the
907 * reference list, so find end to append to. */
908 struct COORD_REF
**append_p_p
;
909 for (append_p_p
= &(newcoordinfo_p
->ref_list_p
);
911 append_p_p
= &((*append_p_p
)->next
)) {
915 *append_p_p
= coordinfo_p
->ref_list_p
;
916 coordinfo_p
->ref_list_p
= 0;
918 delete_coord(oldcoord_p
);
922 /* Delete the given coordinate information */
925 delete_coord(coord_p
)
930 int h
; /* hash number */
931 struct COORD_INFO
**c_p_p
;
933 /* search hash table for matching entry and delete it */
934 h
= coordhash(coord_p
);
935 for (c_p_p
= &(Coord_table
[h
]); *c_p_p
!= 0; *(c_p_p
) = (*c_p_p
)->next
) {
936 if ((*c_p_p
)->coordlist_p
== coord_p
) {
937 struct COORD_INFO
* to_delete_p
;
938 to_delete_p
= *c_p_p
;
939 *c_p_p
= (*c_p_p
)->next
;
947 /* Given a shape name and string containing the 4 note heads to use for it,
948 * as would exist in a line of "headshapes" context, parse the
949 * string with the noteheads and save all the information
950 * in the shapes hash table.
954 add_shape(name
, shapes
)
956 char *name
; /* name of the list of shapes */
957 char *shapes
; /* list of 4 shape names */
960 struct Sym
*sym_p
; /* where added into Shape_table */
961 struct HDSHAPEINFO
*shapeinfo_p
;/* internal format for shape data */
962 int i
; /* index through shapes */
963 int d
; /* index through durations */
964 int nameleng
; /* length of one name in shapes list */
965 char namebuff
[40]; /* one of the names in shapes list.
966 * Needs to be big enough to hold longer
967 * name of any valid note head character. */
968 char ch
; /* music character corresponding to head name */
969 int font
; /* which font FONT_MUSIC* */
970 int size
; /* not really needed here, but function we
972 short flips
; /* YES if stem down uses upside down version */
974 debug(4, "add_shape name='%s' shapes='%s'", name
, shapes
);
976 /* Add to symbol table */
977 sym_p
= add2tbl(name
, Shape_table
);
978 MALLOC(HDSHAPEINFO
, shapeinfo_p
, 1);
979 sym_p
->val
.shapeinfo_p
= shapeinfo_p
;
981 /* Allocate an index and fill in the index-to-info mapping array */
982 shapeinfo_p
->index
= ++Shape_entries
;
983 if (Shape_entries
>= MAX_SHAPE_ENTRIES
) {
984 yyerror("Too many headshapes");
988 Shape_map
[Shape_entries
] = sym_p
;
991 /* Parse the list of 4 shapes and save their info */
993 for (d
= i
= 0; shapes
[i
] != '\0'; ) {
994 /* Skip white space */
995 if (isspace(shapes
[i
])) {
1000 /* Make sure user didn't give too many shapes */
1001 if (d
>= MAX_SHAPE_DURS
) {
1002 l_yyerror(Curr_filename
, yylineno
,
1003 "Too many shapes for headshape '%s' (%d expected, %d found)\n",
1004 name
, MAX_SHAPE_DURS
, d
);
1008 /* Check if stem down gets a flipped character */
1009 if (shapes
[i
] == 'u' && shapes
[i
+1] == '?') {
1017 /* get copy of current head name, and look up its character */
1018 nameleng
= strcspn(shapes
+ i
, " \t\r\n");
1019 /* leave room for null and 'u' for upsidedown */
1020 if (nameleng
> sizeof(namebuff
) - 2) {
1021 ufatal("head shape name too long");
1023 if (nameleng
== 0 && flips
== YES
) {
1024 l_yyerror(Curr_filename
, yylineno
,
1025 "'u?' must be followed immediately by a note head character name");
1028 strncpy(namebuff
, shapes
+ i
, nameleng
);
1029 namebuff
[nameleng
] = '\0';
1030 ch
= mc_name2num(namebuff
, Curr_filename
, yylineno
, &size
, &font
);
1031 if (is_valid_notehead(ch
, font
) == NO
) {
1032 l_yyerror(Curr_filename
, yylineno
,
1033 "'%s' is not a valid note head name", namebuff
);
1037 shapeinfo_p
->headchar
[STEMINDEX(UP
)][d
] = ch
;
1038 shapeinfo_p
->headfont
[STEMINDEX(UP
)][d
] = font
;
1040 /* If flips, get upside down version. Else use same again */
1043 strncpy(namebuff
+ 1, shapes
+ i
, nameleng
);
1044 namebuff
[nameleng
+1] = '\0';
1045 ch
= mc_name2num(namebuff
, Curr_filename
, yylineno
, &size
, &font
);
1046 if (is_valid_notehead(ch
, font
) == NO
) {
1047 l_yyerror(Curr_filename
, yylineno
,
1048 "'%s' is not a valid note head name", namebuff
);
1052 shapeinfo_p
->headchar
[STEMINDEX(DOWN
)][d
] = ch
;
1053 shapeinfo_p
->headfont
[STEMINDEX(DOWN
)][d
] = font
;
1055 /* Prepare for next in the list, if any */
1059 if (d
< MAX_SHAPE_DURS
) {
1060 l_yyerror(Curr_filename
, yylineno
,
1061 "Too few shapes for headshape '%s' (%d expected, %d found)\n",
1062 name
, MAX_SHAPE_DURS
, d
);
1067 /* Given a head shape index, stemdir, and basictime, return the notehead
1068 * character to use and (via font_p pointer)
1069 * which music font that notehead character is in.
1073 nheadchar(headshape
, basictime
, stemdir
, font_p
)
1075 int headshape
; /* head shape index */
1076 int basictime
; /* 8 for eighth, 2 for half, etc */
1077 int stemdir
; /* UP or DOWN */
1078 int *font_p
; /* FONT_MUSIC* is returned here */
1081 struct Sym
*info_p
; /* shape to character map */
1082 int dir
; /* first index into headchar */
1083 int dur
; /* second index into headchar */
1085 if (headshape
== HS_UNKNOWN
|| headshape
> Shape_entries
) {
1086 pfatal("illegal headshape index to nheadchar (%d)", headshape
);
1089 info_p
= Shape_map
[headshape
];
1091 dir
= STEMINDEX(stemdir
);
1092 dur
= HCDUR(basictime
);
1093 *font_p
= info_p
->val
.shapeinfo_p
->headfont
[dir
][dur
];
1094 return(info_p
->val
.shapeinfo_p
->headchar
[dir
][dur
]);
1098 /* Given a head shape name, return the internal index number we use
1099 * to refer to that shape.
1103 get_shape_num(shapename
)
1110 if ((sym_p
= findSym(shapename
, Shape_table
)) != 0) {
1111 return(sym_p
->val
.shapeinfo_p
->index
);
1117 /* Return YES if given character is a valid note head character, else NO */
1120 is_valid_notehead(ch
, font
)
1122 int ch
; /* character code */
1123 int font
; /* FONT_MUSIC* */
1126 if ( IS_MUSIC_FONT(font
) == NO
|| ch
< 0 || ch
>= CHARS_IN_FONT
) {
1127 /* If caller passes us the return from mc_name2num(),
1128 * that could return BAD_CHAR, so we don't pfatal here,
1129 * but do return right away, so we don't do an illegal
1130 * array index below.
1134 return (Nhead_map
[FONTINDEX(font
)][CHARINDEX(ch
)] == 0 ? NO
: YES
);
1138 /* Save note head information in table */
1139 /** If we allow users to supply their own some day,
1140 * would need a function that allocates and fills in a HEADINFO,
1141 * and then calls this one. */
1144 add_head(name
, info_p
)
1146 char *name
; /* music character name */
1147 struct HEADINFO
*info_p
; /* char/font/stem offset */
1153 sym_p
= add2tbl(name
, Nhead_table
);
1154 sym_p
->val
.noteinfo_p
= info_p
;
1156 /* Fill in reverse lookup map */
1157 Nhead_map
[FONTINDEX(info_p
->font
)][CHARINDEX(info_p
->ch
)] = info_p
;
1161 /* Given a note head character and stem direction,
1162 * return the y offset for the stem to end, in stepsizes.
1166 stem_yoff(headch
, font
, stemdir
)
1168 int headch
; /* music character code */
1169 int font
; /* FONT_MUSIC* */
1170 int stemdir
; /* UP or DOWN */
1173 struct HEADINFO
*info_p
;
1175 if ( IS_MUSIC_FONT(font
) == NO
|| headch
< 0 || headch
>= CHARS_IN_FONT
) {
1176 pfatal("invalid argument: stem_yoffset(%d, %d, stemdir)",
1177 headch
, font
, stemdir
);
1179 info_p
= Nhead_map
[FONTINDEX(font
)][CHARINDEX(headch
)];
1181 pfatal("No notehead map for ch=%d, font=%d", headch
, font
);
1183 if (stemdir
== UNKNOWN
) {
1184 pfatal("stem_yoff called with unknown stemdir");
1186 return(info_p
->ystem_off
[STEMINDEX(stemdir
)]);
1190 /* This should be called when an SSV has been collected by the user.
1191 * If the user set beamstyle and/or timeunit in the SSV,
1192 * create a mapping between the current time signature and that beamstyle
1193 * and/or timeunit, so that if the user later sets the same time signature,
1194 * they don't have to set the other things too.
1195 * If they set time signature, see if we have a mapping
1196 * for that time signature. If so, set the beamstyles and timeunits
1197 * from that mapping.
1201 remember_tsig_params(mll_p
)
1203 struct MAINLL
*mll_p
; /* contains SSV */
1206 struct SSV
*ssv_p
; /* the SSV to process */
1207 char *timesig
; /* current time signature representation */
1208 struct Sym
*entry
; /* entry in time sig info mapping table */
1211 if (mll_p
->str
!= S_SSV
) {
1212 pfatal("remember_tsig_params got bad str value %d", mll_p
->str
);
1214 ssv_p
= mll_p
->u
.ssv_p
;
1216 if (ssv_p
->used
[TIME
] == NO
&& ssv_p
->used
[BEAMSTLIST
] == NO
&&
1217 ssv_p
->used
[TIMEUNIT
] == NO
) {
1218 /* nothing of interest in this SSV */
1222 /* If user set time signature in this SSV, that's the time sig
1223 * of interest, otherwise use the current time signature */
1224 timesig
= (ssv_p
->used
[TIME
] == YES ? ssv_p
->timerep
: Score
.timerep
);
1225 if ((entry
= findSym(timesig
, Time_map
)) == 0) {
1226 entry
= add2tbl(timesig
, Time_map
);
1227 /* We'll only allocate the actual table if user gives a
1228 * beamstyle or timeunit somewhere. If they never do,
1229 * this will avoid wasting memory.
1231 entry
->val
.ssvtables_p
= 0;
1234 /* If beamstyle or timeunit are set in this SSV, associate them
1235 * with the current time signature. */
1236 if (ssv_p
->used
[BEAMSTLIST
] == YES
) {
1237 if (entry
->val
.ssvtables_p
== 0) {
1238 CALLOC(SSVTABLES
, entry
->val
.ssvtables_p
, 1);
1240 /* Note that when staffno and voiceno are zero,
1241 * that's actually a score entry, and when voiceno is zero,
1242 * but staffno is non-zero, that is actually a staff entry. */
1243 entry
->val
.ssvtables_p
->beamstyle_table
[ssv_p
->staffno
][ssv_p
->voiceno
] = ssv_p
;
1245 if (ssv_p
->used
[TIMEUNIT
] == YES
) {
1246 if (entry
->val
.ssvtables_p
== 0) {
1247 CALLOC(SSVTABLES
, entry
->val
.ssvtables_p
, 1);
1249 entry
->val
.ssvtables_p
->timeunit_table
[ssv_p
->staffno
][ssv_p
->voiceno
] = ssv_p
;
1252 /* If time signature is set in this SSV, see if we have any
1253 * beamstyles or timeunits associated with that time signature.
1254 * If so, restore their values. */
1255 if (ssv_p
->used
[TIME
] == YES
&& entry
->val
.ssvtables_p
!= 0) {
1256 /* Make new SSVs and copy the relevant fields for any
1257 * remembered beamstyles and/or timesunits associated
1258 * with this time signature. */
1259 struct SSV
*beamstyle_ssv_p
; /* SSV having beamstyle info */
1260 struct SSV
*timeunit_ssv_p
; /* SSV having timeunit info */
1261 struct MAINLL
*mll_ssv_p
; /* new SSV to add to list */
1262 struct SSV
*nssv_p
; /* new SSV to add to list */
1266 /* Check all SSV contexts. The [0][0] entry is for Scoreo * The rest of row [0] is unused.
1267 * The [0] column is for staffs, for s > 0.
1269 for (s
= 0; s
<= MAXSTAFFS
; s
++) {
1270 for (v
= 0; v
<= MAXVOICES
; v
++) {
1272 /* Check if we need to create an SSV for
1273 * this staff/voice */
1274 beamstyle_ssv_p
= entry
->val
.ssvtables_p
->beamstyle_table
[s
][v
];
1275 timeunit_ssv_p
= entry
->val
.ssvtables_p
->timeunit_table
[s
][v
];
1276 if (beamstyle_ssv_p
== 0 &&
1277 timeunit_ssv_p
== 0) {
1278 /* nothing to do for this one */
1282 /* If both saved SSVs are either zero or
1283 * the same SSV as where the time was just
1284 * set, no need to make another SSV */
1285 if ( (beamstyle_ssv_p
== 0 ||
1286 beamstyle_ssv_p
== ssv_p
) &&
1287 (timeunit_ssv_p
== 0 ||
1288 timeunit_ssv_p
== ssv_p
) ) {
1292 /* need to create an SSV */
1293 mll_ssv_p
= newMAINLLstruct(S_SSV
, -1);
1294 insertMAINLL(mll_ssv_p
, mll_p
);
1297 /* populate the new SSV */
1298 nssv_p
= mll_ssv_p
->u
.ssv_p
;
1299 if (beamstyle_ssv_p
!= 0) {
1300 nssv_p
->nbeam
= beamstyle_ssv_p
->nbeam
;
1301 nssv_p
->beamstlist
= beamstyle_ssv_p
->beamstlist
;
1302 nssv_p
->beamrests
= beamstyle_ssv_p
->beamrests
;
1303 nssv_p
->beamspaces
= beamstyle_ssv_p
->beamspaces
;
1304 nssv_p
->nsubbeam
= beamstyle_ssv_p
->nsubbeam
;
1305 nssv_p
->subbeamstlist
= beamstyle_ssv_p
->subbeamstlist
;
1306 nssv_p
->used
[BEAMSTLIST
] = YES
;
1308 if (timeunit_ssv_p
!= 0) {
1309 nssv_p
->timeunit
= timeunit_ssv_p
->timeunit
;
1310 nssv_p
->used
[TIMEUNIT
] = YES
;
1313 /* fill in the SSV header */
1315 nssv_p
->context
= C_VOICE
;
1318 /* The [s][0] entry is for staff s
1320 nssv_p
->context
= C_STAFF
;
1323 /* The [0][0] entry is actually score */
1324 nssv_p
->context
= C_SCORE
;
1326 nssv_p
->staffno
= s
;
1327 nssv_p
->voiceno
= v
;