2 /* Copyright (c) 1995, 1997, 1998, 1999, 2002, 2004 by Arkkra Enterprises */
3 /* All rights reserved */
5 /* Functions for saving away ranges of staff numbers or vno's when user
6 * is defining groups, lyrics, or stuff for one or more staffs and/or
14 /* special marker for "all." use something that can't possibly be a staff num */
18 static void free_rangelist
P((struct RANGELIST
*list_p
));
22 /* When a line of input is being gathered for groups, lyrics, or stuff,
23 * this function should be called first. It makes
24 * sure the current range list is set to empty and makes a note of the place,
25 * (PL_ABOVE, PL_BELOW, or PL_BETWEEN) for later reference
31 int place
; /* PL_ABOVE, etc */
34 Staffrange_p
= (struct RANGELIST
*) 0;
35 Vnorange_p
= (struct RANGELIST
*) 0;
36 Place
= (short) place
;
40 /* This function is called when the parser has found a range of staffs that
41 * is to get the current set of groups, lyrics or stuff.
42 * In the degenerate case, the range
43 * may be a single staff. In the case of PL_BETWEEN, the ending staff number
44 * must be one more than the beginning.
45 * If the endstaffno is ALL, this is a special case of "all" as in
46 * "above all" or "below all."
50 save_staff_range(beginstaffno
, endstaffno
)
52 int beginstaffno
; /* first staff in range */
53 int endstaffno
; /* last staff in range */
56 struct RANGELIST
*new_p
; /* to save info about this range */
60 /* handle special case of "all" */
61 if (endstaffno
== ALL
) {
63 endstaffno
= beginstaffno
;
67 if (rangecheck(beginstaffno
, 1, MAXSTAFFS
, "staff number") == NO
) {
70 if (rangecheck(endstaffno
, 1, MAXSTAFFS
, "staff number") == NO
) {
74 if (endstaffno
< beginstaffno
) {
75 yyerror("end of staff range smaller than beginning");
79 if (Place
== PL_BETWEEN
) {
80 if (endstaffno
!= beginstaffno
+ 1) {
81 yyerror("if place is 'between', second staff must be 1 greater than first");
85 if (beginstaffno
== Score
.staffs
) {
86 yyerror("can't use 'between' on bottom staff");
91 /* allocate a new struct and link onto head of list */
92 CALLOC(RANGELIST
, new_p
, 1);
93 new_p
->next
= Staffrange_p
;
96 /* fill in other fields */
97 new_p
->begin
= (short) beginstaffno
;
98 new_p
->end
= (short) (Place
== PL_BETWEEN ? beginstaffno
: endstaffno
);
100 new_p
->place
= Place
;
104 /* given a range of vno's, save the range for later use */
105 /* Any error checking of the numbers should be done before calling this
109 save_vno_range(begin
, end
)
111 int begin
; /* first vno */
112 int end
; /* last vno */
115 struct RANGELIST
*new_p
; /* to store vno info */
118 /* allocate a new struct and link onto head of list */
119 CALLOC(RANGELIST
, new_p
, 1);
120 new_p
->next
= Vnorange_p
;
123 /* fill in other fields */
124 new_p
->begin
= (short) begin
;
125 new_p
->end
= (short) end
;
129 /* free list of staff ranges */
135 free_rangelist(Staffrange_p
);
136 Staffrange_p
= (struct RANGELIST
*) 0;
141 /* free list of vno ranges */
147 free_rangelist(Vnorange_p
);
148 Vnorange_p
= (struct RANGELIST
*) 0;
154 /* free both the staff and vno lists */
160 if (Svrangelist_p
!= (struct SVRANGELIST
*) 0) {
161 free_sv_list(Svrangelist_p
);
162 Svrangelist_p
= (struct SVRANGELIST
*) 0;
171 /* free the Svrangelist and the RANGELISTs hanging off of it */
174 free_sv_list(svrangelist_p
)
176 struct SVRANGELIST
*svrangelist_p
;
179 if (svrangelist_p
== (struct SVRANGELIST
*) 0) {
183 free_rangelist(svrangelist_p
->stafflist_p
);
184 free_rangelist(svrangelist_p
->vnolist_p
);
187 free_sv_list(svrangelist_p
->next
);
192 /* recursively free a list of RANGELIST structs */
195 free_rangelist(list_p
)
197 struct RANGELIST
*list_p
; /* the list to free */
200 if (list_p
== (struct RANGELIST
*) 0) {
204 free_rangelist(list_p
->next
);
209 /* If doing between, staff ranges must be of the form N&M. If not doing
210 * between, must be either a single number or N-M. Make sure this is so.
214 chk_range_type(has_ampersand
)
216 int has_ampersand
; /* YES if range was of the form N&M */
219 if (has_ampersand
== YES
&& Place
!= PL_BETWEEN
) {
220 yyerror("& only valid with 'between'");
224 if (has_ampersand
== NO
&& Place
== PL_BETWEEN
) {
225 yyerror("must use & to specify ranges with 'between'");
230 /* Create a STAFF struct in the main list for every staff.
231 * Point List_of_staffs_p to the first of them.
232 * Fill in Staffmap_p for each of them to allow quick mapping from staffno
240 struct MAINLL
*mll_insert_p
; /* where to insert in main list */
241 struct MAINLL
*new_p
; /* newly allocated struct */
242 struct MAINLL
*mll_p
; /* for verifiying proper order */
243 struct MAINLL
*next_mll_p
; /* next main list item to be checked */
244 register int s
; /* index through staffs */
247 debug(4, "create_staffs");
249 if (List_of_staffs_p
!= (struct MAINLL
*) 0) {
250 /* this function has already been called for current measure, so
251 * nothing more to do. This is normal, because this function
252 * is called whenever another function needs to make sure
253 * the STAFFs have been created.
258 /* STAFFS are supposed to come before LINES, CURVES, and PRHEADS.
259 * However, the user is not constrained to put things in in that
260 * order, so there may be some already on the list. If so, back
261 * up to before where they should begin and insert the STAFFS there. */
262 for (mll_insert_p
= Mainlltc_p
; mll_insert_p
!= (struct MAINLL
*) 0;
263 mll_insert_p
= mll_insert_p
->prev
) {
265 if (mll_insert_p
->str
!= S_LINE
266 && mll_insert_p
->str
!= S_CURVE
267 && mll_insert_p
->str
!= S_PRHEAD
) {
272 /* keep track of place in main list, for later use */
273 mll_p
= mll_insert_p
;
275 /* allocate and add a struct for each staff in the range */
276 for ( s
= 1; s
<= Score
.staffs
; s
++) {
278 new_p
= newMAINLLstruct(S_STAFF
, yylineno
);
279 new_p
->u
.staff_p
->staffno
= (short) s
;
280 insertMAINLL(new_p
, mll_insert_p
);
282 if (List_of_staffs_p
== (struct MAINLL
*) 0) {
283 List_of_staffs_p
= new_p
;
286 Staffmap_p
[s
] = new_p
;
287 mll_insert_p
= new_p
;
290 /* while we're making sure the main list in in the prescribed order,
291 * back up all the way to the previous bar (or beginning of list).
292 * If there are any LINES, CURVES, or PRHEADS in between there, move
293 * them to the end. This could happen if, for example, the user
294 * put in a print statement followed by a change of clef */
295 while (mll_p
!= (struct MAINLL
*) 0) {
296 if (mll_p
->str
== S_BAR
) {
297 /* this is far enough to back up */
301 if (mll_p
->str
== S_LINE
|| mll_p
->str
== S_CURVE
||
302 mll_p
->str
== S_PRHEAD
) {
303 next_mll_p
= mll_p
->prev
;
305 insertMAINLL(mll_p
, mll_insert_p
);
306 mll_insert_p
= mll_p
;
316 /* if user specifies staff as "all", need to find the top visible
317 * staff (if above) or bottom visible (if below). If not above or below,
324 int s
; /* staff number */
327 /* if user didn't specify a place, have to get default value */
328 if (Place
== PL_UNKNOWN
) {
329 Place
= dflt_place();
334 for (s
= 1; s
<= Score
.staffs
; s
++) {
335 if ( (svpath(s
, VISIBLE
))->visible
== YES
) {
336 save_staff_range(s
, ALL
);
343 for (s
= Score
.staffs
; s
> 0; s
--) {
344 if ( (svpath(s
, VISIBLE
))->visible
== YES
) {
345 save_staff_range(s
, ALL
);
352 yyerror("'all' invalid");
356 yyerror("no staffs visible");
360 /* start a new staff-voice list */
366 Svrangelist_p
= (struct SVRANGELIST
*) 0;
370 /* add the current staff and vno list to the staff-vno list */
376 struct SVRANGELIST
*new_p
;
377 struct SVRANGELIST
**insert_p_p
;
379 MALLOC(SVRANGELIST
, new_p
, 1);
380 new_p
->stafflist_p
= Staffrange_p
;
381 new_p
->vnolist_p
= Vnorange_p
;
382 new_p
->next
= (struct SVRANGELIST
*) 0;
384 /* link onto end of list */
385 for (insert_p_p
= & Svrangelist_p
;
386 *insert_p_p
!= (struct SVRANGELIST
*) 0;
387 insert_p_p
= & ((*insert_p_p
)->next
) ) {
394 /* return YES if given staff is a tab staff, NO if not */
397 is_tab_staff(staffno
)
402 if (staffno
< 1 && staffno
> MAXSTAFFS
) {
403 /* not a staff, so not a tab staff. */
406 return (Staff
[staffno
- 1].strinfo
== (struct STRINGINFO
*) 0 ? NO
: YES
);
410 /* return the staff number of the first staff on the current list of staffs.
411 * In this context, the "first staff" means the first staff the user defined,
412 * so if they said something like 5,6,9-12,2 this would return 5 */
418 struct RANGELIST
*r_p
;
420 if (Staffrange_p
== (struct RANGELIST
*) 0) {
421 pfatal("leadstaff called when no staffs on list");
424 /* since new ranges are linked onto the head of the list, we need
425 * to find the last range on the list. That will be the first one
426 * the user specified. */
427 for (r_p
= Staffrange_p
; r_p
->next
!= (struct RANGELIST
*) 0;