home *** CD-ROM | disk | FTP | other *** search
- /*
- * options.c - Handles commandline options and selection of next module.
- *
- * (C) 1994 Mikael Nordqvist (d91mn@efd.lth.se, mech@df.lth.se)
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <time.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <limits.h>
-
- #include "mod.h"
-
- extern struct mod_info M;
- extern char workdir[PATH_MAX+1];
- extern struct mod_file *files;
- extern int nr_visible_voices;
-
- struct options opt, default_opt;
- int nr_songs; /* Nr of songs specified */
- short *songs; /* Starting pos in argv for the songs */
- short *song_sequence; /* Order of the songs (if played) */
-
- char **av; /* Local pointer to argv */
- int ac; /* Local copy of argc */
-
- char background=0, totallyQ=0;
-
-
- void init_options(int argc, char *argv[])
- {
- int fd;
- char *env;
- char buf[2048], *env_av[80]; /* Should be enough */
- int env_ac, env_pos, buf_pos;
-
- nr_songs=0;
-
- bzero((void *)&default_opt, sizeof(struct options));
- default_opt.max_lines=4711; /* As many as possible */
- default_opt.active_voices=-1; /* All voices active */
- default_opt.maxtime=0; /* No maxtime by default */
-
- default_opt.tempo=125; /* PAL-tempo */
- default_opt.speed=6;
-
- default_opt.speed0stop=1; /* PT3.0 compatability */
- default_opt.click_removal=0; /* Clickremoval off by default */
- default_opt.low_note=0; /* Let patternloader set these */
- default_opt.high_note=0;
-
- default_opt.loop_module=0; /* No forced looping by default */
- default_opt.break_loops=-1; /* Set to default if not specified */
- default_opt.auto_next=-1; /* Set to default if not specified */
-
- default_opt.voice_detail=0; /* Default to not changing it */
-
- /* Check validity and set the "always global" options. First check
- * the environment-variable, then the commandline.
- */
-
- /* Check environment */
- if((env=getenv(ENV_VAR_NAME))) {
- if(env[0]) {
- if(env[0] != '-')
- error("Environment-variable " ENV_VAR_NAME
- " must begin with a hyphen.\n");
- env_pos=env_ac=0;
- strcpy(buf, argv[0]);
- buf_pos=strlen(buf)+1;
-
- /* Build the argument-array */
- while(env[env_pos]) {
- env_av[++env_ac]=&buf[buf_pos];
- while(env[env_pos] && env[env_pos] != ' ' &&
- env[env_pos] != '\t')
- buf[buf_pos++]=env[env_pos++];
- buf[buf_pos++]=0;
-
- while(env[env_pos] && (env[env_pos] == ' ' ||
- env[env_pos] == '\t'))
- env_pos++;
- }
- av=env_av;
- ac=++env_ac;
- check_options(1); /* Parse, but abort at the first filename */
- opt=default_opt;
- parse_options(0);
- default_opt=opt;
- }
- }
-
- /* These must allocated before check_options(0) is called */
- songs=(short *)malloc(argc*sizeof(short));
- song_sequence=(short *)malloc(argc*sizeof(short));
-
- /* Check commandline */
- av=argv;
- ac=argc;
- check_options(0);
-
- if(background && default_opt.verbose)
- error("Can't put a verbose session in the background.\n");
-
- if(default_opt.quiet && default_opt.verbose)
- error("Quiet and verbose can't be used together.\n");
-
- opt=default_opt;
- parse_options(0);
- default_opt=opt;
-
- /* Turn on interactive mode if nothing else is specified */
- if(!default_opt.verbose && !default_opt.quiet)
- default_opt.interactive=1;
-
- /* Set defaults that depend on opt.play_list */
- if(nr_songs < 1) {
- default_opt.play_list=0;
- if(default_opt.break_loops < 0)
- default_opt.break_loops=0;
- if(default_opt.auto_next < 0)
- default_opt.auto_next=0;
- opt=default_opt;
- init_dir(workdir);
- }
- else {
- default_opt.play_list=1;
- if(default_opt.break_loops < 0)
- default_opt.break_loops=1;
- if(default_opt.auto_next < 0)
- default_opt.auto_next=1;
-
- opt=default_opt;
- init_playsequence();
- list_to_files();
- }
-
- if(default_opt.loop_module) /* Loop as composer intended */
- default_opt.break_loops=0;
-
- /* Rediect output if needed */
- if(totallyQ || background) {
- fd=open("/dev/null", O_RDWR, 0);
- dup2(fd, STDIN_FILENO);
- dup2(fd, STDOUT_FILENO);
- dup2(fd, STDERR_FILENO);
- close(fd);
- }
-
- /* Detach if needed */
- if(background) {
- switch(fork()) {
- case -1:
- error("fork() failed.\n");
- case 0:
- write_pid(getpid());
- break;
- default:
- exit(0);
- }
- }
- opt=default_opt;
- }
-
-
- void check_options(char no_files)
- {
- char next, tmp;
- char *s;
- int index=1;
-
- while(index < ac) {
- while(index < ac) {
- s=av[index];
- if(*s == '-') {
- s++;
- next=0;
- while(*s && !next) {
- switch(*s) {
- case 'a':
- default_opt.auto_next=1;
- break;
- case 'A':
- default_opt.auto_next=0;
- break;
- case 'b':
- default_opt.break_loops=1;
- break;
- case 'B':
- default_opt.break_loops=0;
- break;
- case 'C':
- default_opt.replay_forever=1;
- break;
- case '?':
- case 'h':
- print_helptext(av[0]);
- exit(0);
- break;
- case 'L':
- default_opt.loop_module=1;
- break;
- case 'n':
- default_opt.noscroll=1;
- break;
- case 'Q':
- totallyQ=1;
- /* Fall through to 'q' */
- case 'q':
- default_opt.quiet=1;
- break;
- case 'r':
- default_opt.random_mode=1;
- break;
- case 'v':
- default_opt.verbose++;
- break;
-
- case 'z':
- background=1;
- default_opt.quiet=1;
- break;
-
- case 'k':
- error("Option '-k' must be the only argument.\n");
- break;
-
- case 'M':
- case 'N':
- case 'o':
- case 'O':
- case 'P':
- case 'T':
- case '0':
- case '5':
- case '6':
- break;
-
- /* Parsed numerical arguments */
- case 'l':
- tmp=*s;
- if(!getarg(&s, &index))
- goto horrible_goto;
- next=1;
- default_opt.max_lines=MAX(atoi(s), 1);
- break;
- case 'x':
- tmp=*s;
- if(!getarg(&s, &index))
- goto horrible_goto;
- next=1;
- break;
-
- /* Parsed alphanumerical arguments */
- case 'D':
- tmp=*s;
- getarg(&s, &index);
- next=1;
- if(chdir(s))
- error("No such directory.\n");
- getcwd(workdir, PATH_MAX);
- break;
-
- /* Numerical arguments */
- case 'c':
- case 'm':
- case 'p':
- case 's':
- case 't':
- tmp=*s;
- if(!getarg(&s, &index)) {
- horrible_goto:
- error("%s: option -%c requires a (positive)"
- " numerical argument\n", av[0], tmp);
- }
- next=1;
- break;
-
- /* Alphanumerical arguments */
- case 'f':
- getarg(&s, &index);
- next=1;
- break;
-
- default:
- error("%s: Unknown option -- %c\n", av[0], *s);
- break;
- }
- s++;
- }
- index++;
- }
- else {
- if(no_files) /* Abort after a file is found if no_files */
- return;
-
- songs[nr_songs++]=index;
- index++;
- break;
- }
- }
- }
- }
-
-
- /* Parse options */
-
- void parse_options(int index)
- {
- char next;
- char *s;
-
- index++; /* Skip the filename */
-
- for(;;) {
- s=av[index];
- if(*s == '-') {
- s++;
- next=0;
- while(*s && !next) {
- switch(*s) {
-
- /* These needs no further processing */
-
- case 'a': case 'A': case 'b': case 'B':
- case 'C': case '?': case 'h': case 'L':
- case 'n': case 'q': case 'Q': case 'r': case 'v': case 'z':
- break;
-
- case 'D':
- case 'l':
- getarg(&s, &index);
- next=1;
- break;
-
- /* These take no arguments */
-
- case 'M':
- opt.mono=1;
- break;
- case 'N':
- opt.ntsc_samples=1;
- break;
- case 'o':
- opt.low_note=BASE_NOTE+3*12;
- opt.high_note=BASE_NOTE+6*12-1;
- break;
- case 'O':
- opt.low_note=BASE_NOTE+0*12;
- opt.high_note=BASE_NOTE+NR_OCTAVES*12-1;
- break;
- case 'P':
- opt.ntsc_samples=0;
- break;
- case 'T':
- opt.tolerant=1;
- break;
- case '0':
- opt.speed0stop=0;
- break;
- case '5':
- opt.tempo=125; /* 50 Hz (125 BPM) -> 2.000/100 s */
- opt.nobpm=1;
- break;
- case '6':
- opt.tempo=150; /* 60 Hz (150 BPM) -> 1.667/100 s */
- opt.nobpm=1;
- break;
-
- /* These take arguments */
-
- case 'c':
- getarg(&s, &index);
- next=1;
- opt.click_removal=atoi(s);
- break;
- case 'f':
- getarg(&s, &index);
- if(!strcmp(s, "mod"))
- opt.format=MODFORMAT_MOD;
- else if(!strcmp(s, "ult"))
- opt.format=MODFORMAT_ULT;
- else if(!strcmp(s, "mtm"))
- opt.format=MODFORMAT_MTM;
- else if(!strcmp(s, "s3m"))
- opt.format=MODFORMAT_S3M;
- else
- info("Unknown format '%s' specified, "
- "option ignored.\n", s);
- next=1;
- break;
- case 'm':
- getarg(&s, &index);
- next=1;
- opt.maxtime=MAX(atoi(s), 1);
- break;
- case 'p':
- getarg(&s, &index);
- next=1;
- opt.start_pos=MAX(atoi(s), 0);
- break;
- case 's':
- getarg(&s, &index);
- next=1;
- opt.speed=MAX(atoi(s), 1);
- break;
- case 't':
- getarg(&s, &index);
- next=1;
- opt.tempo=MIN(MAX(atoi(s), 32), 255);
- break;
- case 'x':
- getarg(&s, &index);
- next=1;
- opt.voice_detail=MAX(1, MIN(3, atoi(s)));
- break;
-
- default:
- error("Internal error (unknown option).\n");
- }
- s++;
- }
- index++;
- }
- else
- return; /* No more options */
- }
- error("Never reached\n");
- }
-
-
- /* This is rather pointless as we are about to exit() anyways... */
-
- void cleanup_options(void)
- {
- free(songs);
- free(song_sequence);
- }
-
-
- /* Sets *s to the start of the argument. Returns true if the first character
- * of the argument is a digit.
- */
- int getarg(char **s, int *index)
- {
- *s=*s+1;
- if(!**s) {
- *index=*index+1;
- if(*index >= ac)
- error("%s: Missing argument for option "
- "-- %c\n", av[0], *(*s-1));
- *s=av[*index];
- }
-
- return (**s >= '0' && **s <= '9');
- }
-
-
- /* Selects next module by parsing it's options and setting the filename */
-
- void get_module(int nr)
- {
- int idx;
-
- opt=default_opt;
- if(opt.play_list) {
- idx=songs[song_sequence[nr]];
- strcpy(M.real_filename, av[idx]); /* Set filename */
- parse_options(idx);
- }
- else {
- strcpy(M.real_filename, files[nr].name);
- }
- }
-
- /* Returns the filename with path removed (sequenced order). Used to
- * print current modulename on the screen.
- */
-
- char *get_modulename(int nr)
- {
- static char buf[PATH_MAX+1];
- int i;
-
- if(opt.play_list)
- strcpy(buf, av[songs[song_sequence[nr]]]);
- else
- strcpy(buf, files[nr].name);
-
- for(i=strlen(buf); i >= 0 && buf[i] != '/'; --i)
- ;
- return &buf[++i];
- }
-
- /* Returns a pointer to the full filename (real order) ONLY FOR play_list! */
-
- char *get_fullmodulename_ptr(int nr)
- {
- return av[songs[nr]];
- }
-
-
- void init_playsequence(void)
- {
- int i, j, n;
-
- for(i=0; i < nr_songs; ++i)
- song_sequence[i]=-1;
-
- for(i=0; i < nr_songs; ++i) {
- if(default_opt.random_mode) {
- n=rand()%(nr_songs-i);
- for(j=0; n >= 0; ++j)
- if(song_sequence[j] < 0)
- --n;
- song_sequence[--j]=i;
- }
- else {
- song_sequence[i]=i;
- }
- }
- }
-
-
- int fileidx_to_seqidx(int nr)
- {
- int i;
-
- if(opt.play_list) { /* song_sequence not used when there is no play_list */
- for(i=0; ; ++i) {
- if(song_sequence[i] == nr) {
- nr=i;
- break;
- }
- }
- }
- return nr;
- }
-
-
- int seqidx_to_fileidx(int nr)
- {
- return song_sequence[nr];
- }
-