commit 4e69c748f15c0952d83722216229dd4689ee8493 Author: Oleg Borodin Date: Sun Aug 13 19:39:49 2023 +0200 at work diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..55f4134 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*~ +*_test +*.o +*geany diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..59e60f3 --- /dev/null +++ b/Makefile @@ -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 diff --git a/cflexer.c b/cflexer.c new file mode 100644 index 0000000..65d5f79 --- /dev/null +++ b/cflexer.c @@ -0,0 +1,245 @@ +/* + * Copyright 2023 Oleg Borodin + */ + +#include +#include +#include +#include + +#include +#include + + +#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; +} diff --git a/cflexer.h b/cflexer.h new file mode 100644 index 0000000..ace04ab --- /dev/null +++ b/cflexer.h @@ -0,0 +1,46 @@ + +#ifndef CFLEXER_H_QWERTY +#define CFLEXER_H_QWERTY + +#include +#include + +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 diff --git a/cflexer_test.c b/cflexer_test.c new file mode 100644 index 0000000..82ec078 --- /dev/null +++ b/cflexer_test.c @@ -0,0 +1,39 @@ +/* + * Copyright 2023 Oleg Borodin + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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; +} diff --git a/cfparser.c b/cfparser.c new file mode 100644 index 0000000..8cb7fda --- /dev/null +++ b/cfparser.c @@ -0,0 +1,152 @@ +/* + * Copyright 2023 Oleg Borodin + */ + +#include +#include +#include +#include + + +#include + +#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); +} diff --git a/cfparser.h b/cfparser.h new file mode 100644 index 0000000..5efef6e --- /dev/null +++ b/cfparser.h @@ -0,0 +1,30 @@ + +#ifndef CFPARSER_H_QWERTY +#define CFPARSER_H_QWERTY + +#include +#include + +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 diff --git a/cfparser_test.c b/cfparser_test.c new file mode 100644 index 0000000..a552248 --- /dev/null +++ b/cfparser_test.c @@ -0,0 +1,49 @@ +/* + * Copyright 2023 Oleg Borodin + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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; +} diff --git a/cllexer.c b/cllexer.c new file mode 100644 index 0000000..53e10f8 --- /dev/null +++ b/cllexer.c @@ -0,0 +1,246 @@ +/* + * Copyright 2023 Oleg Borodin + */ + +#include +#include +#include +#include + +#include + +#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; +} diff --git a/cllexer.h b/cllexer.h new file mode 100644 index 0000000..01ba077 --- /dev/null +++ b/cllexer.h @@ -0,0 +1,38 @@ + +#ifndef CLLEXER_H_QWERTY +#define CLLEXER_H_QWERTY + +#include + +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 diff --git a/cllexer_test.c b/cllexer_test.c new file mode 100644 index 0000000..860eab4 --- /dev/null +++ b/cllexer_test.c @@ -0,0 +1,32 @@ +/* + * Copyright 2023 Oleg Borodin + */ + +#include +#include +#include +#include +#include +#include + +#include + +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; +} diff --git a/clparser.c b/clparser.c new file mode 100644 index 0000000..bb000b9 --- /dev/null +++ b/clparser.c @@ -0,0 +1,180 @@ +/* + * Copyright 2023 Oleg Borodin + */ + +#include +#include +#include +#include + + +#include + +#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); +} diff --git a/clparser.h b/clparser.h new file mode 100644 index 0000000..fbd098c --- /dev/null +++ b/clparser.h @@ -0,0 +1,30 @@ + +#ifndef CLPARSER_H_QWERTY +#define CLPARSER_H_QWERTY + +#include +#include + +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 diff --git a/clparser_test.c b/clparser_test.c new file mode 100644 index 0000000..3914909 --- /dev/null +++ b/clparser_test.c @@ -0,0 +1,49 @@ +/* + * Copyright 2023 Oleg Borodin + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +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; +} diff --git a/jlexer.c b/jlexer.c new file mode 100644 index 0000000..dd6fd35 --- /dev/null +++ b/jlexer.c @@ -0,0 +1,207 @@ +/* + * Copyright 2023 Oleg Borodin + */ + +#include +#include +#include +#include + +#include +#include + +#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; +} diff --git a/jlexer.h b/jlexer.h new file mode 100644 index 0000000..46694c5 --- /dev/null +++ b/jlexer.h @@ -0,0 +1,45 @@ + +#ifndef JLEXER_H_QWERTY +#define JLEXER_H_QWERTY + +#include +#include + +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 diff --git a/jlexer_test.c b/jlexer_test.c new file mode 100644 index 0000000..6fb50ae --- /dev/null +++ b/jlexer_test.c @@ -0,0 +1,42 @@ +/* + * Copyright 2023 Oleg Borodin + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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; +} diff --git a/jparser.c b/jparser.c new file mode 100644 index 0000000..44587b9 --- /dev/null +++ b/jparser.c @@ -0,0 +1,133 @@ +/* + * Copyright 2023 Oleg Borodin + */ + +#include +#include +#include +#include + + +#include + +#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); +} diff --git a/jparser.h b/jparser.h new file mode 100644 index 0000000..5cdc9f2 --- /dev/null +++ b/jparser.h @@ -0,0 +1,36 @@ + +#ifndef CLPARSER_H_QWERTY +#define CLPARSER_H_QWERTY + +#include +#include + +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 diff --git a/jparser_test.c b/jparser_test.c new file mode 100644 index 0000000..e1ad038 --- /dev/null +++ b/jparser_test.c @@ -0,0 +1,61 @@ +/* + * Copyright 2023 Oleg Borodin + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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; +} diff --git a/massert.c b/massert.c new file mode 100644 index 0000000..0b417b0 --- /dev/null +++ b/massert.c @@ -0,0 +1,14 @@ +/* + * Copyright 2022 Oleg Borodin + */ + + +#include +#include + +#include + +void x__assert(char* path, int line, const char* func) { + printf("%s:%d: assert error in %s\n", path, line, func); + exit(1); +} diff --git a/massert.h b/massert.h new file mode 100644 index 0000000..0596e93 --- /dev/null +++ b/massert.h @@ -0,0 +1,16 @@ +/* + * Copyright 2022 Oleg Borodin + */ + + +#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 diff --git a/rcache.c b/rcache.c new file mode 100644 index 0000000..5a6111f --- /dev/null +++ b/rcache.c @@ -0,0 +1,62 @@ +/* + * + * Copyright 2023 Oleg Borodin + * + */ + +#include +#include +#include +#include + +#include + + +#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); + } +} diff --git a/rcache.h b/rcache.h new file mode 100644 index 0000000..18a2f70 --- /dev/null +++ b/rcache.h @@ -0,0 +1,26 @@ +/* + * + * Copyright 2023 Oleg Borodin + * + */ + +#ifndef RCACHE_H_QWERTY +#define RCACHE_H_QWERTY + +#include +#include + +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 diff --git a/rcache_test.c b/rcache_test.c new file mode 100644 index 0000000..0e27276 --- /dev/null +++ b/rcache_test.c @@ -0,0 +1,38 @@ +/* + * Copyright 2022 Oleg Borodin + */ + +#include +#include +#include +#include + +#include +#include + + +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; +} diff --git a/test.conf b/test.conf new file mode 100644 index 0000000..95365d3 --- /dev/null +++ b/test.conf @@ -0,0 +1,5 @@ +"id" = -123\" +name = "qwerty\"567" +foo = bar # bbbb +"aaa +# aaaa diff --git a/test.dat b/test.dat new file mode 100644 index 0000000..ffb226f --- /dev/null +++ b/test.dat @@ -0,0 +1,3 @@ +qwerty +qwerty +qwerty diff --git a/test.json b/test.json new file mode 100644 index 0000000..88bbeb3 --- /dev/null +++ b/test.json @@ -0,0 +1 @@ +{"id":-123, "name" : "qwerty"} diff --git a/works/bstream.c b/works/bstream.c new file mode 100644 index 0000000..fdc8b9a --- /dev/null +++ b/works/bstream.c @@ -0,0 +1,141 @@ +/* + * + * Copyright 2023 Oleg Borodin + * + */ + +#include +#include +#include +#include + +#include + + +#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); + } +} diff --git a/works/bstream.h b/works/bstream.h new file mode 100644 index 0000000..5d21bf0 --- /dev/null +++ b/works/bstream.h @@ -0,0 +1,36 @@ +/* + * + * Copyright 2023 Oleg Borodin + * + */ + +#ifndef BSTREAM_H_QWERTY +#define BSTREAM_H_QWERTY + +#include +#include + +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 diff --git a/works/bstream_test.c b/works/bstream_test.c new file mode 100644 index 0000000..7bf7ae7 --- /dev/null +++ b/works/bstream_test.c @@ -0,0 +1,69 @@ +/* + * Copyright 2022 Oleg Borodin + */ + +#include +#include +#include +#include + +#include +#include + +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; +}