/************************************************************************** * *N deselect_feature_class_relate * *::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * Purpose: *P * Clear out a previously allocated feature class relate structure * from memory. *E *::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * History: *H * Barry Michaels DOS Turbo C *E *************************************************************************/ void deselect_feature_class_relate( fcrel_type *fcrel ) { register int i; if (fcrel->nchain > 0) { for (i=0;i<fcrel->nchain;i++) { if (fcrel->table[i].status == OPENED) { vpf_close_table(&(fcrel->table[i])); } } free(fcrel->table); ll_reset(fcrel->relate_list); } fcrel->nchain = 0; }
/************************************************************************* * *N query_table * *:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * Purpose: *P * This function returns the set of selected rows of a VPF table * based upon the evaluation of the given selection expression string. * * The expression is strictly evaluated left to right. No nesting * is supported, so parentheses are not allowed. The expression * must match the form: * <field><log op><value> [ <join> <field><log op><value>] * where, * <field> is a valid field name of the table. * <log op> is one of the following: =, <, >, <=, >=, <> (not equal). * <value> is a valid value for the field. * <join> is either " AND " or " OR ". * Any number of clauses (<field><log op><value>) may be joined * together with AND or OR to form the expression. *E *:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * Parameters: *A * expression <input>==(char *) selection expression string. * table <input>==(vpf_table_type) VPF table structure. * return <output>==(set_type) set of selected rows. *E *:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * History: *H * Barry Michaels May 1991 DOS Turbo C *E *:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * External Variables: *X * None *E *:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * Functions Called: *F * set_type set_init( rspf_int32 n ) SET.C * void set_insert( rspf_int32 element, set_type set ) SET.C * linked_list_type parse_expression( char *expression, * vpf_table_type table ) VPFQUERY.C * row_type read_next_row( vpf_table_type table ) VPFREAD.C * position_type ll_first( linked_list_type list ) LINKLIST.C * int ll_end( position_type position ) LINKLIST.C * void ll_element( position_type position, void *element ) LINKLIST.C * void *get_table_element( rspf_int32 field_number, * row_type row, * vpf_table_type table, * void *value, * rspf_int32 *count ) VPFREAD.C * void display_message( char *info ) USER DEFINED * static int strcompare( char *val1, char *val2, char op ) VPFQUERY.C * static int icompare( rspf_int32 val1, rspf_int32 val2, char op ) VPFQUERY.C * static int fcompare( float val1, float val2, char op ) VPFQUERY.C * void ll_reset( linked_list_type list ) LINKLIST.C void free_row( row_type row, vpf_table_type table) VPFREAD.C *E *************************************************************************/ set_type query_table( char *expression, vpf_table_type table ) { row_type row; position_type pos; expr_type expr; register rspf_int32 i; int boolval=FALSE, booltemp=0, join = OR; rspf_int32 lval, lval2, count; float fval, fval2; char tval, tval2, *tptr; linked_list_type exprlist; set_type select_set; select_set = set_init(table.nrows+1); if (strcmp(expression,"*")==0) { set_on(select_set); return select_set; } exprlist = parse_expression( expression, table ); if (!exprlist) return select_set; if (table.storage == DISK) fseek( table.fp, index_pos(1,table), SEEK_SET ); for (i=1;i<=table.nrows;i++) { if (table.storage == DISK) row = read_next_row(table); else row = get_row( i, table ); pos = ll_first(exprlist); while (!ll_end(pos)) { ll_element( pos, &expr ); switch (table.header[expr.field].type) { case 'I': if (table.header[expr.field].count == 1) { get_table_element( expr.field, row, table, &lval, &count ); lval2 = atol(expr.value); booltemp = icompare( lval, lval2, expr.op ); } else { display_message( "Selection may not be performed upon arrays"); i=table.nrows+1; } break; case 'T': if (table.header[expr.field].count == 1) { get_table_element( expr.field, row, table, &tval, &count ); tval2 = expr.value[0]; booltemp = comp( &tval, &tval2, sizeof(tval), expr.op ); } else { tptr = (char *)get_table_element( expr.field, row, table, NULL, &count ); booltemp = strcompare( tptr, expr.value, expr.op ); free(tptr); } break; case 'F': if (table.header[expr.field].count == 1) { get_table_element( expr.field, row, table, &fval, &count ); if (!is_vpf_null_float(fval)) { fval2 = (float)atof(expr.value); booltemp = fcompare( fval, fval2, expr.op ); } else booltemp = FALSE; } else { display_message( "Selection may not be performed upon arrays"); i=table.nrows+3; } break; default: display_message("Field type not supported for query"); i=table.nrows+3; break; } if (i>table.nrows) break; if (join==OR) boolval = boolval || booltemp; else boolval = boolval && booltemp; join = expr.join; pos = pos->next; } free_row( row, table ); if (boolval) set_insert(i,select_set); boolval = FALSE; join = OR; if (i==table.nrows+3) break; } ll_reset(exprlist); return select_set; }
/************************************************************************* * *N parse_expression * *:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * Purpose: *P * This function returns a list of selection expression clause * structures. This list forms the internal structure of the query * expression. *E *:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * Parameters: *A * expression <input>==(char *) selection expression string. * table <input>==(vpf_table_type) VPF table structure. * return <output>==(linked_list_type) list of expression clauses. *E *:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * History: *H * Barry Michaels May 1991 DOS Turbo C *E *:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * External Variables: *X * None *E *:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * Functions Called: *F * char *get_token( char *expression, char *token, int *token_type, * int *token_value) VPFQUERY.C * void display_message( char *input) USER DEFINED * linked_list_type ll_init() LINKLIST.C * void ll_reset( linked_list_type list ) LINKLIST.C * void ll_insert( void *element, unsigned size, * position_type position ) LINKLIST.C *E *************************************************************************/ static linked_list_type parse_expression( char *expression, vpf_table_type table ) { linked_list_type exprlist; position_type pos; expr_type expr; int i, token_type, token_value; char token[260]; exprlist = ll_init(); pos = exprlist; /* Set up static globals */ nfields = table.nfields; fieldname = (char **)memalloc( (nfields+2) * sizeof(char *) ); fieldcol = (int *)memalloc( (nfields+2) * sizeof(int) ); for (i=0;i<table.nfields;i++) { fieldname[i] = (char *)memalloc(40*sizeof(char)); strcpy(fieldname[i], table.header[i].name); fieldcol[i] = i; } /*****/ expression = get_token( expression, token, &token_type, &token_value ); while (token_type != FINISHED) { if (token_type != FIELD) { display_message("Expression syntax error -- Invalid field name"); ll_reset(exprlist); exprlist = NULL; break; } expr.field = token_value; expression = get_token( expression, token, &token_type, &token_value ); if (token_type != LOP) { display_message("Expression syntax error"); ll_reset(exprlist); exprlist = NULL; break; } expr.op = (char)token_value; expression = get_token( expression, token, &token_type, &token_value ); if (token_type == ERROR) { display_message("Expression syntax error"); ll_reset(exprlist); exprlist = NULL; break; } strcpy(expr.value,token); expression = get_token( expression, token, &token_type, &token_value ); if (token_type == JOIN) { expr.join = (char)token_value; ll_insert( &expr, sizeof(expr), pos ); pos = pos->next; expression = get_token( expression, token, &token_type, &token_value ); } else if (token_type == FINISHED) { expr.join = '\0'; ll_insert( &expr, sizeof(expr), pos ); } else { display_message("Expression syntax error"); ll_reset(exprlist); exprlist = NULL; break; } } for (i=0;i<nfields;i++) free(fieldname[i]); free(fieldname); free(fieldcol); return exprlist; }
/************************************************************************** * *N fc_row_numbers * *::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * Purpose: *P * Given the starting row of a feature class relationship, return the * list of row numbers of the table at the end of the feature class * relate chain. * If your relate goes from the feature to the primitive, this will * return the primitive ids for the given feature row. * If your relate goes from the primitive to the feature, this will * return the feature ids of the given primitive row. * * Currently only supports relates on 'I' or 'K' fields. *E *::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * History: *H * Barry Michaels DOS Turbo C *E *************************************************************************/ linked_list_type fc_row_numbers( row_type row, fcrel_type fcrel, long int tile, ThematicIndex *idx ) { row_type relrow; long int count; long int n, rownum, keyval; id_triplet_type triplet_keyval; int KEY1_, KEY_; position_type p, prow, pkey; vpf_relate_struct rcell; linked_list_type rowlist, keylist, templist; p = ll_first(fcrel.relate_list); ll_element(p,&rcell); KEY1_ = table_pos(rcell.key1,fcrel.table[0]); get_table_element(0,row,fcrel.table[0],&rownum,&count); if (KEY1_ == 0) { /* "ID" */ keyval = rownum; } else { switch (fcrel.table[0].header[KEY1_].type) { case 'I': get_table_element(KEY1_,row,fcrel.table[0],&keyval,&count); break; case 'K': get_table_element(KEY1_,row,fcrel.table[0],&triplet_keyval, &count); keyval = triplet_keyval.exid; if (tile != triplet_keyval.tile) { keyval = -2; } break; default: keyval = 0; break; } } keylist = ll_init(); ll_insert(&keyval,sizeof(keyval),keylist); n = 0; p = ll_first(fcrel.relate_list); for (n=1;n<(fcrel.nchain-1);n++) { /* Relate through Join table(s) */ rowlist = ll_init(); pkey = ll_first(keylist); while (!ll_end(pkey)) { ll_element(pkey,&keyval); templist = related_rows(&keyval,fcrel.table[n],rcell.key2,0,NULL); prow = ll_first(templist); while (!ll_end(prow)) { ll_element(prow,&rownum); if (!ll_locate(&rownum,rowlist)) ll_insert(&rownum,sizeof(rownum),ll_last(rowlist)); prow = ll_next(prow); } ll_reset(templist); pkey = ll_next(pkey); } ll_reset(keylist); p = ll_next(p); ll_element(p,&rcell); KEY_ = table_pos(rcell.key1,fcrel.table[n]); keylist = ll_init(); prow = ll_first(rowlist); while (!ll_end(prow)) { ll_element(prow,&rownum); relrow = get_row(rownum,fcrel.table[n]); if (KEY_ == 0) { /* "ID" */ keyval = rownum; } else { switch (fcrel.table[n].header[KEY_].type) { case 'I': get_table_element(KEY_,relrow,fcrel.table[n],&keyval,&count); break; case 'K': get_table_element(KEY_,relrow,fcrel.table[n],&triplet_keyval, &count); keyval = triplet_keyval.exid; if (tile != triplet_keyval.tile) { keyval = -2; } break; default: keyval = 0; break; } } if (keyval > 0) ll_insert(&keyval,sizeof(keyval),ll_last(keylist)); prow = ll_next(prow); free_row(relrow,fcrel.table[n]); } ll_reset(rowlist); } rowlist = ll_init(); p = ll_first(keylist); while (!ll_end(p)) { ll_element(p,&keyval); templist = related_rows(&keyval,fcrel.table[n],rcell.key2,0,idx); prow = ll_first(templist); while (!ll_end(prow)) { ll_element(prow,&rownum); if (!ll_locate(&rownum,rowlist)) ll_insert(&rownum,sizeof(rownum),ll_last(rowlist)); prow = ll_next(prow); } ll_reset(templist); p = ll_next(p); } ll_reset(keylist); return rowlist; }
/************************************************************************** * *N select_feature_class_relate * *::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * Purpose: *P * Set up the relationships between features and primitives or between * primitives and features (one way only) for a specified feature class. *E *::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * History: *H * Barry Michaels DOS Turbo C *E *************************************************************************/ fcrel_type select_feature_class_relate( int fcnum, library_type *library, char *start_table, char *end_table ) { int storage, cov; vpf_table_type fcs; long int i; char path[255], covpath[255]; position_type p; vpf_relate_struct rcell; fcrel_type fcrel; fcrel.nchain = 0; fcrel.table = NULL; fcrel.relate_list = NULL; cov = library->fc[fcnum].coverage; strcpy(covpath,library->cover[cov].path); rightjust(covpath); sprintf( path, "%sfcs", covpath ); /* Feature Class Schema table */ fcs = vpf_open_table( path, disk, "rb", NULL ); fcrel.relate_list = fcs_relate_list( library->fc[fcnum].name, start_table,end_table, fcs ); if (ll_empty(fcrel.relate_list)) { ll_reset(fcrel.relate_list); displaymessage("ERROR in feature class relationship!", start_table,end_table,NULL); return fcrel; } /* Find the number of tables in the relate chain */ p = ll_first(fcrel.relate_list); fcrel.nchain = 0; while (!ll_end(p)) { fcrel.nchain++; p = ll_next(p); } /* Allow for last table2 */ fcrel.nchain++; fcrel.table = (vpf_table_type *) vpfmalloc((fcrel.nchain+1)* sizeof(vpf_table_type)); for (i=0;i<fcrel.nchain+1;i++) vpf_nullify_table( &(fcrel.table[i]) ); p = ll_first(fcrel.relate_list); for (i=0;i<fcrel.nchain-1;i++) { ll_element(p,&rcell); /** Can't open primitive table - may be several under tile **/ /** directories. Open all others **/ if (!is_primitive(rcell.table1)) { sprintf(path,"%s%s",covpath,rcell.table1); if (is_join(rcell.table1)) storage = ram; else storage = disk; fcrel.table[i] = vpf_open_table(path,(storage_type)storage,"rb",NULL); } if (!ll_end(p)) p = ll_next(p); } /* End of relate chain */ i = fcrel.nchain-1; if (!is_primitive(rcell.table2)) { sprintf(path,"%s%s",covpath,rcell.table2); storage = disk; fcrel.table[i] = vpf_open_table(path,(storage_type)storage,"rb",NULL); } vpf_close_table( &fcs ); return fcrel; }
/************************************************************************* * *N get_selected_tile_primitives * *:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * Purpose: *P * This function determines all of the selected primitive rows from * the selected features of a given tile. * * This function expects a feature class relationship structure that * has been successfully created with select_feature_class_relate() * from the feature table to the primitive. The primitive table in * the feature class relate structure must have been successfully * opened for the given tile. *E *:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * Parameters: *A * library <input>==(library_type *) VPF library structure. * fcnum <input>==(int) feature class number of the feature table. * fcrel <input>==(fcrel_type) feature class relate structure. * feature_rows <input>==(set_type) set of selected features. * mapenv <input>==(map_environment_type *) map environment. * tile <input>==(rspf_int32) tile number. * tiledir <input>==(char *) path to the tile directory. * status <output>==(int *) status of the function: * 1 if completed, 0 if user escape. * return <output>==(set_type) set of primitives for the features * in the corresponding tile. *E *:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * History: *H * Barry Michaels May 1991 DOS Turbo C *E *************************************************************************/ set_type get_selected_tile_primitives( library_type *library, int fcnum, fcrel_type fcrel, set_type feature_rows, map_environment_type *mapenv, rspf_int32 tile, char *tiledir, int *status ) { int cov, degree; int feature, prim; row_type row; char *spxname[] = {"","esi","fsi","tsi","nsi","csi"}; char *brname[] = {"","ebr","fbr","tbr","nbr","cbr"}; set_type primitive_rows, tile_features; set_type primitives; rspf_int32 prim_rownum; register rspf_int32 i,pclass, start,end; char path[255], covpath[255]; linked_list_type primlist; position_type p; vpf_relate_struct rcell; ThematicIndex idx; feature = 0; prim = fcrel.nchain-1; /* Assume that fcrel.table[prim] has been opened */ primitives.size = 0; primitives.buf = NULL; cov = library->fc[fcnum].coverage; strcpy( covpath, library->cover[cov].path ); p = ll_previous(ll_last(fcrel.relate_list),fcrel.relate_list); ll_element(p,&rcell); degree = rcell.degree; for (pclass=EDGE;pclass<=CONNECTED_NODE;pclass++) { if ((pclass != library->fc[fcnum].primclass) && (library->fc[fcnum].primclass != COMPLEX_FEATURE)) continue; primitives = set_init(fcrel.table[prim].nrows+1); /* Get the set of primitive rows within the map extent */ /* Look for the spatial index file to weed out primitives in the */ /* given tile but outside of the viewing area. If a projection */ /* other than plate-carree (rectangular) is on, or if the extent */ /* crosses the meridian, the quick check is no longer valid. */ primitive_rows.size = 0; if (mapenv->projection == PLATE_CARREE && mapenv->mapextent.x1 < mapenv->mapextent.x2) { sprintf(path,"%s%s%s",covpath,tiledir,spxname[pclass]); /* 20 (below) is a fairly arbitrary cutoff of the number of */ /* primitives that make a spatial index search worth while. */ if ((access(path,0)==0)&&(fcrel.table[prim].nrows > 20)) { primitive_rows = spatial_index_search(path, mapenv->mapextent.x1,mapenv->mapextent.y1, mapenv->mapextent.x2,mapenv->mapextent.y2); } else { /* Next best thing - bounding rectangle table */ sprintf(path,"%s%s%s",covpath,tiledir,brname[pclass]); if ((access(path,0)==0)&&(fcrel.table[prim].nrows > 20)) { primitive_rows = bounding_select(path,mapenv->mapextent, library->dec_degrees); } } } if (primitive_rows.size == 0) { /* Search through all the primitives */ primitive_rows=set_init(fcrel.table[prim].nrows+1); set_on(primitive_rows); } if (strcmp(tiledir,"") != 0) { tile_thematic_index_name(fcrel.table[feature], path); if ((strcmp(path,"")!=0) && (access(path,4)==0)) { /* Tile thematic index for feature table present, */ tile_features = read_thematic_index( path, (char *)&tile ); } else { tile_features = set_init(fcrel.table[feature].nrows+1); set_on(tile_features); } } else { tile_features = set_init(fcrel.table[feature].nrows+1); set_on(tile_features); } set_delete(0,tile_features); idx.fp = NULL; i = table_pos(rcell.key2,fcrel.table[prim]); if (i >= 0) { if (fcrel.table[prim].header[i].tdx) { sprintf(path,"%s%s",fcrel.table[prim].path, fcrel.table[prim].header[i].tdx); if (access(path,0)==0) idx = open_thematic_index(path); } if (fcrel.table[prim].header[i].keytype == 'U') degree = R_ONE; if (fcrel.table[prim].header[i].keytype == 'N') degree = R_MANY; if (fcrel.table[prim].header[i].keytype == 'P') degree = R_ONE; } start = set_min(tile_features); end = set_max(tile_features); /* It turns out to be MUCH faster off of a CD-ROM to */ /* read each row and discard unwanted ones than to */ /* forward seek past them. It's about the same off */ /* of a hard disk. */ fseek(fcrel.table[feature].fp,index_pos(start,fcrel.table[feature]), SEEK_SET); for (i=start;i<=end;i++) { row = read_next_row(fcrel.table[feature]); if (!set_member( i, feature_rows )) { free_row(row,fcrel.table[feature]); continue; } if (!set_member( i, tile_features )) { free_row(row,fcrel.table[feature]); continue; } if (degree == R_ONE) { prim_rownum = fc_row_number( row, fcrel, tile ); primlist = NULL; p = NULL; } else { primlist = fc_row_numbers( row, fcrel, tile, &idx ); } free_row( row, fcrel.table[feature] ); if (!primlist) { if ((prim_rownum<1)||(prim_rownum>fcrel.table[prim].nrows)) continue; if (set_member( prim_rownum, primitive_rows )) { set_insert(prim_rownum,primitives); } } else { p = ll_first(primlist); while (!ll_end(p)) { ll_element(p,&prim_rownum); if ((prim_rownum<1)|| (prim_rownum>fcrel.table[prim].nrows)) continue; if (set_member( prim_rownum, primitive_rows )) { set_insert(prim_rownum,primitives); } p = ll_next(p); } } if (primlist) ll_reset(primlist); if (kbhit()) { if (getch()==27) { *status = 0; break; } } } set_nuke(&primitive_rows); set_nuke(&tile_features); if (idx.fp) close_thematic_index(&idx); *status = 1; if (kbhit()) { if (getch()==27) { *status = 0; break; } } } return primitives; }
static void read_cf(void) { char tmp[0x100], lv[0x20], rv[0x20]; struct conf_item *ci = NULL; FILE *fd; size_t len; int lnum, found, v_int; char *lp, *conv_err; bool file_needs_update = false; char *cfname = get_confname(); if (access(cfname, F_OK) != 0) goto done; fd = fopen(cfname, "r"); if (fd == NULL) err_sys("can not read configuration file '%s'", cfname); for (lnum = 1; fgets(tmp, sizeof(tmp), fd); lnum++) { lp = tmp + strspn(tmp, " "); if (*lp == '#' || *lp == '\n') continue; len = strcspn(lp, " ="); if (len > sizeof(lv)) err_quit("parse error in %s, line %d: identifier too long", cfname, lnum); strncpy(lv, lp, len); lv[len] = '\0'; lp += len; ll_reset(conf_items); for (found = 0; !found && (ci = ll_getall(conf_items)); ) found = (ci->type != t_sep && ci->type != t_func && strcasecmp(ci->cfname, lv) == 0); if (!found) { err_msg("%s, line %d: ignoring unknown identifier '%s'", cfname, lnum, lv); file_needs_update = true; continue; } lp += strspn(lp, " "); if (*lp++ != '=') err_quit("parse error in %s, line %d: missing '=' operator in assignment", cfname, lnum); lp += strspn(lp, " "); len = strcspn(lp, " \n"); if (len > sizeof(rv)) err_quit("parse error in %s, line %d: argument too long", cfname, lnum); else if (*lp == '\n') err_quit("parse error in %s, line %d: argument expected", cfname, lnum); strncpy(rv, lp, len); rv[len] = '\0'; switch (ci->type) { case t_int: v_int = strtol(rv, &conv_err, 10); if (*conv_err != '\0') { err_quit("parse error in %s, line %d: integer value expected, '%s' found instead", cfname, lnum, rv); } else if (v_int > ci->max) { err_msg("%s, line %d: value exceeds maximum of %d - using maximum", cfname, lnum, (int)ci->max); *ci->v.i = ci->max; file_needs_update = true; } else if (v_int < ci->min) { err_msg("%s, line %d: value is below minimum of %d - using minimum", cfname, lnum, (int)ci->min); *ci->v.i = ci->min; file_needs_update = true; } else { *ci->v.i = v_int; } break; case t_list: assert(ci->list != NULL); if (!argv_count(ci->list)) err_quit("no usable %s candidates available for '%s'", ci->name, rv); v_int = argv_find(ci->list, rv); if (v_int < 0) { err_msg("%s, line %d: '%s = %s' is not valid - using defaults", cfname, lnum, lv, rv); file_needs_update = true; } else { *ci->v.i = v_int; } case t_sep: case t_func: break; } } fclose(fd); done: free(cfname); if (file_needs_update) { write_cf(); } }
static void write_cf(void) { char tmp[0x100], rv[0x40]; struct conf_item *ci = NULL; char *lp, *cp; int add, i; char *cfname = get_confname(); int cfld = ll_create(); FILE *fd = fopen(cfname, "w"); if (fd == NULL) err_sys("failed to open configuration file '%s'", cfname); for (ll_reset(conf_items); (ci = ll_getall(conf_items)); ) { if (ci->type != t_sep && ci->type != t_func && (!ci->dep || (ci->dep && *ci->dep))) { switch (ci->type) { case t_int: sprintf(rv, "%d", *ci->v.i); break; case t_list: if (!argv_count(ci->list)) continue; sprintf(rv, "%s", ci->list[*ci->v.i]); str_tolower(rv); break; case t_sep: case t_func: break; } add = 1; for (i = 0; i < ll_size(cfld); i++) { lp = ll_get(cfld, i); cp = lp += strspn(lp, " "); if (!strncasecmp(cp, ci->cfname, strcspn(cp, " =")) && strlen(ci->cfname) == strcspn(cp, " =")) { add = 0; cp += strcspn(cp, "=") + 1; cp += strspn(cp, " "); strncpy(tmp, cp, strcspn(cp, " #\n")); if (strcasecmp(tmp, rv)) { strncpy(tmp, lp, strcspn(lp, " =")); tmp[strcspn(lp, " =")] = '\0'; strcat(tmp, " = "); strcat(tmp, rv); strcat(tmp, "\n"); ll_replace(cfld, i, "s", tmp); } } } if (add) { strcpy(tmp, ci->cfname); strcat(tmp, " = "); strcat(tmp, rv); strcat(tmp, "\n"); ll_push(cfld, "s", tmp); } } } for (ll_reset(cfld); (lp = ll_getall(cfld)); ) fputs(lp, fd); fclose(fd); ll_destroy(cfld); free(cfname); }