pkin/strff/strff_seek.c
2026-09-04 19:59:24 +02:00

124 lines
2.8 KiB
C

#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;
}