#include #include #include "response.h" #define SET_STR(segment) \ (segment) = malloc(i - start + 1); \ strncpy((segment), s + start, i - start); #define MOVE(amount) \ i += (amount); \ start = i; #define CHECK_AT_END() \ if (cur == '\0') { \ state = END; \ } #define AT_DELIM (cur == '\t' && next == '\r' && next_next == '\n') enum state { STATUS, MESSAGE, MESSAGE_S, TYPE_S, TYPE, LENGTH_S, LENGTH, HASH, HASH_S, CONTENT, END }; int parse_response(struct response *res, char *s) { int i = 0; int start = 0; char cur; char next; char next_next; int s_len = strlen(s); enum state state = STATUS; while (state != END) { cur = s[i]; if (i < s_len) next = s[i + 1]; if (i + 1 < s_len) next_next = s[i + 2]; switch (state) { case STATUS: if (cur == '\r' && next == '\n') { char *status_str; SET_STR(status_str); int status = atoi(status_str); if (status > 0) res->status = status; else return INVALID_STATUS; free(status_str); MOVE(2); state = MESSAGE; } break; case MESSAGE: if (cur == ':') { char *message_str; SET_STR(message_str); if (strncmp(message_str, "message", 7) != 0) { MOVE(strlen(message_str) * -1); state = TYPE; break; } else { MOVE(1); // skip ':' state = MESSAGE_S; } free(message_str); } break; case MESSAGE_S: if (AT_DELIM) { char *message_str; SET_STR(message_str); res->message = message_str; MOVE(3); state = TYPE; } break; case TYPE: if (cur == ':') { char *type_str; SET_STR(type_str); if (strncmp(type_str, "type", 4) != 0) { MOVE(strlen(type_str) * -1); state = LENGTH; } else { MOVE(1); // skip ':' state = TYPE_S; } free(type_str); } break; case TYPE_S: if (cur == '/') { SET_STR(res->type.type); MOVE(1); } else if (AT_DELIM) { SET_STR(res->type.subtype); MOVE(3); state = LENGTH; } break; case LENGTH: if (cur == ':') { char *length_str; SET_STR(length_str); if (strncmp(length_str, "length", 6) != 0) { MOVE(strlen(length_str) * -1); state = HASH; } else { MOVE(1); // skip ':' state = LENGTH_S; } free(length_str); } case LENGTH_S: if (AT_DELIM) { char *length_str; SET_STR(length_str); res->length = atoi(length_str); free(length_str); MOVE(3); state = HASH; } break; case HASH: if (cur == ':') { char *hash_str; SET_STR(hash_str); if (strncmp(hash_str, "hash", 4) != 0) { MOVE(strlen(hash_str) * -1); free(hash_str); return UNKNOWN_KEY; } else { MOVE(1); // skip ':' state = HASH_S; } free(hash_str); } break; case HASH_S: if ((cur == '\r' && next == '\n') || AT_DELIM) { char *hash_str; SET_STR(hash_str); res->hash = hash_str; MOVE(4); state = CONTENT; } case CONTENT: if (res->length < 1) { state = END; break; } if (i == s_len - 1) { char *content_str; SET_STR(content_str); res->content = content_str; state = END; } case END: break; } i++; if (i == s_len) { state = END; } } return 0; } void free_response(struct response *res) { free(res->message); free(res->type.type); free(res->type.subtype); free(res->hash); free(res->content); }