/**=========== Example of Use =============**/ int main(int argc, char * argv[]) { if (argc < 2) { std::cout << "Use: '-read' or '-write'" << std::endl; return -1; } string file_path = "example.txt"; ///Write if (strcmp(argv[1],"-write") == 0) { if (write_comment(file_path, 1, "//Example File Config") == -1)//if file does not exist return -1 { cout << "File Does Not Exist!" << std::endl; return -1; } write_comment(file_path, 2, ""); write_comment(file_path, 3, "//Video Config"); write_variable(file_path, "width", "1024"); write_variable(file_path, "height", "720"); write_variable(file_path, "mode", "fullscreen"); return 0; } ///Read if (strcmp(argv[1],"-read") == 0) { int width; int height; string mode; width = atoi(read_variable(file_path, "width").c_str()); height = atoi(read_variable(file_path, "height").c_str()); mode = read_variable(file_path, "mode");//if file does not exist return "null" std::cout << "Width = " << width << std::endl; std::cout << "Height = " << height << std::endl; std::cout << "Mode = " << mode << std::endl; return 0; } //invalid else { std::cout << "Use: '-read' or '-write'" << std::endl; return -1; } }
static void read_cmd_newindex( Transport *tpt, lua_State *L ) { uint32_t len; char *funcname; char *token = NULL; // read function name len = transport_read_uint32_t( tpt ); // function name string length funcname = ( char * )alloca( len + 1 ); transport_read_string( tpt, funcname, len ); funcname[ len ] = 0; // get function // @@@ perhaps handle more like variables instead of using a long string? // @@@ also strtok is not thread safe if( strlen( funcname ) > 0 ) { token = strtok( funcname, "." ); lua_getglobal( L, token ); token = strtok( NULL, "." ); while( token != NULL ) { lua_getfield( L, -1, token ); lua_remove( L, -2 ); token = strtok( NULL, "." ); } read_variable( tpt, L ); // key read_variable( tpt, L ); // value lua_settable( L, -3 ); // set key to value on indexed table } else { read_variable( tpt, L ); // key read_variable( tpt, L ); // value lua_setglobal( L, lua_tostring( L, -2 ) ); } // Write out 0 to indicate no error and that we're done transport_write_uint8_t( tpt, 0 ); // if ( error_code ) // Add some error handling later // { // size_t len; // const char *errmsg; // errmsg = lua_tolstring (L, -1, &len); // transport_write_uint8_t( tpt, 1 ); // transport_write_uint32_t( tpt, error_code ); // transport_write_uint32_t( tpt, len ); // transport_write_string( tpt, errmsg, len ); // } // empty the stack lua_settop ( L, 0 ); }
// read a table and push in onto the stack static void read_table( Transport *tpt, lua_State *L ) { int table_index; lua_newtable( L ); table_index = lua_gettop( L ); for ( ;; ) { if( !read_variable( tpt, L ) ) return; read_variable( tpt, L ); lua_rawset( L, table_index ); } }
static MonoDebugMethodJitInfo * mono_debug_read_method (MonoDebugMethodAddress *address) { MonoDebugMethodJitInfo *jit; guint32 i; guint8 *ptr; jit = g_new0 (MonoDebugMethodJitInfo, 1); jit->code_start = address->code_start; jit->code_size = address->code_size; ptr = (guint8 *) &address->data; jit->prologue_end = read_leb128 (ptr, &ptr); jit->epilogue_begin = read_leb128 (ptr, &ptr); jit->num_line_numbers = read_leb128 (ptr, &ptr); jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers); for (i = 0; i < jit->num_line_numbers; i++) { MonoDebugLineNumberEntry *lne = &jit->line_numbers [i]; lne->il_offset = read_sleb128 (ptr, &ptr); lne->native_offset = read_sleb128 (ptr, &ptr); } jit->has_var_info = read_leb128 (ptr, &ptr); if (jit->has_var_info) { if (*ptr++) { jit->this_var = g_new0 (MonoDebugVarInfo, 1); read_variable (jit->this_var, ptr, &ptr); } jit->num_params = read_leb128 (ptr, &ptr); jit->params = g_new0 (MonoDebugVarInfo, jit->num_params); for (i = 0; i < jit->num_params; i++) read_variable (&jit->params [i], ptr, &ptr); jit->num_locals = read_leb128 (ptr, &ptr); jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals); for (i = 0; i < jit->num_locals; i++) read_variable (&jit->locals [i], ptr, &ptr); if (*ptr++) { jit->gsharedvt_info_var = g_new0 (MonoDebugVarInfo, 1); jit->gsharedvt_locals_var = g_new0 (MonoDebugVarInfo, 1); read_variable (jit->gsharedvt_info_var, ptr, &ptr); read_variable (jit->gsharedvt_locals_var, ptr, &ptr); } } return jit; }
T read_variable(const char *name) const { static_assert(std::is_trivial<T>::value, "Cannot read a non-trivial type"); T res; read_variable(name, &res, sizeof(T)); return res; }
static EFI_STATUS get_info(CHAR16 *name, update_table *info_out) { EFI_STATUS rc; update_info *info = NULL; UINTN info_size = 0; UINT32 attributes = 0; void *info_ptr = NULL; rc = read_variable(name, fwupdate_guid, &info_ptr, &info_size, &attributes); if (EFI_ERROR(rc)) return rc; info = (update_info *)info_ptr; if (info_size < sizeof (*info)) { Print(L"Update \"%s\" is is too small.\n", name); delete_variable(name, fwupdate_guid, attributes); return EFI_INVALID_PARAMETER; } if (info_size - sizeof (EFI_DEVICE_PATH) <= sizeof (*info)) { Print(L"Update \"%s\" is malformed, " L"and cannot hold a file path.\n", name); delete_variable(name, fwupdate_guid, attributes); return EFI_INVALID_PARAMETER; } EFI_DEVICE_PATH *hdr = (EFI_DEVICE_PATH *)&info->dp; INTN is = EFI_FIELD_OFFSET(update_info, dp); if (is > (INTN)info_size) { Print(L"Update \"%s\" has an invalid file path.\n" L"Device path offset is %d, but total size is %d\n", name, is, info_size); delete_variable(name, fwupdate_guid, attributes); return EFI_INVALID_PARAMETER; } is = info_size - is; INTN sz = dp_size(hdr, info_size); if (sz < 0 || is < 0) { invalid_size: Print(L"Update \"%s\" has an invalid file path.\n" L"update info size: %d dp size: %d size for dp: %d\n", name, info_size, sz, is); delete_variable(name, fwupdate_guid, attributes); return EFI_INVALID_PARAMETER; } if (is > (INTN)info_size) goto invalid_size; if (is != sz) goto invalid_size; info_out->info = info; info_out->size = info_size; info_out->attributes = attributes; return EFI_SUCCESS; }
// read function and load static void read_function( Transport *tpt, lua_State *L ) { const char *b; size_t len; for( ;; ) { if( !read_variable( tpt, L ) ) return; b = luaL_checklstring( L, -1, &len ); luaL_loadbuffer( L, b, len, b ); lua_insert( L, -2 ); lua_pop( L, 1 ); } }
static int helper_get( lua_State *L, Helper *helper ) { struct exception e; int freturn = 0; Transport *tpt = helper->handle; Try { helper_wait_ready( tpt, RPC_CMD_GET ); helper_remote_index( helper ); read_variable( tpt, L ); freturn = 1; } Catch( e ) { freturn = generic_catch_handler( L, helper->handle, e ); } return freturn; }
static int32_t cfg_read_variable(FILE*file, long *start, long* finish) { long begin; long end; char c; while (1) { c = cfg_read_first_noblank(file); if (c == '#') { cfg_skip_comment_line(file); continue; } else if( c == EOF) { *start = *finish = 0; return 0; } break; } begin = ftell(file)-1; cfg_read_variable_line(file); end = ftell(file); *start = begin; *finish = end; #if 0 if(begin == end) { assert(fgetc(file) == EOF); return 0; } fseek(file, begin, SEEK_SET); return read_variable(file, end - begin, variable); #endif return 0; }
/* returns -1 on error */ static char* getstring(struct VarSet *const varset, const char *rd, int *const len, char **const ptr) { struct Variable *v; int i; if(*rd == '\"'){ i = 0; *ptr = (char*) ++rd; while(*rd++ != '\"') i++; *len = i; }else if(isalpha(*rd)){ rd = read_variable(varset, rd, &v); *len = strlen(v->val_s); *ptr = v->val_s; }else{ error("variable or string literal expected"); } return (char*) rd; }
/** * 配置解析 * @param[in] file 配置文件 * @param[in] item_tbl 配置项表 * @param[in] max_size 最大配置项表 * @return 0 配置解析成功 * @return !0 配置解析失败 */ static int32_t cfg_parse(gen_args_t* args, FILE*file) { while (1) { long start; long finish; char*variable; if (cfg_read_variable(file, &start, &finish)) { LIB_ERROR(PARSER, "load variable fail!\n"); return -1; } if (start == finish) { assert(fgetc(file) == EOF); break; } fseek(file, start, SEEK_SET); if (read_variable(file, finish - start, &variable)) { LIB_ERROR(PARSER, "read variable fail!\n"); return -1; } //add variable to hash if (gen_args_hash_add_variable(args, variable)) { LIB_ERROR(PARSER, "args hash add variable '%s' fail!\n", variable); LIB_MEM_FREE(variable); return -1; } LIB_MEM_FREE(variable); } return 0; }
/* return <>0 on error */ int run_let(const struct Line * const l, struct VarSet *varset) { struct Variable *v; char *rd = l->rest; rd = skipwhite_s(rd); rd = read_variable(varset, rd, &v); if(v == NULL){ error("variable error"); return 1; } rd = skipwhite_s(rd); if(*rd++ != '='){ error("'=' expected"); return 1; } rd = skipwhite_s(rd); /* and now expression parsing */ switch(v->type){ case '$': run_let_string(varset, rd, v); break; case '%': run_let_int(varset, rd, v); break; case '#': run_let_float(varset, rd, v); break; default: assert(0); } return 0; }
int helper_call (lua_State *L) { struct exception e; int freturn = 0; Helper *h; Transport *tpt; h = ( Helper * )luaL_checkudata(L, 1, "rpc.helper"); luaL_argcheck(L, h, 1, "helper expected"); tpt = h->handle; // capture special calls, otherwise execute normal remote call if( strcmp("get", h->funcname ) == 0 ) { helper_get( L, h->parent ); freturn = 1; } else { Try { int i,n; uint32_t nret,ret_code; // write function name tpt->timeout = tpt->com_timeout; helper_wait_ready( tpt, RPC_CMD_CALL ); helper_remote_index( h ); // write number of arguments n = lua_gettop( L ); transport_write_uint32_t( tpt, n - 1 ); // write each argument for( i = 2; i <= n; i ++ ) write_variable( tpt, L, i ); transport_flush(tpt); tpt->timeout = tpt->wait_timeout; /* if we're in async mode, we're done */ /*if ( h->handle->async ) { h->handle->read_reply_count++; freturn = 0; }*/ // read return code ret_code = transport_read_uint8_t( tpt ); tpt->timeout = tpt->com_timeout; if ( ret_code == 0 ) { // read return arguments nret = transport_read_uint32_t( tpt ); for ( i = 0; i < ( ( int ) nret ); i ++ ) read_variable( tpt, L ); freturn = ( int )nret; } else { uint32_t len; char* err_string; // read error and handle it transport_read_uint32_t( tpt ); // read code (not being used here) len = transport_read_uint32_t( tpt ); err_string = ( char * )alloca( len + 1 ); transport_read_string( tpt, err_string, len ); err_string[ len ] = 0; deal_with_error( L, err_string ); freturn = 0; } } Catch( e ) { freturn = generic_catch_handler( L, h->handle, e ); } } return freturn; }
Remote<T> read_variable(const char *name) const { Remote<T> res; read_variable(name, res.getBuffer(), sizeof(T)); return res; }
// returns number of items successfully read int scanf(const char *format, ...) { va_list val; int scanned = 0; int64_t read_chars = 0; char c[MAX_STRING] = {0}; char *pStr = NULL; char *char_addr = NULL; unsigned int *hex_addr = NULL; int *int_addr = NULL; va_start(val, format); while(*format) { if (*format == '%') { format++; switch (*format) { case 'c': char_addr = va_arg(val, char *); read_chars = read_variable(0, c, 2); if (read_chars <= 0) return read_chars; *char_addr = c[0]; scanned++; break; case 's': pStr = va_arg(val, char *); read_chars = read_variable(0, c, MAX_STRING); if (read_chars <= 0) return read_chars; strncpy(pStr, c, MAX_STRING); scanned++; break; case 'd': int_addr = va_arg(val, int *); read_chars = read_variable(0, c, MAX_STRING); if (read_chars <= 0) return read_chars; if (atoi(int_addr, c) < 0) return -1; scanned++; break; case 'x': case 'X': hex_addr = va_arg(val, unsigned int *); read_chars = read_variable(0, c, MAX_STRING); if (read_chars <= 0) return read_chars; if (atox(hex_addr, c) < 0) return -1; scanned++; break; default: // Not supported... Ignore break; } } ++format; }
static int read_product(int ncid, harp_product *product, netcdf_dimensions *dimensions) { int num_dimensions; int num_variables; int num_attributes; int unlim_dim; int result; int i; result = nc_inq(ncid, &num_dimensions, &num_variables, &num_attributes, &unlim_dim); if (result != NC_NOERR) { harp_set_error(HARP_ERROR_NETCDF, "%s", nc_strerror(result)); return -1; } for (i = 0; i < num_dimensions; i++) { netcdf_dimension_type dimension_type; char name[NC_MAX_NAME + 1]; size_t length; result = nc_inq_dim(ncid, i, name, &length); if (result != NC_NOERR) { harp_set_error(HARP_ERROR_NETCDF, "%s", nc_strerror(result)); return -1; } if (parse_dimension_type(name, &dimension_type) != 0) { return -1; } if (dimensions_add(dimensions, dimension_type, length) != i) { harp_set_error(HARP_ERROR_IMPORT, "duplicate dimensions with name '%s'", name); return -1; } } for (i = 0; i < num_variables; i++) { if (read_variable(product, ncid, i, dimensions) != 0) { return -1; } } result = nc_inq_att(ncid, NC_GLOBAL, "source_product", NULL, NULL); if (result == NC_NOERR) { if (read_string_attribute(ncid, NC_GLOBAL, "source_product", &product->source_product) != 0) { return -1; } } else if (result != NC_ENOTATT) { harp_set_error(HARP_ERROR_NETCDF, "%s", nc_strerror(result)); return -1; } result = nc_inq_att(ncid, NC_GLOBAL, "history", NULL, NULL); if (result == NC_NOERR) { if (read_string_attribute(ncid, NC_GLOBAL, "history", &product->history) != 0) { return -1; } } else if (result != NC_ENOTATT) { harp_set_error(HARP_ERROR_NETCDF, "%s", nc_strerror(result)); return -1; } return 0; }
struct generic_section_config * parse_param(char const *path, FILE *f, const struct config_section_info *params, int quiet_flag, int _ncond_var, cfg_cond_var_t *_cond_vars, int *p_cond_count) { struct generic_section_config *cfg = NULL; struct generic_section_config **psect = &cfg, *sect = NULL; const struct config_section_info *cur_info = NULL; char sectname[32]; char varname[32]; char varvalue[1024]; int c, sindex; parsecfg_state.ncond_var = _ncond_var; parsecfg_state.cond_vars = _cond_vars; parsecfg_state.cond_stack = 0; parsecfg_state.output_enabled = 1; parsecfg_state.lineno = 1; if (p_cond_count) *p_cond_count = 0; /* found the global section description */ for (sindex = 0; params[sindex].name; sindex++) { if (!strcmp(params[sindex].name, "global")) { cur_info = ¶ms[sindex]; break; } } /* if (!cur_info) { fprintf(stderr, "Cannot find description of section [global]\n"); goto cleanup; } */ if (!f && !(f = fopen(path, "r"))) { fprintf(stderr, "Cannot open configuration file %s\n", path); goto cleanup; } if (cur_info) { cfg = (struct generic_section_config*) xcalloc(1, cur_info->size); if (cur_info->init_func) cur_info->init_func(cfg); cfg->next = NULL; psect = &cfg->next; } while (1) { c = read_first_char(f); if (c == EOF || c == '[') break; if (c == '#' || c== '%' || c == ';') { read_comment(f); continue; } if (c == '@') { if (handle_conditional(f) < 0) goto cleanup; if (p_cond_count) (*p_cond_count)++; continue; } if (!parsecfg_state.output_enabled) { read_comment(f); continue; } if (read_variable(f, varname, sizeof(varname), varvalue, sizeof(varvalue)) < 0) goto cleanup; if (!quiet_flag) { printf("%d: Value: %s = %s\n", parsecfg_state.lineno - 1, varname, varvalue); } if (!cur_info) { fprintf(stderr, "Cannot find description of section [global]\n"); goto cleanup; } if (copy_param(cfg, cur_info, varname, varvalue) < 0) goto cleanup; } while (c != EOF) { if (read_section_name(f, sectname, sizeof(sectname)) < 0) goto cleanup; if (!quiet_flag) { printf("%d: New section %s\n", parsecfg_state.lineno - 1, sectname); } if (!strcmp(sectname, "global")) { fprintf(stderr, "Section global cannot be specified explicitly\n"); goto cleanup; } for (sindex = 0; params[sindex].name; sindex++) { if (!strcmp(params[sindex].name, sectname)) { cur_info = ¶ms[sindex]; break; } } if (!cur_info) { fprintf(stderr, "Cannot find description of section [%s]\n", sectname); goto cleanup; } if (cur_info->pcounter) (*cur_info->pcounter)++; sect = (struct generic_section_config*) xcalloc(1, cur_info->size); strcpy(sect->name, sectname); if (cur_info->init_func) cur_info->init_func(sect); sect->next = NULL; *psect = sect; psect = §->next; while (1) { c = read_first_char(f); if (c == EOF || c == '[') break; if (c == '#' || c == '%' || c == ';') { read_comment(f); continue; } if (c == '@') { if (handle_conditional(f) < 0) goto cleanup; if (p_cond_count) (*p_cond_count)++; continue; } if (!parsecfg_state.output_enabled) { read_comment(f); continue; } if (read_variable(f, varname, sizeof(varname), varvalue, sizeof(varvalue)) < 0) goto cleanup; if (!quiet_flag) { printf("%d: Value: %s = %s\n", parsecfg_state.lineno - 1, varname, varvalue); } if (copy_param(sect, cur_info, varname, varvalue) < 0) goto cleanup; } } if (parsecfg_state.cond_stack) { fprintf(stderr, "%d: unclosed conditional compilation\n", parsecfg_state.lineno); goto cleanup; } fflush(stdout); if (f) fclose(f); return cfg; cleanup: xfree(cfg); if (f) fclose(f); return NULL; }
template<class T> void read_variable(const char* name, T* target) const { read_variable(name, target, sizeof(*target)); }
//**************************************************************************** // lua remote function server // read function call data and execute the function. this function empties the // stack on entry and exit. This sets a custom error handler to catch errors // around the function call. static void read_cmd_call( Transport *tpt, lua_State *L ) { int i, stackpos, good_function, nargs; uint32_t len; char *funcname; char *token = NULL; // read function name len = transport_read_uint32_t( tpt ); /* function name string length */ funcname = ( char * )alloca( len + 1 ); transport_read_string( tpt, funcname, len ); funcname[ len ] = 0; // get function // @@@ perhaps handle more like variables instead of using a long string? // @@@ also strtok is not thread safe token = strtok( funcname, "." ); lua_getglobal( L, token ); token = strtok( NULL, "." ); while( token != NULL ) { lua_getfield( L, -1, token ); lua_remove( L, -2 ); token = strtok( NULL, "." ); } stackpos = lua_gettop( L ) - 1; good_function = LUA_ISCALLABLE( L, -1 ); // read number of arguments nargs = transport_read_uint32_t( tpt ); // read in each argument, leave it on the stack for ( i = 0; i < nargs; i ++ ) read_variable( tpt, L ); // call the function if( good_function ) { int nret, error_code; error_code = lua_pcall( L, nargs, LUA_MULTRET, 0 ); // handle errors if ( error_code ) { size_t len; const char *errmsg; errmsg = lua_tolstring (L, -1, &len); transport_write_uint8_t( tpt, 1 ); transport_write_uint32_t( tpt, error_code ); transport_write_uint32_t( tpt, len ); transport_write_string( tpt, errmsg, len ); } else { // pass the return values back to the caller transport_write_uint8_t( tpt, 0 ); nret = lua_gettop( L ) - stackpos; transport_write_uint32_t( tpt, nret ); for ( i = 0; i < nret; i ++ ) write_variable( tpt, L, stackpos + 1 + i ); } } else { // bad function const char *msg = "undefined function: "; int errlen = strlen( msg ) + len; transport_write_uint8_t( tpt, 1 ); transport_write_uint32_t( tpt, LUA_ERRRUN ); transport_write_uint32_t( tpt, errlen ); transport_write_string( tpt, msg, strlen( msg ) ); transport_write_string( tpt, funcname, len ); } // empty the stack lua_settop ( L, 0 ); }
void deserialize(readable& src, size_t& x) { read_variable(src, x); }
static void load_old_ns_dbase(dbFILE *f, int ver) { struct nickinfo_ { NickInfo *next, *prev; char nick[NICKMAX]; char pass[PASSMAX]; char *last_usermask; char *last_realname; time_t time_registered; time_t last_seen; long accesscount; char **access; long flags; time_t id_stamp; unsigned short memomax; unsigned short channelcount; char *url; char *email; } old_nickinfo; int i, j, c; NickInfo *ni, **last, *prev; int failed = 0; for (i = 33; i < 256 && !failed; i++) { last = &nicklists[i]; prev = NULL; while ((c = getc_db(f)) != 0) { if (c != 1) fatal("Invalid format in %s", NickDBName); SAFE(read_variable(old_nickinfo, f)); if (debug >= 3) log("debug: load_old_ns_dbase read nick %s", old_nickinfo.nick); ni = scalloc(sizeof(NickInfo), 1); *last = ni; last = &ni->next; ni->prev = prev; prev = ni; strscpy(ni->nick, old_nickinfo.nick, NICKMAX); strscpy(ni->pass, old_nickinfo.pass, PASSMAX); ni->time_registered = old_nickinfo.time_registered; ni->last_seen = old_nickinfo.last_seen; ni->accesscount = old_nickinfo.accesscount; ni->flags = old_nickinfo.flags; ni->channelcount = 0; ni->channelmax = CSMaxReg; ni->language = DEF_LANGUAGE; /* ENCRYPTEDPW and VERBOTEN moved from ni->flags to ni->status */ if (ni->flags & 4) ni->status |= NS_VERBOTEN; if (ni->flags & 8) ni->status |= NS_ENCRYPTEDPW; ni->flags &= ~0xE000000C; #ifdef USE_ENCRYPTION if (!(ni->status & (NS_ENCRYPTEDPW | NS_VERBOTEN))) { if (debug) log("debug: %s: encrypting password for `%s' on load", s_NickServ, ni->nick); if (encrypt_in_place(ni->pass, PASSMAX) < 0) fatal("%s: Can't encrypt `%s' nickname password!", s_NickServ, ni->nick); ni->status |= NS_ENCRYPTEDPW; } #else if (ni->status & NS_ENCRYPTEDPW) { /* Bail: it makes no sense to continue with encrypted * passwords, since we won't be able to verify them */ fatal("%s: load database: password for %s encrypted " "but encryption disabled, aborting", s_NickServ, ni->nick); } #endif if (old_nickinfo.url) SAFE(read_string(&ni->url, f)); if (old_nickinfo.email) SAFE(read_string(&ni->email, f)); SAFE(read_string(&ni->last_usermask, f)); if (!ni->last_usermask) ni->last_usermask = sstrdup("@"); SAFE(read_string(&ni->last_realname, f)); if (!ni->last_realname) ni->last_realname = sstrdup(""); if (ni->accesscount) { char **access, *s; if (ni->accesscount > NSAccessMax) ni->accesscount = NSAccessMax; access = smalloc(sizeof(char *) * ni->accesscount); ni->access = access; for (j = 0; j < ni->accesscount; j++, access++) SAFE(read_string(access, f)); while (j < old_nickinfo.accesscount) { SAFE(read_string(&s, f)); if (s) free(s); j++; } } ni->id_stamp = 0; if (ver < 3) { ni->flags |= NI_MEMO_SIGNON | NI_MEMO_RECEIVE; } else if (ver == 3) { if (!(ni->flags & (NI_MEMO_SIGNON | NI_MEMO_RECEIVE))) ni->flags |= NI_MEMO_SIGNON | NI_MEMO_RECEIVE; } } /* while (getc_db(f) != 0) */ *last = NULL; } /* for (i) */ }