release 1.5.0: one panel in all channels; Apple apps (iOS, new macOS tab) only in beta/dev

- stable gets the beta panel and server features (new design, presets, firewall,
  monthly traffic, router failover over all ports/addresses + TCP, altip, HR tab,
  Windows tab, update banner); ios/ macos/ windows/ sources stay out of stable
- menu item "Update to N" under Settings when a new version is out
- mobile: top menu no longer stretches to 200px
- urllib User-Agent: Cloudflare in front of git.bobyrev.com returns 403 to Python-urllib
- docs: GitHub adleibzon-rgb as source, password/uninstall/devices sections,
  new screenshots, PORTS.md TCP fallback and second IP

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andrei Leibzon
2026-11-11 18:12:13 +03:00
parent 22537b3aad
commit 1f3eced228
104 changed files with 2499 additions and 8256 deletions

View File

@@ -1,82 +0,0 @@
/* mini_argp.h
* Tiny callback-based CLI parser */
#ifndef _MINI_ARGP_H_
#define _MINI_ARGP_H_
#include <stdio.h>
#include <string.h>
typedef int (*mini_argp_cb)(const char *lname, char sname,
const char *val, void *ctx);
typedef struct {
const char *long_name; /* "--target" or NULL */
char short_name; /* 't' or 0 */
int has_arg; /* 0 flag, 1 needs val */
mini_argp_cb cb; /* your handler */
} mini_argp_opt;
/* internal: find desc by name */
static const mini_argp_opt *
margp_find(const mini_argp_opt *o, char *lname, char sname)
{
for (; o->long_name || o->short_name; o++)
if ((lname && o->long_name && !strcmp(lname,o->long_name)) ||
(sname && o->short_name==sname))
return o;
return NULL;
}
static int mini_argp_parse(int argc, char **argv,
const mini_argp_opt *opts,
void *ctx,
mini_argp_cb cb)
{
for (int i = 1; i < argc; ++i) {
char *arg = argv[i];
/* long option: --foo or --foo=bar */
if (!strncmp(arg, "--", 2)) {
char *name = arg + 2, *val = NULL;
if ((val = strchr(name, '='))) { *val = 0; ++val; }
const mini_argp_opt *o = margp_find(opts, name, 0);
if (!o) { fprintf(stderr,"unknown --%s\n", name); return -1; }
if (o->has_arg && !val) {
if (++i == argc) { fprintf(stderr,"--%s needs value\n",name);return -1; }
val = argv[i];
}
if (!o->has_arg) val = NULL;
mini_argp_cb to_call = o->cb ? o->cb : cb;
if (to_call(o->long_name, o->short_name, val, ctx)) return -1;
}
/* short(s): -a, -fVAL, -xzvf */
else if (arg[0]=='-' && arg[1]) {
for (size_t pos=1; arg[pos]; ++pos) {
char c = arg[pos];
const mini_argp_opt *o = margp_find(opts,NULL,c);
if (!o){ fprintf(stderr,"unknown -%c\n",c); return -1;}
const char *val = NULL;
if (o->has_arg) {
if (arg[pos+1]) val = &arg[pos+1]; /* -fVAL */
else if (++i < argc) val = argv[i]; /* -f VAL */
else { fprintf(stderr,"-%c needs value\n",c); return -1;}
/* Stop further char-scanning: the rest of the arg is the value */
pos = strlen(arg)-1;
}
mini_argp_cb to_call = o->cb ? o->cb : cb;
if (to_call(o->long_name, o->short_name, val, ctx)) return -1;
}
}
/* positional not allowed */
else {
fprintf(stderr,"unexpected arg: %s\n",arg); return -1;
}
}
return 0;
}
#endif/* _MINI_ARGP_H_ */