chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / assign.c
1
2 /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 by Arkkra Enterprises */
3 /* All rights reserved */
4
5 /* Assign values to internal variables in an SSV struct. The functions in
6  * this file are called from the parse phase. */
7
8
9 #include <string.h>
10 #include "defines.h"
11 #include "structs.h"
12 #include "globals.h"
13
14
15 /* there are several cases where we ultimately want arrays, but don't
16  * know in advance how many elements will be in the array. This could be
17  * done by building a linked list first, then malloc-ing the right size and
18  * copying everything. However, what we'll do is allocate CHUNK elements
19  * to start, and realloc if necessary. When we're done, we realloc down
20  * to the actual size */
21 #define CHUNK  (8)
22
23 /* minimum allowable height or width of page (in inches)
24  * after subtracting off the margins */
25 #define MIN_USABLE_SPACE        0.5
26
27
28 /* Macros to adjust numbers between inches to centimeters . */
29
30 /* Given a number in inches, use that number if in inches mode.
31  * If in centimeter mode, then use the equivalent distance in centimeters,
32  * rounded to the nearest quarter of a centimeter. */
33 #define ADJUST4UNITS(n)  (Score.units == INCHES ? n : NEARESTQUARTER(n * CMPERINCH))
34
35 /* Given an input number, leave as is if in inches mode. If in centimeter
36  * mode, treat the number as being in centimeters, and convert to the inch
37  * equivalent distance. */
38 #define ADJUST2INCHES(n)  { if (Score.units == CM) n /= CMPERINCH; }
39
40 static struct STAFFSET *Curr_staffset_p;/* staffset currently
41                                          * being filled in */
42 static int Ss_count;                    /* num of elements in Curr_staffset_p
43                                          * currently actually being used */
44 static int Ss_length;                   /* num of elements allocated
45                                          * to Curr_staffset_p */
46
47 static struct TOP_BOT *Curr_barstlist_p;/* bar style list being filled in */
48 static int Barst_count;                 /* number of elements in
49                                          * Curr_barstlist_p that are currently
50                                          * filled in with valid values */
51 static int Barst_length;                /* number of elements allocated to
52                                          * Curr_barstlist_p */
53
54 struct BEAMLIST {
55         RATIONAL *list_p;               /* beam list being filled in */
56         int count;                      /* elements filled in list_p */
57         int length;                     /* elements allocated to list_p */
58 };
59 /* These store info from the beamstyle parameter. */
60 static struct BEAMLIST Curr_beamstyle;
61 static struct BEAMLIST Curr_subbeamstyle;
62 static int Subbeam_index;               /* Index into Curr_subbeamstyle where
63                                          * the most recent '(' was, or -1 if
64                                          * no pending unmatched parenthesis. */
65 static char *parmformat = "%s parameter";       /* for error messages */
66
67 /* functions to do all the various checks. They check the context,
68  * range, power_of2, etc, and
69  * mark the variable as used if everything passes the checks. The first
70  * is for int variables (actually short) in SSV, the second for floats */
71 static int do_assign P((int var, int value, int min, int max,
72                 int cont, int empty_value, char *name,
73                 struct MAINLL *mainll_item_p, short *ptr2dest));
74
75 static int do_fassign P((int var, double value, double min,
76                 double max, int cont, char *name, struct MAINLL *mainll_item_p,
77                 float *ptr2dest));
78 static void chg_too_late P((char *var_name));
79
80 /* comparison functions to be passed to qsort */
81 static int comp_staffset P((const void *item1_p,
82                 const void *item2_p));
83 static int comp_barst P((const void *item1_p, const void *item2_p));
84 static int is_tablature_staff P((struct SSV *ssv_p));
85 static void init_beamlist P((struct BEAMLIST *beamlist_p));
86 static void add2outerbeam P((RATIONAL value));
87 \f
88
89 /* assign a value to an SSV variable having a domain of short,
90  * after doing any appropriate checks */
91
92 void
93 assign_int(var, value, mainll_item_p)
94
95 int var;                        /* SSV index of which variable to set */
96 int value;                      /* what to set it to */
97 struct MAINLL *mainll_item_p;   /* where to store SSV info in main list */
98
99 {
100         /* all of these things except font can only go
101          * into score/staff sorts of things,
102          * not head/foot. If we are in a head/foot, the MAINLL will be null */
103         if (Context == C_MUSIC || Context == C_GRIDS || Context == C_HEADSHAPES
104                                 || (mainll_item_p == 0 && var != SIZE)) {
105                 yyerror("trying to set parameter value in wrong context");
106                 return;
107         }
108
109
110         if (mainll_item_p != (struct MAINLL *) 0) {
111                 debug(4, "assign_int file=%s line=%d var=%d t value=%d",
112                         mainll_item_p->inputfile, mainll_item_p->inputlineno, var, value);
113         }
114
115         /* handle each variable appropriately */
116         switch (var) {
117
118         case SIZE:
119                 Curr_size = value;
120                 if ( Context & C_BLOCKHEAD ) {
121                         (void) rangecheck(value, MINSIZE, MAXSIZE, "size");
122
123                         /* special case -- size can be set in block,
124                          * and there we don't put in SSV struct,
125                          * just save its value in Curr_size */
126                         return;
127                 }
128                 else {
129                         (void) do_assign(var, value, MINSIZE, MAXSIZE,
130                                 C_SCORE | C_STAFF, NO, "size",
131                                 mainll_item_p, &(mainll_item_p->u.ssv_p->size));
132                         /* set in Score, in case we get an "all" */
133                         if (Context == C_SCORE) {
134                                 Score.size = (short) value;
135                         }
136                 }
137                 break;
138
139         case LYRICSSIZE:
140                 if (do_assign(var, value, MINSIZE, MAXSIZE, C_SCORE | C_STAFF,
141                                 NO, "lyricssize", mainll_item_p,
142                                 &(mainll_item_p->u.ssv_p->lyricssize) )
143                                 == YES) {
144                         /* save values for any lyrics that come later */
145                         if (Context == C_SCORE) {
146                                 /* set in case we get some "all" lyrics */
147                                 Score.lyricssize = (short) value;
148                         }
149                         setlyrsize(mainll_item_p->u.ssv_p->staffno, value);
150                 }
151                 break;
152
153         case MEASNUMSIZE:
154                 (void) do_assign(var, value, MINSIZE, MAXSIZE, C_SCORE,
155                                 NO, "measnumsize", mainll_item_p,
156                                 &(mainll_item_p->u.ssv_p->measnumsize) );
157                 break;
158
159         case SYLPOSITION:
160                 (void) do_assign(var, value, MINSYLPOSITION, MAXSYLPOSITION,
161                                 C_SCORE | C_STAFF,
162                                 NO, "sylposition", mainll_item_p,
163                                 &(mainll_item_p->u.ssv_p->sylposition) );
164                 break;
165
166         case DEFOCT:
167                 (void) do_assign(var, value, MINOCTAVE, MAXOCTAVE,
168                                 C_SSV, NO, "defoct", mainll_item_p,
169                                 &(mainll_item_p->u.ssv_p->defoct) );
170                 if (Context != C_SCORE &&
171                                 is_tab_staff(mainll_item_p->u.ssv_p->staffno)
172                                 == YES) {
173                         yyerror("defoct not allowed on tablature staff");
174                 }
175                 else {
176                         asgnssv(mainll_item_p->u.ssv_p);
177                 }
178                 break;
179
180         case NUMSTAFF:
181                 if (do_assign(var, value, MINSTAFFS, MAXSTAFFS, C_SCORE, NO,
182                                         "staffs", mainll_item_p,
183                                         &(mainll_item_p->u.ssv_p->staffs) )
184                                         == YES) {
185
186                         /* can only change number of staffs if not in the
187                          * middle of doing music data. We exclaimed about
188                          * the user error in end_prev_context(), so if this
189                          * occurs, we just skip over the code in the "if"
190                          */
191                         if (List_of_staffs_p == (struct MAINLL *) 0) {
192                                 /* NUMSTAFFS is a special case,
193                                  * in that several other
194                                  * items have to do error checking
195                                  * based on the number of staffs specified,
196                                  * so we have to set it immediately rather than
197                                  * waiting for the whole SSV struct
198                                  * to be built. */
199                                 Score.staffs = (short) value;
200
201                                 /* if the number of scores changes,
202                                  * there can't be any
203                                  * pending "til" clauses on STUFF */
204                                 chk4dangling_til_clauses(
205                                                 "change in number of staffs");
206
207                                 /* any pedal information is no long valid */
208                                 reset_ped_state();
209                         }
210                 }
211                 break;
212
213         case VISIBLE:
214                 /* actually yacc already guarantees will be in range */
215                 (void) do_assign(var, value, 0, 1, C_SCORE|C_STAFF|C_VOICE, NO,
216                                 "visible", mainll_item_p,
217                                 &(mainll_item_p->u.ssv_p->visible) );
218                 break;
219
220         case MEASNUM:
221                 /* actually yacc already guarantees will be in range */
222                 (void) do_assign(var, value, 0, 1, C_SCORE, NO,
223                                 "measnum", mainll_item_p,
224                                 &(mainll_item_p->u.ssv_p->measnum) );
225                 break;
226
227         case CANCELKEY:
228                 /* actually yacc already guarantees will be in range */
229                 (void) do_assign(var, value, 0, 1, C_SCORE | C_STAFF, NO,
230                                 "cancelkey", mainll_item_p,
231                                 &(mainll_item_p->u.ssv_p->cancelkey) );
232                 break;
233
234         case MINSTSEP:
235                 (void) do_assign(var, value, MINMINSTSEP, MAXSEPVAL,
236                                 C_SCORE | C_STAFF, NO, "staffsep", mainll_item_p,
237                                 &(mainll_item_p->u.ssv_p->minstsep) );
238                 break;
239
240         case MINSCSEP:
241                 (void) do_assign(var, value, MINMINSCSEP, MAXSEPVAL,
242                                 C_SCORE, NO, "min scoresep", mainll_item_p,
243                                 &(mainll_item_p->u.ssv_p->minscsep) );
244                 break;
245
246         case MAXSCSEP:
247                 (void) do_assign(var, value, MINMAXSCSEP, MAXSEPVAL,
248                                 C_SCORE, NO, "max scoresep", mainll_item_p,
249                                 &(mainll_item_p->u.ssv_p->maxscsep) );
250                 break;
251
252         case CHORDDIST:
253                 (void) do_assign(var, value, MINCHORDDIST, MAXCHORDDIST,
254                                 C_SCORE | C_STAFF, NO, "chorddist",
255                                 mainll_item_p,
256                                 &(mainll_item_p->u.ssv_p->chorddist) );
257                 break;
258
259         case DIST:
260                 (void) do_assign(var, value, MINDIST, MAXDIST,
261                                 C_SCORE | C_STAFF, NO, "dist", mainll_item_p,
262                                 &(mainll_item_p->u.ssv_p->dist) );
263                 break;
264
265         case DYNDIST:
266                 (void) do_assign(var, value, MINDYNDIST, MAXDYNDIST,
267                                 C_SCORE | C_STAFF, NO, "dyndist",
268                                 mainll_item_p,
269                                 &(mainll_item_p->u.ssv_p->dyndist) );
270                 break;
271
272         case STAFFPAD:
273                 (void) do_assign(var,value, MINSTPAD, MAXSTPAD,
274                                 C_SCORE | C_STAFF, NO,
275                                 "staffpad", mainll_item_p,
276                                 &(mainll_item_p->u.ssv_p->staffpad) );
277                 break;
278
279         case MINSCPAD:
280                 (void) do_assign(var, value, MINMINSCPAD, MAXPADVAL,
281                                 C_SCORE, NO, "min scorepad", mainll_item_p,
282                                 &(mainll_item_p->u.ssv_p->minscpad) );
283                 break;
284
285         case MAXSCPAD:
286                 (void) do_assign(var, value, MINMAXSCPAD, MAXPADVAL,
287                                 C_SCORE, NO, "max scorepad", mainll_item_p,
288                                 &(mainll_item_p->u.ssv_p->maxscpad) );
289                 break;
290
291         case DIVISION:
292                 chg_too_late("division");
293                 (void) do_assign(var, value, MINDIVISION, MAXDIVISION,
294                                 C_SCORE, NO, "division", mainll_item_p,
295                                 &(mainll_item_p->u.ssv_p->division) );
296                 /* division values that aren't divisible by 2 and 3 are
297                  * unlikely to be right and are likely to lead to rational
298                  * overflow in MIDI code, so give warning */
299                 if ((value % 6) != 0) {
300                         l_warning(Curr_filename, yylineno,
301                                                 "dubious division value");
302                 }
303
304                 break;
305
306         case RELEASE:
307                 (void) do_assign(var, value, MINRELEASE, MAXRELEASE,
308                                 C_SCORE | C_STAFF | C_VOICE, NO,
309                                 "release", mainll_item_p,
310                                 &(mainll_item_p->u.ssv_p->release) );
311                 break;
312
313         case PANELSPERPAGE:
314                 chg_too_late("panelsperpage");
315                 (void) do_assign(var, value, MINPANELSPERPAGE, MAXPANELSPERPAGE,
316                                 C_SCORE, NO,
317                                 "panelsperpage", mainll_item_p,
318                                 &(mainll_item_p->u.ssv_p->panelsperpage) );
319                 break;
320
321         case RESTCOMBINE:
322                 (void) do_assign(var, value,
323                                 MINRESTCOMBINE, MAXRESTCOMBINE,
324                                 C_SCORE, NORESTCOMBINE,
325                                 "restcombine", mainll_item_p,
326                                 &(mainll_item_p->u.ssv_p->restcombine) );
327                 break;
328
329         case FIRSTPAGE:
330                 chg_too_late("firstpage");
331                 (void) do_assign(var, value, MINFIRSTPAGE, MAXFIRSTPAGE,
332                                 C_SCORE, NO,
333                                 "firstpage", mainll_item_p,
334                                 &(mainll_item_p->u.ssv_p->firstpage) );
335                 break;
336
337         case GRIDFRET:
338                 (void) do_assign(var, value, MINGRIDFRET, MAXGRIDFRET,
339                                 C_SCORE | C_STAFF, NOGRIDFRET,
340                                 "gridfret", mainll_item_p,
341                                 &(mainll_item_p->u.ssv_p->gridfret) );
342                 break;
343
344         case GRIDSWHEREUSED:
345                 (void) do_assign(var, value, 0, 1,
346                                 C_SCORE | C_STAFF, NO,
347                                 "gridswhereused", mainll_item_p,
348                                 &(mainll_item_p->u.ssv_p->gridswhereused) );
349                 break;
350
351         case GRIDSATEND:
352                 (void) do_assign(var, value, 0, 1, C_SCORE, NO,
353                                 "gridsatend", mainll_item_p,
354                                 &(mainll_item_p->u.ssv_p->gridsatend) );
355                 break;
356
357         case TABWHITEBOX:
358                 /* actually yacc already guarantees will be in range */
359                 (void) do_assign(var, value, 0, 1,
360                                 C_SCORE | C_STAFF | C_VOICE, NO,
361                                 "tabwhitebox", mainll_item_p,
362                                 &(mainll_item_p->u.ssv_p->tabwhitebox) );
363                 break;
364
365         case ONTHELINE:
366                 /* This only makes sense on 1-line staffs, but we decided
367                  * it is best to silently accept it elsewhere. For example,
368                  * you might want to set it in score context to apply to all
369                  * the 1-line staffs there are. */
370                 (void) do_assign(var, value, 0, 1,
371                                 C_SCORE | C_STAFF | C_VOICE, NO,
372                                 "ontheline", mainll_item_p,
373                                 &(mainll_item_p->u.ssv_p->ontheline) );
374                 break;
375
376         case WARN:
377                 (void) do_assign(var, value, 0, 1,
378                                 C_SCORE, NO, "warn", mainll_item_p,
379                                 &(mainll_item_p->u.ssv_p->warn) );
380                 break;
381
382         case NUMBERMRPT:
383                 (void) do_assign(var, value, 0, 1,
384                                 C_SCORE | C_STAFF, NO, "numbermrpt", mainll_item_p,
385                                 &(mainll_item_p->u.ssv_p->numbermrpt) );
386                 break;
387
388         case PRINTMULTNUM:
389                 (void) do_assign(var, value, 0, 1,
390                                 C_SCORE | C_STAFF, NO, "printmultnum", mainll_item_p,
391                                 &(mainll_item_p->u.ssv_p->printmultnum) );
392                 break;
393
394         case RESTSYMMULT:
395                 (void) do_assign(var, value, 0, 1,
396                                 C_SCORE | C_STAFF, NO, "restsymmult", mainll_item_p,
397                                 &(mainll_item_p->u.ssv_p->restsymmult) );
398                 break;
399
400         default:
401                 pfatal("bad parameter name\n");
402                 break;
403         }
404 }
405 \f
406
407 /* do all the error checks for an int variable. If it passes all checks,
408  * set the used flag to YES and return YES. If something fails, return NO. */
409 /* Checks are: must be within range, must be in valid context, the MAINLL
410  * struct passed must be non-NULL, and if the pow2 flag is YES, the value
411  * must be a power of two. Also give warning if field already used.  Getting
412  * a null pointer is not fatal--it can happen if user tried to do something
413  * in the wrong context. */
414
415 static int
416 do_assign(var, value, min, max, cont, empty_value, name, mainll_item_p, ptr2dest)
417
418 int var;                        /* which variable to set */
419 int value;                      /* what to set it to */
420 int min;                        /* minimum valid value */
421 int max;                        /* maximum valid value */
422 int cont;                       /* valid context(s)  (bitmap) */
423 int empty_value;                /* if NO, value must be strictly within the
424                                  * given min/max. If != NO, it is an extra
425                                  * value, outside the min/max range, that
426                                  * is legal, and indicates
427                                  * user set the value to empty */
428 char *name;                     /* of internal variable, for error messages */
429 struct MAINLL *mainll_item_p;   /* which structure to set it in */
430 short *ptr2dest;                /* the address of the variable to be set */
431
432 {
433         char fullname[50];      /* name + " parameter" */
434         if (mainll_item_p == (struct MAINLL *) 0) {
435                 l_yyerror(Curr_filename, yylineno, "wrong context for setting %s",
436                                 name);
437                 return(NO);
438         }
439         (void) sprintf(fullname, parmformat, name);
440         if (contextcheck(cont, fullname) == NO) {
441                 return(NO);
442         }
443
444         /* exclaim if already set in this SSV */
445         used_check(mainll_item_p, var, name);
446
447         /* do the checks */
448         if (empty_value != NO && erangecheck(value, min, max, empty_value, name) == NO) {
449                 return(NO);
450         }
451         else if (empty_value == NO && rangecheck(value, min, max, name) == NO) {
452                 return(NO);
453         }
454         /* passed all the checks-- assign and mark it as used */
455         mainll_item_p->u.ssv_p->used[var] = YES;
456         *ptr2dest = (short) value;
457         return(YES);
458 }
459 \f
460
461 /* do assignment of float type SSV variables */
462
463 void
464 assign_float(var, value, mainll_item_p)
465
466 int var;                        /* which variable to set */
467 double value;                   /* what to set it to */
468 struct MAINLL *mainll_item_p;   /* where to store info */
469
470 {
471
472         /* all of these things can only go into score/staff sorts of things,
473          * not head/foot. If we are in a head/foot, the MAINLL will be null */
474         if (mainll_item_p == 0 || Context == C_MUSIC) {
475                 yyerror("trying to set parameter value in wrong context");
476                 return;
477         }
478
479         debug(4, "assign_float file=%s line=%d var=%d  value=%f",
480                 mainll_item_p->inputfile, mainll_item_p->inputlineno, var, value);
481
482         /* some changes are only allowed before music data is entered */
483         if (Got_some_data == YES) {
484                 switch (var) {
485                 case TOPMARGIN:
486                 case BOTMARGIN:
487                 case LEFTMARGIN:
488                 case RIGHTMARGIN:
489                         chg_too_late( "margin");
490                         break;
491                 case SCALE_FACTOR:
492                         chg_too_late( "scale");
493                         break;
494                 case PAGEHEIGHT:
495                 case PAGEWIDTH:
496                         chg_too_late( "page size");
497                         break;
498                 default:
499                         break;
500                 }
501         }
502
503         /* if pagesize minus the margins get too small (or even worse,
504          * negative), we better complain */
505         switch (var) {
506         case TOPMARGIN:
507         case BOTMARGIN:
508         case LEFTMARGIN:
509         case RIGHTMARGIN:
510         case PAGEHEIGHT:
511         case PAGEWIDTH:
512                 chkmargin(Score.topmargin, Score.botmargin, Score.leftmargin,
513                                         Score.rightmargin);
514                 break;
515         default:
516                 break;
517         }
518
519         switch (var) {
520
521         case TOPMARGIN:
522                 if (do_fassign(var, (double) value,
523                                 (double) ADJUST4UNITS(MINVMARGIN),
524                                 (double) ADJUST4UNITS(Score.pageheight - MIN_USABLE_SPACE),
525                                 C_SCORE, "topmargin", mainll_item_p,
526                                 &(mainll_item_p->u.ssv_p->topmargin) )
527                                 == YES) {
528                         ADJUST2INCHES(mainll_item_p->u.ssv_p->topmargin)
529
530                         /* put in score so we can check for margins exceeding paper size */
531                         Score.topmargin = mainll_item_p->u.ssv_p->topmargin;
532                 }
533                 break;
534
535         case BOTMARGIN:
536                 if (do_fassign(var, (double) value,
537                                 (double) ADJUST4UNITS(MINVMARGIN),
538                                 (double) ADJUST4UNITS(Score.pageheight - MIN_USABLE_SPACE),
539                                 C_SCORE, "bottommargin", mainll_item_p,
540                                 &(mainll_item_p->u.ssv_p->botmargin) )
541                                 == YES) {
542                         ADJUST2INCHES(mainll_item_p->u.ssv_p->botmargin)
543                         Score.botmargin = mainll_item_p->u.ssv_p->botmargin;
544                 }
545                 break;
546
547         case LEFTMARGIN:
548                 if (do_fassign(var, (double) value,
549                                 (double) ADJUST4UNITS(MINHMARGIN),
550                                 (double) ADJUST4UNITS(Score.pagewidth - MIN_USABLE_SPACE),
551                                 C_SCORE, "leftmargin", mainll_item_p,
552                                 &(mainll_item_p->u.ssv_p->leftmargin) )
553                                 == YES) {
554                         ADJUST2INCHES(mainll_item_p->u.ssv_p->leftmargin)
555                         Score.leftmargin = mainll_item_p->u.ssv_p->leftmargin;
556                 }
557                 break;
558
559         case RIGHTMARGIN:
560                 if (do_fassign(var, (double) value,
561                                 (double) ADJUST4UNITS(MINHMARGIN),
562                                 (double) ADJUST4UNITS(Score.pagewidth - MIN_USABLE_SPACE),
563                                 C_SCORE, "rightmargin", mainll_item_p,
564                                 &(mainll_item_p->u.ssv_p->rightmargin) )
565                                 == YES) {
566                         ADJUST2INCHES(mainll_item_p->u.ssv_p->rightmargin)
567                         Score.rightmargin = mainll_item_p->u.ssv_p->rightmargin;
568                 }
569                 break;
570
571         case PACKFACT:
572                 (void) do_fassign(var, (double) value,
573                                 (double) MINPACKFACT, (double) MAXPACKFACT,
574                                 C_SCORE, "packfact", mainll_item_p,
575                                 &(mainll_item_p->u.ssv_p->packfact) );
576                 break;
577
578         case PACKEXP:
579                 (void) do_fassign(var, (double) value,
580                                 (double) MINPACKEXP, (double) MAXPACKEXP,
581                                 C_SCORE, "packexp", mainll_item_p,
582                                 &(mainll_item_p->u.ssv_p->packexp) );
583                 break;
584
585         case SCALE_FACTOR:
586                 (void) do_fassign(var, (double) value,
587                                 (double) MINSCALE, (double) MAXSCALE,
588                                 C_SCORE, "scale factor", mainll_item_p,
589                                 &(mainll_item_p->u.ssv_p->scale_factor) );
590                 break;
591
592         case STAFFSCALE:
593                 (void) do_fassign(var, (double) value,
594                                 (double) MINSTFSCALE, (double) MAXSTFSCALE,
595                                 C_SCORE | C_STAFF, "staffscale", mainll_item_p,
596                                 &(mainll_item_p->u.ssv_p->staffscale) );
597                 break;
598
599         case GRIDSCALE:
600                 (void) do_fassign(var, (double) value,
601                                 (double) MINGRIDSCALE, (double) MAXGRIDSCALE,
602                                 C_SCORE | C_STAFF, "gridscale", mainll_item_p,
603                                 &(mainll_item_p->u.ssv_p->gridscale) );
604                 break;
605
606         case PAGEHEIGHT:
607                 if (do_fassign(var, (double) value,
608                                 (double) ADJUST4UNITS(MINPAGEHEIGHT),
609                                 (double) ADJUST4UNITS(MAXPAGEHEIGHT),
610                                 C_SCORE, "pageheight", mainll_item_p,
611                                 &(mainll_item_p->u.ssv_p->pageheight) )
612                                 == YES) {
613                         ADJUST2INCHES(mainll_item_p->u.ssv_p->pageheight)
614                         Score.pageheight = mainll_item_p->u.ssv_p->pageheight;
615                 }
616                 break;
617
618         case PAGEWIDTH:
619                 if (do_fassign(var, (double) value,
620                                 (double) ADJUST4UNITS(MINPAGEWIDTH),
621                                 (double) ADJUST4UNITS(MAXPAGEWIDTH),
622                                 C_SCORE, "pagewidth", mainll_item_p,
623                                 &(mainll_item_p->u.ssv_p->pagewidth) )
624                                 == YES) {
625                         ADJUST2INCHES(mainll_item_p->u.ssv_p->pagewidth)
626                         Score.pagewidth = mainll_item_p->u.ssv_p->pagewidth;
627                 }
628                 break;
629
630         case LYRICSALIGN:
631                 (void) do_fassign(var, (double) value,
632                         (double) MINLYRICSALIGN,
633                         (double) MAXLYRICSALIGN,
634                         C_SCORE | C_STAFF, "lyricsalign", mainll_item_p,
635                         &(mainll_item_p->u.ssv_p->lyricsalign) );
636                 break;
637
638         case PAD:
639                 (void) do_fassign(var, (double) value,
640                         (double) MINPAD,
641                         (double) MAXPAD,
642                         C_SCORE | C_STAFF | C_VOICE, "pad", mainll_item_p,
643                         &(mainll_item_p->u.ssv_p->pad) );
644                 /* What the user calls zero means notes can
645                  * just touch, but internally we want zero to mean the
646                  * default of 1 point of padding, so adjust. */
647                 mainll_item_p->u.ssv_p->pad -= POINT;
648                 break;
649
650         case STEMLEN:
651                 (void) do_fassign(var, (double) value,
652                         (double) MINSTEMLEN,
653                         (double) MAXSTEMLEN,
654                         C_SSV, "stemlen", mainll_item_p,
655                         &(mainll_item_p->u.ssv_p->stemlen) );
656                 break;
657
658
659         case STEMSHORTEN:
660                 (void) do_fassign(var, (double) value,
661                         (double) MINSTEMSHORTEN,
662                         (double) MAXSTEMSHORTEN,
663                         C_SSV, "stemshorten", mainll_item_p,
664                         &(mainll_item_p->u.ssv_p->stemshorten) );
665                 break;
666
667         default:
668                 pfatal("invalid float parameter");
669                 break;
670         }
671 }
672
673 \f
674
675 /* Handle parameters that have two float numbers as their value */
676
677 void
678 assign_2floats(var, value1, value2, mainll_item_p)
679
680 int var;                        /* which variable to set */
681 double value1, value2;          /* which values to set */
682 struct MAINLL *mainll_item_p;   /* where to store info */
683
684 {
685         switch (var) {
686
687         case BEAMSLOPE:
688                 /* First float value is the factor */
689                 if (do_fassign(var, (double) value1,
690                         (double) MINBEAMFACT,
691                         (double) MAXBEAMFACT,
692                         C_SCORE | C_STAFF | C_VOICE, "beamslope factor",
693                         mainll_item_p,
694                         &(mainll_item_p->u.ssv_p->beamfact) ) == YES) {
695
696                         /* Fool do_fassign into thinking we haven't set the used
697                          * flag yet. This is a little kludgy... */
698                         mainll_item_p->u.ssv_p->used[var] = NO;
699
700                         /* Second value is the max angle in degrees */
701                         (void) do_fassign(var, value2,
702                                         (double) MINBEAMMAX,
703                                         (double) MAXBEAMMAX,
704                                         C_SCORE | C_STAFF | C_VOICE,
705                                         "beamslope maximum slope angle",
706                                         mainll_item_p,
707                                         &(mainll_item_p->u.ssv_p->beammax) );
708                 }
709                 break;
710
711         default:
712                 pfatal("bad var value for assign_2floats %d", var);
713                 /*NOTREACHED*/
714                 break;
715         }
716 }
717 \f
718
719 /* If user tries to change something that can only be changed before music
720  * data is entered, but music has been entered, print error message. */
721
722 static void
723 chg_too_late(var_name)
724
725 char *var_name;
726
727 {
728         if (Got_some_data == YES) {
729                 l_yyerror(Curr_filename, yylineno,
730                         "Can't change %s after music or block data has been entered",
731                         var_name);
732         }
733 }
734 \f
735
736 /* Do error checks for a float variable. If it passes all checks,
737  * set the used flag to YES and return YES.
738  * If something fails check, return NO.
739  * Checks are: value within range, valid context, and MAINLL struct pointer
740  * passed non-NULL.
741  * Also give warning if field already used.
742  */
743
744 static int
745 do_fassign(var, value, min, max, cont, name, mainll_item_p, ptr2dest)
746
747 int var;                        /* which variable to set */
748 double value;                   /* what to set it to */
749 double min;                     /* minimum valid value */
750 double max;                     /* maximum valid value */
751 int cont;                       /* valid context(s) (bitmap) */
752 char *name;                     /* for error messages */
753 struct MAINLL *mainll_item_p;   /* which structure to set it in */
754 float *ptr2dest;                /* pointer to the float variable
755                                  * to be assigned */
756
757 {
758         char fullname[50];      /* name + " parameter" */
759
760         if (mainll_item_p == (struct MAINLL *) 0) {
761                 l_yyerror(Curr_filename, yylineno, "wrong context for setting %s",                              name);
762                 return(NO);
763         }
764         (void) sprintf(fullname, parmformat, name);
765         if ( contextcheck(cont, fullname) == NO) {
766                 return(NO);
767         }
768
769         /* exclaim if already set in this SSV */
770         used_check(mainll_item_p, var, name);
771
772         /* do checks */
773         if (frangecheck(value, min, max, name) == NO) {
774                 return(NO);
775         }
776         else {
777                 /* passed all the checks-- assign and mark it as used */
778                 mainll_item_p->u.ssv_p->used[var] = YES;
779                 *ptr2dest = value;
780                 return(YES);
781         }
782 }
783 \f
784
785 /* assign value to vscheme variable */
786
787 void
788 assign_vscheme(numvoices, vtype, mainll_item_p)
789
790 int numvoices;                  /* 1, 2, or 3 */
791 int vtype;                      /* V_1, V_2FREESTEM, or V_2OPSTEM. For 3 voice
792                                  * case, this is still one of the V_2* values,
793                                  * and in that case it specifies whether
794                                  * the stems are free or opposing,
795                                  * with the numvoices indicating the 3 */
796 struct MAINLL *mainll_item_p;   /* where to assign it */
797
798 {
799         /* check for proper context */
800         if (contextcheck(C_SCORE | C_STAFF, "vscheme parameter") == NO) {
801                 return;
802         }
803
804         /* exclaim if already set in this SSV */
805         used_check(mainll_item_p, VSCHEME, "vscheme");
806
807         if (rangecheck(numvoices, MINVOICES, MAXVOICES, "vscheme value") == NO) {
808                 return;
809         }
810
811         /* check for valid combination */
812         if ( (numvoices == 1) && (vtype != V_1) ) {
813                 yyerror("can't have 'o' or 'f' qualifier when vscheme=1");
814                 return;
815         }
816
817         if ( (numvoices == 2 || numvoices == 3) && (vtype == V_1) ) {
818                 yyerror("'o' or 'f' qualifier required when vscheme=2 or vscheme=3");
819                 return;
820         }
821
822         /* The 3 voice things are really just the 2 voice ones, but a third
823          * voice is allowed. They get passed in as V_2*, so fix that */
824         if (numvoices == 3) {
825                 if (vtype == V_2FREESTEM) {
826                         vtype = V_3FREESTEM;
827                 }
828                 else if (vtype == V_2OPSTEM) {
829                         vtype = V_3OPSTEM;
830                 }
831         }
832
833         /* set variable to requested value */
834         mainll_item_p->u.ssv_p->vscheme = (short) vtype;
835         mainll_item_p->u.ssv_p->used[VSCHEME] = YES;
836
837         asgnssv(mainll_item_p->u.ssv_p);
838 }
839 \f
840
841 /* assign value to voicecombine parameter */
842
843 void
844 assign_vcombine(qualifier, mainll_p)
845
846 int qualifier;
847 struct MAINLL * mainll_p;
848
849 {
850         short listed[MAXVOICES + 1];    /* If user mentioned the voice */
851         struct RANGELIST * curr_p;      /* walk through list of voices */
852         int v;                          /* voice */
853         int offset;                     /* index into vcombine array */
854
855
856         if (contextcheck(C_SCORE | C_STAFF, "voicecombine parameter") == NO) {
857                 return;
858         }
859         used_check(mainll_p, VCOMBINE, "voicecombine");
860
861         /* Clear list of voices mentioned by user,
862          * and initialize list of voices to combine to none. */
863         for (v = 1; v <= MAXVOICES; v++) {
864                 listed[v] = NO;
865                 mainll_p->u.ssv_p->vcombine[v-1] = 0;
866         }
867
868         /* We start filling in at beginning of vcombine array */
869         offset = 0;
870
871         /* Add the specified voices in input order to SSV vcombine array */
872         for (curr_p = Vnorange_p; curr_p != 0; curr_p = curr_p->next) {
873                 /* add voices into voice combine list after error checks */
874                 for (v = curr_p->begin; v <= curr_p->end; v++) {
875                         if (listed[v] == YES) {
876                                 l_yyerror(Curr_filename, yylineno,
877                                         "voice %d specified more than once", v);
878                         }
879                         if (offset >= MAXVOICES) {
880                                 /* The only way this can happen is if user
881                                  * specified at least one voice more than once,
882                                  * and we would have already reported that
883                                  * above, so no need to print another error.
884                                  * But we must not attempt to write beyond
885                                  * end of vcombine array, so jump out of loop.
886                                  */
887                                 break;
888                         }
889                         mainll_p->u.ssv_p->vcombine[offset++] = v;
890                         listed[v] = YES;
891                 }
892         }
893
894         free_vnorange();
895         mainll_p->u.ssv_p->vcombinequal = (short) qualifier;
896         mainll_p->u.ssv_p->used[VCOMBINE] = YES;
897         /* Since voicecombine is relatively rare, we set a flag if it is
898          * ever used. If flag is not set, all the voicecombine placement
899          * code can be skipped entirely. If turning off or only a
900          * single voice is specified, that doesn't really count as being used.
901          */
902         if (offset > 1) {
903                 Vcombused = YES;
904         }
905 }
906 \f
907
908 /* assign key signature */
909
910 void
911 assign_key(num, acc, is_minor, mainll_item_p)
912
913 int num;                        /* number of sharps or flats */
914 int acc;                        /* # or & for sharp or flat */
915 int is_minor;                   /* YES or NO */
916 struct MAINLL *mainll_item_p;   /* where to assign */
917
918 {
919         if (contextcheck( C_SCORE | C_STAFF, "key parameter") == NO) {
920                 return;
921         }
922
923         /* exclaim if already set in this SSV */
924         used_check(mainll_item_p, SHARPS, "key");
925
926         /* error check. Must be no more than 7 flats or sharps, and can only
927          * be set in score or staff contexts */
928         if (rangecheck(num, 0, MAXSHARPS,
929                         "number of flats or sharps in key signature") == NO) {
930                 return;
931         }
932
933         /* looks okay, so make assignment */
934         /* NOTE: num of flats == negative number of sharps */
935         mainll_item_p->u.ssv_p->sharps = num * (acc == '#' ? 1 : -1);
936         mainll_item_p->u.ssv_p->used[SHARPS] = YES;
937         mainll_item_p->u.ssv_p->is_minor = (short) is_minor;
938
939         asgnssv(mainll_item_p->u.ssv_p);
940 }
941 \f
942
943 /* Assign a string to an SSV variable. It just assigns the pointer for labels,
944  * so temporary strings should be copied before being passed.
945  * For NOTEHEADS, it parses the string and saves the numeric internal numbers.
946  */
947
948 void
949 assign_string(var, string, mainll_item_p)
950
951 int var;                        /* LABEL, LABEL2, or NOTEHEADS */
952 char *string;                   /* the string to assign */
953 struct MAINLL *mainll_item_p;   /* where to assign it */
954
955 {
956         int n;                  /* note shape index */
957         char namebuff[100];     /* For note shape names. Builtin names are
958                                  * fairly short, but user could define longer
959                                  * ones. We figure 100 should be plenty,
960                                  * and ufatal if they try to go longer. */
961         int nameleng;           /* strlen of a name shape name */
962         int context;            /* which context to check */
963         char *error_msg;        /* what to print in error message */
964
965         if (var == NOTEHEADS) {
966                 context = C_SSV;
967                 error_msg = "noteheads parameter";
968         }
969         else {
970                 context = C_SCORE | C_STAFF;
971                 error_msg = (var == LABEL ? "label parameter"
972                                         : "label2 parameter");
973         }
974
975         if (contextcheck(context, error_msg) == YES) {
976
977                 /* get string into proper internal format */
978                 (void) fix_string(string, string[0], string[1],
979                                         Curr_filename, yylineno);
980
981                 switch (var) {
982
983                 case LABEL:
984                         used_check(mainll_item_p, var, "label");
985                         mainll_item_p->u.ssv_p->label = string;
986                         break;
987
988                 case LABEL2:
989                         used_check(mainll_item_p, var, "label2");
990                         mainll_item_p->u.ssv_p->label2 = string;
991                         break;
992
993                 case NOTEHEADS:
994                         if (is_tab_staff(mainll_item_p->u.ssv_p->staffno) == YES
995                                         && strcmp(string+2, "allx") != 0
996                                         && strcmp(string+2, "norm") != 0) {
997                                 warning("noteheads parameter ignored on tablature staffs (unless allx or norm)");
998                         }
999
1000                         /* skip past font/size */
1001                         string += 2;
1002                         /* split into tokens */
1003                         for (n = 0; n < 7; n++) {
1004                                 /* skip past white space */
1005                                 while ( isspace(*string) ) {
1006                                         string++;
1007                                 }
1008
1009                                 if ( *string == '\0') {
1010                                         break;
1011                                 }
1012
1013                                 nameleng = strcspn(string, " \t\r\n");
1014                                 if (nameleng > sizeof(namebuff) - 1) {
1015                                         ufatal("note head name too long");
1016                                 }
1017                                 strncpy(namebuff, string, nameleng);
1018                                 namebuff[nameleng] = '\0';
1019                                 if ((mainll_item_p->u.ssv_p->noteheads[n] =
1020                                                         get_shape_num(namebuff))
1021                                                         == HS_UNKNOWN) {
1022                                         l_yyerror(Curr_filename, yylineno,
1023                                                 "'%s' is not a valid headshape name",
1024                                                 namebuff);
1025                                 }
1026                                 string += nameleng;
1027                         }
1028                         if (n == 1) {
1029                                 /* copy same shape for all 7 */
1030                                 for (  ; n < 7; n++) {
1031                                         mainll_item_p->u.ssv_p->noteheads[n] =
1032                                         mainll_item_p->u.ssv_p->noteheads[0];
1033                                 }
1034                         }
1035
1036                         /* Skip past trailing white space, and make sure we got
1037                          * right number of tokens. */
1038                         while ( isspace(*string) ) {
1039                                 string++;
1040                         }
1041                         if (n != 7 || *string != '\0') {
1042                                 yyerror("wrong number of notehead names: expecting either 1 or 7");
1043                         }
1044                         break;
1045                 default:
1046                         pfatal("invalid string variable type");
1047                         /*NOTREACHED*/
1048                         break;
1049                 }
1050
1051                 mainll_item_p->u.ssv_p->used[var] = YES;
1052         }
1053 }
1054 \f
1055
1056 /* make a copy of a string and return pointer to it,
1057  * or return NULL if string was NULL. The incoming string is a regular C-style
1058  * string. The returned string is 2 bytes longer, with the font in the first
1059  * byte, size in the second byte, and the copy of the original string in the
1060  * remainder. */
1061
1062 char *
1063 copy_string(string, font, size)
1064
1065 char *string;           /* make a copy of this string */
1066 int font;               /* use this font */
1067 int size;               /* use this point size */
1068
1069 {
1070         char *copy;     /* pointer to new copy of string */
1071
1072
1073         if (string == (char *) 0) {
1074                 return (string);
1075         }
1076
1077         /* need 2 extra bytes at beginning for font and size,
1078          * and 1 at end for '\0' */
1079         MALLOCA(char, copy, strlen(string) + 3);
1080
1081         /* fill in font and size in first 2 bytes */
1082         *copy = (char) font;
1083         *(copy + 1) = (char) size;
1084
1085         /* copy the string and return pointer to copy */
1086         (void) strcpy(copy + 2, string);
1087         return(copy);
1088 }
1089 \f
1090
1091 /* Assign time signature in SSV.
1092  * Derives the effective numerator/denominator and the RATIONAL time value
1093  * from the timerep, and fills them in the SSV. If there are alternating
1094  * time signatures, that will be for the first of them, and a pointer
1095  * to the remaining signature(s) will be returned via next_alternation_p.
1096  * If there are additive time signatures, the effective num/den will
1097  * be based on the largest denominator.
1098  */
1099
1100 void
1101 assign_timesig(mainll_item_p, visibility, next_alternation_p)
1102
1103 struct MAINLL *mainll_item_p;   /* SSV to assign time signature in */
1104 int visibility;                 /* YES, NO, or EACHMEAS */
1105 char **next_alternation_p;      /* If this time signature includes alternating
1106                                  * time signatures, as in  3/4  4/4,
1107                                  * this will be filled in with a pointer to
1108                                  * where the next alternate time signature
1109                                  * begins in the timerep. If there are no
1110                                  * alternating time signatures, it will be
1111                                  * filled by a null pointer. */
1112
1113 {
1114         struct SSV *ssv_p;              /* mainll_item_p->u.ssv_p */
1115         RATIONAL curr_value;            /* There may be compound time
1116                                          * signatures, and each of those
1117                                          * may have multiple numerator
1118                                          * components, so this is used for
1119                                          * getting value of one fraction */
1120         int biggest_denominator;        /* for calculating effective
1121                                          * numerator and denominator */
1122         char *t;                        /* to walk through timerep */
1123
1124
1125         if (contextcheck(C_SCORE, "time parameter") == NO) {
1126                 return;
1127         }
1128
1129         /* exclaim if already set in this SSV */
1130         used_check(mainll_item_p, TIME, "time signature");
1131
1132         ssv_p = mainll_item_p->u.ssv_p;
1133
1134         ssv_p->timevis = visibility;
1135
1136         curr_value = Zero;
1137         ssv_p->time = Zero;
1138         biggest_denominator = 0;
1139         *next_alternation_p = 0;
1140
1141         for (t = ssv_p->timerep; *t != TSR_END; t++) {
1142                 if (*t == TSR_CUT) {
1143                         curr_value.n = 2;
1144                         curr_value.d = 2;
1145                 }
1146                 else if (*t == TSR_COMMON) {
1147                         curr_value.n = 4;
1148                         curr_value.d = 4;
1149                 }
1150                 else if (*t == TSR_SLASH) {
1151                         curr_value.d = *++t;
1152                 }
1153                 else if (*t == TSR_ALTERNATING) {
1154                         *next_alternation_p = ++t;
1155                         break;
1156                 }
1157                 else if (*t == TSR_ADD) {
1158                         continue;
1159                 }
1160                 else {
1161                         curr_value.n += *t;
1162                         continue;
1163                 }
1164                 biggest_denominator = MAX(biggest_denominator, curr_value.d);
1165                 rred(&curr_value);
1166                 ssv_p->time = radd(ssv_p->time, curr_value);
1167                 curr_value = Zero;
1168         }
1169
1170         /* If there were mixed denominators, use the biggest for the
1171          * purpose of effective numerator and denominator */
1172         if (biggest_denominator > ssv_p->time.d) {
1173                 ssv_p->timenum = ssv_p->time.n * (biggest_denominator / ssv_p->time.d);
1174         }
1175         else {
1176                 ssv_p->timenum = ssv_p->time.n;
1177         }
1178         ssv_p->timeden = biggest_denominator;
1179
1180         /* mark time as used */
1181         mainll_item_p->u.ssv_p->used[TIME] = YES;
1182
1183         /* We have to set this for real immediately, since beamstyle and
1184          * other things may need to have it set */
1185         asgnssv(mainll_item_p->u.ssv_p);
1186
1187         if (mainll_item_p->u.ssv_p->used[BEAMSTLIST] == YES) {
1188                 l_warning(Curr_filename, yylineno,
1189                                 "changing time signature clears beamstyle");
1190                 /* have to actually clear it here, because otherwise it
1191                  * would still get assigned in ssv.c because beamstyle is
1192                  * done after the code for time signature */
1193                 mainll_item_p->u.ssv_p->used[BEAMSTLIST] = NO;
1194                 mainll_item_p->u.ssv_p->nbeam = 0;
1195                 if (mainll_item_p->u.ssv_p->beamstlist != (RATIONAL *) 0) {
1196                         FREE(mainll_item_p->u.ssv_p->beamstlist);
1197                 }
1198         }
1199 }
1200 \f
1201
1202 /* assign a font variable (FONT, LYRICSFONT, FONTFAMILY, LYRICSFAMILY) */
1203
1204 void
1205 set_font(var, value, mainll_item_p)
1206
1207 int var;                        /* which variable to set */
1208 int value;                      /* which font to set it too */
1209 struct MAINLL *mainll_item_p;   /* where to assign it in main list */
1210
1211 {
1212         char *varname;  /* name of variable, for error messages */
1213         char fullname[50];      /* varname + " parameter" */
1214
1215
1216         /* determine the name of the variable, for error messages */
1217         switch(var) {
1218         case FONT:
1219                 varname = "font";
1220                 break;
1221         case LYRICSFONT:
1222                 varname = "lyricsfont";
1223                 break;
1224         case MEASNUMFONT:
1225                 varname = "measnumfont";
1226                 break;
1227         case FONTFAMILY:
1228                 varname = "fontfamily";
1229                 break;
1230         case LYRICSFAMILY:
1231                 varname = "lyricsfontfamily";
1232                 break;
1233         case MEASNUMFAMILY:
1234                 varname = "measnumfontfamily";
1235                 break;
1236         default:
1237                 pfatal("bad font variable");
1238                 /*NOTREACHED*/
1239                 return;
1240         }
1241         (void) sprintf(fullname, parmformat, varname);
1242
1243         /* if being called from SSV, exclaim if already set */
1244         if ((Context & C_SSV) != 0) {
1245                 used_check(mainll_item_p, var, varname);
1246         }
1247
1248         switch (var) {
1249
1250         case FONT:
1251                 Curr_font = value;
1252
1253                 if (Context & C_BLOCKHEAD) {
1254                         /* Special case. In block, we just
1255                          * keep track of the current font */
1256                         return;
1257                 }
1258                 else if (contextcheck(C_SCORE | C_STAFF, fullname) == YES) {
1259                         mainll_item_p->u.ssv_p->font = (short) value;
1260                 }
1261                 else {
1262                         return;
1263                 }
1264
1265                 break;
1266
1267         case FONTFAMILY:
1268                 Curr_family = value;
1269
1270                 if (Context & C_BLOCKHEAD) {
1271                         /* Special case. In block, we just
1272                          * keep track of the current font */
1273                         return;
1274                 }
1275                 else if (contextcheck(C_SCORE | C_STAFF, fullname) == YES) {
1276                         mainll_item_p->u.ssv_p->fontfamily = (short) value;
1277                 }
1278                 else {
1279                         return;
1280                 }
1281
1282                 break;
1283
1284         case LYRICSFONT:
1285                 if (contextcheck(C_SCORE | C_STAFF, fullname) == YES) {
1286                         mainll_item_p->u.ssv_p->lyricsfont = (short) value;
1287
1288                         /* assign immediately in case there is a following
1289                          * font family change that needs to read it */
1290                         mainll_item_p->u.ssv_p->used[var] = YES;
1291                         asgnssv(mainll_item_p->u.ssv_p);
1292                         setlyrfont(mainll_item_p->u.ssv_p->staffno, value);
1293                         return;
1294                 }
1295                 else {
1296                         return;
1297                 }
1298
1299                 /*NOTREACHED*/
1300                 break;
1301
1302         case LYRICSFAMILY:
1303                 if (contextcheck(C_SCORE | C_STAFF, fullname) == YES) {
1304                         mainll_item_p->u.ssv_p->lyricsfamily = (short) value;
1305                         /* assign immediately, so we can reset all
1306                          * lyrics info for this staff */
1307                         mainll_item_p->u.ssv_p->used[var] = YES;
1308                         asgnssv(mainll_item_p->u.ssv_p);
1309
1310                         setlyrfont(mainll_item_p->u.ssv_p->staffno,
1311                                 svpath(mainll_item_p->u.ssv_p->staffno,
1312                                 LYRICSFONT)->lyricsfont);
1313                         return;
1314                 }
1315                 else {
1316                         return;
1317                 }
1318
1319                 /*NOTREACHED*/
1320                 break;
1321
1322         case MEASNUMFONT:
1323                 if (contextcheck(C_SCORE, fullname) == YES) {
1324                         mainll_item_p->u.ssv_p->measnumfont = (short) value;
1325                 }
1326                 else {
1327                         return;
1328                 }
1329                 break;
1330
1331         case MEASNUMFAMILY:
1332                 if (contextcheck(C_SCORE, fullname) == YES) {
1333                         mainll_item_p->u.ssv_p->measnumfamily = (short) value;
1334                 }
1335                 else {
1336                         return;
1337                 }
1338                 break;
1339
1340         default:
1341                 pfatal("unknown font variable");
1342                 break;
1343         }
1344
1345         mainll_item_p->u.ssv_p->used[var] = YES;
1346 }
1347 \f
1348
1349 /* set number of stafflines and whether or not to print clef. Number of
1350  * lines must be 1 or 5, unless it's a tablature staff,
1351  * in which case it can be anything from MINTABLINES to MAXTABLINES.
1352  * In any case, it must be set before any music data. */
1353
1354 void
1355 asgn_stafflines(numlines, printclef, mainll_item_p)
1356
1357 int numlines;   /* 1 or 5 for normal, or MINTABLINES to MAXTABLINES for tablature */
1358 int printclef;  /* SS_* */
1359 struct MAINLL *mainll_item_p;   /* where to set value */
1360
1361 {
1362         int is_tab;     /* YES if is tablature staff */
1363         int staff_index;
1364
1365         
1366         if (mainll_item_p == (struct MAINLL *) 0) {
1367                 /* must be in here due to some user syntax error */
1368                 return;
1369         }
1370
1371         is_tab = is_tablature_staff(mainll_item_p->u.ssv_p);
1372         if (is_tab == YES) {
1373                 if (contextcheck(C_STAFF, "stafflines=tab") == NO) {
1374                         return;
1375                 }
1376         }
1377         else {
1378                 if (contextcheck(C_SCORE | C_STAFF, "stafflines parameter") == NO) {
1379                         return;
1380                 }
1381         }
1382
1383         /* exclaim if already set in this SSV */
1384         used_check(mainll_item_p, STAFFLINES, "stafflines");
1385
1386         if (is_tab == YES) {
1387                 /* is a tablature staff */
1388                 (void) rangecheck(numlines, MINTABLINES, MAXTABLINES,
1389                                         "number of tab strings specified");
1390         }
1391         else {
1392                 /* not a tablature staff */
1393                 if (numlines != 5 && numlines != 1) {
1394                         yyerror("stafflines must be 1 or 5");
1395                 }
1396         }
1397
1398
1399         mainll_item_p->u.ssv_p->stafflines = (short) numlines;
1400
1401         /* single line never has clef except the drum clef,
1402          * so if user didn't explictly set 'n' we do it for them */
1403         if (numlines == 1 && printclef == SS_NORMAL) {
1404                 printclef = NO;
1405         }
1406         mainll_item_p->u.ssv_p->printclef = (short) printclef;
1407         mainll_item_p->u.ssv_p->used[STAFFLINES] = YES;
1408
1409         /* index into Staff array is staffno - 1 */
1410         staff_index = mainll_item_p->u.ssv_p->staffno - 1;
1411
1412         /* need to do extra consistency check for tablature staffs */
1413         if (is_tab == YES) {
1414                 
1415                 if (staff_index == 0) {
1416                         yyerror("staff 1 can't be a tablature staff");
1417                 }
1418                 else {
1419                         if (is_tablature_staff( &(Staff[staff_index - 1]) ) == YES
1420                                 || (staff_index < MAXSTAFFS - 1 &&
1421                                 is_tablature_staff( &(Staff[staff_index + 1]) )
1422                                 == YES) ) {
1423                             yyerror("can't have two consecutive tablature staffs");
1424                         }
1425                         if (svpath(mainll_item_p->u.ssv_p->staffno - 1,
1426                                         STAFFLINES)->stafflines != 5) {
1427                                 yyerror("staff before a tablature staff must be a 5-line staff");
1428                         }
1429                 }
1430         }
1431         else {
1432                 /* if trying to establish a non-5-line non-tablature staff,
1433                  * and it's not the bottom staff, and the staff below is a
1434                  * tablature staff, that's a no-no */
1435                 if (numlines != 5 && staff_index < MAXSTAFFS - 1 &&
1436                                 is_tablature_staff( &(Staff[staff_index + 1]) )
1437                                 == YES) {
1438                         yyerror("staff before a tablature staff must be a 5-line staff");
1439                 } 
1440         }
1441
1442         /* assign, so we can do error checking on tablature staffs
1443          * for future SSVs that we process */
1444         asgnssv(mainll_item_p->u.ssv_p);
1445 }
1446 \f
1447
1448 /* When the input contains a rangelist, we need to allocate some space for
1449  * the information. Allocate an array of length CHUNK. Set the Ss_count to start
1450  * filling in element 0, and mark the Ss_length as CHUNK. As we add elements,
1451  * Ss_count will be incremented, and the array size enlarged if it overflows.
1452  */
1453
1454 void
1455 new_staffset()
1456
1457 {
1458         CALLOC(STAFFSET, Curr_staffset_p, CHUNK);
1459
1460         Ss_count = 0;
1461         Ss_length = CHUNK;
1462 }
1463 \f
1464
1465 /* add information about one staffset, at the current offset in the list,
1466  * re-allocating additional space if necessary */
1467
1468 void
1469 add_staffset(start, end, label1, label2)
1470
1471 int start, end;         /* of the range */
1472 char *label1, *label2;  /* malloc-ed copies of labels for the range, or NULL */
1473
1474 {
1475         /* Murphey's Law insurance */
1476         if (Curr_staffset_p == (struct STAFFSET *) 0) {
1477                 pfatal("NULL staffset");
1478         }
1479
1480         /* swap if backwards */
1481         if ( start > end) {
1482                 int tmp;
1483
1484                 tmp = start;
1485                 start = end;
1486                 end = tmp;
1487         }
1488
1489         /* if we guessed too small, need to make a bigger array */
1490         if (Ss_count >= Ss_length) {
1491                 Ss_length += CHUNK;
1492                 REALLOC(STAFFSET, Curr_staffset_p, Ss_length);
1493         }
1494
1495         /* fill in values */
1496         Curr_staffset_p[Ss_count].topstaff = (short) start;
1497         Curr_staffset_p[Ss_count].botstaff = (short) end;
1498         if (label1 != (char *) 0) {
1499                 (void) fix_string(label1, label1[0], label1[1],
1500                                         Curr_filename, yylineno);
1501         }
1502         Curr_staffset_p[Ss_count].label = label1;
1503         if (label2 != (char *) 0) {
1504                 (void) fix_string(label2, label2[0], label2[1],
1505                                         Curr_filename, yylineno);
1506         }
1507         Curr_staffset_p[Ss_count].label2 = label2;
1508
1509         /* one more item in list */
1510         Ss_count++;
1511 }
1512 \f
1513
1514 /* When we have collected an entire list of ranges, assign the
1515  * list to the appropriate place in the SSV struct.
1516  * (Using "set" instead of "assign" for function name because some
1517  * people's compilers are too stupid to tell the difference in names
1518  * after 8 characters, which would clash with another function name) */
1519
1520 void
1521 set_staffset(var, mainll_item_p)
1522
1523 int var;                        /* which rangelist to set */
1524 struct MAINLL *mainll_item_p;   /* which struct to assign it in */
1525
1526 {
1527         register int i;         /* index through ranges */
1528         short okay = NO;        /* if passed all overlap checks */
1529
1530
1531         /* can only do this in score context */
1532         if (contextcheck(C_SCORE, "list of staff ranges") == NO) {
1533                 return;
1534         }
1535
1536         /* first we need to make sure no ranges are out of range */
1537         /* go through the list of ranges */
1538         for (i = 0; i < Ss_count; i++) {
1539
1540                 /* range check. Make sure it is within number of staffs that
1541                  * user specified. Since when we assign the user-specified
1542                  * number, we make sure that is within MAXSTAFFS, it will
1543                  * be within the absolute maximum as well.
1544                  */
1545                 if (rangecheck(Curr_staffset_p[i].botstaff, 1, Score.staffs,
1546                                         "brace/bracket staff number") == NO) {
1547                         return;
1548                 }
1549         }
1550         
1551         /* if explicitly empty, can free space */
1552         if (Ss_count == 0) {
1553                 FREE(Curr_staffset_p);
1554         }
1555         else {
1556                 /* we probably have too much space allocated, shed the rest */
1557                 REALLOC(STAFFSET, Curr_staffset_p, Ss_count);
1558
1559                 /* sort lowest to highest */
1560                 qsort( (char *) Curr_staffset_p, (unsigned int) Ss_count,
1561                                         sizeof(struct STAFFSET), comp_staffset);
1562         }
1563
1564         if (mainll_item_p == (struct MAINLL *) 0) {
1565                 pfatal("NULL SSV for staffset");
1566         }
1567
1568         /* now assign to appropriate variable */
1569         switch (var) {
1570
1571         case BRACELIST:
1572                 mainll_item_p->u.ssv_p->bracelist = (Ss_count == 0 ?
1573                                 (struct STAFFSET *) 0 : Curr_staffset_p);
1574                 mainll_item_p->u.ssv_p->nbrace = (short) Ss_count;
1575                 okay = brac_check(Curr_staffset_p, Ss_count,
1576                                         Score.bracklist, Score.nbrack);
1577                 used_check(mainll_item_p, var, "brace");
1578                 break;
1579
1580         case BRACKLIST:
1581                 mainll_item_p->u.ssv_p->bracklist = (Ss_count == 0 ?
1582                                 (struct STAFFSET *) 0 : Curr_staffset_p);
1583                 mainll_item_p->u.ssv_p->nbrack = (short) Ss_count;
1584                 okay = brac_check(Score.bracelist, Score.nbrace,
1585                                         Curr_staffset_p, Ss_count);
1586                 used_check(mainll_item_p, var, "bracket");
1587                 break;
1588
1589         default:
1590                 pfatal("unknown staffset type");
1591                 break;
1592         }
1593
1594         if (okay == YES) {
1595                 mainll_item_p->u.ssv_p->used[var] = YES;
1596
1597                 /* assign now, so we can check for overlap */
1598                 asgnssv(mainll_item_p->u.ssv_p);
1599         }
1600
1601         /* the list has been attached to its permanent place, so
1602          * reset the temporary pointer to an empty list */
1603         Curr_staffset_p = (struct STAFFSET *) 0;
1604         Ss_count = 0;
1605 }
1606 \f
1607
1608 /* compare 2 STAFFSETs for sorting using qsort */
1609
1610 static int
1611 comp_staffset(item1_p, item2_p)
1612
1613 #ifdef __STDC__
1614 const void *item1_p;    /* the two items to compare */
1615 const void *item2_p;
1616 #else
1617 char *item1_p;  /* the two items to compare */
1618 char *item2_p;
1619 #endif
1620
1621 {
1622         int top1, top2;
1623         int bot1, bot2;
1624
1625         top1 = ((struct STAFFSET *)item1_p)->topstaff;
1626         top2 = ((struct STAFFSET *)item2_p)->topstaff;
1627         bot1 = ((struct STAFFSET *)item1_p)->botstaff;
1628         bot2 = ((struct STAFFSET *)item2_p)->botstaff;
1629
1630         if (top1 < top2) {
1631                 return(-1);
1632         }
1633
1634         else if (top1 > top2) {
1635                 return(1);
1636         }
1637
1638         else if (bot1 < bot2) {
1639                 return(-1);
1640         }
1641
1642         else if (bot1 > bot2) {
1643                 return(1);
1644         }
1645
1646         else {
1647                 return(0);
1648         }
1649 }
1650 \f
1651
1652 /* allocate an array of TOP_BOT structs for building up a list of bar style
1653  * information (which staffs to bar together) */
1654
1655 void
1656 new_barstlist()
1657
1658 {
1659         CALLOC(TOP_BOT, Curr_barstlist_p, CHUNK);
1660
1661         /* initialize used and allocated lengths */
1662         Barst_count = 0;
1663         Barst_length = CHUNK;
1664 }
1665 \f
1666
1667 /* add a pair of staff numbers to bar style list */
1668
1669 void
1670 add_barst(start, end)
1671
1672 int start;      /* first staff to bar together */
1673 int end;        /* last staff to bar together */
1674
1675 {
1676         if (Curr_barstlist_p == (struct TOP_BOT *) 0) {
1677                 pfatal("NULL barstlist");
1678         }
1679
1680         /* swap if backwards */
1681         if ( start > end) {
1682                 int tmp;
1683
1684                 tmp = start;
1685                 start = end;
1686                 end = tmp;
1687         }
1688
1689         /* if we guessed too small, make a bigger array */
1690         if (Barst_count >= Barst_length) {
1691
1692                 Barst_length += CHUNK;
1693
1694                 REALLOC(TOP_BOT, Curr_barstlist_p, Barst_length);
1695         }
1696
1697         Curr_barstlist_p[Barst_count].top = (short) start;
1698         Curr_barstlist_p[Barst_count].bottom = (short) end;
1699
1700         /* one more item on list */
1701         Barst_count++;
1702 }
1703 \f
1704
1705 /* When we have collected an entire list of ranges, assign the
1706  * list to the appropriate place in the SSV struct */
1707
1708 void
1709 set_barstlist(mainll_item_p)
1710
1711 struct MAINLL *mainll_item_p;   /* which struct to assign it in */
1712
1713 {
1714         register int i, s;              /* index for ranges and staffs */
1715         short mentioned[MAXSTAFFS + 1]; /* mark whether each staff occurs in
1716                                          * this list somewhere. Element 0 is
1717                                          * unused */
1718
1719
1720         if (contextcheck(C_SCORE, "barstyle parameter") == NO) {
1721                 return;
1722         }
1723
1724         /* exclaim if alrady set in this SSV */
1725         used_check(mainll_item_p, BARSTLIST, "barstyle");
1726
1727         /* first we need to make sure no ranges overlap or are out of range */
1728
1729         /* initialize that we haven't seen anything yet */
1730         for (s = 1; s < MAXSTAFFS + 1; s++) {
1731                 mentioned[s] = NO;
1732         }
1733
1734         /* go through the list of ranges */
1735         for (i = 0; i < Barst_count; i++) {
1736
1737                 /* range check. */
1738                 if (rangecheck(Curr_barstlist_p[i].bottom, 1, Score.staffs,
1739                                 "barstyle staff number") == NO) {
1740                         continue;
1741                 }
1742                 
1743                 /* fill in each in the range as having been mentioned.
1744                  * If already mentioned, we have a problem */
1745                 for (s = Curr_barstlist_p[i].top;
1746                                         s <= Curr_barstlist_p[i].bottom; s++) {
1747
1748                         if (mentioned[s] == YES) {
1749                                 yyerror("overlapping range in bar list");
1750                         }
1751
1752                         else {
1753                                 mentioned[s] = YES;
1754                         }
1755                 }
1756         }
1757         
1758         /* if explicitly empty, free space */
1759         if (Barst_count == 0) {
1760                 FREE(Curr_barstlist_p);
1761         }
1762
1763         else {
1764                 /* we probably have too much space allocated, shed the rest */
1765                 REALLOC(TOP_BOT, Curr_barstlist_p, Barst_count);
1766
1767                 /* sort lowest to highest */
1768                 qsort ( (char *) Curr_barstlist_p, (unsigned int) Barst_count,
1769                         sizeof(struct TOP_BOT), comp_barst);
1770         }
1771
1772         if (mainll_item_p == (struct MAINLL *) 0) {
1773                 pfatal("NULL SSV for barstlist");
1774         }
1775
1776         /* fill in data */
1777         mainll_item_p->u.ssv_p->nbarst = (short) Barst_count;
1778         if (Barst_count > 0) {
1779                 mainll_item_p->u.ssv_p->barstlist = Curr_barstlist_p;
1780         }
1781
1782         mainll_item_p->u.ssv_p->used[BARSTLIST] = YES;
1783
1784         /* now that list has been assigned to its proper place,
1785          * re-initialize pointer to null to prepare for another list */
1786         Curr_barstlist_p = (struct TOP_BOT *) 0;
1787         Barst_count = 0;
1788 }
1789 \f
1790
1791 /* compare 2 barslist items for sorting using qsort */
1792
1793 static int
1794 comp_barst(item1_p, item2_p)
1795
1796 #ifdef __STDC__
1797 const void *item1_p;    /* the two items to compare */
1798 const void *item2_p;
1799 #else
1800 char *item1_p;  /* the two items to compare */
1801 char *item2_p;
1802 #endif
1803
1804 {
1805         if ( ((struct TOP_BOT *)item1_p)->top
1806                                 < ((struct TOP_BOT *)item2_p)->top) {
1807                 return(-1);
1808         }
1809
1810         else if ( ((struct TOP_BOT *)item1_p)->top
1811                                 > ((struct TOP_BOT *)item2_p)->top) {
1812                 return(1);
1813         }
1814
1815         else {
1816                 /* actually this should never occur */
1817                 return(0);
1818         }
1819 }
1820 \f
1821
1822 /* Initialize and allocate space for beamstyle information */
1823
1824 void
1825 new_beamlist()
1826
1827 {
1828         init_beamlist(&Curr_beamstyle);
1829         init_beamlist(&Curr_subbeamstyle);
1830         Subbeam_index = -1;
1831 }
1832
1833
1834 /* Initalize a BEAMLIST struct.
1835  * Allocate CHUNK entries, and mark that 0 of them are currently used.
1836  */
1837
1838 static void
1839 init_beamlist(beamlist_p)
1840
1841 struct BEAMLIST *beamlist_p;
1842
1843 {
1844         MALLOCA(RATIONAL, beamlist_p->list_p, CHUNK);
1845         beamlist_p->count = 0;
1846         beamlist_p->length = CHUNK;
1847 }
1848 \f
1849
1850 /* This function is called at the parenthesis to begin a sub-beam grouping.
1851  * It saves the current index into the subbeam list. At the ending parenthesis,
1852  * we add up add the subbeam list time values since that saved index.
1853  */
1854
1855 void
1856 begin_subbeam()
1857
1858 {
1859         if (Subbeam_index >= 0) {
1860                 yyerror("Nested sub-beam groups not allowed");
1861                 return;
1862         }
1863         Subbeam_index = Curr_subbeamstyle.count;
1864 }
1865
1866 void
1867 end_subbeam()
1868 {
1869         RATIONAL tot_time;
1870
1871         /* Do error checks */
1872         if (Subbeam_index < 0) {
1873                 yyerror("Missing '(' for sub-beam grouping");
1874                 return;
1875         }
1876         if (Subbeam_index >= Curr_subbeamstyle.count - 1) {
1877                 warning("sub-beam grouping needs at least two values");
1878         }
1879
1880         /* Count up all the time values of subbeams that make up the
1881          * single outer beam. */
1882         for (tot_time = Zero; Subbeam_index < Curr_subbeamstyle.count;
1883                                                 Subbeam_index++) {
1884                 tot_time = radd(tot_time, Curr_subbeamstyle.list_p[Subbeam_index]);
1885         }
1886         add2outerbeam(tot_time);
1887         Subbeam_index = -1;
1888 }
1889 \f
1890
1891 /* Add an entry to the current beam list */
1892
1893 void
1894 add_beamlist(value)
1895
1896 RATIONAL value;         /* what to add to beam list */
1897
1898 {
1899         /* If we guessed too small, make a bigger array */
1900         if (Curr_subbeamstyle.count >= Curr_subbeamstyle.length) {
1901                 Curr_subbeamstyle.length += CHUNK;
1902                 REALLOCA(RATIONAL, Curr_subbeamstyle.list_p, Curr_subbeamstyle.length);
1903         }
1904
1905         Curr_subbeamstyle.list_p[Curr_subbeamstyle.count] = value;
1906         (Curr_subbeamstyle.count)++;
1907
1908         /* If not in a subbeam grouping, goes into Curr_beamstyle too */
1909         if (Subbeam_index < 0) {
1910                 add2outerbeam(value);
1911         }
1912 }
1913 \f
1914
1915 /* Add entry to time values for the outermost beam. In the case of subbeaming,
1916  * the value will be the sum of the subbeams values; otherwise it will be
1917  * the same as that in the subbeam list.
1918  */
1919
1920 static void
1921 add2outerbeam(value)
1922
1923 RATIONAL value;
1924
1925 {
1926         /* If we guessed too small, make a bigger array */
1927         if (Curr_beamstyle.count >= Curr_beamstyle.length) {
1928                 Curr_beamstyle.length += CHUNK;
1929                 REALLOCA(RATIONAL, Curr_beamstyle.list_p, Curr_beamstyle.length);
1930         }
1931         Curr_beamstyle.list_p[Curr_beamstyle.count] = value;
1932         (Curr_beamstyle.count)++;
1933 }
1934 \f
1935
1936 /* Assign current beam list to SSV structure in main list */
1937
1938 void
1939 set_beamlist(mainll_item_p)
1940
1941 struct MAINLL *mainll_item_p;           /* where to attach list */
1942
1943 {
1944         if (contextcheck(C_SSV, "beamstyle parameter") == NO) {
1945                 return;
1946         }
1947
1948         /* exclaim if already set in this SSV */
1949         used_check(mainll_item_p, BEAMSTLIST, "beamstyle");
1950
1951         /* Shed any extra allocated space */
1952         if (Curr_beamstyle.count == 0) {
1953                 FREE(Curr_beamstyle.list_p);
1954                 Curr_beamstyle.list_p = 0;
1955         }
1956         else if (Curr_beamstyle.count < Curr_beamstyle.length) {
1957                 REALLOCA(RATIONAL, Curr_beamstyle.list_p, Curr_beamstyle.count);
1958         }
1959         if (Curr_subbeamstyle.count == 0) {
1960                 FREE(Curr_subbeamstyle.list_p);
1961                 Curr_subbeamstyle.list_p = 0;
1962         }
1963         else if (Curr_subbeamstyle.count < Curr_subbeamstyle.length) {
1964                 REALLOCA(RATIONAL, Curr_subbeamstyle.list_p, Curr_subbeamstyle.count);
1965         }
1966
1967         if (mainll_item_p == (struct MAINLL *) 0) {
1968                 pfatal("NULL SSV for beamlist");
1969         }
1970
1971         if (Context != C_SCORE && is_tab_staff(mainll_item_p->u.ssv_p->staffno)
1972                                         == YES) {
1973                 yyerror("beamstyle not allowed on tablature staff");
1974                 return;
1975         }
1976
1977         /* attach to the SSV struct and mark as used */
1978         mainll_item_p->u.ssv_p->beamstlist = Curr_beamstyle.list_p;
1979         mainll_item_p->u.ssv_p->subbeamstlist = Curr_subbeamstyle.list_p;
1980         mainll_item_p->u.ssv_p->nbeam = (short) Curr_beamstyle.count;
1981         mainll_item_p->u.ssv_p->nsubbeam = (short) Curr_subbeamstyle.count;
1982         mainll_item_p->u.ssv_p->used[BEAMSTLIST] = YES;
1983
1984         if (Curr_beamstyle.count > 0) {
1985                 /* make sure time adds up to exactly a measure */
1986                 RATIONAL tot_time;      /* sum of times in beamstyle list */
1987                 register int n;
1988
1989                 tot_time = Zero;
1990
1991                 for (n = 0; n < Curr_beamstyle.count; n++) {
1992                         tot_time = radd(tot_time, Curr_beamstyle.list_p[n]);
1993                 }
1994
1995                 if (NE(tot_time, Score.time)) {
1996                         yyerror("beam list does not add up to a measure");
1997                 }
1998         }
1999
2000         /* Mark temporary lists as invalid */
2001         Curr_beamstyle.list_p = 0;
2002         Curr_subbeamstyle.list_p = 0;
2003
2004         asgnssv(mainll_item_p->u.ssv_p);
2005 }
2006 \f
2007
2008 void
2009 assign_unit(unittype, mainll_p)
2010
2011 int unittype;
2012 struct MAINLL *mainll_p;
2013
2014 {
2015         if (contextcheck(C_SCORE, "units parameter") == NO) {
2016                 return;
2017         }
2018
2019         mainll_p->u.ssv_p->units = unittype;
2020         Score.units = unittype;
2021 }
2022 \f
2023
2024 /* return YES if given SSV refers to a tablature staff, NO if not.
2025  * This function is different than the is_tab_staff() function in that
2026  * this takes an ssv_p and thus can be used on a user's SSV, whereas
2027  * is_tab_staff takes a staff number and only works on the SSVs in
2028  * the Staff array. */
2029
2030 static int
2031 is_tablature_staff(ssv_p)
2032
2033 struct SSV *ssv_p;
2034
2035 {
2036         return (ssv_p->strinfo != (struct STRINGINFO *) 0 ? YES : NO);
2037 }
2038 \f
2039
2040 /* add information about a string for a tablature staff. This gets put
2041  * in a malloc-ed strinfo array off the ssv_p struct */
2042
2043 void
2044 add_tab_string_info(letter, accidental, nticks, octave, ssv_p)
2045
2046 int letter;             /* pitch letter 'a' to 'g' */
2047 int accidental;         /* #, &, or \0, others are blocked by parser */
2048 int nticks;             /* how many tick marks, to distinguish multiple
2049                          * strings with the same pitch/accidental */
2050 int octave;             /* for MIDI and translating to tabnote staff */
2051 struct SSV *ssv_p;      /* add the info to this struct */
2052
2053 {
2054         int index;      /* which strinfo array element we are filling in */
2055         int i;
2056
2057
2058         /* increment number of stafflines. This gets done for real later
2059          * by asgn_stafflines(), but we do it here to keep track of how
2060          * many structs we have malloc-ed from previous calls to this function
2061          * for previous strings */
2062         (ssv_p->stafflines)++;
2063
2064         /* first get space. If first one to add, malloc, otherwise realloc */
2065         if (ssv_p->stafflines == 1) {
2066                 MALLOC(STRINGINFO, ssv_p->strinfo, ssv_p->stafflines);
2067         }
2068         else {
2069                 REALLOC(STRINGINFO, ssv_p->strinfo, ssv_p->stafflines);
2070         }
2071
2072         /* get the index of the new element we are adding */
2073         index = ssv_p->stafflines - 1;
2074
2075         /* fill in the data */
2076         ssv_p->strinfo[index].letter = (char) letter;
2077         ssv_p->strinfo[index].accidental = (char) accidental;
2078         ssv_p->strinfo[index].nticks = (short) nticks;
2079         ssv_p->strinfo[index].octave
2080                 = (short) (octave == USE_DFLT_OCTAVE ? TABDEFOCT : octave);
2081
2082         /* check for duplicate strings */
2083         for (i = 0; i < index; i++) {
2084                 if (ssv_p->strinfo[i].letter == letter
2085                                 && ssv_p->strinfo[i].accidental == accidental
2086                                 && ssv_p->strinfo[i].nticks == nticks) {
2087                         l_yyerror(Curr_filename, yylineno,
2088                                 "duplicate %c%c%sstring, use ' marks to distinguish",
2089                                 letter, accidental ? accidental : ' ',
2090                                 accidental ? " " : "");
2091                 }
2092         }
2093 }
2094 \f
2095
2096 /* Save user-specified measure number in given bar struct,
2097  * after verifying it is valid (that is it > 0).
2098  */
2099
2100 void
2101 set_mnum(bar_p, mnum)
2102
2103 struct BAR *bar_p;
2104 int mnum;
2105
2106 {
2107         char *old_reh_string;
2108         char num_string[8];
2109
2110         if (mnum < 1) {
2111                 l_yyerror(Curr_filename, yylineno, "mnum must be > 0");
2112         }
2113         else if (bar_p->mnum != 0) {
2114                 l_yyerror(Curr_filename, yylineno,
2115                         "mnum cannot be specified more than once per bar");
2116         }
2117         else {
2118                 Meas_num = bar_p->mnum = mnum;
2119                 /* If user had already specified " reh mnum" on this bar,
2120                  * we would already have made a reh_string for it, so we
2121                  * have to undo that. It would be nicer to delay the call
2122                  * to set_reh_string till after we've set mnum, but by then
2123                  * we would have lost the information we needed unless we
2124                  * added a bunch more code, so even though this approach
2125                  * isn't ideal, it's easiest. This shouldn't happen very
2126                  * often anyway. */
2127                 if ( (bar_p->reh_type == REH_MNUM) &&
2128                                         (bar_p->reh_string != (char *) 0) ) {
2129                         old_reh_string = bar_p->reh_string;
2130                         (void) sprintf(num_string, "%d", mnum);
2131                         bar_p->reh_string = copy_string(num_string,
2132                                         (int) old_reh_string[0],
2133                                         (int) old_reh_string[1]);
2134                         FREE(old_reh_string);
2135                 }
2136         }
2137 }
2138 \f
2139
2140 /* Give error if margin is too wide, If any is negative, use from Score */
2141
2142 void
2143 chkmargin(topmargin, botmargin, leftmargin, rightmargin)
2144
2145 double topmargin;
2146 double botmargin;
2147 double leftmargin;
2148 double rightmargin;
2149
2150 {
2151         if (topmargin < 0.0) {
2152                 topmargin = Score.topmargin;
2153         }
2154         if (botmargin < 0.0) {
2155                 botmargin = Score.botmargin;
2156         }
2157         if (leftmargin < 0.0) {
2158                 leftmargin = Score.leftmargin;
2159         }
2160         if (rightmargin < 0.0) {
2161                 rightmargin = Score.rightmargin;
2162         }
2163         if (((Score.pageheight - topmargin - botmargin) < MIN_USABLE_SPACE)
2164                         || ((Score.pagewidth - leftmargin - rightmargin)
2165                         < MIN_USABLE_SPACE)) {
2166                 yyerror("page size minus margins is too small");
2167         }
2168 }
2169 \f
2170
2171 /* function to let other files get to the ADJUST2INCHES macro */
2172
2173 double
2174 adjust2inches(value)
2175
2176 double value;
2177
2178 {
2179         ADJUST2INCHES(value);
2180         return(value);
2181 }