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.");
+ }
+}