-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathirc_parser.h
193 lines (173 loc) · 6.69 KB
/
irc_parser.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#ifndef irc_parser_h
#define irc_parser_h
#define IRC_PARSER_RAW_BUFFER_SIZE 512
/**
*
*/
#define IRC_PARSER_SETTINGS_BASE_CLASS \
void *data; \
irc_parser_cb on_nick; \
irc_parser_cb on_name; \
irc_parser_cb on_host; \
irc_parser_cb on_command; \
irc_parser_cb on_param; \
irc_parser_cb on_end; \
irc_parser_cb on_error
/**
* This is just the convenience typedef for the parser struct
*/
typedef struct irc_parser_s irc_parser;
/**
* The convenience typedef for the parser settings struct
*/
typedef struct irc_parser_settings_s irc_parser_settings;
/**
* This is the typedef for the callback type that will be called on
* state transitions. At the moment there is only one callback type
* for each transition event but this may change in the future in
* the direction of having more specialized callbacks for each event.
* at the moment i like the simplicity of having a uniform callback
* type though. So we'll see what happens as RethinkIRCd develops
*/
typedef int (*irc_parser_cb)(irc_parser*, const char *at, size_t len);
/**
* These are the different parsing states that the parser can be in.
* We represent them as a zero-indexed enum that will be stored in
* the parser context so we can have a reentrant state machine.
*/
enum irc_parser_state {
IRC_STATE_INIT = 0,
IRC_STATE_NICK,
IRC_STATE_NAME,
IRC_STATE_HOST,
IRC_STATE_COMMAND,
IRC_STATE_PARAMS,
IRC_STATE_TRAILING,
IRC_STATE_END,
IRC_STATE_ERROR
};
/**
* This is the enum type we use within the irc_parser lib to identify
* different parse and user errors that can be generated by the lib.
* The string mappings for these errors can be found in `irc_parser.c`
*/
enum irc_parser_error {
IRC_ERROR_NONE = 0,
IRC_ERROR_PARSE,
IRC_ERROR_UNDEF_STATE,
IRC_ERROR_LENGTH,
IRC_ERROR_USER
};
/**
* This is the struct that makes reentrancy into our parser clean and
* possible. It doesn't matter how you allocate the parser as long as
* you pass it through it's constructor `irc_parser_init()` before
* using it. `irc_parser_init()` takes a pointer to the parser to
* initialize as it's first argument and then takes a pointer to an
* `irc_parser_settings` struct as it's second argument. The settings
* struct should be initialized using it's constructor and should
* contain all the callbacks for the events the user wishes to
* listen to.
*/
struct irc_parser_s {
IRC_PARSER_SETTINGS_BASE_CLASS;
int len;
int last;
enum irc_parser_state state;
enum irc_parser_error error;
char raw[IRC_PARSER_RAW_BUFFER_SIZE+1];
};
/**
* This is the base class for the `irc_parser` struct. It is used as
* reusable container that holds all of the callbacks to be used by
* `irc_parser`'s. This is both an optimization and simplification
* abstraction. Instead of having to manually add each callback to
* every parser context you're going to need, you just assign the
* callbacks once to an instance of `irc_parser_settings` and assign
* the settings instance to each callback. You must initialize this
* struct via `irc_parser_settings_init()` before using it.
*/
struct irc_parser_settings_s {
IRC_PARSER_SETTINGS_BASE_CLASS;
};
/**
* This function is the constructor for the `irc_parser` struct. It
* should be called on all newly allocated `irc_parser`s once before
* they are used.
*
* @param irc_parser *parser - The parser to initialize
* @returns void
*/
void irc_parser_init(irc_parser *parser, irc_parser_settings *settings);
/**
* This function is used to reset the internal state of a parser
* without reseting the assigned callbacks. It's useful for recovering
* parsers from error states once user clean up has been done.
*
* @param irc_parser *parser - The parser to reset
* @returns void
*/
void irc_parser_reset(irc_parser *parser);
/**
* This is the main parsing function. You supply it with a parser
* context, some data to parse and the length of that data and it
* will parse it firing off assigned callbacks as it transitions
* between states. It returns a `size_t` and when the returned value
* is not identical to the `len` parameter this is indicative of an
* error. To check for the type of error and the error string see
* `irc_parser_get_error()` and `irc_parser_error_string()` respectively
*
* @param irc_parser *parser - The parser context to apply `data` to
* @param const char *data - The data to parse
* @param size_t - The length of `data`
* @returns size_t - The number of bytes parsed on success
*/
size_t irc_parser_execute(irc_parser *parser, const char *data, size_t len);
/**
* This function takes a parser and returns non zero if the
* parser is currently in an error state.
*
* @param irc_parser *parser - The parser to check for errors
* @returns void
*/
int irc_parser_has_error(irc_parser *parser);
const char* irc_parser_error_to_string(enum irc_parser_error error);
/**
* This function returns the enumerated value for the current
* error state of the supplied parser.
*
* @param irc_parser *parser - The parser to pull the error code from
* @returns enum irc_parser_errors - The enumerated error code
*/
enum irc_parser_error irc_parser_get_error(irc_parser *parser);
/**
* The function returns the error string associated to the current
* error in the supplied parser. If no error is present it returns
* `NULL` instead.
*
* @param irc_parser *parser - The parser to get the error string from
* @returns const char* - The associated error string.
*/
const char* irc_parser_error_string(irc_parser *parser);
/**
* This is the constructor for the `irc_parser_settings` struct. It
* should be called on each `irc_parser_settings` struct before use.
*
* @param irc_parser_settings *settings - The settings struct to init
* @param irc_parser_cb on_nick - The nick callback or NULL
* @param irc_parser_cb on_name - The name callback or NULL
* @param irc_parser_cb on_host - The host callback or NULL
* @param irc_parser_cb on_command - The command callback or NULL
* @param irc_parser_cb on_param - The param callback or NULL
* @param irc_parser_cb on_end - The end callback or NULL
* @param irc_parser_cb on_error - The error callback or NULL
*/
void irc_parser_settings_init(irc_parser_settings *settings,
irc_parser_cb on_nick,
irc_parser_cb on_name,
irc_parser_cb on_host,
irc_parser_cb on_command,
irc_parser_cb on_param,
irc_parser_cb on_end,
irc_parser_cb on_error);
#endif