00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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
00047
00048 if(str[0]!='[') return(NULL);
00049
00050 if (!sscanf(str, "[%[^]]]", section_tmp))
00051 return(NULL);
00052
00053
00054
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
00066 if (sscanf(str, "%[^= ] = %[^=\n]", option_tmp, value_tmp) != 2)
00067 return NULL;
00068
00069
00070 res[0] = strdup(option_tmp);
00071
00072
00073 res[1] = strdup(value_tmp);
00074
00075
00076
00077
00078 return res;
00079 }
00080
00081
00082
00083
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
00090
00091
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
00102
00103
00104 if (tmp[0] == '#'
00105 || tmp[0] == '\r'
00106 || tmp[0] == '\n'
00107 || tmp[0]=='\0')
00108 continue;
00109
00110
00111 sect = is_a_section(tmp);
00112 if(sect) {
00113
00114 if (!strncmp(sect,section,MAX_SECTION_SIZE)) {
00115 offset = pos;
00116 free(sect);
00117 break;
00118 } else free(sect);
00119 }
00120 }
00121
00122
00123 fseek(fp,bck,SEEK_SET);
00124
00125 return offset;
00126 }
00127
00128
00129
00130
00131
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
00139
00140
00141 bck = ftell(fp);
00142
00143
00144 fseek(fp, section_offset, SEEK_SET);
00145 fgets(tmp, MAX_LINE_SIZE, fp);
00146
00147 while (!feof(fp)) {
00148
00149 pos = ftell(fp);
00150 if(!fgets(tmp, MAX_LINE_SIZE, fp)) break;
00151
00152 chomp(tmp);
00153
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;
00162
00163 res = parse_option(tmp);
00164 if(res) {
00165 if (!strncmp(res[0], option, MAX_OPTION_SIZE)) {
00166 if(value) strncpy(value,res[1],MAX_VALUE_SIZE);
00167 offset = pos;
00168
00169 break;
00170 }
00171
00172 }
00173 }
00174
00175
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;
00185 unsigned int section = 0;
00186 unsigned int err = 0;
00187 char buff[MAX_LINE_SIZE];
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
00199 while (fgets(buff, MAX_LINE_SIZE, fd)) {
00200
00201 line++;
00202
00203 chomp(buff);
00204
00205
00206 if (*buff == '#'
00207 || *buff == '\r'
00208 || *buff == '\n'
00209 || *buff == '\0')
00210 continue;
00211
00212 if ((sect = is_a_section(buff))) {
00213 section = 1;
00214 free(sect);
00215 } else if ((res = parse_option(buff))) {
00216 if (!section) {
00217
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
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
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
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
00278
00279 if (stat(file, &st) == -1) {
00280
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) {
00298 func("cfg_write() : create new section [%s]",section);
00299
00300
00301 fseek(fd, 0, SEEK_END);
00302 fprintf(fd, "\n[%s]\n%s = %s\n\n", section,option,value);
00303
00304 fclose(fd);
00305 return(true);
00306 }
00307
00308 option_offset = find_option(fd, option, val, section_offset);
00309
00310 if(option_offset>0)
00311 if(!strncmp(val,value,MAX_VALUE_SIZE)) {
00312 fclose(fd);
00313 return(true);
00314 }
00315
00316
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) {
00325
00326 fseek(fd, option_offset, SEEK_SET);
00327 fgets(tmp, MAX_LINE_SIZE, fd);
00328
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 {
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
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);
00378
00379 option_offset = find_option(fd, option, NULL, section_offset);
00380 if(option_offset < 0) return(0);
00381
00382
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
00391 fseek(fd,option_offset,SEEK_SET);
00392 fgets(tmp,MAX_LINE_SIZE,fd);
00393
00394
00395 while (!fgets(tmp, MAX_LINE_SIZE, fd))
00396 fputs(tmp, tmp_fp);
00397
00398
00399 ftruncate(fileno(fd), option_offset);
00400
00401
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
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
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
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
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);
00466 if(stat(profile_path, &st) == -1) return(false);
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
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
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
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