/* * functions.c -- Built-in functions for ircII * * Copyright (c) 1990 Michael Sandroff. * Copyright (c) 1991, 1992 Troy Rollo. * Copyright (c) 1992-1996 Matthew Green. * Copyright 1993, 2010 EPIC Software Labs * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notices, the above paragraph (the one permitting redistribution), * this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The names of the author(s) may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Some of the "others" include: * Matt Carothers Colten Edwards * James Sneeringer Eli Sand */ /* * I split alias.c because it was just getting out of hand. */ #include "irc.h" #define __need_ArgList_t__ #include "alias.h" #include "alist.h" #include "array.h" #include "clock.h" #include "ctcp.h" #include "dcc.h" #include "debug.h" #include "commands.h" #include "exec.h" #include "files.h" #include "flood.h" #include "ignore.h" #include "input.h" #include "ircaux.h" #include "keys.h" #include "lastlog.h" #include "log.h" #include "names.h" #include "output.h" #include "parse.h" #include "screen.h" #include "server.h" #include "status.h" #include "vars.h" #include "window.h" #include "termx.h" #include "notify.h" #include "numbers.h" #include "list.h" #include "sedcrypt.h" #include "timer.h" #define need_static_functions #include "functions.h" #include "options.h" #include "words.h" #include "reg.h" #include "ifcmd.h" #include "ssl.h" #include "levels.h" #include "extlang.h" #include "ctcp.h" #include "cJSON.h" #ifdef NEED_GLOB # include "glob.h" #else # include #endif #ifdef HAVE_REGEX_H # include #endif #ifdef HAVE_UNAME # include #endif #include static char *alias_detected (void), *alias_sent_nick (void), *alias_recv_nick (void), *alias_msg_body (void), *alias_joined_nick (void), *alias_public_nick (void), *alias_dollar (void), *alias_channel (void), *alias_server (void), *alias_query_nick (void), *alias_target (void), *alias_nick (void), *alias_invite (void), *alias_cmdchar (void), *alias_line (void), *alias_away (void), *alias_oper (void), *alias_chanop (void), *alias_modes (void), *alias_buffer (void), *alias_time (void), *alias_version (void), *alias_currdir (void), *alias_current_numeric (void), *alias_server_version (void), *alias_show_userhost (void), *alias_show_realname (void), *alias_online (void), *alias_idle (void), *alias_version_str (void), *alias_banner (void); typedef struct { const char * name; char * (*func) (void); } BuiltIns; static BuiltIns built_in[] = { { ".", alias_sent_nick }, { ",", alias_recv_nick }, { ":", alias_joined_nick }, { ";", alias_public_nick }, { "$", alias_dollar }, { "A", alias_away }, { "B", alias_msg_body }, { "C", alias_channel }, { "D", alias_detected }, { "E", alias_idle }, { "F", alias_online }, { "G", alias_banner }, { "H", alias_current_numeric }, { "I", alias_invite }, { "J", alias_version_str }, { "K", alias_cmdchar }, { "L", alias_line }, { "M", alias_modes }, { "N", alias_nick }, { "O", alias_oper }, { "P", alias_chanop }, { "Q", alias_query_nick }, { "R", alias_server_version }, { "S", alias_server }, { "T", alias_target }, { "U", alias_buffer }, { "V", alias_version }, { "W", alias_currdir }, { "X", alias_show_userhost }, { "Y", alias_show_realname }, { "Z", alias_time }, { 0, NULL } }; /* the 30 "standard" functions */ static char *function_channels (char *), *function_connect (char *), *function_curpos (char *), *function_index (char *), *function_ischannel (char *), *function_ischanop (char *), *function_left (char *), *function_listen (char *), *function_match (char *), *function_mid (char *), *function_pid (char *), *function_ppid (char *), *function_rand (char *), *function_right (char *), *function_rindex (char *), *function_rmatch (char *), *function_servers (char *), *function_srand (char *), *function_stime (char *), *function_strip (char *), *function_tdiff (char *), *function_tdiff2 (char *), *function_time (char *), *function_tolower (char *), *function_toupper (char *), *function_userhost (char *), *function_word (char *), *function_utime (char *), *function_strftime (char *), /* the countless "extended" functions */ *function_abs (char *), *function_acos (char *), *function_asin (char *), *function_atan (char *), *function_acosh (char *), *function_asinh (char *), *function_atanh (char *), *function_after (char *), *function_afterw (char *), *function_aliasctl (char *), *function_ascii (char *), *function_asciiq (char *), *function_before (char *), *function_beforew (char *), *function_bindctl (char *), *function_builtin (char *), *function_ceil (char *), *function_center (char *), *function_cexist (char *), *function_chankey (char *), *function_channel (char *), *function_channellimit (char *), *function_channelmode (char *), *function_channelsyncing (char *), *function_check_code (char *), *function_chmod (char *), *function_chngw (char *), *function_chop (char *), *function_chops (char *), *function_chr (char *), *function_chrq (char *), *function_cipher (char *), *function_close (char *), *function_cofilter (char *), *function_corfilter (char *), *function_common (char *), *function_convert (char *), *function_copattern (char *), *function_corpattern (char *), *function_cos (char *), *function_cosh (char *), *function_count (char *), *function_crypt (char *), *function_curcmd (char *), *function_currchans (char *), *function_dbmctl (char *), *function_dccctl (char *), *function_deuhc (char *), *function_diff (char *), *function_encryptparm (char *), *function_eof (char *), *function_epic (char *), *function_error (char *), *function_exec (char *), *function_execctl (char *), *function_exp (char *), *function_fnexist (char *), *function_fexist (char *), *function_filter (char *), *function_findw (char *), *function_findws (char *), *function_fix_arglist (char *), *function_fix_width (char *), *function_floor (char *), *function_fromw (char *), *function_fsize (char *), *function_ftime (char *), *function_ftruncate (char *), *function_functioncall (char *), *function_geom (char *), *function_getcap (char *), *function_getcommands (char *), *function_getenv (char *), *function_getfunctions (char *), *function_getgid (char *), *function_getlogin (char *), *function_getopt (char *), *function_getpgrp (char *), *function_getserial (char *), *function_getset (char *), *function_getsets (char *), *function_getuid (char *), *function_glob (char *), *function_globi (char *), *function_hash_32bit (char *), #if 0 *function_help_topics (char *), #endif *function_hookctl (char *), *function_iconvctl (char *), *function_idle (char *), *function_ignorectl (char *), *function_indextoword (char *), *function_info (char *), *function_insert (char *), *function_insertw (char *), *function_iptolong (char *), *function_iptoname (char *), *function_irclib (char *), *function_is8bit (char *), *function_isalpha (char *), *function_isaway (char *), *function_ischanvoice (char *), *function_isconnected (char *), *function_iscurchan (char *), *function_isdigit (char *), *function_isdisplaying (char *), *function_isencrypted (char *), *function_isfilevalid (char *), *function_ishalfop (char *), *function_isnumber (char *), *function_isutf8 (char *), *function_jn (char *), *function_joinstr (char *), *function_jot (char *), *function_json_error (char *), *function_json_explode (char *), *function_json_implode (char *), *function_jsontest (char *), *function_key (char *), *function_killpid (char *), *function_leftpc (char *), *function_leftw (char *), *function_levelctl (char *), *function_levelwindow (char *), *function_loadinfo (char *), *function_log (char *), *function_log10 (char *), *function_logctl (char *), *function_longtoip (char *), *function_mask (char *), *function_maxlen (char *), *function_metric_time (char *), *function_midw (char *), *function_mkdir (char *), *function_mktime (char *), *function_msar (char *), *function_nametoip (char *), *function_nochops (char *), *function_nohighlight (char *), *function_notify (char *), *function_notifywindows (char *), *function_notw (char *), *function_numlines (char *), *function_numonchannel (char *), *function_numsort (char *), *function_numwords (char *), *function_onchannel (char *), *function_open (char *), *function_outputinfo (char *), *function_pad (char *), *function_pattern (char *), *function_pass (char *), #ifdef HAVE_PERL *function_perl (char *), *function_perlcall (char *), *function_perlxcall (char *), #endif *function_pledge (char *), #ifdef HAVE_PYTHON *function_pydirect (char *), *function_python (char *), #endif *function_prefix (char *), *function_printlen (char *), *function_querywin (char *), *function_qword (char *), *function_randread (char *), *function_read (char *), *function_realpath (char *), *function_regcomp (char *), *function_regcomp_cs (char *), *function_regexec (char *), *function_regerror (char *), *function_regfree (char *), *function_regmatches (char *), *function_remw (char *), *function_remws (char *), *function_rename (char *), *function_repeat (char *), *function_rest (char *), *function_restw (char *), *function_reverse (char *), *function_revw (char *), *function_rewind (char *), *function_rgb (char *), *function_rfilter (char *), *function_rightw (char *), *function_rmdir (char *), *function_rpattern (char *), *function_rsubstr (char *), #ifdef HAVE_RUBY *function_ruby (char *), #endif *function_sar (char *), *function_seek (char *), *function_sequence_point (char *), *function_server_version (char *), *function_serverctl (char *), *function_servports (char *), *function_serverwin (char *), *function_qshuffle (char *), *function_dshuffle (char *), *function_sin (char *), *function_sinh (char *), *function_skip (char *), *function_sort (char *), *function_split (char *), *function_splitw (char *), *function_splice (char *), *function_ssl (char *), *function_startupfile (char *), *function_stat (char *), *function_status (char *), *function_stripansi (char *), *function_stripansicodes(char *), *function_stripc (char *), *function_stripcrap (char *), *function_strlen (char *), *function_strptime (char *), *function_strtol (char *), *function_substr (char *), *function_symbolctl (char *), *function_tags (char *), *function_tan (char *), *function_tanh (char *), *function_tell (char *), *function_timerctl (char *), *function_tobase (char *), *function_tow (char *), *function_translate (char *), *function_truncate (char *), *function_ttyname (char *), *function_twiddle (char *), *function_uhc (char *), *function_umask (char *), *function_umode (char *), *function_uname (char *), *function_unicode (char *), *function_uniq (char *), *function_unlink (char *), *function_unsplit (char *), *function_unveil (char *), *function_uuid4 (char *), *function_which (char *), *function_winchan (char *), *function_windowctl (char *), *function_wordtoindex (char *), *function_write (char *), *function_writeb (char *), *function_xform (char *), *function_yn (char *), *function_cp437test (char *); char *wrapper_pattern (char *, int), *wrapper_rpattern (char *, int); extern char *function_cparse (char *), *function_push (char *), *function_pop (char *), *function_shift (char *), *function_unshift (char *), *function_shiftbrace (char *); typedef char *(bf) (char *); typedef struct { const char *name; bf *func; } BuiltInFunctions; /* * This is the built-in function list. This list *must* be sorted because * it is binary searched. See the code for each function to see how it * is used. Or see the help files. Or see both. Oh heck. Look at the code * and see how it REALLY works, regardless of the documentation >;-) */ static BuiltInFunctions built_in_functions[] = { { "ABS", function_abs }, { "ACOS", function_acos }, { "ACOSH", function_acosh }, { "AFTER", function_after }, { "AFTERW", function_afterw }, { "ALIASCTL", function_aliasctl }, { "ASCII", function_ascii }, { "ASCIIQ", function_asciiq }, { "ASIN", function_asin }, { "ASINH", function_asinh }, { "ATAN", function_atan }, { "ATANH", function_atanh }, { "BEFORE", function_before }, { "BEFOREW", function_beforew }, { "BINDCTL", function_bindctl }, { "BUILTIN_EXPANDO", function_builtin }, { "CEIL", function_ceil }, { "CENTER", function_center }, { "CEXIST", function_cexist }, { "CHANKEY", function_chankey }, { "CHANLIMIT", function_channellimit }, { "CHANMODE", function_channelmode }, { "CHANNEL", function_channel }, { "CHANUSERS", function_onchannel }, { "CHANWIN", function_winchan }, { "CHANSYNCING", function_channelsyncing }, { "CHECK_CODE", function_check_code }, { "CHMOD", function_chmod }, { "CHNGW", function_chngw }, { "CHOP", function_chop }, { "CHOPS", function_chops }, { "CHR", function_chr }, { "CHRQ", function_chrq }, { "CIPHER", function_cipher }, { "CLOSE", function_close }, { "COFILTER", function_cofilter }, { "COMMON", function_common }, { "CONNECT", function_connect }, { "CONVERT", function_convert }, { "COPATTERN", function_copattern }, { "CORFILTER", function_corfilter }, { "CORPATTERN", function_corpattern }, { "COS", function_cos }, { "COSH", function_cosh }, { "COUNT", function_count }, { "CP437TEST", function_cp437test }, { "CPARSE", function_cparse }, { "CRYPT", function_crypt }, { "CTCPCTL", function_ctcpctl }, { "CURCMD", function_curcmd }, { "CURPOS", function_curpos }, { "CURRCHANS", function_currchans }, { "DBMCTL", function_dbmctl }, { "DCCCTL", function_dccctl }, { "DELARRAY", function_delarray }, { "DELITEM", function_delitem }, { "DELITEMS", function_delitems }, { "DEUHC", function_deuhc }, { "DIFF", function_diff }, { "ENCODINGCTL", function_encodingctl }, { "ENCRYPTPARM", function_encryptparm }, { "EOF", function_eof }, { "EPIC", function_epic }, { "EXEC", function_exec }, { "EXECCTL", function_execctl }, { "EXP", function_exp }, { "FERROR", function_error }, { "FEXIST", function_fexist }, { "FILTER", function_filter }, { "FINDITEM", function_finditem }, { "FINDITEMS", function_finditems }, { "FINDW", function_findw }, { "FINDWS", function_findws }, { "FIX_ARGLIST", function_fix_arglist }, { "FIX_WIDTH", function_fix_width }, { "FLOODINFO", function_floodinfo }, { "FLOOR", function_floor }, { "FNEXIST", function_fnexist }, { "FREWIND", function_rewind }, { "FROMW", function_fromw }, { "FSEEK", function_seek }, { "FSIZE", function_fsize }, { "FSKIP", function_skip }, { "FTELL", function_tell }, { "FTIME", function_ftime }, { "FTRUNCATE", function_ftruncate }, { "FUNCTIONCALL", function_functioncall }, { "GEOM", function_geom }, { "GETARRAYS", function_getarrays }, { "GETCAP", function_getcap }, { "GETCOMMANDS", function_getcommands }, { "GETENV", function_getenv }, { "GETFUNCTIONS", function_getfunctions }, { "GETGID", function_getgid }, { "GETITEM", function_getitem }, { "GETLOGIN", function_getlogin }, { "GETMATCHES", function_getmatches }, { "GETOPT", function_getopt }, { "GETPGRP", function_getpgrp }, { "GETRMATCHES", function_getrmatches }, { "GETSERIAL", function_getserial }, { "GETSET", function_getset }, { "GETSETS", function_getsets }, { "GETTMATCH", function_gettmatch }, { "GETUID", function_getuid }, { "GLOB", function_glob }, { "GLOBI", function_globi }, { "HASH_32BIT", function_hash_32bit }, #if 0 { "HELP_TOPICS", function_help_topics }, #endif { "HOOKCTL", function_hookctl }, { "ICONVCTL", function_iconvctl }, { "IDLE", function_idle }, { "IFINDFIRST", function_ifindfirst }, { "IFINDITEM", function_ifinditem }, { "IFINDITEMS", function_ifinditems }, { "IGETITEM", function_igetitem }, { "IGETMATCHES", function_igetmatches }, { "IGETRMATCHES", function_igetrmatches }, { "IGNORECTL", function_ignorectl }, { "INDEX", function_index }, { "INDEXTOITEM", function_indextoitem }, { "INDEXTOWORD", function_indextoword }, { "INFO", function_info }, { "INPUTCTL", function_inputctl }, { "INSERT", function_insert }, { "INSERTW", function_insertw }, { "IPTOLONG", function_iptolong }, { "IPTONAME", function_iptoname }, { "IRCLIB", function_irclib }, { "IS8BIT", function_is8bit }, { "ISALPHA", function_isalpha }, { "ISAWAY", function_isaway }, { "ISCHANNEL", function_ischannel }, { "ISCHANOP", function_ischanop }, { "ISCHANVOICE", function_ischanvoice }, { "ISCONNECTED", function_isconnected }, { "ISCURCHAN", function_iscurchan }, { "ISDIGIT", function_isdigit }, { "ISDISPLAYING", function_isdisplaying }, { "ISENCRYPTED", function_isencrypted }, { "ISFILEVALID", function_isfilevalid }, { "ISHALFOP", function_ishalfop }, { "ISNUMBER", function_isnumber }, { "ISUTF8", function_isutf8 }, { "ITEMTOINDEX", function_itemtoindex }, { "JN", function_jn }, { "JOINSTR", function_joinstr }, { "JOT", function_jot }, { "JSON_ERROR", function_json_error }, { "JSON_EXPLODE", function_json_explode }, { "JSON_IMPLODE", function_json_implode }, { "JSONTEST", function_jsontest }, { "KEY", function_key }, { "KILLPID", function_killpid }, { "LASTLOG", function_lastlog }, /* lastlog.h */ { "LEFT", function_left }, { "LEFTPC", function_leftpc }, { "LEFTW", function_leftw }, { "LEVELCTL", function_levelctl }, { "LEVELWINDOW", function_levelwindow }, { "LINE", function_line }, /* lastlog.h */ { "LISTARRAY", function_listarray }, { "LISTEN", function_listen }, { "LOADINFO", function_loadinfo }, { "LOG", function_log }, { "LOG10", function_log10 }, { "LOGCTL", function_logctl }, /* logfiles.h */ { "LONGTOIP", function_longtoip }, { "MASK", function_mask }, { "MATCH", function_match }, { "MATCHITEM", function_matchitem }, { "MAXLEN", function_maxlen }, { "METRIC_TIME", function_metric_time }, { "MID", function_mid }, { "MIDW", function_midw }, { "MKDIR", function_mkdir }, { "MKTIME", function_mktime }, { "MSAR", function_msar }, { "MYCHANNELS", function_channels }, { "MYSERVERS", function_servers }, { "NAMETOIP", function_nametoip }, { "NOCHOPS", function_nochops }, { "NOHIGHLIGHT", function_nohighlight }, { "NOTIFY", function_notify }, { "NOTIFYWINDOWS", function_notifywindows }, { "NOTW", function_notw }, { "NUMARRAYS", function_numarrays }, { "NUMITEMS", function_numitems }, { "NUMLINES", function_numlines }, { "NUMONCHANNEL", function_numonchannel }, { "NUMSORT", function_numsort }, { "NUMWORDS", function_numwords }, { "ONCHANNEL", function_onchannel }, { "OPEN", function_open }, { "OUTPUTINFO", function_outputinfo }, { "PAD", function_pad }, { "PASS", function_pass }, { "PATTERN", function_pattern }, #ifdef HAVE_PERL { "PERL", function_perl }, { "PERLCALL", function_perlcall }, { "PERLXCALL", function_perlxcall }, #endif { "PLEDGE", function_pledge }, #ifdef HAVE_PYTHON { "PYDIRECT", function_pydirect }, { "PYTHON", function_python }, #endif { "PID", function_pid }, { "POP", function_pop }, { "PPID", function_ppid }, { "PREFIX", function_prefix }, { "PRINTLEN", function_printlen }, { "PUSH", function_push }, { "QUERYWIN", function_querywin }, { "QWORD", function_qword }, { "RAND", function_rand }, { "RANDREAD", function_randread }, { "READ", function_read }, { "REALPATH", function_realpath }, { "REGCOMP", function_regcomp }, { "REGCOMP_CS", function_regcomp_cs }, { "REGERROR", function_regerror }, { "REGEXEC", function_regexec }, { "REGFREE", function_regfree }, { "REGMATCHES", function_regmatches }, { "REMW", function_remw }, { "REMWS", function_remws }, { "RENAME", function_rename }, { "REPEAT", function_repeat }, { "REST", function_rest }, { "RESTW", function_restw }, { "REVERSE", function_reverse }, { "REVW", function_revw }, { "RFILTER", function_rfilter }, { "RGB", function_rgb }, { "RIGHT", function_right }, { "RIGHTW", function_rightw }, { "RINDEX", function_rindex }, { "RMATCH", function_rmatch }, { "RMATCHITEM", function_rmatchitem }, { "RMDIR", function_rmdir }, { "RPATTERN", function_rpattern }, { "RSUBSTR", function_rsubstr }, #ifdef HAVE_RUBY { "RUBY", function_ruby }, #endif { "SAR", function_sar }, { "SEQUENCE_POINT", function_sequence_point }, { "SERVERCTL", function_serverctl }, { "SERVERWIN", function_serverwin }, { "SERVPORTS", function_servports }, { "SETITEM", function_setitem }, { "SHIFT", function_shift }, { "SHIFTBRACE", function_shiftbrace }, { "SIN", function_sin }, { "SINH", function_sinh }, { "SHUFFLE", function_qshuffle }, { "SORT", function_sort }, { "SPLICE", function_splice }, { "SPLIT", function_split }, { "SPLITW", function_splitw }, { "SRAND", function_srand }, { "SSL", function_ssl }, { "STARTUPFILE", function_startupfile }, { "STAT", function_stat }, { "STATUS", function_status }, { "STATUS_ONEOFF", function_status_oneoff }, { "STIME", function_stime }, { "STRFTIME", function_strftime }, { "STRIP", function_strip }, { "STRIPANSI", function_stripansi }, { "STRIPANSICODES", function_stripansicodes }, { "STRIPC", function_stripc }, { "STRIPCRAP", function_stripcrap }, { "STRLEN", function_strlen }, { "STRPTIME", function_strptime }, { "STRTOL", function_strtol }, { "SUBSTR", function_substr }, { "SYMBOLCTL", function_symbolctl }, { "TAGS", function_tags }, { "TAN", function_tan }, { "TANH", function_tanh }, { "TDIFF", function_tdiff }, { "TDIFF2", function_tdiff2 }, { "TIME", function_time }, { "TIMERCTL", function_timerctl }, { "TOBASE", function_tobase }, { "TOLOWER", function_tolower }, { "TOUPPER", function_toupper }, { "TOW", function_tow }, { "TR", function_translate }, { "TRUNC", function_truncate }, { "TTYNAME", function_ttyname }, { "TWIDDLE", function_twiddle }, { "UHC", function_uhc }, { "UMASK", function_umask }, { "UNAME", function_uname }, { "UNICODE", function_unicode }, { "UNIQ", function_uniq }, { "UNLINK", function_unlink }, { "UNSHIFT", function_unshift }, { "UNSPLIT", function_unsplit }, { "UNVEIL", function_unveil }, { "USERHOST", function_userhost }, { "USERMODE", function_umode }, { "USETITEM", function_usetitem }, { "UTIME", function_utime }, { "UUID4", function_uuid4 }, { "VERSION", function_server_version }, { "WHICH", function_which }, { "WINCHAN", function_winchan }, { "WINDOWCTL", function_windowctl }, { "WORD", function_word }, { "WORDTOINDEX", function_wordtoindex }, { "WRITE", function_write }, { "WRITEB", function_writeb }, { "XDEBUG", function_xdebug }, { "XFORM", function_xform }, { "YN", function_yn }, { (char *) 0, NULL } }; void init_expandos (void) { int i; for (i = 0; built_in[i].name; i++) add_builtin_expando(built_in[i].name, built_in[i].func); } void init_functions (void) { int i; for (i = 0; built_in_functions[i].name; i++) add_builtin_func_alias(built_in_functions[i].name, built_in_functions[i].func); } /* * call_function has changed a little bit. Now we take the entire call * including args in the paren list. This is a bit more convenient for * the callers, since there are a bunch of them and all of them seperately * handling extracting the args is just a pain in the butt. */ char *call_function (char *name, const char *args) { char *tmp; char *result = (char *) 0; char *debug_copy = (char *) 0; char *lparen; int debugging; size_t size; char * buf; const char * alias; char * (*func) (char *) = NULL; void * arglist = NULL; size_t type; char * str = NULL; debugging = get_int_var(DEBUG_VAR); if ((lparen = strchr(name, '('))) { ssize_t span; if ((span = MatchingBracket(lparen + 1, '(', ')')) >= 0) lparen[1 + span] = 0; else yell("Unmatched lparen in function call [%s]", name); *lparen++ = 0; } else lparen = endstr(name); upper(name); type = strspn(name, ":"); name += type; str = remove_brackets(name, args); alias = get_func_alias(str, &arglist, &func); if ((type == 0 && (!func && !alias)) || (type == 1 && !alias) || (type == 2 && !func)) { if (x_debug & DEBUG_UNKNOWN) yell("Function call to non-existant alias [%s]", str); if (debugging & DEBUG_FUNCTIONS) privileged_yell("Function %s(%s) returned ", str, lparen); new_free(&str); return malloc_strdup(empty_string); } tmp = expand_alias(lparen, args); debug_copy = LOCAL_COPY(tmp); if (func && type != 1) result = func(tmp); else if (alias && type != 2) result = call_user_function(str, alias, tmp, arglist); size = strlen(str) + strlen(debug_copy) + 15; buf = (char *)alloca(size); snprintf(buf, size, "$%s(%s)", str, debug_copy); MUST_BE_MALLOCED(result, buf); if (debugging & DEBUG_FUNCTIONS) privileged_yell("Function %s(%s) returned %s", str, debug_copy, result); new_free(&str); new_free(&tmp); return result; } static int func_exist (char *command) { char * name; char * (*func) (char *); if (!command || !*command) return 0; name = LOCAL_COPY(command); upper(name); get_func_alias(name, NULL, &func); if (func == NULL) return 0; return 1; } /* * Convert a json object string into arguments as described by 'kwargs'. */ int parse_kwargs (struct kwargs *kwargs, const char *input) { cJSON *json = cJSON_Parse(input); if (json == NULL) { const char *error_ptr = cJSON_GetErrorPtr(); if (error_ptr != NULL) yell("Error before: %s\n", error_ptr); return -1; } while (kwargs && kwargs->kwarg) { const cJSON *value; value = cJSON_GetObjectItem(json, kwargs->kwarg); if (kwargs->type == KWARG_TYPE_STRING) { if (cJSON_IsInvalid(value)) { malloc_strcpy((char **)kwargs->data, empty_string); } else if (cJSON_IsFalse(value)) { malloc_strcpy((char **)kwargs->data, zero); } else if (cJSON_IsTrue(value)) { malloc_strcpy((char **)kwargs->data, one); } else if (cJSON_IsNull(value)) { malloc_strcpy((char **)kwargs->data, empty_string); } else if (cJSON_IsNumber(value)) { malloc_sprintf((char **)kwargs->data, "%f", value->valuedouble); } else if (cJSON_IsString(value) && (value->valuestring != NULL)) { malloc_strcpy((char **)kwargs->data, value->valuestring); } else if (cJSON_IsArray(value)) { malloc_strcpy((char **)kwargs->data, ""); } else if (cJSON_IsObject(value)) { malloc_strcpy((char **)kwargs->data, ""); } else if (kwargs->required) say("kwarg %s not found or was invalid", kwargs->kwarg); } if (kwargs->type == KWARG_TYPE_INTEGER) { if (cJSON_IsInvalid(value)) { *(intmax_t *)kwargs->data = 0; } else if (cJSON_IsFalse(value)) { *(intmax_t *)kwargs->data = 0; } else if (cJSON_IsTrue(value)) { *(intmax_t *)kwargs->data = 1; } else if (cJSON_IsNull(value)) { *(intmax_t *)kwargs->data = 0; } else if (cJSON_IsNumber(value)) { *(intmax_t *)kwargs->data = (intmax_t)value->valuedouble; } else if (cJSON_IsString(value) && (value->valuestring != NULL)) { char *end = NULL; *(intmax_t *)kwargs->data = (intmax_t)strtoimax(value->valuestring, &end, 0); } else if (cJSON_IsArray(value)) { *(intmax_t *)kwargs->data = 0; } else if (cJSON_IsObject(value)) { *(intmax_t *)kwargs->data = 0; } else if (kwargs->required) say("kwarg %s not found or was invalid", kwargs->kwarg); } if (kwargs->type == KWARG_TYPE_NUMBER) { if (cJSON_IsInvalid(value)) { *(long double *)kwargs->data = 0; } else if (cJSON_IsFalse(value)) { *(long double *)kwargs->data = 0; } else if (cJSON_IsTrue(value)) { *(long double *)kwargs->data = 1; } else if (cJSON_IsNull(value)) { *(long double *)kwargs->data = 0; } else if (cJSON_IsNumber(value)) { *(long double *)kwargs->data = (long double)value->valuedouble; } else if (cJSON_IsString(value) && (value->valuestring != NULL)) { char *end = NULL; *(long double *)kwargs->data = (long double)strtod(value->valuestring, &end); } else if (cJSON_IsArray(value)) { *(long double *)kwargs->data = 0; } else if (cJSON_IsObject(value)) { *(long double *)kwargs->data = 0; } else if (kwargs->required) say("kwarg %s not found or was invalid", kwargs->kwarg); } if (kwargs->type == KWARG_TYPE_BOOL) { if (cJSON_IsInvalid(value)) { *(int *)kwargs->data = 0; } else if (cJSON_IsFalse(value)) { *(int *)kwargs->data = 0; } else if (cJSON_IsTrue(value)) { *(int *)kwargs->data = 1; } else if (cJSON_IsNull(value)) { *(int *)kwargs->data = 0; } else if (cJSON_IsNumber(value)) { if (value->valuedouble) *(int *)kwargs->data = 1; else *(int *)kwargs->data = 0; } else if (cJSON_IsString(value)) { if (!value->valuestring || !*value->valuestring) *(int *)kwargs->data = 0; else if (!my_stricmp(value->valuestring, zero)) *(int *)kwargs->data = 0; else *(int *)kwargs->data = 1; } else if (cJSON_IsArray(value)) { *(int *)kwargs->data = 0; } else if (cJSON_IsObject(value)) { *(int *)kwargs->data = 0; } else if (kwargs->required) say("kwarg %s not found or was invalid", kwargs->kwarg); } kwargs++; } cJSON_Delete(json); return 0; } /* built in expando functions */ static char *alias_line (void) { return malloc_strdup(get_input()); } static char *alias_buffer (void) { return malloc_strdup(cut_buffer); } static char *alias_time (void) { return malloc_strdup(get_clock()); } static char *alias_dollar (void) { return malloc_strdup("$"); } static char *alias_detected (void) { return malloc_strdup(last_notify_nick); } static char *alias_nick (void) { return malloc_strdup((get_window_server(0) != NOSERV) ? get_server_nickname(get_window_server(0)) : empty_string); } static char *alias_away (void) { return malloc_strdup(get_server_away(from_server)); } static char *alias_sent_nick (void) { return malloc_strdup((get_server_sent_nick(from_server)) ? get_server_sent_nick(from_server) : empty_string); } static char *alias_recv_nick (void) { return malloc_strdup((get_server_recv_nick(from_server)) ? get_server_recv_nick(from_server) : empty_string); } static char *alias_msg_body (void) { return malloc_strdup((get_server_sent_body(from_server)) ? get_server_sent_body(from_server) : empty_string); } static char *alias_joined_nick (void) { return malloc_strdup((get_server_joined_nick(from_server)) ? get_server_joined_nick(from_server) : empty_string); } static char *alias_public_nick (void) { return malloc_strdup((get_server_public_nick(from_server)) ? get_server_public_nick(from_server) : empty_string); } static char *alias_show_realname (void) { return malloc_strdup( (get_window_server(0) != NOSERV) ? get_server_realname(get_window_server(0)) : empty_string); } static char *alias_version_str (void) { return malloc_strdup(irc_version); } static char *alias_invite (void) { return malloc_strdup((get_server_invite_channel(from_server)) ? get_server_invite_channel(from_server) : empty_string); } static char *alias_oper (void) { return malloc_strdup((from_server != -1) ? get_server_operator(from_server) ? get_string_var(STATUS_OPER_VAR) : empty_string : empty_string); } static char *alias_version (void) { return malloc_strdup(internal_version); } static char *alias_show_userhost (void) { return malloc_strdup(get_server_userhost(from_server)); } static char *alias_online (void) { return malloc_sprintf(NULL, INTMAX_FORMAT, (intmax_t)start_time.tv_sec); } static char *alias_idle (void) { return malloc_sprintf(NULL, INTMAX_FORMAT, (intmax_t)time(NULL) - idle_time.tv_sec); } static char *alias_current_numeric (void) { return malloc_sprintf(NULL, "%03d", current_numeric); } static char *alias_banner (void) { return malloc_strdup(banner()); } static char *alias_currdir (void) { char *tmp = (char *)new_malloc(PATH_MAX+1); if (!getcwd(tmp, PATH_MAX)) *tmp = 0; return tmp; } static char *alias_channel (void) { const char *tmp; return malloc_strdup((tmp = get_window_echannel(0)) ? tmp : zero); } static char *alias_server (void) { return malloc_strdup((parsing_server_index != NOSERV) ? get_server_itsname(parsing_server_index) : (get_window_server(0) != NOSERV) ? get_server_itsname(get_window_server(0)) : empty_string); } static char *alias_query_nick (void) { const char *tmp; return malloc_strdup((tmp = get_window_equery(0)) ? tmp : empty_string); } static char *alias_target (void) { const char *tmp; return malloc_strdup((tmp = get_window_target(0)) ? tmp : empty_string); } static char *alias_cmdchar (void) { const char *cmdchars; char tmp[2]; if ((cmdchars = get_string_var(CMDCHARS_VAR)) == (char *) 0) cmdchars = DEFAULT_CMDCHARS; tmp[0] = cmdchars[0]; tmp[1] = 0; return malloc_strdup(tmp); } static char *alias_chanop (void) { const char *tmp; return malloc_strdup(((tmp = get_window_echannel(0)) && get_channel_oper(tmp, get_window_server(0))) ? "@" : empty_string); } static char *alias_modes (void) { const char *tmp; return malloc_strdup((tmp = get_window_echannel(0)) ? get_channel_mode(tmp, get_window_server(0)) : empty_string); } static char *alias_server_version (void) { int s = from_server; if (s == NOSERV) { if (primary_server != NOSERV) s = primary_server; else return malloc_strdup(empty_string); } return malloc_strdup(get_server_version_string(s)); } /* * * * * * * * * * These are the built-in functions. About 80 of them are here, the rest are in array.c. All of the stock client's functions are supported, as well as about 60 more. Most of the 30 stock client's functions have been re-written for optimization reasons, and also to further distance ircii's code from EPIC. * * * * * * * * * */ /* * Usage: $left(number text) * Returns: the leftmost code points in . * Example: $left(5 the quick brown frog) returns "the q" * * Note: the difference between $[10]foo and $left(10 foo) is that the former * is padded and the latter is not. * * Note: This function counts code points, not columns! So non-printable * codepoints (like ^B/^V/^C) still count! */ BUILT_IN_FUNCTION(function_left, word) { int keepers, /* The number of CPs to retain */ count, /* How many we've copied so far */ code_point; /* The current CP we're working on */ char * s; /* Pointer at next CP */ ptrdiff_t offset; GET_INT_ARG(keepers, word); RETURN_IF_EMPTY(word); if (keepers <= 0) RETURN_EMPTY; /* Return the whole string if it's "short" */ if (keepers >= quick_code_point_count(word)) RETURN_STR(word); count = 0; s = word; while ((code_point = next_code_point2(s, &offset, 0))) { /* Invalid CPs count as 1, + we skip them. */ if (code_point == -1) s++; else s += offset; if (++count >= keepers) break; } /* Chop the string off here */ *s = 0; RETURN_STR(word); } /* * Usage: $right(number text) * Returns: the rightmost characters in . * Example: $right(5 the quick brown frog) returns " frog" * XXX This function should use previous_code_point() like $rest() does. */ BUILT_IN_FUNCTION(function_right, word) { int keepers, /* The number of CPs to retain */ code_point, /* The current CP we're working on */ total, /* How many CPs are in word */ ignores; /* Leading CPs to ignore */ char *s; /* Pointer at next CP */ ptrdiff_t offset; GET_INT_ARG(keepers, word); RETURN_IF_EMPTY(word); if (keepers <= 0) RETURN_EMPTY; /* Return the whole string if it's "short" */ if (keepers >= ((total = quick_code_point_count(word)))) RETURN_STR(word); /* Skip the first 'ignores' CPs */ ignores = total - keepers; s = word; while ((code_point = next_code_point2(s, &offset, 0))) { /* Invalid CPs count as 1, + we skip them. */ if (code_point == -1) s++; else s += offset; if (--ignores <= 0) break; } RETURN_STR((char *)s); } /* * Usage: $mid(start number text) * Returns: the th through +th characters in . * Example: $mid(3 4 the quick brown frog) returns " qui" * * Note: the first character is numbered zero. * XXX It's a shame this isn't generalized and shared with other funcs. */ BUILT_IN_FUNCTION(function_mid, word) { int keepers, /* The number of CPs to retain */ count, /* How many we've copied so far */ code_point; /* The current CP we're working on */ int start; char *s; /* Pointer at next CP */ char *retval; ptrdiff_t offset; GET_INT_ARG(start, word); GET_INT_ARG(keepers, word); RETURN_IF_EMPTY(word); if (keepers <= 0) RETURN_EMPTY; if (start < 0) RETURN_EMPTY; if (start > quick_code_point_count(word)) RETURN_EMPTY; /* Skip the initial CPs */ for (s = word, count = 0; count < start; count++) { /* Invalid CPs count as 1, and we skip them. */ code_point = next_code_point2(s, &offset, 0); if (code_point == -1) s++; else s += offset; } /* This is our anchor */ retval = (char *)s; /* Return the whole string if it's "short" */ if (keepers >= quick_code_point_count(retval)) RETURN_STR(retval); /* Otherwise count off 'keepers' CPs */ count = 0; s = retval; while ((code_point = next_code_point2(s, &offset, 0))) { /* Invalid CPs count as 1, + we skip them. */ if (code_point == -1) s++; else s += offset; if (++count >= keepers) break; } /* Chop the string off here */ *s = 0; RETURN_STR(retval); } /* * Usage: $rand(max) * Returns: A random number from zero to max-1. * Example: $rand(10) might return any number from 0 to 9. */ BUILT_IN_FUNCTION(function_rand, word) { unsigned long tempin, ret; static unsigned long max = 0, rn = 0; GET_INT_ARG(tempin, word); if (tempin == 0) ret = random_number(0); else { if (max < tempin) rn ^= random_number(0), max = -1; ret = rn % tempin; max /= tempin; rn /= tempin; } RETURN_INT(ret); } /* * Usage: $srand(seed) * Returns: Nothing. * Side effect: seeds the random number generater. * Note: the argument is ignored. */ BUILT_IN_FUNCTION(function_srand, word) { random_number(time(NULL)); RETURN_EMPTY; } /* * Usage: $time() * Returns: The number of seconds that has elapsed since Jan 1, 1970, GMT. * Example: $time() returned something around 802835348 at the time I * wrote this comment. */ BUILT_IN_FUNCTION(function_time, input) { RETURN_INT(time(NULL)); } /* * Usage: $stime(time) * Returns: The human-readable form of the date based on the