chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / symtbl.c
1
2 /* Copyright (c) 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006 by Arkkra Enterprises */
3 /* All rights reserved */
4
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.
12  */
13
14 #include "defines.h"
15 #include "structs.h"
16 #include "globals.h"
17
18
19 /* shapes for quarter and shorter, half, whole, double whole */
20 #define MAX_SHAPE_DURS  (4)
21 /* UP and DOWN */
22 #define MAX_STEM_DIRS   (2)
23
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)
33
34 struct HDSHAPEINFO {
35         /* We give each headshape instance a unique index number,
36          * as a compact way to refer to it. */
37         short   index;
38
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).
42          */
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];
47 };
48
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.
52  */
53 #define MAX_SHAPE_ENTRIES       (32)
54
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. */
58 struct SHAPENAMES {
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" },
74         { 0, 0 }
75 };
76
77 /* Information about characters that are allowed to be noteheads */
78 struct HEADINFO {
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 */
82 };
83
84 /* Predefined note head music characters and their attributes. */
85 struct HEADDATA {
86         char *name;
87         struct HEADINFO info;
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 } } }
120 };
121
122 /*
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.
125  *
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.
134  */
135 struct SSVTABLES {
136         struct SSV *beamstyle_table[MAXSTAFFS+1][MAXVOICES+1];
137         struct SSV *timeunit_table[MAXSTAFFS+1][MAXVOICES+1];
138 };
139
140
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 */
147 struct Sym {
148         char    *symname;
149         union {
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;
158         } val;
159         struct Sym *next;               /* for collision chain off hash table */
160 };
161
162 /* symbol hash table size-- if this changes, hash() has to change accordingly */
163 #define SYMTBLSIZE      (128)
164
165 /* this is the symbol table for location tags */
166 static struct Sym *Tag_table[SYMTBLSIZE];
167
168 /* this is the symbol table for guitar grids. It is malloc-ed at runtime
169  * only if needed */
170 static struct Sym **Grid_table;
171
172 /* This is the symbol table for headshapes */
173 static struct Sym *Shape_table[SYMTBLSIZE];
174
175 /* This maps headshape indexes to the corresponding info.
176  * Element 0 is unused, since index 0 means "unknown" shape.
177  */
178 static struct Sym *Shape_map[MAX_SHAPE_ENTRIES];
179 /* How many Shape_map entries are actually used */
180 static short Shape_entries = 0;
181
182 /* This is the symbol table for noteheads, to get stem offsets */
183 static struct Sym  *Nhead_table[SYMTBLSIZE];
184
185 /* This maps notehead character codes to the stem offset info */
186 static struct HEADINFO *Nhead_map[NUM_MFONTS][CHARS_IN_FONT];
187
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.
191  */
192 static struct Sym *Time_map[SYMTBLSIZE];
193
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;
201
202
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));
213
214
215 /* size of Coordinfo hash table. Should be prime */
216 #define COORDTBLSIZE  (271)
217
218 static struct COORD_INFO *Coord_table[COORDTBLSIZE];
219 \f
220
221 /* Add predefined values to the symbol tables */
222
223 void
224 init_symtbl()
225
226 {
227         struct Sym *sym_p;
228         int i;
229
230         addsym("_page", _Page, CT_BUILTIN);
231         addsym("_cur", _Cur, CT_BUILTIN);
232
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().
237          */
238         addsym(Blockwin, 0, CT_BUILTIN);
239         sym_p = findSym(Blockwin, Tag_table);
240         if (sym_p == 0) {
241                 pfatal("couldn't find %s coord right after inserting it!",
242                                                         Blockwin);
243         }
244         Blockcoord_p_p = &(sym_p->val.coordlist_p);
245
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));
249         }
250
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);
255         }
256 }
257 \f
258
259 /* add a symbol to the table if not already there and fill in its coordlist_p
260  * in symbol table. */
261
262 void
263 addsym(symname, coordlist_p, coordtype)
264
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 */
268
269 {
270         struct Sym *sym_p;      /* pointer to info about symbol in hash tbl */
271
272
273         debug(4, "addsym(symname=%s coordlist_p=0x%lx, coordtype=%d)",
274                                         symname, coordlist_p, coordtype);
275
276         /* find in symbol table or add if not yet there */
277         sym_p = add2tbl(symname, Tag_table);
278
279         /* fill in coordlist pointer */
280         sym_p->val.coordlist_p = coordlist_p;
281
282         /* put entry in coord table */
283         add_coord(coordlist_p, coordtype);
284 }
285 \f
286
287 /* add a symbol to the specified hash table */
288
289 static struct Sym *
290 add2tbl(symname, table)
291
292 char *symname;          /* what to add */
293 struct Sym **table;     /* which table to add to */
294
295 {
296         struct Sym *sym_p;
297         int h;                  /* hash number of symbol */
298
299         if ((sym_p = findSym(symname, table)) == (struct Sym *) 0) {
300
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);
305                 h = hash(symname);
306
307                 /* link onto front of list off hash table */
308                 sym_p->next = table[h];
309                 table[h] = sym_p;
310         }
311         return(sym_p);
312 }
313 \f
314
315 /* given a symbol name, return pointer to its symbol table entry, or NULL
316  * if none */
317
318 static struct Sym *
319 findSym(symname, table)
320
321 char *symname;          /* which symbol to look for */
322 struct Sym **table;     /* which table to look in */
323
324 {
325         struct Sym *sym_p;      /* symbol info currently being checked
326                                  * for match with symname */
327         int h;                  /* hash number */
328
329
330         h = hash(symname);
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) {
336                         return(sym_p);
337                 }
338         }
339         return((struct Sym *) 0);
340 }
341 \f
342
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
347  * inside a block.
348  */
349
350 void
351 set_win_coord(coord_p)
352
353 float *coord_p;
354
355 {
356         *Blockcoord_p_p = coord_p;
357 }
358 \f
359
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.
368  */
369
370 float *
371 symval(symname, ref_p_p)
372
373 char *symname;          /* which symbol to look up */
374 float **ref_p_p;        /* address of reference to the tag */
375
376 {
377         struct Sym *sym_p;      /* symbol info currently being checked */
378
379
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);
386                 }
387                 else {
388                         return(_Win);
389                 }
390         }
391         
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 */
396                         if (ref_p_p != 0) {
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;
405                         }
406                         return(sym_p->val.coordlist_p);
407                 }
408         }
409
410         /* whoops! not in table */
411         l_yyerror(Curr_filename, yylineno,
412                         "reference to uninitialized location tag '%s'",
413                         symname);
414         return((float *) 0);
415 }       
416 \f
417
418 /* add item to grid table if not already there. */
419
420 void
421 add_grid(name, griddef)
422
423 char *name;             /* chord name */
424 char *griddef;          /* user's definition of the grid */
425
426 {
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 */
431         struct Sym *sym_p;
432         struct GRID *grid_p;
433
434
435         /* if table doesn't exist yet, create it */
436         if (Grid_table == 0) {
437                 int g;
438
439                 MALLOCA(struct Sym *, Grid_table, SYMTBLSIZE);
440                 for (g = 0; g < SYMTBLSIZE; g++) {
441                         Grid_table[g] = 0;
442                 }
443         }
444
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);
454
455         if (strlen(symname) == 0) {
456                 yyerror("empty grid name not allowed");
457                 return;
458         }
459
460         if ((sym_p = findSym(symname, Grid_table)) != 0) {
461                 l_warning(Curr_filename, yylineno,
462                         "duplicate definition of grid for '%s', discarding previous",
463                         symname);
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);
468                         }
469                         FREE(sym_p->val.grid_p);
470                         sym_p->val.grid_p = 0;
471                 }
472                 key = sym_p->symname;
473         }
474         else {
475                 /* make permanent copy of key */
476                 MALLOCA(char, key, strlen(symname) + 1);
477                 (void) strcpy(key, symname);
478         }
479
480         if ((grid_p = parse_grid(griddef)) != 0) {
481                 /* it's good, so put in hash table */
482                 sym_p = add2tbl(key, Grid_table);
483
484                 /* fill in the name and grid pointer */
485                 grid_p->name = grid_name;
486                 sym_p->val.grid_p = grid_p;;
487                 {
488                         /* buffer--2 digits and a space for each string, plus null */
489                         char fretlist[3 * MAXTABLINES + 1];
490                         int f;
491                         for (f = 0; f < grid_p->numstr; f++) {
492                                 (void) sprintf(fretlist + 3 * f, "%3d",
493                                                          grid_p->positions[f]);
494                         }
495                         fretlist[sizeof(fretlist) - 1] = '\0';
496                         debug(4, "added grid '%s' key '%s' with %d strings: %s curve %d to %d",
497                                         name, key,
498                                         grid_p->numstr, fretlist,
499                                         grid_p->curvel, grid_p->curver);
500                 }
501         }
502 }
503 \f
504
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,
507  * return 0 */
508
509 static struct GRID *
510 parse_grid(griddef)
511
512 char *griddef;  /* user's definition of the grid */
513
514 {
515         struct GRID *grid_p;    /* the malloc-ed grid to populate & return */
516         int error = NO;
517         int value;
518
519         MALLOC(GRID, grid_p, 1);
520         grid_p->numstr = 0;
521         grid_p->curvel = grid_p->curver = 0;
522         grid_p->used = NO;
523         /* the +2 is to skip the font/size bytes */
524         for (griddef += 2; *griddef != '\0' && error == NO; griddef++) {
525                 /* init to something illegal */
526                 value = -1000;
527
528                 while (*griddef == ' ' || *griddef == '\t') {
529                         griddef++;
530                 }
531                 if (*griddef == '\0') {
532                         break;
533                 }
534
535                 if ( isdigit(*griddef) ) {
536                         value = *griddef - '0';
537                         if (isdigit(*(griddef+1))) {
538                                 value *= 10;
539                                 griddef++;
540                                 value += *griddef - '0';
541                         }
542                         if (value == 0) {
543                                 yyerror("fret of zero not allowed; use 'o' for open or '-' for nothing");
544                                 error = YES;
545                         }
546                 }
547                 else if (*griddef == '(') {
548                         if (grid_p->curvel != 0) {
549                                 yyerror("only one '(' allowed in grid definition");
550                                 error = YES;
551                         }
552                         else {
553                                 grid_p->curvel = grid_p->numstr + 1;
554                         }
555                 }
556                 else if (*griddef == ')') {
557                         if (grid_p->curver != 0) {
558                                 yyerror("only one ')' allowed in grid definition");
559                                 error = YES;
560                         }
561                         else if (grid_p->curvel == 0) {
562                                 yyerror("missing '(' in grid definition");
563                                 error = YES;
564                         }
565                         else if (grid_p->curvel == grid_p->numstr) {
566                                 yyerror("curve in grid definition must encompass more than one string");
567                                 error = YES;
568                         }
569                         else {
570                                 grid_p->curver = grid_p->numstr;
571                         }
572                 }
573                 else if (*griddef == 'o') {
574                         value = 0;
575                 }
576                 else if (*griddef == 'x') {
577                         value = -1;
578                 }
579                 else if (*griddef == '-') {
580                         value = -2;
581                 }
582                 else {
583                         yyerror("invalid grid specification");
584                         FREE(grid_p);
585                         return (0);
586                 }
587
588                 if (value >= -2) {
589                         /* We found a fret value (not parentheses).
590                          * Next better be white space sort of thing */
591                         char c;
592                         c = *(griddef + 1);
593                         if (c != ' ' && c != '\t' && c != '(' && c != ')'
594                                                         && c != '\0') {
595                                 yyerror("missing white space in grid specification");
596                                 error = YES;
597                         }
598                         else if (grid_p->numstr < MAXTABLINES) {
599                                 /* all is well; save info for current string */
600                                 grid_p->positions[grid_p->numstr] = value;
601                                 (grid_p->numstr)++;
602                         }
603                         else {
604                                 yyerror("too many strings in grid specification");
605                                 error = YES;
606                         }
607                 }
608         }
609
610         if (error == NO && grid_p->curvel != 0 && grid_p->curver == 0) {
611                 yyerror("missing ')' in grid specification");
612                 error = YES;
613         }
614         
615         if (grid_p->numstr < 1) {
616                 yyerror("grid must include at least one string");
617                 error = YES;
618         }
619
620         /* every curve must have at least one real fret in it */
621         if (grid_p->curvel != 0) {
622                 int s;
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) {
626                                 break;
627                         }
628                 }
629                 if (s == grid_p->curver) {
630                         yyerror("grid curve must include at least one fret number, not just x, o, and -");
631                         error = YES;
632                 }
633         }
634
635         if (error == YES) {
636                 /* clean up */
637                 FREE(grid_p);
638                 grid_p = 0;
639         }
640         return(grid_p);
641 }
642 \f
643
644 /* Locate a named GRID in the grid hash table. Returns 0 if not found,
645  * else pointer to desired GRID. */
646
647 struct GRID *
648 findgrid(name)
649
650 char *name;     /* find GRID with this chord name */
651
652 {
653         struct Sym *sym_p;
654         char *ascii_name;
655         int length;
656         int first_char;
657
658         if (Grid_table == 0) {
659                 /* no grids defined */
660                 return((struct GRID *) 0);
661         }
662
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';
673         }
674
675         /* look it up */
676         sym_p = findSym(ascii_name, Grid_table);
677
678         return (sym_p ? sym_p->val.grid_p : 0);
679 }
680 \f
681
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.
690  */
691
692 struct GRID *
693 nextgrid(grid_p)
694
695 struct GRID *grid_p;
696
697 {
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 */
701
702         if (grid_p == 0) {
703                 /* starting at beginning */
704                 tbl_index = -1;
705                 last_sym_p = 0;
706         }
707         else if (last_sym_p == 0 || grid_p != last_sym_p->val.grid_p) {
708                 pfatal("nextgrid called incorrectly");
709         }
710
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;
714         }
715
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];
723                                 break;
724                         }
725                 }
726         }
727
728         return(last_sym_p == 0 ? 0 : last_sym_p->val.grid_p);
729 }
730 \f
731
732 /* return a hash number from a string. XOR the bytes together */
733
734 static int
735 hash(string)
736
737 char *string;   /* hash this string */
738
739 {
740         int h;  /* hash number */
741
742         for (h = 0; *string != '\0'; string++) {
743                 h ^= *string;
744         }
745         /* return hash number between 0 and 127 */
746         return(h & 0x7f);
747 }
748 \f
749
750 /* add entry to COORD_INFO table */
751
752 void
753 add_coord(coordlist_p, coordtype)
754
755 float *coordlist_p;     /* address of set of 13 coordinates to add to tbl */
756 int coordtype;          /* CT_GRPSYL, etc */
757
758 {
759         struct COORD_INFO *new_p;       /* space for saving coord info */
760         int h;                          /* hash number */
761
762
763         /* if not already in table, add it */
764         if (find_coord(coordlist_p) == (struct COORD_INFO *) 0) {
765
766                 /* get space, fill in coord type, and link into hash table */
767                 CALLOC(COORD_INFO, new_p, 1);
768
769                 new_p->coordlist_p = coordlist_p;
770                 new_p->flags = (short) coordtype;
771
772                 h = coordhash(coordlist_p);
773                 new_p->next = Coord_table[h];
774                 Coord_table[h] = new_p;
775         }
776 }
777 \f
778
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 */
781
782 static int
783 coordhash(key)
784
785 float *key;     /* hash this number */
786
787 {
788         return ((int) ( (unsigned long) key % COORDTBLSIZE));
789 }
790 \f
791
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 */
794
795 struct COORD_INFO *
796 find_coord(key)
797
798 float *key;             /* look up this key in hash table */
799
800 {
801         int h;                  /* hash number */
802         struct COORD_INFO *c_p;
803
804
805         /* search hash table for matching entry */
806         h = coordhash(key);
807         for (c_p = Coord_table[h]; c_p != (struct COORD_INFO *) 0;
808                                                         c_p = c_p->next) {
809                 if (key == c_p->coordlist_p) {
810                         return(c_p);
811                 }
812         }
813         return( (struct COORD_INFO *) 0);
814 }
815 \f
816
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. */
819
820 void
821 rep_inpcoord(old_inpcoord_p, new_inpcoord_p)
822
823 struct INPCOORD *old_inpcoord_p;
824 struct INPCOORD *new_inpcoord_p;
825
826 {
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) );
829         
830 }
831
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.
835  */
836
837 static void
838 rep_ref(old_ref_p_p, new_ref_p_p)
839
840 float **old_ref_p_p;
841 float **new_ref_p_p;
842
843 {
844         struct COORD_INFO *coordinfo_p;
845         struct COORD_REF *ref_p;
846
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. */
850                 return;
851         }
852         if (*new_ref_p_p == 0) {
853                 pfatal("attempt to replace tag reference with null.");
854                 return;
855         }
856
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. */
860                 return;
861         }
862
863         /* Find any references matching the old and update them.
864          * Really should be only one, but seems safer to check all.
865          */
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;
869                 }
870         }
871 }
872 \f
873
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.
877  */
878
879 void
880 upd_ref(oldcoord_p, newcoord_p)
881
882 float * oldcoord_p;
883 float * newcoord_p;
884
885 {
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 */
889
890         if ((coordinfo_p = find_coord(oldcoord_p)) == 0) {
891                 /* apparently no tags associated with this coord array */
892                 return;
893         }
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;
897         }
898
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);
910                                         *append_p_p != 0;
911                                         append_p_p = &((*append_p_p)->next)) {
912                         ;
913                 }
914
915                 *append_p_p = coordinfo_p->ref_list_p;
916                 coordinfo_p->ref_list_p = 0;
917         }
918         delete_coord(oldcoord_p);
919 }
920 \f
921
922 /* Delete the given coordinate information */
923
924 static void
925 delete_coord(coord_p)
926
927 float * coord_p;
928
929 {
930         int h;                  /* hash number */
931         struct COORD_INFO **c_p_p;
932
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;
940                         FREE(to_delete_p);
941                         return;
942                 }
943         }
944 }
945 \f
946
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.
951  */
952
953 void
954 add_shape(name, shapes)
955
956 char *name;     /* name of the list of shapes */
957 char *shapes;   /* list of 4 shape names */
958
959 {
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
971                                  * call expect it */
972         short flips;            /* YES if stem down uses upside down version */
973
974         debug(4, "add_shape name='%s' shapes='%s'", name, shapes);
975
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;
980
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");
985                 return;
986         }
987         else {
988                 Shape_map[Shape_entries] = sym_p;
989         }
990
991         /* Parse the list of 4 shapes and save their info */
992         size = DFLT_SIZE;
993         for (d = i = 0; shapes[i] != '\0';  ) {
994                 /* Skip white space */
995                 if (isspace(shapes[i])) {
996                         i++;
997                         continue;
998                 }
999
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);
1005                         return;
1006                 }
1007
1008                 /* Check if stem down gets a flipped character */
1009                 if (shapes[i] == 'u' && shapes[i+1] == '?') {
1010                         flips = YES;
1011                         i += 2;
1012                 }
1013                 else {
1014                         flips = NO;
1015                 }
1016
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");
1022                 }
1023                 if (nameleng == 0 && flips == YES) {
1024                         l_yyerror(Curr_filename, yylineno,
1025                                 "'u?' must be followed immediately by a note head character name");
1026                         return;
1027                 }
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);
1034                         return;
1035                 }
1036                         
1037                 shapeinfo_p->headchar[STEMINDEX(UP)][d] = ch;
1038                 shapeinfo_p->headfont[STEMINDEX(UP)][d] = font;
1039
1040                 /* If flips, get upside down version. Else use same again */
1041                 if (flips == YES) {
1042                         namebuff[0] = 'u';
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);
1049                                 return;
1050                         }
1051                 }
1052                 shapeinfo_p->headchar[STEMINDEX(DOWN)][d] = ch;
1053                 shapeinfo_p->headfont[STEMINDEX(DOWN)][d] = font;
1054
1055                 /* Prepare for next in the list, if any */
1056                 d++;
1057                 i += nameleng;
1058         }
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);
1063         }
1064 }
1065 \f
1066
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.
1070  */
1071
1072 int
1073 nheadchar(headshape, basictime, stemdir, font_p)
1074
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 */
1079
1080 {
1081         struct Sym *info_p;     /* shape to character map */
1082         int dir;                /* first index into headchar */
1083         int dur;                /* second index into headchar */
1084
1085         if (headshape == HS_UNKNOWN || headshape > Shape_entries) {
1086                 pfatal("illegal headshape index to nheadchar (%d)", headshape);
1087         }
1088
1089         info_p = Shape_map[headshape];
1090
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]);
1095 }
1096 \f
1097
1098 /* Given a head shape name, return the internal index number we use
1099  * to refer to that shape.
1100  */
1101
1102 int
1103 get_shape_num(shapename)
1104
1105 char *shapename;
1106
1107 {
1108         struct Sym *sym_p;
1109
1110         if ((sym_p = findSym(shapename, Shape_table)) != 0) {
1111                 return(sym_p->val.shapeinfo_p->index);
1112         }
1113         return(HS_UNKNOWN);
1114 }
1115 \f
1116
1117 /* Return YES if given character is a valid note head character, else NO */
1118
1119 static int
1120 is_valid_notehead(ch, font)
1121
1122 int ch;         /* character code */
1123 int font;       /* FONT_MUSIC*  */
1124
1125 {
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.
1131                  */
1132                 return(NO);
1133         }
1134         return (Nhead_map[FONTINDEX(font)][CHARINDEX(ch)] == 0 ? NO : YES);
1135 }
1136 \f
1137
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. */
1142
1143 static void
1144 add_head(name, info_p)
1145
1146 char *name;     /* music character name */
1147 struct HEADINFO *info_p;        /* char/font/stem offset */
1148
1149 {
1150         struct Sym *sym_p;
1151
1152         
1153         sym_p = add2tbl(name, Nhead_table);
1154         sym_p->val.noteinfo_p = info_p;
1155
1156         /* Fill in reverse lookup map */
1157         Nhead_map[FONTINDEX(info_p->font)][CHARINDEX(info_p->ch)] = info_p;
1158 }
1159 \f
1160
1161 /* Given a note head character and stem direction,
1162  * return the y offset for the stem to end, in stepsizes.
1163  */
1164
1165 double
1166 stem_yoff(headch, font, stemdir)
1167
1168 int headch;     /* music character code */
1169 int font;       /* FONT_MUSIC*   */
1170 int stemdir;    /* UP or DOWN */
1171
1172 {
1173         struct HEADINFO *info_p;
1174
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);
1178         }
1179         info_p = Nhead_map[FONTINDEX(font)][CHARINDEX(headch)];
1180         if (info_p == 0) {
1181                 pfatal("No notehead map for ch=%d, font=%d", headch, font);
1182         }
1183         if (stemdir == UNKNOWN) {
1184                 pfatal("stem_yoff called with unknown stemdir");
1185         }
1186         return(info_p->ystem_off[STEMINDEX(stemdir)]);
1187 }
1188 \f
1189
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.
1198  */
1199
1200 void
1201 remember_tsig_params(mll_p)
1202
1203 struct MAINLL *mll_p;   /* contains SSV */
1204
1205 {
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 */
1209
1210
1211         if (mll_p->str != S_SSV) {
1212                 pfatal("remember_tsig_params got bad str value %d", mll_p->str);
1213         }
1214         ssv_p = mll_p->u.ssv_p;
1215
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 */
1219                 return;
1220         }
1221
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.
1230                  */
1231                 entry->val.ssvtables_p = 0;
1232         }
1233
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);
1239                 }
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;
1244         }
1245         if (ssv_p->used[TIMEUNIT] == YES) {
1246                 if (entry->val.ssvtables_p == 0) {
1247                         CALLOC(SSVTABLES, entry->val.ssvtables_p, 1);
1248                 }
1249                 entry->val.ssvtables_p->timeunit_table[ssv_p->staffno][ssv_p->voiceno] = ssv_p;
1250         }
1251
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 */
1263                 int s;                          /* staff */
1264                 int v;                          /* voice */
1265
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.
1268                  */
1269                 for (s = 0; s <= MAXSTAFFS; s++) {
1270                         for (v = 0; v <= MAXVOICES; v++) {
1271
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 */
1279                                         continue;
1280                                 }
1281
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) ) {
1289                                         continue;
1290                                 }
1291
1292                                 /* need to create an SSV */
1293                                 mll_ssv_p = newMAINLLstruct(S_SSV, -1);
1294                                 insertMAINLL(mll_ssv_p, mll_p);
1295                                 mll_p = mll_ssv_p;
1296
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;
1307                                 }
1308                                 if (timeunit_ssv_p != 0) {
1309                                         nssv_p->timeunit = timeunit_ssv_p->timeunit;
1310                                         nssv_p->used[TIMEUNIT] = YES;
1311                                 }
1312
1313                                 /* fill in the SSV header */
1314                                 if (v != 0) {
1315                                         nssv_p->context = C_VOICE;
1316                                 }
1317                                 else if (s != 0) {
1318                                         /* The [s][0] entry is for staff s
1319                                          * when s > 0 */
1320                                         nssv_p->context = C_STAFF;
1321                                 }
1322                                 else {
1323                                         /* The [0][0] entry is actually score */
1324                                         nssv_p->context = C_SCORE;
1325                                 }
1326                                 nssv_p->staffno = s;
1327                                 nssv_p->voiceno = v;
1328                                 asgnssv(nssv_p);
1329                         }
1330                 }
1331         }
1332 }