From 946cbbac6737a84bd93b779a824fb4053c49eaf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Tue, 7 Mar 2023 21:29:29 +0800 Subject: [PATCH] add editor --- CMakeLists.txt | 3 + cmoe.c | 29 +++--- editor.c | 250 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 269 insertions(+), 13 deletions(-) create mode 100644 editor.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 1882c10..aa5178a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,10 @@ add_compile_options(-std=c99) message(STATUS "optional:-std=c99") add_executable(cmoe cmoe.c) +add_executable(cmoeditor editor.c) target_link_libraries(cmoe spb) +target_link_libraries(cmoeditor spb) INSTALL(TARGETS cmoe RUNTIME DESTINATION bin) +INSTALL(TARGETS cmoeditor RUNTIME DESTINATION bin) diff --git a/cmoe.c b/cmoe.c index 03586a8..142d4ad 100644 --- a/cmoe.c +++ b/cmoe.c @@ -18,27 +18,24 @@ static FILE* fp; #define ADD_HEADER_PARAM(buf, offset, h, p) sprintf(buf + offset, (h), (p)) #define HEADER(content_type) HTTP200 SERVER_STRING CACHE_CTRL CONTENT_TYPE(content_type) #define headers(content_len, content_type) (_headers(content_len, HEADER(content_type), sizeof(HEADER(content_type))-1)) -static void _headers(uint32_t content_len, const char* h, size_t hlen) { +static int _headers(uint32_t content_len, const char* h, size_t hlen) { char buf[64]; size_t offset = ADD_HEADER_PARAM(buf, 0, CONTENT_LEN "\r\n", content_len); - if(offset <= 0) { - write(1, "\0\0\0\0", 4); - exit(EXIT_FAILURE); - } + if(offset <= 0) return -1; content_len += offset+hlen; struct iovec iov[3] = {{&content_len, sizeof(uint32_t)}, {(void*)h, hlen}, {(void*)buf, offset}}; - writev(1, (const struct iovec *)&iov, 3); + return writev(1, (const struct iovec *)&iov, 3) <= 0; } -static void http_error(errcode_enum_t code, char* msg) { +static inline void http_error(errcode_enum_t code, char* msg) { uint32_t len = strlen(msg) + typel[code]; - char* str = malloc(len); + char str[len]; sprintf(str, types[code], msg); struct iovec iov[2] = {{(void*)&len, sizeof(uint32_t)}, {(void*)str, len}}; writev(1, (const struct iovec *)&iov, 2); - free(str); } +// get_arg used malloc but has never freed static char* get_arg(const char* query) { int len = 0; while(query[len] && query[len] != '&') len++; @@ -75,14 +72,14 @@ static int del_user(FILE* fp, SIMPLE_PB* spb) { return 2; } -static int add_user(char* name, uint32_t count, FILE* fp) { +static inline int add_user(char* name, uint32_t count, FILE* fp) { counter.count = count; strncpy(counter.name, name, COUNTER_NAME_LEN-1); fseek(fp, 0, SEEK_END); return !set_pb(fp, items_len, sizeof(counter_t), &counter); } -static uint32_t get_content_len(int isbig, uint16_t* len_type, char* cntstr) { +static inline uint32_t get_content_len(int isbig, uint16_t* len_type, char* cntstr) { uint32_t len = sizeof(svg_small) // small & big has the same len + sizeof(svg_tail) - 1; for(int i = 0; cntstr[i]; i++) { @@ -142,7 +139,10 @@ static void return_count(FILE* fp, char* name, char* theme) { h = H_SMALL; head = (char*)svg_small; } - headers(get_content_len(isbig, len_type, cntstr), image/svg+xml); + if(headers(get_content_len(isbig, len_type, cntstr), image/svg+xml)) { + write(1, "\0\0\0\0", 4); + return; + } printf(head, w*(10+cntstrbuf-cntstr)); for(int i = 0; cntstr[i]; i++) { printf(img_slot_front, w * i, w, h); @@ -248,7 +248,10 @@ int main(int argc, char **argv) { add_user(name, 0, fp); fclose(fp); fp = NULL; char* msg = "

Success.\r\n"; - headers(strlen(msg), text/html); + if(headers(strlen(msg), text/html)) { + write(1, "\0\0\0\0", 4); + return 8; + } return write(1, msg, strlen(msg)) <= 0; } diff --git a/editor.c b/editor.c new file mode 100644 index 0000000..2b1c7ca --- /dev/null +++ b/editor.c @@ -0,0 +1,250 @@ +#include +#include +#include +#include +#include +#include "cmoe.h" + +static uint32_t* items_len; +static counter_t counter; + +static FILE* fp; + +static char buf[sizeof(SIMPLE_PB)+sizeof(counter_t)]; + +static int del_user(FILE* fp, SIMPLE_PB* spb) { + counter_t *d = (counter_t *)spb->target; + uint32_t next = ftell(fp); + uint32_t this = next - spb->real_len; + fseek(fp, 0, SEEK_END); + uint32_t end = ftell(fp); + if(next == end) return ftruncate(fileno(fp), end - spb->real_len); + uint32_t cap = end - next; + char *data = malloc(cap); + if(data) { + fseek(fp, next, SEEK_SET); + if(fread(data, cap, 1, fp) == 1) { + if(!ftruncate(fileno(fp), end - spb->real_len)){ + fseek(fp, this, SEEK_SET); + if(fwrite(data, cap, 1, fp) == 1) { + free(data); + fflush(fp); + return 0; + } + } + } + free(data); + } + return 2; +} + +#define has_next(fp, ch) ((ch=getc(fp)),(feof(fp)?0:(ungetc(ch,fp),1))) + +int main(int argc, char** argv) { + if (argc != 2) { + puts("Usage: editor dat.sp"); + return 0; + } + fp = fopen(argv[1], "rb+"); + if (!fp) { + perror("fopen"); + return 1; + } + items_len = align_struct(sizeof(counter_t), 2, &counter.name, &counter.count); + if(!items_len) { + perror("align_struct"); + return 2; + } + int go; + lop: do { + go = 1; + puts("\ncommands:"); + puts("\ta string uint: add user with count."); + puts("\td string: delete user."); + puts("\tD string: delete users match the keyword (empty is not allowed)."); + puts("\tg string: get user count."); + puts("\tm uint: print users < count."); + puts("\tM uint: delete users < count."); + puts("\tp string: print users match the keyword (empty for all)."); + puts("\tq: quit."); + putchar('>');putchar(' '); + char c = getchar(); + switch (c) { + case 'a': + while ((c = getchar()) == ' '); // skip space + memset(counter.name, 0, sizeof(counter.name)); + counter.name[0] = c; + while ((c = getchar()) != ' ' && go < sizeof(counter.name)-1) counter.name[go++] = c; + while ((c = getchar()) == ' '); // skip space + ungetc(c, stdin); + scanf("%u", &counter.count); + while (getchar() != '\n'); // skip to endl + printf("set user '%s' to %u\n", counter.name, counter.count); + if (fseek(fp, 0, SEEK_END)) { + perror("fseek"); + return 3; + } + if (set_pb(fp, items_len, sizeof(counter_t), &counter) != 2) { + puts("set pb error."); + return 4; + } + break; + case 'd': + while ((c = getchar()) == ' '); // skip space + memset(counter.name, 0, sizeof(counter.name)); + counter.name[0] = c; + while ((c = getchar()) != '\n' && go < sizeof(counter.name)-1) counter.name[go++] = c; + if (fseek(fp, 0, SEEK_SET)) { + perror("fseek"); + return 5; + } + while(has_next(fp, c)) { + SIMPLE_PB *spb = read_pb_into(fp, (SIMPLE_PB*)buf); + counter_t *d = (counter_t *)spb->target; + if (strcmp(counter.name, d->name)) continue; + if(del_user(fp, spb)) { + perror("del_user"); + return 6; + } + printf("del user '%s'.\n", d->name); + goto lop; + } + printf("no such user '%s'.\n", counter.name); + break; + case 'D': + if (getchar() == '\n') { + puts("empty D is not allowed."); + break; + } + while ((c = getchar()) == ' '); // skip space + memset(counter.name, 0, sizeof(counter.name)); + counter.name[0] = c; + while ((c = getchar()) != '\n' && go < sizeof(counter.name)-1) counter.name[go++] = c; + go = 1; + scanlopD: + if (fseek(fp, 0, SEEK_SET)) { + perror("fseek"); + return 7; + } + while(has_next(fp, c)) { + SIMPLE_PB *spb = read_pb_into(fp, (SIMPLE_PB*)buf); + counter_t *d = (counter_t *)spb->target; + if (strstr(d->name, counter.name)) { + if(del_user(fp, spb)) { + perror("del_user"); + return 8; + } + printf("del user '%s'.\n", d->name); + go++; + goto scanlopD; + } + } + if (go == 1) puts("no result."); + break; + case 'g': + while ((c = getchar()) == ' '); // skip space + memset(counter.name, 0, sizeof(counter.name)); + counter.name[0] = c; + while ((c = getchar()) != '\n' && go < sizeof(counter.name)-1) counter.name[go++] = c; + if (fseek(fp, 0, SEEK_SET)) { + perror("fseek"); + return 5; + } + while(has_next(fp, c)) { + SIMPLE_PB *spb = read_pb_into(fp, (SIMPLE_PB*)buf); + counter_t *d = (counter_t *)spb->target; + if (strcmp(counter.name, d->name)) continue; + printf("user '%s' = %u.\n", d->name, d->count); + goto lop; + } + printf("no such user '%s'.\n", counter.name); + break; + case 'm': + while ((c = getchar()) == ' '); // skip space + ungetc(c, stdin); + scanf("%u", &counter.count); + while (getchar() != '\n'); // skip to endl + go = 1; + if (fseek(fp, 0, SEEK_SET)) { + perror("fseek"); + return 7; + } + while(has_next(fp, c)) { + SIMPLE_PB *spb = read_pb_into(fp, (SIMPLE_PB*)buf); + counter_t *d = (counter_t *)spb->target; + if (d->count < counter.count) { + printf("'%s' = %u\n", d->name, d->count); + go++; + } + } + if (go == 1) puts("no result."); + break; + case 'M': + if (getchar() == '\n') { + puts("empty M is not allowed."); + break; + } + while ((c = getchar()) == ' '); // skip space + ungetc(c, stdin); + scanf("%u", &counter.count); + while (getchar() != '\n'); // skip to endl + go = 1; + scanlopM: + if (fseek(fp, 0, SEEK_SET)) { + perror("fseek"); + return 7; + } + while(has_next(fp, c)) { + SIMPLE_PB *spb = read_pb_into(fp, (SIMPLE_PB*)buf); + counter_t *d = (counter_t *)spb->target; + if (d->count < counter.count) { + if(del_user(fp, spb)) { + perror("del_user"); + return 8; + } + printf("del user '%s'.\n", d->name); + go++; + goto scanlopM; + } + } + if (go == 1) puts("no result."); + break; + case 'p': + if ((c = getchar()) != '\n') { + while ((c = getchar()) == ' '); // skip space + memset(counter.name, 0, sizeof(counter.name)); + counter.name[0] = c; + while ((c = getchar()) != '\n' && go < sizeof(counter.name)-1) counter.name[go++] = c; + } else counter.name[0] = 0; + go = 1; + if (fseek(fp, 0, SEEK_SET)) { + perror("fseek"); + return 7; + } + while(has_next(fp, c)) { + SIMPLE_PB *spb = read_pb_into(fp, (SIMPLE_PB*)buf); + counter_t *d = (counter_t *)spb->target; + if (!counter.name[0] || strstr(d->name, counter.name)) { + printf("'%s' = %u\n", d->name, d->count); + go++; + } + } + if (go == 1) puts("no result."); + break; + case 'q': + go = 0; + break; + default: + printf("invalid operator '%c'.\n", c); + while (getchar() != '\n'); // skip to endl + break; + } + } while (go); +} + +static void __attribute__((destructor)) defer_close_fp() { + if(fp) { + if (fclose(fp)) perror("fclose"); + else puts("file closed."); + } +}