chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / ssv.c
1 /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2  * 2006 by Arkkra Enterprises */
3 /* All rights reserved */
4 /*
5  * Name:        ssv.c
6  *
7  * Description: This file defines the instances of score, staff, and voice
8  *              structures that are used for viewpathing.  It also contains
9  *              functions for accessing them.
10  */
11
12 #include <stdio.h>
13 #include <string.h>
14
15 #include "defines.h"
16 #include "rational.h"
17 #include "structs.h"
18 #include "globals.h"
19
20 /* define the default order of stacking for marks */
21 static char Defmarkorder[] = {
22         1,      /* MK_MUSSYM    */
23         2,      /* MK_OCTAVE    */
24         3,      /* MK_DYN       */
25         3,      /* MK_OTHERTEXT */
26         3,      /* MK_CHORD     */
27         4,      /* MK_LYRICS    */
28         5,      /* MK_ENDING    */
29         6,      /* MK_REHEARSAL */
30         7,      /* MK_PEDAL     */
31 };
32
33 /* default timesig of 4/4 */
34 static char Dflt_timerep[] = { 4, TSR_SLASH, 4, TSR_END };
35
36 static void freestaffset P((int num, struct STAFFSET *ss_p));
37 static void asgnstaffset P((int num, struct STAFFSET **new_p_p,
38                 struct STAFFSET *old_p));
39 static void setorder P((int place, struct SSV *i_p, struct SSV *f_p));
40 \f
41 /*
42  * Name:        initstructs()
43  *
44  * Abstract:    Init the fixed instances of the SSV structures.
45  *
46  * Returns:     void
47  *
48  * Description: This function initializes all the fixed structures Score,
49  *              Staff[s], and Voice[s][v].  This needs to be done before
50  *              scanning through the main linked list of user input
51  *              structures.
52  */
53
54 void
55 initstructs()
56
57 {
58         int s;          /* staff number */
59         int v;          /* voice number */
60         int n;          /* another loop variable */
61         int p;          /* place (PL_*) */
62         int m;          /* mark (MK_*) */
63         int hs;         /* head shape number */
64
65
66         /*
67          * Call zapssv() to release any malloc'ed memory, if any of the
68          * structures have been used before, and mark all fields unused.
69          */
70         zapssv(&Score);
71
72         for (s = 0; s < MAXSTAFFS; s++) {
73                 zapssv(&Staff[s]);
74                 for (v = 0; v < MAXVOICES; v++)
75                         zapssv(&Voice[s][v]);
76         }
77
78         /*
79          * Fill the Score structure with the proper default values, and
80          * mark all its fields as used.
81          */
82         /* score context */
83         Score.scale_factor = DEFSCALE;
84         Score.units = INCHES;
85         Score.pageheight = DEFPAGEHEIGHT;
86         Score.pagewidth = DEFPAGEWIDTH;
87         Score.panelsperpage = DEFPANELSPERPAGE;
88         Score.topmargin = DEFVMARGIN;
89         Score.botmargin = DEFVMARGIN;
90         Score.leftmargin = DEFHMARGIN;
91         Score.rightmargin = DEFHMARGIN;
92         Score.restcombine = NORESTCOMBINE;
93         Score.firstpage = NOFIRSTPAGE;
94         Score.staffs = DEFSTAFFS;
95         Score.minscsep = DEFMINSCSEP;
96         Score.maxscsep = DEFMAXSCSEP;
97         Score.minscpad = DEFMINSCPAD;
98         Score.maxscpad = DEFMAXSCPAD;
99         Score.nbrace = 0;
100         Score.nbrack = 0;
101         Score.nbarst = 0;
102         Score.timerep = Dflt_timerep;
103         Score.timenum = 4;
104         Score.timeden = 4;
105         Score.time.n = 1;
106         Score.time.d = 1;
107         Score.division = DEFDIVISION;
108         Score.endingstyle = ENDING_TOP;
109         Score.gridsatend = NO;
110         Score.measnum = NO;
111         Score.measnumfamily = BASE_TIMES;
112         Score.measnumfont = FONT_TR;
113         Score.measnumsize = MNUM_SIZE;
114         Score.packfact = DFLTPACKFACT;
115         Score.packexp = DFLTPACKEXP;
116         Score.warn = YES;
117
118         /* score and staff context */
119         Score.staffscale = DEFSTFSCALE;
120         Score.visible = YES;
121         Score.hidesilent = NO;
122         Score.stafflines = 5;
123         Score.strinfo = 0;
124         Score.printclef = SS_NORMAL;
125         Score.gridswhereused = NO;
126         Score.gridscale = DEFGRIDSCALE;
127         Score.gridfret = DEFGRIDFRET;
128         Score.numbermrpt = YES;
129         Score.printmultnum = YES;
130         Score.restsymmult = NO;
131         Score.vscheme = V_1;
132         for (v = 0; v < MAXVOICES; v++) {
133                 Score.vcombine[v] = 0;
134         }
135         Score.vcombinequal = VC_NOOVERLAP;
136         Score.sharps = DEFSHARPS;
137         Score.is_minor = NO;
138         Score.cancelkey = NO;
139         Score.inttype = PERFECT;
140         Score.intnum = 1;
141         Score.addinttype = PERFECT;
142         Score.addintnum = 1;
143         Score.clef = TREBLE;
144         Score.rehstyle = RS_BOXED;
145         Score.fontfamily = BASE_TIMES;
146         Score.font = FONT_TR;
147         Score.size = DFLT_SIZE;
148         Score.lyricsfamily = BASE_TIMES;
149         Score.lyricsfont = FONT_TR;
150         Score.lyricssize = DFLT_SIZE;
151         Score.lyricsalign = DEFLYRICSALIGN;
152         Score.sylposition = DEFSYLPOSITION;
153         Score.minstsep = DEFMINSTSEP;
154         Score.staffpad = DEFSTPAD;
155         for (p = 0; p < NUM_PLACE; p++) {
156                 for (m = 0; m < NUM_MARK; m++) {
157                         Score.markorder[p][m] = Defmarkorder[m];
158                 }
159         }
160         Score.pedstyle = P_LINE;
161         Score.chorddist = DEFCHORDDIST;
162         Score.dist = DEFDIST;
163         Score.dyndist = DEFDYNDIST;
164         Score.label = 0;
165         Score.label2 = 0;
166
167         /* score, staff, and voice context */
168         Score.nbeam = 0;
169         Score.nsubbeam = 0;
170         Score.beamfact = DEFBEAMFACT;
171         Score.beammax = DEFBEAMMAX;
172         Score.pad = DEFPAD;
173         Score.stemlen = DEFSTEMLEN;
174         Score.stemshorten = DEFSTEMSHORTEN;
175         Score.defoct = DEFOCTAVE;
176         Score.timeunit.n = 1;
177         Score.timeunit.d = 4;
178         Score.timelist_p = 0;
179         Score.swingunit = Zero;
180         Score.release = DEFRELEASE;
181         Score.ontheline = YES;
182         Score.tabwhitebox = NO;
183         hs = get_shape_num("norm");
184         for (n = 0; n < 7; n++) {
185                 Score.noteheads[n] = hs;
186         }
187
188         for (n = 0; n < NUMFLDS; n++) {
189                 Score.used[n] = YES;    /* all items will be set in Score */
190         }
191 }
192 \f
193 /*
194  * Name:        zapssv()
195  *
196  * Abstract:    Init a fixed instance of the SSV structure to empty.
197  *
198  * Returns:     void
199  *
200  * Description: This function initializes a fixed SSV structure to say that
201  *              all fields are unused.
202  */
203
204 void
205 zapssv(s_p)
206
207 struct SSV *s_p;                /* pointer to the structure to be zapped */
208
209 {
210         int n;          /* loop variable */
211
212
213         /*
214          * If the structure has been used before, we first have to free any
215          * memory that was malloc'ed.  It's okay to check "used" the first
216          * time, because global variables are set to 0 by the compiler;
217          * thus, used[X] == NO.
218          */
219         if (s_p->used[BRACELIST] == YES) {
220                 freestaffset(s_p->nbrace, s_p->bracelist);
221                 s_p->bracelist = 0;
222         }
223         if (s_p->used[BRACKLIST] == YES) {
224                 freestaffset(s_p->nbrack, s_p->bracklist);
225                 s_p->bracklist = 0;
226         }
227         if (s_p->used[BARSTLIST] == YES && s_p->barstlist != 0) {
228                 FREE(s_p->barstlist);
229                 s_p->barstlist = 0;
230         }
231         if (s_p->used[LABEL] == YES && s_p->label != 0) {
232                 FREE(s_p->label);
233                 s_p->label = 0;
234         }
235         if (s_p->used[LABEL2] == YES && s_p->label2 != 0) {
236                 FREE(s_p->label2);
237                 s_p->label2 = 0;
238         }
239         if (s_p->used[BEAMSTLIST] == YES && s_p->beamstlist != 0) {
240                 FREE(s_p->beamstlist);
241                 s_p->beamstlist = 0;
242         }
243
244         /*
245          * Mark all fields unused.
246          */
247         for (n = 0; n < NUMFLDS; n++) {
248                 s_p->used[n] = NO;
249         }
250 }
251 \f
252 /*
253  * Name:        freestaffset()
254  *
255  * Abstract:    Free all malloc'ed memory associated with a staffset list.
256  *
257  * Returns:     void
258  *
259  * Description: This function frees staffset structures, along with their
260  *              labels if they exist.
261  */
262
263 static void
264 freestaffset(num, ss_p)
265
266 int num;                        /* how many staffsets are in list? */
267 struct STAFFSET *ss_p;          /* pointer to first staffset */
268
269 {
270         int n;                  /* loop variable */
271
272
273         if (ss_p == 0)                  /* if there is no list, just return */
274                 return;
275
276         /* for each staffset in the list, free labels if present */
277         for (n = 0; n < num; n++) {
278                 if (ss_p[n].label != 0) {               /* if label, free it */
279                         FREE(ss_p[n].label);
280                         ss_p[n].label = 0;
281                 }
282                 if (ss_p[n].label2 != 0) {      /* if label2, free it */
283                         FREE(ss_p[n].label2);
284                         ss_p[n].label2 = 0;
285                 }
286         }
287
288         FREE(ss_p);                     /* free the staffset list itself */
289 }
290 \f
291 /*
292  * Name:        asgnstaffset()
293  *
294  * Abstract:    Set up a staffset list in another SSV structure.
295  *
296  * Returns:     void
297  *
298  * Description: This function sets up a new staffset list identical to
299  *              another one, including the labels if they exist.
300  */
301
302 static void
303 asgnstaffset(num, new_p_p, old_p)
304
305 int num;                        /* how many staffsets are in list? */
306 struct STAFFSET **new_p_p;      /* ptr to ptr to first staffset of new list */
307 struct STAFFSET *old_p;         /* pointer to first staffset of old list */
308
309 {
310         int n;          /* loop variable */
311
312
313         if (num == 0)           /* if there's no old list, nothing to do */
314                 return;
315
316         /*
317          * Allocate the new list and point at it.
318          */
319         MALLOC(STAFFSET, *new_p_p, num);
320
321         /*
322          * Loop through the old list.  Wherever there is a label, allocate
323          * one for the new list.  When there isn't, set that pointer to null.
324          */
325         for (n = 0; n < num; n++) {
326                 (*new_p_p)[n].topstaff = old_p[n].topstaff;
327                 (*new_p_p)[n].botstaff = old_p[n].botstaff;
328
329                 if (old_p[n].label != 0) {
330                         MALLOCA(char, (*new_p_p)[n].label,
331                                         strlen(old_p[n].label) + 1);
332                         (void)strcpy((*new_p_p)[n].label, old_p[n].label);
333                 } else {
334                         (*new_p_p)[n].label = 0;
335                 }
336
337                 if (old_p[n].label2 != 0) {
338                         MALLOCA(char, (*new_p_p)[n].label2,
339                                         strlen(old_p[n].label2) + 1);
340                         (void)strcpy((*new_p_p)[n].label2, old_p[n].label2);
341                 } else {
342                         (*new_p_p)[n].label2 = 0;
343                 }
344         }
345 }
346 \f
347 /*
348  * Name:        svpath()
349  *
350  * Abstract:    Find a field for a staff, using the viewpath.
351  *
352  * Returns:     pointer to structure containing correct field value
353  *
354  * Description: This function, given a staff number and a field number, looks
355  *              down the viewpath to find the first structure where the field
356  *              is set.  It returns a pointer to that structure.  (However, see
357  *              below for a special kluge for the "visible" field.)
358  *              Note:  0 is allowed for the staff number, and that means use
359  *              the Score value.
360  */
361
362 struct SSV *
363 svpath(s, field)
364
365 int s;          /* staff number, 1 to MAXSTAFFS; or 0, meaning score */
366 int field;      /* the defined symbol for the field desired */
367
368 {
369         static struct SSV phony;        /* phony SSV; see below */
370
371
372         if (s == 0)
373                 return (&Score);
374
375         /*
376          * For the "visible" field, special kluges are needed, for two reasons.
377          * One is that there is a command line option (-s) that overrides the
378          * visibility requests in the Mup input file.  The other is that, even
379          * though it is a score/staff/voice parameter, it is easier to manage
380          * visibility at the staff level than at the voice level.  Otherwise,
381          * to know if a staff should be drawn, we would have to check vscheme
382          * and the visibility state of each voice.
383          *
384          * The design is as follows:  in mkchords.c, if a voice is to be
385          * invisible, a measure space is put in place of its original GRPSYL
386          * list.  Users can use svpath() to check if a staff is visible
387          * instead of having to call vvpath() for its voice(s).  The field
388          * staff_p->visible is set by calling here, so that will also be
389          * consistent.
390          *
391          * If the -s option was used on the command line, only staffs/voices
392          * listed there are ever allowed to be visible.  So although SSVs are
393          * set as for other score/staff/voice parameters, the results from
394          * svpath() also consider what the -s option said.  In vvpath() this
395          * is also done.
396          */
397         if (field == VISIBLE) {
398                 int num_voices;         /* how many voices on this staff */
399
400                 /*
401                  * In case we are going to return the phony SSV, load the
402                  * hidesilent field into it.  Both visible and hidesilent are
403                  * controlled by VISIBLE, but hidesilent is not to be affected
404                  * by the kluges needed for "visible".
405                  */
406                 /* if the field is set in the staff structure, use that */
407                 if (Staff[s-1].used[VISIBLE] == YES) {
408                         phony.hidesilent = Staff[s-1].hidesilent;
409                 } else {
410                         /* use the score structure; it's always set there */
411                         phony.hidesilent = Score.hidesilent;
412                 }
413
414                 /* always return NO if the command line says staff invisible */
415                 if (Staff_vis[s] == NO) {
416                         /* return phony SSV with NO, ignore real SSV */
417                         phony.visible = NO;
418                         return (&phony);
419                 }
420
421                 num_voices = vscheme_voices(svpath(s, VSCHEME)->vscheme);
422
423                 /*
424                  * If a voice that the command line is allowing to be visible
425                  * was requested via an SSV to be visible, we must let the
426                  * staff be visible.
427                  */
428                 if ((Voice_vis[s][1] == YES &&
429                      Voice[s-1][0].used[VISIBLE] == YES &&
430                      Voice[s-1][0].visible == YES) ||
431
432                     (num_voices >= 2 &&
433                      Voice_vis[s][2] == YES &&
434                      Voice[s-1][1].used[VISIBLE] == YES &&
435                      Voice[s-1][1].visible == YES) ||
436
437                     (num_voices >= 3 &&
438                      Voice_vis[s][3] == YES &&
439                      Voice[s-1][2].used[VISIBLE] == YES &&
440                      Voice[s-1][2].visible == YES)) {
441
442                         /* return phony SSV with YES, ignore real SSV */
443                         phony.visible = YES;
444                         return (&phony);
445                 }
446
447                 /*
448                  * If, for each voice that exists, either the command line is
449                  * forcing it to be invisible or else it was requested via an
450                  * SSV to be invisible, then the staff must be invisible.
451                  */
452                 if ((Voice_vis[s][1] == NO ||
453                      Voice[s-1][0].used[VISIBLE] == YES &&
454                      Voice[s-1][0].visible == NO) &&
455
456                     (num_voices < 2 ||
457                      (Voice_vis[s][2] == NO ||
458                       Voice[s-1][1].used[VISIBLE] == YES &&
459                       Voice[s-1][1].visible == NO)) &&
460
461                     (num_voices < 3 ||
462                      (Voice_vis[s][3] == NO ||
463                       Voice[s-1][2].used[VISIBLE] == YES &&
464                       Voice[s-1][2].visible == NO))) {
465
466                         /* return phony SSV with NO, ignore real SSV */
467                         phony.visible = NO;
468                         return (&phony);
469                 }
470
471                 /*
472                  * The command line and the voice(s) aren't forcing the issue.
473                  * So fall through to determine the staff's visibility the
474                  * normal way.
475                  */
476         }
477
478         /* if the field is set in the staff structure, use that */
479         if (Staff[s-1].used[field] == YES)
480                 return (&Staff[s-1]);
481
482         /* else use the score structure; it's always set there */
483         return (&Score);
484 }
485 \f
486 /*
487  * Name:        vvpath()
488  *
489  * Abstract:    Find a field for a voice, using the viewpath.
490  *
491  * Returns:     pointer to structure containing correct field value
492  *
493  * Description: This function, given a staff number, voice number on that
494  *              staff, and a field number, looks down the viewpath to find
495  *              the first structure where the field is set.  It returns a
496  *              pointer to that structure.  (However, see below for a special
497  *              kluge for the "visible" field.)
498  *              Note:  0 is allowed for the voice number, and that means use
499  *              the staff's value.  If staff is 0, the Score is used,
500  *              regardless of the voice number.
501  */
502
503 struct SSV *
504 vvpath(s, v, field)
505
506 int s;          /* staff number, 1 to MAXSTAFFS; or 0, meaning score */
507 int v;          /* voice number, 1 to MAXVOICES; or 0, meaning staff */
508 int field;      /* the defined symbol for the field desired */
509
510 {
511         static struct SSV phony;        /* phony SSV; see below */
512
513
514         if (s == 0 || v == 0)
515                 return (svpath(s, field));
516
517         /*
518          * See the comment in svpath() regarding the "visible" field.  There's
519          * probably no need to call vvpath() for "visible" after mkchords.c has
520          * run, since voices that are to be invisible are changed to measure
521          * spaces there.  But in mkchords.c itself, and earlier, there is
522          * sometimes a need.
523          *
524          * For the "visible" field, first check the command line to see if this
525          * voice or its staff must always be invisible.  If so, return a phony
526          * SSV that says that.  Otherwise fall through to handle the normal way.
527          */
528         if (field == VISIBLE && (Staff_vis[s] == NO || Voice_vis[s][v] == NO)) {
529                 /*
530                  * Since we are going to force visible to NO, it's irrelevant
531                  * what hidesilent is, so don't bother setting it, unlike what
532                  * we had to do in svpath().
533                  */
534                 phony.visible = NO;
535                 return (&phony);
536         }
537
538         /* if the field is set in the voice structure, use that */
539         if (Voice[s-1][v-1].used[field] == YES)
540                 return (&Voice[s-1][v-1]);
541
542         /* else if the field is set in the staff structure, use that */
543         if (Staff[s-1].used[field] == YES)
544                 return (&Staff[s-1]);
545
546         /* else use the score structure; it's always set there */
547         return (&Score);
548 }
549 \f
550 /*
551  * Name:        asgnssv()
552  *
553  * Abstract:    Assign fields from an input SSV to a fixed one.
554  *
555  * Returns:     void
556  *
557  * Description: This function is passed an input SSV structure (from an input
558  *              context).  For each field where "used" is YES in the input SSV,
559  *              it copies it to the appropriate fixed SSV and sets its "used"
560  *              flag to YES.  For each field where "used" is UNSET in the input
561  *              SSV, it sets "used" to NO in the appropriate fixed SSV.
562  *              In some cases, there are side effects, where it also
563  *              alters a lower level structure.  E.g., changing the number of
564  *              voices of a staff inits its voice structures.  In the case
565  *              of stafflines, setting a staff to be a tablature staff
566  *              automatically automatically forces some other fields to be set
567  *              not only in the given staff, but also in the preceding tabnote
568  *              staff.  Note also that the Score "used" flags are already
569  *              always set and don't need to be set here.  And Score fields can
570  *              never be unset.
571  */
572
573 void
574 asgnssv(i_p)
575
576 struct SSV *i_p;        /* input SSV structure to be copied from */
577
578 {
579         struct SSV *f_p;        /* ptr to fixed SSV structure to copy into */
580         int s, v;               /* used for looping through staffs & voices */
581         int start, stop;        /* loop limits */
582         int n;                  /* another loop variable */
583
584
585         f_p = 0;        /* to prevent "uninitialized variable" warnings */
586
587         /*
588          * Using the selector fields in the input structure, set a pointer to
589          * the fixed structure that is to be populated.
590          */
591         switch (i_p->context) {
592         case C_SCORE:
593                 f_p = &Score;
594                 break;
595         case C_STAFF:
596                 /* silently ignore bogus staff no.; it is caught elsewhere */
597                 if (i_p->staffno < 1 || i_p->staffno > MAXSTAFFS) {
598                         return;
599                 }
600                 f_p = &Staff[ i_p->staffno - 1 ];
601                 break;
602         case C_VOICE:
603                 /* silently ignore bogus staff/voice; it is caught elsewhere */
604                 if (i_p->staffno < 1 || i_p->staffno > MAXSTAFFS ||
605                     i_p->voiceno < 1 || i_p->voiceno > MAXVOICES) {
606                         return;
607                 }
608                 f_p = &Voice[ i_p->staffno - 1 ][ i_p->voiceno - 1 ];
609                 break;
610         }
611
612         /*
613          * ========== ITEMS FOR SCORE CONTEXT ONLY ===========
614          * There's no need to set f_p->used[] = YES here; since this is the
615          * score, those bits are already always YES.
616          */
617         if (i_p->used[SCALE_FACTOR] == YES) {
618                 f_p->scale_factor = i_p->scale_factor;
619         }
620
621         if (i_p->used[UNITS] == YES) {
622                 f_p->units = i_p->units;
623         }
624
625         /*
626          * PAGEHEIGHT, PAGEHEIGHT, and PANELSPERPAGE interact, because when the
627          * user sets PAGE*, they are referring to the paper, but internally we
628          * want page* to refer to one "panel" of music, which is a 90 degree
629          * rotated half of the sheet of paper when panelsperpage is 2.
630          */
631         if (i_p->used[PAGEHEIGHT] == YES) {
632                 if (f_p->panelsperpage == 1) {
633                         f_p->pageheight = i_p->pageheight;
634                 } else {
635                         f_p->pagewidth = i_p->pageheight / 2.0;
636                 }
637         }
638
639         if (i_p->used[PAGEWIDTH] == YES) {
640                 if (f_p->panelsperpage == 1) {
641                         f_p->pagewidth = i_p->pagewidth;
642                 } else {
643                         f_p->pageheight = i_p->pagewidth;
644                 }
645         }
646
647         if (i_p->used[PANELSPERPAGE] == YES) {
648                 /* depending on how this is changing, flip height and width */
649                 float oldwidth;
650                 if (f_p->panelsperpage == 1 && i_p->panelsperpage == 2) {
651                         oldwidth = f_p->pagewidth;
652                         f_p->pagewidth = f_p->pageheight / 2.0;
653                         f_p->pageheight = oldwidth;
654                 } else if (f_p->panelsperpage == 2 && i_p->panelsperpage == 1) {
655                         oldwidth = f_p->pagewidth;
656                         f_p->pagewidth = f_p->pageheight;
657                         f_p->pageheight = oldwidth * 2.0;
658                 }
659                 f_p->panelsperpage = i_p->panelsperpage;
660         }
661
662         if (i_p->used[TOPMARGIN] == YES) {
663                 f_p->topmargin = i_p->topmargin;
664         }
665
666         if (i_p->used[BOTMARGIN] == YES) {
667                 f_p->botmargin = i_p->botmargin;
668         }
669
670         if (i_p->used[LEFTMARGIN] == YES) {
671                 f_p->leftmargin = i_p->leftmargin;
672         }
673
674         if (i_p->used[RIGHTMARGIN] == YES) {
675                 f_p->rightmargin = i_p->rightmargin;
676         }
677
678         if (i_p->used[RESTCOMBINE] == YES) {
679                 f_p->restcombine = i_p->restcombine;
680         }
681
682         if (i_p->used[FIRSTPAGE] == YES) {
683                 f_p->firstpage = i_p->firstpage;
684         }
685
686         if (i_p->used[NUMSTAFF] == YES) {
687                 f_p->staffs = i_p->staffs;
688
689                 /* this destroys all staff and voice info */
690                 for (s = 0; s < MAXSTAFFS; s++) {
691                         zapssv(&Staff[s]);
692                         for (v = 0; v < MAXVOICES; v++)
693                                 zapssv(&Voice[s][v]);
694                 }
695         }
696
697         if (i_p->used[MINSCSEP] == YES) {
698                 f_p->minscsep = i_p->minscsep;
699         }
700
701         if (i_p->used[MAXSCSEP] == YES) {
702                 f_p->maxscsep = i_p->maxscsep;
703         }
704
705         if (i_p->used[MINSCPAD] == YES) {
706                 f_p->minscpad = i_p->minscpad;
707         }
708
709         if (i_p->used[MAXSCPAD] == YES) {
710                 f_p->maxscpad = i_p->maxscpad;
711         }
712
713         if (i_p->used[BRACELIST] == YES) {
714                 /* if it was already used, free old list if present */
715                 if (f_p->used[BRACELIST] == YES) {
716                         freestaffset(f_p->nbrace, f_p->bracelist);
717                         f_p->bracelist = 0;
718                 }
719
720                 /* set up new list */
721                 f_p->nbrace = i_p->nbrace;
722                 asgnstaffset(f_p->nbrace, &f_p->bracelist, i_p->bracelist);
723         }
724
725         if (i_p->used[BRACKLIST] == YES) {
726                 /* if it was already used, free old list if present */
727                 if (f_p->used[BRACKLIST] == YES) {
728                         freestaffset(f_p->nbrack, f_p->bracklist);
729                         f_p->bracklist = 0;
730                 }
731
732                 /* set up new list */
733                 f_p->nbrack = i_p->nbrack;
734                 asgnstaffset(f_p->nbrack, &f_p->bracklist, i_p->bracklist);
735         }
736
737         if (i_p->used[BARSTLIST] == YES) {
738                 /* if it was already used, free old list if present */
739                 if (f_p->used[BARSTLIST] == YES && f_p->nbarst != 0)
740                         FREE(f_p->barstlist);
741
742                 /* set up new list */
743                 f_p->nbarst = i_p->nbarst;
744                 /* the +1 is to guard against allocating 0 */
745                 MALLOC(TOP_BOT, f_p->barstlist, f_p->nbarst + 1);
746                 for (n = 0; n < f_p->nbarst; n++) {
747                         f_p->barstlist[n] = i_p->barstlist[n];
748                 }
749         }
750
751         if (i_p->used[TIME] == YES) {
752                 f_p->timenum  = i_p->timenum;
753                 f_p->timeden  = i_p->timeden;
754                 f_p->timevis  = i_p->timevis;
755                 f_p->timerep  = i_p->timerep;
756                 f_p->time     = i_p->time;
757
758                 /*
759                  * Changing the time sig forces a change in default time unit.
760                  * Set it to one "beat" for the score, and unset it for all
761                  * staffs and voices.
762                  */
763                 f_p->timeunit.n = 1;
764                 f_p->timeunit.d = f_p->timeden;
765                 f_p->timelist_p = 0;
766                 for (s = 0; s < MAXSTAFFS; s++) {
767                         Staff[s].used[TIMEUNIT] = NO;
768                         for (v = 0; v < MAXVOICES; v++)
769                                 Voice[s][v].used[TIMEUNIT] = NO;
770                 }
771
772                 /*
773                  * Changing the time also destroys all beamstyle lists.
774                  * However, the special empty beamstyle list that was set up
775                  * for a tablature staff must be retained, so that it will
776                  * continue to override any score beamstyle list that may be
777                  * set up later on.
778                  */
779                 if (Score.used[BEAMSTLIST] == YES) {
780                         if (Score.nbeam != 0) {
781                                 FREE(Score.beamstlist);
782                                 Score.beamstlist = 0;
783                                 Score.nbeam = 0;
784                                 FREE(Score.subbeamstlist);
785                                 Score.subbeamstlist = 0;
786                                 Score.nsubbeam = 0;
787                         }
788                 }
789                 for (s = 0; s < MAXSTAFFS; s++) {
790                         if (Staff[s].used[BEAMSTLIST] == YES &&
791                             Staff[s].strinfo == 0) {    /* not tablature */
792                                 if (Staff[s].nbeam != 0) {
793                                         FREE(Staff[s].beamstlist);
794                                         Staff[s].beamstlist = 0;
795                                         Staff[s].nbeam = 0;
796                                         FREE(Staff[s].subbeamstlist);
797                                         Staff[s].subbeamstlist = 0;
798                                         Staff[s].nsubbeam = 0;
799                                 }
800                                 Staff[s].used[BEAMSTLIST] = NO;
801                         }
802                         for (v = 0; v < MAXVOICES; v++) {
803                                 if (Voice[s][v].used[BEAMSTLIST] == YES) {
804                                         if (Voice[s][v].nbeam != 0) {
805                                                 FREE(Voice[s][v].beamstlist);
806                                                 Voice[s][v].beamstlist = 0;
807                                                 Voice[s][v].nbeam = 0;
808                                                 FREE(Voice[s][v].subbeamstlist);
809                                                 Voice[s][v].subbeamstlist = 0;
810                                                 Voice[s][v].nsubbeam = 0;
811                                         }
812                                         Voice[s][v].used[BEAMSTLIST] = NO;
813                                 }
814                         }
815                 }
816         }
817
818         if (i_p->used[DIVISION] == YES) {
819                 f_p->division = i_p->division;
820         }
821
822         if (i_p->used[ENDINGSTYLE] == YES) {
823                 f_p->endingstyle = i_p->endingstyle;
824         }
825
826         if (i_p->used[GRIDSATEND] == YES) {
827                 f_p->gridsatend = i_p->gridsatend;
828         }
829
830         if (i_p->used[MEASNUM] == YES) {
831                 f_p->measnum = i_p->measnum;
832         }
833
834         if (i_p->used[MEASNUMFAMILY] == YES) {
835                 f_p->measnumfamily = i_p->measnumfamily;
836         }
837
838         if (i_p->used[MEASNUMFONT] == YES) {
839                 f_p->measnumfont = i_p->measnumfont;
840         }
841
842         if (i_p->used[MEASNUMSIZE] == YES) {
843                 f_p->measnumsize = i_p->measnumsize;
844         }
845
846         if (i_p->used[PACKFACT] == YES) {
847                 f_p->packfact = i_p->packfact;
848         }
849
850         if (i_p->used[PACKEXP] == YES) {
851                 f_p->packexp = i_p->packexp;
852         }
853
854         if (i_p->used[WARN] == YES) {
855                 f_p->warn = i_p->warn;
856         }
857
858         /*
859          * ========== ITEMS FOR SCORE AND STAFF CONTEXT ===========
860          */
861         /*
862          * Most parameters involve just a single field, and have no side
863          * effects.  For this, we can use the following switch statement to
864          * do the work, for parameters that can exist on staff or voice.
865          * (Score-only ones don't need it, since that can't be unset.)
866          */
867 #define SETPARM(name, NAME)                     \
868         switch (i_p->used[NAME]) {              \
869         case YES:                               \
870                 f_p->name = i_p->name;          \
871                 f_p->used[NAME] = YES;          \
872                 break;                          \
873         case UNSET:                             \
874                 f_p->used[NAME] = NO;           \
875                 break;                          \
876         /* default is NO; do nothing */         \
877         }
878
879         SETPARM(staffscale, STAFFSCALE)
880
881         switch (i_p->used[STAFFLINES]) {
882         case YES: {
883                 struct SSV *tabnote_p;  /* ptr to tabnote fixed SSV */
884                 f_p->stafflines = i_p->stafflines;
885
886                 if (i_p->strinfo != 0) {        /* tablature */
887                         struct SSV *voice_p;    /* ptr to a voice's fixed SSV*/
888
889                         /*
890                          * This is a tablature staff.  Set printclef to normal
891                          * (even though tab isn't particularly "normal").
892                          * Point f_p->strinfo at the same array that
893                          * i_p->strinfo points at.
894                          */
895                         f_p->printclef = SS_NORMAL;
896                         f_p->strinfo = i_p->strinfo;
897
898                         /*
899                          * Force some other score/staff items to fixed values
900                          * for tab.  The parser blocks the user from setting
901                          * these.  We need to set them here in the staff SSV to
902                          * override whatever may be in the score SSV.  This
903                          * will make it possible to avoid special checks for
904                          * tablature in many places; the right values will be
905                          * set for this staff.  Also force score/staff/voice
906                          * items here.
907                          */
908                         f_p->sharps = 0;
909                         f_p->is_minor = NO;
910                         f_p->used[SHARPS] = YES;
911
912                         f_p->inttype = PERFECT;
913                         f_p->intnum = 1;
914                         f_p->used[TRANSPOSITION] = YES;
915
916                         f_p->addinttype = PERFECT;
917                         f_p->addintnum = 1;
918                         f_p->used[ADDTRANSPOSITION] = YES;
919
920                         f_p->clef = TABCLEF;
921                         f_p->used[CLEF] = YES;
922
923                         if (f_p->used[BEAMSTLIST] == YES && f_p->nbeam != 0) {
924                                 /* if already used, free old list if present */
925                                 FREE(f_p->beamstlist);
926                                 FREE(f_p->subbeamstlist);
927                         }
928                         f_p->nbeam = 0;
929                         f_p->beamstlist = 0;
930                         f_p->nsubbeam = 0;
931                         f_p->subbeamstlist = 0;
932                         f_p->used[BEAMSTLIST] = YES;
933
934                         f_p->defoct = 4;
935                         f_p->used[DEFOCT] = YES;
936
937                         /* blow away the following in tab staff's voices */
938                         for (v = 0; v < MAXVOICES; v++) {
939                                 voice_p = &Voice[ i_p->staffno - 1][ v ];
940
941                                 if (voice_p->used[BEAMSTLIST] == YES) {
942                                         if (voice_p->nbeam != 0) {
943                                                 FREE(f_p->beamstlist);
944                                                 FREE(f_p->subbeamstlist);
945                                         }
946                                         voice_p->used[BEAMSTLIST] = NO;
947                                 }
948                                 voice_p->used[DEFOCT] = NO;
949                         }
950
951                         /*
952                          * Force fields on the tabnote staff above this tab
953                          * staff.
954                          */
955                         tabnote_p = &Staff[ i_p->staffno - 2 ];
956
957                         /*
958                          * The parse phase wouldn't let this be another tab
959                          * staff, so we don't need to check for that.  But it
960                          * might be a 1-line staff.  If so, override it to 5
961                          * line.  If this parameter wasn't set, force printclef
962                          * to normal, but if it was, keep the old value.  (We
963                          * might as well allow 5n and 5 drum as well as 5,
964                          * though that would be a weird usage.)
965                          */
966                         tabnote_p->stafflines = 5;
967                         if (tabnote_p->used[STAFFLINES] == NO)
968                                 tabnote_p->printclef = SS_NORMAL;
969                         tabnote_p->used[STAFFLINES] = YES;
970
971                 } else {        /* not tablature */
972                         /*
973                          * If this staff used to be tablature, we need to unset
974                          * some "used" fields that were forced.
975                          */
976                         if (f_p->strinfo != 0) {
977                                 f_p->used[SHARPS] = NO;
978                                 f_p->used[TRANSPOSITION] = NO;
979                                 f_p->used[ADDTRANSPOSITION] = NO;
980                                 f_p->used[CLEF] = NO;
981                                 f_p->used[BEAMSTLIST] = NO;
982                                 f_p->used[DEFOCT] = NO;
983                                 tabnote_p = &Staff[ i_p->staffno - 2 ];
984
985                                 /* make it non-tablature */
986                                 f_p->strinfo = 0;
987                         }
988
989                         f_p->printclef = i_p->printclef;
990                 }
991                 f_p->used[STAFFLINES] = YES;
992                 } break;
993         case UNSET:
994                 f_p->used[STAFFLINES] = NO;
995                 break;
996         }
997
998         SETPARM(gridswhereused, GRIDSWHEREUSED)
999
1000         SETPARM(gridscale, GRIDSCALE)
1001
1002         SETPARM(gridfret, GRIDFRET)
1003
1004         SETPARM(numbermrpt, NUMBERMRPT)
1005
1006         SETPARM(printmultnum, PRINTMULTNUM)
1007
1008         SETPARM(restsymmult, RESTSYMMULT)
1009
1010         switch (i_p->used[VSCHEME]) {
1011         case YES:
1012                 /*
1013                  * If the vscheme change changes the *number* of voices, we
1014                  * have to wipe out the voice information, but otherwise not.
1015                  */
1016                 if (i_p->context == C_SCORE) {
1017                         start = 0;              /* if score, do test for */
1018                         stop = MAXSTAFFS - 1;   /*  all staffs */
1019                 } else {        /* C_STAFF */
1020                         start = stop = i_p->staffno - 1; /* do just this one */
1021                 }
1022
1023                 /* for each staff affected by this change . . . */
1024                 for (n = start; n <= stop; n++) {
1025                         int oldvoices, newvoices; /* how many before & after */
1026
1027                         oldvoices = vscheme_voices(svpath(n + 1,
1028                                         VSCHEME)->vscheme);
1029                         newvoices = vscheme_voices(i_p->vscheme);
1030
1031                         if (oldvoices != newvoices) {
1032
1033                                 for (v = 0; v < MAXVOICES; v++)
1034                                         zapssv(&Voice[n][v]);
1035                         }
1036                 }
1037
1038                 f_p->vscheme = i_p->vscheme;
1039                 f_p->used[VSCHEME] = YES;
1040                 break;
1041         case UNSET:
1042                 f_p->used[VSCHEME] = NO;
1043                 break;
1044         }
1045
1046         switch (i_p->used[VCOMBINE]) {
1047         case YES:
1048                 for (v = 0; v < MAXVOICES; v++) {
1049                         f_p->vcombine[v] = i_p->vcombine[v];
1050                 }
1051                 f_p->vcombinequal = i_p->vcombinequal;
1052                 f_p->used[VCOMBINE] = YES;
1053                 break;
1054         case UNSET:
1055                 f_p->used[VCOMBINE] = NO;
1056                 break;
1057         }
1058
1059         switch (i_p->used[SHARPS]) {
1060         case YES:
1061                 f_p->sharps = i_p->sharps;
1062                 f_p->is_minor = i_p->is_minor;
1063                 f_p->used[SHARPS] = YES;
1064                 break;
1065         case UNSET:
1066                 f_p->used[SHARPS] = NO;
1067                 break;
1068         }
1069
1070         SETPARM(cancelkey, CANCELKEY)
1071
1072         switch (i_p->used[TRANSPOSITION]) {
1073         case YES:
1074                 f_p->inttype = i_p->inttype;
1075                 f_p->intnum = i_p->intnum;
1076                 f_p->used[TRANSPOSITION] = YES;
1077                 break;
1078         case UNSET:
1079                 f_p->used[TRANSPOSITION] = NO;
1080                 break;
1081         }
1082
1083         switch (i_p->used[ADDTRANSPOSITION]) {
1084         case YES:
1085                 f_p->addinttype = i_p->addinttype;
1086                 f_p->addintnum = i_p->addintnum;
1087                 f_p->used[ADDTRANSPOSITION] = YES;
1088                 break;
1089         case UNSET:
1090                 f_p->used[ADDTRANSPOSITION] = NO;
1091                 break;
1092         }
1093
1094         switch (i_p->used[CLEF]) {
1095         case YES:
1096                 f_p->clef = i_p->clef;
1097                 f_p->used[CLEF] = YES;
1098
1099                 /*
1100                  * Reset the default octave so that the middle line of the
1101                  * staff lies within it.  If the user also set octave in
1102                  * this context, this will get changed again later in this
1103                  * function.
1104                  */
1105                 if (f_p->clef > ALTO)           /* lower than alto */
1106                         f_p->defoct = 3;
1107                 else if (f_p->clef < TREBLE)    /* higher than treble */
1108                         f_p->defoct = 5;
1109                 else
1110                         f_p->defoct = 4;
1111                 f_p->used[DEFOCT] = YES;
1112                 break;
1113         case UNSET:
1114                 f_p->used[DEFOCT] = NO;
1115                 break;
1116         }
1117
1118         SETPARM(rehstyle, REHSTYLE)
1119
1120         SETPARM(fontfamily, FONTFAMILY)
1121
1122         SETPARM(font, FONT)
1123
1124         SETPARM(size, SIZE)
1125
1126         SETPARM(lyricsfamily, LYRICSFAMILY)
1127
1128         SETPARM(lyricsfont, LYRICSFONT)
1129
1130         SETPARM(lyricssize, LYRICSSIZE)
1131
1132         SETPARM(lyricsalign, LYRICSALIGN)
1133
1134         SETPARM(sylposition, SYLPOSITION)
1135
1136         SETPARM(minstsep, MINSTSEP)
1137
1138         SETPARM(staffpad, STAFFPAD)
1139
1140         switch (i_p->used[ABOVEORDER]) {
1141         case YES:
1142                 setorder(PL_ABOVE, i_p, f_p);
1143                 f_p->used[ABOVEORDER] = YES;
1144                 break;
1145         case UNSET:
1146                 f_p->used[ABOVEORDER] = NO;
1147                 break;
1148         }
1149
1150         switch (i_p->used[BELOWORDER]) {
1151         case YES:
1152                 setorder(PL_BELOW, i_p, f_p);
1153                 f_p->used[BELOWORDER] = YES;
1154                 break;
1155         case UNSET:
1156                 f_p->used[BELOWORDER] = NO;
1157                 break;
1158         }
1159
1160         switch (i_p->used[BETWEENORDER]) {
1161         case YES:
1162                 setorder(PL_BETWEEN, i_p, f_p);
1163                 f_p->used[BETWEENORDER] = YES;
1164                 break;
1165         case UNSET:
1166                 f_p->used[BETWEENORDER] = NO;
1167                 break;
1168         }
1169
1170         SETPARM(pedstyle, PEDSTYLE)
1171
1172         SETPARM(chorddist, CHORDDIST)
1173
1174         SETPARM(dist, DIST)
1175
1176         SETPARM(dyndist, DYNDIST)
1177
1178         switch (i_p->used[LABEL]) {
1179         case YES:
1180                 /* if it was already used, free old label */
1181                 if (f_p->used[LABEL] == YES && f_p->label != 0) {
1182                         FREE(f_p->label);
1183                         f_p->label = 0;
1184                 }
1185
1186                 /* set up new label */
1187                 MALLOCA(char, f_p->label, strlen(i_p->label) + 1);      
1188                 (void)strcpy(f_p->label, i_p->label);
1189
1190                 f_p->used[LABEL] = YES;
1191                 break;
1192         case UNSET:
1193                 /* if it was already used, free old label */
1194                 if (f_p->used[LABEL] == YES && f_p->label != 0) {
1195                         FREE(f_p->label);
1196                         f_p->label = 0;
1197                 }
1198                 f_p->used[LABEL] = NO;
1199                 break;
1200         }
1201
1202         switch (i_p->used[LABEL2]) {
1203         case YES:
1204                 /* if it was already used, free old label2 */
1205                 if (f_p->used[LABEL2] == YES && f_p->label2 != 0) {
1206                         FREE(f_p->label2);
1207                         f_p->label2 = 0;
1208                 }
1209
1210                 /* set up new label */
1211                 MALLOCA(char, f_p->label2, strlen(i_p->label2) + 1);
1212                 (void)strcpy(f_p->label2, i_p->label2);
1213
1214                 f_p->used[LABEL2] = YES;
1215                 break;
1216         case UNSET:
1217                 /* if it was already used, free old label2 */
1218                 if (f_p->used[LABEL2] == YES && f_p->label2 != 0) {
1219                         FREE(f_p->label2);
1220                         f_p->label2 = 0;
1221                 }
1222                 f_p->used[LABEL2] = NO;
1223                 break;
1224         }
1225
1226         /*
1227          * ========== ITEMS FOR SCORE, STAFF, AND VOICE CONTEXT ===========
1228          */
1229         switch (i_p->used[VISIBLE]) {
1230         case YES:
1231                 f_p->visible = i_p->visible;
1232                 f_p->hidesilent = i_p->hidesilent;
1233                 f_p->used[VISIBLE] = YES;
1234                 break;
1235         case UNSET:
1236                 f_p->used[VISIBLE] = NO;
1237         }
1238
1239         switch (i_p->used[BEAMSTLIST]) {
1240         case YES:
1241                 /* if it was already used, free old list if present */
1242                 if (f_p->used[BEAMSTLIST] == YES && f_p->nbeam != 0) {
1243                         FREE(f_p->beamstlist);
1244                         FREE(f_p->subbeamstlist);
1245                         f_p->beamstlist = 0;
1246                         f_p->subbeamstlist = 0;
1247                 }
1248
1249                 /* set up new list */
1250                 f_p->nbeam = i_p->nbeam;
1251                 f_p->beamrests = i_p->beamrests;
1252                 f_p->beamspaces = i_p->beamspaces;
1253                 f_p->nsubbeam = i_p->nsubbeam;
1254                 /* the +1 is to guard against allocating 0 */
1255                 MALLOCA(RATIONAL, f_p->beamstlist, f_p->nbeam + 1);
1256                 MALLOCA(RATIONAL, f_p->subbeamstlist, f_p->nsubbeam + 1);
1257                 for (n = 0; n < f_p->nbeam; n++) {
1258                         f_p->beamstlist[n] = i_p->beamstlist[n];
1259                 }
1260                 for (n = 0; n < f_p->nsubbeam; n++) {
1261                         f_p->subbeamstlist[n] = i_p->subbeamstlist[n];
1262                 }
1263
1264                 f_p->used[BEAMSTLIST] = YES;
1265                 break;
1266         case UNSET:
1267                 /* if it was already used, free old list if present */
1268                 if (f_p->used[BEAMSTLIST] == YES && f_p->nbeam != 0) {
1269                         FREE(f_p->beamstlist);
1270                         FREE(f_p->subbeamstlist);
1271                         f_p->beamstlist = 0;
1272                         f_p->subbeamstlist = 0;
1273                 }
1274                 f_p->used[BEAMSTLIST] = NO;
1275                 break;
1276         }
1277
1278         switch (i_p->used[BEAMSLOPE]) {
1279         case YES:
1280                 f_p->beamfact = i_p->beamfact;
1281                 f_p->beammax = i_p->beammax;
1282                 f_p->used[BEAMSLOPE] = YES;
1283                 break;
1284         case UNSET:
1285                 f_p->used[BEAMSLOPE] = NO;
1286                 break;
1287         }
1288
1289         SETPARM(pad, PAD)
1290
1291         SETPARM(stemlen, STEMLEN)
1292
1293         SETPARM(stemshorten, STEMSHORTEN)
1294
1295         SETPARM(defoct, DEFOCT)
1296
1297         switch (i_p->used[TIMEUNIT]) {
1298         case YES:
1299                 f_p->timeunit = i_p->timeunit;
1300                 f_p->timelist_p = i_p->timelist_p;
1301                 f_p->used[TIMEUNIT] = YES;
1302                 break;
1303         case UNSET:
1304                 f_p->used[TIMEUNIT] = NO;
1305         }
1306
1307         SETPARM(swingunit, SWINGUNIT)
1308
1309         SETPARM(release, RELEASE)
1310
1311         SETPARM(ontheline, ONTHELINE)
1312
1313         SETPARM(tabwhitebox, TABWHITEBOX)
1314
1315         switch (i_p->used[NOTEHEADS]) {
1316         case YES:
1317                 for (n = 0; n < 7; n++) {
1318                         f_p->noteheads[n] = i_p->noteheads[n];
1319                 }
1320                 f_p->used[NOTEHEADS] = YES;
1321                 break;
1322         case UNSET:
1323                 f_p->used[NOTEHEADS] = NO;
1324                 break;
1325         }
1326 }
1327 \f
1328 /*
1329  * Name:        setssvstate()
1330  *
1331  * Abstract:    Set the static SSVs to the state for a given place in the MML.
1332  *
1333  * Returns:     void
1334  *
1335  * Description: This function, given any structure from the main linked list,
1336  *              initializes the static SSVs, and then runs through the MLL up
1337  *              to just before that point, assigning SSVs.  It assigns not only
1338  *              the SSVs in the MLL, but also the timed SSVs hanging off
1339  *              barlines.  You can pass a null pointer, and then it will go
1340  *              through the whole MLL.
1341  */
1342
1343 void
1344 setssvstate(mainll_p)
1345
1346 struct MAINLL *mainll_p;        /* place in the MLL to stop */
1347
1348 {
1349         struct MAINLL *mll_p;           /* for looping through MLL */
1350         struct TIMEDSSV *tssv_p;        /* for looping through TIMEDSSV lists*/
1351
1352
1353         initstructs();
1354         for (mll_p = Mainllhc_p; mll_p != 0 && mll_p != mainll_p;
1355                         mll_p = mll_p->next) {
1356                 switch (mll_p->str) {
1357                 case S_SSV:
1358                         /* assign this normal input SSV */
1359                         asgnssv(mll_p->u.ssv_p);
1360                         break;
1361                 case S_BAR:
1362                         /* assign each timed SSV, if any */
1363                         for (tssv_p = mll_p->u.bar_p->timedssv_p; tssv_p != 0;
1364                                         tssv_p = tssv_p->next) {
1365                                 asgnssv(&tssv_p->ssv);
1366                         }
1367                         break;
1368                 }
1369         }
1370 }
1371 \f
1372 /*
1373  * Name:        setorder()
1374  *
1375  * Abstract:    Assign an "order" field from an input SSV to a fixed one.
1376  *
1377  * Returns:     void
1378  *
1379  * Description: This function is called by asgnssv() to assign to the
1380  *              appropriate part of the markorder array, based on above, below,
1381  *              or between.
1382  */
1383
1384 static void
1385 setorder(place, i_p, f_p)
1386
1387 int place;              /* PL_* */
1388 struct SSV *i_p;        /* input SSV structure to be copied from */
1389 struct SSV *f_p;        /* ptr to fixed SSV structure to copy into */
1390
1391 {
1392         int m;          /* mark (MK_*) */
1393         int stk;        /* stacking order */
1394
1395
1396         /*
1397          * First assign all the marks' stacking orders as given.  Keep track of
1398          * the highest stacking order number found.
1399          */
1400         stk = 0;
1401         for (m = 0; m < NUM_MARK; m++) {
1402                 f_p->markorder[place][m] = i_p->markorder[place][m];
1403
1404                 if (f_p->markorder[place][m] > stk)
1405                         stk = f_p->markorder[place][m];
1406         }
1407
1408         /*
1409          * For every mark type that the user didn't list, the stacking order is
1410          * now 0.  Set all these to default settings, higher than all the ones
1411          * the user listed, but in the same order as Defmarkorder.  They will
1412          * all be separate numbers, none set equal, unlike Defmarkorder, where
1413          * some are equal.
1414          */
1415         for (m = 0; m < NUM_MARK; m++) {
1416                 if (f_p->markorder[place][m] == 0) {
1417                         f_p->markorder[place][m] = ++stk;
1418                 }
1419         }
1420 }