summaryrefslogtreecommitdiff
path: root/ext/ircg/php_ircg_tokenizer.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/ircg/php_ircg_tokenizer.c')
-rw-r--r--ext/ircg/php_ircg_tokenizer.c228
1 files changed, 228 insertions, 0 deletions
diff --git a/ext/ircg/php_ircg_tokenizer.c b/ext/ircg/php_ircg_tokenizer.c
new file mode 100644
index 000000000..a226e2d49
--- /dev/null
+++ b/ext/ircg/php_ircg_tokenizer.c
@@ -0,0 +1,228 @@
+#define SMART_STR_PREALLOC 4
+
+#include "php_ircg_private.h"
+#include "php_ircg_alloc.h"
+#include "php_ircg_conversion.h"
+#include "php_ircg_smart_str.h"
+
+/* {{{ token_compiler */
+
+#include "php_ircg_tokenizer.h"
+
+#include "php_ircg_alloc.h"
+
+#define NEW_TOKEN(a, b) \
+ if (n + 1 >= alloced) { \
+ alloced += 10; \
+ f = IRCG_SHARED_REALLOC(f, sizeof *f + alloced * sizeof(token_t)); \
+ *fp = f; \
+ } \
+ f->t[n].code=a; \
+ f->t[n++].para.b
+
+
+#define HANDLE_VERBATIM_STRING() \
+ if (len <= INLINE_STRING_LEN) { \
+ struct inline_string is; \
+ \
+ is.buf_len = len; \
+ memcpy(is.buf, p, len); \
+ NEW_TOKEN(C_STRING_INLINE, is) = is; \
+ } else { \
+ s.c = 0; \
+ smart_str_appendl_ex(&s, p, len, 1); \
+ NEW_TOKEN(C_STRING, s) = s; \
+ }
+
+
+
+void php_ircg_token_compiler(const char *fmt, size_t fmtlen, format_msg_t **fp)
+{
+ const char *p, *pe;
+ const char *q;
+ int n = 0;
+ int alloced = 0;
+ char mode;
+ unsigned long len;
+ char c;
+ smart_str s;
+ format_msg_t *f = *fp;
+
+ php_ircg->exec_token_compiler++;
+
+ if (fmt[0] == '\0') {
+ *fp = NULL;
+ return;
+ }
+
+ p = fmt;
+ pe = fmt + fmtlen;
+
+ do {
+ q = p;
+ while (*q != '%')
+ if (++q >= pe) {
+ len = pe - p;
+ HANDLE_VERBATIM_STRING();
+ goto leave_loop;
+ }
+ len = q - p;
+
+ if (len > 0) {
+ HANDLE_VERBATIM_STRING();
+ }
+ mode = 0;
+
+next:
+ c = *++q; /* skip '%' and look at next char */
+ switch (c) {
+ case '1': mode |= P_JS; goto next;
+ case '2': mode |= P_NICKNAME; goto next;
+ case '3': mode |= P_NOAUTO_LINKS; goto next;
+ case '4': mode |= P_CONV_BR; goto next;
+ case '5': mode |= P_COND_STOP; goto next;
+ case '6': mode |= P_HTML; goto next;
+
+ /* associate mode bits with each command where applicable */
+ case 'c': NEW_TOKEN(C_CHANNEL, v) = mode; break;
+ case 'd': NEW_TOKEN(C_TERMINATE_1, v) = mode; break;
+ case 't': NEW_TOKEN(C_TO, v) = mode; break;
+ case 'f': NEW_TOKEN(C_FROM, v) = mode; break;
+ case 'r': NEW_TOKEN(C_MESSAGE, v) = mode; break;
+ case 'm': NEW_TOKEN(C_MESSAGE, v) = mode | P_HTML; break;
+ case 'j': NEW_TOKEN(C_MESSAGE, v) = mode | P_HTML | P_JS; break;
+
+ case '%': NEW_TOKEN(C_PERCENT, v) = 0; break;
+
+ default: /* ignore invalid combinations */
+ break;
+ }
+ p = q + 1; /* skip last format character */
+ } while (p < pe);
+
+leave_loop:
+
+ f->ntoken = n;
+}
+/* }}} */
+
+/* {{{ format_msg */
+void php_ircg_format_msg(const format_msg_t *fmt_msg, smart_str *channel,
+ smart_str *to, smart_str *from, smart_str *msg, smart_str *result,
+ const char *username, int username_len, int *status)
+{
+ int i = 0;
+ const token_t *t;
+ int ntoken;
+ smart_str tmp = {0};
+
+ if (!fmt_msg) return;
+
+ ntoken = fmt_msg->ntoken;
+ t = fmt_msg->t;
+
+#define IRCG_APPEND(what, use_cache) \
+ if (t[i].para.v & P_COND_STOP) { \
+ if (username_len != what->len || memcmp(what->c, username, username_len) != 0) \
+ goto stop; \
+ continue; \
+ } \
+ switch (t[i].para.v & 7) { \
+ case P_JS: \
+ if (!what) break; \
+ php_ircg_js_escape(what, result); \
+ break; \
+ case P_NICKNAME_JS: { \
+ smart_str tmp = {0}; \
+ if (!what) break; \
+ php_ircg_nickname_unescape(what, &tmp); \
+ php_ircg_js_escape(&tmp, result); \
+ smart_str_free_ex(&tmp, 1); \
+ break; \
+ } \
+ case P_NICKNAME: \
+ if (!what) break; \
+ php_ircg_nickname_unescape(what, result); \
+ break; \
+ case P_RAW: \
+ if (!what) break; \
+ smart_str_append_ex(result, what, 1); \
+ break; \
+ case P_HTML_JS: \
+ if (!what) break; \
+ if (use_cache) { \
+ ircg_mirc_color_cache(msg, \
+ &tmp, channel, \
+ !(t[i].para.v & P_NOAUTO_LINKS), \
+ t[i].para.v & P_CONV_BR); \
+ } else { \
+ ircg_mirc_color(what->c, &tmp, \
+ what->len, \
+ !(t[i].para.v & P_NOAUTO_LINKS), \
+ t[i].para.v & P_CONV_BR); \
+ } \
+ php_ircg_js_escape(&tmp, result); \
+ smart_str_free(&tmp); \
+ break; \
+ case P_HTML: \
+ if (!what) break; \
+ if (use_cache) { \
+ ircg_mirc_color_cache(msg, \
+ result, channel, \
+ !(t[i].para.v & P_NOAUTO_LINKS), \
+ t[i].para.v & P_CONV_BR); \
+ } else { \
+ ircg_mirc_color(what->c, result, \
+ what->len, \
+ !(t[i].para.v & P_NOAUTO_LINKS), \
+ t[i].para.v & P_CONV_BR); \
+ } \
+ break; \
+ }
+
+ for (; ntoken-- > 0; i++) {
+ switch (t[i].code) {
+ case C_STRING_INLINE: smart_str_appendl_ex(result, t[i].para.is.buf,
+ t[i].para.is.buf_len, 1); break;
+ case C_STRING: smart_str_append_ex(result, &t[i].para.s, 1); break;
+ case C_FROM: IRCG_APPEND(from, 0); break;
+ case C_TO: IRCG_APPEND(to, 0); break;
+ case C_CHANNEL: IRCG_APPEND(channel, 0); break;
+ case C_MESSAGE: IRCG_APPEND(msg, 1); break;
+ case C_PERCENT: smart_str_appendc_ex(result, '%', 1); break;
+ case C_TERMINATE_1: /* auth by username */
+ if (ntoken > 0 && t[i+1].code == C_STRING) {
+ if (t[i+1].para.s.len == from->len
+ && strncasecmp(t[i+1].para.s.c, from->c, from->len) == 0)
+ *status = 1;
+ } else
+ *status = 1;
+ }
+ }
+
+stop:
+
+ if (result->c)
+ smart_str_0(result);
+ php_ircg->exec_fmt_msgs++;
+}
+
+
+void php_ircg_free_fmt_msg(format_msg_t *f)
+{
+ int i = 0;
+
+ while (f->ntoken-- > 0) {
+ switch (f->t[i].code) {
+ case C_STRING:
+ smart_str_free_ex(&f->t[i].para.s, 1);
+ break;
+ }
+ i++;
+ }
+ IRCG_SHARED_FREE(f);
+}
+
+/* }}} */
+
+