sas Tue Dec 3 05:13:36 2002 EDT Added files: /php4/ext/ircg php_ircg_cache.c php_ircg_cache.h php_ircg_conversion.c php_ircg_conversion.h php_ircg_error.c php_ircg_error.h php_ircg_private.h php_ircg_tokenizer.c php_ircg_tokenizer.h
Modified files: /php4/ext/ircg config.m4 ircg.c php_ircg.h php_ircg_alloc.h Log: Move subsystems into their own source file.
Index: php4/ext/ircg/config.m4 diff -u php4/ext/ircg/config.m4:1.16 php4/ext/ircg/config.m4:1.17 --- php4/ext/ircg/config.m4:1.16 Sat Nov 30 22:47:49 2002 +++ php4/ext/ircg/config.m4 Tue Dec 3 05:13:36 2002 @@ -1,5 +1,5 @@ dnl -dnl $Id: config.m4,v 1.16 2002/12/01 03:47:49 sas Exp $ +dnl $Id: config.m4,v 1.17 2002/12/03 10:13:36 sas Exp $ dnl PHP_ARG_WITH(ircg, for IRCG support, @@ -26,7 +26,9 @@ PHP_EVAL_INCLINE(`$IRCG_CONFIG --cppflags`) PHP_ADD_LIBRARY_WITH_PATH(ircg, $PHP_IRCG/lib) PHP_ADD_INCLUDE($PHP_IRCG/include) - PHP_NEW_EXTENSION(ircg, ircg.c ircg_scanner.c, $ext_shared) + PHP_NEW_EXTENSION(ircg,[ ircg.c ircg_scanner.c php_ircg_cache.c \ + php_ircg_conversion.c php_ircg_error.c php_ircg_tokenizer.c], + $ext_shared) if test "$PHP_SAPI" = "thttpd"; then PHP_ADD_SOURCES(PHP_EXT_DIR(ircg),ircg_thttpd.c,[],sapi) PHP_ADD_SOURCES(PHP_EXT_DIR(ircg),ircg_common.c,[],cli) Index: php4/ext/ircg/ircg.c diff -u php4/ext/ircg/ircg.c:1.149 php4/ext/ircg/ircg.c:1.150 --- php4/ext/ircg/ircg.c:1.149 Sun Dec 1 01:30:01 2002 +++ php4/ext/ircg/ircg.c Tue Dec 3 05:13:36 2002 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: ircg.c,v 1.149 2002/12/01 06:30:01 sas Exp $ */ +/* $Id: ircg.c,v 1.150 2002/12/03 10:13:36 sas Exp $ */ /* {{{ includes */ @@ -54,54 +54,23 @@ #include <arpa/inet.h> #endif -#include "if_irc.h" -#include "irc_write_buffer.h" - /* }}} */ /* {{{ Definitions */ -#if IRCG_API_VERSION < 20021127 -#define USE_IRCONN_MANAGEMENT -static HashTable h_irconn; /* Integer IDs to php_irconn_t * */ -static int irconn_id; - -#define USE_FD2IRCONN -static HashTable h_fd2irconn; /* fd's to Integer IDs */ - - -/* provide dummy definitions */ -#include "php_ircg_hash.h" -#include "php_ircg_lock.h" - -#else -#include <ircg_resource.h> -#include <ircg_hash.h> -#include <ircg_lock.h> -#endif - +#include "php_ircg_conversion.h" +#include "php_ircg_cache.h" #include "php_ircg_alloc.h" +#include "php_ircg_error.h" +#include "php_ircg_tokenizer.h" #include "ext/standard/php_smart_str.h" +#include "php_ircg_private.h" -static struct { - ircg_hash_table h_fmt_msgs; - - IRCG_LOCK(fmt_msgs_lock); - - /* these just serve statistical/entertainment purposes */ - unsigned long irc_connects, irc_set_currents, irc_quit_handlers, - exec_fmt_msgs, exec_token_compiler; - - unsigned long cache_hits, cache_misses; - - - time_t next_gc; +struct php_ircg_global *php_ircg; - struct errormsg *error_msgs; - - IRCG_LOCK(error_msgs_lock); -} *php_ircg; +/* initialized in the IRCG control process, so that we can avoid locking */ +struct cache_entry *php_ircg_cache_entries; /* }}} */ @@ -199,21 +168,7 @@ #endif typedef struct { - unsigned char code; - union { - unsigned char v; - void *ptr; - smart_str *s; - } para; -} token_t; - -typedef struct { - token_t *t; - int ntoken; -} format_msg_t; - -typedef struct { - format_msg_t fmt_msgs[NO_FMTS]; + format_msg_t *fmt_msgs[NO_FMTS]; } php_fmt_msgs_t; typedef struct { @@ -245,33 +200,9 @@ char *realname; /* dito */ } php_irconn_t; -enum { - C_CHANNEL = 1, - C_FROM, - C_TO, - C_MESSAGE, - C_STRING, - C_PERCENT, - C_TERMINATE_1 /* auth by username */ -}; - -enum { - P_RAW = 0, - P_JS = 1, - P_NICKNAME = 2, - P_NICKNAME_JS = 3, - P_MIRC = 4, - P_MIRC_JS = 5, - P_NOAUTO_LINKS = 8, /* Don't automatically convert links */ - P_CONV_BR = 16, /* Convert a special character to <br> */ - P_COND_STOP = 32, /* If argument != username, stop */ -}; - static php_fmt_msgs_t fmt_msgs_default_compiled; -static void 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); +#define format_msg php_ircg_format_msg static void msg_send(php_irconn_t *conn, smart_str *msg); @@ -280,9 +211,9 @@ /* {{{ Default format messages */ static char *fmt_msgs_default[] = { - "%f@%c: %m<br />", - "%f: %m<br />", - "To %t: %m<br />", + "[%c] %f: %m<br />", + "privat from %f: %m<br />", + "%f privat to %t: %m<br />", "%f leaves %c<br />", "%f joins %c<br />", "%t was kicked by %f from %c (%m)<br />", @@ -324,7 +255,7 @@ format_msg(fmt, chan, to, from, msg, res) #define MSG(conn, type) \ - (&conn->fmt_msgs->fmt_msgs[type]) + (conn->fmt_msgs->fmt_msgs[type]) #define FORMAT_MSG(conn, type, chan, to, from, msg, res, u, ulen) { \ format_msg(MSG(conn, type), chan, \ @@ -335,6 +266,16 @@ /* {{{ Helper-functions */ +static void fmt_msgs_dtor(void *dummy) +{ + php_fmt_msgs_t *fmt_msgs = dummy; + int i; + + for (i = 0; i < NO_FMTS; i++) { + php_ircg_free_fmt_msg(fmt_msgs->fmt_msgs[i]); + } +} + static php_irconn_t *lookup_irconn(int id) { php_irconn_t **ret; @@ -373,33 +314,6 @@ irc_disconnect(&(*conn)->conn, "Browser connection closed"); } -static void 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.ptr, 1); - IRCG_SHARED_FREE(f->t[i].para.ptr); - break; - } - i++; - } - - IRCG_SHARED_FREE(f->t); -} - -static void fmt_msgs_dtor(void *dummy) -{ - php_fmt_msgs_t *fmt_msgs = dummy; - int i; - - for (i = 0; i < NO_FMTS; i++) { - free_fmt_msg(&fmt_msgs->fmt_msgs[i]); - } -} - /* }}} */ @@ -471,341 +385,8 @@ } /* }}} */ -/* {{{ Escape functions */ -static void ircg_js_escape(smart_str *input, smart_str *output) -{ - char *p; - char *end; - - end = input->c + input->len; - - for(p = input->c; p < end; p++) { - switch (*p) { - case '"': - case '\\': - case '\'': - smart_str_appendc_ex(output, '\\', 1); - /* fall-through */ - default: - smart_str_appendc_ex(output, *p, 1); - } - } -} - -static const char hextab[] = "0123456789abcdef"; - -#define NICKNAME_ESC_CHAR '|' - -static void ircg_nickname_escape(smart_str *input, smart_str *output) -{ - unsigned char *p; - unsigned char *end; - unsigned char c; - - p = (unsigned char *) input->c; - end = p + input->len; - - while (p < end) { - c = *p; - if ((c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || (c >= '0' && c <= '9')) - smart_str_appendc_ex(output, c, 1); - else { - smart_str_appendc_ex(output, NICKNAME_ESC_CHAR, 1); - smart_str_appendc_ex(output, hextab[c >> 4], 1); - smart_str_appendc_ex(output, hextab[c & 15], 1); - } - p++; - } -} - -#define HEX_VALUE(c) ((c>='a'&&c<='f')?c-'a'+10:(c>='0'&&c<='9')?c-'0':0) - -static void ircg_nickname_unescape(smart_str *input, smart_str *output) -{ - char *p; - char *end; - - end = input->c + input->len; - - for(p = input->c; p < end; p++) { - switch (p[0]) { - case NICKNAME_ESC_CHAR: - if (p + 2 >= end) break; - smart_str_appendc_ex(output, (HEX_VALUE(p[1]) << 4) + HEX_VALUE(p[2]), 1); - p += 2; - break; - default: - smart_str_appendc_ex(output, p[0], 1); - } - } -} -/* }}} */ - -/* {{{ cache-related stuff */ - -/* This is an expensive operation in terms of CPU time. We - try to spend as little time in it by caching messages which - are sent to channels (and hence used multiple times). */ -void ircg_mirc_color(const char *, smart_str *, size_t, int, int); - - -#undef MIN -#define MIN(a,b) (a<b?a:b) - -static inline php_uint32 ghash(smart_str *str, int auto_links, int gen_br) -{ - php_uint32 h; - const char *data = str->c, *e = str->c + MIN(3, str->len); - - for (h = 2166136261U; data < e; ) { - h *= 16777619; - h ^= *data++; - } - h *= 16777619; - h ^= auto_links ? 1 : 2; - h *= 16777619; - h ^= gen_br ? 1 : 2; - - return h; -} -/* }}} */ - -struct cache_entry { - php_uint32 h; - char mask; - smart_str src; - smart_str result; -}; - -static struct cache_entry *cache_entries; -static int last_ce_write; - -#define NR_CACHE_ENTRIES 8 -/* {{{ ircg_mirc_color_cache */ -void ircg_mirc_color_cache(smart_str *src, smart_str *result, - smart_str *channel, int auto_links, int gen_br) -{ - /* We only cache messages in the context of a channel */ - if (channel && cache_entries) { - int hash; - int i; - char mask = (auto_links ? 1 : 0) | (gen_br ? 2 : 0); - struct cache_entry *ce = cache_entries + last_ce_write; - struct cache_entry *cee = cache_entries + NR_CACHE_ENTRIES; - - hash = ghash(src, auto_links, gen_br); - - /* we search forward .. */ - for (i = 0; i < NR_CACHE_ENTRIES; i++) { - if (ce->h == hash - && ce->mask == mask - && ce->src.len == src->len - && memcmp(ce->src.c, src->c, src->len) == 0) { - php_ircg->cache_hits++; - goto found; - } - if (++ce >= cee) - ce = cache_entries; - } - - php_ircg->cache_misses++; - /* .. and insert in the reverse direction */ - - if (--last_ce_write < 0) - last_ce_write = NR_CACHE_ENTRIES - 1; - - ce = cache_entries + last_ce_write; - ce->h = hash; - ce->mask = mask; - ce->src.len = 0; - ce->result.len = 0; - - smart_str_append_ex(&ce->src, src, 1); - ircg_mirc_color(ce->src.c, &ce->result, ce->src.len, auto_links, gen_br); - -found: - smart_str_append_ex(result, &ce->result, 1); - } else { - /* No channel message, no caching */ - ircg_mirc_color(src->c, result, src->len, auto_links, gen_br); - } -} -/* }}} */ - -/* {{{ token_compiler */ - -#define NEW_TOKEN(a, b) t = IRCG_SHARED_REALLOC(t, sizeof(token_t) * (++n)); t[n-1].code=a; t[n-1].para.b - -static void token_compiler(const char *fmt, format_msg_t *f) -{ - const char *p, *pe; - const char *q; - token_t *t = NULL; - int n = 0; - char mode; - unsigned long len; - char c; - smart_str *s; - - php_ircg->exec_token_compiler++; - - if (fmt[0] == '\0') { - f->t = NULL; - f->ntoken = 0; - return; - } - - p = fmt; - pe = fmt + strlen(p); - - do { - q = p; - while (*q != '%') - if (++q >= pe) { - s = IRCG_SHARED_ALLOC(sizeof *s); - s->c = 0; - smart_str_appendl_ex(s, p, pe - p, 1); - NEW_TOKEN(C_STRING, ptr) = s; - goto leave_loop; - } - len = q - p; - - if (len > 0) { - s = IRCG_SHARED_ALLOC(sizeof *s); - s->c = 0; - smart_str_appendl_ex(s, p, len, 1); - NEW_TOKEN(C_STRING, ptr) = s; - } - 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; - - /* 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_MIRC; break; - case 'j': NEW_TOKEN(C_MESSAGE, v) = mode | P_MIRC | 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; - f->t = t; -} -/* }}} */ - -/* {{{ format_msg */ -static void 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) -{ - smart_str encoded_msg = {0}; - int encoded = 0; - int i = 0; - const token_t *t = fmt_msg->t; - int ntoken = fmt_msg->ntoken; - - php_ircg->exec_fmt_msgs++; - -#define IRCG_APPEND(what) \ - 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; \ - ircg_js_escape(what, result); \ - break; \ - case P_NICKNAME_JS: { \ - smart_str tmp = {0}; \ - if (!what) break; \ - ircg_nickname_unescape(what, &tmp); \ - ircg_js_escape(&tmp, result); \ - smart_str_free_ex(&tmp, 1); \ - break; \ - } \ - case P_NICKNAME: \ - if (!what) break; \ - ircg_nickname_unescape(what, result); \ - break; \ - case P_RAW: \ - if (!what) break; \ - smart_str_append_ex(result, what, 1); \ - break; \ - case P_MIRC_JS: \ - if (!what) break; \ - if (!encoded) { \ - ircg_mirc_color_cache(msg, \ - &encoded_msg, channel, \ - !(t[i].para.v & P_NOAUTO_LINKS), \ - t[i].para.v & P_CONV_BR); \ - encoded = 1; \ - } \ - ircg_js_escape(&encoded_msg, result); \ - break; \ - case P_MIRC: \ - if (!what) break; \ - if (!encoded) { \ - ircg_mirc_color_cache(msg, \ - &encoded_msg, channel, \ - !(t[i].para.v & P_NOAUTO_LINKS), \ - t[i].para.v & P_CONV_BR); \ - encoded = 1; \ - } \ - smart_str_append_ex(result, &encoded_msg, 1); \ - break; \ - } - - for (; ntoken-- > 0; i++) { - switch (t[i].code) { - case C_STRING: smart_str_append_ex(result, t[i].para.ptr, 1); break; - case C_FROM: IRCG_APPEND(from); break; - case C_TO: IRCG_APPEND(to); break; - case C_CHANNEL: IRCG_APPEND(channel); break; - case C_MESSAGE: IRCG_APPEND(msg); 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 (encoded) - smart_str_free_ex(&encoded_msg, 1); - - if (result->c) - smart_str_0(result); -} -/* }}} */ - /* {{{ HTTP-related */ #include "SAPI.h" @@ -831,7 +412,7 @@ /* }}} */ -static time_t php_ircg_now(void) +time_t php_ircg_now(void) { struct timeval now; @@ -844,7 +425,6 @@ return now.tv_sec; } -#define GC_INTVL 60 #define WINDOW_TIMEOUT (3 * 60) static const char timeout_message[] = "Timed out waiting for streaming window"; @@ -946,14 +526,14 @@ real_msg_end = strchr(real_msg, '\001'); if (real_msg_end) { - format_msg_t *fmt_msg; + format_msg_t **fmt_msg_p; smart_str tmp, tmp2; int status = 0; *real_msg_end = '\0'; *token_end = '\0'; - if (ircg_hash_find(&conn->ctcp_msgs, msg->c + 1, token_end - msg->c - 1, (void **) &fmt_msg) != SUCCESS) { + if (ircg_hash_find(&conn->ctcp_msgs, msg->c + 1, token_end - +msg->c - 1, (void **) &fmt_msg_p) != SUCCESS) { return; } @@ -970,7 +550,7 @@ smart_str_setl(&tmp2, conn->conn.username, conn->conn.username_len); to = &tmp2; } - format_msg(fmt_msg, chan, to, from, &tmp, result, conn->conn.username, conn->conn.username_len, &status); + format_msg(*fmt_msg_p, chan, to, from, &tmp, result, +conn->conn.username, conn->conn.username_len, &status); if (status == 1) irc_disconnect(&conn->conn, "Connection terminated by authenticated CTCP message"); @@ -1148,111 +728,6 @@ /* }}} */ -/* {{{ Post-connection error-storage */ - -/* - * This is an internal API which serves the purpose to store the reason - * for terminating a connection. The termination will cause the - * connection id to become invalid. A script can then use a - * function to retrieve the last error message associated with that id - * and will usually present a nicely formatted - * error message to the end-user. - * - * We automatically garbage-collect every GC_INTVL seconds, so there is - * no need for a separate gc thread. - */ - -struct errormsg { - smart_str msg; - int msgid; - int id; - time_t when; - struct errormsg *next; -}; - -static void error_msg_dtor(struct errormsg *m) -{ - smart_str_free_ex(&m->msg, 1); - IRCG_SHARED_FREE(m); -} - -static void error_msg_gc(time_t now) -{ - struct errormsg *m, *prev = NULL, *next; - time_t lim; - - IRCG_LOCK_GET(php_ircg->error_msgs_lock); - lim = now - GC_INTVL; - php_ircg->next_gc = now + GC_INTVL; - - for (m = php_ircg->error_msgs; m; prev = m, m = m->next) { - if (m->when < lim) { - struct errormsg *to; - /* Check whether we have subsequent outdated records */ - - for (to = m->next; to; to = next) { - next = to->next; - if (m->when >= lim) break; - error_msg_dtor(to); - } - - error_msg_dtor(m); - - if (prev) - prev->next = to; - else - php_ircg->error_msgs = to; - - if (!to) break; - m = to; - } - } - IRCG_LOCK_PUT(php_ircg->error_msgs_lock); -} - -static void add_error_msg(smart_str *msg, int msgid, php_irconn_t *conn) -{ - struct errormsg *m; - - IRCG_LOCK_GET(php_ircg->error_msgs_lock); - for (m = php_ircg->error_msgs; m; m = m->next) { - if (m->id == conn->irconn_id) break; - } - - if (!m) { - m = IRCG_SHARED_ALLOC(sizeof(*m)); - m->msg.c = 0; - m->id = conn->irconn_id; - } - - m->when = php_ircg_now(); - m->msg.len = 0; - smart_str_append_ex(&m->msg, msg, 1); - m->msgid = msgid; - m->next = php_ircg->error_msgs; - php_ircg->error_msgs = m; - IRCG_LOCK_PUT(php_ircg->error_msgs_lock); -} - -static struct errormsg *lookup_and_remove_error_msg(int id) -{ - struct errormsg *m, *prev = NULL; - - IRCG_LOCK_GET(php_ircg->error_msgs_lock); - for (m = php_ircg->error_msgs; m; prev = m, m = m->next) { - if (m->id == id) { - if (prev) - prev->next = m->next; - else - php_ircg->error_msgs = m->next; - - break; - } - } - IRCG_LOCK_PUT(php_ircg->error_msgs_lock); - return m; -} - static void error_handler(irconn_t *ircc, int id, int fatal, smart_str *msg, void *conn_data) { php_irconn_t *conn = conn_data; @@ -1273,7 +748,7 @@ &s_username, &tmp, msg, &m, conn->conn.username, conn->conn.username_len); if (fatal) { - add_error_msg(msg, id, conn); + php_ircg_add_error_msg(msg, id, conn->irconn_id); } msg_send(conn, &m); @@ -1283,7 +758,6 @@ if (disconn) irc_disconnect(ircc, "A fatal error occured"); } -/* }}} */ /* {{{ IRCG-handlers */ static void banlist_handler(irconn_t *ircc, smart_str *channel, smart_str *mask, void *conn_data) @@ -1631,7 +1105,7 @@ smart_str_setl(&in, Z_STRVAL_PP(p1), Z_STRLEN_PP(p1)); - ircg_nickname_escape(&in, &out); + php_ircg_nickname_escape(&in, &out); smart_str_0(&out); RETVAL_STRINGL(out.c, out.len, 1); @@ -1655,7 +1129,7 @@ smart_str_setl(&in, Z_STRVAL_PP(p1), Z_STRLEN_PP(p1)); - ircg_nickname_unescape(&in, &out); + php_ircg_nickname_unescape(&in, &out); smart_str_0(&out); RETVAL_STRINGL(out.c, out.len, 1); @@ -1761,14 +1235,14 @@ convert_to_long_ex(args[0]); - m = lookup_and_remove_error_msg(Z_LVAL_PP(args[0])); + m = php_ircg_lookup_and_remove_error_msg(Z_LVAL_PP(args[0])); if (!m) RETURN_FALSE; array_init(return_value); add_index_long(return_value, 0, m->msgid); add_index_stringl(return_value, 1, m->msg.c, m->msg.len, 1); - error_msg_dtor(m); + php_ircg_error_msg_dtor(m); } /* }}} */ @@ -2061,11 +1535,12 @@ h = HASH_OF(*p2); for (i = 0; i < NO_FMTS; i++) { + fmt_msgs.fmt_msgs[i] = 0; if (zend_hash_index_find(h, i, (void **) &arg) == SUCCESS) { convert_to_string_ex(arg); - token_compiler(Z_STRVAL_PP(arg), &fmt_msgs.fmt_msgs[i]); + php_ircg_token_compiler(Z_STRVAL_PP(arg), +&fmt_msgs.fmt_msgs[i]); } else - token_compiler("", &fmt_msgs.fmt_msgs[i]); + php_ircg_token_compiler("", &fmt_msgs.fmt_msgs[i]); } IRCG_LOCK_GET(php_ircg->fmt_msgs_lock); @@ -2104,8 +1579,10 @@ irc_set_realname(conn, &m); } #endif - -#define IFMSG(n, p, q) if (MSG(irconn, n)->ntoken != 0) irc_register_hook(conn, p, q) + +#define MSG_NOT_EMPTY(n) (MSG(irconn,n) && MSG(irconn,n)->ntoken != 0) + +#define IFMSG(n, p, q) if (MSG_NOT_EMPTY(n)) irc_register_hook(conn, p, q) irc_register_hook(conn, IRCG_MSG, msg_handler); irc_register_hook(conn, IRCG_QUIT, quit_handler); @@ -2152,8 +1629,8 @@ #endif #if IRCG_API_VERSION >= 20021115 - if (MSG(irconn, FMT_MSG_WHOREPLY1)->ntoken - || MSG(irconn, FMT_MSG_WHOREPLY2)->ntoken) { + if (MSG_NOT_EMPTY(FMT_MSG_WHOREPLY1) + || MSG_NOT_EMPTY(FMT_MSG_WHOREPLY2)) { irc_register_hook(conn, IRCG_WHOREPLY, whoreply_handler); } IFMSG(FMT_MSG_ENDOFWHO, IRCG_ENDOFWHO, endofwho_handler); @@ -2165,9 +1642,9 @@ } /* }}} */ -static void ctcp_msgs_dtor(format_msg_t *fmt) +static void ctcp_msgs_dtor(format_msg_t **fmt) { - free_fmt_msg(fmt); + php_ircg_free_fmt_msg(*fmt); } /* {{{ ircg_copy_ctcp_msgs */ @@ -2178,14 +1655,14 @@ ulong num; uint str_len; HashPosition pos; - format_msg_t fmt; + format_msg_t *fmt; zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(array), &pos); while (zend_hash_get_current_key_ex(Z_ARRVAL_PP(array), &str, &str_len, &num, 0, &pos) == HASH_KEY_IS_STRING) { zend_hash_get_current_data_ex(Z_ARRVAL_PP(array), (void **) &val, &pos); convert_to_string_ex(val); - token_compiler(Z_STRVAL_PP(val), &fmt); + php_ircg_token_compiler(Z_STRVAL_PP(val), &fmt); ircg_hash_add(&conn->ctcp_msgs, str, str_len - 1, &fmt, sizeof(fmt), NULL); @@ -2298,7 +1775,7 @@ /* XXX: we take chances by assuming that wordsize read/writes are atomic */ if (conn->login >= php_ircg->next_gc) - error_msg_gc(conn->login); + php_ircg_error_msg_gc(conn->login); RETVAL_LONG(conn->irconn_id); } @@ -2617,11 +2094,15 @@ IRCG_LOCK_INIT(php_ircg->error_msgs_lock); for (i = 0; i < NO_FMTS; i++) { - token_compiler(fmt_msgs_default[i], &fmt_msgs_default_compiled.fmt_msgs[i]); + php_ircg_token_compiler(fmt_msgs_default[i], +&fmt_msgs_default_compiled.fmt_msgs[i]); } } else if (stage == 1) { - cache_entries = malloc(sizeof(struct cache_entry) * NR_CACHE_ENTRIES); - memset(cache_entries, 0, sizeof(struct cache_entry) * NR_CACHE_ENTRIES); + php_ircg_cache_entries = malloc(sizeof(struct cache_entry) * +NR_CACHE_ENTRIES); + memset(php_ircg_cache_entries, 0, sizeof(struct cache_entry) * +NR_CACHE_ENTRIES); + } else if (stage == -1) { + memset(php_ircg, 0x78, sizeof *php_ircg); + IRCG_SHARED_FREE(php_ircg); + php_ircg = NULL; } } Index: php4/ext/ircg/php_ircg.h diff -u php4/ext/ircg/php_ircg.h:1.23 php4/ext/ircg/php_ircg.h:1.24 --- php4/ext/ircg/php_ircg.h:1.23 Sat Nov 30 22:47:49 2002 +++ php4/ext/ircg/php_ircg.h Tue Dec 3 05:13:36 2002 @@ -63,18 +63,9 @@ PHP_RSHUTDOWN_FUNCTION(ircg); PHP_MINFO_FUNCTION(ircg); -PHP_FUNCTION(confirm_ircg_compiled); /* For testing, remove later. */ - ZEND_BEGIN_MODULE_GLOBALS(ircg) void *flush_data; ZEND_END_MODULE_GLOBALS(ircg) - -/* In every function that needs to use variables in php_ircg_globals, - do call IRCGLS_FETCH(); after declaring other variables used by - that function, and always refer to them as IRCGG(variable). - You are encouraged to rename these macros something shorter, see - examples in any other php module directory. -*/ #ifdef ZTS #define IRCGG(v) TSRMG(ircg_globals_id, php_ircg_globals *, v) Index: php4/ext/ircg/php_ircg_alloc.h diff -u php4/ext/ircg/php_ircg_alloc.h:1.2 php4/ext/ircg/php_ircg_alloc.h:1.3 --- php4/ext/ircg/php_ircg_alloc.h:1.2 Sun Dec 1 01:30:01 2002 +++ php4/ext/ircg/php_ircg_alloc.h Tue Dec 3 05:13:36 2002 @@ -3,19 +3,18 @@ #include <if_irc.h> -#if IRCG_API_VERSION < 20021127 -#define IRCG_SHARED_ALLOC(a) malloc((a)) -#define IRCG_SHARED_REALLOC(a,b) realloc((a),(b)) -#define IRCG_SHARED_FREE(a) free((a)) -#else +# if IRCG_API_VERSION < 20021127 +# define IRCG_SHARED_ALLOC(a) malloc((a)) +# define IRCG_SHARED_REALLOC(a,b) realloc((a),(b)) +# define IRCG_SHARED_FREE(a) free((a)) +# else /* for smart_strs */ -#define realloc(a,b) IRCG_SHARED_REALLOC(a,b) -#define free(a) IRCG_SHARED_FREE(a) +# define realloc(a,b) IRCG_SHARED_REALLOC(a,b) +# define free(a) IRCG_SHARED_FREE(a) -#include <ircg_alloc.h> +# include <ircg_alloc.h> - -#endif +# endif #endif Index: php4/ext/ircg/php_ircg_cache.c +++ php4/ext/ircg/php_ircg_cache.c /* {{{ cache-related stuff */ #include "php_ircg_private.h" #include "php_ircg_alloc.h" #include "php_ircg_cache.h" #include "ext/standard/php_smart_str.h" /* This is an expensive operation in terms of CPU time. We try to spend as little time in it by caching messages which are sent to channels (and hence used multiple times). */ void ircg_mirc_color(const char *, smart_str *, size_t, int, int); #undef MIN #define MIN(a,b) (a<b?a:b) static inline php_uint32 ghash(smart_str *str, int auto_links, int gen_br) { php_uint32 h; const char *data = str->c, *e = str->c + MIN(3, str->len); for (h = 2166136261U; data < e; ) { h *= 16777619; h ^= *data++; } h *= 16777619; h ^= auto_links ? 1 : 2; h *= 16777619; h ^= gen_br ? 1 : 2; return h; } /* }}} */ static int last_ce_write; #define NR_CACHE_ENTRIES 24 /* {{{ ircg_mirc_color_cache */ void ircg_mirc_color_cache(smart_str *src, smart_str *result, smart_str *channel, int auto_links, int gen_br) { /* We only cache messages in the context of a channel */ if (channel && php_ircg_cache_entries) { int hash; int i; char mask = (auto_links ? 1 : 0) | (gen_br ? 2 : 0); struct cache_entry *ce = php_ircg_cache_entries + last_ce_write; struct cache_entry *cee = php_ircg_cache_entries + NR_CACHE_ENTRIES; hash = ghash(src, auto_links, gen_br); /* we search forward .. */ for (i = 0; i < NR_CACHE_ENTRIES; i++) { if (ce->h == hash && ce->mask == mask && ce->src.len == src->len && memcmp(ce->src.c, src->c, src->len) == 0) { php_ircg->cache_hits++; goto found; } if (++ce >= cee) ce = php_ircg_cache_entries; } php_ircg->cache_misses++; /* .. and insert in the reverse direction */ if (--last_ce_write < 0) last_ce_write = NR_CACHE_ENTRIES - 1; ce = php_ircg_cache_entries + last_ce_write; ce->h = hash; ce->mask = mask; ce->src.len = 0; ce->result.len = 0; smart_str_append_ex(&ce->src, src, 1); ircg_mirc_color(ce->src.c, &ce->result, ce->src.len, auto_links, gen_br); found: smart_str_append_ex(result, &ce->result, 1); } else { /* No channel message, no caching */ ircg_mirc_color(src->c, result, src->len, auto_links, gen_br); } } /* }}} */ Index: php4/ext/ircg/php_ircg_cache.h +++ php4/ext/ircg/php_ircg_cache.h #ifndef PHP_IRCG_CACHE_H #define PHP_IRCG_CACHE_H #include "php.h" #include "ext/standard/basic_functions.h" #include "ext/standard/php_smart_str_public.h" struct cache_entry { php_uint32 h; char mask; smart_str src; smart_str result; }; extern struct cache_entry *php_ircg_cache_entries; extern int php_ircg_last_ce_write; void ircg_mirc_color_cache(smart_str *src, smart_str *result, smart_str *channel, int auto_links, int gen_br); #endif Index: php4/ext/ircg/php_ircg_conversion.c +++ php4/ext/ircg/php_ircg_conversion.c #include "php_ircg_alloc.h" #include "ext/standard/php_smart_str.h" /* {{{ Escape functions */ void php_ircg_js_escape(smart_str *input, smart_str *output) { char *p; char *end; end = input->c + input->len; for(p = input->c; p < end; p++) { switch (*p) { case '"': case '\\': case '\'': smart_str_appendc_ex(output, '\\', 1); /* fall-through */ default: smart_str_appendc_ex(output, *p, 1); } } } static const char hextab[] = "0123456789abcdef"; #define NICKNAME_ESC_CHAR '|' void php_ircg_nickname_escape(smart_str *input, smart_str *output) { unsigned char *p; unsigned char *end; unsigned char c; p = (unsigned char *) input->c; end = p + input->len; while (p < end) { c = *p; if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) smart_str_appendc_ex(output, c, 1); else { smart_str_appendc_ex(output, NICKNAME_ESC_CHAR, 1); smart_str_appendc_ex(output, hextab[c >> 4], 1); smart_str_appendc_ex(output, hextab[c & 15], 1); } p++; } } #define HEX_VALUE(c) ((c>='a'&&c<='f')?c-'a'+10:(c>='0'&&c<='9')?c-'0':0) void php_ircg_nickname_unescape(smart_str *input, smart_str *output) { char *p; char *end; end = input->c + input->len; for(p = input->c; p < end; p++) { switch (p[0]) { case NICKNAME_ESC_CHAR: if (p + 2 >= end) break; smart_str_appendc_ex(output, (HEX_VALUE(p[1]) << 4) + HEX_VALUE(p[2]), 1); p += 2; break; default: smart_str_appendc_ex(output, p[0], 1); } } } /* }}} */ Index: php4/ext/ircg/php_ircg_conversion.h +++ php4/ext/ircg/php_ircg_conversion.h void php_ircg_js_escape(smart_str *input, smart_str *output); void php_ircg_nickname_escape(smart_str *input, smart_str *output); void php_ircg_nickname_unescape(smart_str *input, smart_str *output); Index: php4/ext/ircg/php_ircg_error.c +++ php4/ext/ircg/php_ircg_error.c #include "php_ircg_private.h" #include "php_ircg_alloc.h" #include "php_ircg_error.h" #include "ext/standard/php_smart_str.h" #include <time.h> /* {{{ Post-connection error-storage */ /* * This is an internal API which serves the purpose to store the reason * for terminating a connection. The termination will cause the * connection id to become invalid. A script can then use a * function to retrieve the last error message associated with that id * and will usually present a nicely formatted * error message to the end-user. * * We automatically garbage-collect every GC_INTVL seconds, so there is * no need for a separate gc thread. */ #define GC_INTVL 60 void php_ircg_error_msg_dtor(struct errormsg *m) { smart_str_free_ex(&m->msg, 1); IRCG_SHARED_FREE(m); } void php_ircg_error_msg_gc(time_t now) { struct errormsg *m, *prev = NULL, *next; time_t lim; IRCG_LOCK_GET(php_ircg->error_msgs_lock); lim = now - GC_INTVL; php_ircg->next_gc = now + GC_INTVL; for (m = php_ircg->error_msgs; m; prev = m, m = m->next) { if (m->when < lim) { struct errormsg *to; /* Check whether we have subsequent outdated records */ for (to = m->next; to; to = next) { next = to->next; if (m->when >= lim) break; php_ircg_error_msg_dtor(to); } php_ircg_error_msg_dtor(m); if (prev) prev->next = to; else php_ircg->error_msgs = to; if (!to) break; m = to; } } IRCG_LOCK_PUT(php_ircg->error_msgs_lock); } void php_ircg_add_error_msg(smart_str *msg, int msgid, int connid) { struct errormsg *m; IRCG_LOCK_GET(php_ircg->error_msgs_lock); for (m = php_ircg->error_msgs; m; m = m->next) { if (m->id == connid) break; } if (!m) { m = IRCG_SHARED_ALLOC(sizeof(*m)); m->msg.c = 0; m->id = connid; } m->when = php_ircg_now(); m->msg.len = 0; smart_str_append_ex(&m->msg, msg, 1); m->msgid = msgid; m->next = php_ircg->error_msgs; php_ircg->error_msgs = m; IRCG_LOCK_PUT(php_ircg->error_msgs_lock); } struct errormsg *php_ircg_lookup_and_remove_error_msg(int id) { struct errormsg *m, *prev = NULL; IRCG_LOCK_GET(php_ircg->error_msgs_lock); for (m = php_ircg->error_msgs; m; prev = m, m = m->next) { if (m->id == id) { if (prev) prev->next = m->next; else php_ircg->error_msgs = m->next; break; } } IRCG_LOCK_PUT(php_ircg->error_msgs_lock); return m; } /* }}} */ Index: php4/ext/ircg/php_ircg_error.h +++ php4/ext/ircg/php_ircg_error.h #ifndef PHP_IRCG_ERROR_H #define PHP_IRCG_ERROR_H struct errormsg { smart_str msg; int msgid; int id; time_t when; struct errormsg *next; }; void php_ircg_error_msg_dtor(struct errormsg *m); void php_ircg_error_msg_gc(time_t now); void php_ircg_add_error_msg(smart_str *msg, int msgid, int connid); struct errormsg *php_ircg_lookup_and_remove_error_msg(int id); #endif Index: php4/ext/ircg/php_ircg_private.h +++ php4/ext/ircg/php_ircg_private.h #ifndef PHP_IRCG_PRIVATE_H #define PHP_IRCG_PRIVATE_H #include "php.h" #include "if_irc.h" #include "irc_write_buffer.h" #if IRCG_API_VERSION < 20021127 #define USE_IRCONN_MANAGEMENT static HashTable h_irconn; /* Integer IDs to php_irconn_t * */ static int irconn_id; #define USE_FD2IRCONN static HashTable h_fd2irconn; /* fd's to Integer IDs */ /* provide dummy definitions */ #include "php_ircg_hash.h" #include "php_ircg_lock.h" #else #include <ircg_resource.h> #include <ircg_hash.h> #include <ircg_lock.h> #endif struct php_ircg_global { ircg_hash_table h_fmt_msgs; IRCG_LOCK(fmt_msgs_lock); /* these just serve statistical/entertainment purposes */ unsigned long irc_connects, irc_set_currents, irc_quit_handlers, exec_fmt_msgs, exec_token_compiler; unsigned long cache_hits, cache_misses; time_t next_gc; struct errormsg *error_msgs; IRCG_LOCK(error_msgs_lock); }; extern struct php_ircg_global *php_ircg; time_t php_ircg_now(void); #endif Index: php4/ext/ircg/php_ircg_tokenizer.c +++ php4/ext/ircg/php_ircg_tokenizer.c #include "php_ircg_private.h" #include "php_ircg_alloc.h" #include "php_ircg_conversion.h" #include "ext/standard/php_smart_str.h" /* {{{ token_compiler */ #include "php_ircg_tokenizer.h" #include "php_ircg_alloc.h" #include "ext/standard/php_smart_str.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 void php_ircg_token_compiler(const char *fmt, 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 + strlen(p); do { q = p; while (*q != '%') if (++q >= pe) { s.c = 0; smart_str_appendl_ex(&s, p, pe - p, 1); NEW_TOKEN(C_STRING, s) = s; goto leave_loop; } len = q - p; if (len > 0) { s.c = 0; smart_str_appendl_ex(&s, p, len, 1); NEW_TOKEN(C_STRING, s) = s; } 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; /* 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_MIRC; break; case 'j': NEW_TOKEN(C_MESSAGE, v) = mode | P_MIRC | 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) { smart_str encoded_msg = {0}; int encoded = 0; int i = 0; const token_t *t; int ntoken; if (!fmt_msg) return; ntoken = fmt_msg->ntoken; t = fmt_msg->t; php_ircg->exec_fmt_msgs++; #define IRCG_APPEND(what) \ 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_MIRC_JS: \ if (!what) break; \ if (!encoded) { \ ircg_mirc_color_cache(msg, \ &encoded_msg, channel, \ !(t[i].para.v & P_NOAUTO_LINKS), \ t[i].para.v & P_CONV_BR); \ encoded = 1; \ } \ php_ircg_js_escape(&encoded_msg, result); \ break; \ case P_MIRC: \ if (!what) break; \ if (!encoded) { \ ircg_mirc_color_cache(msg, \ &encoded_msg, channel, \ !(t[i].para.v & P_NOAUTO_LINKS), \ t[i].para.v & P_CONV_BR); \ encoded = 1; \ } \ smart_str_append_ex(result, &encoded_msg, 1); \ break; \ } for (; ntoken-- > 0; i++) { switch (t[i].code) { case C_STRING: smart_str_append_ex(result, &t[i].para.s, 1); break; case C_FROM: IRCG_APPEND(from); break; case C_TO: IRCG_APPEND(to); break; case C_CHANNEL: IRCG_APPEND(channel); break; case C_MESSAGE: IRCG_APPEND(msg); 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 (encoded) smart_str_free_ex(&encoded_msg, 1); if (result->c) smart_str_0(result); } 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); } /* }}} */ Index: php4/ext/ircg/php_ircg_tokenizer.h +++ php4/ext/ircg/php_ircg_tokenizer.h #include "ext/standard/php_smart_str_public.h" typedef struct { unsigned char code; union { unsigned char v; void *ptr; smart_str s; } para; } token_t; typedef struct { int ntoken; token_t t[1]; } format_msg_t; enum { C_CHANNEL = 1, C_FROM, C_TO, C_MESSAGE, C_STRING, C_PERCENT, C_TERMINATE_1 /* auth by username */ }; enum { P_RAW = 0, P_JS = 1, P_NICKNAME = 2, P_NICKNAME_JS = 3, P_MIRC = 4, P_MIRC_JS = 5, P_NOAUTO_LINKS = 8, /* Don't automatically convert links */ P_CONV_BR = 16, /* Convert a special character to <br> */ P_COND_STOP = 32, /* If argument != username, stop */ }; #define NR_CACHE_ENTRIES 24 void php_ircg_token_compiler(const char *fmt, format_msg_t **fp); 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); void php_ircg_fmt_msgs_dtor(void *dummy); void php_ircg_free_fmt_msg(format_msg_t *f);
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php