/* MikMod example player (c) 2003 Raphael Assenat -- see file AUTHORS for complete list. (c) 1999 Miodrag Vallat and others - see file AUTHORS for complete list. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*============================================================================== $Id: mconfig.c,v 1.8 2003/10/08 01:48:51 raph Exp $ Load/Save of config options. ==============================================================================*/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include "player.h" #include "mutilities.h" /* hope this will be enough... */ #define LINE_LEN 500 typedef struct { int id; char *label; } LABEL_CONV; typedef enum { OPT_DRIVER, #if LIBMIKMOD_VERSION >= 0x030107 OPT_DRV_OPTION, #endif OPT_STEREO, OPT_MODE_16BIT, OPT_FREQUENCY, OPT_INTERPOLATE, OPT_HQMIXER, OPT_SURROUND, OPT_REVERB, OPT_VOLUME, OPT_VOLRESTRICT, OPT_FADE, OPT_LOOP, OPT_PANNING, OPT_EXTSPD, OPT_PM_MODULE, OPT_PM_MULTI, OPT_PM_SHUFFLE, OPT_PM_RANDOM, OPT_EXIT_AFTER, OPT_CURIOUS, OPT_TOLERANT, OPT_XTERM, #ifdef ENABLE_COLOR_INTERFACE OPT_COLOR, #endif OPT_RENICE, OPT_STATUSBAR, OPT_S_CONFIG, OPT_S_PLAYLIST, OPT_PL_NAME, OPT_FULLPATHS, OPT_NONE } OPTION_ID; typedef struct { OPTION_ID id; char *label,*description; } OPTION; static LABEL_CONV renice_conv[]={ {RENICE_NONE,"RENICE_NONE"}, {RENICE_PRI, "RENICE_PRI"}, {RENICE_REAL,"RENICE_REAL"}, {-1,NULL} }; static OPTION options[]={ {OPT_DRIVER, "DRIVER", "# DRIVER = , nth driver for output, default: 0\n"}, #if LIBMIKMOD_VERSION >= 0x030107 {OPT_DRV_OPTION, "DRV_OPTIONS", "# DRV_OPTIONS = \"options\", the driver options, e.g. \"buffer=14,count=16\"\n" "# for the OSS-driver\n"}, #endif {OPT_STEREO, "STEREO", "# STEREO = Yes|No, stereo or mono output, default: stereo\n"}, {OPT_MODE_16BIT, "16BIT", "# 16BIT = Yes|No, 8 or 16 bit output, default: 16 bit\n"}, {OPT_FREQUENCY, "FREQUENCY", "# FREQUENCY = , mixing frequency, default: 44100 Hz\n"}, {OPT_INTERPOLATE, "INTERPOLATE", "# INTERPOLATE = Yes|No, use interpolate mixing, default: No\n"}, {OPT_HQMIXER, "HQMIXER", "# HQMIXER = Yes|No, use high-quality (but slow) software mixer, default: No\n"}, {OPT_SURROUND, "SURROUND", "# SURROUND = Yes|No, use surround mixing, default: No\n"}, {OPT_REVERB, "REVERB", "# REVERB = , set reverb amount (0-15), default:0 (none)\n"}, {OPT_VOLUME, "VOLUME", "# VOLUME = , volume from 0 (silence) to 100, default: 100\n"}, {OPT_VOLRESTRICT, "VOLRESTRICT", "# VOLRESTRICT = Yes|No, restrict volume of player to volume supplied by user,\n" " default: No\n"}, {OPT_FADE, "FADEOUT", "# FADEOUT = Yes|No, volume fade at the end of the module, default: No\n"}, {OPT_LOOP, "LOOP", "# LOOP = Yes|No, enable in-module loops, default: No\n"}, {OPT_PANNING, "PANNING", "# PANNING = Yes|No, process panning effects, default: Yes\n"}, {OPT_EXTSPD, "EXTSPD", "# EXTSPD = Yes|No, process Protracker extended speed effect, default: Yes\n"}, {OPT_PM_MODULE ,"PM_MODULE", "# PM_MODULE = Yes|No, Module repeats, default: No\n"}, {OPT_PM_MULTI ,"PM_MULTI", "# PM_MULTI = Yes|No, PlayList repeats, default: Yes\n"}, {OPT_PM_SHUFFLE ,"PM_SHUFFLE", "# PM_SHUFFLE = Yes|No, Shuffle list at start and if all entries are played,\n" "# default: No\n"}, {OPT_PM_RANDOM ,"PM_RANDOM", "# PM_RANDOM = Yes|No, PlayList in random order, default: No\n"}, {OPT_EXIT_AFTER, "EXIT_AFTER", "# EXIT_AFTER = Yes|No, exit mikmod after reaching the end of the playlist, default: No\n"}, {OPT_CURIOUS, "CURIOUS", "# CURIOUS = Yes|No, look for hidden patterns in module, default: No\n"}, {OPT_TOLERANT, "TOLERANT", "# TOLERANT = Yes|No, don't halt on file access errors, default: No\n"}, {OPT_XTERM, "XTERM", "# XTERM = Yes|No, Set the xterm window title, default: Yes\n"}, #ifdef ENABLE_COLOR_INTERFACE {OPT_COLOR, "COLOR", "# COLOR = Yes/No, Use color interface, default: Yes\n"}, #endif {OPT_RENICE, "RENICE", "# RENICE = RENICE_NONE (change nothing), RENICE_PRI (Renice to -20) or\n" "# RENICE_REAL (get realtime priority), default: RENICE_NONE\n" "# Note that RENICE_PRI is only available under FreeBSD, Linux, NetBSD,\n" "# OpenBSD and OS/2, and RENICE_REAL is only available under FreeBSD, Linux\n" "# and OS/2.\n"}, {OPT_STATUSBAR, "STATUSBAR", "# STATUSBAR = , size of statusbar from 0 to 2, default: 2\n"}, {OPT_S_CONFIG, "SAVECONFIG", "# SAVECONFIG = Yes|No, save configuration on exit, default: No\n"}, {OPT_S_PLAYLIST, "SAVEPLAYLIST", "# SAVEPLAYLIST = Yes|No, save playlist on exit, default: No\n"}, {OPT_PL_NAME, "PL_NAME", "# PL_NAME = \"name\", name under which the playlist will be saved\n" "# by selecting 'Save' in the playlist-menu\n"}, {OPT_FULLPATHS, "FULLPATHS", "# FULLPATHS = Yes|No, display full path of files, default: No\n"}, {OPT_NONE, NULL, NULL} }; char* CF_GetFilename(void) { #if defined(__OS2__)||defined(__EMX__) return get_cfg_name("mikmod.cfg"); #else return get_cfg_name(".mikmodrc"); #endif } void CF_Init(CONFIG *cfg) { cfg->driver =0; #if LIBMIKMOD_VERSION >= 0x030107 CF_set_string(&cfg->driveroptions,"",99); #endif cfg->stereo =1; cfg->mode_16bit =1; cfg->frequency =44100; cfg->interpolate =0; cfg->hqmixer =0; cfg->surround =0; cfg->reverb =0; cfg->volume =100; cfg->volrestrict =0; cfg->fade =0; cfg->loop =0; cfg->panning =1; cfg->extspd =1; cfg->playmode =PM_MULTI; cfg->exit_after =0; cfg->curious =0; cfg->tolerant =0; cfg->renice =RENICE_NONE; cfg->statusbar =2; cfg->color =1; cfg->save_config =0; cfg->save_playlist=0; cfg->fullpaths =0; CF_set_string(&cfg->pl_name,"playlist.mpl",PATH_MAX); } static void write_bool(FILE *file,OPTION option,BOOL arg) { if (option.description) fputs(option.description,file); if (arg) fprintf(file,"%s=yes\n\n",option.label); else fprintf(file,"%s=no\n\n",option.label); } static void write_int(FILE *file,OPTION option,int arg) { if (option.description) fputs(option.description,file); fprintf(file,"%s=%d\n\n",option.label,arg); } static void write_label(FILE *file,OPTION option,LABEL_CONV *convert,int arg) { int i; if (option.description) fputs(option.description,file); for (i=0;convert[i].id!=arg;i++); fprintf(file,"%s=%s\n\n",option.label,convert[i].label); } static void write_string(FILE *file,OPTION option,char *arg) { if (option.description) fputs(option.description,file); if (arg) fprintf(file,"%s=\"%s\"\n\n",option.label,arg); else fprintf(file,"%s=\"\"\n\n",option.label); } BOOL CF_Save(CONFIG *cfg) { FILE *file; char *name; if (!(name=CF_GetFilename())) return 0; if (!(file=fopen(name,"w"))) return 0; free(name); if (fputs("#\n" "# "mikversion"\n" "# configuration file\n" "#\n\n",file)==EOF) { fclose(file); return 0; } write_int(file,options[OPT_DRIVER], cfg->driver); #if LIBMIKMOD_VERSION >= 0x030107 write_string(file,options[OPT_DRV_OPTION],cfg->driveroptions); #endif write_bool(file,options[OPT_STEREO], cfg->stereo); write_bool(file,options[OPT_MODE_16BIT], cfg->mode_16bit); write_int(file,options[OPT_FREQUENCY], cfg->frequency); write_bool(file,options[OPT_INTERPOLATE], cfg->interpolate); write_bool(file,options[OPT_HQMIXER], cfg->hqmixer); write_bool(file,options[OPT_SURROUND], cfg->surround); write_int(file,options[OPT_REVERB], cfg->reverb); write_int(file,options[OPT_VOLUME], cfg->volume); write_bool(file,options[OPT_VOLRESTRICT], cfg->volrestrict); write_bool(file,options[OPT_FADE], cfg->fade); write_bool(file,options[OPT_LOOP], cfg->loop); write_bool(file,options[OPT_PANNING], cfg->panning); write_bool(file,options[OPT_EXTSPD], cfg->extspd); write_bool(file,options[OPT_PM_MODULE], BTST(cfg->playmode,PM_MODULE)); write_bool(file,options[OPT_PM_MULTI], BTST(cfg->playmode,PM_MULTI)); write_bool(file,options[OPT_PM_SHUFFLE], BTST(cfg->playmode,PM_SHUFFLE)); write_bool(file,options[OPT_PM_RANDOM], BTST(cfg->playmode,PM_RANDOM)); write_bool(file,options[OPT_EXIT_AFTER], cfg->exit_after); write_bool(file,options[OPT_CURIOUS], cfg->curious); write_bool(file,options[OPT_TOLERANT], cfg->tolerant); write_bool(file,options[OPT_XTERM], cfg->xterm_title); #ifdef ENABLE_COLOR_INTERFACE write_bool(file,options[OPT_COLOR], cfg->color); #endif write_label(file,options[OPT_RENICE], renice_conv,cfg->renice); write_int(file,options[OPT_STATUSBAR], cfg->statusbar); write_bool(file,options[OPT_S_CONFIG], cfg->save_config); write_bool(file,options[OPT_S_PLAYLIST], cfg->save_playlist); write_string(file,options[OPT_PL_NAME], cfg->pl_name); write_bool(file,options[OPT_FULLPATHS], cfg->fullpaths); fclose(file); return 1; } static char skip_space(char **line) { while ((**line==' ')||(**line=='\t')) (*line)++; return **line; } static BOOL parse_line(char *line,char **label,char **arg) { char *end; *label=*arg=NULL; if (skip_space(&line)=='#') return 0; *label=line; while (isalnum((int)*line)||(*line == '_')) { *line=toupper((int)*line); line++; } end=line; if (skip_space(&line)=='='){ line++; skip_space(&line); if ((isgraph((int)*line))&&(*line!='\t')&&(*line!=' ')) { BOOL string=(*line=='"'); if (string) line++; *end='\0'; *arg=line; while ((!string && isgraph((int)*line) && *line!='\t' && *line!=' ') || (string && *line && *line!='"')) { if (!string) *line=toupper((int)*line); line++; } *line='\0'; return 1; } } return 0; } static void set_int(int *value,char *arg,int min,int max) { char *end; int t=strtol(arg,&end,10); if ((!*end)&&(t>=min)&&(t<=max)) *value=t; } static void set_bool(BOOL *value,char *arg) { if ((!strcasecmp(arg,"YES"))||(!strcasecmp(arg,"ON"))||(*arg=='1')) *value=1; else if ((!strcasecmp(arg,"NO"))||(!strcasecmp(arg,"OFF"))||(*arg=='0')) *value = 0; } static void set_bit(int *value,int mask,char *arg) { if ((!strcasecmp(arg,"YES"))||(!strcasecmp(arg,"ON"))||(*arg=='1')) *value |= mask; else if ((!strcasecmp(arg,"NO"))||(!strcasecmp(arg,"OFF"))||(*arg=='0')) *value &= ~mask; } static void set_label(int *value,char *arg,LABEL_CONV *convert) { int i=0; while (convert[i].label) { if (!strcmp(convert[i].label,arg)) { *value=convert[i].id; return; } i++; } } void CF_set_string(char **value,char *arg,int length) { int len=strlen(arg); if (len>length) len=length; if (*value) free(*value); *value=(char*)malloc((len+1)*sizeof(char)); strncpy(*value,arg,len); (*value)[len]='\0'; } static void set_option(CONFIG *cfg,OPTION_ID opt,char *arg) { switch (opt) { case OPT_NONE: break; case OPT_DRIVER: set_int(&cfg->driver,arg,0,999); break; #if LIBMIKMOD_VERSION >= 0x030107 case OPT_DRV_OPTION: CF_set_string(&cfg->driveroptions,arg,99); break; #endif case OPT_STEREO: set_bool(&cfg->stereo,arg); break; case OPT_MODE_16BIT: set_bool(&cfg->mode_16bit,arg); break; case OPT_FREQUENCY: set_int(&cfg->frequency,arg,4000,60000); break; case OPT_INTERPOLATE: set_bool(&cfg->interpolate,arg); break; case OPT_HQMIXER: set_bool(&cfg->hqmixer,arg); break; case OPT_SURROUND: set_bool(&cfg->surround,arg); break; case OPT_REVERB: set_int(&cfg->reverb,arg,0,15); break; case OPT_VOLUME: set_int(&cfg->volume,arg,0,100); break; case OPT_VOLRESTRICT: set_bool(&cfg->volrestrict,arg); break; case OPT_FADE: set_bool(&cfg->fade,arg); break; case OPT_LOOP: set_bool(&cfg->loop,arg); break; case OPT_PANNING: set_bool(&cfg->panning,arg); break; case OPT_EXTSPD: set_bool(&cfg->extspd,arg); break; case OPT_PM_MODULE: set_bit(&cfg->playmode,PM_MODULE,arg); break; case OPT_PM_MULTI: set_bit(&cfg->playmode,PM_MULTI,arg); break; case OPT_PM_SHUFFLE: set_bit(&cfg->playmode,PM_SHUFFLE,arg); break; case OPT_PM_RANDOM: set_bit(&cfg->playmode,PM_RANDOM,arg); break; case OPT_EXIT_AFTER: set_bool(&cfg->exit_after,arg); break; case OPT_CURIOUS: set_bool(&cfg->curious,arg); break; case OPT_TOLERANT: set_bool(&cfg->tolerant,arg); break; case OPT_XTERM: set_bool(&cfg->xterm_title,arg); break; #ifdef ENABLE_COLOR_INTERFACE case OPT_COLOR: set_bool(&cfg->color,arg); break; #endif case OPT_RENICE: set_label(&cfg->renice,arg,renice_conv); break; case OPT_STATUSBAR: set_int(&cfg->statusbar,arg,0,2); break; case OPT_S_CONFIG: set_bool(&cfg->save_config,arg); break; case OPT_S_PLAYLIST: set_bool(&cfg->save_playlist,arg); break; case OPT_PL_NAME: CF_set_string(&cfg->pl_name,arg,PATH_MAX); break; case OPT_FULLPATHS: set_bool(&cfg->fullpaths,arg); break; } } BOOL CF_Load(CONFIG *cfg) { FILE *file; char *name=CF_GetFilename(); CHAR line[LINE_LEN],*label,*arg; int i; if (!name) return 0; if (!(file=fopen(name,"r"))) return 0; free(name); while (fgets(line,LINE_LEN,file)) { if (line[strlen(line)-1]=='\n') line[strlen(line)-1]='\0'; if (!strcasecmp(line,PL_IDENT)) { fclose(file); return 1; } if (parse_line(line,&label,&arg)) { i = 0; while ((options[i].label)&&(strcmp(options[i].label,label))) i++; if (options[i].label) set_option(cfg,options[i].id,arg); } } fclose(file); return 1; } /* ex:set ts=4: */