From ce0a85ebd4fa1997033e46eda68f7c2ee909c9ed Mon Sep 17 00:00:00 2001 From: Doohyeon Won Date: Thu, 29 Oct 2026 15:01:38 +0900 Subject: [PATCH 1/7] feat(ud): wip --- README.md | 1 + ud/README.md | 7 +++++++ ud/ud.1 | 20 ++++++++++++++++++++ vars.mk | 3 ++- 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 ud/README.md create mode 100644 ud/ud.1 diff --git a/README.md b/README.md index 145e5a6..3126a45 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ - **hd** - makes `

` headings - **yandere** - prints a yandere-like sentence *ad infinitum* - **iw** - a helper program to make a message like an installation wizard to stdout +- **ud** - a fake updater ## Installation diff --git a/ud/README.md b/ud/README.md new file mode 100644 index 0000000..09d56e3 --- /dev/null +++ b/ud/README.md @@ -0,0 +1,7 @@ +## Introduction + +`ud` is a fake updater. + +```bash +$ ud +``` diff --git a/ud/ud.1 b/ud/ud.1 new file mode 100644 index 0000000..49d9b57 --- /dev/null +++ b/ud/ud.1 @@ -0,0 +1,20 @@ +.TH ud 1 2026-10-26 "Utils Project" "UTILS PROJECT" +.SH NAME +ud - a fake updater +.SH SYNOPSIS +.nf +\fBud\fR (\-\fIm\fR | \-\-\fImessage\fB) string +\fBud\fR (\-\fIh\fB | \-\-\fIhelp\fB) +.fi +.SH DESCRIPTION +.SH USAGE +.SH EXAMPLE +.SH COMMAND LINE ARGUMENTS +.SH NOTES +.SH EXIT STATUS +.SH IMPLEMENTATIONS +.SH CONTRIBUTORS +Visit \fIhttps://github.com/sdbx/Utils/graphs/contributors\fR to see all the contributors! +.SH UTILS PROJECT +\fBud\fR is part of the \fBUtils\fR utility suite. +For more information, please visit \fIhttps://github.com/sdbx/Utils\fR to browse the whole project. diff --git a/vars.mk b/vars.mk index 29cc875..5af90cb 100644 --- a/vars.mk +++ b/vars.mk @@ -19,8 +19,9 @@ NSY := nsy NSY2 := nsy2 YANDERE := yandere IW := iw +UD := ud -TARGETS = $(BTN) $(HD) $(HHSS) $(NSY) $(NSY2) $(YANDERE) $(IW) +TARGETS = $(BTN) $(HD) $(HHSS) $(NSY) $(NSY2) $(YANDERE) $(IW) $(UD) TEST := test From cb9d431510c4d80ffdaad9027eddae07b5e57e55 Mon Sep 17 00:00:00 2001 From: Doohyeon Won Date: Fri, 30 Oct 2026 11:11:48 +0900 Subject: [PATCH 2/7] feat: a bit of work --- ud/c/argp_drivers.c | 82 +++++++++++++++++++++++++++++++ ud/c/argp_drivers.h | 9 ++++ ud/c/argp_drivers.internals.h | 54 +++++++++++++++++++++ ud/c/config.c | 90 +++++++++++++++++++++++++++++++++++ ud/c/config.h | 33 +++++++++++++ ud/c/config.internals.h | 22 +++++++++ ud/c/global.h | 20 ++++++++ 7 files changed, 310 insertions(+) create mode 100644 ud/c/argp_drivers.c create mode 100644 ud/c/argp_drivers.h create mode 100644 ud/c/argp_drivers.internals.h create mode 100644 ud/c/config.c create mode 100644 ud/c/config.h create mode 100644 ud/c/config.internals.h create mode 100644 ud/c/global.h diff --git a/ud/c/argp_drivers.c b/ud/c/argp_drivers.c new file mode 100644 index 0000000..05f4ab1 --- /dev/null +++ b/ud/c/argp_drivers.c @@ -0,0 +1,82 @@ +#include "argp_drivers.h" +#include "argp_drivers.internals.h" + +static bool drive_help(argtok_t *tok, argerr_t *err) { + (void) tok, (void) err; + cfg.help = true; + return true; +} + +static bool drive_msg(argtok_t *tok, argerr_t *err) { + (void) err; + cfg.msg = strdup(tok->value); + return true; +} + +static bool drive_lang(argtok_t *tok, argerr_t *err) { + typedef struct { + const char *lang; + langopt_enum_t enum_val; + } mapper_t; + + static const mapper_t accept_set[] = { + { "en", LangoptEnumEn }, + { "ko", LangoptEnumKo } + }; + static const size_t accept_set_len = ARRLEN(accept_set); + + const mapper_t *map; + + for (size_t i = 0; i < accept_set_len; i++) { + map = &accept_set[i]; + if (!strcmp(tok->value, map->lang)) { + cfg.lang = map->enum_val; + return true; + } + } + + /* error path */ + static const errhandle_unrecognized_value_ctx_t ctx = { + .targets = (const void **) &accept_set, + .targets_len = accept_set_len, + .target_siz = ESIZ(accept_set) + }; + + err->errhandle = errhandle_unrecognized_value; + err->ctx = &ctx; + err->ctx_siz = sizeof ctx; + return false; +} + +static void errhandle_unrecognized_value(argtok_t *tok, const char *reason, void *ctx) { + find_alikes_ret_t ret; + errhandle_unrecognized_value_ctx_t *ectx; + + (void) reason; + ectx = ctx; + + ret = find_alikes( + tok->value, + ectx->targets, + ectx->targets_len, + ectx->target_siz + ); + + safe_vprintf( + "%s: unrecognized value " Cbwhite "'%s'" Creset ".", + tok->field, tok->value + ); + safe_vprintf(" Do you mean "); + if (ret.nmemb == 1) { + safe_vprintf(Cbgreen "'%s'" Creset "?\n", ret.alikes[0]); + } + else { + safe_vprintf("one of the following?\n\t" Cbgreen); + for (size_t i = 0; i < ret.nmemb; i++) { + safe_vprintf("%s ", ret.alikes[i]); + } + safe_vprintf(Creset "\n"); + } + + free(ret.alikes); +} diff --git a/ud/c/argp_drivers.h b/ud/c/argp_drivers.h new file mode 100644 index 0000000..96d71c2 --- /dev/null +++ b/ud/c/argp_drivers.h @@ -0,0 +1,9 @@ +#ifndef ARGP_DRIVERS_H +#define ARGP_DRIVERS_H + +#include "argparse.h" + +extern optmd_t optmds[]; +extern const size_t optmds_len; + +#endif diff --git a/ud/c/argp_drivers.internals.h b/ud/c/argp_drivers.internals.h new file mode 100644 index 0000000..ba4eefe --- /dev/null +++ b/ud/c/argp_drivers.internals.h @@ -0,0 +1,54 @@ +#ifndef ARGP_DRIVERS_INTERNALS_H +#define ARGP_DRIVERS_INTERNALS_H + +#include "common.h" +#include "config.h" +#include "wrappers.h" +#include "strutils.h" +#include "colorcodes.h" +#include "argp_drivers.h" + +typedef struct { + const void **targets; + size_t targets_len; + size_t target_siz; +} errhandle_unrecognized_value_ctx_t; + +static opt_driver_t drive_help; +static opt_driver_t drive_msg; +static opt_driver_t drive_lang; + +static opt_errhandler_t errhandle_unrecognized_value; + +/*==================* + | EXTERN VARIABLES | + *==================*/ +optmd_t optmds[] = { + { + .sname = 'h', + .lname = "help", + .drive = drive_help, + .reqv = false, + .help = "prints the manual page", + .unique = true + }, + { + .sname = 'm', + .lname = "msg", + .drive = drive_msg, + .reqv = true, + .help = "specify the message to print out", + .unique = true + }, + { + .sname = '\0', + .lname = "lang", + .drive = drive_lang, + .reqv = true, + .help = "specify the language to speak", + .unique = true + } +}; +const size_t optmds_len = ARRLEN(optmds); + +#endif diff --git a/ud/c/config.c b/ud/c/config.c new file mode 100644 index 0000000..b58bf51 --- /dev/null +++ b/ud/c/config.c @@ -0,0 +1,90 @@ +#include "config.h" +#include "config.internals.h" + +extern void init_config(config_t *cfg) { + cfg->srcs = array_create(NULL); + cfg->msg = NULL; + cfg->lang = LangoptEnumEn; +} + +extern void destroy_config(config_t *cfg) { + array_destroy(cfg->srcs); + free(cfg->msg); +} + +extern config_statcode_t apply_config(config_t *cfg) { + config_statcode_t ret; + + if ((ret = check_help(cfg)) != ConfigStatcodeOk) + goto cleanup; + if ((ret = check_msg(cfg)) != ConfigStatcodeOk) + goto cleanup; + +cleanup: /* nothing to clean up, just return */ + return ret; +} + +static config_statcode_t check_help(config_t *cfg) { + config_statcode_t ret = ConfigStatcodeOk; + + if (cfg->help == false) { + return ret; + } + + return print_manpage(); +} + +static config_statcode_t check_msg(config_t *cfg) { + config_statcode_t ret = ConfigStatcodeOk; + + if (cfg->msg != NULL) { + return ret; + } + + fprintf(stderr, ENPREFIX "--msg is a required flag. Terminating.\n"); + ret = ConfigStatcodeNoMsg; + + return ret; +} + +static config_statcode_t print_manpage(void) { +#if !defined(_WIN32) && (defined(__unix__) || defined(__unix)) + if (!system(NULL)) { + return print_manual_fallback(); + } + + if (system("man " DIR_MANPAGE)) { + return print_manual_fallback(); + } + + return ConfigStatcodeNormalExit; +#else + return print_manual_fallback(); +#endif +} + +static config_statcode_t print_manual_fallback(void) { + config_statcode_t ret = ConfigStatcodeNormalExit; + FILE *fp; + int ch; + + fp = fopen(DIR_MANPAGE_TXT, "r"); + if (fp == NULL) { + fprintf( + stderr, + ENPREFIX "couldn't open the manpage from %s\n", + DIR_MANPAGE_TXT + ); + ret = ConfigStatcodeNoManpage; + goto cleanup; + } + + while ((ch = safe_fgetc(fp)) != EOF) { + safe_fputc(stdout, ch); + } + + safe_fclose(fp); + +cleanup: + return ret; +} diff --git a/ud/c/config.h b/ud/c/config.h new file mode 100644 index 0000000..8edd553 --- /dev/null +++ b/ud/c/config.h @@ -0,0 +1,33 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#include + +#include "array.adt.h" + +typedef enum { + LangoptEnumEn, + LangoptEnumKo +} langopt_enum_t; + +typedef struct config { + array_t *srcs; + bool help; + char *msg; + langopt_enum_t lang; +} config_t; + +typedef enum { + ConfigStatcodeOk, + ConfigStatcodeNormalExit, + ConfigStatcodeNoMsg, + ConfigStatcodeNoManpage +} config_statcode_t; + +void init_config(config_t *cfg); +void destroy_config(config_t *cfg); +config_statcode_t apply_config(config_t *cfg); + +extern config_t cfg; + +#endif diff --git a/ud/c/config.internals.h b/ud/c/config.internals.h new file mode 100644 index 0000000..6f7a6c5 --- /dev/null +++ b/ud/c/config.internals.h @@ -0,0 +1,22 @@ +#ifndef CONFIG_INTERNALS_H +#define CONFIG_INTERNALS_H + +#include +#include + +#include "global.h" +#include "config.h" +#include "wrappers.h" + +static config_statcode_t check_help(config_t *cfg); +static config_statcode_t check_msg(config_t *cfg); + +static config_statcode_t print_manpage(void); +static config_statcode_t print_manual_fallback(void); + +/*==================* + | EXTERN VARIABLES | + *==================*/ +config_t cfg = {0}; /* Since config does not change, I made it external */ + +#endif diff --git a/ud/c/global.h b/ud/c/global.h new file mode 100644 index 0000000..817a131 --- /dev/null +++ b/ud/c/global.h @@ -0,0 +1,20 @@ +#ifndef GLOBAL_H +#define GLOBAL_H + +#ifdef PROGNAME +#define EXECNAME PROGNAME +#else +#define EXECNAME "ud" +#endif + +#define ENPREFIX EXECNAME ": " + +#ifdef DIR_DATA +#define DIR_MANPAGE DIR_DATA "/man/man1/ud.1" +#else +#define DIR_MANPAGE "/usr/local/share/man/man1/ud.1" +#endif + +#define DIR_MANPAGE_TXT DIR_MANPAGE ".txt" + +#endif From a172e46d99a11bd3490b4595f14e34c1a8960341 Mon Sep 17 00:00:00 2001 From: Doohyeon Won Date: Sun, 1 Nov 2026 00:04:31 +0900 Subject: [PATCH 3/7] feat: done --- ud/c/.gitignore | 5 ++ ud/c/Makefile | 42 +++++++++++++++++ ud/c/argp_drivers.c | 32 ++++++++++++- ud/c/argp_drivers.internals.h | 12 +++++ ud/c/config.c | 34 ++++++-------- ud/c/config.h | 4 +- ud/c/ud.c | 88 +++++++++++++++++++++++++++++++++++ ud/c/ud.internals.h | 61 ++++++++++++++++++++++++ 8 files changed, 256 insertions(+), 22 deletions(-) create mode 100644 ud/c/.gitignore create mode 100644 ud/c/Makefile create mode 100644 ud/c/ud.c create mode 100644 ud/c/ud.internals.h diff --git a/ud/c/.gitignore b/ud/c/.gitignore new file mode 100644 index 0000000..d4fee75 --- /dev/null +++ b/ud/c/.gitignore @@ -0,0 +1,5 @@ +ud +ud.exe + +*.o +*.d diff --git a/ud/c/Makefile b/ud/c/Makefile new file mode 100644 index 0000000..b224ea6 --- /dev/null +++ b/ud/c/Makefile @@ -0,0 +1,42 @@ +## Variables ## +TARGET := ud + +CC := gcc +CFLAGS := -O -Wall -W -pedantic +CFLAGS += -g --std=c2x +CFLAGS += -MMD -MP +CPPFLAGS = \ + -I $(DIR_LIB) \ + -DPROGNAME='"$(TARGET)"' \ + $(if $(DIR_DATA),-DDIR_DATA='"$(DIR_DATA)"') + +SOURCES = $(wildcard *.c) +LIB_SRCS = $(wildcard $(DIR_LIB)/*.c) +OBJECTS = $(SOURCES:.c=.o) +LIB_OBJS = $(notdir $(LIB_SRCS:.c=.o)) + +DIR_LIB := ../../lib + +## Targets ## +.PHONY: all clean + +## Default Goal ## +all: $(TARGET) + +## Build ## +$(TARGET): $(OBJECTS) $(LIB_OBJS) + $(CC) $^ $(CFLAGS) -o $@ + +$(OBJECTS): %.o: %.c + $(CC) $< $(CPPFLAGS) $(CFLAGS) -c -o $@ + +$(LIB_OBJS): %.o: $(DIR_LIB)/%.c + $(CC) $< $(CPPFLAGS) $(CFLAGS) -c -o $@ + +## Dependency ## +-include $(OBJECTS:.o=.d) +-include $(LIB_OBJS:.o=.d) + +## Tasks ## +clean: + rm -f $(TARGET) $(TARGET).exe *.o *.d diff --git a/ud/c/argp_drivers.c b/ud/c/argp_drivers.c index 05f4ab1..e6baa03 100644 --- a/ud/c/argp_drivers.c +++ b/ud/c/argp_drivers.c @@ -9,7 +9,37 @@ static bool drive_help(argtok_t *tok, argerr_t *err) { static bool drive_msg(argtok_t *tok, argerr_t *err) { (void) err; - cfg.msg = strdup(tok->value); + /* +1 for \0 */ + array_append(cfg.msgs, tok->value, strlen(tok->value) + 1); + return true; +} + +static bool drive_iter(argtok_t *tok, argerr_t *err) { + char *i; + unsigned long ret; + + errno = 0; + ret = strtoul(tok->value, &i, 10); + + err->errhandle = argp_errhandle_default; + if (errno == ERANGE) { + err->reason = "out of range"; + return false; + } + if (i == tok->value) { + err->reason = "conversion not performed"; + return false; + } + if (*i != '\0') { + err->reason = "invalid trailing characters"; + return false; + } + if (ret > SIZE_MAX) { + err->reason = "iteration out of range"; + return false; + } + + cfg.iter = ret; return true; } diff --git a/ud/c/argp_drivers.internals.h b/ud/c/argp_drivers.internals.h index ba4eefe..0dc1623 100644 --- a/ud/c/argp_drivers.internals.h +++ b/ud/c/argp_drivers.internals.h @@ -1,6 +1,9 @@ #ifndef ARGP_DRIVERS_INTERNALS_H #define ARGP_DRIVERS_INTERNALS_H +#include +#include + #include "common.h" #include "config.h" #include "wrappers.h" @@ -16,6 +19,7 @@ typedef struct { static opt_driver_t drive_help; static opt_driver_t drive_msg; +static opt_driver_t drive_iter; static opt_driver_t drive_lang; static opt_errhandler_t errhandle_unrecognized_value; @@ -38,6 +42,14 @@ optmd_t optmds[] = { .drive = drive_msg, .reqv = true, .help = "specify the message to print out", + .unique = false + }, + { + .sname = 'i', + .lname = "iteration", + .drive = drive_iter, + .reqv = true, + .help = "specify the number of iteration", .unique = true }, { diff --git a/ud/c/config.c b/ud/c/config.c index b58bf51..69e9eae 100644 --- a/ud/c/config.c +++ b/ud/c/config.c @@ -3,13 +3,14 @@ extern void init_config(config_t *cfg) { cfg->srcs = array_create(NULL); - cfg->msg = NULL; + cfg->msgs = array_create(NULL); + cfg->iter = 8; cfg->lang = LangoptEnumEn; } extern void destroy_config(config_t *cfg) { array_destroy(cfg->srcs); - free(cfg->msg); + array_destroy(cfg->msgs); } extern config_statcode_t apply_config(config_t *cfg) { @@ -25,26 +26,20 @@ extern config_statcode_t apply_config(config_t *cfg) { } static config_statcode_t check_help(config_t *cfg) { - config_statcode_t ret = ConfigStatcodeOk; - if (cfg->help == false) { - return ret; + return ConfigStatcodeOk; } return print_manpage(); } static config_statcode_t check_msg(config_t *cfg) { - config_statcode_t ret = ConfigStatcodeOk; - - if (cfg->msg != NULL) { - return ret; + if (array_size(cfg->msgs) > 0) { + return ConfigStatcodeOk; } fprintf(stderr, ENPREFIX "--msg is a required flag. Terminating.\n"); - ret = ConfigStatcodeNoMsg; - - return ret; + return ConfigStatcodeNoMsg; } static config_statcode_t print_manpage(void) { @@ -64,7 +59,6 @@ static config_statcode_t print_manpage(void) { } static config_statcode_t print_manual_fallback(void) { - config_statcode_t ret = ConfigStatcodeNormalExit; FILE *fp; int ch; @@ -75,16 +69,16 @@ static config_statcode_t print_manual_fallback(void) { ENPREFIX "couldn't open the manpage from %s\n", DIR_MANPAGE_TXT ); - ret = ConfigStatcodeNoManpage; - goto cleanup; + return ConfigStatcodeNoManpage; } - while ((ch = safe_fgetc(fp)) != EOF) { - safe_fputc(stdout, ch); + while ((ch = fgetc(fp)) != EOF) { + fputc(ch, stdout); } - safe_fclose(fp); + if (fclose(fp) == EOF) { + return ConfigStatcodeErr; + } -cleanup: - return ret; + return ConfigStatcodeNormalExit; } diff --git a/ud/c/config.h b/ud/c/config.h index 8edd553..b60b8b2 100644 --- a/ud/c/config.h +++ b/ud/c/config.h @@ -13,13 +13,15 @@ typedef enum { typedef struct config { array_t *srcs; bool help; - char *msg; + array_t *msgs; + size_t iter; langopt_enum_t lang; } config_t; typedef enum { ConfigStatcodeOk, ConfigStatcodeNormalExit, + ConfigStatcodeErr, ConfigStatcodeNoMsg, ConfigStatcodeNoManpage } config_statcode_t; diff --git a/ud/c/ud.c b/ud/c/ud.c new file mode 100644 index 0000000..73c3700 --- /dev/null +++ b/ud/c/ud.c @@ -0,0 +1,88 @@ +#include "ud.internals.h" + +int main(int argc, const char *argv[]) { + int main_ret = EXIT_SUCCESS; + config_statcode_t cfg_ret; + + checkif_argc1(argc, optmds, optmds_len); + + init_config(&cfg); + parse_argv(argc, argv, optmds, optmds_len, cfg.srcs); + + cfg_ret = apply_config(&cfg); + switch (cfg_ret) { + case ConfigStatcodeOk: { + break; + } + + case ConfigStatcodeNormalExit: { + goto cleanup; + } + + case ConfigStatcodeErr: + [[fallthrough]]; + + case ConfigStatcodeNoMsg: + [[fallthrough]]; + + case ConfigStatcodeNoManpage: { + main_ret = EXIT_FAILURE; + goto cleanup; + } + + default: + ; /* control never reaches default */ + } + + work(&cfg); + +cleanup: + destroy_config(&cfg); + + return main_ret; +} + +static void checkif_argc1( + int argc, + optmd_t table[], + size_t table_len +) { + static const char *intro = + "NAME\n" + "\t" Cbwhite EXECNAME Creset + " - a fake updater\n" + "\n" + "USAGE\n" + "\t" EXECNAME " (-m | --message) string\n" + "\t" EXECNAME " (-h | --help)"; + + if (argc == 1) { + usage(table, table_len, intro); + exit(EXIT_SUCCESS); /* early exit */ + } +} + +static void work(config_t *cfg) { + size_t pidx, sidx, midx; + size_t msgs_len = array_size(cfg->msgs); + + for (size_t i = 0; i < cfg->iter; i++) { + pidx = rand_range(0, prefix_len - 1); + sidx = rand_range(0, suffix_len - 1); + midx = rand_range(0, msgs_len - 1); + printf( + "%s: %s.%s\n", + get_prefix(cfg->lang, pidx), + (char *) array_peek(cfg->msgs, midx), + suffix[sidx] + ); + } +} + +static const char *get_prefix(langopt_enum_t lang, size_t idx) { + switch (lang) { + case LangoptEnumEn: return prefix[idx].en; + case LangoptEnumKo: return prefix[idx].ko; + default: return "unknown lang"; /* control never reaches default */ + } +} diff --git a/ud/c/ud.internals.h b/ud/c/ud.internals.h new file mode 100644 index 0000000..52253bd --- /dev/null +++ b/ud/c/ud.internals.h @@ -0,0 +1,61 @@ +#ifndef UD_INTERNALS_H +#define UD_INTERNALS_H + +#include +#include + +#include "config.h" +#include "global.h" +#include "common.h" +#include "colorcodes.h" +#include "argp_drivers.h" + +typedef struct { + const char *en; + const char *ko; +} prefix_t; + +static void checkif_argc1( + int argc, + optmd_t table[], + size_t table_len +); + +static void work(config_t *cfg); +static const char *get_prefix(langopt_enum_t lang, size_t idx); + +static const prefix_t prefix[] = { + { + .en = "download", + .ko = "다운로드" + }, + { + .en = "archive", + .ko = "압축" + }, + { + .en = "build", + .ko = "빌드" + }, + { + .en = "extract", + .ko = "압축해제" + }, + { + .en = "remove", + .ko = "삭제" + } +}; +static const size_t prefix_len = ARRLEN(prefix); + +static const char *suffix[] = { + "dll", + "exe", + "zip", + "obj", + "txt", + "jpeg" + }; +static const size_t suffix_len = ARRLEN(suffix); + +#endif From e0df0f32b042ef474c97639ba158d37d799a70cc Mon Sep 17 00:00:00 2001 From: Doohyeon Won Date: Sun, 1 Nov 2026 00:21:54 +0900 Subject: [PATCH 4/7] fix: strtoul: check for - --- ud/c/argp_drivers.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ud/c/argp_drivers.c b/ud/c/argp_drivers.c index e6baa03..46fc2c7 100644 --- a/ud/c/argp_drivers.c +++ b/ud/c/argp_drivers.c @@ -18,10 +18,16 @@ static bool drive_iter(argtok_t *tok, argerr_t *err) { char *i; unsigned long ret; + err->errhandle = argp_errhandle_default; + + if (tok->value[strspn(tok->value, " \t\n\r\v\f")] == '-') { + err->reason = "iteration must not be negative"; + return false; + } + errno = 0; ret = strtoul(tok->value, &i, 10); - err->errhandle = argp_errhandle_default; if (errno == ERANGE) { err->reason = "out of range"; return false; From 8e529780668de042183e25eb8c22e2a7be26b075 Mon Sep 17 00:00:00 2001 From: Doohyeon Won Date: Sun, 1 Nov 2026 00:24:14 +0900 Subject: [PATCH 5/7] fix: --iteration => --iterate --- ud/c/argp_drivers.internals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ud/c/argp_drivers.internals.h b/ud/c/argp_drivers.internals.h index 0dc1623..ab6fee9 100644 --- a/ud/c/argp_drivers.internals.h +++ b/ud/c/argp_drivers.internals.h @@ -46,7 +46,7 @@ optmd_t optmds[] = { }, { .sname = 'i', - .lname = "iteration", + .lname = "iterate", .drive = drive_iter, .reqv = true, .help = "specify the number of iteration", From 0ab984c90493fdc8916968bd38f60e6dae8a1f9d Mon Sep 17 00:00:00 2001 From: Doohyeon Won Date: Sun, 1 Nov 2026 00:37:00 +0900 Subject: [PATCH 6/7] docs: update readme --- ud/README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ud/README.md b/ud/README.md index 09d56e3..330016e 100644 --- a/ud/README.md +++ b/ud/README.md @@ -3,5 +3,13 @@ `ud` is a fake updater. ```bash -$ ud +$ ud -m 마인크래프트해킹버전1.21.3 -m 메소복사버그v2 -i8 +remove: 메소복사버그v2.zip +extract: 마인크래프트해킹버전1.21.3.jpeg +archive: 마인크래프트해킹버전1.21.3.txt +build: 메소복사버그v2.zip +archive: 메소복사버그v2.obj +remove: 메소복사버그v2.obj +download: 마인크래프트해킹버전1.21.3.obj +archive: 메소복사버그v2.dll ``` From 325fec14ca8bd55dbc29a44e8eba9488f91d52a2 Mon Sep 17 00:00:00 2001 From: Doohyeon Won Date: Sun, 1 Nov 2026 00:58:36 +0900 Subject: [PATCH 7/7] fix: seed --- ud/c/ud.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ud/c/ud.c b/ud/c/ud.c index 73c3700..e7bb4cc 100644 --- a/ud/c/ud.c +++ b/ud/c/ud.c @@ -34,6 +34,7 @@ int main(int argc, const char *argv[]) { ; /* control never reaches default */ } + seed(); work(&cfg); cleanup: