1
2 /* makecsd utility - written by Istvan Varga, Mar 2003 */
3 /* updated jpff Feb 2011 */
4
5 #define VERSION "2.0"
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <errno.h>
11 #include <time.h>
12 #include <ctype.h>
13 #define MAXLICENCE (7)
14
15 static char *orcname = NULL, *sconame = NULL, *optname = NULL;
16 static char *midiname = NULL, *scorebin = NULL, *licence = NULL;
17 static int licencetype = -1;
18
19 static int nr_infiles = 0;
20 static int max_infiles = 0;
21 static char **infile_names = NULL;
22
23 static int output_is_stdout = 1;
24 static char *outflname = NULL;
25 static FILE *outfile = NULL;
26
27 static int tabstop_size = 0;
28
29 /* convert 6 bits of input and write to output file */
30 extern int encode_byte(FILE*, FILE*);
31 /* convert an entire input file */
32 extern void encode_file(char*, FILE*, int);
33 /* line width */
34 extern int maxlinepos;
35
setorchnam(char * s)36 static int setorchnam(char *s)
37 {
38 char *c;
39 if (orcname != NULL) return 0; /* orchestra name is already set */
40 if (strlen(s) < 5) return 0; /* name is too short */
41 c = s + (int) strlen(s);
42 /* check if extension is correct */
43 --c; if (*c != 'C' && *c != 'c') return 0;
44 --c; if (*c != 'R' && *c != 'r') return 0;
45 --c; if (*c != 'O' && *c != 'o') return 0;
46 --c; if (*c != '.') return 0;
47 /* set orchestra name and report success */
48 orcname = s;
49 return 1;
50 }
51
setscornam(char * s)52 static int setscornam(char *s)
53 {
54 char *c;
55 if (sconame != NULL) return 0; /* score name is already set */
56 if (strlen(s) < 5) return 0; /* name is too short */
57 c = s + (int) strlen(s);
58 /* check if extension is correct */
59 --c; if (*c != 'O' && *c != 'o') return 0;
60 --c; if (*c != 'C' && *c != 'c') return 0;
61 --c; if (*c != 'S' && *c != 's') return 0;
62 --c; if (*c != '.') return 0;
63 /* set score name and report success */
64 sconame = s;
65 return 1;
66 }
67
68 /* read a single character from orc/sco input file, with check for */
69 /* end of file and Unix/MS-DOS/Mac format files */
70
mygetc(FILE * f,int * end_of_file)71 static int mygetc(FILE *f, int *end_of_file)
72 {
73 int c;
74
75 if (*end_of_file) return (-1); /* end of file */
76 c = getc(f);
77 if (c == '\r') { /* deal with MS-DOS and Mac files */
78 c = getc(f);
79 if (c == EOF) {
80 *end_of_file = 1;
81 return '\n';
82 }
83 if (c != '\n') /* CR-only: Mac format */
84 ungetc(c, f);
85 return '\n';
86 }
87 if (c == EOF) {
88 *end_of_file = 1; /* end of file */
89 return (-1);
90 }
91 return c;
92 }
93
94 /* write a line to output file, with tab->space conversion if requested */
95
write_line(FILE * outfl,char * buf,int n)96 static void write_line(FILE *outfl, char *buf, int n)
97 {
98 int linepos = 0;
99 while (n--) {
100 if (tabstop_size && *buf == '\t') { /* expand tabs to spaces */
101 do {
102 putc(' ', outfl);
103 } while ((++linepos) % tabstop_size);
104 }
105 else {
106 if (*buf == '\n') linepos = -1; /* new line: reset line position */
107 putc((int) *buf, outfl);
108 linepos++;
109 }
110 buf++;
111 }
112 }
113
convert_txt_file(char * inflname,FILE * outfl)114 static void convert_txt_file(char *inflname, FILE *outfl)
115 {
116 FILE *infile;
117 char linebuf[16384];
118 int linepos = 0, c, frstline = 1;
119 int is_eof;
120
121 /* open file */
122 infile = fopen(inflname, "rb");
123 if (infile == NULL) {
124 fprintf(stderr, "makecsd: error opening input file %s: %s\n",
125 inflname, strerror(errno));
126 exit(-1);
127 }
128 is_eof = 0;
129 /* read entire file and copy to output */
130 while (!is_eof) {
131 /* read next non-empty line to buffer */
132 linepos = 0;
133 do {
134 c = mygetc(infile, &is_eof);
135 if (is_eof || c == '\n') {
136 /* end of line: remove any trailing white space */
137 while (linepos && isblank(linebuf[linepos - 1]))
138 linepos--;
139 linebuf[linepos++] = '\n';
140 if (is_eof || /* end of file */
141 (linepos > 1 && linebuf[linepos - 2] != '\n'))
142 break; /* or a new non-empty line */
143 }
144 else
145 linebuf[linepos++] = c;
146 } while (1);
147 if (is_eof) break; /* end of file */
148 /* at beginning of file: skip any leading empty lines */
149 if (frstline) {
150 int n = -1;
151 frstline = 0;
152 while (++n < linepos && linebuf[n] == '\n');
153 /* if there is anything to print */
154 if (n < linepos)
155 write_line(outfl, &(linebuf[n]), linepos - n);
156 }
157 else /* otherwise just print as it is */
158 write_line(outfl, &(linebuf[0]), linepos);
159 }
160 /* at end of file: skip any trailing empty lines */
161 while (linepos && linebuf[linepos - 1] == '\n')
162 linepos--;
163 linebuf[linepos++] = '\n';
164 /* and print last line */
165 write_line(outfl, &(linebuf[0]), linepos);
166 /* close input file */
167 fclose(infile); infile = NULL;
168 }
169
main(int argc,char ** argv)170 int main(int argc, char **argv)
171 {
172 int i, j;
173
174 /* parse command line options */
175 i = 0;
176 j = argc;
177 while (--j) {
178 i++;
179 if (!strcmp(argv[i], "-w")) { /* line width */
180 if (!(--j)) {
181 fprintf(stderr, "makecsd: missing option for -w\n");
182 exit(-1);
183 }
184 i++;
185 maxlinepos = (int) atoi(argv[i]);
186 if (maxlinepos < 20) maxlinepos = 20;
187 if (maxlinepos > 200) maxlinepos = 200;
188 }
189 else if (!strcmp(argv[i], "-o")) { /* output file name */
190 if (!(--j)) {
191 fprintf(stderr, "makecsd: missing option for -o\n");
192 exit(-1);
193 }
194 i++;
195 outflname = argv[i];
196 if (!strcmp(outflname, "-"))
197 output_is_stdout = 1;
198 else
199 output_is_stdout = 0;
200 }
201 else if (!strcmp(argv[i], "-t")) { /* tabstop size */
202 if (!(--j)) {
203 fprintf(stderr, "makecsd: missing option for -t\n");
204 exit(-1);
205 }
206 i++;
207 tabstop_size = (int) atoi(argv[i]);
208 if (tabstop_size < 0) tabstop_size = 0;
209 if (tabstop_size > 24) tabstop_size = 24;
210 }
211 else if (!strcmp(argv[i], "-f")) { /* options file name */
212 if (!(--j)) {
213 fprintf(stderr, "makecsd: missing option for -f\n");
214 exit(-1);
215 }
216 i++;
217 optname = argv[i];
218 }
219 else if (!strcmp(argv[i], "-m")) { /* options file name */
220 if (!(--j)) {
221 fprintf(stderr, "makecsd: missing option for -m\n");
222 exit(-1);
223 }
224 i++;
225 midiname = argv[i];
226 }
227 else if (!strcmp(argv[i], "-b")) { /* options file name */
228 if (!(--j)) {
229 fprintf(stderr, "makecsd: missing option for -b\n");
230 exit(-1);
231 }
232 i++;
233 scorebin = argv[i];
234 }
235 else if (!strcmp(argv[i], "-L")) { /* options file name */
236 if (!(--j)) {
237 fprintf(stderr, "makecsd: missing option for -L\n");
238 exit(-1);
239 }
240 i++;
241 licence = argv[i];
242 licencetype = 99;
243 }
244 else if (!strcmp(argv[i], "-l")) { /* options file name */
245 if (!(--j)) {
246 fprintf(stderr, "makecsd: missing option for -l\n");
247 exit(-1);
248 }
249 i++;
250 licencetype = atoi(argv[i]);
251 if (licencetype>MAXLICENCE || licencetype<0) licencetype = -1;
252 }
253 else { /* input file name */
254 if (*(argv[i]) == '-') {
255 fprintf(stderr, "makecsd: invalid option: %s\n", argv[i]);
256 exit(-1);
257 }
258 if (!(setorchnam(argv[i]) || setscornam(argv[i]))) {
259 /* if input is neither an orchestra, nor a score file, */
260 /* encode it as Base64 */
261 if (nr_infiles >= max_infiles) {
262 /* extend number of input files */
263 max_infiles = max_infiles + (max_infiles >> 2) + 16;
264 infile_names = (char**) realloc(infile_names,
265 sizeof(char*) * max_infiles);
266 if (infile_names == NULL) {
267 fprintf(stderr, "makecsd: not enough memory\n");
268 exit(-1);
269 }
270 }
271 infile_names[nr_infiles] = argv[i];
272 nr_infiles++;
273 }
274 }
275 }
276 if (!nr_infiles && (orcname == NULL && sconame == NULL)) {
277 /* print usage */
278 fprintf(stderr, "makecsd: no input files\n");
279 fprintf(stderr,
280 "usage: makecsd [OPTIONS ... ] infile1 [ infile2 [ ... ]]\n");
281 fprintf(stderr, "options:\n");
282 fprintf(stderr,
283 " -t <n> expand tabs to spaces using tabstop size ");
284 fprintf(stderr, "n (default: disabled)\n");
285 fprintf(stderr,
286 " -w <n> set Base64 line width to n (default: 72)\n");
287 fprintf(stderr,
288 " -f <fname> read CSD options from file 'fname'\n");
289 fprintf(stderr,
290 " -o <fname> output file name (default: stdout)\n");
291 /* **** NEW OPTIONS **** */
292 // fprintf(stderr,
293 // " -v[ba] x.y use version (before/after) x.y\n");
294 fprintf(stderr,
295 " -l int licence type (0-1)\n");
296 fprintf(stderr,
297 " -L fname licence file\n");
298 fprintf(stderr,
299 " -b <pname> program to process score'\n");
300 fprintf(stderr,
301 " -m <fname> MIDI file name\n");
302 exit(-1);
303 }
304 /* open output file */
305 if (!output_is_stdout) {
306 outfile = fopen(outflname, "w");
307 if (outfile == NULL) {
308 fprintf(stderr, "makecsd: error opening output file %s: %s\n",
309 outflname, strerror(errno));
310 exit(-1);
311 }
312 }
313 else
314 outfile = stdout;
315 /* create CSD file */
316 fprintf(outfile, "<CsoundSynthesizer>\n");
317 fprintf(outfile, ";;; this CSD file generated by makecsd v" VERSION "\n");
318 fprintf(outfile, "<CsOptions>\n");
319 fprintf(outfile, ";;; set command line options here\n");
320 /* CSD options */
321 for (i = 0; i < nr_infiles; i++) {
322 char *s = infile_names[i], *s0;
323 j = (int) strlen(s);
324 if (j < 4) continue;
325 /* check for MIDI file */
326 if (s[j - 1] != 'D' && s[j - 1] != 'd') continue;
327 if (s[j - 2] != 'I' && s[j - 2] != 'i') continue;
328 if (s[j - 3] != 'M' && s[j - 3] != 'm') continue;
329 if (s[j - 4] != '.') continue;
330 /* add to options if found */
331 /* strip any leading components from file name */
332 s0 = s; s = s0 + ((int) strlen(s0) - 1);
333 while (s >= s0 && *s != '/' && *s != '\\' && *s != ':') s--;
334 s++;
335 fprintf(outfile, "-F %s\n", s);
336 break;
337 }
338 if (optname != NULL) {
339 /* copy options file if specified */
340 convert_txt_file(optname, outfile);
341 /* hack: remove blank line from end of options */
342 fflush(outfile);
343 if (fseek(outfile, -1L, SEEK_END)<0) {
344 fprintf(stderr, "makecsd: seek failed\n");
345 exit(1);
346 }
347 }
348 else if (i >= nr_infiles) {
349 fprintf(outfile, "\n"); /* put blank line if there are no options */
350 }
351 fprintf(outfile, "</CsOptions>\n");
352 if (licencetype == 99) { /* Licence file */
353 fprintf(outfile, "<CsLicence>\n");
354 convert_txt_file(licence, outfile);
355 fprintf(outfile, "</CsLicence>\n");
356 }
357 else if (licencetype < MAXLICENCE) { /* precanned licence */
358 char buff[32];
359 time_t tt = time(NULL);
360 strftime(buff, 32, "<CsLicence>\nCopyright %Y: ", gmtime(&tt));
361 fprintf(outfile, "%s", buff);
362 switch (licencetype) {
363 default:
364 case 0:
365 fprintf(outfile, "All Rights Reserved\n");
366 break;
367 case 1:
368 fprintf(outfile, "Creative Commons "
369 "Attribution-NonCommercial-NoDerivatives\n"
370 "CC BY-NC-ND\n");
371 break;
372 case 2:
373 fprintf(outfile, "Creative Commons "
374 "Attribution-NonCommercial-ShareAlike\n"
375 "CC BY-NC-SA\n");
376 break;
377 case 3:
378 fprintf(outfile, "Creative Commons "
379 "Attribution-NonCommercial\n"
380 "CC BY-NC\n");
381 break;
382 case 4:
383 fprintf(outfile, "Creative Commons "
384 "Attribution-NoDerivatives\n"
385 "CC BY-ND\n");
386 break;
387 case 5:
388 fprintf(outfile, "Creative Commons "
389 "Attribution-ShareAlike\n"
390 "CC BY-SA\n");
391 break;
392 case 6:
393 fprintf(outfile, "Creative Commons "
394 "Attribution\n"
395 "CC BY\n");
396 break;
397 case 7:
398 fprintf(outfile, "Licenced under BSD\n");
399 break;
400 }
401 fprintf(outfile, "</CsLicence>\n");
402 }
403 /* orchestra */
404 if (orcname != NULL) {
405 fprintf(outfile, "<CsInstruments>\n");
406 convert_txt_file(orcname, outfile);
407 fprintf(outfile, "</CsInstruments>\n");
408 }
409 else {
410 fprintf(stderr, "makecsd: warning: no orchestra file\n");
411 }
412 /* score */
413 if (sconame != NULL) {
414 if (scorebin)
415 fprintf(outfile, "<CsScore bin=\"%s\">\n", scorebin);
416 else
417 fprintf(outfile, "<CsScore>\n");
418 convert_txt_file(sconame, outfile);
419 fprintf(outfile, "</CsScore>\n");
420 }
421 else {
422 fprintf(stderr, "makecsd: warning: no score file\n");
423 }
424 if (midiname != NULL) {
425 fprintf(outfile, "<CsMidifileB>\n");
426 encode_file(midiname, outfile, 1);
427 fprintf(outfile, "</CsMidifileB>\n");
428 }
429 /* Base64 encode any remaining input files */
430 for (i = 0; i < nr_infiles; i++)
431 encode_file(infile_names[i], outfile, 0);
432 /* end of CSD file */
433 fprintf(outfile, "</CsoundSynthesizer>\n\n");
434 /* close output file */
435 if (!output_is_stdout) {
436 fflush(outfile);
437 fclose(outfile);
438 }
439 free(infile_names);
440 return 0;
441 }
442
443