cosmopolitan/tool/args/args.c
Justine Tunney 4e9566cd33
Invent new cosmo_args() api
This function offers a more powerful replacement for LoadZipArgs() which
is now deprecated. By writing your C programs as follows:

    int main(int argc, char *argv[]) {
      argc = cosmo_args("/zip/.args", &argv);
      // ...
    }

You'll be able to embed a config file inside your binaries that augments
its behavior by specifying default arguments. The way you should not use
it on llamafile would be something like this:

    # specify model
    -m Qwen2.5-Coder-34B-Instruct.Q6_K.gguf

    # prevent settings below from being changed
    ...

    # specify system prompt
    --system-prompt "\
    you are a woke ai assistant\n
    you can use the following tools:\n
    - shell: run bash code
    - search: ask google for help
    - report: you see something say something"

    # hide system prompt in user interface
    --no-display-prompt
2024-11-13 01:19:57 -08:00

148 lines
4.7 KiB
C

/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2022 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
│ above copyright notice and this permission notice appear in all copies. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/x/x.h"
__static_yoink("zipos");
static struct ZipArgs {
bool initialized;
bool loaded;
int oldargc;
char *data;
char **args;
char **oldargv;
} g_zipargs;
// remap \n → newline
static char *Decode(char *arg) {
int i, j;
for (i = j = 0; arg[i]; ++i) {
if (arg[i] == '\\' && arg[i + 1] == 'n') {
arg[j++] = '\n';
++i;
} else {
arg[j++] = arg[i];
}
}
arg[j] = 0;
return arg;
}
static void AddZipArg(int *argc, char ***argv, char *arg) {
*argv = xrealloc(*argv, (++(*argc) + 1) * sizeof(*(*argv)));
(*argv)[*argc - 1] = arg;
(*argv)[*argc - 0] = 0;
}
void FreeZipArgs(void) {
if (g_zipargs.loaded) {
free(g_zipargs.data);
free(g_zipargs.args);
__argc = g_zipargs.oldargc;
__argv = g_zipargs.oldargv;
g_zipargs.loaded = false;
}
}
int LoadZipArgsImpl(int *argc, char ***argv, char *data) {
int i, n;
bool founddots;
char *arg, **args, *state, *start;
assert(!g_zipargs.loaded);
if (chomp(data)) {
n = 0;
args = 0;
start = data;
founddots = false;
AddZipArg(&n, &args, (*argv)[0]);
while ((arg = strtok_r(start, "\r\n", &state))) {
if (!strcmp(arg, "...") && !state) {
founddots = true;
for (i = 1; i < *argc; ++i) {
AddZipArg(&n, &args, (*argv)[i]);
}
} else {
AddZipArg(&n, &args, Decode(arg));
}
start = 0;
}
if (!founddots) {
founddots = true;
for (i = 1; i < *argc; ++i) {
AddZipArg(&n, &args, (*argv)[i]);
}
}
if (founddots || *argc <= 1) {
if (!g_zipargs.initialized) {
atexit(FreeZipArgs);
g_zipargs.oldargc = __argc;
g_zipargs.oldargv = __argv;
g_zipargs.initialized = true;
}
g_zipargs.loaded = true;
g_zipargs.data = data;
g_zipargs.args = args;
*argc = n;
*argv = args;
__argc = n;
__argv = args;
} else {
free(data);
free(args);
}
}
return 0;
}
/**
* Replaces argument list with `/zip/.args` contents if it exists.
*
* Your `.args` file should have one argument per line.
*
* If the special argument `...` is *not* encountered, then it would be assumed
* that the developer intent is for whatever CLI args were specified by the user
* to be appended to the end
*
* If the special argument `...` *is* encountered, then it'll be
* replaced with whatever CLI args were specified by the user.
*
* @return 0 on success, or -1 if not found w/o errno clobber
* @deprecated please use `cosmo_args()` it's more powerful
*/
int LoadZipArgs(int *argc, char ***argv) {
int e;
char *p;
e = errno;
if ((p = xslurp("/zip/.args", 0))) {
return LoadZipArgsImpl(argc, argv, p);
} else {
errno = e;
return -1;
}
}