chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / parstuff.c
1
2 /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004 by Arkkra Enterprises */
3 /* All rights reserved */
4
5 /* parser functions related to STUFF */
6
7
8 #include <string.h>
9 #include "defines.h"
10 #include "structs.h"
11 #include "globals.h"
12
13 /* if user specifies a "til" clause on stuff with a number of measures > 0,
14  * we need to save away info about where the til clause will end, to make sure
15  * that it doesn't fall off the end of the measure or the piece. This is the
16  * struct we use to save this info. */
17 static struct TIL_INFO {
18         char    *inputfile;     /* where STUFF was defined */
19         int     inputlineno;    /* where STUFF was defined */
20         int     measnum;        /* number of measure in which til clause ends */
21         float   count;          /* count in measure where til clause ends */
22         struct TIL_INFO *next;  /* for linked list */
23 } *Til_info_list_p;
24
25 /* info about the STUFF currently being collected from input */
26 static int Curr_stuff_type;     /* ST_* */
27 static int Stuff_size;          /* point size of stuff text string */
28 static int Modifier;            /* TM_* for text, L_* for phrase */
29 static int Measnum = 1;         /* to check til clauses. Can't use Meas_num
30                                  * global because it doesn't count invisible
31                                  * bars but til clauses do */
32 static int Multi_adjust;        /* adjustment to Measnum to account
33                                  * for multirests */
34
35 /* head and tail of list of STUFF currently being collected from input */
36 static struct STUFF *Head_stufflist_p;
37 static struct STUFF *Tail_stufflist_p;
38
39 /* current pedal state for each staff. YES if in the middle of doing pedal,
40  * NO if not. */
41 static short Pedal_state[MAXSTAFFS + 1];
42 static char *Ped_begin_str;     /* will point to "\(begped)" */
43 static char *Ped_up_down_str;   /* will point to "\(pedal)" */
44
45 /* static functions */
46 static struct STUFF *clone_stufflist P((struct STUFF *stufflist_p,
47                         int staffno, int all));
48 static void do_attach P((int staffno, int all, struct RANGELIST *vno_range_p));
49 static void midi_attach P((int staffno, struct STAFF *staff_p,
50                         struct RANGELIST *vno_range_p, int all));
51 static void free_stufflist P((struct STUFF *stuff_P));
52 static void free_tils P((struct TIL_INFO *til_p));
53 static void fix_pedal P((int staffno, struct STUFF *stuff_p));
54 static void ped_order_chk P((void));
55 \f
56
57 /* save current stuff type value. Also check that we are in data (music)
58  * context */
59
60 void
61 set_stuff_type(stuff_type)
62
63 int stuff_type;
64
65 {
66         Curr_stuff_type = stuff_type;
67
68         (void) contextcheck(C_MUSIC, "statement");
69 }
70 \f
71
72 /* return current stuff type */
73
74 int
75 get_stuff_type()
76
77 {
78         return(Curr_stuff_type);
79 }
80 \f
81
82 /* check all the things in an input line of stuff, up to the colon,
83  * for consistency, and save interesting info away for later use. */
84
85 void
86 chk_stuff_header(size, modifier, place, dist_usage)
87
88 int size;               /* point size, or -1 if to use default */
89 int modifier;           /* TM_* for text, L_* for phrase */
90 int place;              /* PL_* */
91 int dist_usage;         /* SD_* */
92
93 {
94
95         debug(4, "chk_stuff_header");
96
97         switch (Curr_stuff_type) {
98         case ST_ROM:
99         case ST_BOLD:
100         case ST_ITAL:
101         case ST_BOLDITAL:
102         case ST_MUSSYM:
103                 break;
104         case ST_PEDAL:
105                 if (place != PL_BELOW && place != PL_UNKNOWN) {
106                         yyerror("pedal must be below");
107                 }
108                 /*FALLTHRU*/
109         default:
110                 if (size != -1) {
111                         yyerror("can't specify size except with a font or mussym");
112                 }
113                 if (modifier != TM_NONE && Curr_stuff_type != ST_PHRASE) {
114                         l_yyerror(Curr_filename, yylineno,
115                                         "can't specify %s except with a font",
116                                         stuff_modifier(modifier));
117                 }
118                 if (Curr_stuff_type == ST_PHRASE && modifier != L_NORMAL &&
119                                 modifier != L_DOTTED && modifier != L_DASHED) {
120                         l_yyerror(Curr_filename, yylineno,
121                                         "only dotted or dashed line type can be specified for phrase");
122                 }
123                 break;
124         }
125
126         if (Curr_stuff_type == ST_OCTAVE) {
127                 if (is_tab_range() == YES) {
128                         yyerror("octave not allowed on tablature staff");
129                 }
130                 else if(place == PL_BETWEEN) {
131                         yyerror("octave must be above or below");
132                         place = PL_ABOVE;
133                 }
134         }
135
136         if (Curr_stuff_type == ST_PHRASE && place == PL_BETWEEN) {
137                 yyerror("phrase must be above, below, or omitted");
138                 place = PL_ABOVE;
139         }
140
141         if (dist_usage != SD_NONE) {
142                 if (Curr_stuff_type == ST_PEDAL) {
143                         yyerror("dist not allowed on pedal");
144                 }
145                 else if (Curr_stuff_type == ST_PHRASE) {
146                         yyerror("dist not allowed on phrase");
147                 }
148                 else if (Curr_stuff_type == ST_MIDI) {
149                         yyerror("dist not allowed on midi");
150                 }
151
152                 if (place == PL_BETWEEN) {
153                         yyerror("dist not allowed with 'between'");
154                 }
155         }
156
157         /* Save the modifier value.
158          * Have to set this before calling dflt_place() */
159         Modifier = modifier;
160
161         /* fill in default values if user didn't specify */
162         if (place == PL_UNKNOWN) {
163                 place = dflt_place();
164         }
165
166         Stuff_size = size;
167         Place = (short) place;
168
169         /* make sure current list of stuff is empty */
170         Head_stufflist_p = Tail_stufflist_p = (struct STUFF *) 0;
171 }
172 \f
173
174 /* return default value for place depending on value of Curr_stuff_type */
175
176 int
177 dflt_place()
178
179 {
180         switch (Curr_stuff_type) {
181
182         case ST_PEDAL:
183                 return(PL_BELOW);
184
185         case ST_OCTAVE:
186                 yyerror("must specify above or below with octave");
187                 /* arbitrarily return above. If we leave it as unknown,
188                  * we can get double error messages in some cases */
189                 return(PL_ABOVE);
190
191         case ST_PHRASE:
192                 /* stays unknown at this point */
193                 return(PL_UNKNOWN);
194
195         default:
196                 if (Modifier == TM_ANALYSIS || Modifier == TM_FIGBASS) {
197                         return(PL_BELOW);
198                 }
199                 /* default for everything else is above */
200                 return(PL_ABOVE);
201         }
202 }
203 \f
204
205 /* Add a space padding to a string (except if is it boxed).
206  * If padding was added, free the passed-in string and return the padded string,
207  * else return the string as is. The incoming string
208  * is expected to already be converted to font/size/string
209  * internal format by this time, although still in input ASCII form.
210  */
211
212 char *
213 pad_string(string, modifier)
214
215 char *string;
216 int modifier;   /* TM_* */
217
218 {
219         char *padded_string;            /* string with 1-space padding at end */
220         char *str_p;                    /* walk through padded_string */
221         int len;                        /* length of string */
222         int last_was_backslash;         /* YES/NO */
223         int count_backslashed;          /* YES/NO if to count backslashed or
224                                          * unbackslashed colons */
225         int colons;                     /* how many colons found */
226         int extra;                      /* how many extra bytes to malloc */
227
228         /* Boxed and circled strings don't get any extra padding,
229          * so we can use what we have */
230         if (string[2] == '\\' && (string[3] == '[' || string[3] == '{')) {
231                 return(string);
232         }
233
234         /* Make a new copy with a space at the end.
235          * But if the string ends in the middle of a pile,
236          * we need to implicitly end the pile before adding the space.
237          * Since the string is still in ASCII form,
238          * we have to count up the number of colons
239          * to see if we are mid-pile. In chord/analysis/figbass
240          * we need to count unbackslashed colon,
241          * otherwise backslashed.*/
242         count_backslashed = (IS_CHORDLIKE(modifier) ? NO : YES);
243         /* figbass implicitly begins with a pile */
244         colons = (modifier == TM_FIGBASS ? 1 : 0);
245         last_was_backslash = NO;
246         for (str_p = string + 2; *str_p != '\0'; str_p++) {
247                 if (last_was_backslash == YES) {
248                         if (*str_p == ':' && count_backslashed == YES) {
249                                 colons++;
250                         }
251                         last_was_backslash = NO;
252                 }
253                 else {
254                         if (*str_p ==  ':' && count_backslashed == NO) {
255                                 colons++;
256                         }
257                         last_was_backslash = (*str_p == '\\' ? YES : NO);
258                 }
259         }
260
261         /* If odd number of colons, we are mid-pile.  Will need
262          * add extra byte to hold the colon to implicitly end the
263          * pile, and if it needs to be a backslashed colon,
264          * another extra byte for that. */
265         if (colons & 1) {
266                 extra = (count_backslashed == YES ? 2 : 1);
267         }
268         else {
269                 extra = 0;
270         }
271
272         len = strlen(string);
273
274         /* +2 is for space/null at end */
275         MALLOCA(char, padded_string, len + 2 + extra);
276         (void) memcpy(padded_string, string, len);
277         str_p = padded_string + len;
278
279         /* add implicit end-pile if needed */
280         if (extra == 2) {
281                 *str_p++ = '\\';
282         }
283         if (extra > 0) {
284                 *str_p++ = ':';
285         }
286
287         /* now add space padding */
288         *str_p++ = ' ';
289         *str_p = '\0';
290         FREE(string);
291         return(padded_string);
292 }
293 \f
294
295 /* check a "stuff" item  and add to list */
296
297 void
298 add_stuff_item(start_count, start_steps, gracebackup, string, bars, count,
299                 dist, dist_usage)
300
301 double start_count;             /* where in measure to start this stuff */
302 double start_steps;             /* offset by this many stepsizes */
303 int gracebackup;        /* how many grace notes to back up from start */
304 char *string;           /* what to print */
305 int bars;               /* how many bar lines to cross with this stuff */
306 double count;           /* how many beats into last measure */
307 int dist;               /* dist for this specific STUFF, to override param */
308 int dist_usage;         /* meaning of dist, SD_*  */
309
310 {
311         struct STUFF *new_p;            /* where to store STUFF */
312         struct TIL_INFO *til_info_p;    /* to save info about til clause */
313         int len;                        /* length of stuff text string */
314         char *padded_string;            /* string with 1-space padding at end */
315         char lch;                       /* last character of string */
316
317
318         if (bars != 0 || count != 0.0) {
319                 /* has a "til" clause. Check if that is valid */
320                 if (Curr_stuff_type == ST_MUSSYM) {
321                         if (string == (char *) 0) {
322                                 yyerror("missing string");
323                                 return;
324                         }
325
326                         /* not yet changed to internal form, need to compare
327                          * in ASCII form */
328                         if ((strcmp(string + 2, "tr") != 0) &&
329                                         (strcmp(string + 2, "\\(tr)") != 0)) {
330                                 yyerror("til not allowed on mussym except on trills");
331                         }
332                 }
333
334                 else if (Curr_stuff_type == ST_PEDAL) {
335                         yyerror("til not allowed on pedal");
336                 }
337
338                 else if (Curr_stuff_type == ST_MIDI) {
339                         yyerror("til not allowed on midi");
340                 }
341
342                 if (Curr_stuff_type != ST_PHRASE &&
343                         (Modifier == TM_CHORD || Modifier == TM_ANALYSIS) ) {
344                         l_yyerror(Curr_filename, yylineno,
345                                         "til not allowed with %s",
346                                         stuff_modifier(Modifier));
347                 }
348
349                 if (bars == 0) {
350                         if (count > Score.timenum + 1) {
351                                 yyerror("'til' value must be <= numerator of time signature + 1");
352                         }
353
354                         if (count < start_count) {
355                                 yyerror("til value must be >= start value");
356                         }
357                 }
358
359         }
360         else {
361                 /* doesn't have a "til" clause. Check if one is required */
362                 if (Curr_stuff_type == ST_CRESC ||
363                                                 Curr_stuff_type == ST_DECRESC) {
364                         yyerror("til required on cresc/decresc");
365                 }
366         }
367         
368         if (start_count > Score.timenum + 1) {
369                 yyerror("beat offset must be <= numerator of time signature + 1");
370         }
371
372         if (Curr_stuff_type == ST_CRESC || Curr_stuff_type == ST_DECRESC) {
373                 if (string != (char *) 0) {
374                         yyerror("string not allowed with cresc/decresc");
375                 }
376                 Modifier = TM_DYN;
377         }
378
379         else if (Curr_stuff_type == ST_PHRASE) {
380                 if (string != (char *) 0) {
381                         yyerror("string not allowed with phrase");
382                 }
383         }
384
385         else if (Curr_stuff_type == ST_PEDAL) {
386                 if ( (string != (char *) 0)
387                                 && (strcmp(string + 2, "\\(endped)") != 0) ) {
388                         yyerror("pedal string must be either blank or *");
389                 }
390         }
391
392         else {
393                 if (string == (char *) 0) {
394                         yyerror("string is required");
395                         return;
396                 }
397         }
398
399         if (gracebackup != 0 && Place == PL_BETWEEN) {
400                 yyerror("grace backup not allowed with 'between'");
401         }
402
403         /* we can't deal with step offset on phrase marks very well,
404          * so warn and ignore if we get one */
405         if (start_steps != 0.0 && Curr_stuff_type == ST_PHRASE) {
406                 l_warning(Curr_filename, yylineno, "step offset ignored on phrase mark");
407                 start_steps = 0.0;
408         }
409
410         switch (Curr_stuff_type) {
411         case ST_ROM:
412         case ST_BOLD:
413         case ST_ITAL:
414         case ST_BOLDITAL:
415                 /* the text-type stuffs are supposed to have a 1-space padding
416                  * at the end of them */
417                 if (bars != 0 || count != 0.0) {
418                         /* don't add padding if has wavy or solid line
419                          * til clause */
420                         lch = last_char(string);
421                         if (lch == '~' || lch == '_') {
422                                 break;
423                         }
424                 }
425                 string = pad_string(string, Modifier);
426                 break;
427
428         case ST_MUSSYM:
429                 /* in mussym, user can specify things without the usual
430                  * \(---) convention. Change to include them */
431                 if (string[2] == '\\' && string[3] == '(') {
432                         /* if user unnecessarily put in the \(--), leave it */
433                         break;
434                 }
435
436                 len = strlen(string + 2);
437                 MALLOCA(char, padded_string, len + 6);
438                 (void) sprintf(padded_string, "%c%c\\(%s)", FONT_TR, DFLT_SIZE,
439                                                 string + 2);
440                 FREE(string);
441                 string = padded_string;
442                 break;
443
444         default:
445                 break;
446         }
447
448         /* fill in a new STUFF struct with appropriate info */
449         new_p = newSTUFF(string, dist, dist_usage, start_count, start_steps,
450                 gracebackup, bars, count,
451                 Curr_stuff_type, Modifier, Place, Curr_filename, yylineno);
452
453         /* if bars > 0, need to save away til info for later error
454          * checking */
455         if (bars > 0) {
456                 CALLOC(TIL_INFO, til_info_p, 1);
457                 til_info_p->measnum = Measnum + bars;
458                 til_info_p->count = count;
459                 til_info_p->inputfile = new_p->inputfile;
460                 til_info_p->inputlineno = new_p->inputlineno;
461                 til_info_p->next = Til_info_list_p;
462                 Til_info_list_p = til_info_p;
463         }
464
465         /* above/between go on the head of the list, below goes on the
466          * tail of the list, so that things come out in the right order.
467          * Midi always goes at the end */
468         if (Place == PL_BELOW || Curr_stuff_type == ST_MIDI) {
469                 /* link onto list tail */
470                 if ( Tail_stufflist_p == (struct STUFF *) 0) {
471                         Head_stufflist_p = new_p;
472                 }
473                 else {
474                         Tail_stufflist_p->next = new_p;
475                 }
476                 Tail_stufflist_p = new_p;
477         }
478         else {
479                 /* link onto head of list */
480                 new_p->next = Head_stufflist_p;
481                 Head_stufflist_p = new_p;
482                 if (Tail_stufflist_p == (struct STUFF *) 0) {
483                         Tail_stufflist_p = new_p;
484                 }
485         }
486 }
487 \f
488
489 /* return YES if given string consists entirely of the specific music symbol */
490 /* the string should be in the internal format of font/size/string */
491
492 int
493 string_is_sym(string, sym, symfont)
494
495 char *string;   /* which string to check */
496 int sym;        /* check for this music symbol */
497 int symfont;    /* FONT_MUSIC*  */
498
499 {
500         int font, size;
501
502
503         if (string == (char *) 0) {
504                 return(NO);
505         }
506
507         font = *string++;
508         size = *string++;
509         if (next_str_char(&string, &font, &size) != sym) {
510                 return(NO);
511         }
512         if (font != symfont) {
513                 return(NO);
514         }
515         if (next_str_char(&string, &font, &size)  == '\0') {
516                 return(YES);
517         }
518         return (NO);
519 }
520 \f
521
522 /* connect a list of STUFF to a STAFF. If there is already something on
523  * that STAFF's STUFF list, attach at the end or beginning as appropriate
524  * depending on place. */
525
526 void
527 attach_stuff()
528
529 {
530         struct SVRANGELIST *svr_p;      /* to walk through Svrangelist */
531         struct RANGELIST *r_p;          /* to walk through staff range list */
532         short staffno;
533
534
535         debug(4, "attach_stuff");
536
537         /* make sure we've got STAFF structs for this measure */
538         create_staffs();
539
540         for (svr_p = Svrangelist_p; svr_p != (struct SVRANGELIST *) 0;
541                                                 svr_p = svr_p->next) {
542                 for (r_p = svr_p->stafflist_p; r_p != (struct RANGELIST *) 0;
543                                                 r_p = r_p->next) {
544         
545                         for (staffno = r_p->begin; staffno <= r_p->end
546                                         && staffno <= MAXSTAFFS; staffno++) {
547                                 do_attach(staffno, r_p->all, svr_p->vnolist_p);
548
549                                 if (Place == PL_BETWEEN) {
550                                         /* between has 2 staffs in its range,
551                                          * but stuff is only associated
552                                          * with the top staff */
553                                         break;
554                                 }
555                         }
556                 }
557         }
558
559         free_rlists();
560
561         /* have made copies of stuff for each staff that gets one, with
562          * the proper font/size etc, so need to free master stufflist copy */
563         free_stufflist(Head_stufflist_p);
564 }
565 \f
566
567 /* Attach STUFF for a specific staff. */
568
569 static void
570 do_attach(staffno, all, vno_range_p)
571
572 int staffno;
573 int all;
574 struct RANGELIST *vno_range_p;
575
576 {
577         struct STAFF *staff_p;          /* where to attach STUFF */
578         struct STUFF *stufflist_p;      /* current copy of STUFF list */
579
580
581         if (staffno > Score.staffs) {
582                 l_yyerror(Head_stufflist_p->inputfile,
583                                 Head_stufflist_p->inputlineno,
584                                 "staff number out of range");
585                 return;
586         }
587
588         staff_p = Staffmap_p[staffno]->u.staff_p;
589
590         if (Place == PL_BETWEEN) {
591                 if (staffno + 1 > Score.staffs) {
592                         /* will have already exclaimed about
593                          * this error before, so no need to print message,
594                          * but better skip next check */
595                         return;
596                 }
597
598                 /* if either staff of a between is invisible,
599                  * throw this stuff away */
600                 if (svpath(staffno, VISIBLE)->visible == NO ||
601                                 svpath(staffno + 1,
602                                 VISIBLE)->visible == NO) {
603                         return;
604                 }
605         }
606
607         /* handle MIDI stuff specially */
608         if (Curr_stuff_type == ST_MIDI) {
609                 if (all == YES) {
610                         /* need to find top visible staff/voice to attach to */
611                         int s;          /* staff number */
612                         int v;          /* voice number */
613                         struct RANGELIST range;
614         
615                         v = 1;  /* avoid bogus "used before set" warning */
616                         for (s = 1; s <= MAXSTAFFS; s++) {
617                                 if (svpath(s, VISIBLE)->visible == YES) {
618                                         for (v = 1; v <= MAXVOICES; v++) {
619                                                 if (vvpath(s, v, VISIBLE)->visible == YES) {
620                                                         break;
621                                                 }
622                                         }
623                                         if (v <= MAXVOICES) {
624                                                 break;
625                                         }
626                                 }
627                         }
628                         if (s > MAXSTAFFS || v > MAXVOICES) {
629                                 pfatal("failed to find top visible staff/voice");
630                         }
631                         /* make a special RANGELIST for this */
632                         range.begin = range.end = v;
633                         range.all = YES;
634                         range.next = 0;
635                         midi_attach(s, Staffmap_p[s]->u.staff_p, &range, all);
636                 }
637                 else {
638                         midi_attach(staffno, staff_p, vno_range_p, all);
639                 }
640         }
641
642         else {
643                 /* make the copy for this staff from master copy */
644                 stufflist_p = clone_stufflist(Head_stufflist_p, staffno, all);
645
646                 if (Curr_stuff_type == ST_PEDAL) {
647                         fix_pedal(staffno, stufflist_p);
648                 }
649
650                 connect_stuff(staff_p, stufflist_p);
651         }
652 }
653 \f
654
655 /* attach MIDI stuff. This is slightly different than other stuff because
656  * it can be applied to one or both voices. */
657
658 static void
659 midi_attach(staffno, staff_p, vno_range_p, all)
660
661 int staffno;            /* attach to this staff number */
662 struct STAFF *staff_p;  /* attach to this staff struct */
663 struct RANGELIST *vno_range_p;
664 int all;                /* if associated with "all" */
665
666 {
667         struct RANGELIST *r_p;          /* walk through vno_range_p */
668         int vno;                        /* voice number */
669         struct STUFF *stufflist_p;      /* copy of stuff */
670         struct STUFF *st_p;             /* walk through stufflist_p */
671         short place;
672
673
674         /* do for each voice that MIDI stuff applies to */
675         for (r_p = vno_range_p; r_p != (struct RANGELIST *) 0; r_p = r_p->next) {
676                 for (vno = r_p->begin; vno <= r_p->end; vno++) {
677
678                         /* make the copy for this staff from master copy */
679                         stufflist_p = clone_stufflist(Head_stufflist_p,
680                                                 staffno, all);
681
682                         /* fix up place based on voice number */
683                         switch (vno) {
684                         case 1:
685                                 place = PL_ABOVE;
686                                 break;
687                         case 2:
688                                 place = PL_BELOW;
689                                 break;
690                         case 3:
691                                 place = PL_BETWEEN;
692                                 break;
693                         default:
694                                 pfatal("illegal vno for midi");
695                                 /*NOTREACHED*/
696                                 place = PL_UNKNOWN;  /* avoid "used before set" warning */
697                                 break;
698                         }
699                         for (st_p = stufflist_p; st_p != (struct STUFF *) 0;
700                                                 st_p = st_p->next) {
701                                 st_p->place = place;
702                         }
703
704                         connect_stuff(staff_p, stufflist_p);
705                 }
706         }
707 }
708 \f
709
710 /* connect a new stuff list into an existing stuff list. Add below stuff and
711  * MIDI stuff to the end of the list,
712  * and others to beginning of list, but make sure any
713  * "above all" comes after any above non-all, and that any below non-all
714  * comes before any "below all."
715  */
716
717 void
718 connect_stuff(staff_p, stufflist_p)
719
720 struct STAFF *staff_p;          /* connect to stuff off of this staff */
721 struct STUFF *stufflist_p;      /* connect this list  of stuff */
722
723 {
724         struct STUFF *st_p;             /* to find link place in STUFF list */
725         struct STUFF *s_p;              /* to find end of stufflist_p */
726         struct STUFF **ins_p_p;         /* where to insert in list */
727
728
729         if (staff_p == (struct STAFF *) 0 || stufflist_p == (struct STUFF *) 0) {
730                 return;
731         }
732
733         if (staff_p->stuff_p == (struct STUFF *) 0) {
734                 /* no list before, so attach this one
735                  * directly to STAFF */
736                 staff_p->stuff_p = stufflist_p;
737         }
738
739         else if (Place == PL_BELOW || stufflist_p->stuff_type == ST_MIDI) {
740                 /* if this set of stuff isn't associated with
741                  * "all", then it goes before any below "all" stuff */
742                 if (stufflist_p->all == NO) {
743                         for (ins_p_p = &(staff_p->stuff_p); 
744                                         *ins_p_p != (struct STUFF *) 0;
745                                         ins_p_p = &((*ins_p_p)->next)) {
746                                 if ( (*ins_p_p)->place == PL_BELOW &&
747                                                 (*ins_p_p)->all == YES) {
748                                         break;
749                                 }
750                         }
751                         /* find end of list to be inserted */
752                         for (s_p = stufflist_p; s_p->next != (struct STUFF *) 0;
753                                                         s_p = s_p->next) {
754                                 ;
755                         }
756
757                         /* insert */
758                         s_p->next = *ins_p_p;
759                         *ins_p_p = stufflist_p;
760                 }
761
762                 else {
763                         /* goes at end of list. find the end */
764                         for (st_p = staff_p->stuff_p;
765                                         st_p->next != (struct STUFF *)0;
766                                         st_p = st_p->next) {
767                                 ;
768                         }
769
770                         /* connect in the new list */
771                         st_p->next = stufflist_p;
772                 }
773         }
774         else {
775                 /* find end of new list */
776                 for (s_p = stufflist_p;
777                                 s_p->next != (struct STUFF *) 0;
778                                 s_p = s_p->next) {
779                         ;
780                 }
781
782                 if (stufflist_p->all == NO) {
783                         /* goes at the head of the list */
784                         s_p->next = staff_p->stuff_p;
785                         staff_p->stuff_p = stufflist_p;
786                 }
787                 else {
788                         /* goes before any existing above all */
789                         for (ins_p_p = &(staff_p->stuff_p); 
790                                         *ins_p_p != (struct STUFF *) 0;
791                                         ins_p_p = &((*ins_p_p)->next)) {
792                                 if ( (*ins_p_p)->place == PL_ABOVE &&
793                                                 (*ins_p_p)->all == YES) {
794                                         break;
795                                 }
796                         }
797                         /* find end of list to be inserted */
798                         for (s_p = stufflist_p; s_p->next != (struct STUFF *) 0;
799                                                         s_p = s_p->next) {
800                                 ;
801                         }
802
803                         /* insert */
804                         s_p->next = *ins_p_p;
805                         *ins_p_p = stufflist_p;
806                 }
807         }
808 }
809 \f
810
811 /* given a list of STUFF, return a clone of the list */
812
813 static struct STUFF *
814 clone_stufflist(stufflist_p, staffno, all)
815
816 struct STUFF *stufflist_p;      /* what stuff to clone */
817 int staffno;                    /* which staff, to get proper point size */
818 int all;                        /* YES if was "above all" or "below all" */
819
820 {
821         struct STUFF *new_p;    /* copy of STUFF */
822         char *newstring;        /* copy of text string */
823         int font;
824         int fontfamily;
825         int size;
826
827
828         if (stufflist_p == (struct STUFF *) 0) {
829                 return( (struct STUFF *) 0 );
830         }
831
832         /* make copy of string with appropriate font and size */
833         if (stufflist_p->string != (char *) 0) {
834                 switch(stufflist_p->stuff_type) {
835                 case ST_BOLD:
836                         font = FONT_TB;
837                         break;
838                 case ST_OCTAVE:
839                         Stuff_size = DFLT_SIZE;
840                         font = FONT_TI;
841                         break;
842                 case ST_ITAL:
843                         font = FONT_TI;
844                         break;
845                 case ST_BOLDITAL:
846                         font = FONT_TX;
847                         break;
848                 default:
849                         font = FONT_TR;
850                         break;
851                 }
852
853                 /* figure out the proper size if not already determined */
854                 if (Stuff_size  < 0) {
855                         if (all == YES) {
856                                 size = Score.size;
857                         }
858                         else {
859                                 size = svpath(staffno, SIZE)->size;
860                         }
861                 }
862                 else {
863                         size = Stuff_size;
864                 }
865
866                 /* determine fontfamily and font if not already known */
867                 if (Curr_family == FAMILY_DFLT) {
868                         if (all == YES) {
869                                 fontfamily = Score.fontfamily;
870                         }
871                         else {
872                                 fontfamily = svpath(staffno, FONTFAMILY)->
873                                                         fontfamily;
874                         }
875                 }
876                 else {
877                         fontfamily = Curr_family;
878                 }
879
880                 /* clone text string */
881                 newstring = copy_string(stufflist_p->string + 2, font, size);
882                 if (IS_CHORDLIKE(Modifier)) {
883                         newstring = modify_chstr(newstring, Modifier);
884                 }
885                 fix_string(newstring, fontfamily + font, size,
886                         stufflist_p->inputfile, stufflist_p->inputlineno);
887                 if (Modifier == TM_FIGBASS || Modifier == TM_ANALYSIS) {
888                         newstring = acc_trans(newstring);
889                 }
890         }
891         else {
892                 newstring = (char *) 0;
893         }
894         
895         /* create and fill in clone of stuff, then return it */
896         new_p = newSTUFF(newstring, stufflist_p->dist,
897                                 stufflist_p->dist_usage,
898                                 stufflist_p->start.count,
899                                 stufflist_p->start.steps,
900                                 stufflist_p->gracebackup,
901                                 stufflist_p->end.bars, stufflist_p->end.count,
902                                 stufflist_p->stuff_type, stufflist_p->modifier,
903                                 stufflist_p->place, stufflist_p->inputfile,
904                                 stufflist_p->inputlineno);
905         new_p->all = (short) all;
906         new_p->next = clone_stufflist(stufflist_p->next, staffno, all);
907         return(new_p);
908 }
909 \f
910
911 /* allocate a STUFF and fill in all the values given. Initialize carry fields
912  * and "all" to NO. Leave coordinates and next link as 0.
913  * Note that the string pointer
914  * is copied; it does not make a copy of the string itself, so never call this
915  * function more than once with the same string--make a copy. */
916
917 struct STUFF *
918 newSTUFF(string, dist, dist_usage, start_count, start_steps, gracebackup, bars, count,
919                 stuff_type, modifier, place, inputfile, inputlineno)
920
921 char *string;           /* text string of stuff */
922 int dist;               /* dist for this STUFF to override dist parameter */
923 int dist_usage;         /* meaning of dist, SD_* */
924 double start_count;     /* count at which to begin stuff */
925 double start_steps;     /* offset by this many steps */
926 int gracebackup;        /* how many grace notes to back up from start */
927 int bars;               /* bars in "til" clasue */
928 double count;           /* counts in "til" clause */
929 int stuff_type;         /* ST_* */
930 int modifier;           /* TM_* */
931 int place;              /* PL_* */
932 char *inputfile;        /* which file stuff was defined in */
933 int inputlineno;        /* where stuff was defined in input file */
934
935 {
936         struct STUFF *new_p;    /* the new STUFF to fill in */
937
938
939         CALLOC(STUFF, new_p, 1);
940         new_p->string = string;
941         new_p->start.count = start_count;
942         new_p->start.steps = start_steps;
943         new_p->gracebackup = (short) gracebackup;
944         new_p->dist = (short) dist;
945         new_p->dist_usage = (short) dist_usage;
946         new_p->end.bars = (short) bars;
947         new_p->end.count = count;
948         new_p->stuff_type = (short) stuff_type;
949         new_p->modifier = (short) modifier;
950         new_p->place = (short) place;
951         new_p->carryin = new_p->carryout = new_p->all = NO;
952         new_p->costuff_p = 0;
953         new_p->inputfile = inputfile;
954         new_p->inputlineno = (short) inputlineno;
955
956         return(new_p);
957 }
958 \f
959
960 /* recursively free up a stufflist and any strings hanging off of it */
961
962 static void
963 free_stufflist(stuff_p)
964
965 struct STUFF *stuff_p;
966
967 {
968         if (stuff_p == (struct STUFF *) 0 ) {
969                 return;
970         }
971
972         free_stufflist(stuff_p->next);
973         if (stuff_p->string != (char *) 0) {
974                 FREE(stuff_p->string);
975         }
976         FREE(stuff_p);
977 }
978 \f
979
980 /* at each bar line, see if there are any "til" clauses that are supposed
981  * to end in this measure. If so, make sure they end within the time
982  * signature for this measure. */
983
984 void
985 meas_stuff_chk()
986
987 {
988         struct TIL_INFO *til_info_p;            /* to index thru list */
989         struct TIL_INFO **del_place_p_p;        /* for deleting from list */
990         struct TIL_INFO *one2free_p;            /* pointer to which element
991                                                  * to free */
992
993         debug(2, "meas_chk_stuff");
994
995         /* update measure number to conpensate for any multirests */
996         Measnum += Multi_adjust;
997         Multi_adjust = 0;
998
999         /* go through list of in-progress til clauses */
1000         for (til_info_p = Til_info_list_p, del_place_p_p = &Til_info_list_p;
1001                                 til_info_p != (struct TIL_INFO *) 0;  ) {
1002
1003                 if (til_info_p->measnum == Measnum) {
1004
1005                         /* at measure where this til clause ends */
1006                         /* check if within time signature */
1007                         if (til_info_p->count > Score.timenum + 1.0) {
1008                                 l_yyerror(til_info_p->inputfile,
1009                                         til_info_p->inputlineno,
1010                                         "beats in 'til' clause must be <= numerator of time signature + 1 of the measure in which the 'til' clause ends (i.e., <= %d)",
1011                                         Score.timenum);
1012                         }
1013
1014                         /* this one has been taken care of: delete from list */
1015                         *del_place_p_p = til_info_p->next;
1016                         one2free_p = til_info_p;
1017                 }
1018                 else if (til_info_p->measnum < Measnum) {
1019                         /* must have ended inside a multirest, so delete
1020                          * from list */
1021                         *del_place_p_p = til_info_p->next;
1022                         one2free_p = til_info_p;
1023                 }
1024                 else {
1025                         /* this one stays on the list for now, so move pointer
1026                          * to where to potentially delete to next element */
1027                         del_place_p_p = &(til_info_p->next);
1028                         one2free_p = (struct TIL_INFO *) 0;
1029                 }
1030
1031                 /* have to move to next element
1032                  * before freeing the current one */
1033                 til_info_p = til_info_p->next;
1034
1035                 if (one2free_p != (struct TIL_INFO *) 0) {
1036                         FREE(one2free_p);
1037                 }
1038         }
1039
1040         /* update number of measures. */
1041         Measnum++;
1042
1043         /* make sure pedal marks are in proper order */
1044         ped_order_chk();
1045 }
1046 \f
1047
1048 /* adjust number of measures to account for multirests. Called when there is
1049  * a multirest. Saved the number of measures in the multirest (minus 1 since
1050  * the barline at the end will count for one measure) */
1051
1052 void
1053 multi_stuff(nmeas)
1054
1055 int nmeas;      /* number of measures in multirest */
1056
1057 {
1058         /* subtract 1 to account for the fact that at the bar line at the
1059          * end of the multirest we will peg the measure counter */
1060         Multi_adjust = nmeas - 1;
1061 }
1062 \f
1063
1064 /* handle pedal going into endings. When we hit a first ending, save the
1065  * state of the pedal for all staffs. On subsequent endings in the set,
1066  * reset the pedal state to what it was at the beginning of the first ending.
1067  * At the endending, go back to normal operation. This is similar to
1068  * the saveped() function used at print time. */
1069
1070 void
1071 ped_endings(endingloc)
1072
1073 int endingloc;          /* STARTITEM, INITEM, etc */
1074
1075 {
1076         register int s;         /* staff index */
1077
1078
1079         if (endingloc == STARTITEM) {
1080                 if (Ped_snapshot[0] == YES) {
1081
1082                         /* starting 2nd ending: restore pedal state as it was
1083                          * at beginning of first ending */
1084                         for (s = 1; s <= MAXSTAFFS; s++) {
1085                                 Pedal_state[s] = Ped_snapshot[s];
1086                         }
1087                 }
1088
1089                 else {
1090                         /* starting a set of endings,
1091                          * need to save pedal state at this
1092                          * point so we can carry it into subsequent endings */
1093                         for (s = 1; s <= Score.staffs; s++) {
1094                                 Ped_snapshot[s] = Pedal_state[s];
1095                         }
1096                         /* make sure any remaining staffs are set to pedal off,
1097                          * in case user increases the number of staffs
1098                          * during the endings... */
1099                         for (   ; s <= MAXSTAFFS; s++) {
1100                                 Ped_snapshot[s] = NO;
1101                         }
1102
1103                         /* mark that we now have a snapshot */
1104                         Ped_snapshot[0] = YES;
1105                 }
1106         }
1107
1108         else if (endingloc == ENDITEM) {
1109                 /* at end of endings, discard snapshot of pedal states */
1110                 Ped_snapshot[0] = NO;
1111         }
1112 }
1113 \f
1114
1115 /* When all input has been processed, or when changing the number
1116  * of staffs, we better not have any 'til' clauses
1117  * still unfinished. If we do, print a warning message. */
1118
1119 void
1120 chk4dangling_til_clauses(boundary_desc)
1121
1122 char *boundary_desc;            /* "the end of the song" or
1123                                  * "a change in number of staffs" */
1124
1125 {
1126         struct TIL_INFO *til_info_p;
1127
1128
1129         debug(2, "chk4dangling_til_clauses");
1130
1131         /* Go through the whole list of remaining til clauses,
1132          * and print a warning message for each. */
1133         for (til_info_p = Til_info_list_p; til_info_p != (struct TIL_INFO *) 0;
1134                                         til_info_p = til_info_p->next) {
1135
1136                 /* If right on the boundary or spills over only a very tiny
1137                  * amount, don't bother to complain */
1138                 if (til_info_p->measnum - Measnum == 0
1139                                                 && til_info_p->count < .001) {
1140                         continue;
1141                 }
1142
1143                 l_warning(til_info_p->inputfile, til_info_p->inputlineno,
1144                                 "'til' clause extends beyond %s by %dm + %.3f",
1145                                 boundary_desc, til_info_p->measnum - Measnum,
1146                                 til_info_p->count);
1147         }
1148
1149         /* mop up. */
1150         free_tils(Til_info_list_p);
1151         Til_info_list_p = (struct TIL_INFO *) 0;
1152 }
1153 \f
1154
1155 /* recursively free a list of TIL_INFO structs */
1156
1157 static void
1158 free_tils(til_p)
1159
1160 struct TIL_INFO *til_p;         /* free this list */
1161
1162 {
1163         if (til_p == (struct TIL_INFO *) 0) {
1164                 return;
1165         }
1166
1167         free_tils(til_p->next);
1168         FREE(til_p);
1169 }
1170 \f
1171
1172 /* user only has to specify when pedal marks end. We deduce from current
1173  * pedal state whether a pedal mark is begin or up/down. This gets called
1174  * whenever we have a list of pedal STUFFs. Later we enforce that pedal
1175  * marks are put in in ascending order only, so that if user enters more
1176  * than one pedal line for the same staff, that will be handled properly. */
1177
1178 static void
1179 fix_pedal(staffno, stuff_p)
1180
1181 int staffno;                    /* pedal is for this staff */
1182 struct STUFF *stuff_p;          /* list of pedal mark info */
1183
1184 {
1185         /* walk through list of pedal marks */
1186         for (  ; stuff_p != (struct STUFF *) 0; stuff_p = stuff_p->next) {
1187
1188                 if (stuff_p->string == (char *) 0) {
1189                         /* no star, so have to deduce state */
1190
1191                         if (Pedal_state[staffno] == NO) {
1192                                 /* pedal currently off, so begin pedal */
1193                                 Pedal_state[staffno] = YES;
1194                                 stuff_p->string = copy_string(Ped_begin_str + 2,
1195                                         (int) Ped_begin_str[0],
1196                                         (int) Ped_begin_str[1]);
1197                         }
1198                         else {
1199                                 /* pedal currently down, so pedal up/down */
1200                                 stuff_p->string = copy_string(Ped_up_down_str + 2,
1201                                         (int) Ped_up_down_str[0],
1202                                         (int) Ped_up_down_str[1]);
1203                         }
1204                 }
1205
1206                 else if (Pedal_state[staffno] == NO) {
1207                         yyerror("can't end pedal -- none in progress");
1208                 }
1209
1210                 else {
1211                         /* user gave star, so end pedal */
1212                         Pedal_state[staffno] = NO;
1213                 }
1214         }
1215 }
1216 \f
1217
1218 /* reset pedal states for all staffs. This should be called at init time
1219  * and at any time when the number of staffs changes. This function also
1220  * initializes the Ped_begin_str and Ped_up_down_str. */
1221
1222 void
1223 reset_ped_state()
1224
1225 {
1226         static int first_time = YES;    /* flag if function called before */
1227         register int s;                 /* index through staffs */
1228
1229
1230         /* mark pedal off for all staffs */
1231         for (s = 1; s <= Score.staffs; s++) {
1232                 Pedal_state[s] = NO;
1233         }
1234         Ped_snapshot[0] = NO;
1235
1236         /* the first time this function is called, initialize the strings
1237          * for pedal begin and pedal end. We just have one copy of these
1238          * and then make as many copies from these as necessary */
1239         if (first_time == YES) {
1240                 first_time = NO;
1241                 Ped_begin_str = copy_string("\\(begped)", FONT_MUSIC,
1242                                                         DFLT_SIZE);
1243                 Ped_up_down_str = copy_string("\\(pedal)", FONT_MUSIC,
1244                                                         DFLT_SIZE);
1245                 fix_string(Ped_begin_str, FONT_MUSIC, DFLT_SIZE,
1246                                         Curr_filename, -1);
1247                 fix_string(Ped_up_down_str, FONT_MUSIC, DFLT_SIZE,
1248                                          Curr_filename, -1);
1249         }
1250 }
1251 \f
1252
1253 /* fill in rehearsal mark string. This doesn't go in a STUFF, but it's
1254  * sort of like stuff and there didn't seem to be any more appropriate file for
1255  * this function */
1256
1257
1258 static int Reh_let = 0;         /* current value of rehearsal letter. 0 == "A",
1259                                  * 25 == "Z", 26 == "AA", etc to 701 == "ZZ" */
1260 static int Reh_num = 1;         /* current value of rehearsal number */
1261
1262
1263 void
1264 set_reh_string(bar_p, fontfamily, font, size, string)
1265
1266 struct BAR *bar_p;      /* which bar gets the rehearsal mark */
1267 int fontfamily;         /* what font family to use, or FAMILY_DFLT
1268                          * if to use current default */
1269 int font;               /* what font to use, or FONT_UNKNOWN if to use the
1270                          * current default font */
1271 int size;               /* font size to use, or -1 if to use current default */
1272 char *string;           /* string for rehearsal mark */
1273
1274 {
1275         char reh_str[12];       /* temporary buff for string version of
1276                                  * rehearsal number or letter */
1277         static int reh_size = DFLT_SIZE;        /* size to use for reh marks */
1278         static int reh_family = FAMILY_DFLT;    /* font family to use */
1279         static int reh_font = FONT_TB;          /* font to use */
1280
1281
1282         /* if first time through, init the font family to the score family */
1283         if (reh_family == FAMILY_DFLT) {
1284                 reh_family = Score.fontfamily;
1285         }
1286
1287         /* if user specified a new size, save that */
1288         if (size != -1) {
1289                 if (size > 100) {
1290                         yyerror("reh mark size too large");
1291                         return;
1292                 }
1293                 else {
1294                         reh_size = size;
1295                 }
1296         }
1297
1298         /* if user specified new font or font family, save that */
1299         if (font != FONT_UNKNOWN) {
1300                 reh_font = font;
1301         }
1302         if (fontfamily != FAMILY_DFLT) {
1303                 reh_family = fontfamily;
1304         }
1305
1306         switch(bar_p->reh_type) {
1307
1308         case REH_NUM:
1309                 /* get string version of current rehearsal number, and
1310                  * incrment it */
1311                 bar_p->reh_string = copy_string(num2str(Reh_num++) + 2,
1312                                 reh_family + reh_font, reh_size);
1313                 break;
1314
1315         case REH_LET:
1316                 /* Get string version of current rehearsal letter.
1317                  * Start with A-Z, then AA, AB, AC, ... BA, BB, ... up to ZZ.
1318                  */
1319                 if (Reh_let < 26) {
1320                         /* 1-letter long mark */
1321                         (void) sprintf(reh_str, "%c", Reh_let + 'A');
1322                 }
1323                 else if (Reh_let < 27 * 26) {
1324                         /* 2-letter long mark */
1325                         (void) sprintf(reh_str, "%c%c",
1326                                 (Reh_let / 26) + 'A' - 1, (Reh_let % 26) + 'A');
1327                 }
1328                 else {
1329                         ufatal("too many rehearsal letters!");
1330                 }
1331                 bar_p->reh_string = copy_string(reh_str,
1332                                 reh_family + reh_font, reh_size);
1333                 /* increment for next time around */
1334                 Reh_let++;
1335                 break;
1336
1337         case REH_MNUM:
1338                 /* get string version of current measure number */
1339                 bar_p->reh_string = copy_string(num2str(Meas_num) + 2,
1340                                 reh_family + reh_font, reh_size);
1341                 break;
1342
1343         case REH_STRING:
1344                 /* user-specified string */
1345                 bar_p->reh_string = fix_string(string,
1346                                 reh_family + reh_font, reh_size,
1347                                 Curr_filename, yylineno);
1348                 break;
1349
1350         case REH_NONE:
1351                 break;
1352
1353         default:
1354                 pfatal("set_reh_string passed bad value");
1355                 break;
1356         }
1357 }
1358 \f
1359
1360 /* Set rehearsal letter or number to user-specified value.
1361  * If the current bar has a rehearsal mark of the type being changed,
1362  * also replace its current mark with the changed one. This allows user
1363  * to say either
1364  *      reh num num=5
1365  * or
1366  *      num=5 reh num
1367  * and get the same results, which is consistent with how mnum= setting
1368  * had worked.
1369  */
1370
1371 void
1372 init_reh(rehnumber, rehletter, mainbar_p)
1373
1374 int rehnumber;          /* New value for Reh_num or negative if setting Reh_let */
1375 char *rehletter;        /* "A" to "ZZ" or null if setting number */
1376 struct MAINLL *mainbar_p;       /* points to the current BAR */
1377
1378 {
1379         struct BAR *bar_p;
1380         char *oldstr;           /* previous reh_string */
1381
1382         if (mainbar_p == 0 || mainbar_p->str != S_BAR) {
1383                 pfatal("bad mainbar_p passed to init_reh");
1384         }
1385         bar_p = mainbar_p->u.bar_p;
1386         oldstr = bar_p->reh_string;
1387
1388         if (rehnumber >= 0) {
1389                 Reh_num = rehnumber;
1390                 /* If this bar has a rehearsal number on this bar,
1391                  * replace it, and free the old one. */
1392                 if (bar_p->reh_type == REH_NUM) {
1393                         set_reh_string(bar_p, FAMILY_DFLT, FONT_UNKNOWN, -1,
1394                                                                 (char *) 0);
1395                         FREE(oldstr);
1396                 }
1397         }
1398
1399         if (rehletter != 0) {
1400                 /* Letter is stored internally as a number,
1401                  * which is then converted, so we have to convert in reverse.
1402                  * We only allow "A" through "ZZ" */
1403                 if (isupper(rehletter[0]) && rehletter[1] == '\0') {
1404                         Reh_let = rehletter[0] - 'A';
1405                 }
1406                 else if (isupper(rehletter[0]) && isupper(rehletter[1])
1407                                                 && rehletter[2] == '\0') {
1408                         Reh_let = 26 + (rehletter[1] - 'A')
1409                                         + (rehletter[0] - 'A') * 26;
1410                 }
1411                 else {
1412                         yyerror("rehearsal letter setting must be \"A\" through \"ZZ\"");
1413                         return;
1414                 }
1415                 /* If this bar has a rehearsal letter on this bar,
1416                  * replace it, and free the old one. */
1417                 if (bar_p->reh_type == REH_LET) {
1418                         set_reh_string(bar_p, FAMILY_DFLT, FONT_UNKNOWN, -1,
1419                                                                 (char *) 0);
1420                         FREE(oldstr);
1421                 }
1422         }
1423 }
1424 \f
1425
1426 /* go through all stuff lists and verify that pedal marks are given in
1427  * ascending order. If not, error. Some code in both parse and
1428  * placement phases requires that pedal marks be in order. */
1429
1430 static void
1431 ped_order_chk()
1432
1433 {
1434         int staffno;
1435         struct STUFF *stuff_p;  /* walk through stuff list */
1436         float last_ped_count;   /* count where last pedal occurred */
1437         int last_backup;        /* gracebackup of last pedal */
1438
1439
1440         /* check every staff */
1441         for (staffno = 1; staffno <= Score.staffs; staffno++) {
1442
1443                 /* initialize for current staff */
1444                 last_ped_count = -1.0;
1445                 last_backup = 0;
1446
1447                 /* go through stuff list for current staff, looking for pedal */
1448                 for (stuff_p = Staffmap_p[staffno]->u.staff_p->stuff_p;
1449                                         stuff_p != (struct STUFF *) 0;
1450                                         stuff_p = stuff_p->next) {
1451                         if (stuff_p->stuff_type == ST_PEDAL) {
1452
1453                                 /* found a pedal. Make sure it is later than
1454                                  * the previous pedal */
1455                                 if (stuff_p->start.count < last_ped_count ||
1456                                                 (stuff_p->start.count
1457                                                 == last_ped_count
1458                                                 && stuff_p->gracebackup
1459                                                 > last_backup) ) {
1460                                         l_yyerror(stuff_p->inputfile,
1461                                                 stuff_p->inputlineno,
1462                                                 "pedal must be specified in ascending order");
1463                                         /* no need to print error more than
1464                                          * once if multiple errors */
1465                                         continue;
1466                                 }
1467
1468                                 /* keep track of where this pedal is, for
1469                                  * comparing with the next one */
1470                                 last_ped_count = stuff_p->start.count;
1471                                 last_backup = stuff_p->gracebackup;
1472                         }
1473                 }
1474         }
1475 }
1476 \f
1477
1478 /* Translate STUFF text modifier to a printable string. */
1479
1480 char *
1481 stuff_modifier(modifier)
1482
1483 int modifier;
1484
1485 {
1486         switch (modifier) {
1487
1488         case TM_CHORD:
1489                 return("chord");
1490         case TM_ANALYSIS:
1491                 return("analysis");
1492         case TM_FIGBASS:
1493                 return("figbass");
1494         case TM_DYN:
1495                 return("dyn");
1496         case TM_NONE:
1497                 return("(no modifier)");
1498         default:
1499                 return("(invalid modifier)");
1500         }
1501 }