Add errors and refactor some code

This commit is contained in:
Alex D. 2021-03-30 13:24:16 +00:00
parent c5d5f06063
commit 4abc4f35f7
Signed by: caskd
GPG Key ID: F92BA85F61F4C173
12 changed files with 305 additions and 155 deletions

View File

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.16)
project(
uIRC
VERSION 0.3.2
VERSION 0.4.0
DESCRIPTION "Simple and lightweight IRC protocol helper"
LANGUAGES C
)
@ -21,6 +21,7 @@ OPTION(CODE_COVERAGE "Build with coverage tools" OFF)
set(UIRC_SOURCE
src/assemblers/message.c
src/assemblers/user.c
src/error/error.c
src/memory/list.c
src/memory/struct.c
src/tokenizers/message.c
@ -31,6 +32,7 @@ set(UIRC_HEADERS
include/assemblers.h
include/commands.h
include/ctcp.h
include/errors.h
include/memory.h
include/misc.h
include/modes.h

35
include/errors.h Normal file
View File

@ -0,0 +1,35 @@
/*
* This file is part of uIRC. (https://git.redxen.eu/caskd/uIRC)
* Copyright (c) 2019-2021 Alex-David Denes
*
* uIRC is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* uIRC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with uIRC. If not, see <https://www.gnu.org/licenses/>.
*/
/*! \file */
#ifndef UIRC_GUARD_PUBLIC_ERRORS
#define UIRC_GUARD_PUBLIC_ERRORS
typedef enum {
UIRC_ERR_NERROR = 0,
UIRC_ERR_SYSERR,
UIRC_ERR_BUFSIZ,
UIRC_ERR_INVFMT,
} uirc_errno_t;
extern uirc_errno_t uirc_errno;
const char* uirc_strerror(uirc_errno_t errno);
#endif /* UIRC_GUARD_PUBLIC_ERRORS */

View File

@ -19,6 +19,7 @@
#include "assemblers.h"
#include "commands.h"
#include "ctcp.h"
#include "errors.h"
#include "memory.h"
#include "misc.h"
#include "modes.h"

View File

@ -17,6 +17,7 @@
*/
#include "assemblers.h" // uirc_assembler_*
#include "errors.h" // uirc_errno
#include "types.h" // IRC_Message IRC_Tag IRC_User
#include <assert.h> // assert()
@ -33,12 +34,13 @@ uirc_assembler_message(char* buf, const IRC_Message* m, size_t len)
#ifdef UIRC_FEATURE_IRCV3
if (m->tag_list != NULL) {
if (len > 1) {
*(buf++) = '@';
len--;
} else
} else {
uirc_errno = UIRC_ERR_BUFSIZ;
return -1;
}
ssize_t ret;
if ((ret = uirc_assembler_tag_list(buf, m->tag_list, len)) >= 0) {
@ -50,8 +52,10 @@ uirc_assembler_message(char* buf, const IRC_Message* m, size_t len)
if (len > 1) {
*(buf++) = ' ';
len--;
} else
} else {
uirc_errno = UIRC_ERR_BUFSIZ;
return -1;
}
}
assert(sv <= buf);
#endif /* UIRC_FEATURE_IRCV3 */
@ -59,8 +63,10 @@ uirc_assembler_message(char* buf, const IRC_Message* m, size_t len)
if (len > 1) {
*(buf++) = ':';
len--;
} else
} else {
uirc_errno = UIRC_ERR_BUFSIZ;
return -1;
}
ssize_t ret;
if ((ret = uirc_assembler_user(buf, m->source, len)) >= 0) {
@ -72,31 +78,37 @@ uirc_assembler_message(char* buf, const IRC_Message* m, size_t len)
if (len > 1) {
*(buf++) = ' ';
len--;
} else
} else {
uirc_errno = UIRC_ERR_BUFSIZ;
return -1;
}
}
assert(sv <= buf);
if (m->command != NULL) {
if (len < 2) return -1;
int ret;
if ((ret = snprintf(buf, len, "%s", m->command)) >= 0) {
buf += (size_t) ret;
len -= (size_t) ret;
} else
} else {
uirc_errno = UIRC_ERR_BUFSIZ;
return -1;
} else
}
} else {
uirc_errno = UIRC_ERR_INVFMT;
return -1;
}
assert(sv <= buf);
for (unsigned int i = 0; i < IRC_MAXARGS && m->args[i] != NULL; i++) {
if (len < 2) return -1;
int ret;
if ((ret = snprintf(buf, len, (m->args[i + 1] == NULL && m->trailing) ? " :%s" : " %s", m->args[i])) >= 0) {
buf += (size_t) ret;
len -= (size_t) ret;
} else
} else {
uirc_errno = UIRC_ERR_BUFSIZ;
return -1;
}
}
assert(sv <= buf);
@ -104,8 +116,10 @@ uirc_assembler_message(char* buf, const IRC_Message* m, size_t len)
if ((ret = snprintf(buf, len, "\r\n")) >= 0) {
buf += (size_t) ret;
len -= (size_t) ret;
} else
} else {
uirc_errno = UIRC_ERR_BUFSIZ;
return -1;
}
assert(sv <= buf);
return (ssize_t)(buf - sv);

View File

@ -17,6 +17,7 @@
*/
#include "assemblers.h" // uirc_assembler_tag_*
#include "errors.h" // uirc_errno
#include "types.h" // IRC_Tag
#include <assert.h> // assert()
@ -38,24 +39,28 @@ uirc_assembler_tag(char* buf, const IRC_Tag* t, size_t len)
if (len > 1) {
*(buf++) = '+';
len--;
} else
} else {
uirc_errno = UIRC_ERR_BUFSIZ;
return -1;
}
}
if (len < 1) return -1;
if ((res = snprintf(buf, len, "%s", t->key)) >= 0) {
buf += (size_t) res;
len -= (size_t) res;
} else
} else {
uirc_errno = UIRC_ERR_BUFSIZ;
return -1;
}
if (t->value != NULL) {
if (len < 1) return -1;
if ((res = snprintf(buf, len, "=%s", t->value)) >= 0) {
buf += (size_t) res;
len -= (size_t) res;
} else
} else {
uirc_errno = UIRC_ERR_BUFSIZ;
return -1;
}
}
return buf - sv;
@ -73,16 +78,20 @@ uirc_assembler_tag_list(char* buf, const llist_t* tl, size_t len)
if (len > 1) {
*(buf++) = ';';
len--;
} else
} else {
uirc_errno = UIRC_ERR_BUFSIZ;
return -1;
}
}
ssize_t ret;
if ((ret = uirc_assembler_tag(buf, tl->content, len)) >= 0) {
buf += (size_t) ret;
len -= (size_t) ret;
} else
} else {
uirc_errno = UIRC_ERR_BUFSIZ;
return -1;
}
}
return buf - sv;
}

View File

@ -17,6 +17,7 @@
*/
#include "assemblers.h" // Assm_user()
#include "errors.h" // uirc_errno
#include "types.h" // IRC_User
#include <assert.h> // assert()
@ -33,31 +34,34 @@ uirc_assembler_user(char* buf, const IRC_User* u, size_t len)
char* const sv = buf;
if (u->nick != NULL) {
if (len < 1) return -1;
int res;
if ((res = snprintf(buf, len, "%s", u->nick)) >= 0) {
buf += (size_t) res;
len -= (size_t) res;
} else
} else {
uirc_errno = UIRC_ERR_BUFSIZ;
return -1;
}
}
if (u->user != NULL) {
if (len < 1) return -1;
int res;
if ((res = snprintf(buf, len, "!%s", u->user)) >= 0) {
buf += (size_t) res;
len -= (size_t) res;
} else
} else {
uirc_errno = UIRC_ERR_BUFSIZ;
return -1;
}
}
if (u->host != NULL) {
if (len < 1) return -1;
int res;
if ((res = snprintf(buf, len, (u->nick != NULL || u->user != NULL) ? "@%s" : "%s", u->host)) >= 0) {
buf += (size_t) res;
len -= (size_t) res;
} else
} else {
uirc_errno = UIRC_ERR_BUFSIZ;
return -1;
}
}
return buf - sv;

34
src/error/error.c Normal file
View File

@ -0,0 +1,34 @@
/*
* This file is part of uIRC. (https://git.redxen.eu/caskd/uIRC)
* Copyright (c) 2019-2021 Alex-David Denes
*
* uIRC is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* uIRC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with uIRC. If not, see <https://www.gnu.org/licenses/>.
*/
#include "errors.h"
uirc_errno_t uirc_errno = UIRC_ERR_NERROR;
static const char* const uirc_errno_str[] = {
[UIRC_ERR_NERROR] = "No error",
[UIRC_ERR_SYSERR] = "System error",
[UIRC_ERR_BUFSIZ] = "Buffer space full",
[UIRC_ERR_INVFMT] = "Invalid format",
};
const char*
uirc_strerror(uirc_errno_t errno)
{
return uirc_errno_str[errno];
}

View File

@ -42,7 +42,7 @@ uirc_list_free(llist_t* list, IRC_Struct_Type type)
for (; list != NULL; cnt++) {
llist_t* const save = list;
list = list->next;
uirc_struct_free(save->content, type);
if (save->content != NULL) uirc_struct_free(save->content, type);
llist_elem_rm(save);
}
return cnt;

View File

@ -16,6 +16,7 @@
* along with uIRC. If not, see <https://www.gnu.org/licenses/>.
*/
#include "errors.h" // uirc_errno
#include "memory.h"
#include "types.h" // IRC_*
@ -96,40 +97,61 @@ IRC_Tag*
uirc_struct_assm_tag(bool clientbound, const char* key, const char* value)
{
assert(key != NULL);
IRC_Tag* t = malloc(sizeof(*t));
IRC_Tag* t = NULL;
if ((t = malloc(sizeof(*t))) == NULL) {
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
memset(t, 0, sizeof(*t));
t->clientbound = clientbound;
if ((t->key = stringext_strmalloc(key, strlen(key))) == NULL
|| (value != NULL && (t->value = stringext_strmalloc(value, strlen(value))) == NULL)) {
uirc_struct_free(t, IRC_STRUCT_TAG);
free(t);
return NULL;
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
return t;
cleanup:
if (t != NULL) uirc_struct_free(t, IRC_STRUCT_TAG);
free(t);
return NULL;
}
IRC_Capability*
uirc_struct_assm_capability(bool active, const char* name)
{
assert(name != NULL);
IRC_Capability* c = malloc(sizeof(*c));
IRC_Capability* c = NULL;
if ((c = malloc(sizeof(*c))) == NULL) {
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
memset(c, 0, sizeof(*c));
c->active = active;
if ((c->name = stringext_strmalloc(name, strlen(name))) == NULL) {
uirc_struct_free(c, IRC_STRUCT_CAPABILITY);
free(c);
return NULL;
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
return c;
cleanup:
if (c != NULL) uirc_struct_free(c, IRC_STRUCT_CAPABILITY);
free(c);
return NULL;
}
#endif /* UIRC_FEATURE_IRCV3 */
IRC_User*
uirc_struct_assm_user(bool service, IRC_Modes modes, const char* nick, const char* user, const char* real, const char* host)
{
IRC_User* u = malloc(sizeof(*u));
IRC_User* u = NULL;
if ((u = malloc(sizeof(*u))) == NULL) {
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
memset(u, 0, sizeof(*u));
u->is_service = service;
@ -138,45 +160,60 @@ uirc_struct_assm_user(bool service, IRC_Modes modes, const char* nick, const cha
|| (user != NULL && (u->user = stringext_strmalloc(user, strlen(user))) == NULL)
|| (real != NULL && (u->real = stringext_strmalloc(real, strlen(real))) == NULL)
|| (host != NULL && (u->host = stringext_strmalloc(host, strlen(host))) == NULL)) {
uirc_struct_free(u, IRC_STRUCT_USER);
free(u);
return NULL;
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
return u;
cleanup:
if (u != NULL) uirc_struct_free(u, IRC_STRUCT_USER);
free(u);
return NULL;
}
IRC_Message*
uirc_struct_assm_message(const char* cmd, bool trailing, unsigned int argc, ...)
{
assert(cmd != NULL);
IRC_Message* m = malloc(sizeof(*m));
IRC_Message* m = NULL;
if ((m = malloc(sizeof(*m))) == NULL) {
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
memset(m, 0, sizeof(*m));
m->trailing = trailing;
if (cmd != NULL && (m->command = stringext_strmalloc(cmd, strlen(cmd))) == NULL) {
uirc_struct_free(m, IRC_STRUCT_MESSAGE);
free(m);
return NULL;
if ((m->command = stringext_strmalloc(cmd, strlen(cmd))) == NULL) {
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
va_list ap;
va_start(ap, argc);
for (unsigned short i = 0; i < IRC_MAXARGS && i < argc; i++) {
const char* carg = va_arg(ap, const char*);
if ((m->args[i] = stringext_strmalloc(carg, strlen(carg))) == NULL) {
uirc_struct_free(m, IRC_STRUCT_MESSAGE);
free(m);
return NULL;
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
}
va_end(ap);
return m;
cleanup:
if (m != NULL) uirc_struct_free(m, IRC_STRUCT_MESSAGE);
free(m);
return NULL;
}
IRC_Buffer*
uirc_struct_assm_buffer(IRC_Buffer_Type type, IRC_Modes modes, bool subscribed, const char* name, const char* key, const char* topic)
{
assert(name != NULL);
IRC_Buffer* b = malloc(sizeof(*b));
IRC_Buffer* b = NULL;
if ((b = malloc(sizeof(*b))) == NULL) {
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
memset(b, 0, sizeof(*b));
b->subscribed = subscribed;
@ -184,25 +221,36 @@ uirc_struct_assm_buffer(IRC_Buffer_Type type, IRC_Modes modes, bool subscribed,
b->type = type;
if ((b->name = stringext_strmalloc(name, strlen(name))) == NULL || (key != NULL && (b->name = stringext_strmalloc(key, strlen(key))) == NULL)
|| (topic != NULL && (b->topic = stringext_strmalloc(topic, strlen(topic))) == NULL)) {
uirc_struct_free(b, IRC_STRUCT_BUFFER);
free(b);
return NULL;
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
return b;
cleanup:
if (b != NULL) uirc_struct_free(b, IRC_STRUCT_BUFFER);
free(b);
return NULL;
}
IRC_Network*
uirc_struct_assm_network(const char* addr, const char* svc, const char* pass)
{
IRC_Network* n = malloc(sizeof(*n));
IRC_Network* n = NULL;
if ((n = malloc(sizeof(*n))) == NULL) {
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
memset(n, 0, sizeof(*n));
if ((addr != NULL && (n->addr = stringext_strmalloc(addr, strlen(addr))) == NULL)
|| (svc != NULL && (n->svc = stringext_strmalloc(svc, strlen(svc))) == NULL)
|| (pass != NULL && (n->pass = stringext_strmalloc(pass, strlen(pass))) == NULL)) {
uirc_struct_free(n, IRC_STRUCT_NETWORK);
free(n);
return NULL;
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
return n;
cleanup:
uirc_struct_free(n, IRC_STRUCT_NETWORK);
free(n);
return NULL;
}

View File

@ -16,6 +16,7 @@
* along with uIRC. If not, see <https://www.gnu.org/licenses/>.
*/
#include "errors.h" // uirc_errno
#include "memory.h" // uirc_memory_*()
#include "tokenizers.h" // uirc_tokenizer_*()
#include "types.h" // IRC_Message
@ -27,7 +28,6 @@
#include <stdlib.h> // malloc()
#include <string.h> // strlen()
static void free_ctx(IRC_Message* msg, char* str);
static void skip_spaces(char** addr);
IRC_Message*
@ -35,7 +35,14 @@ uirc_tokenizer_message(const char* str)
{
assert(str != NULL);
IRC_Message* const m = malloc(sizeof(IRC_Message));
IRC_Message* m = NULL;
char* ws = NULL;
if ((m = malloc(sizeof(*m))) == NULL) {
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
memset(m, 0, sizeof(*m));
size_t len = strlen(str);
// Ignore CRLF at the end, irrelevant for parsing
@ -43,28 +50,22 @@ uirc_tokenizer_message(const char* str)
len--;
if (str[len - 1] == '\r') len--;
}
char* const ws = stringext_strmalloc(str, len); // NOTE: Some compilers might warn you about modifying contents of p because it points to ws which
// is "immutable". This is safe to ignore as the purpose of it is to not use ws for tokenizing and
// to save the original pointer which can be freed
char* p = ws;
if (ws == NULL || m == NULL) {
free(ws);
free(m);
return NULL;
if ((ws = stringext_strmalloc(str, len)) == NULL) {
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
memset(m, 0, sizeof(IRC_Message));
char* p = ws;
#ifdef UIRC_FEATURE_IRCV3
if (*p == '@') {
p++;
const char* tmp = NULL;
if ((tmp = stringext_strtok_mr(&p, " ")) == NULL || (m->tag_list = uirc_tokenizer_tag_list(tmp)) == NULL) {
free_ctx(m, ws);
return NULL;
if ((tmp = stringext_strtok_mr(&p, " ")) == NULL) {
uirc_errno = UIRC_ERR_INVFMT;
goto cleanup;
}
if ((m->tag_list = uirc_tokenizer_tag_list(tmp)) == NULL) goto cleanup;
}
skip_spaces(&p);
#endif /* UIRC_FEATURE_IRCV3 */
@ -72,22 +73,27 @@ uirc_tokenizer_message(const char* str)
if (*p == ':') {
const char* tmp = NULL;
p++;
if ((tmp = stringext_strtok_mr(&p, " ")) == NULL || (m->source = uirc_tokenizer_user(tmp)) == NULL) {
free_ctx(m, ws);
return NULL;
if ((tmp = stringext_strtok_mr(&p, " ")) == NULL) {
uirc_errno = UIRC_ERR_INVFMT;
goto cleanup;
}
if ((m->source = uirc_tokenizer_user(tmp)) == NULL) goto cleanup;
skip_spaces(&p);
}
if (isalnum(*p)) {
const char* tmp = NULL;
if ((tmp = stringext_strtok_mr(&p, " ")) == NULL || (m->command = stringext_strmalloc(tmp, strlen(tmp))) == NULL) {
free_ctx(m, ws);
return NULL;
if ((tmp = stringext_strtok_mr(&p, " ")) == NULL) {
uirc_errno = UIRC_ERR_INVFMT;
goto cleanup;
}
if ((m->command = stringext_strmalloc(tmp, strlen(tmp))) == NULL) {
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
} else {
free_ctx(m, ws);
return NULL;
uirc_errno = UIRC_ERR_INVFMT;
goto cleanup;
}
skip_spaces(&p);
@ -96,35 +102,36 @@ uirc_tokenizer_message(const char* str)
if (i == IRC_MAXARGS - 1 || *p == ':') {
if (*p == ':') {
p++;
// trailing is supposed to represent a early ending of spaced arguments, not if there's any arguments at all
// trailing is supposed to represent a early ending of spaced arguments, not if there's any trailing arguments at all
m->trailing = true;
}
if ((m->args[i++] = stringext_strmalloc(p, strlen(p))) == NULL) {
free_ctx(m, ws);
return NULL;
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
break;
} else {
const char* tmp = NULL;
if ((tmp = stringext_strtok_mr(&p, " ")) == NULL || (m->args[i++] = stringext_strmalloc(tmp, strlen(tmp))) == NULL) {
free_ctx(m, ws);
return NULL;
if ((tmp = stringext_strtok_mr(&p, " ")) == NULL) {
uirc_errno = UIRC_ERR_INVFMT;
goto cleanup;
}
if ((m->args[i++] = stringext_strmalloc(tmp, strlen(tmp))) == NULL) {
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
skip_spaces(&p);
}
m->args[i] = NULL;
if (i < IRC_MAXARGS) m->args[i] = NULL;
}
free(ws);
return m;
}
static void
free_ctx(IRC_Message* msg, char* str)
{
uirc_struct_free(msg, IRC_STRUCT_MESSAGE);
free(msg);
free(str);
cleanup:
if (m != NULL) uirc_struct_free(m, IRC_STRUCT_MESSAGE);
free(m);
free(ws);
return NULL;
}
static void

View File

@ -16,6 +16,7 @@
* along with uIRC. If not, see <https://www.gnu.org/licenses/>.
*/
#include "errors.h" // uirc_errno
#include "memory.h" // Free_IRC_Tag()
#include "tokenizers.h" // uirc_tokenizer_tags()
#include "types.h" // IRC_Tag
@ -27,28 +28,28 @@
#include <stdlib.h> // free()
#include <string.h> // strchr()
static void free_ctx(llist_t* list, IRC_Tag* t, char* s);
llist_t*
uirc_tokenizer_tag_list(const char* str)
{
assert(str != NULL);
char* const ws = stringext_strmalloc(str, strlen(str));
char * p = ws, *tmp;
llist_t * pl = NULL, *l = NULL;
if (ws == NULL) return NULL;
llist_t* l = NULL;
char* ws = NULL;
if ((ws = stringext_strmalloc(str, strlen(str))) == NULL) {
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
char * p = ws, *tmp;
llist_t* pl = NULL;
while ((tmp = stringext_strtok_mr(&p, ";")) != NULL) {
llist_t* cl;
if ((cl = llist_elem_alloc(0)) == NULL) {
free_ctx(l, NULL, ws);
return NULL;
}
if ((cl->content = uirc_tokenizer_tag(tmp)) == NULL) {
free_ctx(l, NULL, ws);
return NULL;
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
if ((cl->content = uirc_tokenizer_tag(tmp)) == NULL) goto cleanup;
if (l == NULL) l = cl;
else
@ -58,6 +59,9 @@ uirc_tokenizer_tag_list(const char* str)
free(ws);
return l;
cleanup:
if (l != NULL) uirc_list_free(l, IRC_STRUCT_TAG);
return NULL;
}
IRC_Tag*
@ -65,18 +69,21 @@ uirc_tokenizer_tag(const char* str)
{
assert(str != NULL);
char* const ws = stringext_strmalloc(str, strlen(str));
IRC_Tag* t = malloc(sizeof(IRC_Tag));
char* ckey = ws;
char* ws = NULL;
IRC_Tag* t = NULL;
if (t == NULL || ws == NULL) {
free(t);
free(ws);
return NULL;
if ((ws = stringext_strmalloc(str, strlen(str))) == NULL) {
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
memset(t, 0, sizeof(IRC_Tag));
if ((t = malloc(sizeof(*t))) == NULL) {
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
memset(t, 0, sizeof(*t));
char* ckey = ws;
if (*ws == '+') {
ckey++;
t->clientbound = true;
@ -85,30 +92,20 @@ uirc_tokenizer_tag(const char* str)
if (cval != NULL) {
*(cval++) = '\0';
if ((t->value = stringext_strmalloc(cval, strlen(cval))) == NULL) {
free_ctx(NULL, t, ws);
return NULL;
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
}
if ((t->key = stringext_strmalloc(ckey, strlen(ckey))) == NULL) {
free_ctx(NULL, t, ws);
return NULL;
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
free(ws);
return t;
}
static void
free_ctx(llist_t* list, IRC_Tag* t, char* s)
{
for (llist_t* c = list; c != NULL;) {
llist_t* l = c;
c = c->next;
if (l->content != NULL) uirc_struct_free(l->content, IRC_STRUCT_TAG);
llist_elem_rm(l);
}
uirc_struct_free(t, IRC_STRUCT_TAG);
cleanup:
if (t != NULL) uirc_struct_free(t, IRC_STRUCT_TAG);
free(t);
free(s);
free(ws);
return NULL;
}

View File

@ -16,6 +16,7 @@
* along with uIRC. If not, see <https://www.gnu.org/licenses/>.
*/
#include "errors.h" // uirc_errno
#include "memory.h" // uirc_memory_*()
#include "tokenizers.h" // uirc_tokenizer_*()
#include "types.h" // IRC_Message
@ -26,52 +27,50 @@
#include <stdlib.h> // malloc()
#include <string.h> // strchr()
static void free_ctx(IRC_User* u, char* s);
IRC_User*
uirc_tokenizer_user(const char* str)
{
assert(str != NULL);
IRC_User* u = malloc(sizeof(IRC_User));
char* const ws = stringext_strmalloc(str, strlen(str));
char* tmp;
IRC_User* u = NULL;
char* ws = NULL;
if (u == NULL || ws == NULL) {
free(u);
free(ws);
return NULL;
if ((u = malloc(sizeof(*u))) == NULL) {
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
memset(u, 0, sizeof(*u));
if ((ws = stringext_strmalloc(str, strlen(str))) == NULL) {
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
memset(u, 0, sizeof(IRC_User));
char* tmp;
if ((tmp = strchr(ws, '@')) != NULL) {
*(tmp++) = '\0';
if ((u->host = stringext_strmalloc(tmp, strlen(tmp))) == NULL) {
free_ctx(u, ws);
return NULL;
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
}
if ((tmp = strchr(ws, '!')) != NULL) {
*(tmp++) = '\0';
if ((u->user = stringext_strmalloc(tmp, strlen(tmp))) == NULL) {
free_ctx(u, ws);
return NULL;
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
}
if ((u->nick = stringext_strmalloc(ws, strlen(ws))) == NULL) {
free_ctx(u, ws);
return NULL;
uirc_errno = UIRC_ERR_SYSERR;
goto cleanup;
}
free(ws);
return u;
}
static void
free_ctx(IRC_User* u, char* s)
{
uirc_struct_free(u, IRC_STRUCT_USER);
cleanup:
if (u != NULL) uirc_struct_free(u, IRC_STRUCT_USER);
free(u);
free(s);
free(ws);
return NULL;
}