profile.cpp Source File

Main Page Modules Class Hierarchy Compound List File List Compound Members File Members

# profile.cpp

    00001 /* MuSE - Multiple Streaming Engine
    00002  * profile (config file) class
    00003  *
    00004  * this file contains algorithms written by Flavio de Ayra Mender and
    00005  * an object oriented approach to them (and bugfix) by Denis "jaromil" Rojo
    00006  *
    00007  * Copyright (C) 2001 - 2002 Flavio de Ayra Mendes <h4@locked.org>
    00008  * Copyright (C) 2002 - 2003 Denis Rojo <jaromil@dyne.org>
    00009  *
    00010  * This source code is free software; you can redistribute it and/or
    00011  * modify it under the terms of the GNU Public License as published
    00012  * by the Free Software Foundation; either version 2 of the License,
    00013  * or (at your option) any later version.
    00014  *
    00015  * This source code is distributed in the hope that it will be useful,
    00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00018  * Please refer to the GNU Public License for more details.
    00019  *
    00020  * You should have received a copy of the GNU Public License along with
    00021  * this source code; if not, write to:
    00022  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    00023  *
    00024  * "$Id: profile.cpp,v 1.1.1.1 2003/12/08 12:20:33 jaromil Exp $"
    00025  *
    00026  */
    00027
    00028 #include <stdio.h>
    00029 #include <string.h>
    00030 #include <stdlib.h>
    00031 #include <time.h>
    00032 #include <sys/types.h>
    00033 #include <sys/stat.h>
    00034 #include <unistd.h>
    00035 #include <errno.h>
    00036
    00037 #include <jutils.h>
    00038 #include <profile.h>
    00039 #include <config.h>
    00040
    00041
    00042 char *Profile::is_a_section(char *str)
    00043 {
    00044   char section_tmp[MAX_SECTION_SIZE];
    00045
    00046   //  fprintf(stderr,"CFG::is_a_section(%s)\n",str);
    00047
    00048   if(str[0]!='[') return(NULL);
    00049
    00050   if (!sscanf(str, "[%[^]]]", section_tmp))
    00051     return(NULL);
    00052
    00053   //  fprintf(stderr,"CFG::YES it is! %s\n",section_tmp);
    00054   /* return it */
    00055   return(strdup(section_tmp));
    00056 }
    00057
    00058 char **Profile::parse_option(char *str) {
    00059   char option_tmp[MAX_OPTION_SIZE];
    00060   char value_tmp[MAX_VALUE_SIZE];
    00061
    00062   memset(option_tmp, '\0', MAX_OPTION_SIZE);
    00063   memset(value_tmp, '\0', MAX_VALUE_SIZE);
    00064
    00065   /* if its not an option return 0 */
    00066   if (sscanf(str, "%[^= ] = %[^=\n]", option_tmp, value_tmp) != 2)
    00067     return NULL;
    00068
    00069   /* if dest_opt were passed copy the option name there */
    00070   res[0] = strdup(option_tmp);
    00071
    00072   /* if dest_val were passed copy the value there */
    00073   res[1] = strdup(value_tmp);
    00074
    00075   //  func("parse_option: opt[%s] val[%s]",res[0],res[1]);
    00076
    00077   /* return true */
    00078   return res;
    00079 }
    00080
    00081 /* returns:
    00082    -1 EOF
    00083    or offset of section */
    00084 off_t Profile::find_section(FILE *fp, const char *section) {
    00085   char tmp[MAX_LINE_SIZE], *sect;
    00086   off_t offset = -1;
    00087   off_t bck, pos;
    00088
    00089   //  fprintf(stderr,"CFG::find_section: [%s]\n",section);
    00090
    00091   /* save initial offset */
    00092   bck = ftell(fp);
    00093   rewind(fp);
    00094
    00095   while (!feof(fp)) {
    00096
    00097     pos = ftell(fp);
    00098     if(!fgets(tmp, MAX_LINE_SIZE,fp)) break;
    00099
    00100     chomp(tmp);
    00101     //    fprintf(stderr,"find section : \"%s\"\n",tmp);
    00102
    00103     /* ignore comments */
    00104     if (tmp[0] == '#'
    00105         || tmp[0] == '\r'
    00106         || tmp[0] == '\n'
    00107         || tmp[0]=='\0')
    00108       continue;
    00109
    00110     /* is a section line */
    00111     sect = is_a_section(tmp);
    00112     if(sect) {
    00113       /* yes, this is our section. return his offset */
    00114       if (!strncmp(sect,section,MAX_SECTION_SIZE)) {
    00115         offset = pos;
    00116         free(sect);
    00117         break;
    00118       } else free(sect);
    00119     }
    00120   }
    00121
    00122   /* get back to initial offset */
    00123   fseek(fp,bck,SEEK_SET);
    00124
    00125   return offset;
    00126 }
    00127
    00128 /* returns:
    00129    -1 EOF
    00130    0 no option in current section
    00131    OR offset of the option */
    00132 off_t Profile::find_option(FILE *fp, const char *option, char *value, off_t section_offset) {
    00133   char tmp[MAX_LINE_SIZE];
    00134   char **res = NULL;
    00135   off_t offset = -1;
    00136   off_t bck, pos;
    00137
    00138   //  func("find_option(%s)",option);
    00139
    00140   /* backup file pointer */
    00141   bck = ftell(fp);
    00142
    00143   /* seek to section */
    00144   fseek(fp, section_offset, SEEK_SET);
    00145   fgets(tmp, MAX_LINE_SIZE, fp); /* goes to the first option line */
    00146
    00147   while (!feof(fp)) {
    00148
    00149     pos = ftell(fp);
    00150     if(!fgets(tmp, MAX_LINE_SIZE, fp)) break;
    00151
    00152     chomp(tmp);
    00153     //    fprintf(stderr,"find option : \"%s\"\n",tmp);
    00154
    00155     if (tmp[0] == '#'
    00156         || tmp[0] == '\r'
    00157         || tmp[0] == '\n'
    00158         || tmp[0] == '\0')
    00159       continue;
    00160
    00161     if (tmp[0] == '[') break;/* END OF SECTION - nothing found */
    00162
    00163     res = parse_option(tmp);
    00164     if(res) {
    00165       if (!strncmp(res[0], option, MAX_OPTION_SIZE)) { /* SUCCESS */
    00166         if(value) strncpy(value,res[1],MAX_VALUE_SIZE);
    00167         offset = pos;
    00168         //      func("find_option() : FOUND at offset %lu\n",offset);
    00169         break;
    00170       }
    00171       //      free(res[0]); free(res[1]);
    00172     }
    00173   }
    00174
    00175   /* restore backup */
    00176   fseek(fp,bck,SEEK_SET);
    00177
    00178   if(res) { free(res[0]); free(res[1]); }
    00179
    00180   return offset;
    00181 }
    00182
    00183 int Profile::cfg_check(const char *file, int output) {
    00184   unsigned int line = 0; /* line number */
    00185   unsigned int section = 0;
    00186   unsigned int err = 0; /* error checking */
    00187   char buff[MAX_LINE_SIZE]; /* line buffer */
    00188   char *sect = NULL;
    00189   char **res = NULL;
    00190   FILE *fd;
    00191
    00192   fd = fopen(file,"r");
    00193   if(!fd) {
    00194     error("cfg_check(): can't open %s (%s)",file,strerror(errno));
    00195     return(false); }
    00196
    00197
    00198   /* let's work */
    00199   while (fgets(buff, MAX_LINE_SIZE, fd)) {
    00200     /* line counting */
    00201     line++;
    00202
    00203     chomp(buff);
    00204
    00205     /* ignore comments and blank lines */
    00206     if (*buff == '#'
    00207         || *buff == '\r'
    00208         || *buff == '\n'
    00209         || *buff == '\0')
    00210       continue;
    00211
    00212     if ((sect = is_a_section(buff))) { /* ok, its a section */
    00213       section = 1;
    00214       free(sect);
    00215     } else if ((res = parse_option(buff))) {
    00216       if (!section) {
    00217         /* option without a section */
    00218         err = 1;
    00219         if (output)
    00220           error("CFG::check_config : %s:%d: option '%s' whithout a section.\n",
    00221                 file, line, res[0]);
    00222       }
    00223       free(res[0]); free(res[1]);
    00224     } else {
    00225       err = 1;
    00226       if (output)
    00227         error("%s:%d: syntax error: '%s'\n", file, line, buff);
    00228     }
    00229   }
    00230
    00231   free(res[0]); free(res[1]);
    00232   fclose(fd);
    00233   /* return 0 if failed or 1 if ok */
    00234   return (err ? 0: 1);
    00235 }
    00236
    00237
    00238 bool Profile::cfg_read(const char *file, const char *section,
    00239                 const char *option, char *value) {
    00240
    00241   off_t option_offset;
    00242   off_t section_offset;
    00243   FILE *fd;
    00244
    00245   fd = fopen(file,"r");
    00246   if(!fd) {
    00247     error("cfg_read : can't open %s",file);
    00248     error("%s",strerror(errno));
    00249     return(false); }
    00250
    00251   /* return if section not found */
    00252   if ((section_offset = find_section(fd, section)) < 0) {
    00253     func("cfg_read(): can't find section '%s'", section);
    00254     return false;
    00255   }
    00256
    00257   option_offset = find_option(fd, option, value, section_offset);
    00258   /* return if option not found */
    00259   if(option_offset<1) {
    00260     func("cfg_read(): can't find option[%s] section[%s]", option, section);
    00261     return false;
    00262   }
    00263
    00264   fclose(fd);
    00265   return(true);
    00266 }
    00267
    00268 bool Profile::cfg_write(const char *file, const char *section,
    00269                  const char *option, const char *value) {
    00270   off_t section_offset;
    00271   off_t option_offset;
    00272   char val[MAX_VALUE_SIZE];
    00273   char tmp[MAX_LINE_SIZE];
    00274   FILE *fd, *tmp_fp;
    00275   struct stat st;
    00276
    00277   //  func("cfg_write(%s,%s,%s,%s)",file,section,option,value);
    00278
    00279   if (stat(file, &st) == -1) {
    00280     /* file is NEW */
    00281     fd = fopen(file,"w");
    00282     if(!fd) {
    00283       error("cfg_write() : can't open %s",file);
    00284       error("%s",strerror(errno));
    00285       return(false); }
    00286     fprintf(fd, "[%s]\n%s = %s\n", section,option,value);
    00287     fflush(fd);
    00288     fclose(fd);
    00289     return(true);
    00290   } else fd = fopen(file,"r+");
    00291   if(!fd) {
    00292     error("cfg_write : can't open %s (%s)",file, strerror(errno));
    00293     return(false); }
    00294
    00295   section_offset = find_section(fd, section);
    00296
    00297   if(section_offset<0) { /* there is no section */
    00298     func("cfg_write() : create new section [%s]",section);
    00299
    00300     /* write at the end if section not found */
    00301     fseek(fd, 0, SEEK_END);
    00302     fprintf(fd, "\n[%s]\n%s = %s\n\n", section,option,value);
    00303     //    fflush(fd);
    00304     fclose(fd);
    00305     return(true);
    00306   }
    00307
    00308   option_offset = find_option(fd, option, val, section_offset);
    00309
    00310   if(option_offset>0) /* option found */
    00311     if(!strncmp(val,value,MAX_VALUE_SIZE)) { /* value is the same */
    00312       fclose(fd);
    00313       return(true);
    00314     }
    00315
    00316   /* start a tmp file */
    00317   tmp_fp = tmpfile();
    00318   if (tmp_fp == NULL) {
    00319     error("cfg_write(): can't create temp file (%s)",strerror(errno));
    00320     fclose(fd);
    00321     return(false);
    00322   }
    00323
    00324   if(option_offset>0) { /* option exists, change value */
    00325
    00326     fseek(fd, option_offset, SEEK_SET);
    00327     fgets(tmp, MAX_LINE_SIZE, fd);
    00328     // func("substituting: %s\n",tmp);
    00329     while(fgets(tmp, MAX_LINE_SIZE, fd))
    00330       fputs(tmp, tmp_fp);
    00331     ftruncate(fileno(fd), option_offset);
    00332     fprintf(fd,"%s = %s\n", option, value);
    00333     rewind(tmp_fp);
    00334     while(fgets(tmp, MAX_LINE_SIZE, tmp_fp))
    00335       fputs(tmp, fd);
    00336
    00337   } else { /* option not found, add to section (on top) */
    00338
    00339     fseek(fd, section_offset, SEEK_SET);
    00340     fgets(tmp, MAX_LINE_SIZE, fd);
    00341     option_offset = ftell(fd);
    00342     while(fgets(tmp, MAX_LINE_SIZE, fd))
    00343       fputs(tmp, tmp_fp);
    00344     ftruncate(fileno(fd), option_offset);
    00345     fseek(fd,0,SEEK_END);
    00346     fprintf(fd,"%s = %s\n", option, value);
    00347     rewind(tmp_fp);
    00348     while(fgets(tmp, MAX_LINE_SIZE, tmp_fp))
    00349       fputs(tmp, fd);
    00350
    00351   }
    00352
    00353   /* close tmp file (gets deleted automatically) */
    00354   fclose(tmp_fp);
    00355
    00356   fclose(fd);
    00357
    00358   return(true);
    00359 }
    00360
    00361 bool Profile::cfg_erase(const char *file, const char *section, const char *option) {
    00362   off_t section_offset;
    00363   off_t option_offset;
    00364   FILE *fd, *tmp_fp;
    00365   char tmp[MAX_LINE_SIZE];
    00366   struct stat st;
    00367
    00368   if (stat(file, &st) == -1) {
    00369     error("cfg_erase(): %s does'nt exist",file);
    00370     return(false);
    00371   } else fd = fopen(file,"r+");
    00372   if(!fd) {
    00373     error("cfg_erase(): can't open %s (%s)",file, strerror(errno));
    00374     return(false); }
    00375
    00376   section_offset = find_section(fd, section);
    00377   if(section_offset < 0) return(0); /* section not found */
    00378
    00379   option_offset = find_option(fd, option, NULL, section_offset);
    00380   if(option_offset < 0) return(0); /* option not found */
    00381
    00382   /* start a tmp file */
    00383   tmp_fp = tmpfile();
    00384   if (tmp_fp == NULL) {
    00385     error("cfg_erase(): can't create temp file (%s)",strerror(errno));
    00386     fclose(fd);
    00387     return(false);
    00388   }
    00389
    00390   /* go one line under the one to be deleted */
    00391   fseek(fd,option_offset,SEEK_SET);
    00392   fgets(tmp,MAX_LINE_SIZE,fd);
    00393
    00394   /* copy everything after truncate point to tmp file */
    00395   while (!fgets(tmp, MAX_LINE_SIZE, fd))
    00396     fputs(tmp, tmp_fp);
    00397
    00398   /* truncate config file */
    00399   ftruncate(fileno(fd), option_offset);
    00400
    00401   /* restore the backup after truncation from tmp file */
    00402   rewind(tmp_fp);
    00403   while (!fgets(tmp, MAX_LINE_SIZE, tmp_fp))
    00404     fputs(tmp,fd);
    00405
    00406   fclose(tmp_fp);
    00407   fclose(fd);
    00408
    00409   return(true);
    00410 }
    00411
    00412 int Profile::cfg_get_sections(const char *file, char *dest) {
    00413
    00414   char tmp[MAX_LINE_SIZE], *sect;
    00415   unsigned int num = 0;
    00416   unsigned int spac = 0;
    00417   FILE *fd;
    00418
    00419   fd = fopen(file,"r");
    00420   if(!fd) {
    00421     error("cfg_get_sections(): can't open %s (%s)",file,strerror(errno));
    00422     return(false); }
    00423
    00424   while (fgets(tmp,MAX_LINE_SIZE,fd)) {
    00425
    00426     chomp(tmp);
    00427     /* ignore comments */
    00428     if (tmp[0] == '#'
    00429         || tmp[0] == '\r'
    00430         || tmp[0] == '\n'
    00431         || tmp[0]=='\0')
    00432       continue;
    00433
    00434     sect = is_a_section(tmp);
    00435     /* copy the section name there */
    00436     if(sect) {
    00437       sprintf(&dest[spac],"%s:",sect);
    00438       num++; spac+=strlen(sect)+1;
    00439       free(sect);
    00440     }
    00441   }
    00442   return num;
    00443 }
    00444
    00445 Profile::Profile(char *name) {
    00446   char *home = getenv("HOME");
    00447   /* TODO: FIXME */
    00448   if(!home) {
    00449     error("i'm very sorry: you got no $HOME!");
    00450     cfg = NULL; return;
    00451   }
    00452   snprintf(profile_path,MAX_PATH_SIZE,"%s/.muse/%s.muserc",home,name);
    00453   cfg = NULL;
    00454 }
    00455
    00456 Profile::~Profile() { }
    00457
    00458 /* returns false if a option was missing */
    00459 bool Profile::load_profile(const char *section) {
    00460   int ires, *tvar;
    00461   float fres, *fvar;
    00462   bool tres, res = true;
    00463   struct stat st;
    00464
    00465   if(!cfg) return(false); /* no setup() called */
    00466   if(stat(profile_path, &st) == -1) return(false); /* file not there */
    00467
    00468   for(int i=0;cfg[i].name;i++) {
    00469
    00470     switch(cfg[i].type) {
    00471
    00472     case cfgINT:
    00473       tvar = (int*)cfg[i].var;
    00474       ires = read_int(section,cfg[i].name);
    00475       *tvar = (ires<0) ? atoi(cfg[i].defval) : ires;
    00476       func("load_profile(%s) parsed %s value %i",
    00477            section, cfg[i].name, *(int*)cfg[i].var);
    00478       res &= (ires>=0);
    00479       break;
    00480
    00481     case cfgSTR:
    00482       tres = read_str(section,cfg[i].name,(char*)cfg[i].var);
    00483       if(!tres) {
    00484         snprintf((char*)cfg[i].var,MAX_VALUE_SIZE,"%s",cfg[i].defval);
    00485         res = false;
    00486       }
    00487       func("load_profile(%s) parsed %s value %s",
    00488            section, cfg[i].name,(char*)cfg[i].var);
    00489       break;
    00490
    00491     case cfgFLOAT:
    00492       fvar = (float*)cfg[i].var;
    00493       fres = read_float(section,cfg[i].name);
    00494       if(fres==-1.0f) {
    00495         sscanf(cfg[i].defval,"%f",fvar);
    00496         res = false; }
    00497       else *fvar = fres;
    00498       func("load_profile(%s) parsed %s value %.4f",
    00499            section, cfg[i].name, *(float*)cfg[i].var);
    00500       break;
    00501
    00502     case cfgNULL: break;
    00503
    00504     }
    00505   }
    00506   return(res);
    00507 }
    00508
    00509 bool Profile::write_profile(const char *section) {
    00510   bool res = true;
    00511   bool err = true;
    00512   if(!cfg) return(false);
    00513
    00514   for(int i=0;cfg[i].name;i++) {
    00515     switch(cfg[i].type) {
    00516
    00517     case cfgINT:
    00518       res = write_int(section,cfg[i].name,*(int*)cfg[i].var );
    00519       if(!res) {
    00520         error("write_profile(%s) : write_int error",section);
    00521         write_str(section,cfg[i].name,cfg[i].defval);
    00522       }
    00523       break;
    00524
    00525     case cfgSTR:
    00526       res = write_str(section,cfg[i].name,(const char*)cfg[i].var);
    00527       if(!res) {
    00528         error("write_profile(%s) : write_str error",section);
    00529         write_str(section,cfg[i].name,cfg[i].defval);
    00530       }
    00531       break;
    00532
    00533     case cfgFLOAT:
    00534       res = write_float(section, cfg[i].name,*(float*)cfg[i].var );
    00535       if(!res) {
    00536         error("write_profile(%s) : write_float error",section);
    00537         write_str(section,cfg[i].name,cfg[i].defval);
    00538       }
    00539       break;
    00540
    00541     case cfgNULL: break;
    00542     }
    00543   }
    00544   return(err);
    00545 }
    00546
    00547 bool Profile::create_default_profile() {
    00548   int i;
    00549
    00550   if(!cfg) return(false);
    00551
    00552   for(i=0;cfg[i].name;i++) {
    00553     switch(cfg[i].type) {
    00554     case cfgINT:
    00555       sscanf(cfg[i].defval,"%i",(int*)cfg[i].var);
    00556       break;
    00557     case cfgSTR:
    00558       snprintf((char*)cfg[i].var,MAX_VALUE_SIZE,"%s",cfg[i].defval);
    00559       break;
    00560     case cfgFLOAT:
    00561       sscanf(cfg[i].defval,"%f",(float*)cfg[i].var);
    00562       break;
    00563     case cfgNULL: break;
    00564     }
    00565   }
    00566   return write_profile("default");
    00567 }
    00568
    00569 bool Profile::default_profile() {
    00570   /* loads the default */
    00571   if(!load_profile("default")) {
    00572     if(!create_default_profile()) {
    00573       error("can't create default profile %s", profile_path);
    00574       return false;
    00575     }
    00576   }
    00577   return apply_profile();
    00578 }
    00579
    00580 int Profile::read_int(const char *section, const char *option) {
    00581   char temp[MAX_VALUE_SIZE];
    00582   int res = -1;
    00583
    00584   if(!cfg_read(profile_path,section,option,temp)) {
    00585     warning("Profile::read_int(%s,%s) : %s",
    00586           option,section,profile_path);
    00587     return(-1); }
    00588
    00589   res = strtol(temp,NULL,10);
    00590   if(errno==ERANGE) {
    00591     error("Profile::read_int(%s,%s) value %s : ",
    00592           section, option, temp, strerror(errno));
    00593     return(-1);
    00594   } else return(res);
    00595 }
    00596
    00597 bool Profile::write_int(const char *section, const char *option, const int value) {
    00598   //  func("Profile::write_int(%s,%s,%i)",section,option,value);
    00599   char temp[MAX_VALUE_SIZE];
    00600
    00601   snprintf(temp,MAX_VALUE_SIZE,"%i",value);
    00602   if(!cfg_write(profile_path, section, option, temp)) {
    00603     warning("Profile::write_int(%s,%s,%s) : %s",
    00604           section,option,value,profile_path);
    00605     return(false);
    00606   }
    00607   return(true);
    00608 }
    00609
    00610 float Profile::read_float(const char *section, const char *option) {
    00611   char temp[MAX_VALUE_SIZE];
    00612   float val;
    00613
    00614   if(!cfg_read(profile_path, section, option, temp)) {
    00615     warning("Profile::read_float(%s,%s) : %s",
    00616             option,section,profile_path);
    00617     return(-1.0f); }
    00618   sscanf(temp,"%f",&val);
    00619   return val;
    00620 }
    00621
    00622 bool Profile::write_float(const char *section, const char *option, const float value) {
    00623   char temp[MAX_VALUE_SIZE];
    00624
    00625   snprintf(temp,MAX_VALUE_SIZE,"%.1f",value);
    00626   if(!cfg_write(profile_path, section, option, temp)) {
    00627     warning("Profile::write_float(%s,%s,%s) : %s",
    00628             section,option,value,profile_path);
    00629     return false;
    00630   }
    00631   return true;
    00632 }
    00633
    00634 bool Profile::read_str(const char *section, const char *option, char *store) {
    00635   if(!cfg_read(profile_path,section,option,store)) {
    00636     warning("Profile::read_str(%s,%s) : %s",
    00637           option,section,profile_path);
    00638     return(false); }
    00639   return(true);
    00640 }
    00641
    00642 bool Profile::write_str(const char *section, const char *option, const char *value) {
    00643   //  func("Profile::write_int(%s,%s,%s)",section,option,value);
    00644   if(!cfg_write(profile_path, section, option, value)) {
    00645     warning("Profile::write_str(%s,%s,%s) : %s",
    00646           section,option,value,profile_path);
    00647     return(false);
    00648   }
    00649   return(true);
    00650 }
    00651