/* this parser deals with variables and groups. it uses VIEWITEMS internally (also accessible by user) and such sort thing from Linuxconf */ /* lame parser 1.0 sep 13th, 2000 by Daniel Mealha Cabrita (dancab@conectiva.com) */ /* this parser is not suitable for multi-layered grouping (as in apache) */ #include "fviews.h" #include #include /* used in what_is_that_string() */ #define NOTHING_SPECIAL 0 #define GROUP_OPENER 1 #define GROUP_CLOSER 2 struct t_parser_control{ CONFIG_FILE *given_config_file; VIEWITEMS_PARSER *given_viewitems_parser; VIEWITEMS *given_viewitems; int total_of_group_rules; SSTRINGS *group_openers, *group_closers; char *header_var_gstring; /* string to add before every varname inside a group */ int add_lf_after_newgroup; /* adds lf just before group-opener when creating a new group, !=0,yes */ int remove_var_if_empty; /* if write empty value, erases var !=0,yes */ int case_sensitive_names; /* for varnames/groupnames identification */ }; /* here the functions you're more likely to use (the other ones are mostly for internal use) */ t_parser_control *init_parser(CONFIG_FILE &given_config_file, char given_sepchar, char given_quotchar); void close_parser(t_parser_control *parser_control); void add_grouping_rule(t_parser_control *parser_control, char *given_group_opener, char *given_group_closer); int fills_sstrings_with_group_openers(t_parser_control *parser_control, SSTRINGS &sstrings_to_fill); void update_file(t_parser_control *parser_control); void write_var_data(t_parser_control *parser_control, const char *given_groupname, const char *given_varname, const char *given_data); void write_var_data(t_parser_control *parser_control, const char *given_groupname, const char *given_varname, const char *given_data, char sepchar, char quotchar); void load_vardata_into(t_parser_control *parser_control, const char *given_groupname, const char *given_varname, SSTRING &put_it_here_please); void load_vardata_into(t_parser_control *parser_control, const char *given_groupname, const char *given_varname, SSTRING &put_it_here_please, const char sepchar, const char quotchar); t_parser_control *init_parser(CONFIG_FILE &given_config_file, char given_sepchar, char given_quotchar) { static char default_header_var_gstring[]=" "; t_parser_control *parser_control=NULL; if((parser_control=(t_parser_control *)malloc(sizeof(t_parser_control)))){ /* defines pointers */ parser_control->given_config_file=&given_config_file; parser_control->given_viewitems_parser=new VIEWITEMS_PARSER; parser_control->given_viewitems=new VIEWITEMS(*(parser_control->given_viewitems_parser)); parser_control->total_of_group_rules=0; parser_control->group_openers=new SSTRINGS; parser_control->group_closers=new SSTRINGS; /* defines default format */ parser_control->given_viewitems_parser->sepchar=given_sepchar; parser_control->given_viewitems_parser->quotchar=given_quotchar; /* reads file data */ parser_control->given_viewitems->read(given_config_file); /* defines extra vars defaults */ /* you may change these just after parser_control initialization */ parser_control->header_var_gstring=default_header_var_gstring; parser_control->add_lf_after_newgroup=1; parser_control->remove_var_if_empty=1; parser_control->case_sensitive_names=0; } return(parser_control); } /* given_group_closer = "\0" if group has no ending mark (see /etc/wine.conf) */ /* ignores anything just after that string (provided_string*) */ void add_grouping_rule(t_parser_control *parser_control, char *given_group_opener, char *given_group_closer) { parser_control->group_openers->add(new SSTRING(given_group_opener)); parser_control->group_closers->add(new SSTRING(given_group_closer)); } /* dumps changes done in parser_control to file */ void update_file(t_parser_control *parser_control) { parser_control->given_viewitems->write(*(parser_control->given_config_file), 0); } /* MUST be called when finishing (does not updates the file, use update_file() for that) */ void close_parser(t_parser_control *parser_control) { if(parser_control){ delete parser_control->given_viewitems_parser; delete parser_control->given_viewitems; delete parser_control->group_openers; delete parser_control->group_closers; free(parser_control); } } /* same as strncmp but if !case_sensitive, it's case insensitive (really?) */ int smart_strncmp(const char *given_string_1, const char *given_string_2, int given_length, int case_sensitive) { if(case_sensitive){ return(strncmp(given_string_1, given_string_2, given_length)); }else{ SSTRING my_shadow_1, my_shadow_2; my_shadow_1.setfrom(given_string_1); my_shadow_1.to_lower(); my_shadow_2.setfrom(given_string_2); my_shadow_2.to_lower(); return(strncmp(my_shadow_1.get(), my_shadow_2.get(), given_length)); } } /* gives the 'real' beginning of a given string (skips the heading spaces, tabs, etc) */ const char *skip_spaces(const char *given_string) { const char *real_str_start; real_str_start=given_string; while((*real_str_start)&&(*real_str_start<33)) real_str_start++; return(real_str_start); } /* returns string length except the tailing spaces */ unsigned int strlen_except_useless_tail(const char *given_string) { int my_strlen; my_strlen=strlen(given_string); while(my_strlen){ if(*(given_string+(my_strlen-1))!=' ') return(my_strlen); my_strlen--; } return(my_strlen); } /* as strcmp() but ignores spaces after and before */ /* 0, equal !=0, not equal */ int smart_string_compare(const char *given_raw_string, const char *what_it_could_be, int case_sensitive) { const char *real_str_start; if(!given_raw_string && !what_it_could_be) return(0); if(!given_raw_string || !what_it_could_be) return(1); real_str_start=skip_spaces(given_raw_string); if(strlen_except_useless_tail(real_str_start)!=strlen(what_it_could_be)) return(1); // return(strncmp(real_str_start, what_it_could_be, strlen(what_it_could_be))); return(smart_strncmp(real_str_start, what_it_could_be, strlen(what_it_could_be), case_sensitive)); } /* 0, equal !=0, not equal */ /* ignores spaces before the varname in given_string */ int compare_the_header(const char *given_header, const char *given_string, int case_sensitive) { const char *real_str_start; /* picks the real start of given_string */ real_str_start=skip_spaces(given_string); if(strlen(real_str_start)case_sensitive_names; work_openers=parser_control->group_openers; work_closers=parser_control->group_closers; total_items=work_openers->getnb(); if(current_group){ // locate the opener-closer pair for the last_group_found while(total_items--){ if(!compare_the_header(work_openers->getitem(total_items)->get(), current_group, case_sensitive)){ if(*(work_closers->getitem(total_items)->get())){ // verify if the given string is not the proper closer.. if(!compare_the_header(work_closers->getitem(total_items)->get(), given_string, case_sensitive)) return(GROUP_CLOSER); this_group_has_a_closer=1; } total_items=0; // escape from loop } } } total_items=work_openers->getnb(); while(total_items--){ if(!compare_the_header(work_openers->getitem(total_items)->get(), given_string, case_sensitive)){ if(this_group_has_a_closer) return(NOTHING_SPECIAL); return(GROUP_OPENER); } } return(NOTHING_SPECIAL); } /* returns true is given string is an assignment for the given varname */ int is_this_var(const char *given_string, const char *given_varname, const char given_separator, int case_sensitive) { const char *real_str_start; char next_char; /* picks the real start of given_string */ real_str_start=skip_spaces(given_string); if(strlen(real_str_start)case_sensitive_names; work_vitems=parser_control->given_viewitems; total_items=work_vitems->getnb(); while(total_items--){ current_string=work_vitems->getitem(my_line)->line.get(); switch(what_is_that_string(parser_control, current_string, current_group)){ case GROUP_OPENER: current_group=current_string; break; case GROUP_CLOSER: current_group=NULL; break; default: if((!smart_string_compare(current_group, given_groupname, case_sensitive))&& (is_this_var(current_string, given_varname, sepchar, case_sensitive))){ return(my_line); } } my_line++; } return(-1); } VIEWITEM *retrieve_var_viewitem(t_parser_control *parser_control, const char *given_groupname, const char *given_varname, const char sepchar, const char quotchar) { int which_line; which_line=retrieve_var_line(parser_control, given_groupname, given_varname, sepchar, quotchar); if(which_line==-1) return(NULL); return(parser_control->given_viewitems->getitem(which_line)); } /* dumps the list of all the found group_openers lines */ /* returns number of group_openers */ int fills_sstrings_with_group_openers(t_parser_control *parser_control, SSTRINGS &sstrings_to_fill) { int my_line=0, total_items; VIEWITEMS *work_vitems; const char *current_string; int total_gopeners=0; const char *current_group=NULL; work_vitems=parser_control->given_viewitems; total_items=work_vitems->getnb(); while(total_items--){ current_string=work_vitems->getitem(my_line)->line.get(); switch(what_is_that_string(parser_control, current_string, current_group)){ case GROUP_OPENER: current_group=current_string; total_gopeners++; sstrings_to_fill.add(new SSTRING(skip_spaces(current_string))); break; case GROUP_CLOSER: current_group=NULL; break; } my_line++; } return(total_gopeners); } /* create a new group (group_opener provided) and returns the line where the group_opener resides */ /* does NOT verify if: - invalid groupname - repeated groupname */ int create_new_group(t_parser_control *parser_control, const char *given_groupname) { VIEWITEMS *work_vitems; int group_line; const char *groupcloser_to_use=NULL; int case_sensitive; case_sensitive=parser_control->case_sensitive_names; work_vitems=parser_control->given_viewitems; /* get the proper groupcloser for groupcloser_to_use */ { int my_loop; my_loop=parser_control->group_openers->getnb(); while(my_loop--){ /* if they match at header level.. */ if(!compare_the_header(parser_control->group_openers->getitem(my_loop)->get(), given_groupname, case_sensitive)){ groupcloser_to_use=parser_control->group_closers->getitem(my_loop)->get(); if(!(*groupcloser_to_use)) // if string is empty, NULLifies the pointer groupcloser_to_use=NULL; my_loop=0; // forces the end of loop } } } if(parser_control->add_lf_after_newgroup) work_vitems->add(new VIEWITEM("")); work_vitems->add(new VIEWITEM(given_groupname)); group_line=work_vitems->getnb()-1; if(groupcloser_to_use) work_vitems->add(new VIEWITEM(groupcloser_to_use)); return(group_line); } /* groupcloser is only needed if the group doesn't exist yet */ /* valid entries for groupname,varname: [something],[something] - var inside a group NULL,[something] - var outside any group */ void write_var_data(t_parser_control *parser_control, const char *given_groupname, const char *given_varname, const char *given_data) { char sepchar, quotchar; sepchar=parser_control->given_viewitems_parser->sepchar; quotchar=parser_control->given_viewitems_parser->quotchar; write_var_data(parser_control, given_groupname, given_varname, given_data, sepchar, quotchar); } /* groupcloser is only needed if the group doesn't exist yet */ /* valid entries for groupname,varname: [something],[something] - var inside a group NULL,[something] - var outside any group */ void write_var_data(t_parser_control *parser_control, const char *given_groupname, const char *given_varname, const char *given_data, const char sepchar, const char quotchar) { VIEWITEM *vitem_to_use; char *my_buff; int group_line=-1; VIEWITEMS *work_vitems; int case_sensitive; case_sensitive=parser_control->case_sensitive_names; work_vitems=parser_control->given_viewitems; /* if variable not found create it (or the group and the variable) */ if(!(vitem_to_use=retrieve_var_viewitem(parser_control, given_groupname, given_varname, sepchar, quotchar))){ /* if no data provided, line not found and empty_lines_to_be_erased.. */ if((parser_control->remove_var_if_empty)&&(!(*given_data))) return; if(given_groupname){ int my_line=0, total_items; const char *current_string; /* search group.. */ total_items=work_vitems->getnb(); while(total_items--){ current_string=work_vitems->getitem(my_line)->line.get(); if(!smart_string_compare(current_string, given_groupname, case_sensitive)){ group_line=my_line; total_items=0; } my_line++; } /* if group doesn't exist, create it.. */ if(group_line==-1) group_line=create_new_group(parser_control, given_groupname); /* creates variable now.. */ vitem_to_use=new VIEWITEM(given_varname); if(group_line==(work_vitems->getnb()-1)){ work_vitems->add(vitem_to_use); }else{ work_vitems->insert(group_line+1, vitem_to_use); } }else{ /* creates variable now.. (out a group) */ vitem_to_use=new VIEWITEM(given_varname); if(!work_vitems->getnb()){ work_vitems->add(vitem_to_use); }else{ work_vitems->insert(0, vitem_to_use); } } }else{ /* if line exists but no data and empty_lines_shall_be_removed.. */ if((parser_control->remove_var_if_empty)&&(!(*given_data))){ work_vitems->remove_del(vitem_to_use); return; } } /* proper VIEWITEM located/allocated so.. */ if((my_buff=(char *)malloc(strlen(given_varname)+strlen(given_data)+4+strlen(parser_control->header_var_gstring)))){ char empty_string[]=""; char *header_string; if(given_groupname){ header_string=parser_control->header_var_gstring; }else{ header_string=empty_string; } if(quotchar){ sprintf(my_buff, "%s%s%c%c%s%c", header_string, given_varname, sepchar, quotchar, given_data, quotchar); }else{ sprintf(my_buff, "%s%s%c%s", header_string, given_varname, sepchar, given_data); } vitem_to_use->line.setfrom(my_buff); free(my_buff); } } /* these two are the main routines for reading var contents */ void load_vardata_into(t_parser_control *parser_control, const char *given_groupname, const char *given_varname, SSTRING &put_it_here_please) { load_vardata_into(parser_control, given_groupname, given_varname, put_it_here_please, parser_control->given_viewitems_parser->sepchar, parser_control->given_viewitems_parser->quotchar); } void load_vardata_into(t_parser_control *parser_control, const char *given_groupname, const char *given_varname, SSTRING &put_it_here_please, const char sepchar, const char quotchar) { VIEWITEM *work_vitem; const char *work_string; int its_datasize; if((work_vitem=retrieve_var_viewitem(parser_control, given_groupname, given_varname, sepchar, quotchar))){ work_string=skip_spaces(work_vitem->line.get()); if((work_string=strchr(work_string, sepchar))){ work_string++; work_string=skip_spaces(work_string); if(quotchar){ if((work_string=strchr(work_string, quotchar))) work_string++; } if((its_datasize=strlen_except_useless_tail(work_string))&"char) its_datasize--; /* here we have ready work_string and its_datasize */ if(its_datasize){ put_it_here_please.setfrom(work_string, its_datasize); return; } } } put_it_here_please.setfrom(""); } /* sends the whole group to the hell */ void remove_group(t_parser_control *parser_control, const char *given_groupname) { int my_line=0, total_items; VIEWITEMS *work_vitems; const char *current_string; int delete_point=-1; // line where all the delete requests will happen const char *current_group=NULL; SSTRING saved_current_group; const char *secondary_current_group; // current_group will be destroyed later, so its data must be saved int case_sensitive; case_sensitive=parser_control->case_sensitive_names; work_vitems=parser_control->given_viewitems; /* finds beginning of group */ total_items=work_vitems->getnb(); while(total_items--){ current_string=work_vitems->getitem(my_line++)->line.get(); switch(what_is_that_string(parser_control, current_string, current_group)){ case GROUP_OPENER: current_group=current_string; if(!smart_string_compare(current_group, given_groupname, case_sensitive)){ total_items=0; // force exit from loop delete_point=--my_line; } break; case GROUP_CLOSER: current_group=NULL; break; default: break; } } if(delete_point==-1) // group not found return; /* now deletes the lines of the group */ saved_current_group.setfrom(current_group); secondary_current_group=saved_current_group.get(); total_items=work_vitems->getnb()-delete_point; work_vitems->remove_del(delete_point); // removes group opener total_items--; // printf("current group: [%s]\n", current_group); // printf("tot items: [%d] delete point: [%d]\n", total_items, delete_point); while(total_items--){ current_string=work_vitems->getitem(delete_point)->line.get(); switch(what_is_that_string(parser_control, current_string, secondary_current_group)){ case GROUP_OPENER: total_items=0; // force exit from loop break; case GROUP_CLOSER: total_items=0; // force exit from loop, then deletes line default: work_vitems->remove_del(delete_point); } } }