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   

Generated on Sat Apr 17 17:38:49 2004 for MuSE by doxygen1.3