subs.h - abc2ps - A powerful sheet setting tool using the simple abc notation
 (HTM) git clone git://vernunftzentrum.de/abc2ps.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       subs.h (37054B)
       ---
            1 /*  
            2  *  This file is part of abc2ps, 
            3  *  Copyright (C) 1996,1997,1998  Michael Methfessel
            4  *  See file abc2ps.c for details.
            5  */
            6 
            7 /*  miscellaneous subroutines  */
            8 
            9 /* ----- write_help ----- */
           10 void write_help ()
           11 {
           12 
           13   printf ("abc2ps v%s.%s (%s, %s) compiled %s\n", 
           14           VERSION, REVISION, VDATE, STYLE, __DATE__);
           15 
           16   printf ("Usage: abc2ps files..  [-e nums-or-pats] [other flags]\n"
           17           "  - show index of abc files or typeset tunes in Postscript.\n"
           18           "where: files   input files in abc format\n"
           19           "       nums    tune xref numbers, i.e. 1 3 6-7,20-\n"
           20           "       pats    patterns for title search\n" 
           21           "Tunes are selected if they match a number or a pattern.\n"
           22           "Flags: -o      write output for selected tunes\n"
           23           "       -E      produce EPSF output, one tune per file\n"
           24           "       -O aa   set outfile name to aaa\n"
           25           "       -O =    make outfile name from infile/title\n" 
           26           "       -i      run in interactive mode\n"
           27           "       -v nn   set verbosity level to nn\n"
           28           "       -h      show this command summary\n"
           29           "  Selection:\n"
           30           "       -e      following arguments are selectors\n"
           31           "       -f      following arguments are file names\n"
           32           "       -T      search  Title   field (default)\n"
           33           "       -C      search Composer field instead of title\n"
           34           "       -R      search  Rhythm  field instead of title\n"
           35           "       -S      search  Source  field instead of title\n"
           36           "       -V str  select voices, eg. -V 1,4-5\n"
           37           "  Formatting:\n"
           38           "       -H      show the format parameters\n"
           39           "       -p      pretty output (looks better, needs more space)\n"
           40           "       -P      select second predefined pretty output style\n"
           41           "       -s xx   set scale factor for symbol size to xx\n" 
           42           "       -w xx   set staff width (cm/in/pt)\n"
           43           "       -m xx   set left margin (cm/in/pt)\n"
           44           "       -d xx   set staff separation (cm/in/pt)\n"
           45           "       -x      include xref numbers in output\n"
           46           "       -k nn   number every nn bars; 0 for first in staff\n"
           47           "       -n      include notes and history in output\n"
           48           "       -N      write page numbers\n"
           49           "       -I      write index to Ind.ps\n"
           50           "       -1      write one tune per page\n"
           51           "       -l      landscape mode\n"
           52           "       -g xx   set glue mode to shrink|space|stretch|fill\n"
           53           "       -F foo  read format from \"foo.fmt\"\n"
           54           "       -D bar  look for format files in directory \"bar\"\n"
           55           "       -X x    set strictness for note spacing, 0<x<1 \n"
           56           "  Transposing:\n"
           57           "       -t n    transpose by n halftones (_n for negative number)\n"
           58           "       -t XX   transpose root up/down to note XX (eg. C A# ^Bb _Bb)\n"
           59           "  Line breaks:\n"
           60           "       -a xx   set max shrinkage to xx (between 0 and 1)\n"
           61           "       -b      break at all line ends (ignore continuations)\n"
           62           "       -c      continue all line ends (append '\\')\n"
           63           "       -B bb   put line break every bb bars\n"
           64           "  Alloc options:\n"
           65           "     -maxs n   set maximal number of symbols (default %d)\n"
           66           "     -maxv n   set maximal number of voices (default %d)\n"
           67           , maxSyms, maxVc);
           68 }
           69 
           70 
           71 /* ----- write_version ----- */
           72 void write_version ()
           73 {
           74 
           75 /*  printf ("abc2ps v%s (%s, %s) compiled %s\n", 
           76           VERSION, VDATE, STYLE, __DATE__); */
           77 
           78   printf ("abc2ps v%s.%s (%s, %s) compiled %s\n", 
           79           VERSION, REVISION, VDATE, STYLE, __DATE__);
           80   
           81   if (strlen(DEFAULT_FDIR)>0) 
           82     printf ("Default format directory %s\n", DEFAULT_FDIR);
           83   
           84 }
           85 
           86 /* ----- is_xrefstr: check if string ok for xref selection ---- */
           87 int is_xrefstr (str)
           88 char str[];
           89 {
           90   
           91   char *c;
           92   c=str;
           93   while (*c != '\0') {
           94     if ((!isdig(*c)) && (*c!='-') && (*c!=',') && (*c!=' ')) return 0;
           95     c++;
           96   }
           97   return 1;
           98 }
           99 
          100 
          101 /* ----- make_arglist: splits one string into list or arguments ---- */
          102 int make_arglist (str, av)
          103 char str[];
          104 char *av[];
          105 {
          106   char *q;
          107   int n;
          108   
          109   q=str;
          110   n=1;                     /* first real arg is 1, as in argv */
          111   for (;;) {
          112     while (*q==' ') q++;
          113     if (*q=='\0') break;
          114     av[n]=q;
          115     n++;
          116     while ((*q!=' ') && (*q!='\0')) q++;
          117     if (*q=='\0') break;
          118     *q='\0';
          119     q++;
          120   }
          121   return n;
          122 }
          123 
          124 
          125 /* ----- init_ops ----- */
          126 void init_ops (job)
          127 int job;
          128 {
          129 
          130   one_per_page         = -1;
          131   landscape            = -1;
          132   scalefac             = -1.0;
          133   lmargin              = -1.0;
          134   swidth               = -1.0;
          135   write_history        = -1;
          136   staffsep             = -1;
          137   dstaffsep            =  0;
          138   break_continues      = -1;
          139   continue_lines       = -1;
          140   include_xrefs        = -1;
          141   alfa_c               = -1.0;
          142   strict1              = -1.0;
          143   strict2              = -1.0;
          144   barnums              = -1;
          145   make_index           =  0;
          146 
          147   select_all           = 0;
          148   do_mode              = DO_INDEX;
          149   pagenumbers          = 0;
          150   strcpy (styf, "");
          151   strcpy (transpose, "");
          152   strcpy (vcselstr, "");
          153 
          154   if (job) {
          155     strcpy (styd, DEFAULT_FDIR);
          156     strcpy (outf, OUTPUTFILE);
          157     interactive          = 0;
          158     pretty               = 0;
          159     epsf                 = 0;
          160     choose_outname       = 0;
          161     gmode                = G_FILL;
          162     vb                   = VERBOSE0;
          163     search_field0        = S_TITLE;
          164   }
          165 }
          166 
          167 
          168 /* ----- ops_into_fmt ----- */
          169 void ops_into_fmt (fmt)
          170 struct FORMAT *fmt;
          171 {
          172   if (landscape >= 0)        fmt->landscape=landscape;
          173   if (scalefac >= 0)         fmt->scale=scalefac;
          174   if (lmargin >= 0)          fmt->leftmargin=lmargin;
          175   if (swidth >= 0)           fmt->staffwidth=swidth;
          176   if (continue_lines >= 0)   fmt->continueall=continue_lines;
          177   if (break_continues >= 0)  fmt->breakall=break_continues;
          178   if (write_history >= 0)    fmt->writehistory=write_history;
          179   if (bars_per_line > 0)     fmt->barsperstaff=bars_per_line;
          180   if (include_xrefs >= 0)    fmt->withxrefs=include_xrefs;
          181   if (one_per_page >= 0)     fmt->oneperpage=one_per_page;
          182   if (alfa_c >= 0)           fmt->maxshrink=alfa_c;
          183   if (staffsep >= 0)         fmt->staffsep=staffsep;
          184   if (strict1 >= 0)          fmt->strict1=strict1;
          185   if (strict2 >= 0)          fmt->strict2=strict2;
          186   if (barnums >= 0)          fmt->barnums=barnums;
          187   fmt->staffsep    = fmt->staffsep    + dstaffsep;
          188   fmt->sysstaffsep = fmt->sysstaffsep + dstaffsep;
          189 
          190 }
          191 
          192 
          193 /* ----- parse_args: parse list of arguments, interpret flags ----- */
          194 int parse_args (ac, av)
          195 int ac;
          196 char *av[];
          197 {
          198   int i,m,k,nsel,sel_arg,j,ok,f_pos,got_value;
          199   char c,aaa[201],ext[41];
          200 
          201   help_me=0;
          202   ninf=0;
          203   nsel=0;
          204   sel_arg=0;
          205   f_pos=-1;
          206   strcpy (sel_str[0], "");
          207   s_field[0]=search_field0;
          208 
          209   i=1;
          210   while (i<ac) {
          211 
          212     if (av[i][0]=='+') {        /* switch off flags with '+' */
          213       m=1;
          214       k=strlen(av[i]);
          215       while (m<k) {
          216         c=av[i][m];
          217         if      (c=='b')  break_continues=0; 
          218         else if (c=='c')  continue_lines=0;
          219         else if (c=='x')  include_xrefs=0;
          220         else if (c=='1')  one_per_page=0;
          221         else if (c=='B')  bars_per_line=0;
          222         else if (c=='i')  interactive=0;
          223         else if (c=='n')  write_history=0;
          224         else if (c=='l')  landscape=0;
          225         else if (c=='p')  pretty=0;
          226         else if (c=='E')  epsf=0;
          227         else if (c=='F')  strcpy (styf, "");
          228         else if (c=='N')  pagenumbers=0;
          229         else if (c=='O')  { choose_outname=0; strcpy (outf, OUTPUTFILE); }
          230         else {
          231           printf ("+++ Cannot switch off flag: +%c\n", c);
          232           return 1; 
          233         }
          234         m++;
          235       }
          236     }
          237     
          238     else if (av[i][0]=='-') {         /* interpret a flag with '-'*/
          239       
          240                                       /* identify fullword options first */
          241       if (!strcmp(av[i],"-maxv")) {
          242         if ((i==ac-1)||(av[i+1][0]=='-')) rx("missing parameter for ",av[i]);
          243         sscanf(av[++i],"%d",&maxVc);
          244       }
          245       else if (!strcmp(av[i],"-maxs")) {
          246         if ((i==ac-1)||(av[i+1][0]=='-')) rx("missing parameter for ",av[i]);
          247         sscanf(av[++i],"%d",&maxSyms);
          248       }
          249       
          250       else {
          251         m=1;
          252         k=strlen(av[i]);
          253         while (m<k) {
          254           c=av[i][m];
          255           if      (c=='h')  help_me=1;                 /* simple flags */
          256           else if (c=='H')  help_me=2;     
          257           else if (c=='e')  sel_arg=1;
          258           else if (c=='f')  {
          259             nsel++;
          260             strcpy (sel_str[nsel], "");
          261             if (ninf==0) {                /* selector before first file */
          262               strcpy(sel_str[nsel],sel_str[nsel-1]);
          263               s_field[nsel]=s_field[nsel-1];
          264             }
          265             s_field[nsel]=search_field0;
          266             sel_arg=0;
          267             f_pos=i;
          268           }
          269           else if (c=='b')  {break_continues=1; continue_lines=0;}
          270           else if (c=='c')  {continue_lines=1; break_continues=0;}
          271           else if (c=='x')  include_xrefs=1;
          272           else if (c=='1')  one_per_page=1;
          273           else if (c=='i')  interactive=1;
          274           else if (c=='n')  write_history=1;
          275           else if (c=='l')  landscape=1;
          276           else if (c=='p')  pretty=1;
          277           else if (c=='P')  pretty=2;
          278           else if (c=='E')  epsf=1;
          279           else if (c=='o')  do_mode=DO_OUTPUT;
          280           else if (c=='N')  pagenumbers=1;
          281           else if (c=='I')  make_index=1;
          282           else if (strchr("TCRS",c)) {           
          283             if (c=='T') s_field[nsel]=S_TITLE; 
          284             if (c=='C') s_field[nsel]=S_COMPOSER;
          285             if (c=='R') s_field[nsel]=S_RHYTHM; 
          286             if (c=='S') s_field[nsel]=S_SOURCE; 
          287             sel_arg=1; 
          288           }
          289           
          290           else if (strchr("vsdwmgtkDFYBVXaO",c)) {  /* flags with parameter.. */
          291             strcpy (aaa, &av[i][m+1]);
          292             if ((strlen(aaa)>0) && strchr("glO",c)) {     /* no sticky arg */
          293               printf ("+++ Incorrect usage of flag -%c\n", c);
          294               return 1; 
          295             }
          296             
          297             got_value=1;                              /* check for value */
          298             if (strlen(aaa)==0) {
          299               got_value=0;
          300               i++; 
          301               if ((i>=ac) || (av[i][0]=='-')) 
          302                 i--;
          303               else {
          304                 strcpy (aaa,av[i]);
          305                 got_value=1;
          306               }
          307             }
          308             
          309             if (got_value && strchr("vskYB",c)) {      /* check num args */
          310               ok=1;
          311               for (j=0;j<strlen(aaa);j++)
          312                 if (!strchr("0123456789.",aaa[j])) ok=0;
          313               if (!ok) {
          314                 printf ("+++ Invalid parameter <%s> for flag -%c\n",aaa,c);
          315                 return 1;
          316               }
          317             }
          318             
          319             /* --- next ops require a value --- */
          320 
          321             if (!got_value) {                   /* check value was given */
          322               printf ("+++ Missing parameter after flag -%c\n", c);
          323               return 1; 
          324             }
          325 
          326             if (c=='k') {
          327               sscanf(aaa,"%d",&barnums); 
          328               break;
          329             }
          330             
          331             if (c=='V') {                               /* -V flag */
          332               ok=1;
          333               strcpy (vcselstr, aaa);
          334             }
          335             
          336             if (c=='X') {                               /* -X flag */
          337               ok=1;
          338               if (aaa[0]==',') {
          339                 sscanf(aaa,",%f",&strict2);
          340                 if (strict2<-0.001 || strict2>1.001) ok=0;
          341               }            
          342               else if (strchr(aaa,',')) {
          343                 sscanf (aaa,"%f,%f",&strict1,&strict2);
          344                 if (strict1<-0.001 || strict1>1.001) ok=0;
          345                 if (strict2<-0.001 || strict2>1.001) ok=0;
          346               }
          347               else {
          348                 sscanf(aaa,"%f",&strict1);
          349                 if (strict1<-0.001 || strict1>1.001) ok=0;
          350                 strict2=strict1;
          351               }
          352               if (!ok) {
          353                 printf ("+++ Invalid parameter <%s> for flag -%c\n",aaa,c);
          354                 return 1;
          355               }
          356             }
          357             
          358             if (c=='O') {                               /* -O flag  */
          359               if (!strcmp(aaa,"=")) {
          360                 choose_outname=1;
          361               }
          362               else {
          363                 getext (aaa,ext);
          364                 if (strcmp(ext,"ps") && strcmp(ext,"eps") && strcmp(ext,"")) {
          365                   printf ("Wrong extension for output file: %s\n", aaa);
          366                   return 1;
          367                 }
          368                 strext (outf, aaa, "ps", 1);
          369                 choose_outname=0;
          370               }
          371             }
          372             
          373             if (c=='a') {              
          374               sscanf (aaa, "%f", &alfa_c);
          375               if ((alfa_c>1.05)||(alfa_c<-0.01)) {
          376                 printf ("+++ Bad parameter for flag -a: %s\n",aaa);
          377                 return 1;
          378               }
          379             }
          380             
          381             if (c=='B') {
          382               sscanf(aaa,"%d",&bars_per_line); 
          383               continue_lines=0;
          384             }
          385             if (c=='t') strcpy(transpose,aaa);
          386             if (c=='v') sscanf(aaa,"%d",&vb); 
          387             if (c=='s') sscanf(aaa,"%f",&scalefac);
          388             if (c=='d') {
          389               if (aaa[0]=='+' || aaa[0]=='-') dstaffsep = scan_u(aaa);
          390               else staffsep = scan_u(aaa);
          391             }
          392             if (c=='w') swidth   = scan_u(aaa);
          393             if (c=='m') lmargin  = scan_u(aaa);
          394             if (c=='F') strcpy(styf,aaa);
          395             if (c=='D') strcpy (styd,aaa);
          396             if (c=='g') {
          397               if      (abbrev(aaa,"shrink", 2)) gmode=G_SHRINK;
          398               else if (abbrev(aaa,"stretch",2)) gmode=G_STRETCH;
          399               else if (abbrev(aaa,"space",  2)) gmode=G_SPACE;
          400               else if (abbrev(aaa,"fill",   2)) gmode=G_FILL;
          401               else {
          402                 printf ("+++ Bad parameter for flag -g: %s\n",aaa);
          403                 return 1;
          404               }
          405             }
          406             break; 
          407           }
          408           else {
          409             printf ("+++ Unknown flag: -%c\n", c);
          410             return 1;
          411           }
          412           m++;
          413         }
          414       }
          415     }
          416 
          417     else {
          418       if (strstr(av[i],".fmt")) {     /* implict -F */ 
          419         strcpy(styf, av[i]);
          420       }
          421       else {
          422         if (strstr(av[i],".abc") && sel_arg) {     /* file if .abc */
          423           nsel++;
          424           strcpy (sel_str[nsel], "");
          425           s_field[nsel]=S_TITLE;
          426           if (ninf==0) {                /* selector before first file */
          427             strcpy(sel_str[nsel],sel_str[nsel-1]);
          428             s_field[nsel]=s_field[nsel-1];
          429         }
          430           sel_arg=0;
          431         }
          432         if (is_xrefstr(av[i]) && (!sel_arg)) {    /* sel if xref numbers */
          433           if (i-1 != f_pos) sel_arg=1;
          434         }
          435         
          436         if (!sel_arg) {             /* this arg is a file name */
          437           if (ninf>=MAXINF) {
          438             printf ("+++ Too many input files, max is %d\n", MAXINF);
          439             return 1;
          440           }
          441           strcpy (in_file[ninf], av[i]); 
          442           psel[ninf]=nsel;
          443           ninf++;
          444         }
          445         else {                             /* this arg is a selector */
          446           strcat(sel_str[nsel], av[i]);
          447           strcat(sel_str[nsel], " ");
          448         }
          449       }
          450     }
          451     i++;
          452   }
          453   
          454   return 0;
          455 }
          456 
          457 /* ----- alloc_structs ----- */
          458 /* Thanks to Henrik Norbeck for this */
          459 void alloc_structs ()
          460 {
          461   int j;
          462 
          463   sym = (struct SYMBOL *)calloc(maxSyms, sizeof(struct SYMBOL));
          464   if (sym==NULL) rx("Out of memory","");
          465 
          466   symv = (struct SYMBOL **)calloc(maxVc, sizeof(struct SYMBOL *));
          467   if (symv==NULL) rx("Out of memory","");
          468 
          469   for (j=0;j<maxVc;j++) {
          470     symv[j] = (struct SYMBOL *)calloc(maxSyms, sizeof(struct SYMBOL));
          471     if (symv[j]==NULL) rx("Out of memory","");
          472   }
          473   
          474   xp = (struct XPOS *)calloc(maxSyms+1, sizeof(struct XPOS));
          475   if (xp==NULL) rx("Out of memory","");
          476   
          477   for (j=0;j<maxSyms+1;j++) {
          478     xp[j].p = (int *)calloc(maxVc, sizeof(int));
          479     if (xp[j].p==NULL) rx("Out of memory","");
          480   }
          481 
          482   voice=(struct VCESPEC *)calloc(maxVc, sizeof(struct VCESPEC));
          483   if (voice==NULL) rx("Out of memory","");
          484 
          485   sym_st = (struct SYMBOL **)calloc(maxVc, sizeof(struct SYMBOL *));
          486   if (sym_st==NULL) rx("Out of memory","");
          487   
          488   for (j=0;j<maxVc;j++) {
          489     sym_st[j] = (struct SYMBOL *)calloc(MAXSYMST, sizeof(struct SYMBOL));
          490     if (sym_st[j]==NULL) rx("Out of memory","");
          491   }
          492   
          493   nsym_st = (int *)calloc(maxVc, sizeof(int));
          494   if (nsym_st==NULL) rx("Out of memory","");
          495 
          496 }
          497 
          498 
          499 /* ----- set_page_format ----- */
          500 int set_page_format ()
          501 {
          502   int i,j;
          503   
          504   if (pretty==1)
          505     set_pretty_format (&cfmt);
          506   else if (pretty==2)
          507     set_pretty2_format (&cfmt);
          508   else 
          509     set_standard_format (&cfmt);
          510 
          511   i=read_fmt_file ("fonts.fmt", styd, &cfmt);
          512   j=0;
          513   if (strlen(styf)>0) {
          514     strext(styf,styf,"fmt",1);
          515     j=read_fmt_file (styf, styd, &cfmt);
          516     if (j==0)  {
          517       printf ("\n+++ Cannot open file: %s\n", styf);
          518       return 0;
          519     }
          520     strcpy(cfmt.name, styf);
          521   }
          522   if (i || j) printf("\n");
          523   ops_into_fmt (&cfmt);
          524 
          525   make_font_list (&cfmt);
          526   sfmt=cfmt;
          527   dfmt=cfmt;
          528   return 1;
          529 }
          530 
          531 
          532 /* ----- tex_str: change string to take care of some tex-style codes --- */
          533 /* Puts \ in front of ( and ) in case brackets are not balanced,
          534    interprets some TeX-type strings using ISOLatin1 encodings.
          535    Returns the length of the string as finally given out on paper. 
          536    Also returns an estimate of the string width... */
          537 int tex_str (str,s,wid)
          538 char *str;
          539 char s[];
          540 float *wid;
          541 {
          542   char *c;
          543   int base,add,n;
          544   char t[21];
          545   float w;
          546 
          547   c=str;
          548   strcpy(s,"");
          549   n=0;
          550   w=0;
          551   while (*c != '\0') {
          552 
          553     if ((*c=='(') || (*c==')'))           /* ( ) becomes \( \) */
          554       {sprintf(t, "\\%c", *c); strcat(s,t); w+=cwid('('); n++; }
          555 
          556     else if (*c=='\\') {                  /* backslash sequences */
          557       c++;
          558       if (*c=='\0') break;
          559       add=0;                              /* accented vowels */ 
          560       if (*c=='`')  add=1;    
          561       if (*c=='\'') add=2;
          562       if (*c=='^')  add=3;
          563       if (*c=='"')  add=4;
          564       if (add) {
          565         c++;
          566         base=0;
          567         if (*c=='a') { base=340; if (add==4) add=5; }
          568         if (*c=='e')   base=350;
          569         if (*c=='i')   base=354;
          570         if (*c=='o') { base=362; if (add==4) add=5; }
          571         if (*c=='u')   base=371;
          572         if (*c=='A') { base=300; if (add==4) add=5; }
          573         if (*c=='E')   base=310;
          574         if (*c=='I')   base=314;
          575         if (*c=='O') { base=322; if (add==4) add=5; }
          576         if (*c=='U')   base=331;
          577         w+=cwid(*c);
          578         if (base) 
          579           {sprintf(t,"\\%d",base+add-1); strcat(s,t); n+=1; }
          580         else
          581           {sprintf(t,"%c",*c); strcat(s,t); n+=1; }
          582       }
          583 
          584       else if (*c==' ')                               /* \-space */
          585         { strcat(s," "); w+=cwid(' '); n++; }  
          586 
          587       else if (*c=='O')                               /* O-slash */
          588         { strcat(s,"\\330"); w+=cwid('O'); n++; } 
          589 
          590       else if (*c=='o')                               /* o-slash */
          591         { strcat(s,"\\370"); w+=cwid('O'); n++; } 
          592       
          593       else if((*c=='s')&&(*(c+1)=='s'))               /* sz */
          594         { c++; strcat(s,"\\337"); w+=cwid('s'); n++; } 
          595       else if((*c=='a')&&(*(c+1)=='a'))               /* a-ring */
          596         { c++; strcat(s,"\\345"); w+=cwid('a'); n++; } 
          597       else if((*c=='A')&&(*(c+1)=='A'))               /* A-ring */
          598         { c++; strcat(s,"\\305"); w+=cwid('A'); n++; }  
          599       else if((*c=='a')&&(*(c+1)=='e'))               /* ae */
          600         { c++; strcat(s,"\\346"); w+=1.5*cwid('a'); n++; }  
          601       else if((*c=='A')&&(*(c+1)=='E'))               /* AE */
          602         { c++; strcat(s,"\\306"); w+=1.5*cwid('A'); n++; }  
          603 
          604 
          605       else if (*c=='c') {                           /* c-cedilla */ 
          606         c++;
          607         w+=cwid(*c);
          608         if      (*c=='C') { strcat(s,"\\307"); n++; }
          609         else if (*c=='c') { strcat(s,"\\347"); n++; }
          610         else              {sprintf(t,"%c",*c); strcat(s,t); n++; } 
          611       }
          612 
          613       else if (*c=='~') {                           /* n-twiddle */ 
          614         c++;
          615         w+=cwid(*c);
          616         if      (*c=='N') { strcat(s,"\\321"); n++; }
          617         else if (*c=='n') { strcat(s,"\\361"); n++; }
          618         else              { sprintf(t,"%c",*c); strcat(s,t); n++; } 
          619       }
          620       
          621       else                           /* \-something-else; pass through */
          622         {sprintf(t,"\\%c",*c); strcat(s,t); w+=cwid('A'); n++; }
          623     }
          624     
          625     else if (*c=='{')
          626       ;
          627     else if (*c=='}') 
          628       ;
          629 
          630     else                             /* other characters: pass though */
          631       { 
          632         sprintf(t,"%c",*c); 
          633         strcat(s,t); n++; 
          634         w+=cwid(*c);
          635       }
          636    
          637     c++;
          638   }
          639   *wid = w;
          640 
          641   return n;
          642 }
          643 
          644 
          645 /* ----- put_str: output a string in postscript ----- */
          646 void put_str (str)
          647 char *str;
          648 {
          649   char s[801];
          650   float w;
          651   
          652   tex_str (str,s,&w);
          653   PUT1 ("%s", s);
          654 }
          655 
          656 /* ----- set_font ----- */
          657 void set_font (fp,font,add_bracket)
          658 FILE *fp;
          659 struct FONTSPEC font;
          660 int add_bracket;
          661 {
          662   int i,fnum;
          663 
          664   fnum=-1;
          665   for (i=0;i<nfontnames;i++) {
          666     if (!strcmp(font.name,fontnames[i])) fnum=i; 
          667   }
          668   if (fnum<0) {
          669     printf ("\n+++ Font \"%s\" not predefined; using first in list\n",
          670             font.name); 
          671     fnum=0;
          672   }
          673   PUT3("%.1f %d F%d ", font.size, font.box, fnum)
          674   if (add_bracket) PUT0("(")
          675 }
          676 
          677 /* ----- set_font_str ----- */
          678 void set_font_str (str,font)
          679 char str[];
          680 struct FONTSPEC font;
          681 {
          682   int i,fnum;
          683 
          684   fnum=-1;
          685   for (i=0;i<nfontnames;i++) {
          686     if (!strcmp(font.name,fontnames[i])) fnum=i; 
          687   }
          688   sprintf (str,"%.1f %d F%d ", font.size, font.box, fnum);
          689 }
          690 
          691 
          692 /* ----- check_margin: do horizontal shift if needed ---- */
          693 void check_margin (new_posx)
          694 float new_posx;
          695 {
          696   float dif;
          697   
          698   dif=new_posx-posx;
          699   if (dif*dif<0.001) return;
          700 
          701   PUT1("%.2f 0 T\n", dif)
          702   posx=new_posx;
          703 }
          704 
          705 
          706 /* ----- epsf_title ------ */
          707 void epsf_title (title,fnm)
          708 char title[],fnm[];
          709 {
          710   char *p,*q;
          711 
          712   p=title; q=fnm;
          713   while (*p != '\0') {
          714     if (*p == ' ') 
          715       *q = '_';
          716     else
          717       *q = *p;
          718     p++; q++;
          719   }
          720   *q = '\0';
          721 }
          722 
          723 /* ----- close_output_file ------ */
          724 void close_output_file ()
          725 {
          726   int m;
          727 
          728   if (!file_open) return;
          729     
          730   if (interactive) printf ("(close %s)\n", outfnam);
          731 
          732   close_page(fout); 
          733   close_ps (fout);
          734   fclose (fout);
          735   if (tunenum==0) 
          736     printf ("+++ Warning: no tunes written to output file\n");
          737   m=get_file_size (outfnam);
          738   printf ("Output written on %s (%d page%s, %d title%s, %d byte%s)\n", 
          739           outfnam, 
          740           pagenum, pagenum==1 ? "" : "s", 
          741           tunenum, tunenum==1 ? "" : "s",
          742           m, m==1 ? "" : "s");
          743   file_open=0;
          744   file_initialized=0;
          745   
          746 }
          747 
          748 
          749 /* ----- open_output_file ------ */
          750 void open_output_file (fnam,tstr)
          751 char fnam[],tstr[];
          752 {
          753 
          754   if (!strcmp(fnam,outfnam)) return;
          755 
          756   if (file_open) close_output_file ();
          757   
          758   if (interactive) printf ("(open %s)\n", fnam);
          759   strcpy (outfnam, fnam);
          760   if ((fout = fopen (outfnam,"w")) == NULL) 
          761     rx ("Cannot open output file ", outf);
          762   pagenum=0;
          763   tunenum=tnum1=tnum2=0;
          764   file_open=1;
          765   file_initialized=0;
          766   
          767 }
          768 
          769 
          770 
          771 /* ----- open_index_file ------- */
          772 void open_index_file (fnam)
          773 char fnam[];
          774 {
          775   if (vb>=8) printf("Open index file \"%s\"\n", fnam);
          776   if ((findex = fopen (fnam,"w")) == NULL) 
          777     rx ("Cannot open index file: ", fnam);
          778 
          779   index_initialized=0;
          780   
          781 }
          782 
          783 /* ----- close_index_file ------- */
          784 void close_index_file ()
          785 {
          786   
          787   if (vb>=8) printf("Close index file\n");
          788 
          789   close_index_page (findex);
          790 
          791   fclose (findex);
          792 
          793 }
          794 
          795 /* ----- add_to_text_block ----- */
          796 void add_to_text_block (ln,add_final_nl)
          797 char ln[];
          798 int add_final_nl;
          799 {
          800   char *c,*a;
          801   char word[81];
          802   int nt,nl;
          803 
          804   nt=ntxt;
          805   c=ln;
          806 
          807   for (;;) {
          808     while (*c==' ') c++;
          809     if (*c=='\0') break;
          810     a=word;
          811     while ((*c!=' ')&&(*c!='\0')&&(*c!='\n')) {
          812       nl=0;
          813       if ((*c=='\\')&&(*(c+1)=='\\')) {
          814         nl=1;
          815         c+=2;
          816         break;
          817       }
          818       *a=*c;
          819       c++;
          820       a++;
          821 
          822     }
          823     *a='\0';
          824     if (strlen(word)>MAXWLEN) {
          825       word[MAXWLEN-1]='\0';
          826       printf ("+++ Insanely long word truncated to %d chars: %s\n", 
          827               MAXWLEN-1,word);
          828     }
          829     if (nt>=MAXNTEXT) {
          830       printf ("\n+++ Line %d: %s\n", linenum,ln);
          831       rx("Text overflow; increase MAXNTEXT and recompile.","");
          832     }
          833     if (strlen(word)>0) {
          834       strcpy(txt[nt],word);
          835       nt++;
          836     }
          837     if (nl) {
          838       strcpy(txt[nt],"$$NL$$");
          839       nt++;
          840     }
          841   }
          842   if (add_final_nl) {
          843     strcpy(txt[nt],"$$NL$$");
          844     nt++;
          845   }
          846   
          847   ntxt=nt;
          848 
          849 }
          850   
          851 
          852 /* ----- write_text_block ----- */
          853 void write_text_block (fp,job)
          854 FILE *fp;
          855 int  job;
          856 {
          857   int i,i1,i2,ntline,nc,mc,nbreak;
          858   float textwidth,ftline,ftline0,swfac,baseskip,parskip;
          859   float wwidth,wtot,spw;
          860   char str[81];
          861 
          862   if (ntxt<=0) return;
          863 
          864   baseskip = cfmt.textfont.size * cfmt.lineskipfac;
          865   parskip      = cfmt.textfont.size * cfmt.parskipfac;
          866   set_font_str (page_init,cfmt.textfont);
          867 
          868   /* estimate text widths.. ok for T-R, wild guess for other fonts */
          869   swfac=1.0;
          870   if (strstr(cfmt.textfont.name,"Times-Roman"))    swfac=1.00;
          871   if (strstr(cfmt.textfont.name,"Times-Bold"))     swfac=1.05;
          872   if (strstr(cfmt.textfont.name,"Helvetica"))      swfac=1.10;
          873   if (strstr(cfmt.textfont.name,"Helvetica-Bold")) swfac=1.15;
          874   if (strstr(cfmt.textfont.name,"Palatino"))       swfac=1.10;
          875   swfac=1.0;
          876   spw=cwid(' ');
          877   PUT1("/LF {0 %.1f rmoveto} bind def\n",-baseskip)
          878 
          879   /* output by pieces, separate at newline token */
          880   i1=0;
          881   while (i1<ntxt) {
          882     i2=-1;
          883     for (i=i1;i<ntxt;i++) if(!strcmp(txt[i],"$$NL$$")) {i2=i; break; }
          884     if (i2==-1) i2=ntxt;
          885     bskip(baseskip);
          886 
          887     if (job==OBEYLINES) {
          888       PUT0("0 0 M (")
          889       for (i=i1;i<i2;i++) {
          890         tex_str(txt[i],str,&wwidth);
          891         PUT1("%s ",str);
          892       }
          893       PUT0(") rshow\n")
          894     }
          895 
          896     else if (job==OBEYCENTER) {
          897       PUT1("%.1f 0 M (",cfmt.staffwidth/2)
          898       for (i=i1;i<i2;i++) {
          899         tex_str(txt[i],str,&wwidth);
          900         PUT1("%s",str)
          901         if (i<i2-1) PUT0(" ")
          902       }
          903       PUT0(") cshow\n")
          904     }
          905     
          906     else {
          907       PUT0("0 0 M mark\n")
          908       nc=0;
          909       mc=-1;
          910       wtot=-spw;
          911       for (i=i2-1;i>=i1;i--) {
          912         mc+=tex_str(txt[i],str,&wwidth)+1;
          913         wtot+=wwidth+spw;
          914         nc+=strlen(str)+2;
          915         if (nc>=72) {nc=0; PUT0("\n") }
          916         PUT1 ("(%s)",str);
          917       }
          918       if (job==RAGGED)
          919         PUT1(" %.1f P1\n",cfmt.staffwidth)
          920       else 
          921         PUT1(" %.1f P2\n",cfmt.staffwidth)
          922           /* first estimate: (total textwidth)/(available width) */
          923           textwidth=wtot*swfac*cfmt.textfont.size;
          924       if (strstr(cfmt.textfont.name,"Courier")) 
          925         textwidth=0.60*mc*cfmt.textfont.size;
          926       ftline0=textwidth/cfmt.staffwidth;
          927       /* revised estimate: assume some chars lost at each line end */
          928       nbreak=ftline0;
          929       textwidth=textwidth+5*nbreak*cwid('a')*swfac*cfmt.textfont.size;
          930       ftline=textwidth/cfmt.staffwidth;
          931       ntline=ftline+1.0;
          932       if (vb>=10)
          933         printf("first estimate %.2f, revised %.2f\n", ftline0,ftline);
          934       if (vb>=10) 
          935         printf("Output %d word%s, about %.2f lines (fac %.2f)\n",
          936                i2-i1, i2-i1==1?"":"s", ftline,swfac);
          937       bskip((ntline-1)*baseskip);
          938     }
          939 
          940     buffer_eob (fp);  
          941     /* next line to allow pagebreak after each text "line" */
          942     /* if (!epsf && !within_tune) write_buffer(fp); */
          943     i1=i2+1;
          944   }
          945   bskip(parskip);
          946   buffer_eob (fp); 
          947   /* next line to allow pagebreak after each paragraph */
          948   if (!epsf && !within_tune) write_buffer(fp);
          949   strcpy (page_init,"");
          950   return;
          951 }
          952 
          953 
          954 
          955 /* ----- put_words ------- */
          956 void put_words (fp)
          957 FILE *fp;
          958 {
          959   int i,nw,n;
          960   char str[81];
          961   char *p,*q;
          962   
          963   set_font (fp,cfmt.wordsfont, 0);
          964   set_font_str (page_init,cfmt.wordsfont);
          965 
          966   n=0;
          967   for (i=0;i<ntext;i++) if (text_type[i]==TEXT_W) n++;
          968   if (n==0) return;
          969   
          970   bskip(cfmt.wordsspace);
          971   for (i=0;i<ntext;i++) {
          972     if (text_type[i]==TEXT_W) {
          973       bskip(cfmt.lineskipfac*cfmt.wordsfont.size);
          974       p=&text[i][0];
          975       q=&str[0];
          976       if (isdig(text[i][0])) {
          977         while (*p != '\0') {
          978           *q=*p;
          979           q++;
          980           p++;
          981           if (*p==' ') break;
          982           if (*(p-1)==':') break;
          983           if (*(p-1)=='.') break;
          984         }
          985         if (*p==' ') p++;
          986       }
          987       *q='\0';
          988       
          989       /* permit page break at empty lines or stanza start */
          990       nw=nwords(text[i]);
          991       if ((nw==0) || (strlen(str)>0)) buffer_eob(fp);
          992       
          993       if (nw>0) {
          994         if (strlen(str)>0) {
          995           PUT0("45 0 M (")
          996           put_str (str);
          997           PUT0(") lshow\n")
          998         }
          999         if (strlen(p)>0) {
         1000           PUT0("50 0 M (")
         1001           put_str (p);
         1002           PUT0(") rshow\n")
         1003         }
         1004       }
         1005     }
         1006   }
         1007 
         1008   buffer_eob (fp);
         1009   strcpy (page_init,"");
         1010 
         1011 }
         1012 
         1013 /* ----- put_text ------- */
         1014 void put_text (fp, type, str)
         1015 FILE *fp;
         1016 int type;
         1017 char str[];
         1018 {
         1019   int i,n;
         1020   float baseskip,parskip;
         1021 
         1022   n=0;
         1023   for (i=0;i<ntext;i++) if (text_type[i]==type) n++;
         1024   if (n==0) return;
         1025 
         1026   baseskip = cfmt.textfont.size * cfmt.lineskipfac;
         1027   parskip  = cfmt.textfont.size * cfmt.parskipfac;
         1028   PUT0("0 0 M\n")
         1029   ntxt=0;
         1030   add_to_text_block(str,0);
         1031   for (i=0;i<ntext;i++) {
         1032     if (text_type[i]==type) add_to_text_block(text[i],1);
         1033   }
         1034   write_text_block (fp,RAGGED);
         1035   buffer_eob (fp); 
         1036 
         1037 }    
         1038 
         1039 /* ----- put_history ------- */
         1040 void put_history (fp)
         1041 FILE *fp;
         1042 {
         1043   int i,ok;
         1044   float baseskip,parskip;
         1045 
         1046   set_font (fp, cfmt.textfont,0);
         1047   set_font_str (page_init,cfmt.textfont);
         1048   baseskip = cfmt.textfont.size * cfmt.lineskipfac;
         1049   parskip  = cfmt.textfont.size * cfmt.parskipfac;
         1050 
         1051   bskip(cfmt.textspace);
         1052 
         1053   if (strlen(info.rhyth)>0) {
         1054     bskip(baseskip); 
         1055     PUT0("0 0 M (Rhythm: ")
         1056     put_str (info.rhyth);
         1057     PUT0(") show\n")
         1058     bskip(parskip);
         1059   }
         1060   
         1061   if (strlen(info.book)>0) {
         1062     bskip(0.5*CM); 
         1063     PUT0("0 0 M (Book: ")
         1064     put_str (info.book);
         1065     PUT0(") show\n")
         1066     bskip(parskip);
         1067   }
         1068 
         1069   if (strlen(info.src)>0) {
         1070     bskip(0.5*CM); 
         1071     PUT0("0 0 M (Source: ")
         1072     put_str (info.src);
         1073     PUT0(") show\n")
         1074     bskip(parskip);
         1075   }
         1076 
         1077   put_text (fp, TEXT_D, "Discography: ");
         1078   put_text (fp, TEXT_N, "Notes: ");
         1079   put_text (fp, TEXT_Z, "Transcription: ");
         1080   
         1081   ok=0;
         1082   for (i=0;i<ntext;i++) {
         1083     if (text_type[i]==TEXT_H) {
         1084       bskip(0.5*CM); 
         1085       PUT0("0 0 M (")
         1086       put_str (text[i]);
         1087       PUT0(") show\n")
         1088       ok=1;
         1089     }
         1090   }
         1091   if (ok) bskip(parskip);
         1092   buffer_eob (fp);
         1093   strcpy (page_init,"");
         1094 
         1095 }
         1096 
         1097 
         1098 /* ----- write_inside_title  ----- */
         1099 void write_inside_title (fp)
         1100 FILE *fp;
         1101 {
         1102   char t[201];
         1103 
         1104   if      (numtitle==1) strcpy (t,info.title);
         1105   else if (numtitle==2) strcpy (t,info.title2);
         1106   else if (numtitle==3) strcpy (t,info.title3);
         1107   if (vb>15) printf ("write inside title <%s>\n", t);
         1108   if (strlen(t)==0) return;
         1109 
         1110   bskip (cfmt.subtitlefont.size+0.2*CM);
         1111   set_font (fp, cfmt.subtitlefont, 0);
         1112 
         1113   if (cfmt.titlecaps) cap_str(t);
         1114   PUT0(" (")
         1115   put_str (t);
         1116   if (cfmt.titleleft) PUT0(") 0 0 M rshow\n")
         1117   else PUT1(") %.1f 0 M cshow\n", cfmt.staffwidth/2)  
         1118   bskip (cfmt.musicspace+0.2*CM);
         1119 
         1120 }  
         1121 
         1122 
         1123 /* ----- write_tunetop ----- */
         1124 void write_tunetop(fp)
         1125 FILE *fp;
         1126 {
         1127 
         1128   PUT2("\n\n%% --- tune %d %s\n", tunenum+1, info.title)
         1129   if (!epsf) bskip (cfmt.topspace);
         1130 }
         1131 
         1132 
         1133 /* ----- write_tempo ----- */
         1134 void write_tempo(fp,tempo,meter)
         1135 FILE *fp;
         1136 char tempo[];
         1137 struct METERSTR meter;
         1138 {
         1139   char *r, *q;
         1140   char text[STRL];
         1141   int top,bot,value,len,i,err,fac,dig,div,rc;
         1142   struct SYMBOL s;
         1143   float stem,dotx,doty,sc,dx;
         1144 
         1145   if (vb>15) printf ("write tempo <%s>\n", info.tempo);
         1146   r=tempo;
         1147   p0=tempo;
         1148   set_font (fp,cfmt.tempofont,0);
         1149   PUT0(" 18 0 M\n")
         1150 
         1151   for (;;) {
         1152 
         1153     while (*r==' ') r++;                    /* skip blanks */
         1154     if (*r=='\0') break;
         1155 
         1156     if (*r=='"') {                          /* write string */
         1157       r++;
         1158       q=text;
         1159       while (*r!='"' && *r!='\0') { *q=*r; r++; q++; }
         1160       if (*r=='"') r++;
         1161       *q='\0';
         1162       if (strlen(text)>0) {     
         1163         PUT0("6 0 rmoveto (")
         1164         put_str (text);
         1165         PUT0(") rshow 12 0 \n")
         1166       }
         1167     }
         1168 
         1169     else {                                  /* write tempo denotation */
         1170       q=text;
         1171       while (*r!=' ' && *r!='\0') { *q=*r; r++; q++; }
         1172       *q='\0';
         1173       q=text;
         1174 
         1175       len=QUARTER;
         1176       value=0;
         1177       err=0;
         1178       if (strchr(q,'=')) {
         1179         if ((*q=='C') || (*q=='c')) {
         1180           q++;
         1181 
         1182           len=meter.dlen;  
         1183           div=0;
         1184           if (*q=='/') { div=1; q++; }
         1185           fac=0;
         1186           while (isdig(*q)) { dig=*q-'0'; fac=10*fac+dig; q++; }
         1187 
         1188           if (div) {
         1189             if (fac==0) fac=2;
         1190             if (len%fac) printf ("Bad length divisor in tempo: %s", text);
         1191             len=len/fac;
         1192           }
         1193           else  
         1194             if (fac>0) len=len*fac;
         1195           if (*q!='=') err=1;
         1196           q++;
         1197           if (!isdig(*q)) err=1;
         1198           sscanf(q,"%d", &value);
         1199         }
         1200         else if (isdig(*q)) {
         1201           sscanf(q,"%d/%d=%d", &top,&bot,&value);
         1202           len=(BASE*top)/bot;
         1203         }
         1204         else err=1;
         1205       } 
         1206       else {
         1207         if (isdig(*q))
         1208           sscanf(q,"%d", &value);
         1209         else err=1;
         1210       }
         1211       
         1212       s.len=len;
         1213       rc = idfy_note (&s);
         1214       if (rc) err=1;
         1215       if (err)                              /* draw note=value */
         1216         printf("\n+++ invalid tempo specifier: %s\n", text);
         1217       else {
         1218         sc=0.55*cfmt.tempofont.size/10.0;
         1219         PUT2("gsave %.2f %.2f scale 15 3 rmoveto currentpoint\n", sc,sc)
         1220         if (s.head==H_OVAL)  PUT0("HD")
         1221         if (s.head==H_EMPTY) PUT0("Hd")
         1222         if (s.head==H_FULL)  PUT0("hd")
         1223         dx=4.0;
         1224         if (s.dots) {      
         1225           dotx=8; doty=0;
         1226           if (s.flags>0) dotx=dotx+4;
         1227           if (s.head==H_EMPTY) dotx=dotx+1;
         1228           if (s.head==H_OVAL)  dotx=dotx+2;
         1229           for (i=0;i<s.dots;i++) {
         1230             PUT2(" %.1f %.1f dt", dotx, doty)
         1231             dx=dotx;
         1232             dotx=dotx+3.5;
         1233           }
         1234         }
         1235         stem=16.0;
         1236         if (s.flags>1) stem=stem+3*(s.flags-1);
         1237         if (s.len<WHOLE) PUT1(" %.1f su",stem) 
         1238         if (s.flags>0) PUT2(" %.1f f%du",stem,s.flags)
         1239         if ((s.flags>0) && (dx<6.0)) dx=6.0;
         1240         dx=(dx+18)*sc;
         1241         PUT2(" grestore %.2f 0 rmoveto ( = %d) rshow\n", dx,value)
         1242       }
         1243     }
         1244   }
         1245 }
         1246 
         1247 
         1248 /* ----- write_inside_tempo  ----- */
         1249 void write_inside_tempo (fp)
         1250 FILE *fp;
         1251 {
         1252 
         1253   bskip (cfmt.partsfont.size);
         1254   write_tempo(fp,info.tempo,default_meter);
         1255   bskip (0.1*CM);
         1256 }
         1257 
         1258 /* ----- write_heading  ----- */
         1259 void write_heading (fp)
         1260 FILE *fp;
         1261 {
         1262   float lwidth,down1,down2;
         1263   int i,ncl;
         1264   char t[201];
         1265 
         1266   lwidth=cfmt.staffwidth;
         1267 
         1268   /* write the main title */
         1269   bskip (cfmt.titlefont.size+cfmt.titlespace);
         1270   set_font (fp,cfmt.titlefont,1);
         1271   if (cfmt.withxrefs) PUT1("%d. ", xrefnum)
         1272   strcpy (t,info.title);
         1273   if (cfmt.titlecaps) cap_str(t);
         1274   put_str (t);
         1275   if (cfmt.titleleft) PUT0(") 0 0 M rshow\n")
         1276   else PUT1(") %.1f 0 M cshow\n", lwidth/2)  
         1277 
         1278   /* write second title */
         1279   if (numtitle>=2) {
         1280     bskip (cfmt.subtitlespace+cfmt.subtitlefont.size);
         1281     set_font (fp,cfmt.subtitlefont,1);
         1282     strcpy (t,info.title2);
         1283     if (cfmt.titlecaps) cap_str(t);
         1284     put_str (t);
         1285     if (cfmt.titleleft) PUT0(") 0 0 M rshow\n")
         1286     else PUT1(") %.1f 0 M cshow\n", lwidth/2)  
         1287   }
         1288 
         1289   /* write third title */
         1290   if (numtitle>=3) {
         1291     bskip (cfmt.subtitlespace+cfmt.subtitlefont.size);
         1292     set_font (fp,cfmt.subtitlefont,1);
         1293     strcpy (t,info.title3);
         1294     if (cfmt.titlecaps) cap_str(t);
         1295     put_str (t);
         1296     if (cfmt.titleleft) PUT0(") 0 0 M rshow\n")
         1297     else PUT1(") %.1f 0 M cshow\n", lwidth/2)  
         1298   }
         1299 
         1300   /* write composer, origin */
         1301   if ((info.ncomp>0) || (strlen(info.orig)>0)) {
         1302     set_font (fp,cfmt.composerfont,0);
         1303     bskip(cfmt.composerspace);
         1304     ncl=info.ncomp;
         1305     if ((strlen(info.orig)>0) && (ncl<1)) ncl=1;
         1306     for (i=0;i<ncl;i++) {
         1307       bskip(cfmt.composerfont.size);
         1308       PUT1("%.1f 0 M (", lwidth)
         1309       put_str (info.comp[i]);
         1310       if ((i==ncl-1)&&(strlen(info.orig)>0)) {
         1311         put_str (" (");
         1312         put_str (info.orig);
         1313         put_str (")");
         1314       }
         1315       PUT0 (") lshow\n");
         1316     }
         1317     down1=cfmt.composerspace+cfmt.musicspace+ncl*cfmt.composerfont.size;
         1318   }
         1319   else {
         1320     bskip(cfmt.composerfont.size+cfmt.composerspace);
         1321     down1=cfmt.composerspace+cfmt.musicspace+cfmt.composerfont.size;
         1322   }
         1323   bskip (cfmt.musicspace);
         1324 
         1325   /* decide whether we need extra shift for parts and tempo */
         1326   down2=cfmt.composerspace+cfmt.musicspace;
         1327   if (strlen(info.parts)>0) down2=down2+cfmt.partsspace+cfmt.partsfont.size;
         1328   if (strlen(info.tempo)>0) down2=down2+cfmt.partsspace+cfmt.partsfont.size;
         1329   if (down2>down1) bskip (down2-down1);
         1330 
         1331   /* write tempo and parts */
         1332   if (strlen(info.parts)>0 || strlen(info.tempo)>0) {
         1333     
         1334     if (strlen(info.tempo)>0) {
         1335       bskip (-0.2*CM);
         1336       PUT1 (" %.2f 0 T ", cfmt.indent*cfmt.scale)
         1337       write_tempo(fp, info.tempo, default_meter);
         1338       PUT1 (" %.2f 0 T ", -cfmt.indent*cfmt.scale)
         1339       bskip (-cfmt.tempofont.size);
         1340     }
         1341     
         1342     if (strlen(info.parts)>0) {
         1343       bskip (-cfmt.partsspace);
         1344       set_font (fp,cfmt.partsfont,0);
         1345       PUT0("0 0 M (")
         1346       put_str (info.parts);
         1347       PUT0(") rshow\n")
         1348       bskip (cfmt.partsspace);
         1349     }
         1350 
         1351     if (strlen(info.tempo)>0) bskip (cfmt.tempofont.size+0.3*CM);
         1352     
         1353   }
         1354   
         1355 
         1356 }
         1357 
         1358 /* ----- write_parts  ----- */
         1359 void write_parts (fp)
         1360 FILE *fp;
         1361 {
         1362   if (strlen(info.parts)>0) {
         1363     bskip (cfmt.partsfont.size);
         1364     set_font (fp, cfmt.partsfont,0);
         1365     PUT0("0 0 M (")
         1366     put_str (info.parts);
         1367     PUT0(") rshow\n")
         1368     bskip(cfmt.partsspace);
         1369   }
         1370 }   
         1371 
         1372