#include #include #include #include #include #include #include "../include/Y2/Y.h" #include "../include/Y2/Ylib.h" #include "../include/fio.h" #include "../include/disk.h" #include "../include/string.h" #include "../include/cfgfmt.h" #include "guiutils.h" #include "cdialog.h" #include "yc.h" #include "config.h" gint YCLoadConfiguration(yc_struct *yc, const gchar *filename); static void writehseparator(FILE *fp, int columns); gint YCSaveConfiguration(yc_struct *yc, const gchar *filename); gint YCSaveStartScript(yc_struct *yc, const gchar *filename); #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define MAX(a,b) (((a) > (b)) ? (a) : (b)) /* * Loads the configuration values from the specified filename * to the widgets in the yc structure. * * Returns 0 on success and non-zero on error. Error codes are: * * -1 Invalid input error. * -2 Minor file format inconsistancy. * -3 Permission denied. */ gint YCLoadConfiguration(yc_struct *yc, const gchar *filename) { gchar *strptr, *strptr2; FILE *fp; gint lines_read = 0; gchar parm[CFG_PARAMETER_MAX]; gchar val[CFG_VALUE_MAX]; GtkWidget *w; GtkCList *clist; if((yc == NULL) || (filename == NULL)) return(-1); /* Unload all Y Audio Modes. */ YCYModesListDeleteAll(yc); /* Unload all Y Sound Paths. */ YCYSoundPathsListDeleteAll(yc); /* Open YIFF Sound Server configuration file. */ fp = FOpen(filename, "rb"); if(fp == NULL) return(-3); /* Reads the next line, fetches parm and val. Will break the loop * if end of file is reached or continue as needed. Make sure variable * is initially reset to NULL before start of reading file. Uses * variables; strptr, strptr2, fp, parm, val, and lines_read. */ #define DO_READ_LINE \ { \ /* Free previous line and allocate/read next line. */ \ free(strptr); \ strptr = FReadNextLineAlloc(fp, UNIXCFG_COMMENT_CHAR); \ if(strptr == NULL) \ break; \ lines_read++; \ \ /* Fetch parameter. */ \ strptr2 = StringCfgParseParm(strptr); \ if(strptr2 == NULL) \ continue; \ strncpy(parm, strptr2, CFG_PARAMETER_MAX); \ parm[CFG_PARAMETER_MAX - 1] = '\0'; \ \ /* Fetch value. */ \ strptr2 = StringCfgParseValue(strptr); \ if(strptr2 == NULL) \ strptr2 = "0"; /* Set it to "0" if NULL. */ \ strncpy(val, strptr2, CFG_VALUE_MAX); \ val[CFG_VALUE_MAX - 1] = '\0'; \ } /* Begin reading file. */ strptr = NULL; while(1) { DO_READ_LINE /* YIFF Sound Server version number (major). */ if(!strcasecmp(parm, "VersionMajor")) { } /* YIFF Sound Server version number (minor). */ else if(!strcasecmp(parm, "VersionMinor")) { } /* Listening port number. */ else if(!strcasecmp(parm, "Port")) { w = yc->port_entry; if(w != NULL) gtk_entry_set_text(GTK_ENTRY(w), (const gchar *)val); } /* Refresh interval (in microseconds). */ else if(!strcasecmp(parm, "RefreshInterval")) { w = yc->sound_refresh_spin; if(w != NULL) gtk_spin_button_set_value( GTK_SPIN_BUTTON(w), (gfloat)atol(val) ); } /* DSP device. Handle case where parm is ambiguously given * as "Device" to assume it means the DSP device (for * backwards compatability). */ else if(!strcasecmp(parm, "DSPDevice") || !strcasecmp(parm, "Device") ) { w = yc->dsp_device_entry; if(w != NULL) gtk_entry_set_text(GTK_ENTRY(w), (const gchar *)val); } /* Mixer device. Handle case where parm is ambiguously * given as "Mixer" to assume it means the Mixer device (for * backwards compatability). */ else if(!strcasecmp(parm, "MixerDevice") || !strcasecmp(parm, "Mixer") ) { w = yc->mixer_device_entry; if(w != NULL) gtk_entry_set_text(GTK_ENTRY(w), (const gchar *)val); } /* MIDI player command. Note that "%f" is token substitution * for the sound object file when this command is actually * used by the Y server. */ else if(!strcasecmp(parm, "MIDIPlayCommand")) { w = yc->midi_play_cmd_entry; if(w != NULL) gtk_entry_set_text(GTK_ENTRY(w), (const gchar *)val); } /* MIDI device port number (required for ALSA MIDI players). */ else if(!strcasecmp(parm, "MIDIDevicePort")) { w = yc->alsa_midi_port_entry; if(w != NULL) gtk_entry_set_text(GTK_ENTRY(w), (const gchar *)val); } /* Begin Y Audio Mode configuration block, here we check * for a bunch of possible similar parm names for backwards * compatability. Note that BeginYAudioMode is the official * parm name. */ else if(!strcasecmp(parm, "BeginYAudioMode") || !strcasecmp(parm, "BeginAudioMode") || !strcasecmp(parm, "BeginYMode") || !strcasecmp(parm, "BeginMode") ) { gint ymode_num; yc_ymode_data_struct *ymode_data_ptr = YCYModeDataStructNew(); gchar *text[1]; /* Add a new Y Audio Mode data structure to the clist. */ clist = (GtkCList *)yc->ymodes_clist; if(clist != NULL) { ymode_num = clist->rows; text[0] = "Untitled"; gtk_clist_append(clist, text); gtk_clist_set_row_data(clist, ymode_num, ymode_data_ptr); } else { YCYModeDataStructFree(ymode_data_ptr); ymode_data_ptr = NULL; ymode_num = -1; } /* From here on, ymode_data_ptr will be not NULL if * it was successfully added to the clist. */ while(1) { DO_READ_LINE /* Name. */ if(!strcasecmp(parm, "Name")) { if((clist != NULL) && (ymode_num >= 0)) { gtk_clist_set_text( clist, ymode_num, 0, val ); } if(ymode_data_ptr != NULL) { free(ymode_data_ptr->name); ymode_data_ptr->name = strdup(val); } } /* Cycle interval in microseconds. */ else if(!strcasecmp(parm, "Cycle")) { if(ymode_data_ptr != NULL) ymode_data_ptr->cycle_us = MAX(atol(val), 100); } /* Write ahead in microseconds. */ else if(!strcasecmp(parm, "WriteAhead")) { if(ymode_data_ptr != NULL) ymode_data_ptr->write_ahead_us = MAX(atol(val), 100); } /* Sample size in bits. */ else if(!strcasecmp(parm, "SampleSize")) { if(ymode_data_ptr != NULL) { ymode_data_ptr->sample_size = atoi(val); /* Sanitize. */ if(ymode_data_ptr->sample_size != 16) ymode_data_ptr->sample_size = 8; } } /* Channels. */ else if(!strcasecmp(parm, "Channels")) { if(ymode_data_ptr != NULL) { ymode_data_ptr->channels = atoi(val); /* Sanitize. */ if(ymode_data_ptr->channels != 2) ymode_data_ptr->channels = 1; } } /* Sample rate in Hz. */ else if(!strcasecmp(parm, "SampleRate")) { if(ymode_data_ptr != NULL) ymode_data_ptr->sample_rate = MAX(atol(val), YC_MIN_SAMPLE_RATE); } /* Allow fragmenting. */ else if(!strcasecmp(parm, "AllowFragmenting")) { if(ymode_data_ptr != NULL) ymode_data_ptr->allow_fragmenting = StringIsYes(val); } /* Number of fragments. */ else if(!strcasecmp(parm, "Fragments")) { if(ymode_data_ptr != NULL) ymode_data_ptr->num_fragments = atoi(val); } /* Fragment size in bytes. */ else if(!strcasecmp(parm, "FragmentSize")) { if(ymode_data_ptr != NULL) ymode_data_ptr->fragment_size_bytes = MAX(atoi(val), YC_MIN_FRAGMENT_SIZE); } /* Flip stereo. */ else if(!strcasecmp(parm, "FlipStereo")) { if(ymode_data_ptr != NULL) ymode_data_ptr->flip_stereo = StringIsYes(val); } /* Direction. */ else if(!strcasecmp(parm, "Direction")) { if(ymode_data_ptr != NULL) { if(!strcasecmp(val, "Record")) ymode_data_ptr->direction = 1; else ymode_data_ptr->direction = 0; } } /* End Y Audio Mode configuration block. */ else if(!strcasecmp(parm, "EndYAudioMode") || !strcasecmp(parm, "EndAudioMode") || !strcasecmp(parm, "EndYMode") || !strcasecmp(parm, "EndMode") ) { break; } /* Unknown parameter. */ else { fprintf( stderr, "%s: Line %i: Unknown parameter: %s\n", filename, lines_read, parm ); continue; } } } /* Begin Y Sound Path, we check for a few similar * names as the parm. Note that the official value * is BeginYSoundPath. */ else if(!strcasecmp(parm, "BeginYSoundPath") || !strcasecmp(parm, "BeginSoundPath") ) { gint ysound_path_num; gchar *text[1]; /* Add a new Y Sound Path to the clist, there is no * data structure. */ clist = (GtkCList *)yc->ysound_paths_clist; if(clist != NULL) { ysound_path_num = clist->rows; text[0] = "/tmp"; gtk_clist_append(clist, text); } else { ysound_path_num = -1; } while(1) { DO_READ_LINE /* Path */ if(!strcasecmp(parm, "Path")) { if((clist != NULL) && (ysound_path_num >= 0)) { gtk_clist_set_text( clist, ysound_path_num, 0, val ); } } /* End Y Sound Path. */ else if(!strcasecmp(parm, "EndYSoundPath") || !strcasecmp(parm, "EndSoundPath") ) { break; } /* Unknown parameter. */ else { fprintf( stderr, "%s: Line %i: Unknown parameter: %s\n", filename, lines_read, parm ); continue; } } } /* Unknown parameter. */ else { fprintf( stderr, "%s: Line %i: Unknown parameter: %s\n", filename, lines_read, parm ); continue; } } #undef DO_READ_LINE /* Close YIFF Sound Server configuration file. */ FClose(fp); return(0); } /* * Prints a bunch of '#' characters in a row to stream. */ static void writehseparator(FILE *fp, int columns) { gint i; if(fp == NULL) return; fprintf(fp, "# "); columns = columns - 2; for(i = 0; i < columns; i++) fputc('#', fp); fputc('\n', fp); } /* * Saves the values in the yc widgets to the given filename as * a YIFF Sound Server configuration file. * * Returns 0 on success and non-zero on error. Error codes: * * -1 Invalid input error. * -2 Value inconsistancy. * -3 Permission denied. */ gint YCSaveConfiguration(yc_struct *yc, const gchar *filename) { gint i, columns = 80; FILE *fp; GtkWidget *w; GtkCList *clist; if((yc == NULL) || (filename == NULL)) return(-1); /* Create new YIFF Sound Server configuration file. */ fp = FOpen(filename, "wb"); if(fp == NULL) return(-3); /* Header. */ writehseparator(fp, columns); fprintf( fp, "\ #\n\ # YIFF Sound Server Configuration File\n\ #\n\ # Generated by %s %s\n\ #\n\ \n\n", PROG_NAME, PROG_VERSION ); fprintf( fp, "\ # Configuration file version:\n\ #\n\ VersionMajor = %i\n\ VersionMinor = %i\n\ \n\n", PROG_VERSION_MAJOR, PROG_VERSION_MINOR ); /* Listening port number. */ w = yc->port_entry; fprintf( fp, "\ # Listening port number:\n\ #\n\ Port = %s\n\ \n\n", (w == NULL) ? YC_DEF_PORT : gtk_entry_get_text(GTK_ENTRY(w)) ); /* Refresh interval (in microseconds). */ w = yc->sound_refresh_spin; fprintf( fp, "\ # Refresh interval (in microseconds):\n\ #\n\ RefreshInterval = %i\n\ \n\n", (w == NULL) ? 30000000 : gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON(w) ) ); /* DSP device. */ w = yc->dsp_device_entry; fprintf( fp, "\ # DSP device:\n\ #\n\ DSPDevice = %s\n\ \n\n", (w == NULL) ? YC_DEF_DSP_DEVICE : gtk_entry_get_text(GTK_ENTRY(w)) ); /* Mixer device. */ w = yc->mixer_device_entry; fprintf( fp, "\ # Mixer device:\n\ #\n\ MixerDevice = %s\n\ \n\n", (w == NULL) ? YC_DEF_MIXER_DEVICE : gtk_entry_get_text(GTK_ENTRY(w)) ); /* MIDI player command. */ w = yc->midi_play_cmd_entry; fprintf( fp, "\ # Command to execute to play an MIDI Sound Object (a .mid file). Since\n\ # MIDI implmentation is still under development on most platforms, you\n\ # will need to consult your sound driver documentation on the proper\n\ # procedure to play .mid files.\n\ #\n\ # Known MIDI playing implmentations are:\n\ #\n\ # ALSA drivers uses the `pmidi' driver program.\n\ # OSS drivers uses the `drvmidi' driver program.\n\ # Other possible programs include `playmidi'.\n\ #\n\ # The following substitutions will be made to the command:\n\ #\n\ # %%f Full path to the MIDI Sound Object on file.\n\ #\n\ MIDIPlayCommand = %s\n\ \n", (w == NULL) ? YC_DEF_MIDI_PLAY_CMD : gtk_entry_get_text(GTK_ENTRY(w)) ); /* ALSA MIDI device port. */ w = yc->alsa_midi_port_entry; fprintf( fp, "\ # If ALSA support is compiled, then this value specifies the\n\ # MIDI device port to use. Otherwise this value is ignored.\n\ #\n\ MIDIDevicePort = %s\n\ \n\n", (w == NULL) ? YC_DEF_MIDI_PLAY_CMD : gtk_entry_get_text(GTK_ENTRY(w)) ); /* ******************************************************** */ /* Preset Y Audio Modes list. */ writehseparator(fp, columns); fprintf( fp, "\ #\n\ # Preset Y Audio Modes:\n\ #\n\ # All timing values are in microseconds unless noted otherwise. Values for\n\ # FragmentSize are in values of 2^n, where n is a value from 8 to 14 (some\n\ # Sound drivers may have greater restrictions on the value of n, please read\n\ # the documentation that pertains to your Sound driver).\n\ #\n\ \n" ); clist = (GtkCList *)yc->ymodes_clist; if(clist != NULL) { yc_ymode_data_struct *ymode_data_ptr; /* Go through each Y Audio Mode on the clist. */ for(i = 0; i < clist->rows; i++) { ymode_data_ptr = (yc_ymode_data_struct *) gtk_clist_get_row_data(clist, i); if(ymode_data_ptr == NULL) continue; /* First entry? */ if(i == 0) { /* First Audio mode, the default one. Write comment * about it. */ fprintf( fp, "\ # This is the first mode and thus the default mode that YIFF will start\n\ # up with.\n\ #\n" ); } fprintf(fp, "BeginYAudioMode\n"); fprintf(fp, " Name = %s\n", ymode_data_ptr->name ); fprintf(fp, " Cycle = %ld\n", ymode_data_ptr->cycle_us ); fprintf(fp, " WriteAhead = %ld\n", ymode_data_ptr->write_ahead_us ); fprintf(fp, " SampleSize = %i\n", ymode_data_ptr->sample_size ); fprintf(fp, " Channels = %i\n", ymode_data_ptr->channels ); fprintf(fp, " SampleRate = %i\n", ymode_data_ptr->sample_rate ); fprintf(fp, " AllowFragmenting = %s\n", (ymode_data_ptr->allow_fragmenting) ? "yes" : "no" ); fprintf(fp, " Fragments = %i\n", ymode_data_ptr->num_fragments ); /* In bytes. */ fprintf(fp, " FragmentSize = %i\n", ymode_data_ptr->fragment_size_bytes ); fprintf(fp, " FlipStereo = %s\n", (ymode_data_ptr->flip_stereo) ? "yes" : "no" ); fprintf(fp, " Direction = %s\n", (ymode_data_ptr->direction == 1) ? "Record" : "Play" ); fprintf(fp, "EndYAudioMode\n\n"); } } fprintf(fp, "\n"); /* ******************************************************** */ /* Y Sound Paths. */ writehseparator(fp, columns); fprintf( fp, "\ #\n\ # Y Sound Paths:\n\ #\n\ # Y Sound Objects with relative paths are searched for through these\n\ # Y Sound Paths (directories).\n\ #\n\ # You may specify as many Sound Paths as you wish, keep in mind that the\n\ # Sound Paths are searched through in the order from first to last.\n\ #\n\ \n" ); clist = (GtkCList *)yc->ysound_paths_clist; if(clist != NULL) { gchar *path_ptr; /* Go through each Y Sound Path on the clist. */ for(i = 0; i < clist->rows; i++) { gtk_clist_get_text(clist, i, 0, &path_ptr); if(path_ptr == NULL) continue; fprintf(fp, "BeginYSoundPath\n"); fprintf(fp, " Path = %s\n", path_ptr); fprintf(fp, "EndYSoundPath\n\n"); } } fprintf(fp, "\n"); /* Footer. */ fprintf( fp, "\ #\n\ # End of file.\n" ); writehseparator(fp, columns); /* Close created YIFF Sound Server configuration file. */ FClose(fp); return(0); } /* * Writes a start script for the YIFF Sound Server with * respect to the given values on widgets in the yc. * * Returns 0 on success and non-zero on error. Error codes: * * -1 Invalid input error. * -2 Value inconsistancy. * -3 Permission denied. */ int YCSaveStartScript(yc_struct *yc, const char *filename) { FILE *fp; GtkWidget *w; gchar *strptr; const gchar *parm_varstr; const gchar *prog_varstr = "YIFF_PROGRAM"; const gchar *config_varstr = "YIFF_CONFIGURATION"; if((yc == NULL) || (filename == NULL)) return(-1); /* Create new YIFF start script file. */ fp = FOpen(filename, "wb"); if(fp == NULL) return(-3); /* Script type header, use /bin/sh for better compatability. */ fprintf( fp, "#!/bin/sh\n" ); fputc('\n', fp); /* Write variable setup section. */ fprintf( fp, "# Locations of YIFF compoents and resources, make any changes as needed.\n\ #\n" ); /* YIFF program file location. */ w = yc->yiff_program_entry; parm_varstr = prog_varstr; if((w != NULL) && (parm_varstr != NULL)) { strptr = gtk_entry_get_text(GTK_ENTRY(w)); if(strptr != NULL) fprintf( fp, "%s=%s\n", parm_varstr, strptr ); } /* YIFF configuration file location. */ w = yc->yiff_configuration_file_entry; parm_varstr = config_varstr; if((w != NULL) && (parm_varstr != NULL)) { strptr = gtk_entry_get_text(GTK_ENTRY(w)); if(strptr != NULL) fprintf( fp, "%s=%s\n", parm_varstr, strptr ); } fputc('\n', fp); /* Run the YIFF Sound Server. */ fprintf( fp, "# Run the YIFF Sound Server, syntax is; \" \"\n\ # YIFF will put the process into background by itself.\n\ #\n" ); fprintf( fp, "$%s $%s\n", prog_varstr, config_varstr ); fputc('\n', fp); /* Add commented out section for yhosts. */ fprintf( fp, "# Put list of Y hosts that you would like to allow connecting to the\n\ # Y server in this section. Note that localhost (127.0.0.1) is always\n\ # given permission to connect when the YIFF server is runned.\n\ #\n" ); /* Commented out example. */ fprintf( fp, "#yhost 127.0.0.1\n" ); fputc('\n', fp); /* Play a sound object on successful startup. */ fprintf( fp, "# Play a sound object on successful startup?\n" ); fprintf( fp, "#yplay -m /usr/share/sounds/startup1.wav\n" ); fputc('\n', fp); /* Set proper permissions. */ fchmod( fileno(fp), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH ); /* Close created YIFF start script file. */ FClose(fp); return(0); }