.
This commit is contained in:
commit
55385f8857
69 changed files with 1125 additions and 0 deletions
18
README
Normal file
18
README
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
depends: https://github.com/arp242/toml-c
|
||||||
|
|
||||||
|
expected usage:
|
||||||
|
(1) pkg_add /path/to/source/code/with/template/file
|
||||||
|
(2) pkg_add name of source template in source repo
|
||||||
|
|
||||||
|
We need a template format that specifies compiletime
|
||||||
|
dependencies in addition to the standart rpm spec fields
|
||||||
|
such as name, description, build script, etc..
|
||||||
|
In the case of (2), it must also specify an URL to get the
|
||||||
|
source code from.
|
||||||
|
|
||||||
|
in the end it should produce an rpm package and install it
|
||||||
|
(with dnf). referenced packages(like in dependencies) should
|
||||||
|
use the name from fedoras package list.
|
||||||
|
If a source template depends on another package that only
|
||||||
|
exists as a source template, pkg_add must make sure to
|
||||||
|
compile that first.
|
||||||
9
builder/README
Normal file
9
builder/README
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
build steps:
|
||||||
|
- create rootfs(empty fs)
|
||||||
|
- fetch all files(including dependencies) + cache
|
||||||
|
- extract/install files/deps
|
||||||
|
- chroot into rootfs
|
||||||
|
|
||||||
|
impl details:
|
||||||
|
- use queues for fetch and extract with parallel workers
|
||||||
|
- rootfs
|
||||||
10
builder/run
Executable file
10
builder/run
Executable file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#!/bin/sh
|
||||||
|
mkdir -p rootfs
|
||||||
|
podman run \
|
||||||
|
-v ./rootfs:/data \
|
||||||
|
docker.io/fedora \
|
||||||
|
dnf5 \
|
||||||
|
--installroot /data \
|
||||||
|
--repofrompath "bootstrap,https://ftp.uni-stuttgart.de/fedora/releases/44/Everything/x86_64/os/" \
|
||||||
|
--assumeyes \
|
||||||
|
install basesystem ed
|
||||||
12
conf.strff
Normal file
12
conf.strff
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
name=pkg_add
|
||||||
|
version=0.1
|
||||||
|
makedeps=muon samurai
|
||||||
|
|
||||||
|
[build]
|
||||||
|
muon setup build
|
||||||
|
samu -C build
|
||||||
|
|
||||||
|
[install]
|
||||||
|
install -d /usr/local/bin
|
||||||
|
install -m755 pkg_add /usr/local/bin
|
||||||
|
|
||||||
11
example.source-template
Normal file
11
example.source-template
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
name=lr
|
||||||
|
ver=2.0.1
|
||||||
|
descr=List files, recursively
|
||||||
|
|
||||||
|
build() {
|
||||||
|
make
|
||||||
|
}
|
||||||
|
|
||||||
|
install() {
|
||||||
|
make install
|
||||||
|
}
|
||||||
BIN
fetcher/.cache/clangd/index/fetcher.h.C36D6C766E6C351D.idx
Normal file
BIN
fetcher/.cache/clangd/index/fetcher.h.C36D6C766E6C351D.idx
Normal file
Binary file not shown.
BIN
fetcher/.cache/clangd/index/main.c.4133924D837FB6CB.idx
Normal file
BIN
fetcher/.cache/clangd/index/main.c.4133924D837FB6CB.idx
Normal file
Binary file not shown.
BIN
fetcher/.cache/clangd/index/spawnchild.c.CA3605D2CF26EC96.idx
Normal file
BIN
fetcher/.cache/clangd/index/spawnchild.c.CA3605D2CF26EC96.idx
Normal file
Binary file not shown.
10
fetcher/README
Normal file
10
fetcher/README
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
idea:
|
||||||
|
given a list of URL-to-path pairs, it downloads them in
|
||||||
|
parallel to the specified path.
|
||||||
|
|
||||||
|
implementation:
|
||||||
|
These pairs are added to a queue(FIFO) along with an
|
||||||
|
attempt counter. Multiple worker processes are spawned
|
||||||
|
that each handle an entry in a queue.
|
||||||
|
|
||||||
|
workers write to an error pipe and to a out pipe.
|
||||||
11
fetcher/a.txt
Normal file
11
fetcher/a.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>lab 0x13</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>welcome to the lab!</h1>
|
||||||
|
<p><a href="https://git.lab0x13.site/explore/repos">git</a></p>
|
||||||
|
<p><a href="intellij-colorscheme.icls">intellij colorscheme</a>
|
||||||
|
inspired by <a href="https://hank.bond/posts/highlighting-my-code-based-on-how-much-i-care/">this blog post</a></p>
|
||||||
|
</html>
|
||||||
5
fetcher/fetcher-worker.c
Normal file
5
fetcher/fetcher-worker.c
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
/*
|
||||||
|
* stdin serves as a queue in the form of
|
||||||
|
* URL outputDir
|
||||||
|
* where outputDir is the directory to save the downloaded
|
||||||
|
* file in.
|
||||||
60
fetcher/fetcher.c
Normal file
60
fetcher/fetcher.c
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <libowfat/errmsg.h>
|
||||||
|
#include <libowfat/buffer.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include "fetcher.h"
|
||||||
|
|
||||||
|
#define dieusage() die(100, "usage: ", argv0, " [-v] [-j jobs] URL...\n\
|
||||||
|
(-v means verbose)")
|
||||||
|
|
||||||
|
int verbose = 0;
|
||||||
|
int jobs = 5;
|
||||||
|
|
||||||
|
int queuepipe[2];
|
||||||
|
/* merged stdout of workers */
|
||||||
|
int errpipe[2];
|
||||||
|
/* merged stderr of workers */
|
||||||
|
int outpipe[2];
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
errmsg_iam(*argv);
|
||||||
|
int i;
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
if (argv[i][0] != '-') break;
|
||||||
|
if (argv[i][1] == '-' && !argv[i][2]) break;
|
||||||
|
switch (argv[i][1]) {
|
||||||
|
case 'j':
|
||||||
|
i++;
|
||||||
|
jobs = atoi(argv[i]);
|
||||||
|
if (jobs < 1)
|
||||||
|
die(100, "value for -n must be >= 1");
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
verbose = 1;
|
||||||
|
break;
|
||||||
|
default: dieusage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argc -= i;
|
||||||
|
argv += i;
|
||||||
|
if (argc < 1) dieusage();
|
||||||
|
|
||||||
|
if (pipe(errpipe)<0
|
||||||
|
|| pipe(outpipe)<0
|
||||||
|
) diesys(111, "pipe");
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
buffer_puts(buffer_2, "Using ");
|
||||||
|
buffer_putlong(buffer_2, jobs);
|
||||||
|
buffer_puts(buffer_2, " parallel jobs\n");
|
||||||
|
buffer_flush(buffer_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
char **fetchcmd = (char *[]){"curl", "-o", "a.txt", "https://lab0x13.site/index.html", NULL};
|
||||||
|
pid_t pid = spawnchild(fetchcmd, outpipe[1], errpipe[1]);
|
||||||
|
if (pid<0)
|
||||||
|
exit(111);
|
||||||
|
waitpid(pid, NULL, 0);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
13
fetcher/fetcher.h
Normal file
13
fetcher/fetcher.h
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef FETCHER_H
|
||||||
|
#define FETCHER_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* execs args[0] with args. output is connected to outfd
|
||||||
|
* and errfd.
|
||||||
|
* return: pid of child process or -1 on error.
|
||||||
|
*/
|
||||||
|
pid_t spawnchild(char **args, int outfd, int errfd);
|
||||||
|
|
||||||
|
#endif
|
||||||
26
fetcher/meson.build
Normal file
26
fetcher/meson.build
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
project(
|
||||||
|
'fetcher', 'c',
|
||||||
|
default_options: [
|
||||||
|
'c_std=c99',
|
||||||
|
'warning_level=2',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc = meson.get_compiler('c')
|
||||||
|
deps = [
|
||||||
|
cc.find_library('libowfat'),
|
||||||
|
dependency('libtoml'),
|
||||||
|
]
|
||||||
|
|
||||||
|
tmpdir = get_option('tmpdir')
|
||||||
|
add_project_arguments('-DTMPDIR="'+tmpdir+'"', language: 'c')
|
||||||
|
|
||||||
|
executable('fetcher', files(
|
||||||
|
'fetcher.c',
|
||||||
|
'spawnchild.c',
|
||||||
|
), dependencies:deps)
|
||||||
|
|
||||||
|
executable('fetcher-worker', files(
|
||||||
|
'fetcher-worker.c',
|
||||||
|
'spawnchild.c',
|
||||||
|
), dependencies:deps)
|
||||||
1
fetcher/meson.options
Normal file
1
fetcher/meson.options
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
option('tmpdir', type : 'string', value : '/tmp', description : 'writable directory for temporary files')
|
||||||
41
fetcher/spawnchild.c
Normal file
41
fetcher/spawnchild.c
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <libowfat/errmsg.h>
|
||||||
|
#include <libowfat/buffer.h>
|
||||||
|
|
||||||
|
static void carpsysargs(char *args[])
|
||||||
|
{
|
||||||
|
buffer_puts(buffer_2, "failed to exec");
|
||||||
|
while (*args) {
|
||||||
|
buffer_puts(buffer_2, " \'");
|
||||||
|
buffer_puts(buffer_2, *args);
|
||||||
|
buffer_puts(buffer_2, "'");
|
||||||
|
args++;
|
||||||
|
}
|
||||||
|
buffer_puts(buffer_2, ": ");
|
||||||
|
buffer_puts(buffer_2, strerror(errno));
|
||||||
|
buffer_puts(buffer_2, "\n");
|
||||||
|
buffer_flush(buffer_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_t spawnchild(char *args[], int infd, int outfd, int errfd)
|
||||||
|
{
|
||||||
|
pid_t pid = fork();
|
||||||
|
switch (pid) {
|
||||||
|
case -1: carpsys("fork: "); return -1;
|
||||||
|
case 0:
|
||||||
|
// TODO pipe
|
||||||
|
if (dup2(1, outfd)<0
|
||||||
|
|| dup2(2, errfd)<0
|
||||||
|
) {
|
||||||
|
carpsys("dup2");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
execvp(args[0], args);
|
||||||
|
carpsysargs(args);
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
}
|
||||||
23
meson.build
Normal file
23
meson.build
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
project(
|
||||||
|
'pkg_add', 'c',
|
||||||
|
default_options: [
|
||||||
|
'c_std=c99',
|
||||||
|
'warning_level=2',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc = meson.get_compiler('c')
|
||||||
|
deps = [
|
||||||
|
cc.find_library('libowfat'),
|
||||||
|
dependency('libtoml'),
|
||||||
|
]
|
||||||
|
|
||||||
|
executable('pkg_add', files(
|
||||||
|
'pkg_add.c',
|
||||||
|
'strff/strff_open.c',
|
||||||
|
'strff/strff_close.c',
|
||||||
|
'strff/strff_seek.c',
|
||||||
|
'strff/strff_read.c',
|
||||||
|
'strff/strff_read_sa.c',
|
||||||
|
'strff/strff_get.c',
|
||||||
|
), dependencies:deps)
|
||||||
BIN
pkin/.cache/clangd/index/command.h.727709215E1D2925.idx
Normal file
BIN
pkin/.cache/clangd/index/command.h.727709215E1D2925.idx
Normal file
Binary file not shown.
BIN
pkin/.cache/clangd/index/command.h.E33C7F315E9CF039.idx
Normal file
BIN
pkin/.cache/clangd/index/command.h.E33C7F315E9CF039.idx
Normal file
Binary file not shown.
BIN
pkin/.cache/clangd/index/pkin-fetch.c.B7C410291EA526B1.idx
Normal file
BIN
pkin/.cache/clangd/index/pkin-fetch.c.B7C410291EA526B1.idx
Normal file
Binary file not shown.
BIN
pkin/.cache/clangd/index/pkin-search.c.8730E14F4B8BB0EA.idx
Normal file
BIN
pkin/.cache/clangd/index/pkin-search.c.8730E14F4B8BB0EA.idx
Normal file
Binary file not shown.
BIN
pkin/.cache/clangd/index/pkin-search.c.D3DBB6646E975011.idx
Normal file
BIN
pkin/.cache/clangd/index/pkin-search.c.D3DBB6646E975011.idx
Normal file
Binary file not shown.
BIN
pkin/.cache/clangd/index/pkin.c.C675078E4F1A4042.idx
Normal file
BIN
pkin/.cache/clangd/index/pkin.c.C675078E4F1A4042.idx
Normal file
Binary file not shown.
BIN
pkin/.cache/clangd/index/pkin.c.D857533628058145.idx
Normal file
BIN
pkin/.cache/clangd/index/pkin.c.D857533628058145.idx
Normal file
Binary file not shown.
BIN
pkin/.cache/clangd/index/pkin.h.5D4259BBCB8EB07C.idx
Normal file
BIN
pkin/.cache/clangd/index/pkin.h.5D4259BBCB8EB07C.idx
Normal file
Binary file not shown.
BIN
pkin/.cache/clangd/index/pkin__spawn.c.044553C952326624.idx
Normal file
BIN
pkin/.cache/clangd/index/pkin__spawn.c.044553C952326624.idx
Normal file
Binary file not shown.
BIN
pkin/.cache/clangd/index/pkin_internal.h.C7C817E1AC1D4889.idx
Normal file
BIN
pkin/.cache/clangd/index/pkin_internal.h.C7C817E1AC1D4889.idx
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
pkin/.cache/clangd/index/pkin_repo.h.084305234E7EB486.idx
Normal file
BIN
pkin/.cache/clangd/index/pkin_repo.h.084305234E7EB486.idx
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
pkin/.cache/clangd/index/pkin_repo_simple.c.EAE9A2D3F20C471B.idx
Normal file
BIN
pkin/.cache/clangd/index/pkin_repo_simple.c.EAE9A2D3F20C471B.idx
Normal file
Binary file not shown.
17
pkin/README
Normal file
17
pkin/README
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
pkin is the binary package management frontend.
|
||||||
|
think of this as something like debian's apt or alpine's apk.
|
||||||
|
|
||||||
|
source package templates specify compile-time dependencies,
|
||||||
|
i.e. packages that are required to be present in the build
|
||||||
|
environment, e.g. gcc and glibc to compile a c project.
|
||||||
|
|
||||||
|
repositories
|
||||||
|
------------
|
||||||
|
|
||||||
|
goal:
|
||||||
|
- lazy pkg building
|
||||||
|
- lazy metadata
|
||||||
|
-
|
||||||
|
|
||||||
|
deps: aria2
|
||||||
|
makedeps: meson(or muon), ninja(or samu), a c compiler
|
||||||
2
pkin/asset/example.a
Normal file
2
pkin/asset/example.a
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
lr 1.0 foo https://lab0x13.site/index.html
|
||||||
|
asd 1.0 asd http://kentoj/index.html
|
||||||
2
pkin/asset/example.b
Normal file
2
pkin/asset/example.b
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
lsasdr 1.0 folo
|
||||||
|
lasd 1.0 asdl
|
||||||
8
pkin/command.h
Normal file
8
pkin/command.h
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef PKIN_SUBCOMMAND_H
|
||||||
|
#define PKIN_SUBCOMMAND_H
|
||||||
|
|
||||||
|
void command_search(int argc, char **argv);
|
||||||
|
|
||||||
|
void command_fetch(int argc, char **argv);
|
||||||
|
|
||||||
|
#endif
|
||||||
22
pkin/doc/pkin-repo.7.scd
Normal file
22
pkin/doc/pkin-repo.7.scd
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
pkin-repo(8)
|
||||||
|
|
||||||
|
# DESCRIPTION
|
||||||
|
|
||||||
|
Every repository really just consists of an indexfile.
|
||||||
|
The indexfile is used for querying/filtering available packages for e.g
|
||||||
|
pkin-search(8).
|
||||||
|
|
||||||
|
The indexfile plain text file where each line presents a package's most
|
||||||
|
crucial metadata: name, version and description.
|
||||||
|
These fields are tab-separated.
|
||||||
|
|
||||||
|
```
|
||||||
|
foo 1.0 foo's description
|
||||||
|
foo 1.0 foo's description
|
||||||
|
```
|
||||||
|
|
||||||
|
# LIMITATIONS
|
||||||
|
|
||||||
|
- it's hard to add fields to the indexfile with this format
|
||||||
|
- the format is not versioned. changing the format requires
|
||||||
|
changing the filename
|
||||||
24
pkin/meson.build
Normal file
24
pkin/meson.build
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
project(
|
||||||
|
'pkin', 'c',
|
||||||
|
default_options: [
|
||||||
|
'c_std=c99',
|
||||||
|
'warning_level=2',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc = meson.get_compiler('c')
|
||||||
|
deps = [
|
||||||
|
cc.find_library('libowfat'),
|
||||||
|
]
|
||||||
|
|
||||||
|
executable('pkin', files(
|
||||||
|
'./pkin.c',
|
||||||
|
'./pkin-search.c',
|
||||||
|
'./pkin-fetch.c',
|
||||||
|
'./pkin/pkin_repo_iter_init.c',
|
||||||
|
'./pkin/pkin_repo_iter_read.c',
|
||||||
|
'./pkin/pkin_pkg_fetch_prepare.c',
|
||||||
|
'./pkin/pkin_pkg_fetch_add.c',
|
||||||
|
'./pkin/pkin_pkg_fetch_start.c',
|
||||||
|
'./pkin_internal/pkin__spawn.c',
|
||||||
|
), dependencies:deps)
|
||||||
54
pkin/pkin-fetch.c
Normal file
54
pkin/pkin-fetch.c
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
#include <libowfat/errmsg.h>
|
||||||
|
#include <libowfat/str.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "../pkin.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
#define dieusage() die(100, "usage: ", argv0, " PACKGE")
|
||||||
|
|
||||||
|
static int find_package(char *name, pkin_pkgmeta *pkgmeta)
|
||||||
|
{
|
||||||
|
pkin_repo_iter iter;
|
||||||
|
pkin_repo_iter_init(&iter);
|
||||||
|
|
||||||
|
while (pkin_repo_iter_read(&iter, pkgmeta))
|
||||||
|
if (str_equal(pkgmeta->name, name))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void run(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
pkin_pkgmeta pkgmeta;
|
||||||
|
pkin_fetch_queue queue;
|
||||||
|
if (!pkin_fetch_prepare(&queue))
|
||||||
|
die(111, "failed to create package fetch queue");
|
||||||
|
|
||||||
|
for (i = 0; i < argc; i++) {
|
||||||
|
if (!find_package(argv[i], &pkgmeta))
|
||||||
|
die(100, "package '", argv[i], "' not found ");
|
||||||
|
pkin_fetch_add(&queue, pkgmeta.url, pkgmeta.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pkin_fetch_start(&queue))
|
||||||
|
die(111, "failed fetching packages");
|
||||||
|
}
|
||||||
|
|
||||||
|
void command_fetch(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
errmsg_iam("pkin-fetch");
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
if (argv[i][0] != '-') break;
|
||||||
|
if (argv[i][1] == '-' && !argv[i][2]) break;
|
||||||
|
switch (argv[i][1]) {
|
||||||
|
default: dieusage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argc -= i;
|
||||||
|
argv += i;
|
||||||
|
|
||||||
|
run(argc, argv);
|
||||||
|
}
|
||||||
54
pkin/pkin-search.c
Normal file
54
pkin/pkin-search.c
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
#include <libowfat/errmsg.h>
|
||||||
|
#include <libowfat/str.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "../pkin.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
#define dieusage() die(100, "usage: ",argv0, " PATTERN...")
|
||||||
|
|
||||||
|
static void print_meta(pkin_pkgmeta *pkgmeta)
|
||||||
|
{
|
||||||
|
buffer_puts(buffer_1, pkgmeta->name);
|
||||||
|
buffer_puts(buffer_1, "-");
|
||||||
|
buffer_puts(buffer_1, pkgmeta->version);
|
||||||
|
buffer_puts(buffer_1, ": ");
|
||||||
|
buffer_puts(buffer_1, pkgmeta->descr);
|
||||||
|
buffer_puts(buffer_1, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void run(int argc, char **argv)
|
||||||
|
{
|
||||||
|
pkin_repo_iter iter;
|
||||||
|
pkin_pkgmeta pkgmeta;
|
||||||
|
int i;
|
||||||
|
pkin_repo_iter_init(&iter);
|
||||||
|
while (pkin_repo_iter_read(&iter, &pkgmeta)) {
|
||||||
|
int matches = 1;
|
||||||
|
for (i = 0; i < argc; i++) {
|
||||||
|
if (!strstr(pkgmeta.name, argv[i]) && !strstr(pkgmeta.descr, argv[i]))
|
||||||
|
matches = 0;
|
||||||
|
}
|
||||||
|
if (matches)
|
||||||
|
print_meta(&pkgmeta);
|
||||||
|
}
|
||||||
|
if (buffer_flush(buffer_1) < 0)
|
||||||
|
carpsys("write to stdout");
|
||||||
|
}
|
||||||
|
|
||||||
|
void command_search(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
errmsg_iam("pkin-search");
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
if (argv[i][0] != '-') break;
|
||||||
|
if (argv[i][1] == '-' && !argv[i][2]) break;
|
||||||
|
switch (argv[i][1]) {
|
||||||
|
default: dieusage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argc -= i;
|
||||||
|
argv += i;
|
||||||
|
|
||||||
|
run(argc, argv);
|
||||||
|
}
|
||||||
90
pkin/pkin.c
Normal file
90
pkin/pkin.c
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
#include <libowfat/array.h>
|
||||||
|
#include <libowfat/str.h>
|
||||||
|
#include <libowfat/byte.h>
|
||||||
|
#include <libowfat/errmsg.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../pkin.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
#define dienoarg(OPT) \
|
||||||
|
do { \
|
||||||
|
carp("missing argument for -"OPT); \
|
||||||
|
dieusage(); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
int pkin_verbose = 0;
|
||||||
|
array pkin_repos;
|
||||||
|
|
||||||
|
static void add_repo(char *path, size_t pathlen)
|
||||||
|
{
|
||||||
|
char **repo;
|
||||||
|
repo = array_allocate(&pkin_repos, sizeof(char *), array_length(&pkin_repos, sizeof(char *)));
|
||||||
|
if (!repo) diesys(111, "failed allocating repository entry");
|
||||||
|
*repo = malloc(pathlen + 1);
|
||||||
|
if (!*repo) diesys(111, "failed allocating repository");
|
||||||
|
byte_copy(*repo, pathlen, path);
|
||||||
|
(*repo)[pathlen] = 0;
|
||||||
|
|
||||||
|
if (pkin_verbose) {
|
||||||
|
buffer_puts(buffer_2, "added repository ");
|
||||||
|
buffer_put(buffer_2, path, pathlen);
|
||||||
|
buffer_putsflush(buffer_2, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* imports repositories defined by the PKIN_REPOS env var */
|
||||||
|
static void env_import_repos(void) {
|
||||||
|
char *repos;
|
||||||
|
size_t l;
|
||||||
|
repos = getenv("PKIN_REPOS");
|
||||||
|
if (!repos) {
|
||||||
|
carp("PKIN_REPOS not defined");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
l = str_chr(repos, ':');
|
||||||
|
add_repo(repos, l);
|
||||||
|
if (l == str_len(repos)) break;
|
||||||
|
repos += l + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dieusage()
|
||||||
|
{
|
||||||
|
die(100, "usage: ",argv0, " [-r repository]... [-v] COMMAND\n"
|
||||||
|
" -v for verbose\n"
|
||||||
|
"Commands: search, fetch");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
errmsg_iam(*argv);
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
if (argv[i][0] != '-') break;
|
||||||
|
if (argv[i][1] == '-' && !argv[i][2]) break;
|
||||||
|
switch (argv[i][1]) {
|
||||||
|
case 'r':
|
||||||
|
if (!argv[++i]) dienoarg("r");
|
||||||
|
add_repo(argv[i], str_len(argv[i]));
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
pkin_verbose = 1;
|
||||||
|
break;
|
||||||
|
default: dieusage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argc -= i;
|
||||||
|
argv += i;
|
||||||
|
|
||||||
|
if (argc == 0) dieusage();
|
||||||
|
env_import_repos();
|
||||||
|
|
||||||
|
if (str_equal(*argv, "search"))
|
||||||
|
command_search(argc, argv);
|
||||||
|
else if (str_equal(*argv, "fetch"))
|
||||||
|
command_fetch(argc, argv);
|
||||||
|
else dieusage();
|
||||||
|
}
|
||||||
65
pkin/pkin.h
Normal file
65
pkin/pkin.h
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
#ifndef PKIN_REPO_H
|
||||||
|
#define PKIN_REPO_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* each repo is a directory with a repo-index json file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libowfat/stralloc.h>
|
||||||
|
#include <libowfat/array.h>
|
||||||
|
#include <libowfat/buffer.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <jansson.h>
|
||||||
|
|
||||||
|
#define PKIN_PKGMETA_NAME_MAX 128
|
||||||
|
#define PKIN_PKGMETA_DESCR_MAX 256
|
||||||
|
#define PKIN_PKGMETA_VERSION_MAX 256
|
||||||
|
#define PKIN_PKGMETA_URL_MAX 2048
|
||||||
|
|
||||||
|
extern int pkin_verbose;
|
||||||
|
extern array pkin_repos; /* of char * */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char name[PKIN_PKGMETA_NAME_MAX];
|
||||||
|
char descr[PKIN_PKGMETA_DESCR_MAX];
|
||||||
|
char version[PKIN_PKGMETA_VERSION_MAX];
|
||||||
|
char url[PKIN_PKGMETA_URL_MAX]; /* url to download binary package from */
|
||||||
|
} pkin_pkgmeta;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
buffer b;
|
||||||
|
int fd;
|
||||||
|
char buf[4096];
|
||||||
|
stralloc line;
|
||||||
|
size_t repos_i;
|
||||||
|
size_t repos_len;
|
||||||
|
} pkin_repo_iter;
|
||||||
|
|
||||||
|
/* parlallel querying would be nice */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* initialize a pkin_repo_query.
|
||||||
|
*/
|
||||||
|
void pkin_repo_iter_init(pkin_repo_iter *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gets the next pkgmeta.
|
||||||
|
* return: 1 if found, 0 if no next
|
||||||
|
*/
|
||||||
|
int pkin_repo_iter_read(pkin_repo_iter *, pkin_pkgmeta *res);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
buffer writeb;
|
||||||
|
char writebuf[1024];
|
||||||
|
int pipefd[2];
|
||||||
|
} pkin_fetch_queue;
|
||||||
|
|
||||||
|
int pkin_fetch_prepare(pkin_fetch_queue *queue);
|
||||||
|
void pkin_fetch_add(pkin_fetch_queue *queue, char *url, char *output);
|
||||||
|
/*
|
||||||
|
* downloads the binary package from url to the given
|
||||||
|
* directory and writes the resulting path to rest
|
||||||
|
*/
|
||||||
|
int pkin_fetch_start(pkin_fetch_queue *queue);
|
||||||
|
|
||||||
|
#endif
|
||||||
2
pkin/pkin/pkin_pkg_fetch.c
Normal file
2
pkin/pkin/pkin_pkg_fetch.c
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
int pkin_pkg_fetch(char *url, char *dir, stralloc *result);
|
||||||
8
pkin/pkin/pkin_pkg_fetch_add.c
Normal file
8
pkin/pkin/pkin_pkg_fetch_add.c
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include "../pkin.h"
|
||||||
|
|
||||||
|
void pkin_fetch_add(pkin_fetch_queue *queue, char *url, char *output)
|
||||||
|
{
|
||||||
|
buffer_puts(&queue->writeb, url);
|
||||||
|
buffer_puts(&queue->writeb, "\n -o ");
|
||||||
|
buffer_puts(&queue->writeb, output);
|
||||||
|
}
|
||||||
15
pkin/pkin/pkin_pkg_fetch_prepare.c
Normal file
15
pkin/pkin/pkin_pkg_fetch_prepare.c
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
#include <libowfat/errmsg.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "../pkin.h"
|
||||||
|
|
||||||
|
int pkin_fetch_prepare(pkin_fetch_queue *queue)
|
||||||
|
{
|
||||||
|
if (pipe(queue->pipefd) < 0) {
|
||||||
|
carpsys("pipe");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
buffer_init_write(&queue->writeb, queue->pipefd[1],
|
||||||
|
queue->writebuf, sizeof(queue->writebuf));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
27
pkin/pkin/pkin_pkg_fetch_start.c
Normal file
27
pkin/pkin/pkin_pkg_fetch_start.c
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
#include <libowfat/errmsg.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include "../pkin.h"
|
||||||
|
#include "../pkin_internal.h"
|
||||||
|
|
||||||
|
int pkin_fetch_start(pkin_fetch_queue *queue)
|
||||||
|
{
|
||||||
|
char **fetchcmd;
|
||||||
|
pid_t pid;
|
||||||
|
if (buffer_flush(&queue->writeb) < 0) {
|
||||||
|
carpsys("write to pipe");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchcmd = (char *[]){"aria2c", "-i", "-", NULL};
|
||||||
|
pid = pkin__spawn(fetchcmd, queue->pipefd[0], 1, 2);
|
||||||
|
if (pid < 0) {
|
||||||
|
carp("failed spawning aria2c to fetch files");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (waitpid(pid, NULL, 0) < 0) {
|
||||||
|
carp("waitpid");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
9
pkin/pkin/pkin_repo_iter_init.c
Normal file
9
pkin/pkin/pkin_repo_iter_init.c
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include "../pkin.h"
|
||||||
|
|
||||||
|
void pkin_repo_iter_init(pkin_repo_iter *iter)
|
||||||
|
{
|
||||||
|
iter->fd = -1;
|
||||||
|
iter->repos_i = 0;
|
||||||
|
iter->repos_len = array_length(&pkin_repos, sizeof(char *));
|
||||||
|
stralloc_init(&iter->line);
|
||||||
|
}
|
||||||
106
pkin/pkin/pkin_repo_iter_read.c
Normal file
106
pkin/pkin/pkin_repo_iter_read.c
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
#include <libowfat/array.h>
|
||||||
|
#include <libowfat/buffer.h>
|
||||||
|
#include <libowfat/errmsg.h>
|
||||||
|
#include <libowfat/byte.h>
|
||||||
|
#include <libowfat/str.h>
|
||||||
|
#include <libowfat/open.h>
|
||||||
|
#include <libowfat/stralloc.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "../pkin.h"
|
||||||
|
|
||||||
|
static int parse_field(char *line, char *field, size_t fieldmax)
|
||||||
|
{
|
||||||
|
size_t l;
|
||||||
|
l = str_chr(line, '\t');
|
||||||
|
if (l == 0) return 0;
|
||||||
|
if (l >= fieldmax) {
|
||||||
|
carp("field ", field, " is too long ");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
byte_copy(field, l, line);
|
||||||
|
field[l] = 0;
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_pkgmeta(char *line, pkin_pkgmeta *res)
|
||||||
|
{
|
||||||
|
size_t l;
|
||||||
|
|
||||||
|
l = parse_field(line, res->name, PKIN_PKGMETA_NAME_MAX);
|
||||||
|
if (l == 0) goto skip;
|
||||||
|
line += l+1;
|
||||||
|
|
||||||
|
l = parse_field(line, res->version, PKIN_PKGMETA_VERSION_MAX);
|
||||||
|
if (l == 0) goto skip;
|
||||||
|
line += l+1;
|
||||||
|
|
||||||
|
l = parse_field(line, res->descr, PKIN_PKGMETA_DESCR_MAX);
|
||||||
|
if (l == 0) goto skip;
|
||||||
|
line += l+1;
|
||||||
|
|
||||||
|
l = parse_field(line, res->url, PKIN_PKGMETA_URL_MAX);
|
||||||
|
if (l == 0) goto skip;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
skip:
|
||||||
|
carp("skipping malformed pkgmeta: '", line, "'");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int repo_iter_read(char *repo, pkin_repo_iter *iter, pkin_pkgmeta *res)
|
||||||
|
{
|
||||||
|
pkin_pkgmeta pkgmeta;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (iter->fd < 0) {
|
||||||
|
iter->fd = open_read(repo);
|
||||||
|
if (iter->fd < 0) {
|
||||||
|
carpsys("open_read repo indexfile ", repo);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
buffer_init_read(&iter->b, iter->fd, iter->buf, sizeof(iter->buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
r = buffer_getnewline_sa(&iter->b, &iter->line);
|
||||||
|
if (r == 0) return 0;
|
||||||
|
if (r < 0) {
|
||||||
|
carpsys("failed to read ", repo);
|
||||||
|
goto notfound;
|
||||||
|
}
|
||||||
|
stralloc_chomp(&iter->line);
|
||||||
|
stralloc_0(&iter->line);
|
||||||
|
if (!parse_pkgmeta(iter->line.s, &pkgmeta)) {
|
||||||
|
carp("bad pkgmeta in ", repo, ": '", iter->line.s, "'");
|
||||||
|
goto notfound;
|
||||||
|
}
|
||||||
|
*res = pkgmeta;
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
notfound:
|
||||||
|
buffer_close(&iter->b);
|
||||||
|
close(iter->fd);
|
||||||
|
iter->fd = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pkin_repo_iter_read(pkin_repo_iter *iter, pkin_pkgmeta *res)
|
||||||
|
{
|
||||||
|
char **repo;
|
||||||
|
int found;
|
||||||
|
|
||||||
|
for (; iter->repos_i < iter->repos_len; iter->repos_i++) {
|
||||||
|
repo = array_get(&pkin_repos, sizeof(char *), iter->repos_i);
|
||||||
|
found = repo_iter_read(*repo, iter, res);
|
||||||
|
if (found)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
stralloc_free(&iter->line);
|
||||||
|
if (iter->fd >= 0) {
|
||||||
|
close(iter->fd);
|
||||||
|
buffer_close(&iter->b);
|
||||||
|
iter->fd = -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
8
pkin/pkin_internal.h
Normal file
8
pkin/pkin_internal.h
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef PKIN_INTERNAL
|
||||||
|
#define PKIN_INTERNAL
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
pid_t pkin__spawn(char *args[], int infd, int outfd, int errfd);
|
||||||
|
|
||||||
|
#endif
|
||||||
43
pkin/pkin_internal/pkin__spawn.c
Normal file
43
pkin/pkin_internal/pkin__spawn.c
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <libowfat/errmsg.h>
|
||||||
|
#include <libowfat/buffer.h>
|
||||||
|
|
||||||
|
static void carpsysargs(char *args[])
|
||||||
|
{
|
||||||
|
buffer_puts(buffer_2, "failed to exec");
|
||||||
|
while (*args) {
|
||||||
|
buffer_puts(buffer_2, " \'");
|
||||||
|
buffer_puts(buffer_2, *args);
|
||||||
|
buffer_puts(buffer_2, "'");
|
||||||
|
args++;
|
||||||
|
}
|
||||||
|
buffer_puts(buffer_2, ": ");
|
||||||
|
buffer_puts(buffer_2, strerror(errno));
|
||||||
|
buffer_puts(buffer_2, "\n");
|
||||||
|
buffer_flush(buffer_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_t pkin__spawn(char *args[], int infd, int outfd, int errfd)
|
||||||
|
{
|
||||||
|
pid_t pid = fork();
|
||||||
|
switch (pid) {
|
||||||
|
case -1: carpsys("fork: "); return -1;
|
||||||
|
case 0:
|
||||||
|
// TODO pipe
|
||||||
|
if (dup2(0, infd)<0
|
||||||
|
|| dup2(1, outfd)<0
|
||||||
|
|| dup2(2, errfd)<0
|
||||||
|
) {
|
||||||
|
carpsys("dup2");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
execvp(args[0], args);
|
||||||
|
carpsysargs(args);
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
51
strff.h
Normal file
51
strff.h
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
/* string file format */
|
||||||
|
#ifndef STRFF_H
|
||||||
|
#define STRFF_H
|
||||||
|
|
||||||
|
#include <libowfat/stralloc.h>
|
||||||
|
#include <libowfat/buffer.h>
|
||||||
|
|
||||||
|
enum strff_type {
|
||||||
|
STRFF_TYPE_NONE = 0,
|
||||||
|
STRFF_TYPE_BRACKET,
|
||||||
|
STRFF_TYPE_EQUAL
|
||||||
|
};
|
||||||
|
|
||||||
|
struct strff {
|
||||||
|
buffer b;
|
||||||
|
char buf[1024];
|
||||||
|
int fd;
|
||||||
|
enum strff_type fieldtype;
|
||||||
|
};
|
||||||
|
|
||||||
|
void strff_open(struct strff *, int fd);
|
||||||
|
void strff_close(struct strff *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* seeks for a field with the specified key in the file.
|
||||||
|
* sets cursor position ofc.
|
||||||
|
* strff_read can be used to get the value.
|
||||||
|
* key may not contain '['.
|
||||||
|
* if key not found, sets errno to ENOKEY
|
||||||
|
* return: 1 if found, 0 on error.
|
||||||
|
*/
|
||||||
|
int strff_seek(struct strff *, char *key);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* reads n bytes into buf.
|
||||||
|
* return: bytes read, 0 on end-of-field, -1 on error.
|
||||||
|
*/
|
||||||
|
int strff_read(struct strff *, size_t buflen, char buf[buflen]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* same as strff_read but reads the whole value into sa
|
||||||
|
* return: 1 on success, 0 on error.
|
||||||
|
*/
|
||||||
|
int strff_read_sa(struct strff *, stralloc *sa);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* wrapper around strff_seek and strff_read_sa.
|
||||||
|
*/
|
||||||
|
int strff_get(struct strff *, char *key, stralloc *sa);
|
||||||
|
|
||||||
|
#endif
|
||||||
6
strff/strff_close.c
Normal file
6
strff/strff_close.c
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
#include "../strff.h"
|
||||||
|
|
||||||
|
void strff_close(struct strff *strff)
|
||||||
|
{
|
||||||
|
buffer_close(&strff->b);
|
||||||
|
}
|
||||||
8
strff/strff_get.c
Normal file
8
strff/strff_get.c
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include "../strff.h"
|
||||||
|
|
||||||
|
int strff_get(struct strff *strff, char *key, stralloc *sa)
|
||||||
|
{
|
||||||
|
if (!strff_seek(strff, key))
|
||||||
|
return 0;
|
||||||
|
return strff_read_sa(strff, sa);
|
||||||
|
}
|
||||||
8
strff/strff_open.c
Normal file
8
strff/strff_open.c
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include "../strff.h"
|
||||||
|
#include <libowfat/byte.h>
|
||||||
|
|
||||||
|
void strff_open(struct strff *strff, int fd)
|
||||||
|
{
|
||||||
|
byte_zero(strff, sizeof *strff);
|
||||||
|
strff->fd = fd;
|
||||||
|
}
|
||||||
44
strff/strff_read.c
Normal file
44
strff/strff_read.c
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#include "../strff.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
int strff_read(struct strff *strff, size_t buflen, char buf[buflen])
|
||||||
|
{
|
||||||
|
size_t nread;
|
||||||
|
int r;
|
||||||
|
char c;
|
||||||
|
int isnewline;
|
||||||
|
if (strff->fieldtype == STRFF_TYPE_NONE) {
|
||||||
|
errno = EINVAL; /* cannot read NONE field */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
isnewline = 1;
|
||||||
|
nread = 0;
|
||||||
|
while (nread < buflen) {
|
||||||
|
r = buffer_peekc(&strff->b, &c);
|
||||||
|
if (r < 0) return -1;
|
||||||
|
if (r == 0) {
|
||||||
|
if (isnewline && nread > 0)
|
||||||
|
nread--; /* remove last \n */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strff->fieldtype == STRFF_TYPE_EQUAL && c == '\n')
|
||||||
|
break;
|
||||||
|
else if (strff->fieldtype == STRFF_TYPE_BRACKET) {
|
||||||
|
if (isnewline && c == '[') {
|
||||||
|
if (nread > 0)
|
||||||
|
nread--; /* remove last \n */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
isnewline = 0;
|
||||||
|
if (c == '\n')
|
||||||
|
isnewline = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[nread++] = c;
|
||||||
|
strff->b.p++;
|
||||||
|
}
|
||||||
|
return nread;
|
||||||
|
}
|
||||||
15
strff/strff_read_sa.c
Normal file
15
strff/strff_read_sa.c
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
#include "../strff.h"
|
||||||
|
#include <libowfat/stralloc.h>
|
||||||
|
|
||||||
|
int strff_read_sa(struct strff *strff, stralloc *sa)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
char buf[1024];
|
||||||
|
for (;;) {
|
||||||
|
n = strff_read(strff, sizeof buf, buf);
|
||||||
|
if (n == 0) break;
|
||||||
|
if (n < 0) return 0;
|
||||||
|
if (!stralloc_catb(sa, buf, n)) return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
124
strff/strff_seek.c
Normal file
124
strff/strff_seek.c
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
#include "../strff.h"
|
||||||
|
|
||||||
|
#include <libowfat/buffer.h>
|
||||||
|
#include <libowfat/stralloc.h>
|
||||||
|
#include <libowfat/errmsg.h>
|
||||||
|
#include <libowfat/str.h>
|
||||||
|
#include <libowfat/byte.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <alloca.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
keys can be defined either with key= or with [key].
|
||||||
|
The first is the equalform, the second the bracketform.
|
||||||
|
There can be no keyforms after the bracketform.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int skip_to_next_line(buffer *b)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
char c;
|
||||||
|
for (;;) {
|
||||||
|
r = buffer_getc(b, &c);
|
||||||
|
if (r == 0 || c == '\n') break;
|
||||||
|
if (r < 0) return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* advances the cursor until it is positioned at the value of a
|
||||||
|
* field. It will look for both the equalform and bracketform of
|
||||||
|
* the field, and returns STRFF_TYPE_BRACKET or STRFF_TYPE_EQUAL
|
||||||
|
* accordingly. If no such field is found, it returns STRFF_TYPE_NONE.
|
||||||
|
* On error, -1 is returned.
|
||||||
|
*/
|
||||||
|
static int seek_field(buffer *b, char *equalform, char *bracketform)
|
||||||
|
{
|
||||||
|
size_t linemax, linelen;
|
||||||
|
char *line;
|
||||||
|
int r;
|
||||||
|
/* bracketform is longer */
|
||||||
|
linemax = str_len(bracketform) + 1;
|
||||||
|
line = alloca(linemax);
|
||||||
|
linelen = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
r = buffer_getc(b, line + linelen);
|
||||||
|
if (r < 0) return -1;
|
||||||
|
if (r == 0) break;
|
||||||
|
linelen++;
|
||||||
|
|
||||||
|
if (byte_starts(line, linelen, bracketform)) {
|
||||||
|
return STRFF_TYPE_BRACKET;
|
||||||
|
}
|
||||||
|
if (line[0] == '[') {
|
||||||
|
/* equalform cannot come after a bracketform */
|
||||||
|
equalform = NULL;
|
||||||
|
}
|
||||||
|
if (equalform && byte_starts(line, linelen, equalform)){
|
||||||
|
return STRFF_TYPE_EQUAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line[linelen-1] == '\n') {
|
||||||
|
/* reset line */
|
||||||
|
linelen = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (linelen == linemax) {
|
||||||
|
if (!skip_to_next_line(b))
|
||||||
|
return -1;
|
||||||
|
linelen = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* not found */
|
||||||
|
return STRFF_TYPE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int to_equalform(char *key, char *result)
|
||||||
|
{
|
||||||
|
size_t l;
|
||||||
|
l = str_copy(result, key);
|
||||||
|
result[l++] = '=';
|
||||||
|
result[l++] = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int to_bracketform(char *key, char *result)
|
||||||
|
{
|
||||||
|
size_t l;
|
||||||
|
l = 0;
|
||||||
|
result[l++] = '[';
|
||||||
|
l += str_copy(result + l, key);
|
||||||
|
result[l++] = ']';
|
||||||
|
result[l++] = '\n';
|
||||||
|
result[l++] = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int strff_seek(struct strff *strff, char *key) {
|
||||||
|
char *equalform, *bracketform;
|
||||||
|
int fieldtype;
|
||||||
|
if (str_chr(key, '[') != str_len(key)) {
|
||||||
|
errno = EINVAL; /* key cannot contain '[' */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
equalform = alloca(str_len(key) + 2);
|
||||||
|
to_equalform(key, equalform);
|
||||||
|
bracketform = alloca(str_len(key) + 4);
|
||||||
|
to_bracketform(key, bracketform);
|
||||||
|
|
||||||
|
buffer_init(&strff->b, read, strff->fd, strff->buf, sizeof strff->buf);
|
||||||
|
lseek(strff->fd, 0, SEEK_SET);
|
||||||
|
fieldtype = seek_field(&strff->b, equalform, bracketform);
|
||||||
|
if (fieldtype < 0) return 0;
|
||||||
|
strff->fieldtype = fieldtype;
|
||||||
|
if (fieldtype == STRFF_TYPE_NONE) {
|
||||||
|
errno = ENOKEY;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
63
strff_test.c
Normal file
63
strff_test.c
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
#include <libowfat/open.h>
|
||||||
|
#include <libowfat/errmsg.h>
|
||||||
|
#include <libowfat/stralloc.h>
|
||||||
|
#include "strff.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
stralloc name;
|
||||||
|
stralloc version;
|
||||||
|
stralloc makedeps;
|
||||||
|
stralloc buildcmd;
|
||||||
|
stralloc installcmd;
|
||||||
|
} pkg;
|
||||||
|
|
||||||
|
static struct strff cfgff;
|
||||||
|
|
||||||
|
static void pkg_load(pkg *pkg, char *path)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
fd = open_read(path);
|
||||||
|
if (fd < 0)
|
||||||
|
diesys(111, "open_read ", path);
|
||||||
|
|
||||||
|
stralloc_init(&pkg->name);
|
||||||
|
stralloc_init(&pkg->version);
|
||||||
|
stralloc_init(&pkg->makedeps);
|
||||||
|
stralloc_init(&pkg->buildcmd);
|
||||||
|
stralloc_init(&pkg->installcmd);
|
||||||
|
strff_open(&cfgff, fd);
|
||||||
|
|
||||||
|
if (!strff_get(&cfgff, "name", &pkg->name))
|
||||||
|
diesys(111, "cannot get value for name");
|
||||||
|
if (!strff_get(&cfgff, "version", &pkg->version))
|
||||||
|
diesys(111, "cannot get value for version");
|
||||||
|
if (!strff_get(&cfgff, "makedeps", &pkg->makedeps))
|
||||||
|
diesys(111, "cannot get value for makedeps");
|
||||||
|
if (!strff_get(&cfgff, "build", &pkg->buildcmd))
|
||||||
|
diesys(111, "cannot get value for buildcmd");
|
||||||
|
if (!strff_get(&cfgff, "install", &pkg->installcmd))
|
||||||
|
diesys(111, "cannot get value for installcmd");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
pkg pkg;
|
||||||
|
pkg_load(&pkg, "./conf.strff");
|
||||||
|
|
||||||
|
buffer_puts(buffer_1, "name is '");
|
||||||
|
buffer_put(buffer_1, pkg.name.s, pkg.name.len);
|
||||||
|
buffer_puts(buffer_1, "', ");
|
||||||
|
buffer_puts(buffer_1, "version is '");
|
||||||
|
buffer_put(buffer_1, pkg.version.s, pkg.version.len);
|
||||||
|
buffer_puts(buffer_1, "', ");
|
||||||
|
buffer_puts(buffer_1, "makedeps is '");
|
||||||
|
buffer_put(buffer_1, pkg.makedeps.s, pkg.makedeps.len);
|
||||||
|
buffer_puts(buffer_1, "', ");
|
||||||
|
buffer_puts(buffer_1, "buildcmd is '");
|
||||||
|
buffer_put(buffer_1, pkg.buildcmd.s, pkg.buildcmd.len);
|
||||||
|
buffer_puts(buffer_1, "', ");
|
||||||
|
buffer_puts(buffer_1, "installcmd is '");
|
||||||
|
buffer_put(buffer_1, pkg.installcmd.s, pkg.installcmd.len);
|
||||||
|
buffer_putsflush(buffer_1, "'\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue