Last commit with db. Switching to makdown articles representation

This commit is contained in:
Dmitriy Shishkov 2020-07-03 11:22:41 +05:00
parent db9b46f041
commit 68d1c8211c
24 changed files with 427 additions and 96 deletions

View File

@ -13,11 +13,11 @@ INC_FLAGS := $(addprefix -I,$(INC_DIRS))
CPPFLAGS ?= $(INC_FLAGS) -MMD -MP
$(BUILD_DIR)/$(TARGET_EXEC): $(OBJS)
$(CC) $(OBJS) -o $@ $(LDFLAGS)
$(CC) -ggdb3 $(OBJS) -o $@ $(LDFLAGS)
$(BUILD_DIR)/%.c.o: %.c
$(MKDIR_P) $(dir $@)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
$(CC) -ggdb3 $(CPPFLAGS) $(CFLAGS) -c $< -o $@
.PHONY: clean

26
include/db_op/article.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef _ARTICLE_H
#define _ARTICLE_H
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "../../include/db_op/db.h"
#ifndef ARTICLE_T_TYPE
#define ARTICLE_T_TYPE
typedef struct {
unsigned int id;
char *header;
char *content;
char *author;
char *topic;
} article_t;
#endif
int expand_line_article(int n, char *buff, entry_s *rec);
char *serialize_article(entry_s *rec);
#endif

View File

@ -1,11 +0,0 @@
#include <stdio.h>
#include <unistd.h>
typedef struct
{
char *header;
char *content;
char **tags;
char *author;
unsigned int key;
} blogpost_t;

View File

@ -1,3 +1,6 @@
#ifndef _DB_H
#define _DB_H
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
@ -5,13 +8,44 @@
#include <string.h>
#include <sys/stat.h>
#include "./blogpost.h"
#ifndef ARTICLE_T_TYPE
#define ARTICLE_T_TYPE
typedef struct {
unsigned int id;
char *header;
char *content;
char *author;
char *topic;
} article_t;
#endif
typedef enum
{
BLOGPOST_T,
ARTICLE_T
} types;
typedef struct
{
types type;
union {
article_t a;
} data;
} entry_s;
#include "./article.h"
#define LINE_SIZE 512
int open_db(char *file_name, char *type, FILE **file, char ***head, int *head_length);
int open_db(char *file_name, types type, FILE **file, char ***head, int *head_length);
int open_table(char *file_name, FILE **file);
int read_head(FILE *file, char ***head);
int get_entry(FILE *file, void **rec, int type, int n, int (*process_line)(char *, void **, int));
int append_table(FILE *file, void *rec, int type, char *(*process_line)(void *, int));
int get_entry(FILE *file, entry_s *rec, int n, int (*process_line)(int, char *, entry_s *));
int append_table(FILE *file, entry_s *rec, char *(*process_line)(entry_s *));
int remove_entry(FILE *file, int n);
int read_whole_table(FILE *file, entry_s **rec, int (*process_line)(int, char *, entry_s *));
int find_by(FILE *file, entry_s **entries, int (*check_line)(int, char *, entry_s), int (*process_line)(int, char *, entry_s));
#endif

8
include/db_op/db_cli.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _DB_CLI_H
#define _DB_CLI_H
#include "../../include/db_op/db.h"
char *get_all_articles_list();
#endif

View File

@ -1,3 +1,6 @@
#ifndef _FILE_H
#define _FILE_H
#include <string.h>
#include <stdlib.h>
#include <sys/sendfile.h>
@ -14,4 +17,6 @@ struct file_s
char *gen_file_path(char *path);
int send_file(int cli_fd, struct file_s *file);
struct file_s *get_file_info(char *file_path);
struct file_s *get_file_info(char *file_path);
#endif

View File

@ -1,3 +1,10 @@
#ifndef _MIME_H
#define _MIME_H
#include <string.h>
char *get_mime_type(char *file_path);
#define DEFAULT_MIME_TYPE "application/octet-stream"
char *get_mime_type(char *file_path);
#endif

View File

@ -1,8 +1,15 @@
#ifndef _NETW_H
#define _NETW_H
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netdb.h>
#define BACKLOG 10
int get_listener_socket(char *port);
void *get_in_addr(struct sockaddr *sa);
void *get_in_addr(struct sockaddr *sa);
#endif

View File

@ -1,3 +1,6 @@
#ifndef _REQUEST_H
#define _REQUEST_H
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
@ -8,13 +11,19 @@
#include <sys/types.h>
#include <sys/socket.h>
#define FILE_SIZE 1024
struct header_s {
char * str;
size_t size;
};
void res_404(int fd, char *path);
void res_500(int fd);
char *get_path(char *request);
struct header_s *gen_header(int status_code, size_t file_size, char *mime_type);
int send_response(int fd, char *req_path);
void handle_post_request(int fd, char *request);
void handle_get_request(int fd, char *request);
void handle_get_request(int fd, char *request);
#endif

View File

@ -1,5 +1,11 @@
#ifndef _ARR_H
#define _ARR_H
#include <string.h>
#include <stdlib.h>
void insert_to_arr(char ***arr, size_t length, char *value);
void free_arr(char **arr, int length);
void free_arr(char **arr, int length);
int check_if_contains(char **arr, size_t length, char *str);
#endif

View File

@ -0,0 +1,20 @@
#ifndef _LLIST_H
#define _LLIST_H
#include <stdio.h>
#include <stdlib.h>
#define NUMBER 5
typedef struct llist_s
{
char *value;
struct llist_s *next;
} llist_t;
llist_t *find_item(llist_t *list, int n);
void fill_with_arr(llist_t **list, char **arr, size_t n);
void print_llist(llist_t *list);
llist_t *add_to_list(llist_t **head, int pos, char *value);
#endif

View File

@ -1,9 +1,14 @@
#ifndef _UTILS_H
#define _UTILS_H
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
void err_msg(char *msg);
char *add_to_front(char **str1, char *str2);
char *concat_to_front(char **str1, char *str2);
char *get_status_message(int status_code);
char *to_lower(char *str);
char *to_lower(char *str);
#endif

49
src/db_op/article.c Normal file
View File

@ -0,0 +1,49 @@
#include "../../include/db_op/db.h"
int expand_line_article(int n, char *buff, entry_s *rec)
{
#define entry rec->data.a
entry.id = n;
char *tmp = strtok(buff, ";");
if (tmp == NULL)
return -1;
entry.header = malloc(strlen(tmp) + 1);
entry.header = tmp;
tmp = strtok(NULL, ";");
if (tmp == NULL)
return -2;
entry.content = malloc(strlen(tmp) + 1);
entry.content = tmp;
tmp = strtok(NULL, ";");
if (tmp == NULL)
return -3;
entry.author = malloc(strlen(tmp) + 1);
entry.author = tmp;
tmp = strtok(NULL, "\n");
if (tmp == NULL)
return -4;
entry.topic = malloc(strlen(tmp) + 1);
entry.topic = tmp;
return 0;
}
char *serialize_article(entry_s *rec)
{
int line_length = snprintf(NULL, 0, "%s;%s;%s;%s\n", entry.header, entry.content, entry.author, entry.topic) + 1;
char *line = malloc(line_length);
if (line == NULL)
return "";
snprintf(line, line_length, "%s;%s;%s;%s\n", entry.header, entry.content, entry.author, entry.topic);
return line;
}

View File

@ -1 +0,0 @@
#include "../../include/db_op/blogpost.h"

View File

@ -12,8 +12,24 @@
* @param head_length
* @return int
*/
int open_db(char *file_name, char *type, FILE **file, char ***head, int *head_length)
int open_db(char *file_name, types type, FILE **file, char ***head, int *head_length)
{
char *type_string;
switch (type)
{
case BLOGPOST_T:
type_string = "blogpost";
break;
case ARTICLE_T:
type_string = "article";
break;
default:
err_msg("This type is not supported");
return -1;
}
FILE *root_file;
if ((root_file = fopen(file_name, "a+")) == NULL)
{
@ -25,8 +41,7 @@ int open_db(char *file_name, char *type, FILE **file, char ***head, int *head_le
size_t size = LINE_SIZE;
while (getline(&buff, &size, root_file) >= 0)
{
if (strcmp(type, strtok(buff, " ")) == 0)
if (strcmp(type_string, strtok(buff, " ")) == 0)
{
int ret = open_table(strtok(NULL, "\n"), file);
@ -36,20 +51,19 @@ int open_db(char *file_name, char *type, FILE **file, char ***head, int *head_le
return ret;
}
}
free(buff);
struct stat st = {0};
if (stat("./db", &st) == -1)
{
mkdir("./db", 0700);
}
int table_file_name_size = snprintf(NULL, 0, "./db/%s.csv", type) + 1;
int table_file_name_size = snprintf(NULL, 0, "./db/%s.csv", type_string) + 1;
char *table_file_name = malloc(table_file_name_size);
snprintf(table_file_name, table_file_name_size, "./db/%s.csv", type);
snprintf(table_file_name, table_file_name_size, "./db/%s.csv", type_string);
fseek(root_file, 0, SEEK_SET);
fprintf(root_file, "%s %s\n", type, table_file_name);
fprintf(root_file, "%s %s\n", type_string, table_file_name);
fclose(root_file);
@ -98,9 +112,7 @@ int read_head(FILE *file, char ***head)
char *tok;
int i = 0;
for (tok = strtok(buff, ";"); tok && *tok; tok = strtok(NULL, ";"))
{
insert_to_arr(head, length++, tok);
}
return length;
}
@ -110,12 +122,11 @@ int read_head(FILE *file, char ***head)
*
* @param file
* @param rec
* @param type
* @param n
* @param process_line
* @return int
*/
int get_entry(FILE *file, void **rec, int type, int n, int (*process_line)(char *, void **, int))
int get_entry(FILE *file, entry_s *rec, int n, int (*process_line)(int, char *, entry_s *))
{
char *buff = NULL;
int i = 0;
@ -127,13 +138,15 @@ int get_entry(FILE *file, void **rec, int type, int n, int (*process_line)(char
{
if (i == n)
{
int res = (*process_line)(buff, rec, type);
int res = (*process_line)(n, buff, rec);
return res;
}
else
i++;
}
free(buff);
return -1;
}
@ -142,14 +155,13 @@ int get_entry(FILE *file, void **rec, int type, int n, int (*process_line)(char
*
* @param file
* @param rec
* @param type
* @param process_line
* @return int
*/
int append_table(FILE *file, void *rec, int type, char *(*process_line)(void *, int))
int append_table(FILE *file, entry_s *rec, char *(*process_line)(entry_s *))
{
fseek(file, 0, SEEK_END);
char *buff = (*process_line)(rec, type);
char *buff = (*process_line)(rec);
if (fprintf(file, "%s", buff) < 0)
return -1;
@ -189,9 +201,8 @@ int remove_entry(FILE *file, int n)
while (getline(&buff, &size, file) >= 0)
{
if (i != n)
{
fprintf(tmp_file, "%s", buff);
}
i++;
}
@ -230,4 +241,42 @@ int remove_entry(FILE *file, int n)
free(tmp_file_name);
return i;
}
int read_whole_table(FILE *file, entry_s **entries, int (*process_line)(int ,char *, entry_s *))
{
char *buff;
int i = 0;
size_t size = LINE_SIZE;
fseek(file, 0, SEEK_SET);
printf("Begining line-by-line reading\n");
while (getline(&buff, &size, file) >= 0)
{
if (i == 0)
{
i++;
continue;
}
printf("Read line [%d]: %s\n", i, buff);
int res = (*process_line)(i, buff, &((*entries)[i]));
if (res < 0)
return res;
i++;
printf("---%lu---\n", sizeof(entry_s));
*entries = (entry_s *)realloc(*entries, sizeof(entry_s) * i);
}
if (i == 1)
return -1;
free(buff);
return ++i;
}

103
src/db_op/db_cli.c Normal file
View File

@ -0,0 +1,103 @@
#include "../../include/db_op/db_cli.h"
#include "../../include/utils_op/arr.h"
char *get_all_articles_list()
{
FILE *db_file;
char **db_head;
int length = -1;
int ret = open_db("root.db", ARTICLE_T, &db_file, &db_head, &length);
if (ret == 1)
{
perror("No such database\n");
}
entry_s *articles_table = (entry_s *)malloc(sizeof(entry_s));
if (articles_table == NULL)
return "";
size_t entries_amount = read_whole_table(db_file, &articles_table, expand_line_article);
printf("\nStarting processing table\n");
size_t topics_amount = 0;
char **articles_by_topics_lists = malloc(topics_amount * sizeof(char *));
char **topics_list = malloc(topics_amount * sizeof(char));
if (articles_by_topics_lists == NULL || topics_list == NULL)
return "";
printf("Initialized lists arrays\n");
size_t topics_list_size = 1;
for (int i = 0; i < entries_amount; i++)
{
printf("Processing entry [%d]\n", i);
article_t rec = articles_table[i].data.a;
int pos = check_if_contains(topics_list, topics_amount, rec.topic);
if (pos == 0)
{
topics_amount++;
char **tmp_topics_list = realloc(topics_list, topics_list_size + strlen(rec.topic));
if (tmp_topics_list == NULL)
continue;
else
topics_list = tmp_topics_list;
topics_list_size += strlen(rec.topic);
pos = topics_amount - 1;
topics_list[pos] = rec.topic;
char **tmp_articles_by_topics_lists = realloc(articles_by_topics_lists, topics_amount * sizeof(char *));
if (tmp_articles_by_topics_lists == NULL)
continue;
else
articles_by_topics_lists = tmp_articles_by_topics_lists;
}
int line_length = snprintf(NULL, 0, "<li>%s</li>\n", rec.header) + 1;
char *tmp_line = malloc(line_length);
if (tmp_line == NULL)
return "";
snprintf(tmp_line, line_length, "<li>%s</li>\n", rec.header);
char *tmp_articles_by_topics_lists_line = realloc(articles_by_topics_lists[pos], strlen(articles_by_topics_lists[pos]) + line_length + 1);
if (tmp_articles_by_topics_lists_line == NULL)
continue;
else
articles_by_topics_lists[pos] = tmp_articles_by_topics_lists_line;
strncat(articles_by_topics_lists[pos], tmp_line, line_length);
}
char *articles_table_list_str = malloc(topics_amount * strlen("<h1></h1>\n<ul></ul>\n"));
if (articles_table_list_str == NULL)
return "";
for (int i = 0; i < topics_amount; i++)
{
int add_len = snprintf(NULL, 0, "<h1>%s</h1>\n<ul>%s</ul>\n", topics_list[i], articles_by_topics_lists[i]);
char *tmp_line = malloc(add_len);
if (tmp_line == NULL)
continue;
snprintf(tmp_line, add_len, "<h1>%s</h1>\n<ul>%s</ul>\n", topics_list[i], articles_by_topics_lists[i]);
char *tmp_articles_table_list_str = realloc(articles_table_list_str, strlen(articles_table_list_str) + add_len + 1);
if (tmp_articles_table_list_str == NULL)
continue;
else
articles_table_list_str = tmp_articles_table_list_str;
strcat(articles_table_list_str, tmp_line);
}
return articles_table_list_str;
}

View File

@ -25,7 +25,7 @@ char *gen_file_path(char *req_path)
char *webroot = "static";
path = realloc(path, strlen(path) + strlen(webroot));
path = add_to_front(&path, webroot);
path = concat_to_front(&path, webroot);
return path;
}

View File

@ -1,8 +1,6 @@
#include "../../include/file_op/mime.h"
#include "../../include/utils_op/utils.h"
#define DEFAULT_mime_TYPE "application/octet-stream"
/**
* @brief Get the mime type of file
*
@ -15,11 +13,10 @@ char *get_mime_type(char *file_path)
if (ext == NULL)
{
return DEFAULT_mime_TYPE;
return DEFAULT_MIME_TYPE;
}
ext++;
ext = to_lower(ext);
if (strcmp(ext, "html") == 0 || strcmp(ext, "htm") == 0)
@ -59,5 +56,5 @@ char *get_mime_type(char *file_path)
return "image/x-icon";
}
return DEFAULT_mime_TYPE;
return DEFAULT_MIME_TYPE;
}

View File

@ -1,8 +1,6 @@
#include "../../include/netw_op/netw.h"
#include "../../include/utils_op/utils.h"
#define BACKLOG 10
/**
* @brief Get the listener socket object
*

View File

@ -2,6 +2,7 @@
#include "../../include/utils_op/utils.h"
#include "../../include/file_op/file.h"
#include "../../include/file_op/mime.h"
#include "../../include/db_op/db_cli.h"
/**
* @brief Send 404 response
@ -13,12 +14,12 @@ void res_404(int fd, char *path)
{
FILE *fp = fopen("static/404.html", "r");
const ssize_t fsize = 512;
char buf[fsize], msg[fsize];
char buff[fsize], msg[fsize];
fread(buf, fsize, 1, fp);
fread(buff, fsize, 1, fp);
fclose(fp);
sprintf(msg, buf, path, path);
sprintf(msg, buff, path, path);
struct header_s *header = gen_header(404, strlen(msg), "text/html");
send(fd, header->str, header->size - 1, 0);
@ -29,8 +30,21 @@ void res_404(int fd, char *path)
printf("404 ERROR\n");
}
void res_500(int fd)
{
char *msg = "Server error";
struct header_s *header = gen_header(500, sizeof(msg), "text/plain");
send(fd, header->str, header->size - 1, 0);
send(fd, msg, sizeof(msg), 0);
close(fd);
printf("500 ERROR\n");
}
/**
* @brief Get the path object
* @brief Get the path string
*
* @param request
* @return char*
@ -85,29 +99,13 @@ int send_response(int fd, char *req_path)
if (file == NULL)
{
char *msg = "Server error";
struct header_s *header = gen_header(500, sizeof(msg), "text/plain");
send(fd, header->str, header->size - 1, 0);
send(fd, msg, sizeof(msg), 0);
close(fd);
res_500(fd);
return 0;
}
if (file->fd < 0)
{
// char *msg = "<html>\n<body>404, Not Found. Return to home? <a href=\"/\">Home</a></body><html/>";
// struct header_s *header = gen_header(404, strlen(msg), "text/html");
// send(fd, header->str, header->size - 1, 0);
// send(fd, msg, strlen(msg), 0);
// close(fd);
// printf("404 ERROR\n");
res_404(fd, req_path);
return 0;
@ -160,6 +158,29 @@ void handle_get_request(int fd, char *request)
char *path = get_path(request);
printf("Client accessed path: %s\n", path);
if (strcmp(path, "/") == 0)
{
FILE *fp = fopen("static/index.html", "r");
char buff[FILE_SIZE], msg[FILE_SIZE * 2], articles_list_str[FILE_SIZE / 2] = {0}, blogposts_list_str[FILE_SIZE / 2] = {0};
fread(buff, FILE_SIZE, 1, fp);
fclose(fp);
sprintf(msg, buff, articles_list_str, blogposts_list_str);
struct header_s *header = gen_header(200, strlen(msg), "text/html");
send(fd, header->str, header->size - 1, 0);
send(fd, msg, strlen(msg), 0);
close(fd);
printf("Sent home page\n");
return;
}
if (strncmp(path, "/blog/", strlen("/blog/")) == 0)
{
char *id = (char *)malloc(strlen(path) - strlen("/blog/") + 1);
@ -167,7 +188,6 @@ void handle_get_request(int fd, char *request)
printf("Blog post id = %s\n", id);
}
if (send_response(fd, path) < 0)
{

View File

@ -28,4 +28,21 @@ void free_arr(char **arr, int length)
free(arr[i]);
free(arr);
}
/**
* @brief Check if array contains string
*
* @param arr
* @param length
* @param str
* @return int
*/
int check_if_contains(char **arr, size_t length, char *str)
{
for (int i = 0; i < length; i++)
if (strcmp(arr[i], str) == 0)
return i;
return 0;
}

View File

@ -1,13 +1,4 @@
#include <stdio.h>
#include <stdlib.h>
#define NUMBER 5
typedef struct llist_s
{
char *value;
struct llist_s *next;
} llist_t;
#include "../../include/utils_op/llist.h"
/**
* @brief Find item by number
@ -41,7 +32,7 @@ void fill_with_arr(llist_t **list, char **arr, size_t n)
}
/**
* @brief Print hole list
* @brief Print whole list
*
* @param list
*/
@ -94,6 +85,7 @@ llist_t *add_to_list(llist_t **head, int pos, char *value)
return current->next;
}
// Example of usage
// int main()
// {
// llist_t *head = malloc(sizeof(llist_t));

View File

@ -17,15 +17,13 @@ void err_msg(char *msg)
* @param str2
* @return char*
*/
char *add_to_front(char **str1, char *str2)
char *concat_to_front(char **str1, char *str2)
{
char *tmp = strdup(*str1);
strcpy(*str1, str2);
strcat(*str1, tmp);
// free(tmp);
return *str1;
}

View File

@ -21,14 +21,7 @@
<li><a href="/projects">Projects</a></li>
<li><a href="/philosophy">Philosophy</a></li>
</ul>
<h1>Blog</h1>
<ul>
%s
</ul>
<h1>Tech articles</h1>
<ul>
%s
</ul>
%s
</main>
</body>