src/irc_line.c
changeset 17 5001564ac5fc
child 23 542c73d07d3c
equal deleted inserted replaced
16:20ce0029e4a0 17:5001564ac5fc
       
     1 
       
     2 #include "irc_line.h"
       
     3 
       
     4 #include <string.h>
       
     5 #include <assert.h>
       
     6 
       
     7 err_t irc_line_parse (struct irc_line *line, char *data)
       
     8 {
       
     9     int i;
       
    10 
       
    11     // prefix?
       
    12     if (data && *data == ':') {
       
    13         // consume as token
       
    14         line->prefix = strsep(&data, " ") + 1;
       
    15     }
       
    16 
       
    17     // command
       
    18     line->command = strsep(&data, " ");
       
    19 
       
    20     // args
       
    21     for (i = 0; i < IRC_ARG_MAX; i++) {
       
    22         // trailing?
       
    23         if (data && *data == ':') {
       
    24             // consume the rest of the line
       
    25             line->args[i] = data + 1;
       
    26             data = NULL;
       
    27 
       
    28         } else {
       
    29             // either NULL or a normal token
       
    30             line->args[i] = strsep(&data, " ");
       
    31         }
       
    32     }
       
    33 
       
    34     // parse errors? What are those?
       
    35     return SUCCESS;
       
    36 }
       
    37 
       
    38 /*
       
    39  * Tokens for output_token
       
    40  */
       
    41 enum {
       
    42     /* No space before token */
       
    43     TOK_NOSPACE     = 0x01,
       
    44 
       
    45     /* Prefix with :, may contain spaces, last token */
       
    46     TOK_TRAILING    = 0x02,
       
    47 };
       
    48 
       
    49 static err_t output_token (char *buf, size_t *offset, const char *token, int flags)
       
    50 {
       
    51     size_t token_len = strlen(token), len;
       
    52     char *dest = buf + *offset;
       
    53 
       
    54     // overall length
       
    55     len = token_len + (flags & TOK_NOSPACE ? 0 : 1) + (flags & TOK_TRAILING ? 1 : 0);
       
    56     
       
    57     // check overflow
       
    58     if (*offset + len > IRC_LINE_MAX)
       
    59         return ERR_LINE_TOO_LONG;
       
    60 
       
    61     // check invalid tokens
       
    62     if (strpbrk(token, (flags & TOK_TRAILING) ? IRC_TOKEN_TRAILING_INVALID : IRC_TOKEN_INVALID))
       
    63         return ERR_LINE_INVALID_TOKEN;
       
    64 
       
    65     // delimit with space?
       
    66     if (!(flags & TOK_NOSPACE))
       
    67         *dest++ = ' ';
       
    68 
       
    69     // prefix trailing?
       
    70     if (flags & TOK_TRAILING)
       
    71         *dest++= ':';
       
    72     
       
    73     // copy to buffer
       
    74     memcpy(dest, token, token_len);
       
    75 
       
    76     // update offset
       
    77     *offset += len;
       
    78 
       
    79     // ok
       
    80     return 0;
       
    81 }
       
    82 
       
    83 err_t irc_line_build (const struct irc_line *line, char *buf)
       
    84 {
       
    85     size_t off = 0;
       
    86     int i;
       
    87     err_t err;
       
    88 
       
    89     // XXX: no need for prefix on client
       
    90     assert(line->prefix == NULL);
       
    91     
       
    92     // command
       
    93     if ((err = output_token(buf, &off, line->command, TOK_NOSPACE)))
       
    94         return err;
       
    95 
       
    96     // args
       
    97     for (i = 0; i < IRC_ARG_MAX; i++) {
       
    98         // skip unused args at end
       
    99         if (line->args[i] == NULL)
       
   100             break;
       
   101 
       
   102         // if last and contains a space, format as a trailing param
       
   103         if ((i < IRC_ARG_MAX - 1) && line->args[i + 1] == NULL && strchr(line->args[i], ' ')) {
       
   104             // output using TOK_TRAILING
       
   105             if ((err = output_token(buf, &off, line->args[i], TOK_TRAILING)))
       
   106                 return err;
       
   107 
       
   108        } else {
       
   109             // output as normal token
       
   110             if ((err = output_token(buf, &off, line->args[i], 0)))
       
   111                 return err;
       
   112        }
       
   113     }
       
   114 
       
   115     // done
       
   116     return SUCCESS;
       
   117 }
       
   118