chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / assign.c
CommitLineData
69695f33
MW
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
40static struct STAFFSET *Curr_staffset_p;/* staffset currently
41 * being filled in */
42static int Ss_count; /* num of elements in Curr_staffset_p
43 * currently actually being used */
44static int Ss_length; /* num of elements allocated
45 * to Curr_staffset_p */
46
47static struct TOP_BOT *Curr_barstlist_p;/* bar style list being filled in */
48static int Barst_count; /* number of elements in
49 * Curr_barstlist_p that are currently
50 * filled in with valid values */
51static int Barst_length; /* number of elements allocated to
52 * Curr_barstlist_p */
53
54struct 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. */
60static struct BEAMLIST Curr_beamstyle;
61static struct BEAMLIST Curr_subbeamstyle;
62static int Subbeam_index; /* Index into Curr_subbeamstyle where
63 * the most recent '(' was, or -1 if
64 * no pending unmatched parenthesis. */
65static 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 */
71static 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
75static 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));
78static void chg_too_late P((char *var_name));
79
80/* comparison functions to be passed to qsort */
81static int comp_staffset P((const void *item1_p,
82 const void *item2_p));
83static int comp_barst P((const void *item1_p, const void *item2_p));
84static int is_tablature_staff P((struct SSV *ssv_p));
85static void init_beamlist P((struct BEAMLIST *beamlist_p));
86static 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
92void
93assign_int(var, value, mainll_item_p)
94
95int var; /* SSV index of which variable to set */
96int value; /* what to set it to */
97struct 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
415static int
416do_assign(var, value, min, max, cont, empty_value, name, mainll_item_p, ptr2dest)
417
418int var; /* which variable to set */
419int value; /* what to set it to */
420int min; /* minimum valid value */
421int max; /* maximum valid value */
422int cont; /* valid context(s) (bitmap) */
423int 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 */
428char *name; /* of internal variable, for error messages */
429struct MAINLL *mainll_item_p; /* which structure to set it in */
430short *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
463void
464assign_float(var, value, mainll_item_p)
465
466int var; /* which variable to set */
467double value; /* what to set it to */
468struct 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
677void
678assign_2floats(var, value1, value2, mainll_item_p)
679
680int var; /* which variable to set */
681double value1, value2; /* which values to set */
682struct 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
722static void
723chg_too_late(var_name)
724
725char *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
744static int
745do_fassign(var, value, min, max, cont, name, mainll_item_p, ptr2dest)
746
747int var; /* which variable to set */
748double value; /* what to set it to */
749double min; /* minimum valid value */
750double max; /* maximum valid value */
751int cont; /* valid context(s) (bitmap) */
752char *name; /* for error messages */
753struct MAINLL *mainll_item_p; /* which structure to set it in */
754float *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
787void
788assign_vscheme(numvoices, vtype, mainll_item_p)
789
790int numvoices; /* 1, 2, or 3 */
791int 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 */
796struct 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
843void
844assign_vcombine(qualifier, mainll_p)
845
846int qualifier;
847struct 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
910void
911assign_key(num, acc, is_minor, mainll_item_p)
912
913int num; /* number of sharps or flats */
914int acc; /* # or & for sharp or flat */
915int is_minor; /* YES or NO */
916struct 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
948void
949assign_string(var, string, mainll_item_p)
950
951int var; /* LABEL, LABEL2, or NOTEHEADS */
952char *string; /* the string to assign */
953struct 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
1062char *
1063copy_string(string, font, size)
1064
1065char *string; /* make a copy of this string */
1066int font; /* use this font */
1067int 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
1100void
1101assign_timesig(mainll_item_p, visibility, next_alternation_p)
1102
1103struct MAINLL *mainll_item_p; /* SSV to assign time signature in */
1104int visibility; /* YES, NO, or EACHMEAS */
1105char **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
1204void
1205set_font(var, value, mainll_item_p)
1206
1207int var; /* which variable to set */
1208int value; /* which font to set it too */
1209struct 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
1354void
1355asgn_stafflines(numlines, printclef, mainll_item_p)
1356
1357int numlines; /* 1 or 5 for normal, or MINTABLINES to MAXTABLINES for tablature */
1358int printclef; /* SS_* */
1359struct 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
1454void
1455new_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
1468void
1469add_staffset(start, end, label1, label2)
1470
1471int start, end; /* of the range */
1472char *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
1520void
1521set_staffset(var, mainll_item_p)
1522
1523int var; /* which rangelist to set */
1524struct 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
1610static int
1611comp_staffset(item1_p, item2_p)
1612
1613#ifdef __STDC__
1614const void *item1_p; /* the two items to compare */
1615const void *item2_p;
1616#else
1617char *item1_p; /* the two items to compare */
1618char *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
1655void
1656new_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
1669void
1670add_barst(start, end)
1671
1672int start; /* first staff to bar together */
1673int 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
1708void
1709set_barstlist(mainll_item_p)
1710
1711struct 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
1793static int
1794comp_barst(item1_p, item2_p)
1795
1796#ifdef __STDC__
1797const void *item1_p; /* the two items to compare */
1798const void *item2_p;
1799#else
1800char *item1_p; /* the two items to compare */
1801char *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
1824void
1825new_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
1838static void
1839init_beamlist(beamlist_p)
1840
1841struct 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
1855void
1856begin_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
1866void
1867end_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
1893void
1894add_beamlist(value)
1895
1896RATIONAL 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
1920static void
1921add2outerbeam(value)
1922
1923RATIONAL 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
1938void
1939set_beamlist(mainll_item_p)
1940
1941struct 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
2008void
2009assign_unit(unittype, mainll_p)
2010
2011int unittype;
2012struct 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
2030static int
2031is_tablature_staff(ssv_p)
2032
2033struct 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
2043void
2044add_tab_string_info(letter, accidental, nticks, octave, ssv_p)
2045
2046int letter; /* pitch letter 'a' to 'g' */
2047int accidental; /* #, &, or \0, others are blocked by parser */
2048int nticks; /* how many tick marks, to distinguish multiple
2049 * strings with the same pitch/accidental */
2050int octave; /* for MIDI and translating to tabnote staff */
2051struct 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
2100void
2101set_mnum(bar_p, mnum)
2102
2103struct BAR *bar_p;
2104int 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
2142void
2143chkmargin(topmargin, botmargin, leftmargin, rightmargin)
2144
2145double topmargin;
2146double botmargin;
2147double leftmargin;
2148double 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
2173double
2174adjust2inches(value)
2175
2176double value;
2177
2178{
2179 ADJUST2INCHES(value);
2180 return(value);
2181}