char *aobjnam(struct obj *otmp, char *verb) { char *bp = xname(otmp); char prefix[PREFIX]; if(otmp->quan != 1) { sprintf(prefix, "%d ", otmp->quan); bp = strprepend(bp, prefix); } if(verb != NULL) { /* Verb is given in plural (i.e., without trailing 's') */ strcat(bp, " "); if(otmp->quan != 1) { strcat(bp, verb); } else if(strcmp(verb, "are") == 0) { strcat(bp, "is"); } else { strcat(bp, verb); strcat(bp, "s"); } } return bp; }
repository_t *local_get_repository(driver_t * self, char *supfile, list_t * repositories_hierarchy) { FILE *file; char *line, *path, *name, *extension; repository_t *repository; size_t n; int nread; assert(supfile); if (!(extension = rindex(supfile, '.')) || strcmp(extension, ".local")) return NULL; supfile = xstrdup_printf("/etc/ports/%s", supfile); file = fopen(supfile, "r"); if (file == NULL) return NULL; line = NULL; repository = NULL; while ((nread = getline(&line, &n, file)) >= 0) { *(line + strlen(line) - 1) = 0; strtrim(line); if (line[0] == '#' || strlen(line) == 0 || (!strstr(line, "PATH") && strchr(line, '='))) continue; path = strtrim(xstrdup(strchr(line, '=') + 1)); name = xstrdup(strrchr(supfile, '/')); *(strrchr(name, '.')) = 0; strprepend(&name, "local"); repository = repository_new(name, path, supfile, self, repositories_hierarchy); break; } free(line); fclose(file); return repository; }
unsigned char *ramdisk_load (const char *filename, int32_t *outlen) { ramdisk_t *ramfile = ramdisk_data; unsigned char *out; char *alt_filename; alt_filename = 0; /* * If the file is on disk and is newer than the program, use that in * preference. */ if (file_exists(filename)) { if (strstr(filename, "data/")) { if (file_exists_and_is_newer_than(filename, EXEC_FULL_PATH_AND_NAME)) { out = file_read_if_exists(filename, outlen); if (out) { DBG("Locdisk %s (newer than exec)", filename); return (out); } } if (file_exists_and_is_newer_than(filename, ".o/ramdisk_data.o")) { out = file_read_if_exists(filename, outlen); if (out) { DBG("Locdisk %s (newer than build)", filename); return (out); } } if (file_exists_and_is_newer_than(filename, "src/.o/ramdisk_data.o")) { out = file_read_if_exists(filename, outlen); if (out) { DBG("Locdisk %s (newer than src build)", filename); return (out); } } } else { out = file_read_if_exists(filename, outlen); if (out) { DBG("Locdisk %s (exists locally)", filename); return (out); } } } if (EXEC_DIR) { alt_filename = strprepend(filename, EXEC_DIR); if (file_exists(alt_filename)) { if (file_exists_and_is_newer_than(alt_filename, EXEC_FULL_PATH_AND_NAME)) { out = file_read_if_exists(alt_filename, outlen); if (out) { DBG("Locdisk %s", filename); myfree(alt_filename); return (out); } } if (file_exists_and_is_newer_than(alt_filename, ".o/ramdisk_data.o")) { out = file_read_if_exists(alt_filename, outlen); if (out) { DBG("Locdisk %s", filename); myfree(alt_filename); return (out); } } if (file_exists_and_is_newer_than(alt_filename, "src/.o/ramdisk_data.o")) { out = file_read_if_exists(alt_filename, outlen); if (out) { DBG("Locdisk %s", filename); myfree(alt_filename); return (out); } } } } while (ramfile->filename) { if (strcmp(ramfile->filename, filename)) { ramfile++; continue; } if (outlen) { *outlen = (int)ramfile->len; } DBG("Ramdisk %s, %d bytes", filename, ramfile->len); if (alt_filename) { myfree(alt_filename); } uint8_t *copy = (TYPEOF(copy)) mymalloc((int)ramfile->len + 1, "ramdisk load"); if (!copy) { DBG("no memory for loading ramdisk copy, %s", filename); return (0); } memcpy(copy, (unsigned char*)ramfile->data, (int)ramfile->len); *(copy + (int)ramfile->len) = 0; return (copy); #ifdef USE_ZLIB int32_t err; out = mymalloc(ramfile->orig_len, "RAMDISK scratchpad"); if (!out) { ERR("no memory for ramdisk, %s", filename); } outlenl = ramfile->orig_len; err = uncompress(out, &outlenl, (unsigned char *)ramfile->data, ramfile->len); if (err) { ERR("file failed to decompress from ramdisk, %s, " "orig len %d, compressed len %d, err %d", filename, ramfile->orig_len, ramfile->len, err); } if (outlen) { *outlen = (int)outlenl; } #endif #ifdef USE_MINIZ int32_t err; out = (TYPEOF(out)) mymalloc(ramfile->orig_len, "RAMDISK scratchpad"); if (!out) { ERR("no memory for ramdisk, %s", filename); } outlenl = ramfile->orig_len; err = mz_uncompress(out, &outlenl, (unsigned char *)ramfile->data, ramfile->len); if (err) { ERR("file failed to decompress from ramdisk, %s, err %d", filename, err); } if (outlen) { *outlen = (int32_t)outlenl; } #endif #ifdef USE_STB_IMAGE out = (TYPEOF(out)) stbi_zlib_decode_malloc((const char *)ramfile->data, ramfile->len, &outlenl); if (!out) { ERR("file failed to decompress from ramdisk, %s", filename); } if (outlen) { *outlen = (int)outlenl; } #endif return (out); } /* * Fallback to the disk. */ out = file_read_if_exists(filename, outlen); if (out) { DBG("Locdisk %s", filename); if (alt_filename) { myfree(alt_filename); } return (out); } out = file_read_if_exists(alt_filename, outlen); if (out) { DBG("Locdisk %s", filename); if (alt_filename) { myfree(alt_filename); } return (out); } if (alt_filename) { myfree(alt_filename); } alt_filename = mybasename(filename, "strip dir"); out = file_read_if_exists(alt_filename, outlen); if (out) { DBG("Locdisk %s", alt_filename); if (alt_filename) { myfree(alt_filename); } return (out); } /* * Fail. Caller should whinge. * char *popup_str = dynprintf("Filename was not found on ramdisk or " "on the local disk, %s", filename); MSG_BOX("%s", popup_str); myfree(popup_str); */ LOG("File not found \"%s\"", filename); if (alt_filename) { myfree(alt_filename); } return (0); }
char *doname(struct obj *obj) { char prefix[PREFIX]; char *bp = xname(obj); if(obj->quan != 1) { sprintf(prefix, "%d ", obj->quan); } else { strcpy(prefix, "a "); } switch(obj->olet) { case AMULET_SYM: if(strncmp(bp, "cheap ", 6) != 0) { strcpy(prefix, "the "); } break; case ARMOR_SYM: if((obj->owornmask & W_ARMOR) != 0) { strcat(bp, " (being worn)"); } if(obj->known != 0) { strcat(prefix, sitoa((obj->spe - 10) + objects[obj->otyp].a_ac)); strcat(prefix, " "); } break; case WEAPON_SYM: if(obj->known != 0) { strcat(prefix, sitoa(obj->spe)); strcat(prefix, " "); } break; case WAND_SYM: if(obj->known) { sprintf(eos(bp), " (%d)", obj->spe); } break; case RING_SYM: if((obj->owornmask & W_RINGR) != 0) { strcat(bp, " (on right hand)"); } if((obj->owornmask & W_RINGL) != 0) { strcat(bp, " (on left hand)"); } if((obj->known != 0) && ((objects[obj->otyp].bits & SPEC) != 0)) { strcat(prefix, sitoa(obj->spe)); strcat(prefix, " "); } break; } if((obj->owornmask & W_WEP) != 0) { strcat(bp, " (weapon in hand)"); } if(obj->unpaid != 0) { strcat(bp, " (unpaid)"); } if((strcmp(prefix, "a ") == 0) && (index(vowels, *bp) != 0)) { strcpy(prefix, "an "); } bp = strprepend(bp, prefix); return bp; }
int main(int argc, char **argv) { unsigned i; conf_t *conf; dict_t *repositories; dict_t *ports_dict; dict_t *not_founds; list_t *ports_list; list_t *packages; list_t *list; list_t *drivers; struct arguments arguments; arguments.action = 0; arguments.no_favourite_repositories = 0; arguments.no_locked_versions = 0; arguments.no_aliases = 0; arguments.no_colors = 0; arguments.no_deps = 1; arguments.all = 0; arguments.fetch_only = 0; arguments.no_repositories_hierarchy = 0; arguments.tree = 0; arguments.verbose = 0; arguments.rebuild_cache = 0; arguments.args = list_new(); if (argc < 2) { char *fake_arg[2]; fake_arg[0] = "ilenia"; fake_arg[1] = "--help"; argp_parse(&argp, 2, fake_arg, 0, 0, &arguments); } argp_parse(&argp, argc, argv, 0, 0, &arguments); conf = conf_init(); if (arguments.no_repositories_hierarchy) { list_free(conf->repositories_hierarchy, free); conf->repositories_hierarchy = list_new(); } if (arguments.no_favourite_repositories) { dict_free(conf->favourite_repositories, NULL); conf->favourite_repositories = dict_new(); } if (arguments.no_locked_versions) { dict_free(conf->locked_versions, free); conf->locked_versions = dict_new(); } if (arguments.no_aliases) { aliases_free(conf->aliases); conf->aliases = dict_new(); } drivers = drivers_list_init(); repositories = repositories_dict_init(drivers, conf->repositories_hierarchy); if (!conf->enable_colors || arguments.no_colors) cprintf = uncoloredprintf; else cprintf = coloredprintf; if (arguments.rebuild_cache) cache_build(repositories); packages = packages_list_init(); if ((ports_list = ports_list_init(repositories)) == NULL) { list_free(arguments.args, NULL); dict_free(repositories, repository_free); list_free(packages, port_free); list_free(drivers, free); dict_free(conf->favourite_repositories, free); conf->favourite_repositories = dict_new(); conf_free(conf); return 1; } conf_reparse(conf, ports_list); ports_dict = ports_dict_init(ports_list, packages, conf); not_founds = dict_new(); if (!arguments.verbose) arguments.verbose = conf->verbose; switch (arguments.action) { case ACT_LIST: if (!arguments.args->length) { list_dump(ports_list, port_dump); break; } for (i = 0; i < arguments.args->length; i++) { if (dict_get(repositories, list_get(arguments.args, i)) == NULL) { warning("repository %s not found!", list_get(arguments.args, i)); continue; } list = list_query(ports_list, port_query_by_repository, list_get(arguments.args, i)); list_dump(list, port_dump); list_free(list, NULL); } break; case ACT_SEARCH: if (!arguments.args->length) { warning("action --search (-s) requires at least an " "argument!"); break; } for (i = 0; i < arguments.args->length; i++) { list = list_query(ports_list, port_query_by_name, list_get(arguments.args, i)); if (arguments.verbose) list_dump(list, port_info_dump); else list_dump(list, port_dump); if (list->length == 0) printf("%s not found!\n", (char *)list_get(arguments.args, i)); list_free(list, NULL); } break; case ACT_SEARCHDESC: if (!arguments.args->length) { warning("action --search-desc requires at least an " "argument!"); break; } for (i = 0; i < arguments.args->length; i++) { char *key = xstrdup(list_get(arguments.args, i)); if (isalpha(*key) && isalpha(*(key + strlen(key) - 1))) { strprepend(&key, "*"); strappend(&key, "*"); } list = list_query(ports_list, port_query_by_description, key); if (arguments.verbose) list_dump(list, port_info_dump); else list_dump(list, port_dump); list_free(list, NULL); free(key); } break; case ACT_DIFF: port_show_diffs(ports_dict, packages); break; case ACT_UPDATED: port_show_outdated(ports_dict, packages); break; case ACT_DEPENDENCIES: if (!arguments.args->length) { warning("action --dependencies (-D) requires at " "least an argument!"); break; } //for (i = 0; i < arguments.args->length; i++) dependencies_dump(arguments.args, ports_dict, conf->aliases, not_founds, arguments.tree, arguments.verbose); break; case ACT_DEPENDENTS: if (!arguments.args->length) { warning("action --dependents (-T) requires at " "least an argument!"); break; } for (i = 0; i < arguments.args->length; i++) dependents_dump(list_get(arguments.args, i), ports_dict, conf->aliases, arguments.tree, arguments.verbose, arguments.all); break; case ACT_INFO: if (!arguments.args->length) { warning("action --info requires at " "least an argument!"); break; } for (i = 0; i < arguments.args->length; i++) info_dump(list_get(arguments.args, i), ports_dict); break; case ACT_README: if (!arguments.args->length) { warning("action --show-readme requires at " "least an argument!"); break; } for (i = 0; i < arguments.args->length; i++) readme_dump(list_get(arguments.args, i), ports_dict); break; case ACT_REPOSITORY_LIST: repositories_dict_dump(repositories); break; case ACT_UPDATE: if (arguments.args->length) repositories_dict_update(repositories, arguments.args); else repositories_dict_update_all(repositories); break; case ACT_REMOVE: if (!arguments.args->length) { warning("action --remove (-R) requires at " "least an argument!"); break; } remove_packages(arguments.args, packages, ports_dict, conf, arguments.all); break; case ACT_UPDATE_PKG: if (!arguments.args->length) { update_system(ports_dict, conf->aliases, arguments.fetch_only, conf->ask_for_update, conf->not_found_policy); break; } update_package(arguments.args, ports_dict, conf, arguments.fetch_only); break; default: if (!arguments.rebuild_cache) warning("What can I do for you?"); } list_free(arguments.args, NULL); dict_free(repositories, repository_free); list_free(ports_list, port_free); list_free(packages, port_free); dict_free(ports_dict, NULL); list_free(drivers, free); conf_free(conf); dict_free(not_founds, port_free); return 0; }
/* Expands macros in the *format string advancing the pointer as it goes. The * opt represents conditional expression state, should be zero for non-recursive * calls. Returns newly allocated string, which should be freed by the * caller. */ static char * parse_view_macros(FileView *view, const char **format, const char macros[], int opt) { const dir_entry_t *const entry = &view->dir_entry[view->list_pos]; char *result = strdup(""); size_t len = 0; char c; int nexpansions = 0; while((c = **format) != '\0') { size_t width = 0; int left_align = 0; char buf[PATH_MAX]; const char *const next = ++*format; int skip, ok; if(c != '%' || (!char_is_one_of(macros, *next) && !isdigit(*next))) { if(strappendch(&result, &len, c) != 0) { break; } continue; } if(*next == '-') { left_align = 1; ++*format; } while(isdigit(**format)) { width = width*10 + *(*format)++ - '0'; } c = *(*format)++; skip = 0; ok = 1; switch(c) { case 't': format_entry_name(entry, sizeof(buf), buf); break; case 'A': #ifndef _WIN32 get_perm_string(buf, sizeof(buf), entry->mode); #else snprintf(buf, sizeof(buf), "%s", attr_str_long(entry->attrs)); #endif break; case 'u': get_uid_string(entry, 0, sizeof(buf), buf); break; case 'g': get_gid_string(entry, 0, sizeof(buf), buf); break; case 's': friendly_size_notation(entry->size, sizeof(buf), buf); break; case 'E': { uint64_t size = 0; if(view->selected_files > 0) { int i; for(i = 0; i < view->list_rows; i++) { if(view->dir_entry[i].selected) { size += get_file_size_by_entry(view, i); } } } /* Make exception for VISUAL_MODE, since it can contain empty * selection when cursor is on ../ directory. */ else if(!vle_mode_is(VISUAL_MODE)) { size = get_file_size_by_entry(view, view->list_pos); } friendly_size_notation(size, sizeof(buf), buf); } break; case 'd': { struct tm *tm_ptr = localtime(&entry->mtime); strftime(buf, sizeof(buf), cfg.time_format, tm_ptr); } break; case '-': skip = expand_num(buf, sizeof(buf), view->filtered); break; case 'l': skip = expand_num(buf, sizeof(buf), view->list_pos + 1); break; case 'L': skip = expand_num(buf, sizeof(buf), view->list_rows + view->filtered); break; case 'S': skip = expand_num(buf, sizeof(buf), view->list_rows); break; case '%': snprintf(buf, sizeof(buf), "%%"); break; case '[': { char *const opt_str = parse_view_macros(view, format, macros, 1); copy_str(buf, sizeof(buf), opt_str); free(opt_str); break; } case ']': if(opt) { if(nexpansions == 0) { replace_string(&result, ""); } return result; } else { LOG_INFO_MSG("Unmatched %]", c); ok = 0; } break; default: LOG_INFO_MSG("Unexpected %%-sequence: %%%c", c); ok = 0; break; } if(!ok) { *format = next; if(strappendch(&result, &len, '%') != 0) { break; } continue; } check_expanded_str(buf, skip, &nexpansions); stralign(buf, width, ' ', left_align); if(strappend(&result, &len, buf) != 0) { break; } } /* Unmatched %[. */ if(opt) { (void)strprepend(&result, &len, "%["); } return result; }
/* Expands macros in the *format string advancing the pointer as it goes. The * opt represents conditional expression state, should be zero for non-recursive * calls. Returns newly allocated string, which should be freed by the * caller. */ static LineWithAttrs parse_view_macros(view_t *view, const char **format, const char macros[], int opt) { const dir_entry_t *const curr = get_current_entry(view); LineWithAttrs result = { .line = strdup(""), .attrs = strdup("") }; char c; int nexpansions = 0; int has_expander = 0; if(curr == NULL) { return result; } while((c = **format) != '\0') { size_t width = 0; int left_align = 0; char buf[PATH_MAX + 1]; const char *const next = ++*format; int skip, ok; if(c != '%' || (!char_is_one_of(macros, *next) && !isdigit(*next) && (*next != '=' || has_expander))) { if(strappendch(&result.line, &result.line_len, c) != 0) { break; } continue; } if(*next == '=') { (void)sync_attrs(&result, 0); if(strappend(&result.line, &result.line_len, "%=") != 0 || strappendch(&result.attrs, &result.attrs_len, '=') != 0) { break; } ++*format; has_expander = 1; continue; } if(*next == '-') { left_align = 1; ++*format; } while(isdigit(**format)) { width = width*10 + *(*format)++ - '0'; } c = *(*format)++; skip = 0; ok = 1; buf[0] = '\0'; switch(c) { case 'a': friendly_size_notation(get_free_space(curr_view->curr_dir), sizeof(buf), buf); break; case 't': format_entry_name(curr, NF_FULL, sizeof(buf), buf); break; case 'T': if(curr->type == FT_LINK) { char full_path[PATH_MAX + 1]; char link_path[PATH_MAX + 1]; //add by sim1 get_full_path_of(curr, sizeof(full_path), full_path); //mod by sim1 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< if(get_link_target(full_path, link_path, sizeof(link_path)) != 0) { copy_str(buf, sizeof(buf), "Failed to resolve link"); } else { snprintf(buf, sizeof(buf), " -> %s", link_path); } //mod by sim1 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> } break; case 'f': get_short_path_of(view, curr, NF_FULL, 0, sizeof(buf), buf); break; case 'A': #ifndef _WIN32 get_perm_string(buf, sizeof(buf), curr->mode); #else copy_str(buf, sizeof(buf), attr_str_long(curr->attrs)); #endif break; case 'u': get_uid_string(curr, 0, sizeof(buf), buf); break; case 'g': get_gid_string(curr, 0, sizeof(buf), buf); break; case 's': friendly_size_notation(fentry_get_size(view, curr), sizeof(buf), buf); break; //add by sim1 ************************************************ case 'r': { char path[PATH_MAX] = {0}; get_full_path_at(view, view->list_pos, sizeof(path), path); (void)get_rating_string(buf, sizeof(buf), path); } break; case 'n': { int nitems = !fentry_is_dir(curr) ? 0 : (int)fentry_get_nitems(view, curr); snprintf(buf, sizeof(buf), "%d", nitems); } break; //add by sim1 ************************************************ case 'E': { uint64_t size = 0U; typedef int (*iter_f)(view_t *view, dir_entry_t **entry); /* No current element for visual mode, since it can contain truly * empty selection when cursor is on ../ directory. */ iter_f iter = vle_mode_is(VISUAL_MODE) ? &iter_selected_entries : &iter_selection_or_current; dir_entry_t *entry = NULL; while(iter(view, &entry)) { size += fentry_get_size(view, entry); } friendly_size_notation(size, sizeof(buf), buf); } break; case 'd': { struct tm *tm_ptr = localtime(&curr->mtime); strftime(buf, sizeof(buf), cfg.time_format, tm_ptr); } break; case '-': case 'x': skip = expand_num(buf, sizeof(buf), view->filtered); break; case 'l': skip = expand_num(buf, sizeof(buf), view->list_pos + 1); break; case 'L': skip = expand_num(buf, sizeof(buf), view->list_rows + view->filtered); break; case 'S': skip = expand_num(buf, sizeof(buf), view->list_rows); break; case '%': copy_str(buf, sizeof(buf), "%"); break; case 'z': copy_str(buf, sizeof(buf), get_tip()); break; case 'D': if(curr_stats.number_of_windows == 1) { view_t *const other = (view == curr_view) ? other_view : curr_view; //mod by sim1 //copy_str(buf, sizeof(buf), replace_home_part(other->curr_dir)); snprintf(buf, sizeof(buf), " ‖ %s", replace_home_part(other->curr_dir)); } break; case '[': { LineWithAttrs opt = parse_view_macros(view, format, macros, 1); copy_str(buf, sizeof(buf), opt.line); free(opt.line); char *attrs = opt.attrs; if(sync_attrs(&result, 0) && opt.attrs_len > 0U) { if(*attrs != ' ') { result.attrs[result.attrs_len - 1U] = *attrs; } ++attrs; } strappend(&result.attrs, &result.attrs_len, attrs); free(opt.attrs); break; } case ']': if(opt) { if(nexpansions == 0) { replace_string(&result.line, ""); replace_string(&result.attrs, ""); result.line_len = 0U; result.attrs_len = 0U; } if(sync_attrs(&result, 0)) { result.attrs[--result.attrs_len] = '\0'; } return result; } LOG_INFO_MSG("Unmatched %%]"); ok = 0; break; case '{': { /* Try to find matching closing bracket * TODO: implement the way to escape it, so that the expr may contain * closing brackets */ const char *e = strchr(*format, '}'); char *expr = NULL, *resstr = NULL; var_t res = var_false(); ParsingErrors parsing_error; /* If there's no matching closing bracket, just add the opening one * literally */ if(e == NULL) { ok = 0; break; } /* Create a NULL-terminated copy of the given expr. * TODO: we could temporarily use buf for that, to avoid extra * allocation, but explicitly named variable reads better. */ expr = calloc(e - (*format) + 1 /* NUL-term */, 1); memcpy(expr, *format, e - (*format)); /* Try to parse expr, and convert the res to string if succeed. */ parsing_error = parse(expr, 0, &res); if(parsing_error == PE_NO_ERROR) { resstr = var_to_str(res); } if(resstr != NULL) { copy_str(buf, sizeof(buf), resstr); } else { copy_str(buf, sizeof(buf), "<Invalid expr>"); } var_free(res); free(resstr); free(expr); *format = e + 1 /* closing bracket */; } break; case '*': if(width > 9) { snprintf(buf, sizeof(buf), "%%%d*", (int)width); width = 0; break; } (void)sync_attrs(&result, 1); result.attrs[result.attrs_len - 1] = '0' + width; width = 0; break; default: LOG_INFO_MSG("Unexpected %%-sequence: %%%c", c); ok = 0; break; } if(char_is_one_of("tTAugsEd", c) && fentry_is_fake(curr)) { buf[0] = '\0'; } if(!ok) { *format = next; if(strappendch(&result.line, &result.line_len, '%') != 0) { break; } continue; } check_expanded_str(buf, skip, &nexpansions); stralign(buf, width, ' ', left_align); if(strappend(&result.line, &result.line_len, buf) != 0) { break; } } /* Unmatched %[. */ if(opt) { (void)strprepend(&result.line, &result.line_len, "%["); } if(sync_attrs(&result, 0)) { result.attrs[--result.attrs_len] = '\0'; } return result; } /* Makes sure that result->attrs has at least as many elements as result->line * contains characters + extra_width. Returns non-zero if result->attrs has * extra characters compared to result->line. */ static int sync_attrs(LineWithAttrs *result, int extra_width) { const size_t nchars = utf8_strsw(result->line) + extra_width; if(result->attrs_len < nchars) { char *const new_attrs = format_str("%s%*s", result->attrs, (int)(nchars - result->attrs_len), ""); free(result->attrs); result->attrs = new_attrs; result->attrs_len = nchars; } return (result->attrs_len > nchars); } /* Prints number into the buffer. Returns non-zero if numeric value is * "empty" (zero). */ static int expand_num(char buf[], size_t buf_len, int val) { snprintf(buf, buf_len, "%d", val); return (val == 0); }