at work
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*~
|
||||
*_test
|
||||
*.o
|
||||
*geany
|
||||
73
Makefile
Normal file
73
Makefile
Normal file
@@ -0,0 +1,73 @@
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -O -I. -std=c99 -pthread
|
||||
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) -o $@ $<
|
||||
|
||||
rcache.c: rcache.h
|
||||
rcache.o: rcache.c
|
||||
|
||||
RCACHE_OBJS = rcache.o massert.o
|
||||
rcache_test: rcache_test.o $(RCACHE_OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $< $(RCACHE_OBJS)
|
||||
|
||||
JLEXER_OBJS = jlexer.o massert.o rcache.o
|
||||
jlexer_test: jlexer_test.o $(JLEXER_OBJS)
|
||||
$(CC) -o $@ $< $(JLEXER_OBJS)
|
||||
|
||||
JPARSER_OBJS = jparser.o $(JLEXER_OBJS)
|
||||
jparser_test: jparser_test.o $(JPARSER_OBJS)
|
||||
$(CC) -o $@ $< $(JPARSER_OBJS)
|
||||
|
||||
CLLEXER_OBJS = cllexer.o massert.o
|
||||
cllexer_test: cllexer_test.o $(CLLEXER_OBJS)
|
||||
$(CC) -o $@ $< $(CLLEXER_OBJS)
|
||||
|
||||
CLPARSER_OBJS = clparser.o $(CLLEXER_OBJS)
|
||||
clparser_test: clparser_test.o $(CLPARSER_OBJS)
|
||||
$(CC) -o $@ $< $(CLPARSER_OBJS)
|
||||
|
||||
CFLEXER_OBJS = cflexer.o $(RCACHE_OBJS)
|
||||
cflexer_test: cflexer_test.o $(CFLEXER_OBJS)
|
||||
$(CC) -o $@ $< $(CFLEXER_OBJS)
|
||||
|
||||
|
||||
CFPARSER_OBJS = cfparser.o $(CFLEXER_OBJS)
|
||||
cfparser_test: cfparser_test.o $(CFPARSER_OBJS)
|
||||
$(CC) -o $@ $< $(CFPARSER_OBJS)
|
||||
|
||||
|
||||
all: $(TESTS)
|
||||
test: $(TESTS)
|
||||
|
||||
#TESTS += cllexer_test
|
||||
#TESTS += clparser_test
|
||||
#TESTS += rcache_test
|
||||
#TESTS += jlexer_test
|
||||
#TESTS += jparser_test
|
||||
TESTS += cflexer_test
|
||||
TESTS += cfparser_test
|
||||
|
||||
|
||||
all: $(TESTS)
|
||||
|
||||
test: $(TESTS)
|
||||
# ./cllexer_test
|
||||
# ./clparser_test
|
||||
# ./rcache_test
|
||||
# ./jlexer_test
|
||||
# ./jparser_test
|
||||
# ./cflexer_test
|
||||
./cfparser_test
|
||||
|
||||
|
||||
clean:
|
||||
rm -f *_test
|
||||
rm -f *.o *~
|
||||
rm -f *.gch
|
||||
|
||||
|
||||
|
||||
#EOF
|
||||
245
cflexer.c
Normal file
245
cflexer.c
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright 2023 Oleg Borodin <borodin@unix7.org>
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <rcache.h>
|
||||
#include <cflexer.h>
|
||||
|
||||
|
||||
#define CFLEXTYPE_CHAR 1
|
||||
#define CFLEXTYPE_COMM 2
|
||||
#define CFLEXTYPE_EOF 3
|
||||
#define CFLEXTYPE_NEWLN 4
|
||||
#define CFLEXTYPE_SCR 5
|
||||
#define CFLEXTYPE_SEPAR 6
|
||||
#define CFLEXTYPE_SPACE 7
|
||||
#define CFLEXTYPE_UNDEF 8
|
||||
#define CFLEXTYPE_WORDL 9
|
||||
|
||||
static int get_ltype(char letter) {
|
||||
switch (letter) {
|
||||
case EOF:
|
||||
return CFLEXTYPE_EOF;
|
||||
case ' ':
|
||||
case '\t':
|
||||
return CFLEXTYPE_SPACE;
|
||||
case '=':
|
||||
return CFLEXTYPE_SEPAR;
|
||||
case '\n':
|
||||
return CFLEXTYPE_NEWLN;
|
||||
case '#':
|
||||
return CFLEXTYPE_COMM;
|
||||
case '"':
|
||||
return CFLEXTYPE_WORDL;
|
||||
case '\\':
|
||||
return CFLEXTYPE_SCR;
|
||||
default:
|
||||
return CFLEXTYPE_CHAR;
|
||||
}
|
||||
return CFLEXTYPE_UNDEF;
|
||||
}
|
||||
|
||||
void cflexer_init(cflexer_t * lexer, rcache_t * cache) {
|
||||
lexer->cache = cache;
|
||||
lexer->context = CFLEXCONT_UNDEF;
|
||||
lexer->tokpos = 0;
|
||||
lexer->letter = EOF;
|
||||
lexer->rewind = false;
|
||||
lexer->screen = false;
|
||||
}
|
||||
|
||||
int cflexer_gettoken(cflexer_t * lexer, char* token) {
|
||||
|
||||
while (true) {
|
||||
if (!lexer->rewind) {
|
||||
lexer->letter = rcache_getc(lexer->cache);
|
||||
}
|
||||
lexer->rewind = false;
|
||||
int type = get_ltype(lexer->letter);
|
||||
|
||||
switch (lexer->context) {
|
||||
case CFLEXCONT_END:{
|
||||
lexer->context = CFLEXCONT_END;
|
||||
lexer->tokpos = 0;
|
||||
lexer->rewind = true;
|
||||
strcpy(token, "END");
|
||||
return CFLEXTOK_END;
|
||||
}
|
||||
case CFLEXCONT_UNDEF:{
|
||||
switch (type) {
|
||||
case CFLEXTYPE_EOF:{
|
||||
lexer->context = CFLEXCONT_END;
|
||||
lexer->rewind = true;
|
||||
break;
|
||||
}
|
||||
case CFLEXTYPE_CHAR:{
|
||||
lexer->tokpos = 0;
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
lexer->context = CFLEXCONT_WORD;
|
||||
break;
|
||||
}
|
||||
case CFLEXTYPE_SEPAR:{
|
||||
strcpy(token, "=");
|
||||
lexer->context = CFLEXCONT_UNDEF;
|
||||
return CFLEXTOK_SEPAR;
|
||||
}
|
||||
case CFLEXTYPE_NEWLN:{
|
||||
lexer->tokpos = 0;
|
||||
token[lexer->tokpos] = '\0';
|
||||
strcpy(token, "NEWLN");
|
||||
lexer->context = CFLEXCONT_UNDEF;
|
||||
return CFLEXTOK_NEXT;
|
||||
}
|
||||
case CFLEXTYPE_SPACE:{
|
||||
lexer->tokpos = 0;
|
||||
token[lexer->tokpos] = '\0';
|
||||
lexer->context = CFLEXCONT_SPACE;
|
||||
break;
|
||||
}
|
||||
case CFLEXTYPE_COMM:{
|
||||
lexer->tokpos = 0;
|
||||
token[lexer->tokpos] = '\0';
|
||||
lexer->context = CFLEXCONT_COMM;
|
||||
break;
|
||||
}
|
||||
case CFLEXTYPE_WORDL:{
|
||||
lexer->tokpos = 0;
|
||||
token[lexer->tokpos] = '\0';
|
||||
lexer->context = CFLEXCONT_LWORD;
|
||||
break;
|
||||
}
|
||||
case CFLEXTYPE_SCR: {
|
||||
lexer->tokpos = 0;
|
||||
lexer->screen = true;
|
||||
lexer->context = CFLEXCONT_WORD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CFLEXCONT_WORD:{
|
||||
switch (type) {
|
||||
case CFLEXTYPE_SCR: {
|
||||
if (lexer->screen == true) {
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
lexer->screen = false;
|
||||
} else {
|
||||
lexer->screen = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case CFLEXTYPE_CHAR:
|
||||
break;
|
||||
case CFLEXTYPE_EOF:
|
||||
default: {
|
||||
if (lexer->screen == true) {
|
||||
lexer->screen = false;
|
||||
break;
|
||||
}
|
||||
token[lexer->tokpos++] = '\0';
|
||||
lexer->context = CFLEXCONT_UNDEF;
|
||||
lexer->rewind = true;
|
||||
lexer->screen = false;
|
||||
return CFLEXTOK_WORD;
|
||||
}
|
||||
}
|
||||
lexer->screen = false;
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
break;
|
||||
}
|
||||
case CFLEXCONT_LWORD:{
|
||||
switch (type) {
|
||||
case CFLEXTYPE_SCR: {
|
||||
if (lexer->screen == true) {
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
lexer->screen = false;
|
||||
} else {
|
||||
lexer->screen = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case CFLEXTYPE_WORDL: {
|
||||
if (lexer->screen == true) {
|
||||
lexer->screen = false;
|
||||
break;
|
||||
}
|
||||
token[lexer->tokpos++] = '\0';
|
||||
lexer->context = CFLEXCONT_UNDEF;
|
||||
lexer->screen = false;
|
||||
return CFLEXTOK_WORD;
|
||||
}
|
||||
case CFLEXTYPE_EOF: {
|
||||
token[lexer->tokpos++] = '\0';
|
||||
lexer->context = CFLEXCONT_UNDEF;
|
||||
lexer->rewind = true;
|
||||
return CFLEXTOK_WORD;
|
||||
}
|
||||
default:{
|
||||
break;
|
||||
}
|
||||
}
|
||||
lexer->screen = false;
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
break;
|
||||
}
|
||||
case CFLEXCONT_SPACE:{
|
||||
switch (type) {
|
||||
case CFLEXTYPE_SPACE:
|
||||
break;
|
||||
case CFLEXTYPE_EOF:
|
||||
default: {
|
||||
lexer->rewind = true;
|
||||
lexer->context = CFLEXCONT_UNDEF;
|
||||
continue;
|
||||
//lexer->context = CFLEXCONT_UNDEF;
|
||||
//lexer->rewind = true;
|
||||
//strcpy(token, "SPACE");
|
||||
//return CFLEXTOK_SPACE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CFLEXCONT_NEWLN:{
|
||||
switch (type) {
|
||||
case CFLEXTYPE_NEWLN:
|
||||
break;
|
||||
case CFLEXTYPE_EOF:
|
||||
default: {
|
||||
lexer->rewind = true;
|
||||
lexer->context = CFLEXCONT_UNDEF;
|
||||
strcpy(token, "NEWSLN");
|
||||
return CFLEXTOK_NEXT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CFLEXCONT_COMM:{
|
||||
switch (type) {
|
||||
case CFLEXTYPE_EOF:
|
||||
case CFLEXTYPE_NEWLN:
|
||||
lexer->context = CFLEXCONT_UNDEF;
|
||||
lexer->rewind = true;
|
||||
strcpy(token, "COMMENT");
|
||||
return CFLEXTOK_COMM;
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
strcpy(token, "UNDEF");
|
||||
return CFLEXTOK_UNDEF;
|
||||
}
|
||||
|
||||
void cflexer_destroy(cflexer_t * lexer) {
|
||||
(void)lexer;
|
||||
}
|
||||
46
cflexer.h
Normal file
46
cflexer.h
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
#ifndef CFLEXER_H_QWERTY
|
||||
#define CFLEXER_H_QWERTY
|
||||
|
||||
#include <rcache.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
rcache_t* cache;
|
||||
int fd;
|
||||
int context;
|
||||
char letter;
|
||||
int tokpos;
|
||||
bool rewind;
|
||||
bool screen;
|
||||
} cflexer_t;
|
||||
|
||||
|
||||
#define CFLEXCONT_COMM 1
|
||||
#define CFLEXCONT_END 2
|
||||
#define CFLEXCONT_LWORD 3
|
||||
#define CFLEXCONT_SEPAR 4
|
||||
#define CFLEXCONT_SPACE 5
|
||||
#define CFLEXCONT_UNDEF 6
|
||||
#define CFLEXCONT_UNKNOW 7
|
||||
#define CFLEXCONT_WORD 8
|
||||
#define CFLEXCONT_NEWLN 9
|
||||
|
||||
|
||||
#define CFLEXTOK_BLOCKB 1
|
||||
#define CFLEXTOK_COMM 2
|
||||
#define CFLEXTOK_END 3
|
||||
#define CFLEXTOK_NEXT 4
|
||||
#define CFLEXTOK_SEPAR 5
|
||||
#define CFLEXTOK_SPACE 6
|
||||
#define CFLEXTOK_UNDEF 7
|
||||
#define CFLEXTOK_UNKNOW 8
|
||||
#define CFLEXTOK_WORD 9
|
||||
|
||||
|
||||
void cflexer_init(cflexer_t * lexer, rcache_t * cache);
|
||||
int cflexer_gettoken(cflexer_t * lexer, char* token);
|
||||
void cflexer_destroy(cflexer_t * lexer);
|
||||
|
||||
|
||||
#endif
|
||||
39
cflexer_test.c
Normal file
39
cflexer_test.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2023 Oleg Borodin <borodin@unix7.org>
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <massert.h>
|
||||
#include <rcache.h>
|
||||
#include <cflexer.h>
|
||||
|
||||
int main(void) {
|
||||
|
||||
int fd = open("test.conf", O_RDONLY);
|
||||
MASSERT(fd > 0);
|
||||
|
||||
rcache_t cache;
|
||||
rcache_init(&cache, fd);
|
||||
|
||||
cflexer_t lexer;
|
||||
cflexer_init(&lexer, &cache);
|
||||
|
||||
char token[1024];
|
||||
int type = 0;
|
||||
|
||||
while ((type = cflexer_gettoken(&lexer, token)) != CFLEXTOK_END) {
|
||||
printf("[%d]: [%s]\n", type, token);
|
||||
}
|
||||
printf("[%d]: [%s]\n", type, token);
|
||||
|
||||
rcache_destroy(&cache);
|
||||
|
||||
return 0;
|
||||
}
|
||||
152
cfparser.c
Normal file
152
cfparser.c
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 2023 Oleg Borodin <borodin@unix7.org>
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#include <cfparser.h>
|
||||
|
||||
#define INIT_BSIZE 64
|
||||
|
||||
|
||||
static char* strcopy(char* src) {
|
||||
size_t srcsize = strlen(src) + 1;
|
||||
char* dst = malloc(srcsize);
|
||||
|
||||
memset(dst, '\0', srcsize);
|
||||
strcpy(dst, src);
|
||||
return dst;
|
||||
}
|
||||
|
||||
static char* strconcat(char** str, int num) {
|
||||
size_t tsize = 0;
|
||||
size_t size[num];
|
||||
|
||||
for (int i = 0; i < num; i++) {
|
||||
size[i] = 0;
|
||||
if (str[i] != NULL) {
|
||||
size[i] = strlen(str[i]);
|
||||
tsize += size[i];
|
||||
}
|
||||
}
|
||||
tsize++;
|
||||
char* dst = malloc(tsize);
|
||||
|
||||
memset(dst, '\0', tsize);
|
||||
int pos = 0;
|
||||
|
||||
for (int i = 0; i < num; i++) {
|
||||
if (str[i] != NULL) {
|
||||
strcpy(&dst[pos], str[i]);
|
||||
pos += size[i];
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
void cfparser_init(cfparser_t * parser, cflexer_t * lexer) {
|
||||
parser->lexer = lexer;
|
||||
parser->kvalarr = malloc(sizeof(cfkval_t) * INIT_BSIZE);
|
||||
parser->kvalcapa = INIT_BSIZE;
|
||||
parser->kvalsize = 0;
|
||||
}
|
||||
|
||||
void cfparser_bind(cfparser_t * parser, int type, char* key, void* ref) {
|
||||
for (int i = 0; i < parser->kvalsize; i++) {
|
||||
if (strcmp(key, parser->kvalarr[i].key) == 0) {
|
||||
switch (type) {
|
||||
case CFVALTYPE_STR: {
|
||||
*(char**)(ref) = strcopy(parser->kvalarr[i].val);
|
||||
break;
|
||||
}
|
||||
case CFVALTYPE_INT: {
|
||||
char* eptr = NULL;
|
||||
*(int64_t*)(ref) = (int64_t)strtol(parser->kvalarr[i].val, &eptr, 10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_TOKEN_SIZE 1024
|
||||
|
||||
|
||||
int cfparser_parse(cfparser_t * parser) {
|
||||
cflexer_t* lex = parser->lexer;
|
||||
|
||||
char token[MAX_TOKEN_SIZE];
|
||||
int type = 0;
|
||||
int pos = 0;
|
||||
|
||||
char* key;
|
||||
char* val;
|
||||
|
||||
while ((type = cflexer_gettoken(lex, token)) != CFLEXTOK_END) {
|
||||
switch (pos) {
|
||||
// POS 0
|
||||
case 0:{
|
||||
if (type == CFLEXTOK_SPACE) continue;
|
||||
if (type == CFLEXTOK_COMM) continue;
|
||||
if (type == CFLEXTOK_NEXT) continue;
|
||||
if (type == CFLEXTOK_WORD) {
|
||||
key = strcopy(token);
|
||||
pos++;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// POS 1
|
||||
case 1:{
|
||||
if (type == CFLEXTOK_SPACE) continue;
|
||||
if (type == CFLEXTOK_SEPAR) {
|
||||
pos++;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// POS 2
|
||||
case 2:{
|
||||
if (type == CFLEXTOK_SPACE) continue;
|
||||
if (type == CFLEXTOK_WORD) {
|
||||
char* val = strcopy(token);
|
||||
if (parser->kvalsize >= parser->kvalcapa) {
|
||||
// TODO
|
||||
}
|
||||
parser->kvalarr[parser->kvalsize].key = key;
|
||||
parser->kvalarr[parser->kvalsize].val = val;
|
||||
parser->kvalsize++;
|
||||
pos++;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3:{
|
||||
if (type == CFLEXTOK_SPACE) continue;
|
||||
if (type == CFLEXTOK_COMM) continue;
|
||||
if (type == CFLEXTOK_NEXT) {
|
||||
pos = 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void cfparser_destroy(cfparser_t * parser) {
|
||||
free(parser->kvalarr);
|
||||
}
|
||||
30
cfparser.h
Normal file
30
cfparser.h
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
#ifndef CFPARSER_H_QWERTY
|
||||
#define CFPARSER_H_QWERTY
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <cflexer.h>
|
||||
|
||||
typedef struct {
|
||||
char* key;
|
||||
char* val;
|
||||
} cfkval_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
cflexer_t* lexer;
|
||||
cfkval_t* kvalarr;
|
||||
int kvalcapa;
|
||||
int kvalsize;
|
||||
} cfparser_t;
|
||||
|
||||
#define CFVALTYPE_STR 1
|
||||
#define CFVALTYPE_INT 2
|
||||
#define CFVALTYPE_BOOL 3
|
||||
|
||||
void cfparser_init(cfparser_t* parser, cflexer_t* lexer);
|
||||
int cfparser_parse(cfparser_t* parser);
|
||||
void cfparser_bind(cfparser_t* parser, int type, char* key, void* ref);
|
||||
void cfparser_destroy(cfparser_t * parser);
|
||||
|
||||
#endif
|
||||
49
cfparser_test.c
Normal file
49
cfparser_test.c
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2023 Oleg Borodin <borodin@unix7.org>
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <cflexer.h>
|
||||
#include <cfparser.h>
|
||||
#include <massert.h>
|
||||
#include <rcache.h>
|
||||
|
||||
int main(void) {
|
||||
|
||||
int fd = open("test.conf", O_RDONLY);
|
||||
MASSERT(fd > 0);
|
||||
|
||||
rcache_t cache;
|
||||
rcache_init(&cache, fd);
|
||||
|
||||
cflexer_t lexer;
|
||||
cflexer_init(&lexer, &cache);
|
||||
|
||||
cfparser_t parser;
|
||||
cfparser_init(&parser, &lexer);
|
||||
|
||||
if (cfparser_parse(&parser)) {
|
||||
printf("parse args error\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int64_t id = 0;
|
||||
cfparser_bind(&parser, CFVALTYPE_INT, "id", (void *)&id);
|
||||
char* name = "";
|
||||
cfparser_bind(&parser, CFVALTYPE_STR, "name", (void *)&name);
|
||||
|
||||
cfparser_destroy(&parser);
|
||||
cflexer_destroy(&lexer);
|
||||
|
||||
printf("id = %d\n", id);
|
||||
printf("name = %s\n", name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
246
cllexer.c
Normal file
246
cllexer.c
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright 2023 Oleg Borodin <borodin@unix7.org>
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <cllexer.h>
|
||||
|
||||
#define CLLEXTYPE_UNDEF 0
|
||||
#define CLLEXTYPE_KEY 1
|
||||
#define CLLEXTYPE_CHAR 2
|
||||
#define CLLEXTYPE_SEP 3
|
||||
#define CLLEXTYPE_SPACE 4
|
||||
#define CLLEXTYPE_WORDL 5
|
||||
#define CLLEXTYPE_SCR 6
|
||||
#define CLLEXTYPE_EOF 7
|
||||
|
||||
static int get_ltype(char letter) {
|
||||
switch (letter) {
|
||||
case EOF:
|
||||
return CLLEXTYPE_EOF;
|
||||
case '"':
|
||||
return CLLEXTYPE_WORDL;
|
||||
case '\\':
|
||||
return CLLEXTYPE_SCR;
|
||||
case '-':
|
||||
return CLLEXTYPE_KEY;
|
||||
case ' ':
|
||||
case '\t':
|
||||
return CLLEXTYPE_SPACE;
|
||||
case '=':
|
||||
return CLLEXTYPE_SEP;
|
||||
default:
|
||||
return CLLEXTYPE_CHAR;
|
||||
}
|
||||
return CLLEXTYPE_UNDEF;
|
||||
}
|
||||
|
||||
void cllexer_init(cllexer_t * lexer) {
|
||||
lexer->context = CLLEXCONT_UNDEF;
|
||||
lexer->tokpos = 0;
|
||||
lexer->letter = EOF;
|
||||
lexer->rewind = false;
|
||||
lexer->argstr = NULL;
|
||||
lexer->arglen = 0;
|
||||
lexer->argpos = 0;
|
||||
lexer->screen = false;
|
||||
}
|
||||
|
||||
void cllexer_reset(cllexer_t * lexer, char* argstr) {
|
||||
lexer->context = CLLEXCONT_UNDEF;
|
||||
lexer->tokpos = 0;
|
||||
lexer->letter = EOF;
|
||||
lexer->rewind = false;
|
||||
lexer->argstr = argstr;
|
||||
lexer->arglen = strlen(argstr);
|
||||
lexer->argpos = 0;
|
||||
lexer->screen = false;
|
||||
}
|
||||
|
||||
int cllexer_gettoken(cllexer_t * lexer, char* token) {
|
||||
while (true) {
|
||||
if (!lexer->rewind) {
|
||||
if (lexer->argpos >= lexer->arglen) {
|
||||
lexer->letter = EOF;
|
||||
} else {
|
||||
lexer->letter = lexer->argstr[lexer->argpos++];
|
||||
}
|
||||
}
|
||||
lexer->rewind = false;
|
||||
|
||||
int type = get_ltype(lexer->letter);
|
||||
|
||||
switch (lexer->context) {
|
||||
case CLLEXCONT_END:{
|
||||
lexer->context = CLLEXCONT_END;
|
||||
lexer->tokpos = 0;
|
||||
strcpy(token, "END");
|
||||
return CLLEXTOK_END;
|
||||
}
|
||||
case CLLEXCONT_UNDEF:{
|
||||
switch (type) {
|
||||
case CLLEXTYPE_WORDL:{
|
||||
lexer->tokpos = 0;
|
||||
lexer->context = CLLEXCONT_LWORD;
|
||||
break;
|
||||
}
|
||||
case CLLEXTYPE_EOF:{
|
||||
lexer->tokpos = 0;
|
||||
lexer->context = CLLEXCONT_END;
|
||||
lexer->rewind = true;
|
||||
break;
|
||||
}
|
||||
case CLLEXTYPE_KEY:{
|
||||
lexer->tokpos = 0;
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
lexer->context = CLLEXCONT_KEY;
|
||||
break;
|
||||
}
|
||||
case CLLEXTYPE_SEP:{
|
||||
lexer->tokpos = 0;
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
lexer->context = CLLEXCONT_SEP;
|
||||
break;
|
||||
}
|
||||
case CLLEXTYPE_SCR: {
|
||||
lexer->tokpos = 0;
|
||||
lexer->screen = true;
|
||||
lexer->context = CLLEXCONT_WORD;
|
||||
break;
|
||||
}
|
||||
case CLLEXTYPE_CHAR:{
|
||||
lexer->tokpos = 0;
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
lexer->context = CLLEXCONT_WORD;
|
||||
break;
|
||||
}
|
||||
case CLLEXTYPE_SPACE:{
|
||||
lexer->tokpos = 0;
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
lexer->context = CLLEXCONT_SPACE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CLLEXCONT_KEY:{
|
||||
switch (type) {
|
||||
case CLLEXTYPE_KEY:
|
||||
break;
|
||||
case CLLEXTYPE_EOF:
|
||||
default:{
|
||||
token[lexer->tokpos++] = '\0';
|
||||
lexer->context = CLLEXCONT_UNDEF;
|
||||
lexer->rewind = true;
|
||||
return CLLEXTOK_KEY;
|
||||
}
|
||||
}
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
break;
|
||||
}
|
||||
case CLLEXCONT_WORD:{
|
||||
switch (type) {
|
||||
case CLLEXTYPE_SCR: {
|
||||
if (lexer->screen == true) {
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
lexer->screen = false;
|
||||
} else {
|
||||
lexer->screen = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case CLLEXTYPE_CHAR:
|
||||
break;
|
||||
case CLLEXTYPE_EOF:
|
||||
default: {
|
||||
if (lexer->screen == true) {
|
||||
lexer->screen = false;
|
||||
break;
|
||||
}
|
||||
token[lexer->tokpos++] = '\0';
|
||||
lexer->context = CLLEXCONT_UNDEF;
|
||||
lexer->rewind = true;
|
||||
return CLLEXTOK_WORD;
|
||||
}
|
||||
}
|
||||
lexer->screen = false;
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
break;
|
||||
}
|
||||
case CLLEXCONT_LWORD:{
|
||||
switch (type) {
|
||||
case CLLEXTYPE_SCR:
|
||||
if (lexer->screen == true) {
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
lexer->screen = false;
|
||||
} else {
|
||||
lexer->screen = true;
|
||||
}
|
||||
continue;
|
||||
case CLLEXTYPE_WORDL:
|
||||
if (lexer->screen == true) {
|
||||
lexer->screen = false;
|
||||
break;
|
||||
}
|
||||
token[lexer->tokpos++] = '\0';
|
||||
lexer->context = CLLEXCONT_UNDEF;
|
||||
lexer->screen = false;
|
||||
return CLLEXTOK_WORD;
|
||||
case CLLEXTYPE_EOF:
|
||||
token[lexer->tokpos++] = '\0';
|
||||
lexer->context = CLLEXCONT_UNDEF;
|
||||
lexer->rewind = true;
|
||||
lexer->screen = false;
|
||||
return CLLEXTOK_WORD;
|
||||
default:{
|
||||
break;
|
||||
}
|
||||
}
|
||||
lexer->screen = false;
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
break;
|
||||
}
|
||||
case CLLEXCONT_SPACE:{
|
||||
switch (type) {
|
||||
case CLLEXTYPE_SPACE:
|
||||
break;
|
||||
case CLLEXTYPE_EOF:
|
||||
default:{
|
||||
token[lexer->tokpos++] = '\0';
|
||||
lexer->context = CLLEXCONT_UNDEF;
|
||||
lexer->rewind = true;
|
||||
return CLLEXTOK_SPACE;
|
||||
}
|
||||
}
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
break;
|
||||
}
|
||||
case CLLEXCONT_SEP:{
|
||||
switch (type) {
|
||||
case CLLEXTYPE_SEP:
|
||||
break;
|
||||
case CLLEXTYPE_EOF:
|
||||
default:{
|
||||
token[lexer->tokpos++] = '\0';
|
||||
lexer->context = CLLEXCONT_UNDEF;
|
||||
lexer->rewind = true;
|
||||
return CLLEXTOK_SEP;
|
||||
}
|
||||
}
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strcpy(token, "UNDEF");
|
||||
return CLLEXTOK_UNDEF;
|
||||
}
|
||||
|
||||
void cllexer_destroy(cllexer_t * lexer) {
|
||||
(void)lexer;
|
||||
}
|
||||
38
cllexer.h
Normal file
38
cllexer.h
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
#ifndef CLLEXER_H_QWERTY
|
||||
#define CLLEXER_H_QWERTY
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
int context;
|
||||
char letter;
|
||||
int tokpos;
|
||||
bool rewind;
|
||||
char* argstr;
|
||||
int arglen;
|
||||
int argpos;
|
||||
bool screen;
|
||||
} cllexer_t;
|
||||
|
||||
#define CLLEXCONT_UNDEF 0
|
||||
#define CLLEXCONT_KEY 1
|
||||
#define CLLEXCONT_WORD 2
|
||||
#define CLLEXCONT_SPACE 3
|
||||
#define CLLEXCONT_SEP 4
|
||||
#define CLLEXCONT_END 5
|
||||
#define CLLEXCONT_LWORD 6
|
||||
|
||||
#define CLLEXTOK_UNDEF 0
|
||||
#define CLLEXTOK_KEY 1
|
||||
#define CLLEXTOK_WORD 2
|
||||
#define CLLEXTOK_SPACE 3
|
||||
#define CLLEXTOK_SEP 4
|
||||
#define CLLEXTOK_END 5
|
||||
|
||||
void cllexer_init(cllexer_t* lexer);
|
||||
void cllexer_reset(cllexer_t* lexer, char* argstr);
|
||||
int cllexer_gettoken(cllexer_t* lexer, char* token);
|
||||
void cllexer_destroy(cllexer_t* lexer);
|
||||
|
||||
#endif
|
||||
32
cllexer_test.c
Normal file
32
cllexer_test.c
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2023 Oleg Borodin <borodin@unix7.org>
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <cllexer.h>
|
||||
|
||||
int main(void) {
|
||||
|
||||
char* src = "\\\"---\"\\\"qwer\\1-ty\"=\"a123-45\\\" \\\"5678\"";
|
||||
|
||||
cllexer_t lexer;
|
||||
|
||||
cllexer_init(&lexer);
|
||||
cllexer_reset(&lexer, src);
|
||||
|
||||
char token[1024];
|
||||
int type = 0;
|
||||
|
||||
while ((type = cllexer_gettoken(&lexer, token)) != CLLEXTOK_END) {
|
||||
printf("[%d]: [%s]\n", type, token);
|
||||
}
|
||||
printf("[%d]: [%s]\n", type, token);
|
||||
|
||||
return 0;
|
||||
}
|
||||
180
clparser.c
Normal file
180
clparser.c
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright 2023 Oleg Borodin <borodin@unix7.org>
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#include <clparser.h>
|
||||
|
||||
#define INIT_BSIZE 64
|
||||
|
||||
|
||||
static char* strcopy(char* src) {
|
||||
size_t srcsize = strlen(src) + 1;
|
||||
char* dst = malloc(srcsize);
|
||||
|
||||
memset(dst, '\0', srcsize);
|
||||
strcpy(dst, src);
|
||||
return dst;
|
||||
}
|
||||
|
||||
static char* strconcat(char** str, int num) {
|
||||
size_t tsize = 0;
|
||||
size_t size[num];
|
||||
|
||||
for (int i = 0; i < num; i++) {
|
||||
size[i] = 0;
|
||||
if (str[i] != NULL) {
|
||||
size[i] = strlen(str[i]);
|
||||
tsize += size[i];
|
||||
}
|
||||
}
|
||||
tsize++;
|
||||
char* dst = malloc(tsize);
|
||||
|
||||
memset(dst, '\0', tsize);
|
||||
int pos = 0;
|
||||
|
||||
for (int i = 0; i < num; i++) {
|
||||
if (str[i] != NULL) {
|
||||
strcpy(&dst[pos], str[i]);
|
||||
pos += size[i];
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
void clparser_init(clparser_t * parser, cllexer_t * lexer) {
|
||||
parser->lexer = lexer;
|
||||
parser->bindarr = malloc(sizeof(clbind_t) * INIT_BSIZE);
|
||||
parser->bindcapa = INIT_BSIZE;
|
||||
parser->bindsize = 0;
|
||||
}
|
||||
|
||||
void clparser_bind(clparser_t * parser, int type, char* key, void* ref) {
|
||||
if (parser->bindsize >= parser->bindcapa) {
|
||||
return; // TODO
|
||||
}
|
||||
clbind_t* b = &(parser->bindarr[parser->bindsize]);
|
||||
|
||||
b->type = type;
|
||||
b->key = key;
|
||||
b->ref = ref;
|
||||
parser->bindsize++;
|
||||
}
|
||||
|
||||
#define MAX_TOKEN_SIZE 1024
|
||||
|
||||
static int clparser_compile(clparser_t * parser, char* arg, char** refkey, char** refval) {
|
||||
cllexer_t* lex = parser->lexer;
|
||||
|
||||
cllexer_reset(lex, arg);
|
||||
|
||||
char token[MAX_TOKEN_SIZE];
|
||||
int type = 0;
|
||||
int pos = 0;
|
||||
|
||||
char* key;
|
||||
char* vals[2] = { NULL };
|
||||
|
||||
while ((type = cllexer_gettoken(lex, token)) != CLLEXTOK_END) {
|
||||
switch (pos) {
|
||||
// POS 0
|
||||
case 0:{
|
||||
if (type == CLLEXTOK_KEY) {
|
||||
pos++;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// POS 1
|
||||
case 1:{
|
||||
if (type == CLLEXTOK_WORD) {
|
||||
key = strcopy(token);
|
||||
pos++;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// POS 2
|
||||
case 2:{
|
||||
if (type == CLLEXTOK_SEP) {
|
||||
pos++;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// POS 3
|
||||
case 3:{
|
||||
if (type == CLLEXTOK_WORD || type == CLLEXTOK_KEY) {
|
||||
pos++;
|
||||
vals[0] = strcopy(token);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// POS 4
|
||||
case 4:{
|
||||
if (type == CLLEXTOK_WORD) {
|
||||
pos++;
|
||||
vals[1] = strcopy(token);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:{
|
||||
return -1;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
*refkey = key;
|
||||
*refval = strconcat(vals, 2);
|
||||
free(vals[0]);
|
||||
free(vals[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clparser_parse(clparser_t * parser, char** argv, int argc) {
|
||||
for (int i = 0; i < argc; i++) {
|
||||
char* key;
|
||||
char* val;
|
||||
|
||||
if (clparser_compile(parser, argv[i], &key, &val) < 0) {
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < parser->bindsize; i++) {
|
||||
if (strcmp(parser->bindarr[i].key, key) == 0) {
|
||||
switch (parser->bindarr[i].type) {
|
||||
case CLTYPE_INT:{
|
||||
char* eptr = NULL;
|
||||
*(int *)(parser->bindarr[i].ref) = (int)strtol(val, &eptr, 10);
|
||||
free(key);
|
||||
free(val);
|
||||
break;
|
||||
}
|
||||
case CLTYPE_STR:{
|
||||
*(char **)(parser->bindarr[i].ref) = strcopy(val);
|
||||
free(key);
|
||||
free(val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clparser_destroy(clparser_t * parser) {
|
||||
free(parser->bindarr);
|
||||
}
|
||||
30
clparser.h
Normal file
30
clparser.h
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
#ifndef CLPARSER_H_QWERTY
|
||||
#define CLPARSER_H_QWERTY
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <cllexer.h>
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
char* key;
|
||||
void* ref;
|
||||
} clbind_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
cllexer_t* lexer;
|
||||
clbind_t* bindarr;
|
||||
int bindcapa;
|
||||
int bindsize;
|
||||
} clparser_t;
|
||||
|
||||
#define CLTYPE_INT 1
|
||||
#define CLTYPE_STR 2
|
||||
|
||||
void clparser_init(clparser_t* parser, cllexer_t* lexer);
|
||||
void clparser_bind(clparser_t* parser, int type, char* key, void* ref);
|
||||
int clparser_parse(clparser_t* parser, char** argv, int argc);
|
||||
void clparser_destroy(clparser_t * parser);
|
||||
|
||||
#endif
|
||||
49
clparser_test.c
Normal file
49
clparser_test.c
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2023 Oleg Borodin <borodin@unix7.org>
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <cllexer.h>
|
||||
#include <clparser.h>
|
||||
|
||||
int main(void) {
|
||||
//(void)argc;
|
||||
//(void)argv;
|
||||
|
||||
char* argv[] = { "main", "--id=-123", "--name=qwerty12234" };
|
||||
int argc = 3;
|
||||
|
||||
cllexer_t lexer;
|
||||
|
||||
cllexer_init(&lexer);
|
||||
|
||||
clparser_t parser;
|
||||
|
||||
clparser_init(&parser, &lexer);
|
||||
|
||||
int id = 0;
|
||||
|
||||
clparser_bind(&parser, CLTYPE_INT, "id", (void *)&id);
|
||||
|
||||
char* name = "";
|
||||
|
||||
clparser_bind(&parser, CLTYPE_STR, "name", (void *)&name);
|
||||
|
||||
if (clparser_parse(&parser, &argv[1], argc - 1) < 0) {
|
||||
printf("parse args error\n");
|
||||
return 1;
|
||||
}
|
||||
printf("id = %d\n", id);
|
||||
printf("name = %s\n", name);
|
||||
|
||||
clparser_destroy(&parser);
|
||||
cllexer_destroy(&lexer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
207
jlexer.c
Normal file
207
jlexer.c
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright 2023 Oleg Borodin <borodin@unix7.org>
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <rcache.h>
|
||||
#include <jlexer.h>
|
||||
|
||||
#define JLEXTYPE_UNDEF 0
|
||||
#define JLEXTYPE_BLOCKB 1
|
||||
#define JLEXTYPE_BLOCKE 2
|
||||
#define JLEXTYPE_WORDL 3
|
||||
#define JLEXTYPE_SPACE 4
|
||||
#define JLEXTYPE_SEPAR 5
|
||||
#define JLEXTYPE_NUM 6
|
||||
#define JLEXTYPE_COMMA 7
|
||||
#define JLEXTYPE_CHAR 8
|
||||
#define JLEXTYPE_EOF 9
|
||||
|
||||
|
||||
static int get_ltype(char letter) {
|
||||
switch (letter) {
|
||||
case EOF:
|
||||
return JLEXTYPE_EOF;
|
||||
case '{':
|
||||
return JLEXTYPE_BLOCKB;
|
||||
case '}':
|
||||
return JLEXTYPE_BLOCKE;
|
||||
case '"':
|
||||
return JLEXTYPE_WORDL;
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
return JLEXTYPE_SPACE;
|
||||
case ':':
|
||||
return JLEXTYPE_SEPAR;
|
||||
case ',':
|
||||
return JLEXTYPE_COMMA;
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case '0':
|
||||
case '.':
|
||||
case 'E':
|
||||
case 'e':
|
||||
case '+':
|
||||
case '-':
|
||||
return JLEXTYPE_NUM;
|
||||
default:
|
||||
return JLEXTYPE_CHAR;
|
||||
}
|
||||
return JLEXTYPE_UNDEF;
|
||||
}
|
||||
|
||||
void jlexer_init(jlexer_t * lexer, rcache_t * cache) {
|
||||
lexer->cache = cache;
|
||||
lexer->context = JLEXCONT_UNDEF;
|
||||
lexer->tokpos = 0;
|
||||
lexer->letter = EOF;
|
||||
lexer->rewind = false;
|
||||
}
|
||||
|
||||
int jlexer_gettoken(jlexer_t * lexer, char* token) {
|
||||
|
||||
while (true) {
|
||||
if (!lexer->rewind) {
|
||||
lexer->letter = rcache_getc(lexer->cache);
|
||||
}
|
||||
lexer->rewind = false;
|
||||
int type = get_ltype(lexer->letter);
|
||||
|
||||
switch (lexer->context) {
|
||||
case JLEXCONT_END:{
|
||||
lexer->context = JLEXCONT_END;
|
||||
lexer->tokpos = 0;
|
||||
lexer->rewind = true;
|
||||
strcpy(token, "END");
|
||||
return JLEXTOK_END;
|
||||
}
|
||||
case JLEXCONT_UNDEF:{
|
||||
switch (type) {
|
||||
case JLEXTYPE_EOF:{
|
||||
lexer->context = JLEXCONT_END;
|
||||
lexer->rewind = true;
|
||||
break;
|
||||
}
|
||||
case JLEXTYPE_BLOCKB:{
|
||||
strcpy(token, "BEGIN");
|
||||
lexer->context = JLEXCONT_UNDEF;
|
||||
return JLEXTOK_BLOCKB;
|
||||
}
|
||||
case JLEXTYPE_BLOCKE:{
|
||||
strcpy(token, "END");
|
||||
lexer->context = JLEXCONT_UNDEF;
|
||||
return JLEXTOK_BLOCKE;
|
||||
}
|
||||
case JLEXTYPE_SEPAR:{
|
||||
strcpy(token, "IS");
|
||||
lexer->context = JLEXCONT_UNDEF;
|
||||
return JLEXTOK_SEPAR;
|
||||
}
|
||||
case JLEXTYPE_COMMA:{
|
||||
strcpy(token, "NEXT");
|
||||
lexer->context = JLEXCONT_UNDEF;
|
||||
return JLEXTOK_NEXT;
|
||||
}
|
||||
case JLEXTYPE_WORDL:{
|
||||
lexer->tokpos = 0;
|
||||
//char* prefix = "STRING ";
|
||||
//strcpy(token, prefix);
|
||||
//lexer->tokpos =+ strlen(prefix);
|
||||
lexer->context = JLEXCONT_WORD;
|
||||
break;
|
||||
}
|
||||
case JLEXTYPE_NUM:{
|
||||
lexer->tokpos = 0;
|
||||
//char* prefix = "NUMBER ";
|
||||
//strcpy(token, prefix);
|
||||
//lexer->tokpos =+ strlen(prefix);
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
lexer->context = JLEXCONT_NUM;
|
||||
break;
|
||||
}
|
||||
case JLEXTYPE_CHAR:{
|
||||
lexer->tokpos = 0;
|
||||
char* prefix = "WTF? ";
|
||||
|
||||
strcpy(token, prefix);
|
||||
lexer->tokpos = +strlen(prefix);
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
lexer->context = JLEXCONT_UNKNOW;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JLEXCONT_WORD:{
|
||||
int newcontext = lexer->context;
|
||||
|
||||
switch (type) {
|
||||
case JLEXTYPE_EOF:
|
||||
case JLEXTYPE_WORDL:{
|
||||
token[lexer->tokpos++] = '\0';
|
||||
lexer->context = JLEXCONT_UNDEF;
|
||||
return JLEXTOK_WORD;
|
||||
}
|
||||
}
|
||||
lexer->context = newcontext;
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
break;
|
||||
}
|
||||
case JLEXCONT_NUM:{
|
||||
int newcontext = lexer->context;
|
||||
|
||||
switch (type) {
|
||||
case JLEXTYPE_NUM:
|
||||
break;
|
||||
case JLEXTYPE_EOF:
|
||||
default:
|
||||
token[lexer->tokpos++] = '\0';
|
||||
lexer->rewind = true;
|
||||
lexer->context = JLEXCONT_UNDEF;
|
||||
return JLEXTOK_NUMB;
|
||||
}
|
||||
lexer->context = newcontext;
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
break;
|
||||
}
|
||||
case JLEXCONT_UNKNOW:{
|
||||
int newcontext = lexer->context;
|
||||
|
||||
switch (type) {
|
||||
case JLEXTYPE_CHAR:
|
||||
case JLEXTYPE_NUM:
|
||||
break;
|
||||
case JLEXTYPE_EOF:
|
||||
default:{
|
||||
token[lexer->tokpos++] = '\0';
|
||||
lexer->rewind = true;
|
||||
lexer->context = JLEXCONT_UNDEF;
|
||||
return JLEXTOK_UNKNOW;
|
||||
}
|
||||
}
|
||||
lexer->context = newcontext;
|
||||
token[lexer->tokpos++] = lexer->letter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strcpy(token, "UNDEF");
|
||||
return JLEXTOK_UNDEF;
|
||||
}
|
||||
|
||||
void jlexer_destroy(jlexer_t * lexer) {
|
||||
(void)lexer;
|
||||
}
|
||||
45
jlexer.h
Normal file
45
jlexer.h
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
#ifndef JLEXER_H_QWERTY
|
||||
#define JLEXER_H_QWERTY
|
||||
|
||||
#include <rcache.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
rcache_t* cache;
|
||||
int fd;
|
||||
int context;
|
||||
char letter;
|
||||
int tokpos;
|
||||
bool rewind;
|
||||
} jlexer_t;
|
||||
|
||||
#define JLEXCONT_UNDEF 0
|
||||
#define JLEXCONT_WORD 1
|
||||
#define JLEXCONT_BLOCKB 2
|
||||
#define JLEXCONT_BLOCKE 3
|
||||
#define JLEXCONT_SEPAR 4
|
||||
#define JLEXCONT_NUM 5
|
||||
#define JLEXCONT_UNKNOW 6
|
||||
#define JLEXCONT_END 9
|
||||
|
||||
|
||||
#define JLEXTOK_BLOCKB 1
|
||||
#define JLEXTOK_BLOCKE 2
|
||||
#define JLEXTOK_SPACE 4
|
||||
#define JLEXTOK_SEPAR 3
|
||||
#define JLEXTOK_UNDEF 4
|
||||
#define JLEXTOK_WORD 5
|
||||
#define JLEXTOK_NUMB 6
|
||||
#define JLEXTOK_UNKNOW 7
|
||||
#define JLEXTOK_NEXT 8
|
||||
#define JLEXTOK_END 9
|
||||
|
||||
|
||||
|
||||
void jlexer_init(jlexer_t * lexer, rcache_t * cache);
|
||||
int jlexer_gettoken(jlexer_t * lexer, char* token);
|
||||
void jlexer_destroy(jlexer_t * lexer);
|
||||
|
||||
|
||||
#endif
|
||||
42
jlexer_test.c
Normal file
42
jlexer_test.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2023 Oleg Borodin <borodin@unix7.org>
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <massert.h>
|
||||
#include <rcache.h>
|
||||
#include <jlexer.h>
|
||||
|
||||
int main(void) {
|
||||
|
||||
int fd = open("test.json", O_RDONLY);
|
||||
|
||||
MASSERT(fd > 0);
|
||||
|
||||
rcache_t cache;
|
||||
|
||||
rcache_init(&cache, fd);
|
||||
|
||||
jlexer_t lexer;
|
||||
|
||||
jlexer_init(&lexer, &cache);
|
||||
|
||||
char token[1024];
|
||||
int type = 0;
|
||||
|
||||
while ((type = jlexer_gettoken(&lexer, token)) != JLEXTOK_END) {
|
||||
printf("%d: %s\n", type, token);
|
||||
}
|
||||
printf("%d: %s\n", type, token);
|
||||
|
||||
rcache_destroy(&cache);
|
||||
|
||||
return 0;
|
||||
}
|
||||
133
jparser.c
Normal file
133
jparser.c
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2023 Oleg Borodin <borodin@unix7.org>
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#include <jparser.h>
|
||||
|
||||
#define INIT_BSIZE 64
|
||||
|
||||
|
||||
static char* strcopy(char* src) {
|
||||
size_t srcsize = strlen(src) + 1;
|
||||
char* dst = malloc(srcsize);
|
||||
|
||||
memset(dst, '\0', srcsize);
|
||||
strcpy(dst, src);
|
||||
return dst;
|
||||
}
|
||||
|
||||
void jparser_init(jparser_t * parser, jlexer_t * lexer) {
|
||||
parser->lexer = lexer;
|
||||
parser->kvalarr = malloc(sizeof(jkval_t) * INIT_BSIZE);
|
||||
parser->kvalcapa = INIT_BSIZE;
|
||||
parser->kvalsize = 0;
|
||||
}
|
||||
|
||||
#define MAX_TOKEN_SIZE 1024
|
||||
|
||||
int jparser_parse(jparser_t * parser) {
|
||||
jlexer_t* lex = parser->lexer;
|
||||
char token[MAX_TOKEN_SIZE];
|
||||
int type = 0;
|
||||
|
||||
int pos = 0;
|
||||
char* key = "";
|
||||
|
||||
while ((type = jlexer_gettoken(lex, token)) != JLEXTOK_END) {
|
||||
switch (pos) {
|
||||
// POS 0
|
||||
case 0:{
|
||||
if (type != JLEXTOK_BLOCKB)
|
||||
return -1;
|
||||
pos++;
|
||||
break;
|
||||
}
|
||||
// POS 1
|
||||
case 1:{
|
||||
if (type == JLEXTOK_SPACE)
|
||||
continue;
|
||||
if (type == JLEXTOK_NEXT)
|
||||
continue;
|
||||
if (type == JLEXTOK_BLOCKE)
|
||||
return 0;
|
||||
if (type != JLEXTOK_WORD)
|
||||
return -1;
|
||||
key = strcopy(token);
|
||||
pos++;
|
||||
break;
|
||||
}
|
||||
// POS 2
|
||||
case 2:{
|
||||
if (type == JLEXTOK_SPACE)
|
||||
continue;
|
||||
if (type != JLEXTOK_SEPAR)
|
||||
return -1;
|
||||
pos++;
|
||||
break;
|
||||
}
|
||||
// POS 3
|
||||
case 3:{
|
||||
if (type == JLEXTOK_SPACE)
|
||||
continue;
|
||||
if (type != JLEXTOK_WORD && type != JLEXTOK_NUMB)
|
||||
return -1;
|
||||
char* val = strcopy(token);
|
||||
|
||||
jkval_t* kv = &(parser->kvalarr[parser->kvalsize]);
|
||||
|
||||
kv->key = key;
|
||||
if (type == JLEXTOK_NUMB) {
|
||||
kv->type = JVALTYPE_NUM;
|
||||
char* eptr = NULL;
|
||||
kv->num = (int64_t)strtol(val, &eptr, 10);;
|
||||
free(val);
|
||||
} else {
|
||||
kv->type = JVALTYPE_STR;
|
||||
kv->str = val;
|
||||
}
|
||||
parser->kvalsize++;
|
||||
pos++;
|
||||
break;
|
||||
}
|
||||
// POS 4
|
||||
case 4:{
|
||||
if (type == JLEXTOK_SPACE)
|
||||
continue;
|
||||
if (type != JLEXTOK_NEXT && type != JLEXTOK_BLOCKE)
|
||||
return -1;
|
||||
pos = 1;
|
||||
break;
|
||||
}
|
||||
default:{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int jparser_bind(jparser_t* parser, int type, char* key, void* ref) {
|
||||
for (int i = 0; i < parser->kvalsize; i++) {
|
||||
jkval_t* kv = &(parser->kvalarr[i]);
|
||||
|
||||
if (strcmp(kv->key, key) == 0) {
|
||||
if (kv->type == JVALTYPE_STR) {
|
||||
*(char**)(ref) = strcopy(kv->str);
|
||||
} else if (kv->type == JVALTYPE_NUM) {
|
||||
*(int*)(ref) = kv->num;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void jparser_destroy(jparser_t * parser) {
|
||||
free(parser->kvalarr);
|
||||
}
|
||||
36
jparser.h
Normal file
36
jparser.h
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
#ifndef CLPARSER_H_QWERTY
|
||||
#define CLPARSER_H_QWERTY
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <jlexer.h>
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
char* key;
|
||||
union {
|
||||
char* str;
|
||||
int64_t num;
|
||||
bool flag;
|
||||
};
|
||||
} jkval_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
jkval_t* kvalarr;
|
||||
int kvalcapa;
|
||||
int kvalsize;
|
||||
jlexer_t* lexer;
|
||||
} jparser_t;
|
||||
|
||||
#define JVALTYPE_STR 1
|
||||
#define JVALTYPE_NUM 2
|
||||
#define JVALTYPE_BOOL 3
|
||||
|
||||
|
||||
void jparser_init(jparser_t* parser, jlexer_t* lexer);
|
||||
int jparser_bind(jparser_t* parser, int type, char* key, void* ref);
|
||||
int jparser_parse(jparser_t* parser);
|
||||
void jparser_destroy(jparser_t * parser);
|
||||
|
||||
#endif
|
||||
61
jparser_test.c
Normal file
61
jparser_test.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2023 Oleg Borodin <borodin@unix7.org>
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <massert.h>
|
||||
#include <jlexer.h>
|
||||
#include <jparser.h>
|
||||
|
||||
int main(void) {
|
||||
|
||||
int fd = open("test.json", O_RDONLY);
|
||||
|
||||
MASSERT(fd > 0);
|
||||
|
||||
rcache_t cache;
|
||||
|
||||
rcache_init(&cache, fd);
|
||||
|
||||
jlexer_t lexer;
|
||||
|
||||
jlexer_init(&lexer, &cache);
|
||||
|
||||
jparser_t parser;
|
||||
|
||||
jparser_init(&parser, &lexer);
|
||||
|
||||
if (jparser_parse(&parser) < 0) {
|
||||
dprintf(STDERR_FILENO, "cannot parse json\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int64_t id = 0;
|
||||
|
||||
if (jparser_bind(&parser, JVALTYPE_NUM, "id", (void *)&id) < 0) {
|
||||
dprintf(STDERR_FILENO, "cannot bind variable\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char* name = "";
|
||||
|
||||
if (jparser_bind(&parser, JVALTYPE_STR, "name", (void *)&name) < 0) {
|
||||
dprintf(STDERR_FILENO, "cannot bind variable\n");
|
||||
}
|
||||
|
||||
printf("id = %d\n", id);
|
||||
printf("name = %s\n", name);
|
||||
|
||||
jparser_destroy(&parser);
|
||||
jlexer_destroy(&lexer);
|
||||
rcache_destroy(&cache);
|
||||
|
||||
return 0;
|
||||
}
|
||||
14
massert.c
Normal file
14
massert.c
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright 2022 Oleg Borodin <borodin@unix7.org>
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <massert.h>
|
||||
|
||||
void x__assert(char* path, int line, const char* func) {
|
||||
printf("%s:%d: assert error in %s\n", path, line, func);
|
||||
exit(1);
|
||||
}
|
||||
16
massert.h
Normal file
16
massert.h
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2022 Oleg Borodin <borodin@unix7.org>
|
||||
*/
|
||||
|
||||
|
||||
#ifndef MASSERT_H_QWERTY
|
||||
#define MASSERT_H_QWERTY
|
||||
|
||||
#define massert(expr) if (!(expr)) \
|
||||
{ x__assert(__FILE__, __LINE__, (const char*)__func__); }
|
||||
|
||||
#define MASSERT(expr) if (!(expr)) \
|
||||
{ x__assert(__FILE__, __LINE__, (const char*)__func__); }
|
||||
|
||||
void x__assert(char* path, int line, const char* func);
|
||||
#endif
|
||||
62
rcache.c
Normal file
62
rcache.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2023 Oleg Borodin <borodin@unix7.org>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <rcache.h>
|
||||
|
||||
|
||||
#define CACHE_INITCAPA 512
|
||||
|
||||
rcache_t* rcache_init(rcache_t * cache, int fd) {
|
||||
cache->data = malloc(CACHE_INITCAPA);
|
||||
if (cache->data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
cache->wpos = 0;
|
||||
cache->rpos = 0;
|
||||
cache->capa = CACHE_INITCAPA;
|
||||
cache->fd = fd;
|
||||
return cache;
|
||||
}
|
||||
|
||||
#define BUFFER_SIZE 1024
|
||||
|
||||
char rcache_getc(rcache_t * cache) {
|
||||
size_t unread = cache->wpos - cache->rpos;
|
||||
|
||||
if (unread == 0) {
|
||||
char* buffer[BUFFER_SIZE];
|
||||
size_t rsize = read(cache->fd, buffer, sizeof(buffer));
|
||||
|
||||
if (rsize == 0) {
|
||||
return EOF;
|
||||
}
|
||||
if ((cache->wpos + rsize) > cache->capa) {
|
||||
size_t newcapa = cache->capa * 2 + rsize;
|
||||
uint8_t* newdata = realloc(cache->data, (size_t)newcapa);
|
||||
|
||||
if (newdata == NULL) {
|
||||
return (ssize_t) - 1;
|
||||
}
|
||||
cache->data = newdata;
|
||||
cache->capa = newcapa;
|
||||
}
|
||||
memcpy(&(cache->data[cache->wpos]), buffer, (size_t)rsize);
|
||||
cache->wpos += rsize;
|
||||
}
|
||||
return (char)cache->data[cache->rpos++];
|
||||
}
|
||||
|
||||
|
||||
void rcache_destroy(rcache_t * cache) {
|
||||
if (cache != NULL) {
|
||||
free(cache->data);
|
||||
}
|
||||
}
|
||||
26
rcache.h
Normal file
26
rcache.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2023 Oleg Borodin <borodin@unix7.org>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RCACHE_H_QWERTY
|
||||
#define RCACHE_H_QWERTY
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef struct {
|
||||
size_t rpos;
|
||||
size_t wpos;
|
||||
size_t capa;
|
||||
uint8_t* data;
|
||||
int fd;
|
||||
} rcache_t;
|
||||
|
||||
|
||||
rcache_t* rcache_init(rcache_t* cache, int fd);
|
||||
char rcache_getc(rcache_t* cache);
|
||||
void rcache_destroy(rcache_t* cache);
|
||||
|
||||
#endif
|
||||
38
rcache_test.c
Normal file
38
rcache_test.c
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2022 Oleg Borodin <borodin@unix7.org>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <rcache.h>
|
||||
#include <massert.h>
|
||||
|
||||
|
||||
void test_getnc(void) {
|
||||
|
||||
int fd = open("test.json", O_RDONLY);
|
||||
|
||||
MASSERT(fd > 0);
|
||||
|
||||
rcache_t stream;
|
||||
|
||||
rcache_init(&stream, fd);
|
||||
|
||||
char c = rcache_getc(&stream);
|
||||
|
||||
printf("%c\n", c);
|
||||
printf("%s", (char *)stream.data);
|
||||
|
||||
rcache_destroy(&stream);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
test_getnc();
|
||||
return 0;
|
||||
}
|
||||
5
test.conf
Normal file
5
test.conf
Normal file
@@ -0,0 +1,5 @@
|
||||
"id" = -123\"
|
||||
name = "qwerty\"567"
|
||||
foo = bar # bbbb
|
||||
"aaa
|
||||
# aaaa
|
||||
141
works/bstream.c
Normal file
141
works/bstream.c
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2023 Oleg Borodin <borodin@unix7.org>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <bstream.h>
|
||||
|
||||
|
||||
#define STREAM_INITCAPA 512
|
||||
|
||||
bstream_t* bstream_init(bstream_t* stream) {
|
||||
stream->data = malloc(STREAM_INITCAPA);
|
||||
if (stream->data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
stream->wpos = 0;
|
||||
stream->rpos = 0;
|
||||
stream->capa = STREAM_INITCAPA;
|
||||
return stream;
|
||||
}
|
||||
|
||||
size_t bstream_dump(bstream_t * stream) {
|
||||
for (size_t i = 0; i < stream->wpos; i++) {
|
||||
printf("%c", stream->data[i]);
|
||||
}
|
||||
return stream->wpos;
|
||||
}
|
||||
|
||||
|
||||
ssize_t bstream_write(bstream_t * stream, void* buffer, size_t size) {
|
||||
if ((stream->wpos + size) > stream->capa) {
|
||||
size_t newcapa = stream->capa * 2;
|
||||
|
||||
uint8_t* newdata = realloc(stream->data, (size_t)newcapa);
|
||||
if (newdata == NULL) {
|
||||
return (ssize_t)-1;
|
||||
}
|
||||
stream->data = newdata;
|
||||
stream->capa = newcapa;
|
||||
}
|
||||
if (buffer != NULL) {
|
||||
memcpy(&(stream->data[stream->wpos]), buffer, (size_t)size);
|
||||
}
|
||||
stream->wpos += size;
|
||||
return (ssize_t) size;
|
||||
}
|
||||
|
||||
ssize_t bstream_read(bstream_t* stream, void* buffer, size_t size) {
|
||||
size_t unread = stream->wpos - stream->rpos;
|
||||
|
||||
if (size > unread) {
|
||||
size = unread;
|
||||
}
|
||||
if (buffer != NULL) {
|
||||
memcpy(buffer, &(stream->data[stream->rpos]), size);
|
||||
}
|
||||
stream->rpos += size;
|
||||
return (ssize_t) size;
|
||||
}
|
||||
|
||||
#define BUFFER_SIZE 1024
|
||||
|
||||
|
||||
ssize_t bstream_fread(bstream_t * stream, char* filename) {
|
||||
int fd = open(filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
return (ssize_t)-1;
|
||||
}
|
||||
char buffer[BUFFER_SIZE];
|
||||
size_t rsize = 0;
|
||||
size_t tsize = 0;
|
||||
|
||||
while ((rsize = (size_t)read(fd, buffer, BUFFER_SIZE)) > 0) {
|
||||
if ((stream->wpos + rsize) > stream->capa) {
|
||||
size_t newcapa = stream->capa * 2 + rsize;
|
||||
stream->data = realloc(stream->data, (size_t)newcapa);
|
||||
stream->capa = newcapa;
|
||||
}
|
||||
if (buffer != NULL) {
|
||||
memcpy(&(stream->data[stream->wpos]), buffer, (size_t)rsize);
|
||||
}
|
||||
stream->wpos += rsize;
|
||||
tsize += rsize;
|
||||
}
|
||||
close(fd);
|
||||
return (ssize_t)tsize;
|
||||
}
|
||||
|
||||
|
||||
char bstream_getc(bstream_t* stream) {
|
||||
size_t unread = stream->wpos - stream->rpos;
|
||||
if (unread == 0) {
|
||||
return EOF;
|
||||
}
|
||||
return (char)stream->data[stream->rpos++];
|
||||
}
|
||||
|
||||
|
||||
char bstream_getnc(bstream_t* stream, int fd) {
|
||||
size_t unread = stream->wpos - stream->rpos;
|
||||
if (unread == 0) {
|
||||
char* buffer[BUFFER_SIZE];
|
||||
size_t rsize = read(fd, buffer, sizeof(buffer));
|
||||
if (rsize == 0) {
|
||||
return EOF;
|
||||
}
|
||||
if ((stream->wpos + rsize) > stream->capa) {
|
||||
size_t newcapa = stream->capa * 2 + rsize;
|
||||
uint8_t* newdata = realloc(stream->data, (size_t)newcapa);
|
||||
if (newdata == NULL) {
|
||||
return (ssize_t)-1;
|
||||
}
|
||||
stream->data = newdata;
|
||||
stream->capa = newcapa;
|
||||
}
|
||||
memcpy(&(stream->data[stream->wpos]), buffer, (size_t)rsize);
|
||||
stream->wpos += rsize;
|
||||
}
|
||||
return (char)stream->data[stream->rpos++];
|
||||
}
|
||||
|
||||
|
||||
size_t bstream_wpos(bstream_t* stream) {
|
||||
return stream->wpos;
|
||||
}
|
||||
|
||||
size_t bstream_rpos(bstream_t* stream) {
|
||||
return stream->rpos;
|
||||
}
|
||||
|
||||
void bstream_destroy(bstream_t* stream) {
|
||||
if (stream != NULL) {
|
||||
free(stream->data);
|
||||
}
|
||||
}
|
||||
36
works/bstream.h
Normal file
36
works/bstream.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2023 Oleg Borodin <borodin@unix7.org>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BSTREAM_H_QWERTY
|
||||
#define BSTREAM_H_QWERTY
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef struct {
|
||||
size_t rpos;
|
||||
size_t wpos;
|
||||
size_t capa;
|
||||
uint8_t* data;
|
||||
} bstream_t;
|
||||
|
||||
|
||||
|
||||
bstream_t* bstream_init(bstream_t* stream);
|
||||
size_t bstream_dump(bstream_t* stream);
|
||||
ssize_t bstream_write(bstream_t* stream, void* buf, size_t size);
|
||||
ssize_t bstream_read(bstream_t* stream, void* buf, size_t size);
|
||||
|
||||
ssize_t bstream_fread(bstream_t* stream, char* filename);
|
||||
char bstream_getc(bstream_t* stream);
|
||||
char bstream_getnc(bstream_t* stream, int fd);
|
||||
|
||||
size_t bstream_wpos(bstream_t* stream);
|
||||
size_t bstream_rpos(bstream_t* stream);
|
||||
|
||||
void bstream_destroy(bstream_t* stream);
|
||||
|
||||
#endif
|
||||
69
works/bstream_test.c
Normal file
69
works/bstream_test.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2022 Oleg Borodin <borodin@unix7.org>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <bstream.h>
|
||||
#include <massert.h>
|
||||
|
||||
void test_rwrite(void) {
|
||||
bstream_t stream;
|
||||
|
||||
bstream_init(&stream);
|
||||
char* data = "_123456789";
|
||||
size_t dsize = strlen(data);
|
||||
ssize_t wsize = 0;
|
||||
|
||||
size_t count = 3;
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
wsize += bstream_write(&stream, data, dsize);
|
||||
}
|
||||
printf("wsize = %ld, data = [%s]\n", wsize, stream.data);
|
||||
|
||||
MASSERT(stream.wpos == dsize * count);
|
||||
MASSERT(wsize == (ssize_t) (dsize * count));
|
||||
|
||||
size_t bsize = bstream_wpos(&stream);
|
||||
char* buf = malloc((size_t)bsize + (size_t)1);
|
||||
|
||||
memset(buf, 0, (size_t)bsize + (size_t)1);
|
||||
|
||||
ssize_t rsize = bstream_read(&stream, buf, bsize);
|
||||
|
||||
printf("rsize = %lu, buf = [%s]\n", rsize, buf);
|
||||
|
||||
MASSERT(wsize == (ssize_t) (dsize * count));
|
||||
MASSERT(rsize == wsize);
|
||||
|
||||
bstream_destroy(&stream);
|
||||
}
|
||||
|
||||
void test_getnc(void) {
|
||||
bstream_t stream;
|
||||
|
||||
bstream_init(&stream);
|
||||
|
||||
int fd = open("test.json", O_RDONLY);
|
||||
MASSERT(fd > 0);
|
||||
|
||||
char c = bstream_getnc(&stream, fd);
|
||||
printf("%c\n", c);
|
||||
|
||||
printf("%s", (char*)stream.data);
|
||||
|
||||
bstream_destroy(&stream);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
//test_rwrite();
|
||||
test_getnc();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user