terom@17: #include "irc_line.h" terom@75: #include "log.h" terom@17: terom@17: #include terom@17: #include terom@17: terom@75: err_t irc_line_parse (struct irc_line *line, struct irc_nm *nm, char *data) terom@17: { terom@17: int i; terom@75: err_t err; terom@17: terom@17: // prefix? terom@17: if (data && *data == ':') { terom@17: // consume as token terom@75: char *prefix = strsep(&data, " ") + 1; terom@75: terom@75: // parse as a nickmask terom@75: if ((err = irc_nm_parse_buf(nm, prefix))) { terom@75: line->source = NULL; terom@75: log_warn("invalid prefix: '%s': %s", prefix, error_name(err)); terom@75: terom@75: } else { terom@75: // valid, store terom@75: line->source = nm; terom@75: } terom@17: } terom@17: terom@17: // command terom@17: line->command = strsep(&data, " "); terom@17: terom@17: // args terom@17: for (i = 0; i < IRC_ARG_MAX; i++) { terom@17: // trailing? terom@17: if (data && *data == ':') { terom@17: // consume the rest of the line terom@17: line->args[i] = data + 1; terom@17: data = NULL; terom@17: terom@17: } else { terom@17: // either NULL or a normal token terom@17: line->args[i] = strsep(&data, " "); terom@17: } terom@17: } terom@17: terom@17: // parse errors? What are those? terom@17: return SUCCESS; terom@17: } terom@17: terom@17: /* terom@123: * Flags for output_token terom@17: */ terom@123: enum output_token_flag { terom@17: /* No space before token */ terom@17: TOK_NOSPACE = 0x01, terom@17: terom@17: /* Prefix with :, may contain spaces, last token */ terom@17: TOK_TRAILING = 0x02, terom@17: }; terom@17: terom@17: static err_t output_token (char *buf, size_t *offset, const char *token, int flags) terom@17: { terom@17: size_t token_len = strlen(token), len; terom@17: char *dest = buf + *offset; terom@17: terom@17: // overall length terom@17: len = token_len + (flags & TOK_NOSPACE ? 0 : 1) + (flags & TOK_TRAILING ? 1 : 0); terom@17: terom@17: // check overflow terom@23: if (*offset + len + 1 > IRC_LINE_MAX) terom@17: return ERR_LINE_TOO_LONG; terom@17: terom@17: // check invalid tokens terom@17: if (strpbrk(token, (flags & TOK_TRAILING) ? IRC_TOKEN_TRAILING_INVALID : IRC_TOKEN_INVALID)) terom@17: return ERR_LINE_INVALID_TOKEN; terom@17: terom@17: // delimit with space? terom@17: if (!(flags & TOK_NOSPACE)) terom@17: *dest++ = ' '; terom@17: terom@17: // prefix trailing? terom@17: if (flags & TOK_TRAILING) terom@17: *dest++= ':'; terom@17: terom@17: // copy to buffer terom@17: memcpy(dest, token, token_len); terom@17: terom@17: // update offset terom@17: *offset += len; terom@17: terom@17: // ok terom@17: return 0; terom@17: } terom@17: terom@17: err_t irc_line_build (const struct irc_line *line, char *buf) terom@17: { terom@17: size_t off = 0; terom@17: int i; terom@17: err_t err; terom@17: terom@17: // XXX: no need for prefix on client terom@75: assert(line->source == NULL); terom@17: terom@17: // command terom@17: if ((err = output_token(buf, &off, line->command, TOK_NOSPACE))) terom@17: return err; terom@17: terom@17: // args terom@17: for (i = 0; i < IRC_ARG_MAX; i++) { terom@17: // skip unused args at end terom@17: if (line->args[i] == NULL) terom@17: break; terom@17: terom@17: // if last and contains a space, format as a trailing param terom@17: if ((i < IRC_ARG_MAX - 1) && line->args[i + 1] == NULL && strchr(line->args[i], ' ')) { terom@17: // output using TOK_TRAILING terom@17: if ((err = output_token(buf, &off, line->args[i], TOK_TRAILING))) terom@17: return err; terom@17: terom@17: } else { terom@17: // output as normal token terom@17: if ((err = output_token(buf, &off, line->args[i], 0))) terom@17: return err; terom@17: } terom@17: } terom@17: terom@23: // terminate, output_token reserved the space for this terom@23: buf[off] = '\0'; terom@23: terom@17: // done terom@17: return SUCCESS; terom@17: } terom@17: