diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | pygments/lexers/__init__.py | 2 | ||||
-rw-r--r-- | pygments/lexers/special.py | 25 | ||||
-rw-r--r-- | tests/examplefiles/example.c | 20146 | ||||
-rw-r--r-- | tests/examplefiles/example.cpp | 7300 | ||||
-rw-r--r-- | tests/examplefiles/example.rb | 2514 | ||||
-rw-r--r-- | tests/examplefiles/pleac.in.rb | 3409 | ||||
-rw-r--r-- | tests/examplefiles/test.html | 3553 | ||||
-rw-r--r-- | tests/test_basic_api.py | 80 | ||||
-rw-r--r-- | tests/test_clexer.py | 2 |
10 files changed, 96 insertions, 36937 deletions
@@ -64,4 +64,4 @@ reindent: @$(PYTHON) scripts/reindent.py -r -B . test: - @$(PYTHON) tests/run.py + @$(PYTHON) tests/run.py $(TESTS) diff --git a/pygments/lexers/__init__.py b/pygments/lexers/__init__.py index 3b405f88..96e68a28 100644 --- a/pygments/lexers/__init__.py +++ b/pygments/lexers/__init__.py @@ -91,7 +91,7 @@ def _iter_lexerclasses(): """ Returns an iterator over all lexer classes. """ - for module_name, name, _, _ in LEXERS.itervalues(): + for module_name, name, _, _, _ in LEXERS.itervalues(): if name not in _lexer_cache: _load_lexers(module_name) yield _lexer_cache[name] diff --git a/pygments/lexers/special.py b/pygments/lexers/special.py index 621145a2..dcf9899c 100644 --- a/pygments/lexers/special.py +++ b/pygments/lexers/special.py @@ -13,7 +13,7 @@ import re import cStringIO from pygments.lexer import Lexer, RegexLexer -from pygments.token import Token, \ +from pygments.token import Token, Error, \ Text, Comment, Operator, Keyword, Name, String, Number @@ -66,14 +66,19 @@ class RawTokenLexer(Lexer): def get_tokens_unprocessed(self, text): length = 0 for match in line_re.finditer(text): - ttypestr, val = match.group().split('\t', 1) - ttype = _ttype_cache.get(ttypestr) - if not ttype: - ttype = Token - ttypes = ttypestr.split('.')[1:] - for ttype_ in ttypes: - ttype = getattr(ttype, ttype_) - _ttype_cache[ttypestr] = ttype - val = val[1:-2].decode('string-escape') + try: + ttypestr, val = match.group().split('\t', 1) + except ValueError: + val = match.group() + ttype = Error + else: + ttype = _ttype_cache.get(ttypestr) + if not ttype: + ttype = Token + ttypes = ttypestr.split('.')[1:] + for ttype_ in ttypes: + ttype = getattr(ttype, ttype_) + _ttype_cache[ttypestr] = ttype + val = val[1:-2].decode('string-escape') yield length, ttype, val length += len(val) diff --git a/tests/examplefiles/example.c b/tests/examplefiles/example.c index bbd1a75c..9f9c477d 100644 --- a/tests/examplefiles/example.c +++ b/tests/examplefiles/example.c @@ -9841,20149 +9841,3 @@ aix_loaderror(const char *pathname) #endif /* NO_DLN_LOAD */ -void* -dln_load(file) - const char *file; -{ -#ifdef NO_DLN_LOAD - rb_raise(rb_eLoadError, "this executable file can't load extension libraries"); -#else - -#if !defined(_AIX) && !defined(NeXT) - const char *error = 0; -#define DLN_ERROR() (error = dln_strerror(), strcpy(ALLOCA_N(char, strlen(error) + 1), error)) -#endif - -#if defined _WIN32 && !defined __CYGWIN__ - HINSTANCE handle; - char winfile[MAXPATHLEN]; - void (*init_fct)(); - char *buf; - - if (strlen(file) >= MAXPATHLEN) rb_loaderror("filename too long"); - - /* Load the file as an object one */ - init_funcname(&buf, file); - - strcpy(winfile, file); - - /* Load file */ - if ((handle = LoadLibrary(winfile)) == NULL) { - error = dln_strerror(); - goto failed; - } - - if ((init_fct = (void(*)())GetProcAddress(handle, buf)) == NULL) { - rb_loaderror("%s - %s\n%s", dln_strerror(), buf, file); - } - - /* Call the init code */ - (*init_fct)(); - return handle; -#else -#ifdef USE_DLN_A_OUT - if (load(file) == -1) { - error = dln_strerror(); - goto failed; - } - return 0; -#else - - char *buf; - /* Load the file as an object one */ - init_funcname(&buf, file); - -#ifdef USE_DLN_DLOPEN -#define DLN_DEFINED - { - void *handle; - void (*init_fct)(); - -#ifndef RTLD_LAZY -# define RTLD_LAZY 1 -#endif -#ifdef __INTERIX -# undef RTLD_GLOBAL -#endif -#ifndef RTLD_GLOBAL -# define RTLD_GLOBAL 0 -#endif - - /* Load file */ - if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) { - error = dln_strerror(); - goto failed; - } - - init_fct = (void(*)())dlsym(handle, buf); - if (init_fct == NULL) { - error = DLN_ERROR(); - dlclose(handle); - goto failed; - } - /* Call the init code */ - (*init_fct)(); - - return handle; - } -#endif /* USE_DLN_DLOPEN */ - -#ifdef __hpux -#define DLN_DEFINED - { - shl_t lib = NULL; - int flags; - void (*init_fct)(); - - flags = BIND_DEFERRED; - lib = shl_load(file, flags, 0); - if (lib == NULL) { - extern int errno; - rb_loaderror("%s - %s", strerror(errno), file); - } - shl_findsym(&lib, buf, TYPE_PROCEDURE, (void*)&init_fct); - if (init_fct == NULL) { - shl_findsym(&lib, buf, TYPE_UNDEFINED, (void*)&init_fct); - if (init_fct == NULL) { - errno = ENOSYM; - rb_loaderror("%s - %s", strerror(ENOSYM), file); - } - } - (*init_fct)(); - return (void*)lib; - } -#endif /* hpux */ - -#if defined(_AIX) && ! defined(_IA64) -#define DLN_DEFINED - { - void (*init_fct)(); - - init_fct = (void(*)())load((char*)file, 1, 0); - if (init_fct == NULL) { - aix_loaderror(file); - } - if (loadbind(0, (void*)dln_load, (void*)init_fct) == -1) { - aix_loaderror(file); - } - (*init_fct)(); - return (void*)init_fct; - } -#endif /* _AIX */ - -#if defined(NeXT) || defined(__APPLE__) -#define DLN_DEFINED -/*---------------------------------------------------- - By SHIROYAMA Takayuki Psi@fortune.nest.or.jp - - Special Thanks... - Yu tomoak-i@is.aist-nara.ac.jp, - Mi hisho@tasihara.nest.or.jp, - sunshine@sunshineco.com, - and... Miss ARAI Akino(^^;) - ----------------------------------------------------*/ -#if defined(NeXT) && (NS_TARGET_MAJOR < 4)/* NeXTSTEP rld functions */ - - { - NXStream* s; - unsigned long init_address; - char *object_files[2] = {NULL, NULL}; - - void (*init_fct)(); - - object_files[0] = (char*)file; - - s = NXOpenFile(2,NX_WRITEONLY); - - /* Load object file, if return value ==0 , load failed*/ - if(rld_load(s, NULL, object_files, NULL) == 0) { - NXFlush(s); - NXClose(s); - rb_loaderror("Failed to load %.200s", file); - } - - /* lookup the initial function */ - if(rld_lookup(s, buf, &init_address) == 0) { - NXFlush(s); - NXClose(s); - rb_loaderror("Failed to lookup Init function %.200s", file); - } - - NXFlush(s); - NXClose(s); - - /* Cannot call *init_address directory, so copy this value to - funtion pointer */ - init_fct = (void(*)())init_address; - (*init_fct)(); - return (void*)init_address; - } -#else/* OPENSTEP dyld functions */ - { - int dyld_result; - NSObjectFileImage obj_file; /* handle, but not use it */ - /* "file" is module file name . - "buf" is pointer to initial function name with "_" . */ - - void (*init_fct)(); - - - dyld_result = NSCreateObjectFileImageFromFile(file, &obj_file); - - if (dyld_result != NSObjectFileImageSuccess) { - rb_loaderror("Failed to load %.200s", file); - } - - NSLinkModule(obj_file, file, NSLINKMODULE_OPTION_BINDNOW); - - /* lookup the initial function */ - if(!NSIsSymbolNameDefined(buf)) { - rb_loaderror("Failed to lookup Init function %.200s",file); - } - init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf)); - (*init_fct)(); - - return (void*)init_fct; - } -#endif /* rld or dyld */ -#endif - -#ifdef __BEOS__ -# define DLN_DEFINED - { - status_t err_stat; /* BeOS error status code */ - image_id img_id; /* extention module unique id */ - void (*init_fct)(); /* initialize function for extention module */ - - /* load extention module */ - img_id = load_add_on(file); - if (img_id <= 0) { - rb_loaderror("Failed to load %.200s", file); - } - - /* find symbol for module initialize function. */ - /* The Be Book KernelKit Images section described to use - B_SYMBOL_TYPE_TEXT for symbol of function, not - B_SYMBOL_TYPE_CODE. Why ? */ - /* strcat(init_fct_symname, "__Fv"); */ /* parameter nothing. */ - /* "__Fv" dont need! The Be Book Bug ? */ - err_stat = get_image_symbol(img_id, buf, - B_SYMBOL_TYPE_TEXT, (void **)&init_fct); - - if (err_stat != B_NO_ERROR) { - char real_name[MAXPATHLEN]; - - strcpy(real_name, buf); - strcat(real_name, "__Fv"); - err_stat = get_image_symbol(img_id, real_name, - B_SYMBOL_TYPE_TEXT, (void **)&init_fct); - } - - if ((B_BAD_IMAGE_ID == err_stat) || (B_BAD_INDEX == err_stat)) { - unload_add_on(img_id); - rb_loaderror("Failed to lookup Init function %.200s", file); - } - else if (B_NO_ERROR != err_stat) { - char errmsg[] = "Internal of BeOS version. %.200s (symbol_name = %s)"; - unload_add_on(img_id); - rb_loaderror(errmsg, strerror(err_stat), buf); - } - - /* call module initialize function. */ - (*init_fct)(); - return (void*)img_id; - } -#endif /* __BEOS__*/ - -#ifdef __MACOS__ -# define DLN_DEFINED - { - OSErr err; - FSSpec libspec; - CFragConnectionID connID; - Ptr mainAddr; - char errMessage[1024]; - Boolean isfolder, didsomething; - Str63 fragname; - Ptr symAddr; - CFragSymbolClass class; - void (*init_fct)(); - char fullpath[MAXPATHLEN]; - - strcpy(fullpath, file); - - /* resolve any aliases to find the real file */ - c2pstr(fullpath); - (void)FSMakeFSSpec(0, 0, fullpath, &libspec); - err = ResolveAliasFile(&libspec, 1, &isfolder, &didsomething); - if (err) { - rb_loaderror("Unresolved Alias - %s", file); - } - - /* Load the fragment (or return the connID if it is already loaded */ - fragname[0] = 0; - err = GetDiskFragment(&libspec, 0, 0, fragname, - kLoadCFrag, &connID, &mainAddr, - errMessage); - if (err) { - p2cstr(errMessage); - rb_loaderror("%s - %s",errMessage , file); - } - - /* Locate the address of the correct init function */ - c2pstr(buf); - err = FindSymbol(connID, buf, &symAddr, &class); - if (err) { - rb_loaderror("Unresolved symbols - %s" , file); - } - init_fct = (void (*)())symAddr; - (*init_fct)(); - return (void*)init_fct; - } -#endif /* __MACOS__ */ - -#if defined(__VMS) -#define DLN_DEFINED - { - void *handle, (*init_fct)(); - char *fname, *p1, *p2; - - fname = (char *)__alloca(strlen(file)+1); - strcpy(fname,file); - if (p1 = strrchr(fname,'/')) - fname = p1 + 1; - if (p2 = strrchr(fname,'.')) - *p2 = '\0'; - - if ((handle = (void*)dlopen(fname, 0)) == NULL) { - error = dln_strerror(); - goto failed; - } - - if ((init_fct = (void (*)())dlsym(handle, buf)) == NULL) { - error = DLN_ERROR(); - dlclose(handle); - goto failed; - } - /* Call the init code */ - (*init_fct)(); - return handle; - } -#endif /* __VMS */ - -#ifndef DLN_DEFINED - rb_notimplement(); -#endif - -#endif /* USE_DLN_A_OUT */ -#endif -#if !defined(_AIX) && !defined(NeXT) - failed: - rb_loaderror("%s - %s", error, file); -#endif - -#endif /* NO_DLN_LOAD */ - return 0; /* dummy return */ -} - -static char *dln_find_1(); - -char * -dln_find_exe(fname, path) - const char *fname; - const char *path; -{ - if (!path) { - path = getenv(PATH_ENV); - } - - if (!path) { -#if defined(MSDOS) || defined(_WIN32) || defined(__human68k__) || defined(__MACOS__) - path = "/usr/local/bin;/usr/ucb;/usr/bin;/bin;."; -#else - path = "/usr/local/bin:/usr/ucb:/usr/bin:/bin:."; -#endif - } - return dln_find_1(fname, path, 1); -} - -char * -dln_find_file(fname, path) - const char *fname; - const char *path; -{ -#ifndef __MACOS__ - if (!path) path = "."; - return dln_find_1(fname, path, 0); -#else - if (!path) path = "."; - return _macruby_path_conv_posix_to_macos(dln_find_1(fname, path, 0)); -#endif -} - -#if defined(__CYGWIN32__) -const char * -conv_to_posix_path(win32, posix, len) - char *win32; - char *posix; - int len; -{ - char *first = win32; - char *p = win32; - char *dst = posix; - - for (p = win32; *p; p++) - if (*p == ';') { - *p = 0; - cygwin32_conv_to_posix_path(first, posix); - posix += strlen(posix); - *posix++ = ':'; - first = p + 1; - *p = ';'; - } - if (len < strlen(first)) - fprintf(stderr, "PATH length too long: %s\n", first); - else - cygwin32_conv_to_posix_path(first, posix); - return dst; -} -#endif - -static char fbuf[MAXPATHLEN]; - -static char * -dln_find_1(fname, path, exe_flag) - char *fname; - char *path; - int exe_flag; /* non 0 if looking for executable. */ -{ - register char *dp; - register char *ep; - register char *bp; - struct stat st; -#ifdef __MACOS__ - const char* mac_fullpath; -#endif - - if (!fname) return fname; - if (fname[0] == '/') return fname; - if (strncmp("./", fname, 2) == 0 || strncmp("../", fname, 3) == 0) - return fname; - if (exe_flag && strchr(fname, '/')) return fname; -#ifdef DOSISH - if (fname[0] == '\\') return fname; -# ifdef DOSISH_DRIVE_LETTER - if (strlen(fname) > 2 && fname[1] == ':') return fname; -# endif - if (strncmp(".\\", fname, 2) == 0 || strncmp("..\\", fname, 3) == 0) - return fname; - if (exe_flag && strchr(fname, '\\')) return fname; -#endif - - for (dp = path;; dp = ++ep) { - register int l; - int i; - int fspace; - - /* extract a component */ - ep = strchr(dp, PATH_SEP[0]); - if (ep == NULL) - ep = dp+strlen(dp); - - /* find the length of that component */ - l = ep - dp; - bp = fbuf; - fspace = sizeof fbuf - 2; - if (l > 0) { - /* - ** If the length of the component is zero length, - ** start from the current directory. If the - ** component begins with "~", start from the - ** user's $HOME environment variable. Otherwise - ** take the path literally. - */ - - if (*dp == '~' && (l == 1 || -#if defined(DOSISH) - dp[1] == '\\' || -#endif - dp[1] == '/')) { - char *home; - - home = getenv("HOME"); - if (home != NULL) { - i = strlen(home); - if ((fspace -= i) < 0) - goto toolong; - memcpy(bp, home, i); - bp += i; - } - dp++; - l--; - } - if (l > 0) { - if ((fspace -= l) < 0) - goto toolong; - memcpy(bp, dp, l); - bp += l; - } - - /* add a "/" between directory and filename */ - if (ep[-1] != '/') - *bp++ = '/'; - } - - /* now append the file name */ - i = strlen(fname); - if ((fspace -= i) < 0) { - toolong: - fprintf(stderr, "openpath: pathname too long (ignored)\n"); - *bp = '\0'; - fprintf(stderr, "\tDirectory \"%s\"\n", fbuf); - fprintf(stderr, "\tFile \"%s\"\n", fname); - goto next; - } - memcpy(bp, fname, i + 1); - -#ifndef __MACOS__ - if (stat(fbuf, &st) == 0) { - if (exe_flag == 0) return fbuf; - /* looking for executable */ - if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0) - return fbuf; - } -#else - if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf)) { - if (exe_flag == 0) return mac_fullpath; - /* looking for executable */ - if (stat(mac_fullpath, &st) == 0) { - if (!S_ISDIR(st.st_mode) && eaccess(mac_fullpath, X_OK) == 0) - return mac_fullpath; - } - } -#endif -#if defined(DOSISH) - if (exe_flag) { - static const char *extension[] = { -#if defined(MSDOS) - ".com", ".exe", ".bat", -#if defined(DJGPP) - ".btm", ".sh", ".ksh", ".pl", ".sed", -#endif -#elif defined(__EMX__) || defined(_WIN32) - ".exe", ".com", ".cmd", ".bat", -/* end of __EMX__ or _WIN32 */ -#else - ".r", ".R", ".x", ".X", ".bat", ".BAT", -/* __human68k__ */ -#endif - (char *) NULL - }; - int j; - - for (j = 0; extension[j]; j++) { - if (fspace < strlen(extension[j])) { - fprintf(stderr, "openpath: pathname too long (ignored)\n"); - fprintf(stderr, "\tDirectory \"%.*s\"\n", (int) (bp - fbuf), fbuf); - fprintf(stderr, "\tFile \"%s%s\"\n", fname, extension[j]); - continue; - } - strcpy(bp + i, extension[j]); -#ifndef __MACOS__ - if (stat(fbuf, &st) == 0) - return fbuf; -#else - if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf)) - return mac_fullpath; - -#endif - } - } -#endif /* MSDOS or _WIN32 or __human68k__ or __EMX__ */ - - next: - /* if not, and no other alternatives, life is bleak */ - if (*ep == '\0') { - return NULL; - } - - /* otherwise try the next component in the search path */ - } -} -#define NO_DLN_LOAD 1 -#include "dln.c" -void -Init_ext() -{ -} -/********************************************************************** - - enum.c - - - $Author: murphy $ - $Date: 2005-11-05 04:33:55 +0100 (Sa, 05 Nov 2005) $ - created at: Fri Oct 1 15:15:19 JST 1993 - - Copyright (C) 1993-2003 Yukihiro Matsumoto - -**********************************************************************/ - -#include "ruby.h" -#include "node.h" -#include "util.h" - -VALUE rb_mEnumerable; -static ID id_each, id_eqq, id_cmp; - -VALUE -rb_each(obj) - VALUE obj; -{ - return rb_funcall(obj, id_each, 0, 0); -} - -static VALUE -grep_i(i, arg) - VALUE i, *arg; -{ - if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) { - rb_ary_push(arg[1], i); - } - return Qnil; -} - -static VALUE -grep_iter_i(i, arg) - VALUE i, *arg; -{ - if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) { - rb_ary_push(arg[1], rb_yield(i)); - } - return Qnil; -} - -/* - * call-seq: - * enum.grep(pattern) => array - * enum.grep(pattern) {| obj | block } => array - * - * Returns an array of every element in <i>enum</i> for which - * <code>Pattern === element</code>. If the optional <em>block</em> is - * supplied, each matching element is passed to it, and the block's - * result is stored in the output array. - * - * (1..100).grep 38..44 #=> [38, 39, 40, 41, 42, 43, 44] - * c = IO.constants - * c.grep(/SEEK/) #=> ["SEEK_END", "SEEK_SET", "SEEK_CUR"] - * res = c.grep(/SEEK/) {|v| IO.const_get(v) } - * res #=> [2, 0, 1] - * - */ - -static VALUE -enum_grep(obj, pat) - VALUE obj, pat; -{ - VALUE ary = rb_ary_new(); - VALUE arg[2]; - - arg[0] = pat; - arg[1] = ary; - - rb_iterate(rb_each, obj, rb_block_given_p() ? grep_iter_i : grep_i, (VALUE)arg); - - return ary; -} - -static VALUE -find_i(i, memo) - VALUE i; - NODE *memo; -{ - if (RTEST(rb_yield(i))) { - memo->u2.value = Qtrue; - memo->u1.value = i; - rb_iter_break(); - } - return Qnil; -} - -/* - * call-seq: - * enum.detect(ifnone = nil) {| obj | block } => obj or nil - * enum.find(ifnone = nil) {| obj | block } => obj or nil - * - * Passes each entry in <i>enum</i> to <em>block</em>. Returns the - * first for which <em>block</em> is not <code>false</code>. If no - * object matches, calls <i>ifnone</i> and returns its result when it - * is specified, or returns <code>nil</code> - * - * (1..10).detect {|i| i % 5 == 0 and i % 7 == 0 } #=> nil - * (1..100).detect {|i| i % 5 == 0 and i % 7 == 0 } #=> 35 - * - */ - -static VALUE -enum_find(argc, argv, obj) - int argc; - VALUE* argv; - VALUE obj; -{ - NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, Qfalse, 0); - VALUE if_none; - - rb_scan_args(argc, argv, "01", &if_none); - rb_iterate(rb_each, obj, find_i, (VALUE)memo); - if (memo->u2.value) { - return memo->u1.value; - } - if (!NIL_P(if_none)) { - return rb_funcall(if_none, rb_intern("call"), 0, 0); - } - return Qnil; -} - -static VALUE -find_all_i(i, ary) - VALUE i, ary; -{ - if (RTEST(rb_yield(i))) { - rb_ary_push(ary, i); - } - return Qnil; -} - -/* - * call-seq: - * enum.find_all {| obj | block } => array - * enum.select {| obj | block } => array - * - * Returns an array containing all elements of <i>enum</i> for which - * <em>block</em> is not <code>false</code> (see also - * <code>Enumerable#reject</code>). - * - * (1..10).find_all {|i| i % 3 == 0 } #=> [3, 6, 9] - * - */ - -static VALUE -enum_find_all(obj) - VALUE obj; -{ - VALUE ary = rb_ary_new(); - - rb_iterate(rb_each, obj, find_all_i, ary); - - return ary; -} - -static VALUE -reject_i(i, ary) - VALUE i, ary; -{ - if (!RTEST(rb_yield(i))) { - rb_ary_push(ary, i); - } - return Qnil; -} - -/* - * call-seq: - * enum.reject {| obj | block } => array - * - * Returns an array for all elements of <i>enum</i> for which - * <em>block</em> is false (see also <code>Enumerable#find_all</code>). - * - * (1..10).reject {|i| i % 3 == 0 } #=> [1, 2, 4, 5, 7, 8, 10] - * - */ - -static VALUE -enum_reject(obj) - VALUE obj; -{ - VALUE ary = rb_ary_new(); - - rb_iterate(rb_each, obj, reject_i, ary); - - return ary; -} - -static VALUE -collect_i(i, ary) - VALUE i, ary; -{ - rb_ary_push(ary, rb_yield(i)); - - return Qnil; -} - -static VALUE -collect_all(i, ary) - VALUE i, ary; -{ - rb_ary_push(ary, i); - - return Qnil; -} - -/* - * call-seq: - * enum.collect {| obj | block } => array - * enum.map {| obj | block } => array - * - * Returns a new array with the results of running <em>block</em> once - * for every element in <i>enum</i>. - * - * (1..4).collect {|i| i*i } #=> [1, 4, 9, 16] - * (1..4).collect { "cat" } #=> ["cat", "cat", "cat", "cat"] - * - */ - -static VALUE -enum_collect(obj) - VALUE obj; -{ - VALUE ary = rb_ary_new(); - - rb_iterate(rb_each, obj, rb_block_given_p() ? collect_i : collect_all, ary); - - return ary; -} - -/* - * call-seq: - * enum.to_a => array - * enum.entries => array - * - * Returns an array containing the items in <i>enum</i>. - * - * (1..7).to_a #=> [1, 2, 3, 4, 5, 6, 7] - * { 'a'=>1, 'b'=>2, 'c'=>3 }.to_a #=> [["a", 1], ["b", 2], ["c", 3]] - */ -static VALUE -enum_to_a(obj) - VALUE obj; -{ - VALUE ary = rb_ary_new(); - - rb_iterate(rb_each, obj, collect_all, ary); - - return ary; -} - -static VALUE -inject_i(i, memo) - VALUE i; - NODE *memo; -{ - if (memo->u2.value) { - memo->u2.value = Qfalse; - memo->u1.value = i; - } - else { - memo->u1.value = rb_yield_values(2, memo->u1.value, i); - } - return Qnil; -} - -/* - * call-seq: - * enum.inject(initial) {| memo, obj | block } => obj - * enum.inject {| memo, obj | block } => obj - * - * Combines the elements of <i>enum</i> by applying the block to an - * accumulator value (<i>memo</i>) and each element in turn. At each - * step, <i>memo</i> is set to the value returned by the block. The - * first form lets you supply an initial value for <i>memo</i>. The - * second form uses the first element of the collection as a the - * initial value (and skips that element while iterating). - * - * # Sum some numbers - * (5..10).inject {|sum, n| sum + n } #=> 45 - * # Multiply some numbers - * (5..10).inject(1) {|product, n| product * n } #=> 151200 - * - * # find the longest word - * longest = %w{ cat sheep bear }.inject do |memo,word| - * memo.length > word.length ? memo : word - * end - * longest #=> "sheep" - * - * # find the length of the longest word - * longest = %w{ cat sheep bear }.inject(0) do |memo,word| - * memo >= word.length ? memo : word.length - * end - * longest #=> 5 - * - */ - -static VALUE -enum_inject(argc, argv, obj) - int argc; - VALUE *argv, obj; -{ - NODE *memo; - VALUE n; - - if (rb_scan_args(argc, argv, "01", &n) == 1) { - memo = rb_node_newnode(NODE_MEMO, n, Qfalse, 0); - } - else { - memo = rb_node_newnode(NODE_MEMO, Qnil, Qtrue, 0); - } - rb_iterate(rb_each, obj, inject_i, (VALUE)memo); - n = memo->u1.value; - return n; -} - -static VALUE -partition_i(i, ary) - VALUE i, *ary; -{ - if (RTEST(rb_yield(i))) { - rb_ary_push(ary[0], i); - } - else { - rb_ary_push(ary[1], i); - } - return Qnil; -} - -/* - * call-seq: - * enum.partition {| obj | block } => [ true_array, false_array ] - * - * Returns two arrays, the first containing the elements of - * <i>enum</i> for which the block evaluates to true, the second - * containing the rest. - * - * (1..6).partition {|i| (i&1).zero?} #=> [[2, 4, 6], [1, 3, 5]] - * - */ - -static VALUE -enum_partition(obj) - VALUE obj; -{ - VALUE ary[2]; - - ary[0] = rb_ary_new(); - ary[1] = rb_ary_new(); - rb_iterate(rb_each, obj, partition_i, (VALUE)ary); - - return rb_assoc_new(ary[0], ary[1]); -} - -/* - * call-seq: - * enum.sort => array - * enum.sort {| a, b | block } => array - * - * Returns an array containing the items in <i>enum</i> sorted, - * either according to their own <code><=></code> method, or by using - * the results of the supplied block. The block should return -1, 0, or - * +1 depending on the comparison between <i>a</i> and <i>b</i>. As of - * Ruby 1.8, the method <code>Enumerable#sort_by</code> implements a - * built-in Schwartzian Transform, useful when key computation or - * comparison is expensive.. - * - * %w(rhea kea flea).sort #=> ["flea", "kea", "rhea"] - * (1..10).sort {|a,b| b <=> a} #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] - */ - -static VALUE -enum_sort(obj) - VALUE obj; -{ - return rb_ary_sort(enum_to_a(obj)); -} - -static VALUE -sort_by_i(i, ary) - VALUE i, ary; -{ - VALUE v; - NODE *memo; - - v = rb_yield(i); - if (RBASIC(ary)->klass) { - rb_raise(rb_eRuntimeError, "sort_by reentered"); - } - memo = rb_node_newnode(NODE_MEMO, v, i, 0); - rb_ary_push(ary, (VALUE)memo); - return Qnil; -} - -static int -sort_by_cmp(aa, bb) - NODE **aa, **bb; -{ - VALUE a = aa[0]->u1.value; - VALUE b = bb[0]->u1.value; - - return rb_cmpint(rb_funcall(a, id_cmp, 1, b), a, b); -} - -/* - * call-seq: - * enum.sort_by {| obj | block } => array - * - * Sorts <i>enum</i> using a set of keys generated by mapping the - * values in <i>enum</i> through the given block. - * - * %w{ apple pear fig }.sort_by {|word| word.length} - #=> ["fig", "pear", "apple"] - * - * The current implementation of <code>sort_by</code> generates an - * array of tuples containing the original collection element and the - * mapped value. This makes <code>sort_by</code> fairly expensive when - * the keysets are simple - * - * require 'benchmark' - * include Benchmark - * - * a = (1..100000).map {rand(100000)} - * - * bm(10) do |b| - * b.report("Sort") { a.sort } - * b.report("Sort by") { a.sort_by {|a| a} } - * end - * - * <em>produces:</em> - * - * user system total real - * Sort 0.180000 0.000000 0.180000 ( 0.175469) - * Sort by 1.980000 0.040000 2.020000 ( 2.013586) - * - * However, consider the case where comparing the keys is a non-trivial - * operation. The following code sorts some files on modification time - * using the basic <code>sort</code> method. - * - * files = Dir["*"] - * sorted = files.sort {|a,b| File.new(a).mtime <=> File.new(b).mtime} - * sorted #=> ["mon", "tues", "wed", "thurs"] - * - * This sort is inefficient: it generates two new <code>File</code> - * objects during every comparison. A slightly better technique is to - * use the <code>Kernel#test</code> method to generate the modification - * times directly. - * - * files = Dir["*"] - * sorted = files.sort { |a,b| - * test(?M, a) <=> test(?M, b) - * } - * sorted #=> ["mon", "tues", "wed", "thurs"] - * - * This still generates many unnecessary <code>Time</code> objects. A - * more efficient technique is to cache the sort keys (modification - * times in this case) before the sort. Perl users often call this - * approach a Schwartzian Transform, after Randal Schwartz. We - * construct a temporary array, where each element is an array - * containing our sort key along with the filename. We sort this array, - * and then extract the filename from the result. - * - * sorted = Dir["*"].collect { |f| - * [test(?M, f), f] - * }.sort.collect { |f| f[1] } - * sorted #=> ["mon", "tues", "wed", "thurs"] - * - * This is exactly what <code>sort_by</code> does internally. - * - * sorted = Dir["*"].sort_by {|f| test(?M, f)} - * sorted #=> ["mon", "tues", "wed", "thurs"] - */ - -static VALUE -enum_sort_by(obj) - VALUE obj; -{ - VALUE ary; - long i; - - if (TYPE(obj) == T_ARRAY) { - ary = rb_ary_new2(RARRAY(obj)->len); - } - else { - ary = rb_ary_new(); - } - RBASIC(ary)->klass = 0; - rb_iterate(rb_each, obj, sort_by_i, ary); - if (RARRAY(ary)->len > 1) { - qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE), sort_by_cmp, 0); - } - if (RBASIC(ary)->klass) { - rb_raise(rb_eRuntimeError, "sort_by reentered"); - } - for (i=0; i<RARRAY(ary)->len; i++) { - RARRAY(ary)->ptr[i] = RNODE(RARRAY(ary)->ptr[i])->u2.value; - } - RBASIC(ary)->klass = rb_cArray; - return ary; -} - -static VALUE -all_iter_i(i, memo) - VALUE i; - NODE *memo; -{ - if (!RTEST(rb_yield(i))) { - memo->u1.value = Qfalse; - rb_iter_break(); - } - return Qnil; -} - -static VALUE -all_i(i, memo) - VALUE i; - NODE *memo; -{ - if (!RTEST(i)) { - memo->u1.value = Qfalse; - rb_iter_break(); - } - return Qnil; -} - -/* - * call-seq: - * enum.all? [{|obj| block } ] => true or false - * - * Passes each element of the collection to the given block. The method - * returns <code>true</code> if the block never returns - * <code>false</code> or <code>nil</code>. If the block is not given, - * Ruby adds an implicit block of <code>{|obj| obj}</code> (that is - * <code>all?</code> will return <code>true</code> only if none of the - * collection members are <code>false</code> or <code>nil</code>.) - * - * %w{ ant bear cat}.all? {|word| word.length >= 3} #=> true - * %w{ ant bear cat}.all? {|word| word.length >= 4} #=> false - * [ nil, true, 99 ].all? #=> false - * - */ - -static VALUE -enum_all(obj) - VALUE obj; -{ - VALUE result; - NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0); - - memo->u1.value = Qtrue; - rb_iterate(rb_each, obj, rb_block_given_p() ? all_iter_i : all_i, (VALUE)memo); - result = memo->u1.value; - return result; -} - -static VALUE -any_iter_i(i, memo) - VALUE i; - NODE *memo; -{ - if (RTEST(rb_yield(i))) { - memo->u1.value = Qtrue; - rb_iter_break(); - } - return Qnil; -} - -static VALUE -any_i(i, memo) - VALUE i; - NODE *memo; -{ - if (RTEST(i)) { - memo->u1.value = Qtrue; - rb_iter_break(); - } - return Qnil; -} - -/* - * call-seq: - * enum.any? [{|obj| block } ] => true or false - * - * Passes each element of the collection to the given block. The method - * returns <code>true</code> if the block ever returns a value other - * that <code>false</code> or <code>nil</code>. If the block is not - * given, Ruby adds an implicit block of <code>{|obj| obj}</code> (that - * is <code>any?</code> will return <code>true</code> if at least one - * of the collection members is not <code>false</code> or - * <code>nil</code>. - * - * %w{ ant bear cat}.any? {|word| word.length >= 3} #=> true - * %w{ ant bear cat}.any? {|word| word.length >= 4} #=> true - * [ nil, true, 99 ].any? #=> true - * - */ - -static VALUE -enum_any(obj) - VALUE obj; -{ - VALUE result; - NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0); - - memo->u1.value = Qfalse; - rb_iterate(rb_each, obj, rb_block_given_p() ? any_iter_i : any_i, (VALUE)memo); - result = memo->u1.value; - return result; -} - -static VALUE -min_i(i, memo) - VALUE i; - NODE *memo; -{ - VALUE cmp; - - if (NIL_P(memo->u1.value)) { - memo->u1.value = i; - } - else { - cmp = rb_funcall(i, id_cmp, 1, memo->u1.value); - if (rb_cmpint(cmp, i, memo->u1.value) < 0) { - memo->u1.value = i; - } - } - return Qnil; -} - -static VALUE -min_ii(i, memo) - VALUE i; - NODE *memo; -{ - VALUE cmp; - - if (NIL_P(memo->u1.value)) { - memo->u1.value = i; - } - else { - cmp = rb_yield_values(2, i, memo->u1.value); - if (rb_cmpint(cmp, i, memo->u1.value) < 0) { - memo->u1.value = i; - } - } - return Qnil; -} - - -/* - * call-seq: - * enum.min => obj - * enum.min {| a,b | block } => obj - * - * Returns the object in <i>enum</i> with the minimum value. The - * first form assumes all objects implement <code>Comparable</code>; - * the second uses the block to return <em>a <=> b</em>. - * - * a = %w(albatross dog horse) - * a.min #=> "albatross" - * a.min {|a,b| a.length <=> b.length } #=> "dog" - */ - -static VALUE -enum_min(obj) - VALUE obj; -{ - VALUE result; - NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0); - - rb_iterate(rb_each, obj, rb_block_given_p() ? min_ii : min_i, (VALUE)memo); - result = memo->u1.value; - return result; -} - -static VALUE -max_i(i, memo) - VALUE i; - NODE *memo; -{ - VALUE cmp; - - if (NIL_P(memo->u1.value)) { - memo->u1.value = i; - } - else { - cmp = rb_funcall(i, id_cmp, 1, memo->u1.value); - if (rb_cmpint(cmp, i, memo->u1.value) > 0) { - memo->u1.value = i; - } - } - return Qnil; -} - -static VALUE -max_ii(i, memo) - VALUE i; - NODE *memo; -{ - VALUE cmp; - - if (NIL_P(memo->u1.value)) { - memo->u1.value = i; - } - else { - cmp = rb_yield_values(2, i, memo->u1.value); - if (rb_cmpint(cmp, i, memo->u1.value) > 0) { - memo->u1.value = i; - } - } - return Qnil; -} - -/* - * call-seq: - * enum.max => obj - * enum.max {|a,b| block } => obj - * - * Returns the object in _enum_ with the maximum value. The - * first form assumes all objects implement <code>Comparable</code>; - * the second uses the block to return <em>a <=> b</em>. - * - * a = %w(albatross dog horse) - * a.max #=> "horse" - * a.max {|a,b| a.length <=> b.length } #=> "albatross" - */ - -static VALUE -enum_max(obj) - VALUE obj; -{ - VALUE result; - NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0); - - rb_iterate(rb_each, obj, rb_block_given_p() ? max_ii : max_i, (VALUE)memo); - result = memo->u1.value; - return result; -} - -static VALUE -min_by_i(i, memo) - VALUE i; - NODE *memo; -{ - VALUE v; - - v = rb_yield(i); - if (NIL_P(memo->u1.value)) { - memo->u1.value = v; - memo->u2.value = i; - } - else if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo->u1.value), v, memo->u1.value) < 0) { - memo->u1.value = v; - memo->u2.value = i; - } - return Qnil; -} - -/* - * call-seq: - * enum.min_by {| obj| block } => obj - * - * Returns the object in <i>enum</i> that gives the minimum - * value from the given block. - * - * a = %w(albatross dog horse) - * a.min_by {|x| x.length } #=> "dog" - */ - -static VALUE -enum_min_by(obj) - VALUE obj; -{ - VALUE result; - NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0); - - rb_iterate(rb_each, obj, min_by_i, (VALUE)memo); - result = memo->u2.value; - return result; -} - -static VALUE -max_by_i(i, memo) - VALUE i; - NODE *memo; -{ - VALUE v; - - v = rb_yield(i); - if (NIL_P(memo->u1.value)) { - memo->u1.value = v; - memo->u2.value = i; - } - else if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo->u1.value), v, memo->u1.value) > 0) { - memo->u1.value = v; - memo->u2.value = i; - } - return Qnil; -} - -/* - * call-seq: - * enum.max_by {| obj| block } => obj - * - * Returns the object in <i>enum</i> that gives the maximum - * value from the given block. - * - * a = %w(albatross dog horse) - * a.max_by {|x| x.length } #=> "albatross" - */ - -static VALUE -enum_max_by(obj) - VALUE obj; -{ - VALUE result; - NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0); - - rb_iterate(rb_each, obj, max_by_i, (VALUE)memo); - result = memo->u2.value; - return result; -} - -static VALUE -member_i(item, memo) - VALUE item; - NODE *memo; -{ - if (rb_equal(item, memo->u1.value)) { - memo->u2.value = Qtrue; - rb_iter_break(); - } - return Qnil; -} - -/* - * call-seq: - * enum.include?(obj) => true or false - * enum.member?(obj) => true or false - * - * Returns <code>true</code> if any member of <i>enum</i> equals - * <i>obj</i>. Equality is tested using <code>==</code>. - * - * IO.constants.include? "SEEK_SET" #=> true - * IO.constants.include? "SEEK_NO_FURTHER" #=> false - * - */ - -static VALUE -enum_member(obj, val) - VALUE obj, val; -{ - VALUE result; - NODE *memo = rb_node_newnode(NODE_MEMO, val, Qfalse, 0); - - rb_iterate(rb_each, obj, member_i, (VALUE)memo); - result = memo->u2.value; - return result; -} - -static VALUE -each_with_index_i(val, memo) - VALUE val; - NODE *memo; -{ - rb_yield_values(2, val, INT2FIX(memo->u3.cnt)); - memo->u3.cnt++; - return Qnil; -} - -/* - * call-seq: - * enum.each_with_index {|obj, i| block } -> enum - * - * Calls <em>block</em> with two arguments, the item and its index, for - * each item in <i>enum</i>. - * - * hash = Hash.new - * %w(cat dog wombat).each_with_index {|item, index| - * hash[item] = index - * } - * hash #=> {"cat"=>0, "wombat"=>2, "dog"=>1} - * - */ - -static VALUE -enum_each_with_index(obj) - VALUE obj; -{ - NODE *memo = rb_node_newnode(NODE_MEMO, 0, 0, 0); - - rb_iterate(rb_each, obj, each_with_index_i, (VALUE)memo); - return obj; -} - -static VALUE -zip_i(val, memo) - VALUE val; - NODE *memo; -{ - VALUE result = memo->u1.value; - VALUE args = memo->u2.value; - int idx = memo->u3.cnt++; - VALUE tmp; - int i; - - tmp = rb_ary_new2(RARRAY(args)->len + 1); - rb_ary_store(tmp, 0, val); - for (i=0; i<RARRAY(args)->len; i++) { - rb_ary_push(tmp, rb_ary_entry(RARRAY(args)->ptr[i], idx)); - } - if (rb_block_given_p()) { - rb_yield(tmp); - } - else { - rb_ary_push(result, tmp); - } - return Qnil; -} - -/* - * call-seq: - * enum.zip(arg, ...) => array - * enum.zip(arg, ...) {|arr| block } => nil - * - * Converts any arguments to arrays, then merges elements of - * <i>enum</i> with corresponding elements from each argument. This - * generates a sequence of <code>enum#size</code> <em>n</em>-element - * arrays, where <em>n</em> is one more that the count of arguments. If - * the size of any argument is less than <code>enum#size</code>, - * <code>nil</code> values are supplied. If a block given, it is - * invoked for each output array, otherwise an array of arrays is - * returned. - * - * a = [ 4, 5, 6 ] - * b = [ 7, 8, 9 ] - * - * (1..3).zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]] - * "cat\ndog".zip([1]) #=> [["cat\n", 1], ["dog", nil]] - * (1..3).zip #=> [[1], [2], [3]] - * - */ - -static VALUE -enum_zip(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - int i; - VALUE result; - NODE *memo; - - for (i=0; i<argc; i++) { - argv[i] = rb_convert_type(argv[i], T_ARRAY, "Array", "to_a"); - } - result = rb_block_given_p() ? Qnil : rb_ary_new(); - memo = rb_node_newnode(NODE_MEMO, result, rb_ary_new4(argc, argv), 0); - rb_iterate(rb_each, obj, zip_i, (VALUE)memo); - - return result; -} - -/* - * The <code>Enumerable</code> mixin provides collection classes with - * several traversal and searching methods, and with the ability to - * sort. The class must provide a method <code>each</code>, which - * yields successive members of the collection. If - * <code>Enumerable#max</code>, <code>#min</code>, or - * <code>#sort</code> is used, the objects in the collection must also - * implement a meaningful <code><=></code> operator, as these methods - * rely on an ordering between members of the collection. - */ - -void -Init_Enumerable() -{ - rb_mEnumerable = rb_define_module("Enumerable"); - - rb_define_method(rb_mEnumerable,"to_a", enum_to_a, 0); - rb_define_method(rb_mEnumerable,"entries", enum_to_a, 0); - - rb_define_method(rb_mEnumerable,"sort", enum_sort, 0); - rb_define_method(rb_mEnumerable,"sort_by", enum_sort_by, 0); - rb_define_method(rb_mEnumerable,"grep", enum_grep, 1); - rb_define_method(rb_mEnumerable,"find", enum_find, -1); - rb_define_method(rb_mEnumerable,"detect", enum_find, -1); - rb_define_method(rb_mEnumerable,"find_all", enum_find_all, 0); - rb_define_method(rb_mEnumerable,"select", enum_find_all, 0); - rb_define_method(rb_mEnumerable,"reject", enum_reject, 0); - rb_define_method(rb_mEnumerable,"collect", enum_collect, 0); - rb_define_method(rb_mEnumerable,"map", enum_collect, 0); - rb_define_method(rb_mEnumerable,"inject", enum_inject, -1); - rb_define_method(rb_mEnumerable,"partition", enum_partition, 0); - rb_define_method(rb_mEnumerable,"all?", enum_all, 0); - rb_define_method(rb_mEnumerable,"any?", enum_any, 0); - rb_define_method(rb_mEnumerable,"min", enum_min, 0); - rb_define_method(rb_mEnumerable,"max", enum_max, 0); - rb_define_method(rb_mEnumerable,"min_by", enum_min_by, 0); - rb_define_method(rb_mEnumerable,"max_by", enum_max_by, 0); - rb_define_method(rb_mEnumerable,"member?", enum_member, 1); - rb_define_method(rb_mEnumerable,"include?", enum_member, 1); - rb_define_method(rb_mEnumerable,"each_with_index", enum_each_with_index, 0); - rb_define_method(rb_mEnumerable, "zip", enum_zip, -1); - - id_eqq = rb_intern("==="); - id_each = rb_intern("each"); - id_cmp = rb_intern("<=>"); -} - -/********************************************************************** - - error.c - - - $Author: murphy $ - $Date: 2005-11-05 04:33:55 +0100 (Sa, 05 Nov 2005) $ - created at: Mon Aug 9 16:11:34 JST 1993 - - Copyright (C) 1993-2003 Yukihiro Matsumoto - -**********************************************************************/ - -#include "ruby.h" -#include "env.h" -#include "st.h" - -#include <stdio.h> -#ifdef HAVE_STDARG_PROTOTYPES -#include <stdarg.h> -#define va_init_list(a,b) va_start(a,b) -#else -#include <varargs.h> -#define va_init_list(a,b) va_start(a) -#endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifndef EXIT_SUCCESS -#define EXIT_SUCCESS 0 -#endif - -extern const char ruby_version[], ruby_release_date[], ruby_platform[]; - -int ruby_nerrs; - -static int -err_position(buf, len) - char *buf; - long len; -{ - ruby_set_current_source(); - if (!ruby_sourcefile) { - return 0; - } - else if (ruby_sourceline == 0) { - return snprintf(buf, len, "%s: ", ruby_sourcefile); - } - else { - return snprintf(buf, len, "%s:%d: ", ruby_sourcefile, ruby_sourceline); - } -} - -static void -err_snprintf(buf, len, fmt, args) - char *buf; - long len; - const char *fmt; - va_list args; -{ - long n; - - n = err_position(buf, len); - if (len > n) { - vsnprintf((char*)buf+n, len-n, fmt, args); - } -} - -static void err_append _((const char*)); -static void -err_print(fmt, args) - const char *fmt; - va_list args; -{ - char buf[BUFSIZ]; - - err_snprintf(buf, BUFSIZ, fmt, args); - err_append(buf); -} - -void -#ifdef HAVE_STDARG_PROTOTYPES -rb_compile_error(const char *fmt, ...) -#else -rb_compile_error(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - va_list args; - - va_init_list(args, fmt); - err_print(fmt, args); - va_end(args); - ruby_nerrs++; -} - -void -#ifdef HAVE_STDARG_PROTOTYPES -rb_compile_error_append(const char *fmt, ...) -#else -rb_compile_error_append(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - va_list args; - char buf[BUFSIZ]; - - va_init_list(args, fmt); - vsnprintf(buf, BUFSIZ, fmt, args); - va_end(args); - err_append(buf); -} - -static void -warn_print(fmt, args) - const char *fmt; - va_list args; -{ - char buf[BUFSIZ]; - int len; - - err_snprintf(buf, BUFSIZ, fmt, args); - len = strlen(buf); - buf[len++] = '\n'; - rb_write_error2(buf, len); -} - -void -#ifdef HAVE_STDARG_PROTOTYPES -rb_warn(const char *fmt, ...) -#else -rb_warn(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - char buf[BUFSIZ]; - va_list args; - - if (NIL_P(ruby_verbose)) return; - - snprintf(buf, BUFSIZ, "warning: %s", fmt); - - va_init_list(args, fmt); - warn_print(buf, args); - va_end(args); -} - -/* rb_warning() reports only in verbose mode */ -void -#ifdef HAVE_STDARG_PROTOTYPES -rb_warning(const char *fmt, ...) -#else -rb_warning(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - char buf[BUFSIZ]; - va_list args; - - if (!RTEST(ruby_verbose)) return; - - snprintf(buf, BUFSIZ, "warning: %s", fmt); - - va_init_list(args, fmt); - warn_print(buf, args); - va_end(args); -} - -/* - * call-seq: - * warn(msg) => nil - * - * Display the given message (followed by a newline) on STDERR unless - * warnings are disabled (for example with the <code>-W0</code> flag). - */ - -static VALUE -rb_warn_m(self, mesg) - VALUE self, mesg; -{ - if (!NIL_P(ruby_verbose)) { - rb_io_write(rb_stderr, mesg); - rb_io_write(rb_stderr, rb_default_rs); - } - return Qnil; -} - -void -#ifdef HAVE_STDARG_PROTOTYPES -rb_bug(const char *fmt, ...) -#else -rb_bug(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - char buf[BUFSIZ]; - va_list args; - FILE *out = stderr; - int len = err_position(buf, BUFSIZ); - - if (fwrite(buf, 1, len, out) == len || - fwrite(buf, 1, len, (out = stdout)) == len) { - fputs("[BUG] ", out); - va_init_list(args, fmt); - vfprintf(out, fmt, args); - va_end(args); - fprintf(out, "\nruby %s (%s) [%s]\n\n", - ruby_version, ruby_release_date, ruby_platform); - } - abort(); -} - -static struct types { - int type; - const char *name; -} builtin_types[] = { - {T_NIL, "nil"}, - {T_OBJECT, "Object"}, - {T_CLASS, "Class"}, - {T_ICLASS, "iClass"}, /* internal use: mixed-in module holder */ - {T_MODULE, "Module"}, - {T_FLOAT, "Float"}, - {T_STRING, "String"}, - {T_REGEXP, "Regexp"}, - {T_ARRAY, "Array"}, - {T_FIXNUM, "Fixnum"}, - {T_HASH, "Hash"}, - {T_STRUCT, "Struct"}, - {T_BIGNUM, "Bignum"}, - {T_FILE, "File"}, - {T_TRUE, "true"}, - {T_FALSE, "false"}, - {T_SYMBOL, "Symbol"}, /* :symbol */ - {T_DATA, "Data"}, /* internal use: wrapped C pointers */ - {T_MATCH, "MatchData"}, /* data of $~ */ - {T_VARMAP, "Varmap"}, /* internal use: dynamic variables */ - {T_SCOPE, "Scope"}, /* internal use: variable scope */ - {T_NODE, "Node"}, /* internal use: syntax tree node */ - {T_UNDEF, "undef"}, /* internal use: #undef; should not happen */ - {-1, 0} -}; - -void -rb_check_type(x, t) - VALUE x; - int t; -{ - struct types *type = builtin_types; - - if (x == Qundef) { - rb_bug("undef leaked to the Ruby space"); - } - - if (TYPE(x) != t) { - while (type->type >= 0) { - if (type->type == t) { - char *etype; - - if (NIL_P(x)) { - etype = "nil"; - } - else if (FIXNUM_P(x)) { - etype = "Fixnum"; - } - else if (SYMBOL_P(x)) { - etype = "Symbol"; - } - else if (rb_special_const_p(x)) { - etype = RSTRING(rb_obj_as_string(x))->ptr; - } - else { - etype = rb_obj_classname(x); - } - rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)", - etype, type->name); - } - type++; - } - rb_bug("unknown type 0x%x (0x%x given)", t, TYPE(x)); - } -} - -/* exception classes */ -#include <errno.h> - -VALUE rb_eException; -VALUE rb_eSystemExit; -VALUE rb_eInterrupt; -VALUE rb_eSignal; -VALUE rb_eFatal; -VALUE rb_eStandardError; -VALUE rb_eRuntimeError; -VALUE rb_eTypeError; -VALUE rb_eArgError; -VALUE rb_eIndexError; -VALUE rb_eKeyError; -VALUE rb_eRangeError; -VALUE rb_eNameError; -VALUE rb_eNoMethodError; -VALUE rb_eSecurityError; -VALUE rb_eNotImpError; -VALUE rb_eNoMemError; -static VALUE rb_cNameErrorMesg; - -VALUE rb_eScriptError; -VALUE rb_eSyntaxError; -VALUE rb_eLoadError; - -VALUE rb_eSystemCallError; -VALUE rb_mErrno; -static VALUE eNOERROR; - -VALUE -rb_exc_new(etype, ptr, len) - VALUE etype; - const char *ptr; - long len; -{ - return rb_funcall(etype, rb_intern("new"), 1, rb_str_new(ptr, len)); -} - -VALUE -rb_exc_new2(etype, s) - VALUE etype; - const char *s; -{ - return rb_exc_new(etype, s, strlen(s)); -} - -VALUE -rb_exc_new3(etype, str) - VALUE etype, str; -{ - StringValue(str); - return rb_funcall(etype, rb_intern("new"), 1, str); -} - -/* - * call-seq: - * Exception.new(msg = nil) => exception - * - * Construct a new Exception object, optionally passing in - * a message. - */ - -static VALUE -exc_initialize(argc, argv, exc) - int argc; - VALUE *argv; - VALUE exc; -{ - VALUE arg; - - rb_scan_args(argc, argv, "01", &arg); - rb_iv_set(exc, "mesg", arg); - rb_iv_set(exc, "bt", Qnil); - - return exc; -} - -/* - * Document-method: exception - * - * call-seq: - * exc.exception(string) -> an_exception or exc - * - * With no argument, or if the argument is the same as the receiver, - * return the receiver. Otherwise, create a new - * exception object of the same class as the receiver, but with a - * message equal to <code>string.to_str</code>. - * - */ - -static VALUE -exc_exception(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ - VALUE exc; - - if (argc == 0) return self; - if (argc == 1 && self == argv[0]) return self; - exc = rb_obj_clone(self); - exc_initialize(argc, argv, exc); - - return exc; -} - -/* - * call-seq: - * exception.to_s => string - * - * Returns exception's message (or the name of the exception if - * no message is set). - */ - -static VALUE -exc_to_s(exc) - VALUE exc; -{ - VALUE mesg = rb_attr_get(exc, rb_intern("mesg")); - - if (NIL_P(mesg)) return rb_class_name(CLASS_OF(exc)); - if (OBJ_TAINTED(exc)) OBJ_TAINT(mesg); - return mesg; -} - -/* - * call-seq: - * exception.message => string - * - * Returns the result of invoking <code>exception.to_s</code>. - * Normally this returns the exception's message or name. By - * supplying a to_str method, exceptions are agreeing to - * be used where Strings are expected. - */ - -static VALUE -exc_message(exc) - VALUE exc; -{ - return rb_funcall(exc, rb_intern("to_s"), 0, 0); -} - -/* - * call-seq: - * exception.inspect => string - * - * Return this exception's class name an message - */ - -static VALUE -exc_inspect(exc) - VALUE exc; -{ - VALUE str, klass; - - klass = CLASS_OF(exc); - exc = rb_obj_as_string(exc); - if (RSTRING(exc)->len == 0) { - return rb_str_dup(rb_class_name(klass)); - } - - str = rb_str_buf_new2("#<"); - klass = rb_class_name(klass); - rb_str_buf_append(str, klass); - rb_str_buf_cat(str, ": ", 2); - rb_str_buf_append(str, exc); - rb_str_buf_cat(str, ">", 1); - - return str; -} - -/* - * call-seq: - * exception.backtrace => array - * - * Returns any backtrace associated with the exception. The backtrace - * is an array of strings, each containing either ``filename:lineNo: in - * `method''' or ``filename:lineNo.'' - * - * def a - * raise "boom" - * end - * - * def b - * a() - * end - * - * begin - * b() - * rescue => detail - * print detail.backtrace.join("\n") - * end - * - * <em>produces:</em> - * - * prog.rb:2:in `a' - * prog.rb:6:in `b' - * prog.rb:10 -*/ - -static VALUE -exc_backtrace(exc) - VALUE exc; -{ - ID bt = rb_intern("bt"); - - if (!rb_ivar_defined(exc, bt)) return Qnil; - return rb_ivar_get(exc, bt); -} - -static VALUE -check_backtrace(bt) - VALUE bt; -{ - long i; - static char *err = "backtrace must be Array of String"; - - if (!NIL_P(bt)) { - int t = TYPE(bt); - - if (t == T_STRING) return rb_ary_new3(1, bt); - if (t != T_ARRAY) { - rb_raise(rb_eTypeError, err); - } - for (i=0;i<RARRAY(bt)->len;i++) { - if (TYPE(RARRAY(bt)->ptr[i]) != T_STRING) { - rb_raise(rb_eTypeError, err); - } - } - } - return bt; -} - -/* - * call-seq: - * exc.set_backtrace(array) => array - * - * Sets the backtrace information associated with <i>exc</i>. The - * argument must be an array of <code>String</code> objects in the - * format described in <code>Exception#backtrace</code>. - * - */ - -static VALUE -exc_set_backtrace(exc, bt) - VALUE exc; - VALUE bt; -{ - return rb_iv_set(exc, "bt", check_backtrace(bt)); -} - -/* - * call-seq: - * exc == obj => true or false - * - * Equality---If <i>obj</i> is not an <code>Exception</code>, returns - * <code>false</code>. Otherwise, returns <code>true</code> if <i>exc</i> and - * <i>obj</i> share same class, messages, and backtrace. - */ - -static VALUE -exc_equal(exc, obj) - VALUE exc; - VALUE obj; -{ - ID id_mesg = rb_intern("mesg"); - - if (exc == obj) return Qtrue; - if (rb_obj_class(exc) != rb_obj_class(obj)) - return Qfalse; - if (!rb_equal(rb_attr_get(exc, id_mesg), rb_attr_get(obj, id_mesg))) - return Qfalse; - if (!rb_equal(exc_backtrace(exc), exc_backtrace(obj))) - return Qfalse; - return Qtrue; -} - -/* - * call-seq: - * SystemExit.new(status=0) => system_exit - * - * Create a new +SystemExit+ exception with the given status. - */ - -static VALUE -exit_initialize(argc, argv, exc) - int argc; - VALUE *argv; - VALUE exc; -{ - VALUE status = INT2FIX(EXIT_SUCCESS); - if (argc > 0 && FIXNUM_P(argv[0])) { - status = *argv++; - --argc; - } - exc_initialize(argc, argv, exc); - rb_iv_set(exc, "status", status); - return exc; -} - - -/* - * call-seq: - * system_exit.status => fixnum - * - * Return the status value associated with this system exit. - */ - -static VALUE -exit_status(exc) - VALUE exc; -{ - return rb_attr_get(exc, rb_intern("status")); -} - - -/* - * call-seq: - * system_exit.success? => true or false - * - * Returns +true+ if exiting successful, +false+ if not. - */ - -static VALUE -exit_success_p(exc) - VALUE exc; -{ - VALUE status = rb_attr_get(exc, rb_intern("status")); - if (NIL_P(status)) return Qtrue; - if (status == INT2FIX(EXIT_SUCCESS)) return Qtrue; - return Qfalse; -} - -void -#ifdef HAVE_STDARG_PROTOTYPES -rb_name_error(ID id, const char *fmt, ...) -#else -rb_name_error(id, fmt, va_alist) - ID id; - const char *fmt; - va_dcl -#endif -{ - VALUE exc, argv[2]; - va_list args; - char buf[BUFSIZ]; - - va_init_list(args, fmt); - vsnprintf(buf, BUFSIZ, fmt, args); - va_end(args); - - argv[0] = rb_str_new2(buf); - argv[1] = ID2SYM(id); - exc = rb_class_new_instance(2, argv, rb_eNameError); - rb_exc_raise(exc); -} - -/* - * call-seq: - * NameError.new(msg [, name]) => name_error - * - * Construct a new NameError exception. If given the <i>name</i> - * parameter may subsequently be examined using the <code>NameError.name</code> - * method. - */ - -static VALUE -name_err_initialize(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ - VALUE name; - - name = (argc > 1) ? argv[--argc] : Qnil; - exc_initialize(argc, argv, self); - rb_iv_set(self, "name", name); - return self; -} - -/* - * call-seq: - * name_error.name => string or nil - * - * Return the name associated with this NameError exception. - */ - -static VALUE -name_err_name(self) - VALUE self; -{ - return rb_attr_get(self, rb_intern("name")); -} - -/* - * call-seq: - * name_error.to_s => string - * - * Produce a nicely-formated string representing the +NameError+. - */ - -static VALUE -name_err_to_s(exc) - VALUE exc; -{ - VALUE mesg = rb_attr_get(exc, rb_intern("mesg")); - VALUE str = mesg; - - if (NIL_P(mesg)) return rb_class_name(CLASS_OF(exc)); - StringValue(str); - if (str != mesg) { - rb_iv_set(exc, "mesg", mesg = str); - } - if (OBJ_TAINTED(exc)) OBJ_TAINT(mesg); - return mesg; -} - -/* - * call-seq: - * NoMethodError.new(msg, name [, args]) => no_method_error - * - * Construct a NoMethodError exception for a method of the given name - * called with the given arguments. The name may be accessed using - * the <code>#name</code> method on the resulting object, and the - * arguments using the <code>#args</code> method. - */ - -static VALUE -nometh_err_initialize(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ - VALUE args = (argc > 2) ? argv[--argc] : Qnil; - name_err_initialize(argc, argv, self); - rb_iv_set(self, "args", args); - return self; -} - -/* :nodoc: */ -static void -name_err_mesg_mark(ptr) - VALUE *ptr; -{ - rb_gc_mark_locations(ptr, ptr+3); -} - -/* :nodoc: */ -static VALUE -name_err_mesg_new(obj, mesg, recv, method) - VALUE obj, mesg, recv, method; -{ - VALUE *ptr = ALLOC_N(VALUE, 3); - - ptr[0] = mesg; - ptr[1] = recv; - ptr[2] = method; - return Data_Wrap_Struct(rb_cNameErrorMesg, name_err_mesg_mark, -1, ptr); -} - -/* :nodoc: */ -static VALUE -name_err_mesg_equal(obj1, obj2) - VALUE obj1, obj2; -{ - VALUE *ptr1, *ptr2; - int i; - - if (obj1 == obj2) return Qtrue; - if (rb_obj_class(obj2) != rb_cNameErrorMesg) - return Qfalse; - - Data_Get_Struct(obj1, VALUE, ptr1); - Data_Get_Struct(obj2, VALUE, ptr2); - for (i=0; i<3; i++) { - if (!rb_equal(ptr1[i], ptr2[i])) - return Qfalse; - } - return Qtrue; -} - -/* :nodoc: */ -static VALUE -name_err_mesg_to_str(obj) - VALUE obj; -{ - VALUE *ptr, mesg; - Data_Get_Struct(obj, VALUE, ptr); - - mesg = ptr[0]; - if (NIL_P(mesg)) return Qnil; - else { - char *desc = 0; - VALUE d = 0, args[3]; - - obj = ptr[1]; - switch (TYPE(obj)) { - case T_NIL: - desc = "nil"; - break; - case T_TRUE: - desc = "true"; - break; - case T_FALSE: - desc = "false"; - break; - default: - d = rb_protect(rb_inspect, obj, 0); - if (NIL_P(d) || RSTRING(d)->len > 65) { - d = rb_any_to_s(obj); - } - desc = RSTRING(d)->ptr; - break; - } - if (desc && desc[0] != '#') { - d = rb_str_new2(desc); - rb_str_cat2(d, ":"); - rb_str_cat2(d, rb_obj_classname(obj)); - } - args[0] = mesg; - args[1] = ptr[2]; - args[2] = d; - mesg = rb_f_sprintf(3, args); - } - if (OBJ_TAINTED(obj)) OBJ_TAINT(mesg); - return mesg; -} - -/* :nodoc: */ -static VALUE -name_err_mesg_load(klass, str) - VALUE klass, str; -{ - return str; -} - -/* - * call-seq: - * no_method_error.args => obj - * - * Return the arguments passed in as the third parameter to - * the constructor. - */ - -static VALUE -nometh_err_args(self) - VALUE self; -{ - return rb_attr_get(self, rb_intern("args")); -} - -void -rb_invalid_str(str, type) - const char *str, *type; -{ - VALUE s = rb_str_inspect(rb_str_new2(str)); - - rb_raise(rb_eArgError, "invalid value for %s: %s", type, RSTRING(s)->ptr); -} - -/* - * Document-module: Errno - * - * Ruby exception objects are subclasses of <code>Exception</code>. - * However, operating systems typically report errors using plain - * integers. Module <code>Errno</code> is created dynamically to map - * these operating system errors to Ruby classes, with each error - * number generating its own subclass of <code>SystemCallError</code>. - * As the subclass is created in module <code>Errno</code>, its name - * will start <code>Errno::</code>. - * - * The names of the <code>Errno::</code> classes depend on - * the environment in which Ruby runs. On a typical Unix or Windows - * platform, there are <code>Errno</code> classes such as - * <code>Errno::EACCES</code>, <code>Errno::EAGAIN</code>, - * <code>Errno::EINTR</code>, and so on. - * - * The integer operating system error number corresponding to a - * particular error is available as the class constant - * <code>Errno::</code><em>error</em><code>::Errno</code>. - * - * Errno::EACCES::Errno #=> 13 - * Errno::EAGAIN::Errno #=> 11 - * Errno::EINTR::Errno #=> 4 - * - * The full list of operating system errors on your particular platform - * are available as the constants of <code>Errno</code>. - * - * Errno.constants #=> E2BIG, EACCES, EADDRINUSE, EADDRNOTAVAIL, ... - */ - -static st_table *syserr_tbl; - -static VALUE -set_syserr(n, name) - int n; - const char *name; -{ - VALUE error; - - if (!st_lookup(syserr_tbl, n, &error)) { - error = rb_define_class_under(rb_mErrno, name, rb_eSystemCallError); - rb_define_const(error, "Errno", INT2NUM(n)); - st_add_direct(syserr_tbl, n, error); - } - else { - rb_define_const(rb_mErrno, name, error); - } - return error; -} - -static VALUE -get_syserr(n) - int n; -{ - VALUE error; - - if (!st_lookup(syserr_tbl, n, &error)) { - char name[8]; /* some Windows' errno have 5 digits. */ - - snprintf(name, sizeof(name), "E%03d", n); - error = set_syserr(n, name); - } - return error; -} - -/* - * call-seq: - * SystemCallError.new(msg, errno) => system_call_error_subclass - * - * If _errno_ corresponds to a known system error code, constructs - * the appropriate <code>Errno</code> class for that error, otherwise - * constructs a generic <code>SystemCallError</code> object. The - * error number is subsequently available via the <code>errno</code> - * method. - */ - -static VALUE -syserr_initialize(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ -#if !defined(_WIN32) && !defined(__VMS) - char *strerror(); -#endif - char *err; - VALUE mesg, error; - VALUE klass = rb_obj_class(self); - - if (klass == rb_eSystemCallError) { - rb_scan_args(argc, argv, "11", &mesg, &error); - if (argc == 1 && FIXNUM_P(mesg)) { - error = mesg; mesg = Qnil; - } - if (!NIL_P(error) && st_lookup(syserr_tbl, NUM2LONG(error), &klass)) { - /* change class */ - if (TYPE(self) != T_OBJECT) { /* insurance to avoid type crash */ - rb_raise(rb_eTypeError, "invalid instance type"); - } - RBASIC(self)->klass = klass; - } - } - else { - rb_scan_args(argc, argv, "01", &mesg); - error = rb_const_get(klass, rb_intern("Errno")); - } - if (!NIL_P(error)) err = strerror(NUM2LONG(error)); - else err = "unknown error"; - if (!NIL_P(mesg)) { - VALUE str = mesg; - StringValue(str); - mesg = rb_str_new(0, strlen(err)+RSTRING(str)->len+3); - sprintf(RSTRING(mesg)->ptr, "%s - %.*s", err, - (int)RSTRING(str)->len, RSTRING(str)->ptr); - rb_str_resize(mesg, strlen(RSTRING(mesg)->ptr)); - } - else { - mesg = rb_str_new2(err); - } - exc_initialize(1, &mesg, self); - rb_iv_set(self, "errno", error); - return self; -} - -/* - * call-seq: - * system_call_error.errno => fixnum - * - * Return this SystemCallError's error number. - */ - -static VALUE -syserr_errno(self) - VALUE self; -{ - return rb_attr_get(self, rb_intern("errno")); -} - -/* - * call-seq: - * system_call_error === other => true or false - * - * Return +true+ if the receiver is a generic +SystemCallError+, or - * if the error numbers _self_ and _other_ are the same. - */ - -static VALUE -syserr_eqq(self, exc) - VALUE self, exc; -{ - VALUE num, e; - - if (!rb_obj_is_kind_of(exc, rb_eSystemCallError)) return Qfalse; - if (self == rb_eSystemCallError) return Qtrue; - - num = rb_attr_get(exc, rb_intern("errno")); - if (NIL_P(num)) { - VALUE klass = CLASS_OF(exc); - - while (TYPE(klass) == T_ICLASS || FL_TEST(klass, FL_SINGLETON)) { - klass = (VALUE)RCLASS(klass)->super; - } - num = rb_const_get(klass, rb_intern("Errno")); - } - e = rb_const_get(self, rb_intern("Errno")); - if (FIXNUM_P(num) ? num == e : rb_equal(num, e)) - return Qtrue; - return Qfalse; -} - -/* - * call-seq: - * Errno.const_missing => SystemCallError - * - * Returns default SystemCallError class. - */ -static VALUE -errno_missing(self, id) - VALUE self, id; -{ - return eNOERROR; -} - -/* - * Descendents of class <code>Exception</code> are used to communicate - * between <code>raise</code> methods and <code>rescue</code> - * statements in <code>begin/end</code> blocks. <code>Exception</code> - * objects carry information about the exception---its type (the - * exception's class name), an optional descriptive string, and - * optional traceback information. Programs may subclass - * <code>Exception</code> to add additional information. - */ - -void -Init_Exception() -{ - rb_eException = rb_define_class("Exception", rb_cObject); - rb_define_singleton_method(rb_eException, "exception", rb_class_new_instance, -1); - rb_define_method(rb_eException, "exception", exc_exception, -1); - rb_define_method(rb_eException, "initialize", exc_initialize, -1); - rb_define_method(rb_eException, "==", exc_equal, 1); - rb_define_method(rb_eException, "to_s", exc_to_s, 0); - rb_define_method(rb_eException, "message", exc_message, 0); - rb_define_method(rb_eException, "inspect", exc_inspect, 0); - rb_define_method(rb_eException, "backtrace", exc_backtrace, 0); - rb_define_method(rb_eException, "set_backtrace", exc_set_backtrace, 1); - - rb_eSystemExit = rb_define_class("SystemExit", rb_eException); - rb_define_method(rb_eSystemExit, "initialize", exit_initialize, -1); - rb_define_method(rb_eSystemExit, "status", exit_status, 0); - rb_define_method(rb_eSystemExit, "success?", exit_success_p, 0); - - rb_eFatal = rb_define_class("fatal", rb_eException); - rb_eSignal = rb_define_class("SignalException", rb_eException); - rb_eInterrupt = rb_define_class("Interrupt", rb_eSignal); - - rb_eStandardError = rb_define_class("StandardError", rb_eException); - rb_eTypeError = rb_define_class("TypeError", rb_eStandardError); - rb_eArgError = rb_define_class("ArgumentError", rb_eStandardError); - rb_eIndexError = rb_define_class("IndexError", rb_eStandardError); - rb_eKeyError = rb_define_class("KeyError", rb_eIndexError); - rb_eRangeError = rb_define_class("RangeError", rb_eStandardError); - rb_eNameError = rb_define_class("NameError", rb_eStandardError); - rb_define_method(rb_eNameError, "initialize", name_err_initialize, -1); - rb_define_method(rb_eNameError, "name", name_err_name, 0); - rb_define_method(rb_eNameError, "to_s", name_err_to_s, 0); - rb_cNameErrorMesg = rb_define_class_under(rb_eNameError, "message", rb_cData); - rb_define_singleton_method(rb_cNameErrorMesg, "!", name_err_mesg_new, 3); - rb_define_method(rb_cNameErrorMesg, "==", name_err_mesg_equal, 1); - rb_define_method(rb_cNameErrorMesg, "to_str", name_err_mesg_to_str, 0); - rb_define_method(rb_cNameErrorMesg, "_dump", name_err_mesg_to_str, 1); - rb_define_singleton_method(rb_cNameErrorMesg, "_load", name_err_mesg_load, 1); - rb_eNoMethodError = rb_define_class("NoMethodError", rb_eNameError); - rb_define_method(rb_eNoMethodError, "initialize", nometh_err_initialize, -1); - rb_define_method(rb_eNoMethodError, "args", nometh_err_args, 0); - - rb_eScriptError = rb_define_class("ScriptError", rb_eException); - rb_eSyntaxError = rb_define_class("SyntaxError", rb_eScriptError); - rb_eLoadError = rb_define_class("LoadError", rb_eScriptError); - rb_eNotImpError = rb_define_class("NotImplementedError", rb_eScriptError); - - rb_eRuntimeError = rb_define_class("RuntimeError", rb_eStandardError); - rb_eSecurityError = rb_define_class("SecurityError", rb_eStandardError); - rb_eNoMemError = rb_define_class("NoMemoryError", rb_eException); - - syserr_tbl = st_init_numtable(); - rb_eSystemCallError = rb_define_class("SystemCallError", rb_eStandardError); - rb_define_method(rb_eSystemCallError, "initialize", syserr_initialize, -1); - rb_define_method(rb_eSystemCallError, "errno", syserr_errno, 0); - rb_define_singleton_method(rb_eSystemCallError, "===", syserr_eqq, 1); - - rb_mErrno = rb_define_module("Errno"); - rb_define_singleton_method(rb_mErrno, "const_missing", errno_missing, 1); - - rb_define_global_function("warn", rb_warn_m, 1); -} - -void -#ifdef HAVE_STDARG_PROTOTYPES -rb_raise(VALUE exc, const char *fmt, ...) -#else -rb_raise(exc, fmt, va_alist) - VALUE exc; - const char *fmt; - va_dcl -#endif -{ - va_list args; - char buf[BUFSIZ]; - - va_init_list(args,fmt); - vsnprintf(buf, BUFSIZ, fmt, args); - va_end(args); - rb_exc_raise(rb_exc_new2(exc, buf)); -} - -void -#ifdef HAVE_STDARG_PROTOTYPES -rb_loaderror(const char *fmt, ...) -#else -rb_loaderror(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - va_list args; - char buf[BUFSIZ]; - - va_init_list(args, fmt); - vsnprintf(buf, BUFSIZ, fmt, args); - va_end(args); - rb_exc_raise(rb_exc_new2(rb_eLoadError, buf)); -} - -void -rb_notimplement() -{ - rb_raise(rb_eNotImpError, - "The %s() function is unimplemented on this machine", - rb_id2name(ruby_frame->callee)); -} - -void -#ifdef HAVE_STDARG_PROTOTYPES -rb_fatal(const char *fmt, ...) -#else -rb_fatal(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - va_list args; - char buf[BUFSIZ]; - - va_init_list(args, fmt); - vsnprintf(buf, BUFSIZ, fmt, args); - va_end(args); - - ruby_in_eval = 0; - rb_exc_fatal(rb_exc_new2(rb_eFatal, buf)); -} - -void -rb_sys_fail(mesg) - const char *mesg; -{ - extern int errno; - int n = errno; - VALUE arg; - - errno = 0; - if (n == 0) { - rb_bug("rb_sys_fail(%s) - errno == 0", mesg ? mesg : ""); - } - - arg = mesg ? rb_str_new2(mesg) : Qnil; - rb_exc_raise(rb_class_new_instance(1, &arg, get_syserr(n))); -} - -void -#ifdef HAVE_STDARG_PROTOTYPES -rb_sys_warning(const char *fmt, ...) -#else -rb_sys_warning(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - char buf[BUFSIZ]; - va_list args; - int errno_save; - - errno_save = errno; - - if (!RTEST(ruby_verbose)) return; - - snprintf(buf, BUFSIZ, "warning: %s", fmt); - snprintf(buf+strlen(buf), BUFSIZ-strlen(buf), ": %s", strerror(errno_save)); - - va_init_list(args, fmt); - warn_print(buf, args); - va_end(args); - errno = errno_save; -} - -void -rb_load_fail(path) - const char *path; -{ - rb_loaderror("%s -- %s", strerror(errno), path); -} - -void -rb_error_frozen(what) - const char *what; -{ - rb_raise(rb_eRuntimeError, "can't modify frozen %s", what); -} - -void -rb_check_frozen(obj) - VALUE obj; -{ - if (OBJ_FROZEN(obj)) rb_error_frozen(rb_obj_classname(obj)); -} - -void -Init_syserr() -{ -#ifdef EPERM - set_syserr(EPERM, "EPERM"); -#endif -#ifdef ENOENT - set_syserr(ENOENT, "ENOENT"); -#endif -#ifdef ESRCH - set_syserr(ESRCH, "ESRCH"); -#endif -#ifdef EINTR - set_syserr(EINTR, "EINTR"); -#endif -#ifdef EIO - set_syserr(EIO, "EIO"); -#endif -#ifdef ENXIO - set_syserr(ENXIO, "ENXIO"); -#endif -#ifdef E2BIG - set_syserr(E2BIG, "E2BIG"); -#endif -#ifdef ENOEXEC - set_syserr(ENOEXEC, "ENOEXEC"); -#endif -#ifdef EBADF - set_syserr(EBADF, "EBADF"); -#endif -#ifdef ECHILD - set_syserr(ECHILD, "ECHILD"); -#endif -#ifdef EAGAIN - set_syserr(EAGAIN, "EAGAIN"); -#endif -#ifdef ENOMEM - set_syserr(ENOMEM, "ENOMEM"); -#endif -#ifdef EACCES - set_syserr(EACCES, "EACCES"); -#endif -#ifdef EFAULT - set_syserr(EFAULT, "EFAULT"); -#endif -#ifdef ENOTBLK - set_syserr(ENOTBLK, "ENOTBLK"); -#endif -#ifdef EBUSY - set_syserr(EBUSY, "EBUSY"); -#endif -#ifdef EEXIST - set_syserr(EEXIST, "EEXIST"); -#endif -#ifdef EXDEV - set_syserr(EXDEV, "EXDEV"); -#endif -#ifdef ENODEV - set_syserr(ENODEV, "ENODEV"); -#endif -#ifdef ENOTDIR - set_syserr(ENOTDIR, "ENOTDIR"); -#endif -#ifdef EISDIR - set_syserr(EISDIR, "EISDIR"); -#endif -#ifdef EINVAL - set_syserr(EINVAL, "EINVAL"); -#endif -#ifdef ENFILE - set_syserr(ENFILE, "ENFILE"); -#endif -#ifdef EMFILE - set_syserr(EMFILE, "EMFILE"); -#endif -#ifdef ENOTTY - set_syserr(ENOTTY, "ENOTTY"); -#endif -#ifdef ETXTBSY - set_syserr(ETXTBSY, "ETXTBSY"); -#endif -#ifdef EFBIG - set_syserr(EFBIG, "EFBIG"); -#endif -#ifdef ENOSPC - set_syserr(ENOSPC, "ENOSPC"); -#endif -#ifdef ESPIPE - set_syserr(ESPIPE, "ESPIPE"); -#endif -#ifdef EROFS - set_syserr(EROFS, "EROFS"); -#endif -#ifdef EMLINK - set_syserr(EMLINK, "EMLINK"); -#endif -#ifdef EPIPE - set_syserr(EPIPE, "EPIPE"); -#endif -#ifdef EDOM - set_syserr(EDOM, "EDOM"); -#endif -#ifdef ERANGE - set_syserr(ERANGE, "ERANGE"); -#endif -#ifdef EDEADLK - set_syserr(EDEADLK, "EDEADLK"); -#endif -#ifdef ENAMETOOLONG - set_syserr(ENAMETOOLONG, "ENAMETOOLONG"); -#endif -#ifdef ENOLCK - set_syserr(ENOLCK, "ENOLCK"); -#endif -#ifdef ENOSYS - set_syserr(ENOSYS, "ENOSYS"); -#endif -#ifdef ENOTEMPTY - set_syserr(ENOTEMPTY, "ENOTEMPTY"); -#endif -#ifdef ELOOP - set_syserr(ELOOP, "ELOOP"); -#endif -#ifdef EWOULDBLOCK - set_syserr(EWOULDBLOCK, "EWOULDBLOCK"); -#endif -#ifdef ENOMSG - set_syserr(ENOMSG, "ENOMSG"); -#endif -#ifdef EIDRM - set_syserr(EIDRM, "EIDRM"); -#endif -#ifdef ECHRNG - set_syserr(ECHRNG, "ECHRNG"); -#endif -#ifdef EL2NSYNC - set_syserr(EL2NSYNC, "EL2NSYNC"); -#endif -#ifdef EL3HLT - set_syserr(EL3HLT, "EL3HLT"); -#endif -#ifdef EL3RST - set_syserr(EL3RST, "EL3RST"); -#endif -#ifdef ELNRNG - set_syserr(ELNRNG, "ELNRNG"); -#endif -#ifdef EUNATCH - set_syserr(EUNATCH, "EUNATCH"); -#endif -#ifdef ENOCSI - set_syserr(ENOCSI, "ENOCSI"); -#endif -#ifdef EL2HLT - set_syserr(EL2HLT, "EL2HLT"); -#endif -#ifdef EBADE - set_syserr(EBADE, "EBADE"); -#endif -#ifdef EBADR - set_syserr(EBADR, "EBADR"); -#endif -#ifdef EXFULL - set_syserr(EXFULL, "EXFULL"); -#endif -#ifdef ENOANO - set_syserr(ENOANO, "ENOANO"); -#endif -#ifdef EBADRQC - set_syserr(EBADRQC, "EBADRQC"); -#endif -#ifdef EBADSLT - set_syserr(EBADSLT, "EBADSLT"); -#endif -#ifdef EDEADLOCK - set_syserr(EDEADLOCK, "EDEADLOCK"); -#endif -#ifdef EBFONT - set_syserr(EBFONT, "EBFONT"); -#endif -#ifdef ENOSTR - set_syserr(ENOSTR, "ENOSTR"); -#endif -#ifdef ENODATA - set_syserr(ENODATA, "ENODATA"); -#endif -#ifdef ETIME - set_syserr(ETIME, "ETIME"); -#endif -#ifdef ENOSR - set_syserr(ENOSR, "ENOSR"); -#endif -#ifdef ENONET - set_syserr(ENONET, "ENONET"); -#endif -#ifdef ENOPKG - set_syserr(ENOPKG, "ENOPKG"); -#endif -#ifdef EREMOTE - set_syserr(EREMOTE, "EREMOTE"); -#endif -#ifdef ENOLINK - set_syserr(ENOLINK, "ENOLINK"); -#endif -#ifdef EADV - set_syserr(EADV, "EADV"); -#endif -#ifdef ESRMNT - set_syserr(ESRMNT, "ESRMNT"); -#endif -#ifdef ECOMM - set_syserr(ECOMM, "ECOMM"); -#endif -#ifdef EPROTO - set_syserr(EPROTO, "EPROTO"); -#endif -#ifdef EMULTIHOP - set_syserr(EMULTIHOP, "EMULTIHOP"); -#endif -#ifdef EDOTDOT - set_syserr(EDOTDOT, "EDOTDOT"); -#endif -#ifdef EBADMSG - set_syserr(EBADMSG, "EBADMSG"); -#endif -#ifdef EOVERFLOW - set_syserr(EOVERFLOW, "EOVERFLOW"); -#endif -#ifdef ENOTUNIQ - set_syserr(ENOTUNIQ, "ENOTUNIQ"); -#endif -#ifdef EBADFD - set_syserr(EBADFD, "EBADFD"); -#endif -#ifdef EREMCHG - set_syserr(EREMCHG, "EREMCHG"); -#endif -#ifdef ELIBACC - set_syserr(ELIBACC, "ELIBACC"); -#endif -#ifdef ELIBBAD - set_syserr(ELIBBAD, "ELIBBAD"); -#endif -#ifdef ELIBSCN - set_syserr(ELIBSCN, "ELIBSCN"); -#endif -#ifdef ELIBMAX - set_syserr(ELIBMAX, "ELIBMAX"); -#endif -#ifdef ELIBEXEC - set_syserr(ELIBEXEC, "ELIBEXEC"); -#endif -#ifdef EILSEQ - set_syserr(EILSEQ, "EILSEQ"); -#endif -#ifdef ERESTART - set_syserr(ERESTART, "ERESTART"); -#endif -#ifdef ESTRPIPE - set_syserr(ESTRPIPE, "ESTRPIPE"); -#endif -#ifdef EUSERS - set_syserr(EUSERS, "EUSERS"); -#endif -#ifdef ENOTSOCK - set_syserr(ENOTSOCK, "ENOTSOCK"); -#endif -#ifdef EDESTADDRREQ - set_syserr(EDESTADDRREQ, "EDESTADDRREQ"); -#endif -#ifdef EMSGSIZE - set_syserr(EMSGSIZE, "EMSGSIZE"); -#endif -#ifdef EPROTOTYPE - set_syserr(EPROTOTYPE, "EPROTOTYPE"); -#endif -#ifdef ENOPROTOOPT - set_syserr(ENOPROTOOPT, "ENOPROTOOPT"); -#endif -#ifdef EPROTONOSUPPORT - set_syserr(EPROTONOSUPPORT, "EPROTONOSUPPORT"); -#endif -#ifdef ESOCKTNOSUPPORT - set_syserr(ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT"); -#endif -#ifdef EOPNOTSUPP - set_syserr(EOPNOTSUPP, "EOPNOTSUPP"); -#endif -#ifdef EPFNOSUPPORT - set_syserr(EPFNOSUPPORT, "EPFNOSUPPORT"); -#endif -#ifdef EAFNOSUPPORT - set_syserr(EAFNOSUPPORT, "EAFNOSUPPORT"); -#endif -#ifdef EADDRINUSE - set_syserr(EADDRINUSE, "EADDRINUSE"); -#endif -#ifdef EADDRNOTAVAIL - set_syserr(EADDRNOTAVAIL, "EADDRNOTAVAIL"); -#endif -#ifdef ENETDOWN - set_syserr(ENETDOWN, "ENETDOWN"); -#endif -#ifdef ENETUNREACH - set_syserr(ENETUNREACH, "ENETUNREACH"); -#endif -#ifdef ENETRESET - set_syserr(ENETRESET, "ENETRESET"); -#endif -#ifdef ECONNABORTED - set_syserr(ECONNABORTED, "ECONNABORTED"); -#endif -#ifdef ECONNRESET - set_syserr(ECONNRESET, "ECONNRESET"); -#endif -#ifdef ENOBUFS - set_syserr(ENOBUFS, "ENOBUFS"); -#endif -#ifdef EISCONN - set_syserr(EISCONN, "EISCONN"); -#endif -#ifdef ENOTCONN - set_syserr(ENOTCONN, "ENOTCONN"); -#endif -#ifdef ESHUTDOWN - set_syserr(ESHUTDOWN, "ESHUTDOWN"); -#endif -#ifdef ETOOMANYREFS - set_syserr(ETOOMANYREFS, "ETOOMANYREFS"); -#endif -#ifdef ETIMEDOUT - set_syserr(ETIMEDOUT, "ETIMEDOUT"); -#endif -#ifdef ECONNREFUSED - set_syserr(ECONNREFUSED, "ECONNREFUSED"); -#endif -#ifdef EHOSTDOWN - set_syserr(EHOSTDOWN, "EHOSTDOWN"); -#endif -#ifdef EHOSTUNREACH - set_syserr(EHOSTUNREACH, "EHOSTUNREACH"); -#endif -#ifdef EALREADY - set_syserr(EALREADY, "EALREADY"); -#endif -#ifdef EINPROGRESS - set_syserr(EINPROGRESS, "EINPROGRESS"); -#endif -#ifdef ESTALE - set_syserr(ESTALE, "ESTALE"); -#endif -#ifdef EUCLEAN - set_syserr(EUCLEAN, "EUCLEAN"); -#endif -#ifdef ENOTNAM - set_syserr(ENOTNAM, "ENOTNAM"); -#endif -#ifdef ENAVAIL - set_syserr(ENAVAIL, "ENAVAIL"); -#endif -#ifdef EISNAM - set_syserr(EISNAM, "EISNAM"); -#endif -#ifdef EREMOTEIO - set_syserr(EREMOTEIO, "EREMOTEIO"); -#endif -#ifdef EDQUOT - set_syserr(EDQUOT, "EDQUOT"); -#endif - eNOERROR = set_syserr(0, "NOERROR"); -} - -static void -err_append(s) - const char *s; -{ - extern VALUE ruby_errinfo; - - if (ruby_in_eval) { - if (NIL_P(ruby_errinfo)) { - ruby_errinfo = rb_exc_new2(rb_eSyntaxError, s); - } - else { - VALUE str = rb_obj_as_string(ruby_errinfo); - - rb_str_cat2(str, "\n"); - rb_str_cat2(str, s); - ruby_errinfo = rb_exc_new3(rb_eSyntaxError, str); - } - } - else { - rb_write_error(s); - rb_write_error("\n"); - } -} -/********************************************************************** - euc_jp.c - Oniguruma (regular expression library) -**********************************************************************/ -/*- - * Copyright (c) 2002-2005 K.Kosako <sndgk393 AT ybb DOT ne DOT jp> - * 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 - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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. - */ - -#include "regenc.h" - -#define eucjp_islead(c) ((UChar )((c) - 0xa1) > 0xfe - 0xa1) - -static int EncLen_EUCJP[] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 -}; - -static int -eucjp_mbc_enc_len(const UChar* p) -{ - return EncLen_EUCJP[*p]; -} - -static OnigCodePoint -eucjp_mbc_to_code(const UChar* p, const UChar* end) -{ - int c, i, len; - OnigCodePoint n; - - len = enc_len(ONIG_ENCODING_EUC_JP, p); - n = (OnigCodePoint )*p++; - if (len == 1) return n; - - for (i = 1; i < len; i++) { - if (p >= end) break; - c = *p++; - n <<= 8; n += c; - } - return n; -} - -static int -eucjp_code_to_mbclen(OnigCodePoint code) -{ - if (ONIGENC_IS_CODE_ASCII(code)) return 1; - else if ((code & 0xff0000) != 0) return 3; - else if ((code & 0xff00) != 0) return 2; - else return 0; -} - -#if 0 -static int -eucjp_code_to_mbc_first(OnigCodePoint code) -{ - int first; - - if ((code & 0xff0000) != 0) { - first = (code >> 16) & 0xff; - } - else if ((code & 0xff00) != 0) { - first = (code >> 8) & 0xff; - } - else { - return (int )code; - } - return first; -} -#endif - -static int -eucjp_code_to_mbc(OnigCodePoint code, UChar *buf) -{ - UChar *p = buf; - - if ((code & 0xff0000) != 0) *p++ = (UChar )(((code >> 16) & 0xff)); - if ((code & 0xff00) != 0) *p++ = (UChar )(((code >> 8) & 0xff)); - *p++ = (UChar )(code & 0xff); - -#if 1 - if (enc_len(ONIG_ENCODING_EUC_JP, buf) != (p - buf)) - return ONIGENCERR_INVALID_WIDE_CHAR_VALUE; -#endif - return p - buf; -} - -static int -eucjp_mbc_to_normalize(OnigAmbigType flag, - const UChar** pp, const UChar* end, UChar* lower) -{ - int len; - const UChar* p = *pp; - - if (ONIGENC_IS_MBC_ASCII(p)) { - if ((flag & ONIGENC_AMBIGUOUS_MATCH_ASCII_CASE) != 0) { - *lower = ONIGENC_ASCII_CODE_TO_LOWER_CASE(*p); - } - else { - *lower = *p; - } - - (*pp)++; - return 1; - } - else { - len = enc_len(ONIG_ENCODING_EUC_JP, p); - if (lower != p) { - int i; - for (i = 0; i < len; i++) { - *lower++ = *p++; - } - } - (*pp) += len; - return len; /* return byte length of converted char to lower */ - } -} - -static int -eucjp_is_mbc_ambiguous(OnigAmbigType flag, const UChar** pp, const UChar* end) -{ - return onigenc_mbn_is_mbc_ambiguous(ONIG_ENCODING_EUC_JP, flag, pp, end); -} - -static int -eucjp_is_code_ctype(OnigCodePoint code, unsigned int ctype) -{ - if ((ctype & ONIGENC_CTYPE_WORD) != 0) { - if (code < 128) - return ONIGENC_IS_ASCII_CODE_CTYPE(code, ctype); - else - return (eucjp_code_to_mbclen(code) > 1 ? TRUE : FALSE); - - ctype &= ~ONIGENC_CTYPE_WORD; - if (ctype == 0) return FALSE; - } - - if (code < 128) - return ONIGENC_IS_ASCII_CODE_CTYPE(code, ctype); - else - return FALSE; -} - -static UChar* -eucjp_left_adjust_char_head(const UChar* start, const UChar* s) -{ - /* In this encoding - mb-trail bytes doesn't mix with single bytes. - */ - const UChar *p; - int len; - - if (s <= start) return (UChar* )s; - p = s; - - while (!eucjp_islead(*p) && p > start) p--; - len = enc_len(ONIG_ENCODING_EUC_JP, p); - if (p + len > s) return (UChar* )p; - p += len; - return (UChar* )(p + ((s - p) & ~1)); -} - -static int -eucjp_is_allowed_reverse_match(const UChar* s, const UChar* end) -{ - const UChar c = *s; - if (c <= 0x7e || c == 0x8e || c == 0x8f) - return TRUE; - else - return FALSE; -} - -OnigEncodingType OnigEncodingEUC_JP = { - eucjp_mbc_enc_len, - "EUC-JP", /* name */ - 3, /* max enc length */ - 1, /* min enc length */ - ONIGENC_AMBIGUOUS_MATCH_ASCII_CASE, - { - (OnigCodePoint )'\\' /* esc */ - , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar '.' */ - , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anytime '*' */ - , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* zero or one time '?' */ - , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* one or more time '+' */ - , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar anytime */ - }, - onigenc_is_mbc_newline_0x0a, - eucjp_mbc_to_code, - eucjp_code_to_mbclen, - eucjp_code_to_mbc, - eucjp_mbc_to_normalize, - eucjp_is_mbc_ambiguous, - onigenc_ascii_get_all_pair_ambig_codes, - onigenc_nothing_get_all_comp_ambig_codes, - eucjp_is_code_ctype, - onigenc_not_support_get_ctype_code_range, - eucjp_left_adjust_char_head, - eucjp_is_allowed_reverse_match -}; -/********************************************************************** - - eval.c - - - $Author: murphy $ - $Date: 2005-11-05 04:33:55 +0100 (Sa, 05 Nov 2005) $ - created at: Thu Jun 10 14:22:17 JST 1993 - - Copyright (C) 1993-2003 Yukihiro Matsumoto - Copyright (C) 2000 Network Applied Communication Laboratory, Inc. - Copyright (C) 2000 Information-technology Promotion Agency, Japan - -**********************************************************************/ - -#include "ruby.h" -#include "node.h" -#include "env.h" -#include "util.h" -#include "rubysig.h" - -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifndef EXIT_SUCCESS -#define EXIT_SUCCESS 0 -#endif -#ifndef EXIT_FAILURE -#define EXIT_FAILURE 1 -#endif - -#include <stdio.h> -#if defined(HAVE_GETCONTEXT) && defined(HAVE_SETCONTEXT) -#include <ucontext.h> -#define USE_CONTEXT -#else -#include <setjmp.h> -#endif - -#include "st.h" -#include "dln.h" - -#ifdef __APPLE__ -#include <crt_externs.h> -#endif - -/* Make alloca work the best possible way. */ -#ifdef __GNUC__ -# ifndef atarist -# ifndef alloca -# define alloca __builtin_alloca -# endif -# endif /* atarist */ -#else -# ifdef HAVE_ALLOCA_H -# include <alloca.h> -# else -# ifdef _AIX - #pragma alloca -# else -# ifndef alloca /* predefined by HP cc +Olibcalls */ -void *alloca (); -# endif -# endif /* AIX */ -# endif /* HAVE_ALLOCA_H */ -#endif /* __GNUC__ */ - -#ifdef HAVE_STDARG_PROTOTYPES -#include <stdarg.h> -#define va_init_list(a,b) va_start(a,b) -#else -#include <varargs.h> -#define va_init_list(a,b) va_start(a) -#endif - -#ifndef HAVE_STRING_H -char *strrchr _((const char*,const char)); -#endif - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#ifdef __BEOS__ -#include <net/socket.h> -#endif - -#ifdef __MACOS__ -#include "macruby_private.h" -#endif - -#ifdef USE_CONTEXT -typedef struct { - ucontext_t context; - volatile int status; -} rb_jmpbuf_t[1]; - -#undef longjmp -#undef setjmp -NORETURN(static void rb_jump_context(rb_jmpbuf_t, int)); -static inline void -rb_jump_context(env, val) - rb_jmpbuf_t env; - int val; -{ - env->status = val; - setcontext(&env->context); - abort(); /* ensure noreturn */ -} -#define longjmp(env, val) rb_jump_context(env, val) -#define setjmp(j) ((j)->status = 0, getcontext(&(j)->context), (j)->status) -#else -typedef jmp_buf rb_jmpbuf_t; -#ifndef setjmp -#ifdef HAVE__SETJMP -#define setjmp(env) _setjmp(env) -#define longjmp(env,val) _longjmp(env,val) -#endif -#endif -#endif - -#include <sys/types.h> -#include <signal.h> -#include <errno.h> - -#if defined(__VMS) -#pragma nostandard -#endif - -#ifdef HAVE_SYS_SELECT_H -#include <sys/select.h> -#endif - -#include <sys/stat.h> - -VALUE rb_cProc; -static VALUE rb_cBinding; -static VALUE proc_invoke _((VALUE,VALUE,VALUE,VALUE)); -static VALUE rb_f_binding _((VALUE)); -static void rb_f_END _((void)); -static VALUE rb_f_block_given_p _((void)); -static VALUE block_pass _((VALUE,NODE*)); -static VALUE rb_cMethod; -static VALUE method_call _((int, VALUE*, VALUE)); -static VALUE rb_cUnboundMethod; -static VALUE umethod_bind _((VALUE, VALUE)); -static VALUE rb_mod_define_method _((int, VALUE*, VALUE)); -NORETURN(static void rb_raise_jump _((VALUE))); -static VALUE rb_make_exception _((int argc, VALUE *argv)); - -static int scope_vmode; -#define SCOPE_PUBLIC 0 -#define SCOPE_PRIVATE 1 -#define SCOPE_PROTECTED 2 -#define SCOPE_MODFUNC 5 -#define SCOPE_MASK 7 -#define SCOPE_SET(f) (scope_vmode=(f)) -#define SCOPE_TEST(f) (scope_vmode&(f)) - -NODE* ruby_current_node; -int ruby_safe_level = 0; -/* safe-level: - 0 - strings from streams/environment/ARGV are tainted (default) - 1 - no dangerous operation by tainted value - 2 - process/file operations prohibited - 3 - all generated objects are tainted - 4 - no global (non-tainted) variable modification/no direct output -*/ - -static VALUE safe_getter _((void)); -static void safe_setter _((VALUE val)); - -void -rb_secure(level) - int level; -{ - if (level <= ruby_safe_level) { - if (ruby_frame->callee) { - rb_raise(rb_eSecurityError, "Insecure operation `%s' at level %d", - rb_id2name(ruby_frame->callee), ruby_safe_level); - } - else { - rb_raise(rb_eSecurityError, "Insecure operation at level %d", ruby_safe_level); - } - } -} - -void -rb_secure_update(obj) - VALUE obj; -{ - if (!OBJ_TAINTED(obj)) rb_secure(4); -} - -void -rb_check_safe_obj(x) - VALUE x; -{ - if (ruby_safe_level > 0 && OBJ_TAINTED(x)){ - if (ruby_frame->callee) { - rb_raise(rb_eSecurityError, "Insecure operation - %s", - rb_id2name(ruby_frame->callee)); - } - else { - rb_raise(rb_eSecurityError, "Insecure operation: -r"); - } - } - rb_secure(4); -} - -void -rb_check_safe_str(x) - VALUE x; -{ - rb_check_safe_obj(x); - if (TYPE(x)!= T_STRING) { - rb_raise(rb_eTypeError, "wrong argument type %s (expected String)", - rb_obj_classname(x)); - } -} - -NORETURN(static void print_undef _((VALUE, ID))); -static void -print_undef(klass, id) - VALUE klass; - ID id; -{ - rb_name_error(id, "undefined method `%s' for %s `%s'", - rb_id2name(id), - (TYPE(klass) == T_MODULE) ? "module" : "class", - rb_class2name(klass)); -} - -static ID removed, singleton_removed, undefined, singleton_undefined; - -#define CACHE_SIZE 0x800 -#define CACHE_MASK 0x7ff -#define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK) - -struct cache_entry { /* method hash table. */ - ID mid; /* method's id */ - ID mid0; /* method's original id */ - VALUE klass; /* receiver's class */ - VALUE origin; /* where method defined */ - NODE *method; - int noex; -}; - -static struct cache_entry cache[CACHE_SIZE]; -static int ruby_running = 0; - -void -rb_clear_cache() -{ - struct cache_entry *ent, *end; - - if (!ruby_running) return; - ent = cache; end = ent + CACHE_SIZE; - while (ent < end) { - ent->mid = 0; - ent++; - } -} - -static void -rb_clear_cache_for_undef(klass, id) - VALUE klass; - ID id; -{ - struct cache_entry *ent, *end; - - if (!ruby_running) return; - ent = cache; end = ent + CACHE_SIZE; - while (ent < end) { - if (ent->origin == klass && ent->mid == id) { - ent->mid = 0; - } - ent++; - } -} - -static void -rb_clear_cache_by_id(id) - ID id; -{ - struct cache_entry *ent, *end; - - if (!ruby_running) return; - ent = cache; end = ent + CACHE_SIZE; - while (ent < end) { - if (ent->mid == id) { - ent->mid = 0; - } - ent++; - } -} - -void -rb_clear_cache_by_class(klass) - VALUE klass; -{ - struct cache_entry *ent, *end; - - if (!ruby_running) return; - ent = cache; end = ent + CACHE_SIZE; - while (ent < end) { - if (ent->klass == klass || ent->origin == klass) { - ent->mid = 0; - } - ent++; - } -} - -static ID init, eqq, each, aref, aset, match, missing; -static ID added, singleton_added; -static ID __id__, __send__, respond_to; - -void -rb_add_method(klass, mid, node, noex) - VALUE klass; - ID mid; - NODE *node; - int noex; -{ - NODE *body; - - if (NIL_P(klass)) klass = rb_cObject; - if (ruby_safe_level >= 4 && (klass == rb_cObject || !OBJ_TAINTED(klass))) { - rb_raise(rb_eSecurityError, "Insecure: can't define method"); - } - if (!FL_TEST(klass, FL_SINGLETON) && - node && nd_type(node) != NODE_ZSUPER && - (mid == rb_intern("initialize" )|| mid == rb_intern("initialize_copy"))) { - noex = NOEX_PRIVATE | noex; - } - else if (FL_TEST(klass, FL_SINGLETON) && node && nd_type(node) == NODE_CFUNC && - mid == rb_intern("allocate")) { - rb_warn("defining %s.allocate is deprecated; use rb_define_alloc_func()", - rb_class2name(rb_iv_get(klass, "__attached__"))); - mid = ID_ALLOCATOR; - } - if (OBJ_FROZEN(klass)) rb_error_frozen("class/module"); - rb_clear_cache_by_id(mid); - body = NEW_METHOD(node, noex); - st_insert(RCLASS(klass)->m_tbl, mid, (st_data_t)body); - if (node && mid != ID_ALLOCATOR && ruby_running) { - if (FL_TEST(klass, FL_SINGLETON)) { - rb_funcall(rb_iv_get(klass, "__attached__"), singleton_added, 1, ID2SYM(mid)); - } - else { - rb_funcall(klass, added, 1, ID2SYM(mid)); - } - } -} - -void -rb_define_alloc_func(klass, func) - VALUE klass; - VALUE (*func) _((VALUE)); -{ - Check_Type(klass, T_CLASS); - rb_add_method(CLASS_OF(klass), ID_ALLOCATOR, NEW_CFUNC(func, 0), NOEX_PRIVATE); -} - -void -rb_undef_alloc_func(klass) - VALUE klass; -{ - Check_Type(klass, T_CLASS); - rb_add_method(CLASS_OF(klass), ID_ALLOCATOR, 0, NOEX_UNDEF); -} - -static NODE* -search_method(klass, id, origin) - VALUE klass, *origin; - ID id; -{ - NODE *body; - - if (!klass) return 0; - while (!st_lookup(RCLASS(klass)->m_tbl, id, (st_data_t *)&body)) { - klass = RCLASS(klass)->super; - if (!klass) return 0; - } - - if (origin) *origin = klass; - return body; -} - -static NODE* -rb_get_method_body(klassp, idp, noexp) - VALUE *klassp; - ID *idp; - int *noexp; -{ - ID id = *idp; - VALUE klass = *klassp; - VALUE origin; - NODE * volatile body; - struct cache_entry *ent; - - if ((body = search_method(klass, id, &origin)) == 0 || !body->nd_body) { - /* store empty info in cache */ - ent = cache + EXPR1(klass, id); - ent->klass = klass; - ent->origin = klass; - ent->mid = ent->mid0 = id; - ent->noex = 0; - ent->method = 0; - - return 0; - } - - if (ruby_running) { - /* store in cache */ - ent = cache + EXPR1(klass, id); - ent->klass = klass; - ent->noex = body->nd_noex; - if (noexp) *noexp = body->nd_noex; - body = body->nd_body; - if (nd_type(body) == NODE_FBODY) { - ent->mid = id; - *klassp = body->nd_orig; - ent->origin = body->nd_orig; - *idp = ent->mid0 = body->nd_mid; - body = ent->method = body->nd_head; - } - else { - *klassp = origin; - ent->origin = origin; - ent->mid = ent->mid0 = id; - ent->method = body; - } - } - else { - if (noexp) *noexp = body->nd_noex; - body = body->nd_body; - if (nd_type(body) == NODE_FBODY) { - *klassp = body->nd_orig; - *idp = body->nd_mid; - body = body->nd_head; - } - else { - *klassp = origin; - } - } - - return body; -} - -NODE* -rb_method_node(klass, id) - VALUE klass; - ID id; -{ - int noex; - struct cache_entry *ent; - - ent = cache + EXPR1(klass, id); - if (ent->mid == id && ent->klass == klass && ent->method){ - return ent->method; - } - - return rb_get_method_body(&klass, &id, &noex); -} - -static void -remove_method(klass, mid) - VALUE klass; - ID mid; -{ - NODE *body; - - if (klass == rb_cObject) { - rb_secure(4); - } - if (ruby_safe_level >= 4 && !OBJ_TAINTED(klass)) { - rb_raise(rb_eSecurityError, "Insecure: can't remove method"); - } - if (OBJ_FROZEN(klass)) rb_error_frozen("class/module"); - if (mid == __id__ || mid == __send__ || mid == init) { - rb_warn("removing `%s' may cause serious problem", rb_id2name(mid)); - } - if (!st_delete(RCLASS(klass)->m_tbl, &mid, (st_data_t *)&body) || - !body->nd_body) { - rb_name_error(mid, "method `%s' not defined in %s", - rb_id2name(mid), rb_class2name(klass)); - } - rb_clear_cache_for_undef(klass, mid); - if (FL_TEST(klass, FL_SINGLETON)) { - rb_funcall(rb_iv_get(klass, "__attached__"), singleton_removed, 1, ID2SYM(mid)); - } - else { - rb_funcall(klass, removed, 1, ID2SYM(mid)); - } -} - -void -rb_remove_method(klass, name) - VALUE klass; - const char *name; -{ - remove_method(klass, rb_intern(name)); -} - -/* - * call-seq: - * remove_method(symbol) => self - * - * Removes the method identified by _symbol_ from the current - * class. For an example, see <code>Module.undef_method</code>. - */ - -static VALUE -rb_mod_remove_method(argc, argv, mod) - int argc; - VALUE *argv; - VALUE mod; -{ - int i; - - for (i=0; i<argc; i++) { - remove_method(mod, rb_to_id(argv[i])); - } - return mod; -} - -#undef rb_disable_super -#undef rb_enable_super - -void -rb_disable_super(klass, name) - VALUE klass; - const char *name; -{ - /* obsolete - no use */ -} - -void -rb_enable_super(klass, name) - VALUE klass; - const char *name; -{ - rb_warning("rb_enable_super() is obsolete"); -} - -static void -rb_export_method(klass, name, noex) - VALUE klass; - ID name; - ID noex; -{ - NODE *body; - VALUE origin; - - if (klass == rb_cObject) { - rb_secure(4); - } - body = search_method(klass, name, &origin); - if (!body && TYPE(klass) == T_MODULE) { - body = search_method(rb_cObject, name, &origin); - } - if (!body || !body->nd_body) { - print_undef(klass, name); - } - if (body->nd_noex != noex) { - if (klass == origin) { - body->nd_noex = noex; - } - else { - rb_add_method(klass, name, NEW_ZSUPER(), noex); - } - } -} - -int -rb_method_boundp(klass, id, ex) - VALUE klass; - ID id; - int ex; -{ - struct cache_entry *ent; - int noex; - - /* is it in the method cache? */ - ent = cache + EXPR1(klass, id); - if (ent->mid == id && ent->klass == klass) { - if (ex && (ent->noex & NOEX_PRIVATE)) - return Qfalse; - if (!ent->method) return Qfalse; - return Qtrue; - } - if (rb_get_method_body(&klass, &id, &noex)) { - if (ex && (noex & NOEX_PRIVATE)) - return Qfalse; - return Qtrue; - } - return Qfalse; -} - -void -rb_attr(klass, id, read, write, ex) - VALUE klass; - ID id; - int read, write, ex; -{ - const char *name; - char *buf; - ID attriv; - int noex; - - if (!ex) noex = NOEX_PUBLIC; - else { - if (SCOPE_TEST(SCOPE_PRIVATE)) { - noex = NOEX_PRIVATE; - rb_warning((scope_vmode == SCOPE_MODFUNC) ? - "attribute accessor as module_function" : - "private attribute?"); - } - else if (SCOPE_TEST(SCOPE_PROTECTED)) { - noex = NOEX_PROTECTED; - } - else { - noex = NOEX_PUBLIC; - } - } - - if (!rb_is_local_id(id) && !rb_is_const_id(id)) { - rb_name_error(id, "invalid attribute name `%s'", rb_id2name(id)); - } - name = rb_id2name(id); - if (!name) { - rb_raise(rb_eArgError, "argument needs to be symbol or string"); - } - buf = ALLOCA_N(char,strlen(name)+2); - sprintf(buf, "@%s", name); - attriv = rb_intern(buf); - if (read) { - rb_add_method(klass, id, NEW_IVAR(attriv), noex); - } - if (write) { - rb_add_method(klass, rb_id_attrset(id), NEW_ATTRSET(attriv), noex); - } -} - -VALUE ruby_errinfo = Qnil; -extern int ruby_nerrs; - -static VALUE rb_eLocalJumpError; -static VALUE rb_eSysStackError; - -extern VALUE ruby_top_self; - -struct FRAME *ruby_frame; -struct SCOPE *ruby_scope; -static struct FRAME *top_frame; -static struct SCOPE *top_scope; - -static unsigned long frame_unique = 0; - -#define PUSH_FRAME() do { \ - struct FRAME _frame; \ - _frame.prev = ruby_frame; \ - _frame.tmp = 0; \ - _frame.node = ruby_current_node; \ - _frame.iter = ruby_iter->iter; \ - _frame.argc = 0; \ - _frame.flags = 0; \ - _frame.uniq = frame_unique++; \ - ruby_frame = &_frame - -#define POP_FRAME() \ - ruby_current_node = _frame.node; \ - ruby_frame = _frame.prev; \ -} while (0) - -struct BLOCK { - NODE *var; - NODE *body; - VALUE self; - struct FRAME frame; - struct SCOPE *scope; - VALUE klass; - NODE *cref; - int iter; - int vmode; - int flags; - int uniq; - struct RVarmap *dyna_vars; - VALUE orig_thread; - VALUE wrapper; - VALUE block_obj; - struct BLOCK *outer; - struct BLOCK *prev; -}; - -#define BLOCK_D_SCOPE 1 -#define BLOCK_LAMBDA 2 -#define BLOCK_FROM_METHOD 4 - -static struct BLOCK *ruby_block; -static unsigned long block_unique = 0; - -#define PUSH_BLOCK(v,b) do { \ - struct BLOCK _block; \ - _block.var = (v); \ - _block.body = (b); \ - _block.self = self; \ - _block.frame = *ruby_frame; \ - _block.klass = ruby_class; \ - _block.cref = ruby_cref; \ - _block.frame.node = ruby_current_node;\ - _block.scope = ruby_scope; \ - _block.prev = ruby_block; \ - _block.outer = ruby_block; \ - _block.iter = ruby_iter->iter; \ - _block.vmode = scope_vmode; \ - _block.flags = BLOCK_D_SCOPE; \ - _block.dyna_vars = ruby_dyna_vars; \ - _block.wrapper = ruby_wrapper; \ - _block.block_obj = 0; \ - _block.uniq = (b)?block_unique++:0; \ - if (b) { \ - prot_tag->blkid = _block.uniq; \ - } \ - ruby_block = &_block - -#define POP_BLOCK() \ - ruby_block = _block.prev; \ -} while (0) - -struct RVarmap *ruby_dyna_vars; -#define PUSH_VARS() do { \ - struct RVarmap * volatile _old; \ - _old = ruby_dyna_vars; \ - ruby_dyna_vars = 0 - -#define POP_VARS() \ - if (_old && (ruby_scope->flags & SCOPE_DONT_RECYCLE)) {\ - if (RBASIC(_old)->flags) /* unless it's already recycled */ \ - FL_SET(_old, DVAR_DONT_RECYCLE); \ - }\ - ruby_dyna_vars = _old; \ -} while (0) - -#define DVAR_DONT_RECYCLE FL_USER2 - -static struct RVarmap* -new_dvar(id, value, prev) - ID id; - VALUE value; - struct RVarmap *prev; -{ - NEWOBJ(vars, struct RVarmap); - OBJSETUP(vars, 0, T_VARMAP); - vars->id = id; - vars->val = value; - vars->next = prev; - - return vars; -} - -VALUE -rb_dvar_defined(id) - ID id; -{ - struct RVarmap *vars = ruby_dyna_vars; - - while (vars) { - if (vars->id == id) return Qtrue; - vars = vars->next; - } - return Qfalse; -} - -VALUE -rb_dvar_curr(id) - ID id; -{ - struct RVarmap *vars = ruby_dyna_vars; - - while (vars) { - if (vars->id == 0) break; - if (vars->id == id) return Qtrue; - vars = vars->next; - } - return Qfalse; -} - -VALUE -rb_dvar_ref(id) - ID id; -{ - struct RVarmap *vars = ruby_dyna_vars; - - while (vars) { - if (vars->id == id) { - return vars->val; - } - vars = vars->next; - } - return Qnil; -} - -void -rb_dvar_push(id, value) - ID id; - VALUE value; -{ - ruby_dyna_vars = new_dvar(id, value, ruby_dyna_vars); -} - -static void -dvar_asgn_internal(id, value, curr) - ID id; - VALUE value; - int curr; -{ - int n = 0; - struct RVarmap *vars = ruby_dyna_vars; - - while (vars) { - if (curr && vars->id == 0) { - /* first null is a dvar header */ - n++; - if (n == 2) break; - } - if (vars->id == id) { - vars->val = value; - return; - } - vars = vars->next; - } - if (!ruby_dyna_vars) { - ruby_dyna_vars = new_dvar(id, value, 0); - } - else { - vars = new_dvar(id, value, ruby_dyna_vars->next); - ruby_dyna_vars->next = vars; - } -} - -static inline void -dvar_asgn(id, value) - ID id; - VALUE value; -{ - dvar_asgn_internal(id, value, 0); -} - -static inline void -dvar_asgn_curr(id, value) - ID id; - VALUE value; -{ - dvar_asgn_internal(id, value, 1); -} - -VALUE * -rb_svar(cnt) - int cnt; -{ - struct RVarmap *vars = ruby_dyna_vars; - ID id; - - if (!ruby_scope->local_tbl) return NULL; - if (cnt >= ruby_scope->local_tbl[0]) return NULL; - id = ruby_scope->local_tbl[cnt+1]; - while (vars) { - if (vars->id == id) return &vars->val; - vars = vars->next; - } - if (ruby_scope->local_vars == 0) return NULL; - return &ruby_scope->local_vars[cnt]; -} - -struct iter { - int iter; - struct iter *prev; -}; -static struct iter *ruby_iter; - -#define ITER_NOT 0 -#define ITER_PRE 1 -#define ITER_CUR 2 - -#define PUSH_ITER(i) do { \ - struct iter _iter; \ - _iter.prev = ruby_iter; \ - _iter.iter = (i); \ - ruby_iter = &_iter - -#define POP_ITER() \ - ruby_iter = _iter.prev; \ -} while (0) - -struct tag { - rb_jmpbuf_t buf; - struct FRAME *frame; - struct iter *iter; - VALUE tag; - VALUE retval; - struct SCOPE *scope; - VALUE dst; - struct tag *prev; - int blkid; -}; -static struct tag *prot_tag; - -#define PUSH_TAG(ptag) do { \ - struct tag _tag; \ - _tag.retval = Qnil; \ - _tag.frame = ruby_frame; \ - _tag.iter = ruby_iter; \ - _tag.prev = prot_tag; \ - _tag.scope = ruby_scope; \ - _tag.tag = ptag; \ - _tag.dst = 0; \ - _tag.blkid = 0; \ - prot_tag = &_tag - -#define PROT_NONE Qfalse /* 0 */ -#define PROT_THREAD Qtrue /* 2 */ -#define PROT_FUNC INT2FIX(0) /* 1 */ -#define PROT_LOOP INT2FIX(1) /* 3 */ -#define PROT_LAMBDA INT2FIX(2) /* 5 */ -#define PROT_YIELD INT2FIX(3) /* 7 */ -#define PROT_TOP INT2FIX(4) /* 9 */ - -#define EXEC_TAG() (FLUSH_REGISTER_WINDOWS, setjmp(prot_tag->buf)) - -#define JUMP_TAG(st) do { \ - ruby_frame = prot_tag->frame; \ - ruby_iter = prot_tag->iter; \ - longjmp(prot_tag->buf,(st)); \ -} while (0) - -#define POP_TAG() \ - prot_tag = _tag.prev; \ -} while (0) - -#define TAG_DST() (_tag.dst == (VALUE)ruby_frame->uniq) - -#define TAG_RETURN 0x1 -#define TAG_BREAK 0x2 -#define TAG_NEXT 0x3 -#define TAG_RETRY 0x4 -#define TAG_REDO 0x5 -#define TAG_RAISE 0x6 -#define TAG_THROW 0x7 -#define TAG_FATAL 0x8 -#define TAG_CONTCALL 0x9 -#define TAG_THREAD 0xa -#define TAG_MASK 0xf - -VALUE ruby_class; -static VALUE ruby_wrapper; /* security wrapper */ - -#define PUSH_CLASS(c) do { \ - VALUE _class = ruby_class; \ - ruby_class = (c) - -#define POP_CLASS() ruby_class = _class; \ -} while (0) - -static NODE *ruby_cref = 0; -static NODE *top_cref; -#define PUSH_CREF(c) ruby_cref = NEW_NODE(NODE_CREF,(c),0,ruby_cref) -#define POP_CREF() ruby_cref = ruby_cref->nd_next - -#define PUSH_SCOPE() do { \ - volatile int _vmode = scope_vmode; \ - struct SCOPE * volatile _old; \ - NEWOBJ(_scope, struct SCOPE); \ - OBJSETUP(_scope, 0, T_SCOPE); \ - _scope->local_tbl = 0; \ - _scope->local_vars = 0; \ - _scope->flags = 0; \ - _old = ruby_scope; \ - ruby_scope = _scope; \ - scope_vmode = SCOPE_PUBLIC - -typedef struct thread * rb_thread_t; -static rb_thread_t curr_thread = 0; -static rb_thread_t main_thread; -static void scope_dup _((struct SCOPE *)); - -#define POP_SCOPE() \ - if (ruby_scope->flags & SCOPE_DONT_RECYCLE) {\ - if (_old) scope_dup(_old); \ - } \ - if (!(ruby_scope->flags & SCOPE_MALLOC)) {\ - ruby_scope->local_vars = 0; \ - ruby_scope->local_tbl = 0; \ - if (!(ruby_scope->flags & SCOPE_DONT_RECYCLE) && \ - ruby_scope != top_scope) { \ - rb_gc_force_recycle((VALUE)ruby_scope);\ - } \ - } \ - ruby_scope->flags |= SCOPE_NOSTACK; \ - ruby_scope = _old; \ - scope_vmode = _vmode; \ -} while (0) - -struct ruby_env { - struct ruby_env *prev; - struct FRAME *frame; - struct SCOPE *scope; - struct BLOCK *block; - struct iter *iter; - struct tag *tag; - NODE *cref; -}; - -static void push_thread_anchor _((struct ruby_env *)); -static void pop_thread_anchor _((struct ruby_env *)); - -#define PUSH_THREAD_TAG() PUSH_TAG(PROT_THREAD); \ - do { \ - struct ruby_env _interp; \ - push_thread_anchor(&_interp); -#define POP_THREAD_TAG() \ - pop_thread_anchor(&_interp); \ - } while (0); \ - POP_TAG() - -static VALUE rb_eval _((VALUE,NODE*)); -static VALUE eval _((VALUE,VALUE,VALUE,char*,int)); -static NODE *compile _((VALUE, char*, int)); - -static VALUE rb_yield_0 _((VALUE, VALUE, VALUE, int, int)); - -#define YIELD_LAMBDA_CALL 1 -#define YIELD_PROC_CALL 2 -#define YIELD_PUBLIC_DEF 4 -#define YIELD_FUNC_AVALUE 1 -#define YIELD_FUNC_SVALUE 2 - -static VALUE rb_call _((VALUE,VALUE,ID,int,const VALUE*,int)); -static VALUE module_setup _((VALUE,NODE*)); - -static VALUE massign _((VALUE,NODE*,VALUE,int)); -static void assign _((VALUE,NODE*,VALUE,int)); - -typedef struct event_hook { - rb_event_hook_func_t func; - rb_event_t events; - struct event_hook *next; -} rb_event_hook_t; - -static rb_event_hook_t *event_hooks; - -#define EXEC_EVENT_HOOK(event, node, self, id, klass) \ - do { \ - rb_event_hook_t *hook; \ - \ - for (hook = event_hooks; hook; hook = hook->next) { \ - if (hook->events & event) \ - (*hook->func)(event, node, self, id, klass); \ - } \ - } while (0) - -static VALUE trace_func = 0; -static int tracing = 0; -static void call_trace_func _((rb_event_t,NODE*,VALUE,ID,VALUE)); - -#if 0 -#define SET_CURRENT_SOURCE() (ruby_sourcefile = ruby_current_node->nd_file, \ - ruby_sourceline = nd_line(ruby_current_node)) -#else -#define SET_CURRENT_SOURCE() ((void)0) -#endif - -void -ruby_set_current_source() -{ - if (ruby_current_node) { - ruby_sourcefile = ruby_current_node->nd_file; - ruby_sourceline = nd_line(ruby_current_node); - } -} - -static void -#ifdef HAVE_STDARG_PROTOTYPES -warn_printf(const char *fmt, ...) -#else -warn_printf(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - char buf[BUFSIZ]; - va_list args; - - va_init_list(args, fmt); - vsnprintf(buf, BUFSIZ, fmt, args); - va_end(args); - rb_write_error(buf); -} - -#define warn_print(x) rb_write_error(x) -#define warn_print2(x,l) rb_write_error2(x,l) - -static void -error_pos() -{ - ruby_set_current_source(); - if (ruby_sourcefile) { - if (ruby_frame->callee) { - warn_printf("%s:%d:in `%s'", ruby_sourcefile, ruby_sourceline, - rb_id2name(ruby_frame->callee)); - } - else if (ruby_sourceline == 0) { - warn_printf("%s", ruby_sourcefile); - } - else { - warn_printf("%s:%d", ruby_sourcefile, ruby_sourceline); - } - } -} - -static VALUE -get_backtrace(info) - VALUE info; -{ - if (NIL_P(info)) return Qnil; - info = rb_funcall(info, rb_intern("backtrace"), 0); - if (NIL_P(info)) return Qnil; - return rb_check_array_type(info); -} - -static void -set_backtrace(info, bt) - VALUE info, bt; -{ - rb_funcall(info, rb_intern("set_backtrace"), 1, bt); -} - -static void -error_print() -{ - VALUE errat = Qnil; /* OK */ - volatile VALUE eclass, e; - char *einfo; - long elen; - - if (NIL_P(ruby_errinfo)) return; - - PUSH_TAG(PROT_NONE); - if (EXEC_TAG() == 0) { - errat = get_backtrace(ruby_errinfo); - } - else { - errat = Qnil; - } - if (EXEC_TAG()) goto error; - if (NIL_P(errat)){ - ruby_set_current_source(); - if (ruby_sourcefile) - warn_printf("%s:%d", ruby_sourcefile, ruby_sourceline); - else - warn_printf("%d", ruby_sourceline); - } - else if (RARRAY(errat)->len == 0) { - error_pos(); - } - else { - VALUE mesg = RARRAY(errat)->ptr[0]; - - if (NIL_P(mesg)) error_pos(); - else { - warn_print2(RSTRING(mesg)->ptr, RSTRING(mesg)->len); - } - } - - eclass = CLASS_OF(ruby_errinfo); - if (EXEC_TAG() == 0) { - e = rb_funcall(ruby_errinfo, rb_intern("message"), 0, 0); - StringValue(e); - einfo = RSTRING(e)->ptr; - elen = RSTRING(e)->len; - } - else { - einfo = ""; - elen = 0; - } - if (EXEC_TAG()) goto error; - if (eclass == rb_eRuntimeError && elen == 0) { - warn_print(": unhandled exception\n"); - } - else { - VALUE epath; - - epath = rb_class_name(eclass); - if (elen == 0) { - warn_print(": "); - warn_print2(RSTRING(epath)->ptr, RSTRING(epath)->len); - warn_print("\n"); - } - else { - char *tail = 0; - long len = elen; - - if (RSTRING(epath)->ptr[0] == '#') epath = 0; - if (tail = memchr(einfo, '\n', elen)) { - len = tail - einfo; - tail++; /* skip newline */ - } - warn_print(": "); - warn_print2(einfo, len); - if (epath) { - warn_print(" ("); - warn_print2(RSTRING(epath)->ptr, RSTRING(epath)->len); - warn_print(")\n"); - } - if (tail) { - warn_print2(tail, elen-len-1); - } - } - } - - if (!NIL_P(errat)) { - long i; - struct RArray *ep = RARRAY(errat); - -#define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5) -#define TRACE_HEAD 8 -#define TRACE_TAIL 5 - - ep = RARRAY(errat); - for (i=1; i<ep->len; i++) { - if (TYPE(ep->ptr[i]) == T_STRING) { - warn_printf("\tfrom %s\n", RSTRING(ep->ptr[i])->ptr); - } - if (i == TRACE_HEAD && ep->len > TRACE_MAX) { - warn_printf("\t ... %ld levels...\n", - ep->len - TRACE_HEAD - TRACE_TAIL); - i = ep->len - TRACE_TAIL; - } - } - } - error: - POP_TAG(); -} - -#if defined(__APPLE__) -#define environ (*_NSGetEnviron()) -#elif !defined(_WIN32) && !defined(__MACOS__) || defined(_WIN32_WCE) -extern char **environ; -#endif -char **rb_origenviron; - -void rb_call_inits _((void)); -void Init_stack _((VALUE*)); -void Init_heap _((void)); -void Init_ext _((void)); - -#ifdef HAVE_NATIVETHREAD -static rb_nativethread_t ruby_thid; -int -is_ruby_native_thread() -{ - return NATIVETHREAD_EQUAL(ruby_thid, NATIVETHREAD_CURRENT()); -} - -# ifdef HAVE_NATIVETHREAD_KILL -void -ruby_native_thread_kill(sig) - int sig; -{ - NATIVETHREAD_KILL(ruby_thid, sig); -} -# endif -#endif - -NORETURN(static void rb_thread_start_1 _((void))); - -void -ruby_init() -{ - static int initialized = 0; - static struct FRAME frame; - static struct iter iter; - int state; - - if (initialized) - return; - initialized = 1; -#ifdef HAVE_NATIVETHREAD - ruby_thid = NATIVETHREAD_CURRENT(); -#endif - - ruby_frame = top_frame = &frame; - ruby_iter = &iter; - -#ifdef __MACOS__ - rb_origenviron = 0; -#else - rb_origenviron = environ; -#endif - - Init_stack((void*)&state); - Init_heap(); - PUSH_SCOPE(); - top_scope = ruby_scope; - /* default visibility is private at toplevel */ - SCOPE_SET(SCOPE_PRIVATE); - - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - rb_call_inits(); - ruby_class = rb_cObject; - ruby_frame->self = ruby_top_self; - top_cref = rb_node_newnode(NODE_CREF,rb_cObject,0,0); - ruby_cref = top_cref; - rb_define_global_const("TOPLEVEL_BINDING", rb_f_binding(ruby_top_self)); -#ifdef __MACOS__ - _macruby_init(); -#endif - ruby_prog_init(); - ALLOW_INTS; - } - POP_TAG(); - if (state) { - error_print(); - exit(EXIT_FAILURE); - } - POP_SCOPE(); - ruby_scope = top_scope; - top_scope->flags &= ~SCOPE_NOSTACK; - ruby_running = 1; -} - -static VALUE -eval_node(self, node) - VALUE self; - NODE *node; -{ - if (!node) return Qnil; - if (nd_type(node) == NODE_PRELUDE) { - rb_eval(self, node->nd_head); - node = node->nd_body; - } - if (!node) return Qnil; - return rb_eval(self, node); -} - -int ruby_in_eval; - -static void rb_thread_cleanup _((void)); -static void rb_thread_wait_other_threads _((void)); - -static int thread_set_raised(); -static int thread_reset_raised(); - -static VALUE exception_error; -static VALUE sysstack_error; - -static int -error_handle(ex) - int ex; -{ - int status = EXIT_FAILURE; - - if (thread_set_raised()) return EXIT_FAILURE; - switch (ex & TAG_MASK) { - case 0: - status = EXIT_SUCCESS; - break; - - case TAG_RETURN: - error_pos(); - warn_print(": unexpected return\n"); - break; - case TAG_NEXT: - error_pos(); - warn_print(": unexpected next\n"); - break; - case TAG_BREAK: - error_pos(); - warn_print(": unexpected break\n"); - break; - case TAG_REDO: - error_pos(); - warn_print(": unexpected redo\n"); - break; - case TAG_RETRY: - error_pos(); - warn_print(": retry outside of rescue clause\n"); - break; - case TAG_THROW: - if (prot_tag && prot_tag->frame && prot_tag->frame->node) { - NODE *tag = prot_tag->frame->node; - warn_printf("%s:%d: uncaught throw\n", - tag->nd_file, nd_line(tag)); - } - else { - error_pos(); - warn_printf(": unexpected throw\n"); - } - break; - case TAG_RAISE: - case TAG_FATAL: - if (rb_obj_is_kind_of(ruby_errinfo, rb_eSystemExit)) { - VALUE st = rb_iv_get(ruby_errinfo, "status"); - status = NUM2INT(st); - } - else { - error_print(); - } - break; - default: - rb_bug("Unknown longjmp status %d", ex); - break; - } - thread_reset_raised(); - return status; -} - -void -ruby_options(argc, argv) - int argc; - char **argv; -{ - int state; - -#ifdef _WIN32 - argc = rb_w32_cmdvector(GetCommandLine(), &argv); -#endif - - Init_stack((void*)&state); - PUSH_THREAD_TAG(); - if ((state = EXEC_TAG()) == 0) { - ruby_process_options(argc, argv); - } - else { - if (state == TAG_THREAD) { - rb_thread_start_1(); - } - trace_func = 0; - tracing = 0; - exit(error_handle(state)); - } - POP_THREAD_TAG(); - -#ifdef _WIN32_WCE - wce_FreeCommandLine(); -#endif -} - -void rb_exec_end_proc _((void)); - -static void -ruby_finalize_0() -{ - PUSH_TAG(PROT_NONE); - if (EXEC_TAG() == 0) { - rb_trap_exit(); - } - POP_TAG(); - rb_exec_end_proc(); -} - -static void -ruby_finalize_1() -{ - signal(SIGINT, SIG_DFL); - ruby_errinfo = 0; - rb_gc_call_finalizer_at_exit(); - trace_func = 0; - tracing = 0; -} - -void -ruby_finalize() -{ - ruby_finalize_0(); - ruby_finalize_1(); -} - -int -ruby_cleanup(ex) - int ex; -{ - int state; - volatile VALUE err = ruby_errinfo; - - ruby_safe_level = 0; - Init_stack((void*)&state); - PUSH_THREAD_TAG(); - PUSH_ITER(ITER_NOT); - if ((state = EXEC_TAG()) == 0) { - ruby_finalize_0(); - if (ruby_errinfo) err = ruby_errinfo; - rb_thread_cleanup(); - rb_thread_wait_other_threads(); - } - else if (state == TAG_THREAD) { - rb_thread_start_1(); - } - else if (ex == 0) { - ex = state; - } - POP_ITER(); - ruby_errinfo = err; - ex = error_handle(ex); - ruby_finalize_1(); - POP_THREAD_TAG(); - - if (err && rb_obj_is_kind_of(err, rb_eSystemExit)) { - VALUE st = rb_iv_get(err, "status"); - return NUM2INT(st); - } - return ex; -} - -extern NODE *ruby_eval_tree; - -static void cont_call _((VALUE)); - -static int -ruby_exec_internal() -{ - int state; - - PUSH_THREAD_TAG(); - PUSH_ITER(ITER_NOT); - /* default visibility is private at toplevel */ - SCOPE_SET(SCOPE_PRIVATE); - if ((state = EXEC_TAG()) == 0) { - eval_node(ruby_top_self, ruby_eval_tree); - } -#if 0 - else if (state == TAG_CONTCALL) { - cont_call(prot_tag->retval); - } -#endif - else if (state == TAG_THREAD) { - rb_thread_start_1(); - } - POP_ITER(); - POP_THREAD_TAG(); - return state; -} - -int -ruby_exec() -{ - volatile NODE *tmp; - - Init_stack((void*)&tmp); - return ruby_exec_internal(); -} - -void -ruby_stop(ex) - int ex; -{ - exit(ruby_cleanup(ex)); -} - -void -ruby_run() -{ - int state; - static int ex; - - if (ruby_nerrs > 0) exit(EXIT_FAILURE); - state = ruby_exec(); - if (state && !ex) ex = state; - ruby_stop(ex); -} - -static void -compile_error(at) - const char *at; -{ - VALUE str; - - ruby_nerrs = 0; - str = rb_str_buf_new2("compile error"); - if (at) { - rb_str_buf_cat2(str, " in "); - rb_str_buf_cat2(str, at); - } - rb_str_buf_cat(str, "\n", 1); - if (!NIL_P(ruby_errinfo)) { - rb_str_append(str, rb_obj_as_string(ruby_errinfo)); - } - rb_exc_raise(rb_exc_new3(rb_eSyntaxError, str)); -} - -VALUE -rb_eval_string(str) - const char *str; -{ - VALUE v; - NODE *oldsrc = ruby_current_node; - - ruby_current_node = 0; - ruby_sourcefile = rb_source_filename("(eval)"); - v = eval(ruby_top_self, rb_str_new2(str), Qnil, 0, 0); - ruby_current_node = oldsrc; - - return v; -} - -VALUE -rb_eval_string_protect(str, state) - const char *str; - int *state; -{ - return rb_protect((VALUE (*)_((VALUE)))rb_eval_string, (VALUE)str, state); -} - -VALUE -rb_eval_string_wrap(str, state) - const char *str; - int *state; -{ - int status; - VALUE self = ruby_top_self; - VALUE wrapper = ruby_wrapper; - VALUE val; - - PUSH_CLASS(ruby_wrapper = rb_module_new()); - ruby_top_self = rb_obj_clone(ruby_top_self); - rb_extend_object(ruby_top_self, ruby_wrapper); - PUSH_FRAME(); - ruby_frame->callee = 0; - ruby_frame->this_func = 0; - ruby_frame->this_class = 0; - ruby_frame->self = self; - PUSH_CREF(ruby_wrapper); - PUSH_SCOPE(); - - val = rb_eval_string_protect(str, &status); - ruby_top_self = self; - - POP_SCOPE(); - POP_FRAME(); - POP_CLASS(); - ruby_wrapper = wrapper; - if (state) { - *state = status; - } - else if (status) { - JUMP_TAG(status); - } - return val; -} - -NORETURN(static void localjump_error(const char*, VALUE, int)); -static void -localjump_error(mesg, value, reason) - const char *mesg; - VALUE value; - int reason; -{ - VALUE exc = rb_exc_new2(rb_eLocalJumpError, mesg); - ID id; - - rb_iv_set(exc, "@exit_value", value); - switch (reason) { - case TAG_BREAK: - id = rb_intern("break"); break; - case TAG_REDO: - id = rb_intern("redo"); break; - case TAG_RETRY: - id = rb_intern("retry"); break; - case TAG_NEXT: - id = rb_intern("next"); break; - case TAG_RETURN: - id = rb_intern("return"); break; - default: - id = rb_intern("noreason"); break; - } - rb_iv_set(exc, "@reason", ID2SYM(id)); - rb_exc_raise(exc); -} - -/* - * call_seq: - * local_jump_error.exit_value => obj - * - * Returns the exit value associated with this +LocalJumpError+. - */ -static VALUE -localjump_xvalue(exc) - VALUE exc; -{ - return rb_iv_get(exc, "@exit_value"); -} - -/* - * call-seq: - * local_jump_error.reason => symbol - * - * The reason this block was terminated: - * :break, :redo, :retry, :next, :return, or :noreason. - */ - -static VALUE -localjump_reason(exc) - VALUE exc; -{ - return rb_iv_get(exc, "@reason"); -} - -NORETURN(static void jump_tag_but_local_jump _((int,VALUE))); -static void -jump_tag_but_local_jump(state, val) - int state; - VALUE val; -{ - - if (val == Qundef) val = prot_tag->retval; - switch (state) { - case 0: - break; - case TAG_RETURN: - localjump_error("unexpected return", val, state); - break; - case TAG_BREAK: - localjump_error("unexpected break", val, state); - break; - case TAG_NEXT: - localjump_error("unexpected next", val, state); - break; - case TAG_REDO: - localjump_error("unexpected redo", Qnil, state); - break; - case TAG_RETRY: - localjump_error("retry outside of rescue clause", Qnil, state); - break; - default: - break; - } - JUMP_TAG(state); -} - -VALUE -rb_eval_cmd(cmd, arg, level) - VALUE cmd, arg; - int level; -{ - int state; - VALUE val = Qnil; /* OK */ - struct SCOPE *saved_scope; - volatile int safe = ruby_safe_level; - - if (OBJ_TAINTED(cmd)) { - level = 4; - } - if (TYPE(cmd) != T_STRING) { - PUSH_ITER(ITER_NOT); - PUSH_TAG(PROT_NONE); - ruby_safe_level = level; - if ((state = EXEC_TAG()) == 0) { - val = rb_funcall2(cmd, rb_intern("call"), RARRAY(arg)->len, RARRAY(arg)->ptr); - } - ruby_safe_level = safe; - POP_TAG(); - POP_ITER(); - if (state) JUMP_TAG(state); - return val; - } - - saved_scope = ruby_scope; - ruby_scope = top_scope; - PUSH_FRAME(); - ruby_frame->callee = 0; - ruby_frame->this_func = 0; - ruby_frame->this_class = 0; - ruby_frame->self = ruby_top_self; - PUSH_CREF(ruby_wrapper ? ruby_wrapper : rb_cObject); - - ruby_safe_level = level; - - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - val = eval(ruby_top_self, cmd, Qnil, 0, 0); - } - if (ruby_scope->flags & SCOPE_DONT_RECYCLE) - scope_dup(saved_scope); - ruby_scope = saved_scope; - ruby_safe_level = safe; - POP_TAG(); - POP_FRAME(); - - jump_tag_but_local_jump(state, val); - return val; -} - -#define ruby_cbase (ruby_cref->nd_clss) - -static VALUE -ev_const_defined(cref, id, self) - NODE *cref; - ID id; - VALUE self; -{ - NODE *cbase = cref; - VALUE result; - - while (cbase && cbase->nd_next) { - struct RClass *klass = RCLASS(cbase->nd_clss); - - if (NIL_P(klass)) return rb_const_defined(CLASS_OF(self), id); - if (klass->iv_tbl && st_lookup(klass->iv_tbl, id, &result)) { - if (result == Qundef && NIL_P(rb_autoload_p((VALUE)klass, id))) { - return Qfalse; - } - return Qtrue; - } - cbase = cbase->nd_next; - } - return rb_const_defined(cref->nd_clss, id); -} - -static VALUE -ev_const_get(cref, id, self) - NODE *cref; - ID id; - VALUE self; -{ - NODE *cbase = cref; - VALUE result; - - while (cbase && cbase->nd_next) { - VALUE klass = cbase->nd_clss; - - if (NIL_P(klass)) return rb_const_get(CLASS_OF(self), id); - while (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, &result)) { - if (result == Qundef) { - rb_autoload_load(klass, id); - continue; - } - return result; - } - cbase = cbase->nd_next; - } - return rb_const_get(cref->nd_clss, id); -} - -static VALUE -cvar_cbase() -{ - NODE *cref = ruby_cref; - - while (cref && cref->nd_next && (NIL_P(cref->nd_clss) || FL_TEST(cref->nd_clss, FL_SINGLETON))) { - cref = cref->nd_next; - if (!cref->nd_next) { - rb_warn("class variable access from toplevel singleton method"); - } - } - if (NIL_P(cref->nd_clss)) { - rb_raise(rb_eTypeError, "no class variables available"); - } - return cref->nd_clss; -} - -/* - * call-seq: - * Module.nesting => array - * - * Returns the list of +Modules+ nested at the point of call. - * - * module M1 - * module M2 - * $a = Module.nesting - * end - * end - * $a #=> [M1::M2, M1] - * $a[0].name #=> "M1::M2" - */ - -static VALUE -rb_mod_nesting() -{ - NODE *cbase = ruby_cref; - VALUE ary = rb_ary_new(); - - while (cbase && cbase->nd_next) { - if (!NIL_P(cbase->nd_clss)) rb_ary_push(ary, cbase->nd_clss); - cbase = cbase->nd_next; - } - if (ruby_wrapper && RARRAY(ary)->len == 0) { - rb_ary_push(ary, ruby_wrapper); - } - return ary; -} - -/* - * call-seq: - * Module.constants => array - * - * Returns an array of the names of all constants defined in the - * system. This list includes the names of all modules and classes. - * - * p Module.constants.sort[1..5] - * - * <em>produces:</em> - * - * ["ARGV", "ArgumentError", "Array", "Bignum", "Binding"] - */ - -static VALUE -rb_mod_s_constants() -{ - NODE *cbase = ruby_cref; - void *data = 0; - - while (cbase) { - if (!NIL_P(cbase->nd_clss)) { - data = rb_mod_const_at(cbase->nd_clss, data); - } - cbase = cbase->nd_next; - } - - if (!NIL_P(ruby_cbase)) { - data = rb_mod_const_of(ruby_cbase, data); - } - return rb_const_list(data); -} - -void -rb_frozen_class_p(klass) - VALUE klass; -{ - char *desc = "something(?!)"; - - if (OBJ_FROZEN(klass)) { - if (FL_TEST(klass, FL_SINGLETON)) - desc = "object"; - else { - switch (TYPE(klass)) { - case T_MODULE: - case T_ICLASS: - desc = "module"; break; - case T_CLASS: - desc = "class"; break; - } - } - rb_error_frozen(desc); - } -} - -void -rb_undef(klass, id) - VALUE klass; - ID id; -{ - VALUE origin; - NODE *body; - - if (ruby_cbase == rb_cObject && klass == rb_cObject) { - rb_secure(4); - } - if (ruby_safe_level >= 4 && !OBJ_TAINTED(klass)) { - rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'", rb_id2name(id)); - } - rb_frozen_class_p(klass); - if (id == __id__ || id == __send__ || id == init) { - rb_warn("undefining `%s' may cause serious problem", rb_id2name(id)); - } - body = search_method(klass, id, &origin); - if (!body || !body->nd_body) { - char *s0 = " class"; - VALUE c = klass; - - if (FL_TEST(c, FL_SINGLETON)) { - VALUE obj = rb_iv_get(klass, "__attached__"); - - switch (TYPE(obj)) { - case T_MODULE: - case T_CLASS: - c = obj; - s0 = ""; - } - } - else if (TYPE(c) == T_MODULE) { - s0 = " module"; - } - rb_name_error(id, "undefined method `%s' for%s `%s'", - rb_id2name(id),s0,rb_class2name(c)); - } - rb_add_method(klass, id, 0, NOEX_PUBLIC); - if (FL_TEST(klass, FL_SINGLETON)) { - rb_funcall(rb_iv_get(klass, "__attached__"), - singleton_undefined, 1, ID2SYM(id)); - } - else { - rb_funcall(klass, undefined, 1, ID2SYM(id)); - } -} - -/* - * call-seq: - * undef_method(symbol) => self - * - * Prevents the current class from responding to calls to the named - * method. Contrast this with <code>remove_method</code>, which deletes - * the method from the particular class; Ruby will still search - * superclasses and mixed-in modules for a possible receiver. - * - * class Parent - * def hello - * puts "In parent" - * end - * end - * class Child < Parent - * def hello - * puts "In child" - * end - * end - * - * - * c = Child.new - * c.hello - * - * - * class Child - * remove_method :hello # remove from child, still in parent - * end - * c.hello - * - * - * class Child - * undef_method :hello # prevent any calls to 'hello' - * end - * c.hello - * - * <em>produces:</em> - * - * In child - * In parent - * prog.rb:23: undefined method `hello' for #<Child:0x401b3bb4> (NoMethodError) - */ - -static VALUE -rb_mod_undef_method(argc, argv, mod) - int argc; - VALUE *argv; - VALUE mod; -{ - int i; - - for (i=0; i<argc; i++) { - rb_undef(mod, rb_to_id(argv[i])); - } - return mod; -} - -void -rb_alias(klass, name, def) - VALUE klass; - ID name, def; -{ - VALUE origin; - NODE *orig, *body, *node; - VALUE singleton = 0; - - rb_frozen_class_p(klass); - if (name == def) return; - if (klass == rb_cObject) { - rb_secure(4); - } - orig = search_method(klass, def, &origin); - if (!orig || !orig->nd_body) { - if (TYPE(klass) == T_MODULE) { - orig = search_method(rb_cObject, def, &origin); - } - } - if (!orig || !orig->nd_body) { - print_undef(klass, def); - } - if (FL_TEST(klass, FL_SINGLETON)) { - singleton = rb_iv_get(klass, "__attached__"); - } - body = orig->nd_body; - orig->nd_cnt++; - if (nd_type(body) == NODE_FBODY) { /* was alias */ - def = body->nd_mid; - origin = body->nd_orig; - body = body->nd_head; - } - - rb_clear_cache_by_id(name); - if (RTEST(ruby_verbose) && st_lookup(RCLASS(klass)->m_tbl, name, (st_data_t *)&node)) { - if (node->nd_cnt == 0 && node->nd_body) { - rb_warning("discarding old %s", rb_id2name(name)); - } - } - st_insert(RCLASS(klass)->m_tbl, name, - (st_data_t)NEW_METHOD(NEW_FBODY(body, def, origin), orig->nd_noex)); - if (singleton) { - rb_funcall(singleton, singleton_added, 1, ID2SYM(name)); - } - else { - rb_funcall(klass, added, 1, ID2SYM(name)); - } -} - -/* - * call-seq: - * alias_method(new_name, old_name) => self - * - * Makes <i>new_name</i> a new copy of the method <i>old_name</i>. This can - * be used to retain access to methods that are overridden. - * - * module Mod - * alias_method :orig_exit, :exit - * def exit(code=0) - * puts "Exiting with code #{code}" - * orig_exit(code) - * end - * end - * include Mod - * exit(99) - * - * <em>produces:</em> - * - * Exiting with code 99 - */ - -static VALUE -rb_mod_alias_method(mod, newname, oldname) - VALUE mod, newname, oldname; -{ - rb_alias(mod, rb_to_id(newname), rb_to_id(oldname)); - return mod; -} - -static NODE* -copy_node_scope(node, rval) - NODE *node; - NODE *rval; -{ - NODE *copy = NEW_NODE(NODE_SCOPE,0,rval,node->nd_next); - - if (node->nd_tbl) { - copy->nd_tbl = ALLOC_N(ID, node->nd_tbl[0]+1); - MEMCPY(copy->nd_tbl, node->nd_tbl, ID, node->nd_tbl[0]+1); - } - else { - copy->nd_tbl = 0; - } - return copy; -} - -#ifdef C_ALLOCA -# define TMP_PROTECT NODE * volatile tmp__protect_tmp=0 -# define TMP_ALLOC(n) \ - (tmp__protect_tmp = rb_node_newnode(NODE_ALLOCA, \ - ALLOC_N(VALUE,n),tmp__protect_tmp,n), \ - (void*)tmp__protect_tmp->nd_head) -#else -# define TMP_PROTECT typedef int foobazzz -# define TMP_ALLOC(n) ALLOCA_N(VALUE,n) -#endif - -#define SETUP_ARGS0(anode,alen) do {\ - NODE *n = anode;\ - if (!n) {\ - argc = 0;\ - argv = 0;\ - }\ - else if (nd_type(n) == NODE_ARRAY) {\ - argc=alen;\ - if (argc > 0) {\ - int i;\ - n = anode;\ - argv = TMP_ALLOC(argc);\ - for (i=0;i<argc;i++) {\ - argv[i] = rb_eval(self,n->nd_head);\ - n=n->nd_next;\ - }\ - }\ - else {\ - argc = 0;\ - argv = 0;\ - }\ - }\ - else {\ - VALUE args = rb_eval(self,n);\ - if (TYPE(args) != T_ARRAY)\ - args = rb_ary_to_ary(args);\ - argc = RARRAY(args)->len;\ - argv = ALLOCA_N(VALUE, argc);\ - MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc);\ - }\ -} while (0) - -#define SETUP_ARGS(anode) SETUP_ARGS0(anode, anode->nd_alen) - -#define BEGIN_CALLARGS do {\ - struct BLOCK *tmp_block = ruby_block;\ - int tmp_iter = ruby_iter->iter;\ - if (tmp_iter == ITER_PRE) {\ - ruby_block = ruby_block->outer;\ - tmp_iter = ITER_NOT;\ - }\ - PUSH_ITER(tmp_iter) - -#define END_CALLARGS \ - ruby_block = tmp_block;\ - POP_ITER();\ -} while (0) - -#define MATCH_DATA *rb_svar(node->nd_cnt) - -static const char* is_defined _((VALUE, NODE*, char*, int)); - -static char* -arg_defined(self, node, buf, type) - VALUE self; - NODE *node; - char *buf; - char *type; -{ - int argc; - int i; - - if (!node) return type; /* no args */ - if (nd_type(node) == NODE_ARRAY) { - argc=node->nd_alen; - if (argc > 0) { - for (i=0;i<argc;i++) { - if (!is_defined(self, node->nd_head, buf, 0)) - return 0; - node = node->nd_next; - } - } - } - else if (!is_defined(self, node, buf, 0)) { - return 0; - } - return type; -} - -static const char* -is_defined(self, node, buf, noeval) - VALUE self; - NODE *node; /* OK */ - char *buf; - int noeval; -{ - VALUE val; /* OK */ - int state; - static const char *ex = "expression"; - - if (!node) return ex; - switch (nd_type(node)) { - case NODE_SUPER: - case NODE_ZSUPER: - if (ruby_frame->this_func == 0) return 0; - else if (ruby_frame->this_class == 0) return 0; - val = ruby_frame->this_class; - if (rb_method_boundp(RCLASS(val)->super, ruby_frame->this_func, 0)) { - if (nd_type(node) == NODE_SUPER) { - return arg_defined(self, node->nd_args, buf, "super"); - } - return "super"; - } - break; - - case NODE_VCALL: - case NODE_FCALL: - val = self; - goto check_bound; - - case NODE_ATTRASGN: - val = self; - if (node->nd_recv == (NODE *)1) goto check_bound; - case NODE_CALL: - if (!is_defined(self, node->nd_recv, buf, Qtrue)) return 0; - if (noeval) return ex; - val = rb_eval(self, node->nd_recv); - check_bound: - { - int call = nd_type(node)==NODE_CALL; - - val = CLASS_OF(val); - if (call) { - int noex; - ID id = node->nd_mid; - - if (!rb_get_method_body(&val, &id, &noex)) - break; - if ((noex & NOEX_PRIVATE)) - break; - if ((noex & NOEX_PROTECTED) && - !rb_obj_is_kind_of(self, rb_class_real(val))) - break; - } - else if (!rb_method_boundp(val, node->nd_mid, call)) - break; - return arg_defined(self, node->nd_args, buf, - nd_type(node) == NODE_ATTRASGN ? - "assignment" : "method"); - } - break; - - case NODE_MATCH2: - case NODE_MATCH3: - return "method"; - - case NODE_YIELD: - if (rb_block_given_p()) { - return "yield"; - } - break; - - case NODE_SELF: - return "self"; - - case NODE_NIL: - return "nil"; - - case NODE_TRUE: - return "true"; - - case NODE_FALSE: - return "false"; - - case NODE_ATTRSET: - case NODE_OP_ASGN1: - case NODE_OP_ASGN2: - case NODE_MASGN: - case NODE_LASGN: - case NODE_DASGN: - case NODE_DASGN_CURR: - case NODE_GASGN: - case NODE_IASGN: - case NODE_CDECL: - case NODE_CVDECL: - case NODE_CVASGN: - return "assignment"; - - case NODE_LVAR: - return "local-variable"; - case NODE_DVAR: - return "local-variable(in-block)"; - - case NODE_GVAR: - if (rb_gvar_defined(node->nd_entry)) { - return "global-variable"; - } - break; - - case NODE_IVAR: - if (rb_ivar_defined(self, node->nd_vid)) { - return "instance-variable"; - } - break; - - case NODE_CONST: - if (ev_const_defined(ruby_cref, node->nd_vid, self)) { - return "constant"; - } - break; - - case NODE_CVAR: - if (rb_cvar_defined(cvar_cbase(), node->nd_vid)) { - return "class variable"; - } - break; - - case NODE_COLON2: - if (!is_defined(self, node->nd_recv, buf, Qtrue)) return 0; - if (noeval) return ex; - val = rb_eval(self, node->nd_recv); - switch (TYPE(val)) { - case T_CLASS: - case T_MODULE: - if (rb_const_defined_from(val, node->nd_mid)) - return "constant"; - break; - default: - if (rb_method_boundp(CLASS_OF(val), node->nd_mid, 1)) { - return "method"; - } - } - break; - - case NODE_COLON3: - if (rb_const_defined_from(rb_cObject, node->nd_mid)) { - return "constant"; - } - break; - - case NODE_NTH_REF: - if (RTEST(rb_reg_nth_defined(node->nd_nth, MATCH_DATA))) { - if (!buf) return ex; - sprintf(buf, "$%d", (int)node->nd_nth); - return buf; - } - break; - - case NODE_BACK_REF: - if (RTEST(rb_reg_nth_defined(0, MATCH_DATA))) { - if (!buf) return ex; - sprintf(buf, "$%c", (char)node->nd_nth); - return buf; - } - break; - - default: - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - rb_eval(self, node); - } - POP_TAG(); - if (!state) { - return ex; - } - ruby_errinfo = Qnil; - break; - } - return 0; -} - -static int handle_rescue _((VALUE,NODE*)); - -static void blk_free(); - -static VALUE -rb_obj_is_proc(proc) - VALUE proc; -{ - if (TYPE(proc) == T_DATA && RDATA(proc)->dfree == (RUBY_DATA_FUNC)blk_free) { - return Qtrue; - } - return Qfalse; -} - -void -rb_add_event_hook(func, events) - rb_event_hook_func_t func; - rb_event_t events; -{ - rb_event_hook_t *hook; - - hook = ALLOC(rb_event_hook_t); - hook->func = func; - hook->events = events; - hook->next = event_hooks; - event_hooks = hook; -} - -int -rb_remove_event_hook(func) - rb_event_hook_func_t func; -{ - rb_event_hook_t *prev, *hook; - - prev = NULL; - hook = event_hooks; - while (hook) { - if (hook->func == func) { - if (prev) { - prev->next = hook->next; - } - else { - event_hooks = hook->next; - } - xfree(hook); - return 0; - } - prev = hook; - hook = hook->next; - } - return -1; -} - -/* - * call-seq: - * set_trace_func(proc) => proc - * set_trace_func(nil) => nil - * - * Establishes _proc_ as the handler for tracing, or disables - * tracing if the parameter is +nil+. _proc_ takes up - * to six parameters: an event name, a filename, a line number, an - * object id, a binding, and the name of a class. _proc_ is - * invoked whenever an event occurs. Events are: <code>c-call</code> - * (call a C-language routine), <code>c-return</code> (return from a - * C-language routine), <code>call</code> (call a Ruby method), - * <code>class</code> (start a class or module definition), - * <code>end</code> (finish a class or module definition), - * <code>line</code> (execute code on a new line), <code>raise</code> - * (raise an exception), and <code>return</code> (return from a Ruby - * method). Tracing is disabled within the context of _proc_. - * - * class Test - * def test - * a = 1 - * b = 2 - * end - * end - * - * set_trace_func proc { |event, file, line, id, binding, classname| - * printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname - * } - * t = Test.new - * t.test - * - * line prog.rb:11 false - * c-call prog.rb:11 new Class - * c-call prog.rb:11 initialize Object - * c-return prog.rb:11 initialize Object - * c-return prog.rb:11 new Class - * line prog.rb:12 false - * call prog.rb:2 test Test - * line prog.rb:3 test Test - * line prog.rb:4 test Test - * return prog.rb:4 test Test - */ - - -static VALUE -set_trace_func(obj, trace) - VALUE obj, trace; -{ - rb_event_hook_t *hook; - - if (NIL_P(trace)) { - trace_func = 0; - rb_remove_event_hook(call_trace_func); - return Qnil; - } - if (!rb_obj_is_proc(trace)) { - rb_raise(rb_eTypeError, "trace_func needs to be Proc"); - } - trace_func = trace; - for (hook = event_hooks; hook; hook = hook->next) { - if (hook->func == call_trace_func) - return trace; - } - rb_add_event_hook(call_trace_func, RUBY_EVENT_ALL); - return trace; -} - -static char * -get_event_name(rb_event_t event) -{ - switch (event) { - case RUBY_EVENT_LINE: - return "line"; - case RUBY_EVENT_CLASS: - return "class"; - case RUBY_EVENT_END: - return "end"; - case RUBY_EVENT_CALL: - return "call"; - case RUBY_EVENT_RETURN: - return "return"; - case RUBY_EVENT_C_CALL: - return "c-call"; - case RUBY_EVENT_C_RETURN: - return "c-return"; - case RUBY_EVENT_RAISE: - return "raise"; - default: - return "unknown"; - } -} - -static void -call_trace_func(event, node, self, id, klass) - rb_event_t event; - NODE *node; - VALUE self; - ID id; - VALUE klass; /* OK */ -{ - int state, raised; - struct FRAME *prev; - NODE *node_save; - VALUE srcfile; - char *event_name; - - if (!trace_func) return; - if (tracing) return; - if (id == ID_ALLOCATOR) return; - if (!node && ruby_sourceline == 0) return; - - if (!(node_save = ruby_current_node)) { - node_save = NEW_BEGIN(0); - } - tracing = 1; - prev = ruby_frame; - PUSH_FRAME(); - *ruby_frame = *prev; - ruby_frame->prev = prev; - ruby_frame->iter = 0; /* blocks not available anyway */ - - if (node) { - ruby_current_node = node; - ruby_frame->node = node; - ruby_sourcefile = node->nd_file; - ruby_sourceline = nd_line(node); - } - if (klass) { - if (TYPE(klass) == T_ICLASS) { - klass = RBASIC(klass)->klass; - } - else if (FL_TEST(klass, FL_SINGLETON)) { - klass = self; - } - } - PUSH_TAG(PROT_NONE); - raised = thread_reset_raised(); - if ((state = EXEC_TAG()) == 0) { - srcfile = rb_str_new2(ruby_sourcefile?ruby_sourcefile:"(ruby)"); - event_name = get_event_name(event); - proc_invoke(trace_func, rb_ary_new3(6, rb_str_new2(event_name), - srcfile, - INT2FIX(ruby_sourceline), - id?ID2SYM(id):Qnil, - self ? rb_f_binding(self) : Qnil, - klass?klass:Qnil), - Qundef, 0); - } - if (raised) thread_set_raised(); - POP_TAG(); - POP_FRAME(); - - tracing = 0; - ruby_current_node = node_save; - SET_CURRENT_SOURCE(); - if (state) JUMP_TAG(state); -} - -static VALUE -avalue_to_svalue(v) - VALUE v; -{ - VALUE tmp, top; - - tmp = rb_check_array_type(v); - if (NIL_P(tmp)) { - return v; - } - if (RARRAY(tmp)->len == 0) { - return Qundef; - } - if (RARRAY(tmp)->len == 1) { - top = rb_check_array_type(RARRAY(tmp)->ptr[0]); - if (NIL_P(top)) { - return RARRAY(tmp)->ptr[0]; - } - if (RARRAY(top)->len > 1) { - return v; - } - return top; - } - return tmp; -} - -static VALUE -svalue_to_avalue(v) - VALUE v; -{ - VALUE tmp, top; - - if (v == Qundef) return rb_ary_new2(0); - tmp = rb_check_array_type(v); - if (NIL_P(tmp)) { - return rb_ary_new3(1, v); - } - if (RARRAY(tmp)->len == 1) { - top = rb_check_array_type(RARRAY(tmp)->ptr[0]); - if (!NIL_P(top) && RARRAY(top)->len > 1) { - return tmp; - } - return rb_ary_new3(1, v); - } - return tmp; -} - -static VALUE -svalue_to_mrhs(v, lhs) - VALUE v; - NODE *lhs; -{ - VALUE tmp; - - if (v == Qundef) return rb_values_new2(0, 0); - tmp = rb_check_array_type(v); - if (NIL_P(tmp)) { - return rb_values_new(1, v); - } - /* no lhs means splat lhs only */ - if (!lhs) { - return rb_values_new(1, v); - } - return tmp; -} - -static VALUE -avalue_splat(v) - VALUE v; -{ - if (RARRAY(v)->len == 0) { - return Qundef; - } - if (RARRAY(v)->len == 1) { - return RARRAY(v)->ptr[0]; - } - return v; -} - -static VALUE -splat_value(v) - VALUE v; -{ - VALUE val; - - if (NIL_P(v)) val = rb_ary_new3(1, Qnil); - else val = rb_Array(v); - return rb_values_from_ary(val); -} - -static VALUE -class_prefix(self, cpath) - VALUE self; - NODE *cpath; -{ - if (!cpath) { - rb_bug("class path missing"); - } - if (cpath->nd_head) { - VALUE c = rb_eval(self, cpath->nd_head); - switch (TYPE(c)) { - case T_CLASS: - case T_MODULE: - break; - default: - rb_raise(rb_eTypeError, "%s is not a class/module", - RSTRING(rb_obj_as_string(c))->ptr); - } - return c; - } - else if (nd_type(cpath) == NODE_COLON2) { - return ruby_cbase; - } - else if (ruby_wrapper) { - return ruby_wrapper; - } - else { - return rb_cObject; - } -} - -#define return_value(v) do {\ - if ((prot_tag->retval = (v)) == Qundef) {\ - prot_tag->retval = Qnil;\ - }\ -} while (0) - -NORETURN(static void return_jump _((VALUE))); -NORETURN(static void break_jump _((VALUE))); - -static VALUE -rb_eval(self, n) - VALUE self; - NODE *n; -{ - NODE * volatile contnode = 0; - NODE * volatile node = n; - int state; - volatile VALUE result = Qnil; - -#define RETURN(v) do { \ - result = (v); \ - goto finish; \ -} while (0) - - again: - if (!node) RETURN(Qnil); - - ruby_current_node = node; - if (node->flags & NODE_NEWLINE) { - EXEC_EVENT_HOOK(RUBY_EVENT_LINE, node, self, - ruby_frame->this_func, - ruby_frame->this_class); - } - switch (nd_type(node)) { - case NODE_BLOCK: - if (contnode) { - result = rb_eval(self, node); - break; - } - contnode = node->nd_next; - node = node->nd_head; - goto again; - - case NODE_POSTEXE: - rb_f_END(); - nd_set_type(node, NODE_NIL); /* exec just once */ - result = Qnil; - break; - - /* begin .. end without clauses */ - case NODE_BEGIN: - node = node->nd_body; - goto again; - - /* nodes for speed-up(default match) */ - case NODE_MATCH: - result = rb_reg_match2(node->nd_lit); - break; - - /* nodes for speed-up(literal match) */ - case NODE_MATCH2: - { - VALUE l = rb_eval(self,node->nd_recv); - VALUE r = rb_eval(self,node->nd_value); - result = rb_reg_match(l, r); - } - break; - - /* nodes for speed-up(literal match) */ - case NODE_MATCH3: - { - VALUE r = rb_eval(self,node->nd_recv); - VALUE l = rb_eval(self,node->nd_value); - if (TYPE(l) == T_STRING) { - result = rb_reg_match(r, l); - } - else { - result = rb_funcall(l, match, 1, r); - } - } - break; - - /* node for speed-up(top-level loop for -n/-p) */ - case NODE_OPT_N: - PUSH_TAG(PROT_LOOP); - switch (state = EXEC_TAG()) { - case 0: - opt_n_next: - while (!NIL_P(rb_gets())) { - opt_n_redo: - rb_eval(self, node->nd_body); - } - break; - - case TAG_REDO: - state = 0; - goto opt_n_redo; - case TAG_NEXT: - state = 0; - goto opt_n_next; - case TAG_BREAK: - state = 0; - default: - break; - } - POP_TAG(); - if (state) JUMP_TAG(state); - RETURN(Qnil); - - case NODE_SELF: - RETURN(self); - - case NODE_NIL: - RETURN(Qnil); - - case NODE_TRUE: - RETURN(Qtrue); - - case NODE_FALSE: - RETURN(Qfalse); - - case NODE_ERRINFO: - RETURN(ruby_errinfo); - - case NODE_IF: - EXEC_EVENT_HOOK(RUBY_EVENT_LINE, node, self, - ruby_frame->this_func, - ruby_frame->this_class); - if (RTEST(rb_eval(self, node->nd_cond))) { - node = node->nd_body; - } - else { - node = node->nd_else; - } - goto again; - - case NODE_WHEN: - while (node) { - NODE *tag; - - if (nd_type(node) != NODE_WHEN) goto again; - tag = node->nd_head; - while (tag) { - EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self, - ruby_frame->this_func, - ruby_frame->this_class); - if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) { - VALUE v = rb_eval(self, tag->nd_head->nd_head); - long i; - - if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(v); - for (i=0; i<RARRAY(v)->len; i++) { - if (RTEST(RARRAY(v)->ptr[i])) { - node = node->nd_body; - goto again; - } - } - tag = tag->nd_next; - continue; - } - if (RTEST(rb_eval(self, tag->nd_head))) { - node = node->nd_body; - goto again; - } - tag = tag->nd_next; - } - node = node->nd_next; - } - RETURN(Qnil); - - case NODE_CASE: - { - VALUE val; - - val = rb_eval(self, node->nd_head); - node = node->nd_body; - while (node) { - NODE *tag; - - if (nd_type(node) != NODE_WHEN) { - goto again; - } - tag = node->nd_head; - while (tag) { - EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self, - ruby_frame->this_func, - ruby_frame->this_class); - if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) { - VALUE v = rb_eval(self, tag->nd_head->nd_head); - long i; - - if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(v); - for (i=0; i<RARRAY(v)->len; i++) { - if (RTEST(rb_funcall2(RARRAY(v)->ptr[i], eqq, 1, &val))){ - node = node->nd_body; - goto again; - } - } - tag = tag->nd_next; - continue; - } - if (RTEST(rb_funcall2(rb_eval(self, tag->nd_head), eqq, 1, &val))) { - node = node->nd_body; - goto again; - } - tag = tag->nd_next; - } - node = node->nd_next; - } - } - RETURN(Qnil); - - case NODE_WHILE: - PUSH_TAG(PROT_LOOP); - result = Qnil; - switch (state = EXEC_TAG()) { - case 0: - if (node->nd_state && !RTEST(rb_eval(self, node->nd_cond))) - goto while_out; - do { - while_redo: - rb_eval(self, node->nd_body); - while_next: - ; - } while (RTEST(rb_eval(self, node->nd_cond))); - break; - - case TAG_REDO: - state = 0; - goto while_redo; - case TAG_NEXT: - state = 0; - goto while_next; - case TAG_BREAK: - if (TAG_DST()) { - state = 0; - result = prot_tag->retval; - } - /* fall through */ - default: - break; - } - while_out: - POP_TAG(); - if (state) JUMP_TAG(state); - RETURN(result); - - case NODE_UNTIL: - PUSH_TAG(PROT_LOOP); - result = Qnil; - switch (state = EXEC_TAG()) { - case 0: - if (node->nd_state && RTEST(rb_eval(self, node->nd_cond))) - goto until_out; - do { - until_redo: - rb_eval(self, node->nd_body); - until_next: - ; - } while (!RTEST(rb_eval(self, node->nd_cond))); - break; - - case TAG_REDO: - state = 0; - goto until_redo; - case TAG_NEXT: - state = 0; - goto until_next; - case TAG_BREAK: - if (TAG_DST()) { - state = 0; - result = prot_tag->retval; - } - /* fall through */ - default: - break; - } - until_out: - POP_TAG(); - if (state) JUMP_TAG(state); - RETURN(result); - - case NODE_BLOCK_PASS: - result = block_pass(self, node); - break; - - case NODE_ITER: - case NODE_FOR: - case NODE_LAMBDA: - { - PUSH_TAG(PROT_LOOP); - PUSH_BLOCK(node->nd_var, node->nd_body); - - state = EXEC_TAG(); - if (state == 0) { - iter_retry: - PUSH_ITER(ITER_PRE); - if (nd_type(node) == NODE_ITER) { - result = rb_eval(self, node->nd_iter); - } - else if (nd_type(node) == NODE_LAMBDA) { - ruby_iter->iter = ruby_frame->iter = ITER_CUR; - result = rb_block_proc(); - } - else { - VALUE recv; - - _block.flags &= ~BLOCK_D_SCOPE; - BEGIN_CALLARGS; - recv = rb_eval(self, node->nd_iter); - END_CALLARGS; - ruby_current_node = node; - SET_CURRENT_SOURCE(); - result = rb_call(CLASS_OF(recv),recv,each,0,0,0); - } - POP_ITER(); - } - else if (state == TAG_BREAK && TAG_DST()) { - result = prot_tag->retval; - state = 0; - } - else if (state == TAG_RETRY && ruby_block == &_block) { - state = 0; - goto iter_retry; - } - POP_BLOCK(); - POP_TAG(); - switch (state) { - case 0: - break; - default: - JUMP_TAG(state); - } - } - break; - - case NODE_BREAK: - break_jump(rb_eval(self, node->nd_stts)); - break; - - case NODE_NEXT: - CHECK_INTS; - return_value(rb_eval(self, node->nd_stts)); - JUMP_TAG(TAG_NEXT); - break; - - case NODE_REDO: - CHECK_INTS; - JUMP_TAG(TAG_REDO); - break; - - case NODE_RETRY: - CHECK_INTS; - JUMP_TAG(TAG_RETRY); - break; - - case NODE_SPLAT: - result = splat_value(rb_eval(self, node->nd_head)); - break; - - case NODE_TO_ARY: - result = rb_ary_to_ary(rb_eval(self, node->nd_head)); - break; - - case NODE_SVALUE: - result = avalue_splat(rb_eval(self, node->nd_head)); - if (result == Qundef) result = Qnil; - break; - - case NODE_YIELD: - if (node->nd_head) { - result = rb_eval(self, node->nd_head); - ruby_current_node = node; - } - else { - result = Qundef; /* no arg */ - } - SET_CURRENT_SOURCE(); - result = rb_yield_0(result, 0, 0, 0, node->nd_state); - break; - - case NODE_RESCUE: - { - volatile VALUE e_info = ruby_errinfo; - volatile int rescuing = 0; - - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - retry_entry: - result = rb_eval(self, node->nd_head); - } - else if (rescuing) { - if (rescuing < 0) { - /* in rescue argument, just reraise */ - } - else if (state == TAG_RETRY) { - rescuing = state = 0; - ruby_errinfo = e_info; - goto retry_entry; - } - else if (state != TAG_RAISE) { - result = prot_tag->retval; - } - } - else if (state == TAG_RAISE) { - NODE *resq = node->nd_resq; - - rescuing = -1; - while (resq) { - ruby_current_node = resq; - if (handle_rescue(self, resq)) { - state = 0; - rescuing = 1; - result = rb_eval(self, resq->nd_body); - break; - } - resq = resq->nd_head; /* next rescue */ - } - } - else { - result = prot_tag->retval; - } - POP_TAG(); - if (state != TAG_RAISE) ruby_errinfo = e_info; - if (state) { - if (state == TAG_NEXT) prot_tag->retval = result; - JUMP_TAG(state); - } - /* no exception raised */ - if (!rescuing && (node = node->nd_else)) { /* else clause given */ - goto again; - } - } - break; - - case NODE_ENSURE: - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - result = rb_eval(self, node->nd_head); - } - POP_TAG(); - if (node->nd_ensr) { - VALUE retval = prot_tag->retval; /* save retval */ - VALUE errinfo = ruby_errinfo; - - rb_eval(self, node->nd_ensr); - return_value(retval); - ruby_errinfo = errinfo; - } - if (state) JUMP_TAG(state); - break; - - case NODE_AND: - result = rb_eval(self, node->nd_1st); - if (!RTEST(result)) break; - node = node->nd_2nd; - goto again; - - case NODE_OR: - result = rb_eval(self, node->nd_1st); - if (RTEST(result)) break; - node = node->nd_2nd; - goto again; - - case NODE_NOT: - if (RTEST(rb_eval(self, node->nd_body))) result = Qfalse; - else result = Qtrue; - break; - - case NODE_DOT2: - case NODE_DOT3: - result = rb_range_new(rb_eval(self, node->nd_beg), - rb_eval(self, node->nd_end), - nd_type(node) == NODE_DOT3); - break; - - case NODE_FLIP2: /* like AWK */ - { - VALUE *flip = rb_svar(node->nd_cnt); - if (!flip) rb_bug("unexpected local variable"); - if (!RTEST(*flip)) { - if (RTEST(rb_eval(self, node->nd_beg))) { - *flip = RTEST(rb_eval(self, node->nd_end))?Qfalse:Qtrue; - result = Qtrue; - } - else { - result = Qfalse; - } - } - else { - if (RTEST(rb_eval(self, node->nd_end))) { - *flip = Qfalse; - } - result = Qtrue; - } - } - break; - - case NODE_FLIP3: /* like SED */ - { - VALUE *flip = rb_svar(node->nd_cnt); - if (!flip) rb_bug("unexpected local variable"); - if (!RTEST(*flip)) { - result = RTEST(rb_eval(self, node->nd_beg)) ? Qtrue : Qfalse; - *flip = result; - } - else { - if (RTEST(rb_eval(self, node->nd_end))) { - *flip = Qfalse; - } - result = Qtrue; - } - } - break; - - case NODE_RETURN: - return_jump(rb_eval(self, node->nd_stts)); - break; - - case NODE_ARGSCAT: - { - VALUE args = rb_eval(self, node->nd_head); - result = rb_ary_concat(args, splat_value(rb_eval(self, node->nd_body))); - } - break; - - case NODE_ARGSPUSH: - { - VALUE args = rb_ary_dup(rb_eval(self, node->nd_head)); - result = rb_ary_push(args, rb_eval(self, node->nd_body)); - } - break; - - case NODE_ATTRASGN: - { - VALUE recv; - int argc; VALUE *argv; /* used in SETUP_ARGS */ - int scope; - TMP_PROTECT; - - BEGIN_CALLARGS; - if (node->nd_recv == (NODE *)1) { - recv = self; - scope = 1; - } - else { - recv = rb_eval(self, node->nd_recv); - scope = 0; - } - SETUP_ARGS(node->nd_args); - END_CALLARGS; - - ruby_current_node = node; - SET_CURRENT_SOURCE(); - rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,scope); - result = argv[argc-1]; - } - break; - - case NODE_CALL: - { - VALUE recv; - int argc; VALUE *argv; /* used in SETUP_ARGS */ - TMP_PROTECT; - - BEGIN_CALLARGS; - recv = rb_eval(self, node->nd_recv); - SETUP_ARGS(node->nd_args); - END_CALLARGS; - - ruby_current_node = node; - SET_CURRENT_SOURCE(); - result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0); - } - break; - - case NODE_FCALL: - { - int argc; VALUE *argv; /* used in SETUP_ARGS */ - TMP_PROTECT; - - BEGIN_CALLARGS; - SETUP_ARGS(node->nd_args); - END_CALLARGS; - - ruby_current_node = node; - SET_CURRENT_SOURCE(); - result = rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1); - } - break; - - case NODE_VCALL: - SET_CURRENT_SOURCE(); - result = rb_call(CLASS_OF(self),self,node->nd_mid,0,0,2); - break; - - case NODE_SUPER: - case NODE_ZSUPER: - { - int argc; VALUE *argv; /* used in SETUP_ARGS */ - TMP_PROTECT; - - if (ruby_frame->this_class == 0) { - if (ruby_frame->this_func) { - rb_name_error(ruby_frame->callee, - "superclass method `%s' disabled", - rb_id2name(ruby_frame->this_func)); - } - else { - rb_raise(rb_eNoMethodError, "super called outside of method"); - } - } - if (nd_type(node) == NODE_ZSUPER) { - argc = ruby_frame->argc; - if (argc && ruby_frame->prev && - (ruby_frame->prev->flags & FRAME_DMETH)) { - if (TYPE(RBASIC(ruby_scope)->klass) != T_ARRAY || - RARRAY(RBASIC(ruby_scope)->klass)->len != argc) { - rb_raise(rb_eRuntimeError, - "super: specify arguments explicitly"); - } - argv = RARRAY(RBASIC(ruby_scope)->klass)->ptr; - } - else { - argv = ruby_scope->local_vars + 2; - } - } - else { - BEGIN_CALLARGS; - SETUP_ARGS(node->nd_args); - END_CALLARGS; - ruby_current_node = node; - } - - SET_CURRENT_SOURCE(); - result = rb_call_super(argc, argv); - } - break; - - case NODE_SCOPE: - { - struct FRAME frame; - NODE *saved_cref = 0; - - frame = *ruby_frame; - frame.tmp = ruby_frame; - ruby_frame = &frame; - - PUSH_SCOPE(); - PUSH_TAG(PROT_NONE); - if (node->nd_rval) { - saved_cref = ruby_cref; - ruby_cref = (NODE*)node->nd_rval; - } - if (node->nd_tbl) { - VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1); - *vars++ = (VALUE)node; - ruby_scope->local_vars = vars; - rb_mem_clear(ruby_scope->local_vars, node->nd_tbl[0]); - ruby_scope->local_tbl = node->nd_tbl; - } - else { - ruby_scope->local_vars = 0; - ruby_scope->local_tbl = 0; - } - if ((state = EXEC_TAG()) == 0) { - result = rb_eval(self, node->nd_next); - } - POP_TAG(); - POP_SCOPE(); - ruby_frame = frame.tmp; - if (saved_cref) - ruby_cref = saved_cref; - if (state) JUMP_TAG(state); - } - break; - - case NODE_OP_ASGN1: - { - int argc; VALUE *argv; /* used in SETUP_ARGS */ - VALUE recv, val; - NODE *rval; - TMP_PROTECT; - - recv = rb_eval(self, node->nd_recv); - rval = node->nd_args->nd_head; - SETUP_ARGS0(node->nd_args->nd_next, node->nd_args->nd_alen - 1); - val = rb_funcall2(recv, aref, argc-1, argv); - switch (node->nd_mid) { - case 0: /* OR */ - if (RTEST(val)) RETURN(val); - val = rb_eval(self, rval); - break; - case 1: /* AND */ - if (!RTEST(val)) RETURN(val); - val = rb_eval(self, rval); - break; - default: - val = rb_funcall(val, node->nd_mid, 1, rb_eval(self, rval)); - } - argv[argc-1] = val; - rb_funcall2(recv, aset, argc, argv); - result = val; - } - break; - - case NODE_OP_ASGN2: - { - ID id = node->nd_next->nd_vid; - VALUE recv, val; - - recv = rb_eval(self, node->nd_recv); - val = rb_funcall(recv, id, 0); - switch (node->nd_next->nd_mid) { - case 0: /* OR */ - if (RTEST(val)) RETURN(val); - val = rb_eval(self, node->nd_value); - break; - case 1: /* AND */ - if (!RTEST(val)) RETURN(val); - val = rb_eval(self, node->nd_value); - break; - default: - val = rb_funcall(val, node->nd_next->nd_mid, 1, - rb_eval(self, node->nd_value)); - } - - rb_funcall2(recv, node->nd_next->nd_aid, 1, &val); - result = val; - } - break; - - case NODE_OP_ASGN_AND: - result = rb_eval(self, node->nd_head); - if (!RTEST(result)) break; - node = node->nd_value; - goto again; - - case NODE_OP_ASGN_OR: - if ((node->nd_aid && !is_defined(self, node->nd_head, 0, 0)) || - !RTEST(result = rb_eval(self, node->nd_head))) { - node = node->nd_value; - goto again; - } - break; - - case NODE_MASGN: - result = massign(self, node, rb_eval(self, node->nd_value), 0); - break; - - case NODE_LASGN: - if (ruby_scope->local_vars == 0) - rb_bug("unexpected local variable assignment"); - result = rb_eval(self, node->nd_value); - ruby_scope->local_vars[node->nd_cnt] = result; - break; - - case NODE_DASGN: - result = rb_eval(self, node->nd_value); - dvar_asgn(node->nd_vid, result); - break; - - case NODE_DASGN_CURR: - result = rb_eval(self, node->nd_value); - dvar_asgn_curr(node->nd_vid, result); - break; - - case NODE_GASGN: - result = rb_eval(self, node->nd_value); - rb_gvar_set(node->nd_entry, result); - break; - - case NODE_IASGN: - result = rb_eval(self, node->nd_value); - rb_ivar_set(self, node->nd_vid, result); - break; - - case NODE_CDECL: - result = rb_eval(self, node->nd_value); - if (node->nd_vid == 0) { - rb_const_set(class_prefix(self, node->nd_else), node->nd_else->nd_mid, result); - } - else { - if (NIL_P(ruby_cbase)) { - rb_raise(rb_eTypeError, "no class/module to define constant"); - } - rb_const_set(ruby_cbase, node->nd_vid, result); - } - break; - - case NODE_CVDECL: - if (NIL_P(ruby_cbase)) { - rb_raise(rb_eTypeError, "no class/module to define class variable"); - } - result = rb_eval(self, node->nd_value); - rb_cvar_set(cvar_cbase(), node->nd_vid, result, Qtrue); - break; - - case NODE_CVASGN: - result = rb_eval(self, node->nd_value); - rb_cvar_set(cvar_cbase(), node->nd_vid, result, Qfalse); - break; - - case NODE_LVAR: - if (ruby_scope->local_vars == 0) { - rb_bug("unexpected local variable"); - } - result = ruby_scope->local_vars[node->nd_cnt]; - break; - - case NODE_DVAR: - result = rb_dvar_ref(node->nd_vid); - break; - - case NODE_GVAR: - result = rb_gvar_get(node->nd_entry); - break; - - case NODE_IVAR: - result = rb_ivar_get(self, node->nd_vid); - break; - - case NODE_CONST: - result = ev_const_get(ruby_cref, node->nd_vid, self); - break; - - case NODE_CVAR: - result = rb_cvar_get(cvar_cbase(), node->nd_vid); - break; - - case NODE_BLOCK_ARG: - if (ruby_scope->local_vars == 0) - rb_bug("unexpected block argument"); - if (rb_block_given_p()) { - result = rb_block_proc(); - ruby_scope->local_vars[node->nd_cnt] = result; - } - else { - result = Qnil; - } - break; - - case NODE_COLON2: - { - VALUE klass; - - klass = rb_eval(self, node->nd_head); - if (rb_is_const_id(node->nd_mid)) { - switch (TYPE(klass)) { - case T_CLASS: - case T_MODULE: - result = rb_const_get_from(klass, node->nd_mid); - break; - default: - rb_raise(rb_eTypeError, "%s is not a class/module", - RSTRING(rb_obj_as_string(klass))->ptr); - break; - } - } - else { - result = rb_funcall(klass, node->nd_mid, 0, 0); - } - } - break; - - case NODE_COLON3: - result = rb_const_get_from(rb_cObject, node->nd_mid); - break; - - case NODE_NTH_REF: - result = rb_reg_nth_match(node->nd_nth, MATCH_DATA); - break; - - case NODE_BACK_REF: - switch (node->nd_nth) { - case '&': - result = rb_reg_last_match(MATCH_DATA); - break; - case '`': - result = rb_reg_match_pre(MATCH_DATA); - break; - case '\'': - result = rb_reg_match_post(MATCH_DATA); - break; - case '+': - result = rb_reg_match_last(MATCH_DATA); - break; - default: - rb_bug("unexpected back-ref"); - } - break; - - case NODE_HASH: - { - NODE *list; - VALUE hash = rb_hash_new(); - VALUE key, val; - - list = node->nd_head; - while (list) { - key = rb_eval(self, list->nd_head); - list = list->nd_next; - if (list == 0) - rb_bug("odd number list for Hash"); - val = rb_eval(self, list->nd_head); - list = list->nd_next; - rb_hash_aset(hash, key, val); - } - result = hash; - } - break; - - case NODE_ZARRAY: /* zero length list */ - result = rb_ary_new(); - break; - - case NODE_ARRAY: - { - VALUE ary; - long i; - - i = node->nd_alen; - ary = rb_ary_new2(i); - for (i=0;node;node=node->nd_next) { - RARRAY(ary)->ptr[i++] = rb_eval(self, node->nd_head); - RARRAY(ary)->len = i; - } - - result = ary; - } - break; - - case NODE_VALUES: - { - VALUE val; - long i; - - i = node->nd_alen; - val = rb_values_new2(i, 0); - for (i=0;node;node=node->nd_next) { - RARRAY(val)->ptr[i++] = rb_eval(self, node->nd_head); - RARRAY(val)->len = i; - } - - result = val; - } - break; - - case NODE_STR: - result = rb_str_new3(node->nd_lit); - break; - - case NODE_EVSTR: - result = rb_obj_as_string(rb_eval(self, node->nd_body)); - break; - - case NODE_DSTR: - case NODE_DXSTR: - case NODE_DREGX: - case NODE_DREGX_ONCE: - case NODE_DSYM: - { - VALUE str, str2; - NODE *list = node->nd_next; - - str = rb_str_new3(node->nd_lit); - while (list) { - if (list->nd_head) { - switch (nd_type(list->nd_head)) { - case NODE_STR: - str2 = list->nd_head->nd_lit; - break; - default: - str2 = rb_eval(self, list->nd_head); - break; - } - rb_str_append(str, str2); - OBJ_INFECT(str, str2); - } - list = list->nd_next; - } - switch (nd_type(node)) { - case NODE_DREGX: - result = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, - node->nd_cflag); - break; - case NODE_DREGX_ONCE: /* regexp expand once */ - result = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, - node->nd_cflag); - nd_set_type(node, NODE_LIT); - node->nd_lit = result; - break; - case NODE_LIT: - /* other thread may replace NODE_DREGX_ONCE to NODE_LIT */ - goto again; - case NODE_DXSTR: - result = rb_funcall(self, '`', 1, str); - break; - case NODE_DSYM: - result = rb_str_intern(str); - break; - default: - result = str; - break; - } - } - break; - - case NODE_XSTR: - result = rb_funcall(self, '`', 1, rb_str_new3(node->nd_lit)); - break; - - case NODE_LIT: - result = node->nd_lit; - break; - - case NODE_DEFN: - if (node->nd_defn) { - NODE *body, *defn; - VALUE origin; - int noex; - - if (NIL_P(ruby_class)) { - rb_raise(rb_eTypeError, "no class/module to add method"); - } - if (ruby_class == rb_cObject && node->nd_mid == init) { - rb_warn("redefining Object#initialize may cause infinite loop"); - } - if (node->nd_mid == __id__ || node->nd_mid == __send__) { - rb_warn("redefining `%s' may cause serious problem", - rb_id2name(node->nd_mid)); - } - rb_frozen_class_p(ruby_class); - body = search_method(ruby_class, node->nd_mid, &origin); - if (body){ - if (RTEST(ruby_verbose) && ruby_class == origin && body->nd_cnt == 0 && body->nd_body) { - rb_warning("method redefined; discarding old %s", rb_id2name(node->nd_mid)); - } - } - - if (SCOPE_TEST(SCOPE_PRIVATE) || node->nd_mid == init) { - noex = NOEX_PRIVATE; - } - else if (SCOPE_TEST(SCOPE_PROTECTED)) { - noex = NOEX_PROTECTED; - } - else { - noex = NOEX_PUBLIC; - } - if (body && origin == ruby_class && body->nd_body == 0) { - noex |= NOEX_NOSUPER; - } - - defn = copy_node_scope(node->nd_defn, ruby_cref); - rb_add_method(ruby_class, node->nd_mid, defn, noex); - if (scope_vmode == SCOPE_MODFUNC) { - rb_add_method(rb_singleton_class(ruby_class), - node->nd_mid, defn, NOEX_PUBLIC); - } - result = Qnil; - } - break; - - case NODE_DEFS: - if (node->nd_defn) { - VALUE recv = rb_eval(self, node->nd_recv); - VALUE klass; - NODE *body = 0, *defn; - - if (ruby_safe_level >= 4 && !OBJ_TAINTED(recv)) { - rb_raise(rb_eSecurityError, "Insecure: can't define singleton method"); - } - if (FIXNUM_P(recv) || SYMBOL_P(recv)) { - rb_raise(rb_eTypeError, - "can't define singleton method \"%s\" for %s", - rb_id2name(node->nd_mid), - rb_obj_classname(recv)); - } - - if (OBJ_FROZEN(recv)) rb_error_frozen("object"); - klass = rb_singleton_class(recv); - if (st_lookup(RCLASS(klass)->m_tbl, node->nd_mid, (st_data_t *)&body)) { - if (ruby_safe_level >= 4) { - rb_raise(rb_eSecurityError, "redefining method prohibited"); - } - if (RTEST(ruby_verbose)) { - rb_warning("redefine %s", rb_id2name(node->nd_mid)); - } - } - defn = copy_node_scope(node->nd_defn, ruby_cref); - rb_add_method(klass, node->nd_mid, defn, - NOEX_PUBLIC|(body?body->nd_noex&NOEX_UNDEF:0)); - result = Qnil; - } - break; - - case NODE_UNDEF: - if (NIL_P(ruby_class)) { - rb_raise(rb_eTypeError, "no class to undef method"); - } - rb_undef(ruby_class, rb_to_id(rb_eval(self, node->u2.node))); - result = Qnil; - break; - - case NODE_ALIAS: - if (NIL_P(ruby_class)) { - rb_raise(rb_eTypeError, "no class to make alias"); - } - rb_alias(ruby_class, rb_to_id(rb_eval(self, node->u1.node)), - rb_to_id(rb_eval(self, node->u2.node))); - result = Qnil; - break; - - case NODE_VALIAS: - rb_alias_variable(node->u1.id, node->u2.id); - result = Qnil; - break; - - case NODE_CLASS: - { - VALUE super, klass, tmp, cbase; - ID cname; - int gen = Qfalse; - - cbase = class_prefix(self, node->nd_cpath); - cname = node->nd_cpath->nd_mid; - - if (NIL_P(ruby_cbase)) { - rb_raise(rb_eTypeError, "no outer class/module"); - } - if (node->nd_super) { - super = rb_eval(self, node->nd_super); - rb_check_inheritable(super); - } - else { - super = 0; - } - - if (rb_const_defined_at(cbase, cname)) { - klass = rb_const_get_at(cbase, cname); - if (TYPE(klass) != T_CLASS) { - rb_raise(rb_eTypeError, "%s is not a class", - rb_id2name(cname)); - } - if (super) { - tmp = rb_class_real(RCLASS(klass)->super); - if (tmp != super) { - rb_raise(rb_eTypeError, "superclass mismatch for class %s", - rb_id2name(cname)); - } - super = 0; - } - if (ruby_safe_level >= 4) { - rb_raise(rb_eSecurityError, "extending class prohibited"); - } - } - else { - if (!super) super = rb_cObject; - klass = rb_define_class_id(cname, super); - rb_set_class_path(klass, cbase, rb_id2name(cname)); - rb_const_set(cbase, cname, klass); - gen = Qtrue; - } - if (ruby_wrapper) { - rb_extend_object(klass, ruby_wrapper); - rb_include_module(klass, ruby_wrapper); - } - if (super && gen) { - rb_class_inherited(super, klass); - } - result = module_setup(klass, node); - } - break; - - case NODE_MODULE: - { - VALUE module, cbase; - ID cname; - - if (NIL_P(ruby_cbase)) { - rb_raise(rb_eTypeError, "no outer class/module"); - } - cbase = class_prefix(self, node->nd_cpath); - cname = node->nd_cpath->nd_mid; - if (rb_const_defined_at(cbase, cname)) { - module = rb_const_get_at(cbase, cname); - if (TYPE(module) != T_MODULE) { - rb_raise(rb_eTypeError, "%s is not a module", - rb_id2name(cname)); - } - if (ruby_safe_level >= 4) { - rb_raise(rb_eSecurityError, "extending module prohibited"); - } - } - else { - module = rb_define_module_id(cname); - rb_set_class_path(module, cbase, rb_id2name(cname)); - rb_const_set(cbase, cname, module); - } - if (ruby_wrapper) { - rb_extend_object(module, ruby_wrapper); - rb_include_module(module, ruby_wrapper); - } - - result = module_setup(module, node); - } - break; - - case NODE_SCLASS: - { - VALUE klass; - - result = rb_eval(self, node->nd_recv); - if (FIXNUM_P(result) || SYMBOL_P(result)) { - rb_raise(rb_eTypeError, "no singleton class for %s", - rb_obj_classname(result)); - } - if (ruby_safe_level >= 4 && !OBJ_TAINTED(result)) - rb_raise(rb_eSecurityError, "Insecure: can't extend object"); - klass = rb_singleton_class(result); - - if (ruby_wrapper) { - rb_extend_object(klass, ruby_wrapper); - rb_include_module(klass, ruby_wrapper); - } - - result = module_setup(klass, node); - } - break; - - case NODE_DEFINED: - { - char buf[20]; - const char *desc = is_defined(self, node->nd_head, buf, 0); - - if (desc) result = rb_str_new2(desc); - else result = Qnil; - } - break; - - default: - rb_bug("unknown node type %d", nd_type(node)); - } - finish: - CHECK_INTS; - if (contnode) { - node = contnode; - contnode = 0; - goto again; - } - return result; -} - -static VALUE -module_setup(module, n) - VALUE module; - NODE *n; -{ - NODE * volatile node = n->nd_body; - int state; - struct FRAME frame; - VALUE result = Qnil; /* OK */ - TMP_PROTECT; - - frame = *ruby_frame; - frame.tmp = ruby_frame; - ruby_frame = &frame; - - PUSH_CLASS(module); - PUSH_SCOPE(); - PUSH_VARS(); - - if (node->nd_tbl) { - VALUE *vars = TMP_ALLOC(node->nd_tbl[0]+1); - *vars++ = (VALUE)node; - ruby_scope->local_vars = vars; - rb_mem_clear(ruby_scope->local_vars, node->nd_tbl[0]); - ruby_scope->local_tbl = node->nd_tbl; - } - else { - ruby_scope->local_vars = 0; - ruby_scope->local_tbl = 0; - } - - PUSH_CREF(module); - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - EXEC_EVENT_HOOK(RUBY_EVENT_CLASS, n, ruby_cbase, - ruby_frame->this_func, ruby_frame->this_class); - result = rb_eval(ruby_cbase, node->nd_next); - } - POP_TAG(); - POP_CREF(); - POP_VARS(); - POP_SCOPE(); - POP_CLASS(); - - ruby_frame = frame.tmp; - EXEC_EVENT_HOOK(RUBY_EVENT_END, n, 0, ruby_frame->this_func, - ruby_frame->this_class); - if (state) JUMP_TAG(state); - - return result; -} - -static NODE *basic_respond_to = 0; - -int -rb_respond_to(obj, id) - VALUE obj; - ID id; -{ - VALUE klass = CLASS_OF(obj); - if (rb_method_node(klass, respond_to) == basic_respond_to && - rb_method_boundp(klass, id, 0)) { - return Qtrue; - } - else{ - return rb_funcall(obj, respond_to, 1, ID2SYM(id)); - } - return Qfalse; -} - - -/* - * call-seq: - * obj.respond_to?(symbol, include_private=false) => true or false - * - * Returns +true+> if _obj_ responds to the given - * method. Private methods are included in the search only if the - * optional second parameter evaluates to +true+. - */ - -static VALUE -rb_obj_respond_to(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - VALUE mid, priv; - ID id; - - rb_scan_args(argc, argv, "11", &mid, &priv); - id = rb_to_id(mid); - if (rb_method_boundp(CLASS_OF(obj), id, !RTEST(priv))) { - return Qtrue; - } - return Qfalse; -} - -/* - * call-seq: - * mod.method_defined?(symbol) => true or false - * - * Returns +true+ if the named method is defined by - * _mod_ (or its included modules and, if _mod_ is a class, - * its ancestors). Public and protected methods are matched. - * - * module A - * def method1() end - * end - * class B - * def method2() end - * end - * class C < B - * include A - * def method3() end - * end - * - * A.method_defined? :method1 #=> true - * C.method_defined? "method1" #=> true - * C.method_defined? "method2" #=> true - * C.method_defined? "method3" #=> true - * C.method_defined? "method4" #=> false - */ - -static VALUE -rb_mod_method_defined(mod, mid) - VALUE mod, mid; -{ - return rb_method_boundp(mod, rb_to_id(mid), 1); -} - -#define VISI_CHECK(x,f) (((x)&NOEX_MASK) == (f)) - -/* - * call-seq: - * mod.public_method_defined?(symbol) => true or false - * - * Returns +true+ if the named public method is defined by - * _mod_ (or its included modules and, if _mod_ is a class, - * its ancestors). - * - * module A - * def method1() end - * end - * class B - * protected - * def method2() end - * end - * class C < B - * include A - * def method3() end - * end - * - * A.method_defined? :method1 #=> true - * C.public_method_defined? "method1" #=> true - * C.public_method_defined? "method2" #=> false - * C.method_defined? "method2" #=> true - */ - -static VALUE -rb_mod_public_method_defined(mod, mid) - VALUE mod, mid; -{ - ID id = rb_to_id(mid); - int noex; - - if (rb_get_method_body(&mod, &id, &noex)) { - if (VISI_CHECK(noex, NOEX_PUBLIC)) - return Qtrue; - } - return Qfalse; -} - -/* - * call-seq: - * mod.private_method_defined?(symbol) => true or false - * - * Returns +true+ if the named private method is defined by - * _ mod_ (or its included modules and, if _mod_ is a class, - * its ancestors). - * - * module A - * def method1() end - * end - * class B - * private - * def method2() end - * end - * class C < B - * include A - * def method3() end - * end - * - * A.method_defined? :method1 #=> true - * C.private_method_defined? "method1" #=> false - * C.private_method_defined? "method2" #=> true - * C.method_defined? "method2" #=> false - */ - -static VALUE -rb_mod_private_method_defined(mod, mid) - VALUE mod, mid; -{ - ID id = rb_to_id(mid); - int noex; - - if (rb_get_method_body(&mod, &id, &noex)) { - if (VISI_CHECK(noex, NOEX_PRIVATE)) - return Qtrue; - } - return Qfalse; -} - -/* - * call-seq: - * mod.protected_method_defined?(symbol) => true or false - * - * Returns +true+ if the named protected method is defined - * by _mod_ (or its included modules and, if _mod_ is a - * class, its ancestors). - * - * module A - * def method1() end - * end - * class B - * protected - * def method2() end - * end - * class C < B - * include A - * def method3() end - * end - * - * A.method_defined? :method1 #=> true - * C.protected_method_defined? "method1" #=> false - * C.protected_method_defined? "method2" #=> true - * C.method_defined? "method2" #=> true - */ - -static VALUE -rb_mod_protected_method_defined(mod, mid) - VALUE mod, mid; -{ - ID id = rb_to_id(mid); - int noex; - - if (rb_get_method_body(&mod, &id, &noex)) { - if (VISI_CHECK(noex, NOEX_PROTECTED)) - return Qtrue; - } - return Qfalse; -} - -NORETURN(static VALUE terminate_process _((int, const char *, long))); -static VALUE -terminate_process(status, mesg, mlen) - int status; - const char *mesg; - long mlen; -{ - VALUE args[2]; - args[0] = INT2NUM(status); - args[1] = rb_str_new(mesg, mlen); - - rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit)); -} - -void -rb_exit(status) - int status; -{ - if (prot_tag) { - terminate_process(status, "exit", 4); - } - ruby_finalize(); - exit(status); -} - - -/* - * call-seq: - * exit(integer=0) - * Kernel::exit(integer=0) - * Process::exit(integer=0) - * - * Initiates the termination of the Ruby script by raising the - * <code>SystemExit</code> exception. This exception may be caught. The - * optional parameter is used to return a status code to the invoking - * environment. - * - * begin - * exit - * puts "never get here" - * rescue SystemExit - * puts "rescued a SystemExit exception" - * end - * puts "after begin block" - * - * <em>produces:</em> - * - * rescued a SystemExit exception - * after begin block - * - * Just prior to termination, Ruby executes any <code>at_exit</code> functions - * (see Kernel::at_exit) and runs any object finalizers (see - * ObjectSpace::define_finalizer). - * - * at_exit { puts "at_exit function" } - * ObjectSpace.define_finalizer("string", proc { puts "in finalizer" }) - * exit - * - * <em>produces:</em> - * - * at_exit function - * in finalizer - */ - -VALUE -rb_f_exit(argc, argv) - int argc; - VALUE *argv; -{ - VALUE status; - int istatus; - - rb_secure(4); - if (rb_scan_args(argc, argv, "01", &status) == 1) { - switch (status) { - case Qtrue: - istatus = EXIT_SUCCESS; - break; - case Qfalse: - istatus = EXIT_FAILURE; - break; - default: - istatus = NUM2INT(status); - break; - } - } - else { - istatus = EXIT_SUCCESS; - } - rb_exit(istatus); - return Qnil; /* not reached */ -} - - -/* - * call-seq: - * abort - * Kernel::abort - * Process::abort - * - * Terminate execution immediately, effectively by calling - * <code>Kernel.exit(1)</code>. If _msg_ is given, it is written - * to STDERR prior to terminating. - */ - -VALUE -rb_f_abort(argc, argv) - int argc; - VALUE *argv; -{ - rb_secure(4); - if (argc == 0) { - if (!NIL_P(ruby_errinfo)) { - error_print(); - } - rb_exit(EXIT_FAILURE); - } - else { - VALUE mesg; - - rb_scan_args(argc, argv, "1", &mesg); - StringValue(argv[0]); - rb_io_puts(argc, argv, rb_stderr); - terminate_process(EXIT_FAILURE, RSTRING(argv[0])->ptr, RSTRING(argv[0])->len); - } - return Qnil; /* not reached */ -} - -void -rb_iter_break() -{ - break_jump(Qnil); -} - -NORETURN(static void rb_longjmp _((int, VALUE))); -static VALUE make_backtrace _((void)); - -static void -rb_longjmp(tag, mesg) - int tag; - VALUE mesg; -{ - VALUE at; - - if (thread_set_raised()) { - ruby_errinfo = exception_error; - JUMP_TAG(TAG_FATAL); - } - if (NIL_P(mesg)) mesg = ruby_errinfo; - if (NIL_P(mesg)) { - mesg = rb_exc_new(rb_eRuntimeError, 0, 0); - } - - ruby_set_current_source(); - if (ruby_sourcefile && !NIL_P(mesg)) { - at = get_backtrace(mesg); - if (NIL_P(at)) { - at = make_backtrace(); - set_backtrace(mesg, at); - } - } - if (!NIL_P(mesg)) { - ruby_errinfo = mesg; - } - - if (RTEST(ruby_debug) && !NIL_P(ruby_errinfo) - && !rb_obj_is_kind_of(ruby_errinfo, rb_eSystemExit)) { - VALUE e = ruby_errinfo; - int status; - - PUSH_TAG(PROT_NONE); - if ((status = EXEC_TAG()) == 0) { - e = rb_obj_as_string(e); - warn_printf("Exception `%s' at %s:%d - %s\n", - rb_obj_classname(ruby_errinfo), - ruby_sourcefile, ruby_sourceline, - RSTRING(e)->ptr); - } - POP_TAG(); - if (status == TAG_FATAL && ruby_errinfo == exception_error) { - ruby_errinfo = mesg; - } - else if (status) { - thread_reset_raised(); - JUMP_TAG(status); - } - } - - rb_trap_restore_mask(); - if (tag != TAG_FATAL) { - EXEC_EVENT_HOOK(RUBY_EVENT_RAISE, ruby_current_node, - ruby_frame->self, - ruby_frame->this_func, - ruby_frame->this_class); - } - if (!prot_tag) { - error_print(); - } - thread_reset_raised(); - JUMP_TAG(tag); -} - -void -rb_exc_raise(mesg) - VALUE mesg; -{ - rb_longjmp(TAG_RAISE, mesg); -} - -void -rb_exc_fatal(mesg) - VALUE mesg; -{ - rb_longjmp(TAG_FATAL, mesg); -} - -void -rb_interrupt() -{ - rb_raise(rb_eInterrupt, ""); -} - -/* - * call-seq: - * raise - * raise(string) - * raise(exception [, string [, array]]) - * fail - * fail(string) - * fail(exception [, string [, array]]) - * - * With no arguments, raises the exception in <code>$!</code> or raises - * a <code>RuntimeError</code> if <code>$!</code> is +nil+. - * With a single +String+ argument, raises a - * +RuntimeError+ with the string as a message. Otherwise, - * the first parameter should be the name of an +Exception+ - * class (or an object that returns an +Exception+ object when sent - * an +exception+ message). The optional second parameter sets the - * message associated with the exception, and the third parameter is an - * array of callback information. Exceptions are caught by the - * +rescue+ clause of <code>begin...end</code> blocks. - * - * raise "Failed to create socket" - * raise ArgumentError, "No parameters", caller - */ - -static VALUE -rb_f_raise(argc, argv) - int argc; - VALUE *argv; -{ - rb_raise_jump(rb_make_exception(argc, argv)); - return Qnil; /* not reached */ -} - -static VALUE -rb_make_exception(argc, argv) - int argc; - VALUE *argv; -{ - VALUE mesg; - ID exception; - int n; - - mesg = Qnil; - switch (argc) { - case 0: - mesg = Qnil; - break; - case 1: - if (NIL_P(argv[0])) break; - if (TYPE(argv[0]) == T_STRING) { - mesg = rb_exc_new3(rb_eRuntimeError, argv[0]); - break; - } - n = 0; - goto exception_call; - - case 2: - case 3: - n = 1; - exception_call: - exception = rb_intern("exception"); - if (!rb_respond_to(argv[0], exception)) { - rb_raise(rb_eTypeError, "exception class/object expected"); - } - mesg = rb_funcall(argv[0], exception, n, argv[1]); - break; - default: - rb_raise(rb_eArgError, "wrong number of arguments"); - break; - } - if (argc > 0) { - if (!rb_obj_is_kind_of(mesg, rb_eException)) - rb_raise(rb_eTypeError, "exception object expected"); - if (argc>2) - set_backtrace(mesg, argv[2]); - } - - return mesg; -} - -static void -rb_raise_jump(mesg) - VALUE mesg; -{ - if (ruby_frame != top_frame) { - PUSH_FRAME(); /* fake frame */ - *ruby_frame = *_frame.prev->prev; - rb_longjmp(TAG_RAISE, mesg); - POP_FRAME(); - } - rb_longjmp(TAG_RAISE, mesg); -} - -void -rb_jump_tag(tag) - int tag; -{ - JUMP_TAG(tag); -} - -int -rb_block_given_p() -{ - if (ruby_frame->iter == ITER_CUR && ruby_block) - return Qtrue; - return Qfalse; -} - -int -rb_iterator_p() -{ - return rb_block_given_p(); -} - -/* - * call-seq: - * block_given? => true or false - * iterator? => true or false - * - * Returns <code>true</code> if <code>yield</code> would execute a - * block in the current context. The <code>iterator?</code> form - * is mildly deprecated. - * - * def try - * if block_given? - * yield - * else - * "no block" - * end - * end - * try #=> "no block" - * try { "hello" } #=> "hello" - * try do "hello" end #=> "hello" - */ - - -static VALUE -rb_f_block_given_p() -{ - if (ruby_frame->prev && ruby_frame->prev->iter == ITER_CUR && ruby_block) - return Qtrue; - return Qfalse; -} - -static VALUE rb_eThreadError; - -NORETURN(static void proc_jump_error(int, VALUE)); -static void -proc_jump_error(state, result) - int state; - VALUE result; -{ - char mesg[32]; - char *statement; - - switch (state) { - case TAG_BREAK: - statement = "break"; break; - case TAG_RETURN: - statement = "return"; break; - case TAG_RETRY: - statement = "retry"; break; - default: - statement = "local-jump"; break; /* should not happen */ - } - snprintf(mesg, sizeof mesg, "%s from proc-closure", statement); - localjump_error(mesg, result, state); -} - -NORETURN(static void return_jump(VALUE)); -static void -return_jump(retval) - VALUE retval; -{ - struct tag *tt = prot_tag; - int yield = Qfalse; - - if (retval == Qundef) retval = Qnil; - while (tt) { - if (tt->tag == PROT_YIELD) { - yield = Qtrue; - tt = tt->prev; - } - if ((tt->tag == PROT_FUNC && tt->frame->uniq == ruby_frame->uniq) || - (tt->tag == PROT_LAMBDA && !yield)) - { - tt->dst = (VALUE)tt->frame->uniq; - tt->retval = retval; - JUMP_TAG(TAG_RETURN); - } - if (tt->tag == PROT_THREAD) { - rb_raise(rb_eThreadError, "return can't jump across threads"); - } - tt = tt->prev; - } - localjump_error("unexpected return", retval, TAG_RETURN); -} - -static void -break_jump(retval) - VALUE retval; -{ - struct tag *tt = prot_tag; - - if (retval == Qundef) retval = Qnil; - while (tt) { - switch (tt->tag) { - case PROT_THREAD: - case PROT_YIELD: - case PROT_LOOP: - case PROT_LAMBDA: - tt->dst = (VALUE)tt->frame->uniq; - tt->retval = retval; - JUMP_TAG(TAG_BREAK); - break; - default: - break; - } - tt = tt->prev; - } - localjump_error("unexpected break", retval, TAG_BREAK); -} - -static VALUE bmcall _((VALUE, VALUE)); -static int method_arity _((VALUE)); - -static VALUE -rb_yield_0(val, self, klass, flags, avalue) - VALUE val, self, klass; /* OK */ - int flags, avalue; -{ - NODE *node, *var; - volatile VALUE result = Qnil; - volatile VALUE old_cref; - volatile VALUE old_wrapper; - struct BLOCK * volatile block; - struct SCOPE * volatile old_scope; - int old_vmode; - struct FRAME frame; - NODE *cnode = ruby_current_node; - int lambda = flags & YIELD_LAMBDA_CALL; - int state; - - if (!rb_block_given_p()) { - localjump_error("no block given", Qnil, 0); - } - - PUSH_VARS(); - block = ruby_block; - frame = block->frame; - frame.prev = ruby_frame; - ruby_frame = &(frame); - old_cref = (VALUE)ruby_cref; - ruby_cref = block->cref; - old_wrapper = ruby_wrapper; - ruby_wrapper = block->wrapper; - old_scope = ruby_scope; - ruby_scope = block->scope; - old_vmode = scope_vmode; - scope_vmode = (flags & YIELD_PUBLIC_DEF) ? SCOPE_PUBLIC : block->vmode; - ruby_block = block->prev; - if (block->flags & BLOCK_D_SCOPE) { - /* put place holder for dynamic (in-block) local variables */ - ruby_dyna_vars = new_dvar(0, 0, block->dyna_vars); - } - else { - /* FOR does not introduce new scope */ - ruby_dyna_vars = block->dyna_vars; - } - PUSH_CLASS(klass ? klass : block->klass); - if (!klass) { - self = block->self; - } - node = block->body; - var = block->var; - - if (var) { - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - NODE *bvar = NULL; - block_var: - if (var == (NODE*)1) { /* no parameter || */ - if (lambda && RARRAY(val)->len != 0) { - rb_raise(rb_eArgError, "wrong number of arguments (%ld for 0)", - RARRAY(val)->len); - } - } - else if (var == (NODE*)2) { - if (TYPE(val) == T_ARRAY && RARRAY(val)->len != 0) { - rb_raise(rb_eArgError, "wrong number of arguments (%ld for 0)", - RARRAY(val)->len); - } - } - else if (!bvar && nd_type(var) == NODE_BLOCK_PASS) { - bvar = var->nd_body; - var = var->nd_args; - goto block_var; - } - else if (nd_type(var) == NODE_MASGN) { - if (!avalue) { - val = svalue_to_mrhs(val, var->nd_head); - } - massign(self, var, val, lambda); - } - else { - int len = 0; - if (avalue) { - len = RARRAY(val)->len; - if (len == 0) { - goto zero_arg; - } - if (len == 1) { - val = RARRAY(val)->ptr[0]; - } - else { - goto multi_values; - } - } - else if (val == Qundef) { - zero_arg: - val = Qnil; - multi_values: - { - ruby_current_node = var; - rb_warn("multiple values for a block parameter (%d for 1)\n\tfrom %s:%d", - len, cnode->nd_file, nd_line(cnode)); - ruby_current_node = cnode; - } - } - assign(self, var, val, lambda); - } - if (bvar) { - VALUE blk; - if (flags & YIELD_PROC_CALL) - blk = block->block_obj; - else - blk = rb_block_proc(); - assign(self, bvar, blk, 0); - } - } - POP_TAG(); - if (state) goto pop_state; - } - else if (lambda && RARRAY(val)->len != 0 && - (!node || nd_type(node) != NODE_IFUNC || - node->nd_cfnc != bmcall)) { - rb_raise(rb_eArgError, "wrong number of arguments (%ld for 0)", - RARRAY(val)->len); - } - if (!node) { - state = 0; - goto pop_state; - } - ruby_current_node = node; - - PUSH_ITER(block->iter); - PUSH_TAG(lambda ? PROT_NONE : PROT_YIELD); - if ((state = EXEC_TAG()) == 0) { - redo: - if (nd_type(node) == NODE_CFUNC || nd_type(node) == NODE_IFUNC) { - if (node->nd_state == YIELD_FUNC_AVALUE) { - if (!avalue) { - val = svalue_to_avalue(val); - } - } - else { - if (avalue) { - val = avalue_to_svalue(val); - } - if (val == Qundef && node->nd_state != YIELD_FUNC_SVALUE) - val = Qnil; - } - if ((block->flags&BLOCK_FROM_METHOD) && RTEST(block->block_obj)) { - struct BLOCK *data, _block; - Data_Get_Struct(block->block_obj, struct BLOCK, data); - _block = *data; - _block.outer = ruby_block; - _block.uniq = block_unique++; - ruby_block = &_block; - PUSH_ITER(ITER_PRE); - ruby_frame->iter = ITER_CUR; - result = (*node->nd_cfnc)(val, node->nd_tval, self); - POP_ITER(); - } - else { - result = (*node->nd_cfnc)(val, node->nd_tval, self); - } - } - else { - result = rb_eval(self, node); - } - } - else { - switch (state) { - case TAG_REDO: - state = 0; - CHECK_INTS; - goto redo; - case TAG_NEXT: - state = 0; - result = prot_tag->retval; - break; - case TAG_BREAK: - if (TAG_DST()) { - result = prot_tag->retval; - } - else { - lambda = Qtrue; /* just pass TAG_BREAK */ - } - break; - default: - break; - } - } - POP_TAG(); - POP_ITER(); - pop_state: - POP_CLASS(); - if (ruby_dyna_vars && (block->flags & BLOCK_D_SCOPE) && - !FL_TEST(ruby_dyna_vars, DVAR_DONT_RECYCLE)) { - struct RVarmap *vars = ruby_dyna_vars; - - if (ruby_dyna_vars->id == 0) { - vars = ruby_dyna_vars->next; - rb_gc_force_recycle((VALUE)ruby_dyna_vars); - while (vars && vars->id != 0 && vars != block->dyna_vars) { - struct RVarmap *tmp = vars->next; - rb_gc_force_recycle((VALUE)vars); - vars = tmp; - } - } - } - POP_VARS(); - ruby_block = block; - ruby_frame = ruby_frame->prev; - ruby_cref = (NODE*)old_cref; - ruby_wrapper = old_wrapper; - if (ruby_scope->flags & SCOPE_DONT_RECYCLE) - scope_dup(old_scope); - ruby_scope = old_scope; - scope_vmode = old_vmode; - switch (state) { - case 0: - break; - case TAG_BREAK: - if (!lambda) { - struct tag *tt = prot_tag; - - while (tt) { - if (tt->tag == PROT_LOOP && tt->blkid == ruby_block->uniq) { - tt->dst = (VALUE)tt->frame->uniq; - tt->retval = result; - JUMP_TAG(TAG_BREAK); - } - tt = tt->prev; - } - proc_jump_error(TAG_BREAK, result); - } - /* fall through */ - default: - JUMP_TAG(state); - break; - } - ruby_current_node = cnode; - return result; -} - -VALUE -rb_yield(val) - VALUE val; -{ - return rb_yield_0(val, 0, 0, 0, Qfalse); -} - -VALUE -#ifdef HAVE_STDARG_PROTOTYPES -rb_yield_values(int n, ...) -#else -rb_yield_values(n, va_alist) - int n; - va_dcl -#endif -{ - int i; - va_list args; - VALUE val; - - if (n == 0) { - return rb_yield_0(Qundef, 0, 0, 0, Qfalse); - } - val = rb_values_new2(n, 0); - va_init_list(args, n); - for (i=0; i<n; i++) { - RARRAY(val)->ptr[i] = va_arg(args, VALUE); - } - RARRAY(val)->len = n; - va_end(args); - return rb_yield_0(val, 0, 0, 0, Qtrue); -} - -VALUE -rb_yield_splat(values) - VALUE values; -{ - int avalue = Qfalse; - - if (TYPE(values) == T_ARRAY) { - if (RARRAY(values)->len == 0) { - values = Qundef; - } - else { - avalue = Qtrue; - } - } - return rb_yield_0(values, 0, 0, 0, avalue); -} - -/* - * call-seq: - * loop {|| block } - * - * Repeatedly executes the block. - * - * loop do - * print "Input: " - * line = gets - * break if !line or line =~ /^qQ/ - * # ... - * end - */ - -static VALUE -rb_f_loop() -{ - for (;;) { - rb_yield_0(Qundef, 0, 0, 0, Qfalse); - CHECK_INTS; - } - return Qnil; /* dummy */ -} - -static VALUE -massign(self, node, val, pcall) - VALUE self; - NODE *node; - VALUE val; - int pcall; -{ - NODE *list; - long i = 0, len; - - len = RARRAY(val)->len; - list = node->nd_head; - for (; list && i<len; i++) { - assign(self, list->nd_head, RARRAY(val)->ptr[i], pcall); - list = list->nd_next; - } - if (pcall && list) goto arg_error; - if (node->nd_args) { - if ((long)(node->nd_args) == -1) { - /* no check for mere `*' */ - } - else if (!list && i<len) { - assign(self, node->nd_args, rb_ary_new4(len-i, RARRAY(val)->ptr+i), pcall); - } - else { - assign(self, node->nd_args, rb_ary_new2(0), pcall); - } - } - else if (pcall && i < len) { - goto arg_error; - } - - while (list) { - i++; - assign(self, list->nd_head, Qnil, pcall); - list = list->nd_next; - } - return val; - - arg_error: - while (list) { - i++; - list = list->nd_next; - } - rb_raise(rb_eArgError, "wrong number of arguments (%ld for %ld)", len, i); -} - -static void -assign(self, lhs, val, pcall) - VALUE self; - NODE *lhs; - VALUE val; - int pcall; -{ - ruby_current_node = lhs; - if (val == Qundef) { - rb_warning("assigning void value"); - val = Qnil; - } - switch (nd_type(lhs)) { - case NODE_GASGN: - rb_gvar_set(lhs->nd_entry, val); - break; - - case NODE_IASGN: - rb_ivar_set(self, lhs->nd_vid, val); - break; - - case NODE_LASGN: - if (ruby_scope->local_vars == 0) - rb_bug("unexpected local variable assignment"); - ruby_scope->local_vars[lhs->nd_cnt] = val; - break; - - case NODE_DASGN: - dvar_asgn(lhs->nd_vid, val); - break; - - case NODE_DASGN_CURR: - dvar_asgn_curr(lhs->nd_vid, val); - break; - - case NODE_CDECL: - if (lhs->nd_vid == 0) { - rb_const_set(class_prefix(self, lhs->nd_else), lhs->nd_else->nd_mid, val); - } - else { - rb_const_set(ruby_cbase, lhs->nd_vid, val); - } - break; - - case NODE_CVDECL: - if (RTEST(ruby_verbose) && FL_TEST(ruby_cbase, FL_SINGLETON)) { - rb_warn("declaring singleton class variable"); - } - rb_cvar_set(cvar_cbase(), lhs->nd_vid, val, Qtrue); - break; - - case NODE_CVASGN: - rb_cvar_set(cvar_cbase(), lhs->nd_vid, val, Qfalse); - break; - - case NODE_MASGN: - massign(self, lhs, svalue_to_mrhs(val, lhs->nd_head), pcall); - break; - - case NODE_CALL: - case NODE_ATTRASGN: - { - VALUE recv; - int scope; - if (lhs->nd_recv == (NODE *)1) { - recv = self; - scope = 1; - } - else { - recv = rb_eval(self, lhs->nd_recv); - scope = 0; - } - if (!lhs->nd_args) { - /* attr set */ - ruby_current_node = lhs; - SET_CURRENT_SOURCE(); - rb_call(CLASS_OF(recv), recv, lhs->nd_mid, 1, &val, scope); - } - else { - /* array set */ - VALUE args; - - args = rb_eval(self, lhs->nd_args); - rb_ary_push(args, val); - ruby_current_node = lhs; - SET_CURRENT_SOURCE(); - rb_call(CLASS_OF(recv), recv, lhs->nd_mid, - RARRAY(args)->len, RARRAY(args)->ptr, scope); - } - } - break; - - default: - rb_bug("bug in variable assignment"); - break; - } -} - -VALUE -rb_iterate(it_proc, data1, bl_proc, data2) - VALUE (*it_proc) _((VALUE)), (*bl_proc)(ANYARGS); - VALUE data1, data2; -{ - int state; - volatile VALUE retval = Qnil; - NODE *node = NEW_IFUNC(bl_proc, data2); - VALUE self = ruby_top_self; - - PUSH_ITER(ITER_PRE); - PUSH_TAG(PROT_LOOP); - PUSH_BLOCK(0, node); - state = EXEC_TAG(); - if (state == 0) { - iter_retry: - retval = (*it_proc)(data1); - } - else if (state == TAG_BREAK && TAG_DST()) { - retval = prot_tag->retval; - state = 0; - } - else if (state == TAG_RETRY) { - state = 0; - goto iter_retry; - } - POP_BLOCK(); - POP_TAG(); - POP_ITER(); - - switch (state) { - case 0: - break; - default: - JUMP_TAG(state); - } - return retval; -} - -static int -handle_rescue(self, node) - VALUE self; - NODE *node; -{ - int argc; VALUE *argv; /* used in SETUP_ARGS */ - TMP_PROTECT; - - if (!node->nd_args) { - return rb_obj_is_kind_of(ruby_errinfo, rb_eStandardError); - } - - BEGIN_CALLARGS; - SETUP_ARGS(node->nd_args); - END_CALLARGS; - - while (argc--) { - if (!rb_obj_is_kind_of(argv[0], rb_cModule)) { - rb_raise(rb_eTypeError, "class or module required for rescue clause"); - } - if (RTEST(rb_funcall(*argv, eqq, 1, ruby_errinfo))) return 1; - argv++; - } - return 0; -} - -VALUE -#ifdef HAVE_STDARG_PROTOTYPES -rb_rescue2(VALUE (*b_proc)(ANYARGS), VALUE data1, VALUE (*r_proc)(ANYARGS), VALUE data2, ...) -#else -rb_rescue2(b_proc, data1, r_proc, data2, va_alist) - VALUE (*b_proc)(ANYARGS), (*r_proc)(ANYARGS); - VALUE data1, data2; - va_dcl -#endif -{ - int state; - volatile VALUE result; - volatile VALUE e_info = ruby_errinfo; - va_list args; - - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - retry_entry: - result = (*b_proc)(data1); - } - else if (state == TAG_RAISE) { - int handle = Qfalse; - VALUE eclass; - - va_init_list(args, data2); - while (eclass = va_arg(args, VALUE)) { - if (rb_obj_is_kind_of(ruby_errinfo, eclass)) { - handle = Qtrue; - break; - } - } - va_end(args); - - if (handle) { - if (r_proc) { - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - result = (*r_proc)(data2, ruby_errinfo); - } - POP_TAG(); - if (state == TAG_RETRY) { - state = 0; - ruby_errinfo = Qnil; - goto retry_entry; - } - } - else { - result = Qnil; - state = 0; - } - if (state == 0) { - ruby_errinfo = e_info; - } - } - } - POP_TAG(); - if (state) JUMP_TAG(state); - - return result; -} - -VALUE -rb_rescue(b_proc, data1, r_proc, data2) - VALUE (*b_proc)(), (*r_proc)(); - VALUE data1, data2; -{ - return rb_rescue2(b_proc, data1, r_proc, data2, rb_eStandardError, (VALUE)0); -} - -static VALUE cont_protect; - -VALUE -rb_protect(proc, data, state) - VALUE (*proc) _((VALUE)); - VALUE data; - int *state; -{ - VALUE result = Qnil; /* OK */ - int status; - - PUSH_THREAD_TAG(); - cont_protect = (VALUE)rb_node_newnode(NODE_MEMO, cont_protect, 0, 0); - if ((status = EXEC_TAG()) == 0) { - result = (*proc)(data); - } - else if (status == TAG_THREAD) { - rb_thread_start_1(); - } - cont_protect = ((NODE *)cont_protect)->u1.value; - POP_THREAD_TAG(); - if (state) { - *state = status; - } - if (status != 0) { - return Qnil; - } - - return result; -} - -VALUE -rb_ensure(b_proc, data1, e_proc, data2) - VALUE (*b_proc)(); - VALUE data1; - VALUE (*e_proc)(); - VALUE data2; -{ - int state; - volatile VALUE result = Qnil; - VALUE retval; - - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - result = (*b_proc)(data1); - } - POP_TAG(); - retval = prot_tag ? prot_tag->retval : Qnil; /* save retval */ - (*e_proc)(data2); - if (prot_tag) return_value(retval); - if (state) JUMP_TAG(state); - return result; -} - -VALUE -rb_with_disable_interrupt(proc, data) - VALUE (*proc)(); - VALUE data; -{ - VALUE result = Qnil; /* OK */ - int status; - - DEFER_INTS; - { - int thr_critical = rb_thread_critical; - - rb_thread_critical = Qtrue; - PUSH_TAG(PROT_NONE); - if ((status = EXEC_TAG()) == 0) { - result = (*proc)(data); - } - POP_TAG(); - rb_thread_critical = thr_critical; - } - ENABLE_INTS; - if (status) JUMP_TAG(status); - - return result; -} - -static inline void -stack_check() -{ - static int overflowing = 0; - - if (!overflowing && ruby_stack_check()) { - int state; - overflowing = 1; - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - rb_exc_raise(sysstack_error); - } - POP_TAG(); - overflowing = 0; - JUMP_TAG(state); - } -} - -static int last_call_status; - -#define CSTAT_PRIV 1 -#define CSTAT_PROT 2 -#define CSTAT_VCALL 4 -#define CSTAT_SUPER 8 - -/* - * call-seq: - * obj.method_missing(symbol [, *args] ) => result - * - * Invoked by Ruby when <i>obj</i> is sent a message it cannot handle. - * <i>symbol</i> is the symbol for the method called, and <i>args</i> - * are any arguments that were passed to it. By default, the interpreter - * raises an error when this method is called. However, it is possible - * to override the method to provide more dynamic behavior. - * The example below creates - * a class <code>Roman</code>, which responds to methods with names - * consisting of roman numerals, returning the corresponding integer - * values. - * - * class Roman - * def romanToInt(str) - * # ... - * end - * def method_missing(methId) - * str = methId.id2name - * romanToInt(str) - * end - * end - * - * r = Roman.new - * r.iv #=> 4 - * r.xxiii #=> 23 - * r.mm #=> 2000 - */ - -static VALUE -rb_method_missing(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - ID id; - VALUE exc = rb_eNoMethodError; - char *format = 0; - NODE *cnode = ruby_current_node; - - if (argc == 0 || !SYMBOL_P(argv[0])) { - rb_raise(rb_eArgError, "no id given"); - } - - stack_check(); - - id = SYM2ID(argv[0]); - - if (last_call_status & CSTAT_PRIV) { - format = "private method `%s' called for %s"; - } - else if (last_call_status & CSTAT_PROT) { - format = "protected method `%s' called for %s"; - } - else if (last_call_status & CSTAT_VCALL) { - format = "undefined local variable or method `%s' for %s"; - exc = rb_eNameError; - } - else if (last_call_status & CSTAT_SUPER) { - format = "super: no superclass method `%s'"; - } - if (!format) { - format = "undefined method `%s' for %s"; - } - - ruby_current_node = cnode; - { - int n = 0; - VALUE args[3]; - - args[n++] = rb_funcall(rb_const_get(exc, rb_intern("message")), '!', - 3, rb_str_new2(format), obj, argv[0]); - args[n++] = argv[0]; - if (exc == rb_eNoMethodError) { - args[n++] = rb_ary_new4(argc-1, argv+1); - } - exc = rb_class_new_instance(n, args, exc); - ruby_frame = ruby_frame->prev; /* pop frame for "method_missing" */ - rb_exc_raise(exc); - } - - return Qnil; /* not reached */ -} - -static VALUE -method_missing(obj, id, argc, argv, call_status) - VALUE obj; - ID id; - int argc; - const VALUE *argv; - int call_status; -{ - VALUE *nargv; - - last_call_status = call_status; - - if (id == missing) { - PUSH_FRAME(); - rb_method_missing(argc, argv, obj); - POP_FRAME(); - } - else if (id == ID_ALLOCATOR) { - rb_raise(rb_eTypeError, "allocator undefined for %s", rb_class2name(obj)); - } - - nargv = ALLOCA_N(VALUE, argc+1); - nargv[0] = ID2SYM(id); - MEMCPY(nargv+1, argv, VALUE, argc); - - return rb_funcall2(obj, missing, argc+1, nargv); -} - -static inline VALUE -call_cfunc(func, recv, len, argc, argv) - VALUE (*func)(); - VALUE recv; - int len, argc; - VALUE *argv; -{ - if (len >= 0 && argc != len) { - rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", - argc, len); - } - - switch (len) { - case -2: - return (*func)(recv, rb_ary_new4(argc, argv)); - break; - case -1: - return (*func)(argc, argv, recv); - break; - case 0: - return (*func)(recv); - break; - case 1: - return (*func)(recv, argv[0]); - break; - case 2: - return (*func)(recv, argv[0], argv[1]); - break; - case 3: - return (*func)(recv, argv[0], argv[1], argv[2]); - break; - case 4: - return (*func)(recv, argv[0], argv[1], argv[2], argv[3]); - break; - case 5: - return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4]); - break; - case 6: - return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5]); - break; - case 7: - return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6]); - break; - case 8: - return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7]); - break; - case 9: - return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7], argv[8]); - break; - case 10: - return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7], argv[8], argv[9]); - break; - case 11: - return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]); - break; - case 12: - return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7], argv[8], argv[9], - argv[10], argv[11]); - break; - case 13: - return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], - argv[11], argv[12]); - break; - case 14: - return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], - argv[11], argv[12], argv[13]); - break; - case 15: - return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], - argv[11], argv[12], argv[13], argv[14]); - break; - default: - rb_raise(rb_eArgError, "too many arguments (%d)", len); - break; - } - return Qnil; /* not reached */ -} - -static VALUE -rb_call0(klass, recv, id, oid, argc, argv, body, nosuper) - VALUE klass, recv; - ID id; - ID oid; - int argc; /* OK */ - VALUE *argv; /* OK */ - NODE *body; /* OK */ - int nosuper; -{ - NODE *b2; /* OK */ - volatile VALUE result = Qnil; - int itr; - static int tick; - volatile VALUE args; - TMP_PROTECT; - - switch (ruby_iter->iter) { - case ITER_PRE: - itr = ITER_CUR; - break; - case ITER_CUR: - default: - itr = ITER_NOT; - break; - } - - if ((++tick & 0xff) == 0) { - CHECK_INTS; /* better than nothing */ - stack_check(); - rb_gc_finalize_deferred(); - } - if (argc < 0) { - argc = -argc-1; - args = rb_ary_concat(rb_ary_new4(argc, argv), splat_value(argv[argc])); - argc = RARRAY(args)->len; - argv = RARRAY(args)->ptr; - } - PUSH_ITER(itr); - PUSH_FRAME(); - ruby_frame->callee = id; - ruby_frame->this_func = oid; - ruby_frame->this_class = nosuper?0:klass; - ruby_frame->self = recv; - ruby_frame->argc = argc; - - switch (nd_type(body)) { - case NODE_CFUNC: - { - int len = body->nd_argc; - - if (len < -2) { - rb_bug("bad argc (%d) specified for `%s(%s)'", - len, rb_class2name(klass), rb_id2name(id)); - } - if (event_hooks) { - int state; - - EXEC_EVENT_HOOK(RUBY_EVENT_C_CALL, ruby_current_node, - recv, id, klass); - PUSH_TAG(PROT_FUNC); - if ((state = EXEC_TAG()) == 0) { - result = call_cfunc(body->nd_cfnc, recv, len, argc, argv); - } - POP_TAG(); - ruby_current_node = ruby_frame->node; - EXEC_EVENT_HOOK(RUBY_EVENT_C_RETURN, ruby_current_node, - recv, id, klass); - if (state) JUMP_TAG(state); - } - else { - result = call_cfunc(body->nd_cfnc, recv, len, argc, argv); - } - } - break; - - /* for attr get/set */ - case NODE_IVAR: - if (argc != 0) { - rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc); - } - result = rb_attr_get(recv, body->nd_vid); - break; - - case NODE_ATTRSET: - if (argc != 1) - rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc); - result = rb_ivar_set(recv, body->nd_vid, argv[0]); - break; - - case NODE_ZSUPER: /* visibility override */ - result = rb_call_super(argc, argv); - break; - - case NODE_BMETHOD: - ruby_frame->flags |= FRAME_DMETH; - result = proc_invoke(body->nd_cval, rb_ary_new4(argc, argv), recv, klass); - break; - - case NODE_SCOPE: - { - int state; - VALUE *local_vars; /* OK */ - NODE *saved_cref = 0; - - PUSH_SCOPE(); - - if (body->nd_rval) { - saved_cref = ruby_cref; - ruby_cref = (NODE*)body->nd_rval; - } - PUSH_CLASS(ruby_cbase); - if (body->nd_tbl) { - local_vars = TMP_ALLOC(body->nd_tbl[0]+1); - *local_vars++ = (VALUE)body; - rb_mem_clear(local_vars, body->nd_tbl[0]); - ruby_scope->local_tbl = body->nd_tbl; - ruby_scope->local_vars = local_vars; - } - else { - local_vars = ruby_scope->local_vars = 0; - ruby_scope->local_tbl = 0; - } - b2 = body = body->nd_next; - - PUSH_VARS(); - PUSH_TAG(PROT_FUNC); - - if ((state = EXEC_TAG()) == 0) { - NODE *node = 0; - int i; - - if (nd_type(body) == NODE_ARGS) { - node = body; - body = 0; - } - else if (nd_type(body) == NODE_BLOCK) { - node = body->nd_head; - body = body->nd_next; - } - if (node) { - if (nd_type(node) != NODE_ARGS) { - rb_bug("no argument-node"); - } - - i = node->nd_cnt; - if (i > argc) { - rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, i); - } - if ((long)node->nd_rest == -1) { - int opt = i; - NODE *optnode = node->nd_opt; - - while (optnode) { - opt++; - optnode = optnode->nd_next; - } - if (opt < argc) { - rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", - argc, opt); - } - ruby_frame->argc = opt; - } - - if (local_vars) { - if (i > 0) { - /* +2 for $_ and $~ */ - MEMCPY(local_vars+2, argv, VALUE, i); - } - argv += i; argc -= i; - if (node->nd_opt) { - NODE *opt = node->nd_opt; - - while (opt && argc) { - assign(recv, opt->nd_head, *argv, 1); - argv++; argc--; - opt = opt->nd_next; - } - if (opt) { - rb_eval(recv, opt); - } - } - if ((long)node->nd_rest >= 0) { - VALUE v; - - if (argc > 0) - v = rb_ary_new4(argc,argv); - else - v = rb_ary_new2(0); - ruby_scope->local_vars[node->nd_rest] = v; - } - } - } - if ((long)node->nd_rest >= 0) { - ruby_frame->argc = -(ruby_frame->argc - argc)-1; - } - - if (event_hooks) { - EXEC_EVENT_HOOK(RUBY_EVENT_CALL, b2, recv, id, klass); - } - result = rb_eval(recv, body); - } - else if (state == TAG_RETURN && TAG_DST()) { - result = prot_tag->retval; - state = 0; - } - POP_TAG(); - POP_VARS(); - POP_CLASS(); - POP_SCOPE(); - ruby_cref = saved_cref; - if (event_hooks) { - EXEC_EVENT_HOOK(RUBY_EVENT_RETURN, body, recv, id, klass); - } - switch (state) { - case 0: - break; - - case TAG_BREAK: - case TAG_RETURN: - JUMP_TAG(state); - break; - - case TAG_RETRY: - if (rb_block_given_p()) JUMP_TAG(state); - /* fall through */ - default: - jump_tag_but_local_jump(state, result); - break; - } - } - break; - - default: - rb_bug("unknown node type %d", nd_type(body)); - break; - } - POP_FRAME(); - POP_ITER(); - return result; -} - -static VALUE -rb_call(klass, recv, mid, argc, argv, scope) - VALUE klass, recv; - ID mid; - int argc; /* OK */ - const VALUE *argv; /* OK */ - int scope; -{ - NODE *body; /* OK */ - int noex; - ID id = mid; - struct cache_entry *ent; - - if (!klass) { - rb_raise(rb_eNotImpError, "method `%s' called on terminated object (0x%lx)", - rb_id2name(mid), recv); - } - /* is it in the method cache? */ - ent = cache + EXPR1(klass, mid); - if (ent->mid == mid && ent->klass == klass) { - if (!ent->method) - return method_missing(recv, mid, argc, argv, scope==2?CSTAT_VCALL:0); - klass = ent->origin; - id = ent->mid0; - noex = ent->noex; - body = ent->method; - } - else if ((body = rb_get_method_body(&klass, &id, &noex)) == 0) { - if (scope == 3) { - return method_missing(recv, mid, argc, argv, CSTAT_SUPER); - } - return method_missing(recv, mid, argc, argv, scope==2?CSTAT_VCALL:0); - } - - if (mid != missing) { - /* receiver specified form for private method */ - if ((noex & NOEX_PRIVATE) && scope == 0) - return method_missing(recv, mid, argc, argv, CSTAT_PRIV); - - /* self must be kind of a specified form for protected method */ - if ((noex & NOEX_PROTECTED)) { - VALUE defined_class = klass; - - if (TYPE(defined_class) == T_ICLASS) { - defined_class = RBASIC(defined_class)->klass; - } - if (!rb_obj_is_kind_of(ruby_frame->self, rb_class_real(defined_class))) - return method_missing(recv, mid, argc, argv, CSTAT_PROT); - } - } - - return rb_call0(klass, recv, mid, id, argc, argv, body, noex & NOEX_NOSUPER); -} - -VALUE -rb_apply(recv, mid, args) - VALUE recv; - ID mid; - VALUE args; -{ - int argc; - VALUE *argv; - - argc = RARRAY(args)->len; /* Assigns LONG, but argc is INT */ - argv = ALLOCA_N(VALUE, argc); - MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc); - return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1); -} - -/* - * call-seq: - * obj.send(symbol [, args...]) => obj - * obj.__send__(symbol [, args...]) => obj - * - * Invokes the method identified by _symbol_, passing it any - * arguments specified. You can use <code>__send__</code> if the name - * +send+ clashes with an existing method in _obj_. - * - * class Klass - * def hello(*args) - * "Hello " + args.join(' ') - * end - * end - * k = Klass.new - * k.send :hello, "gentle", "readers" #=> "Hello gentle readers" - */ - -static VALUE -rb_f_send(argc, argv, recv) - int argc; - VALUE *argv; - VALUE recv; -{ - VALUE vid; - - if (argc == 0) rb_raise(rb_eArgError, "no method name given"); - - vid = *argv++; argc--; - PUSH_ITER(rb_block_given_p()?ITER_PRE:ITER_NOT); - vid = rb_call(CLASS_OF(recv), recv, rb_to_id(vid), argc, argv, 1); - POP_ITER(); - - return vid; -} - -VALUE -#ifdef HAVE_STDARG_PROTOTYPES -rb_funcall(VALUE recv, ID mid, int n, ...) -#else -rb_funcall(recv, mid, n, va_alist) - VALUE recv; - ID mid; - int n; - va_dcl -#endif -{ - VALUE *argv; - va_list ar; - va_init_list(ar, n); - - if (n > 0) { - long i; - - argv = ALLOCA_N(VALUE, n); - - for (i=0;i<n;i++) { - argv[i] = va_arg(ar, VALUE); - } - va_end(ar); - } - else { - argv = 0; - } - - return rb_call(CLASS_OF(recv), recv, mid, n, argv, 1); -} - -VALUE -rb_funcall2(recv, mid, argc, argv) - VALUE recv; - ID mid; - int argc; - const VALUE *argv; -{ - return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1); -} - -VALUE -rb_funcall3(recv, mid, argc, argv) - VALUE recv; - ID mid; - int argc; - const VALUE *argv; -{ - return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 0); -} - -VALUE -rb_call_super(argc, argv) - int argc; - const VALUE *argv; -{ - VALUE result, self, klass, k; - - if (ruby_frame->this_class == 0) { - rb_name_error(ruby_frame->callee, "calling `super' from `%s' is prohibited", - rb_id2name(ruby_frame->this_func)); - } - - self = ruby_frame->self; - klass = ruby_frame->this_class; - - PUSH_ITER(ruby_iter->iter ? ITER_PRE : ITER_NOT); - result = rb_call(RCLASS(klass)->super, self, ruby_frame->this_func, argc, argv, 3); - POP_ITER(); - - return result; -} - -static VALUE -backtrace(lev) - int lev; -{ - struct FRAME *frame = ruby_frame; - char buf[BUFSIZ]; - volatile VALUE ary; - NODE *n; - - ary = rb_ary_new(); - if (frame->this_func == ID_ALLOCATOR) { - frame = frame->prev; - } - if (lev < 0) { - ruby_set_current_source(); - if (frame->this_func) { - snprintf(buf, BUFSIZ, "%s:%d:in `%s'", - ruby_sourcefile, ruby_sourceline, - rb_id2name(frame->this_func)); - } - else if (ruby_sourceline == 0) { - snprintf(buf, BUFSIZ, "%s", ruby_sourcefile); - } - else { - snprintf(buf, BUFSIZ, "%s:%d", ruby_sourcefile, ruby_sourceline); - } - rb_ary_push(ary, rb_str_new2(buf)); - if (lev < -1) return ary; - } - else { - while (lev-- > 0) { - frame = frame->prev; - if (!frame) { - ary = Qnil; - break; - } - } - } - while (frame && (n = frame->node)) { - if (frame->prev && frame->prev->this_func) { - snprintf(buf, BUFSIZ, "%s:%d:in `%s'", - n->nd_file, nd_line(n), - rb_id2name(frame->prev->this_func)); - } - else { - snprintf(buf, BUFSIZ, "%s:%d", n->nd_file, nd_line(n)); - } - rb_ary_push(ary, rb_str_new2(buf)); - frame = frame->prev; - } - - return ary; -} - -/* - * call-seq: - * caller(start=1) => array - * - * Returns the current execution stack---an array containing strings in - * the form ``<em>file:line</em>'' or ``<em>file:line: in - * `method'</em>''. The optional _start_ parameter - * determines the number of initial stack entries to omit from the - * result. - * - * def a(skip) - * caller(skip) - * end - * def b(skip) - * a(skip) - * end - * def c(skip) - * b(skip) - * end - * c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10"] - * c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11"] - * c(2) #=> ["prog:8:in `c'", "prog:12"] - * c(3) #=> ["prog:13"] - */ - -static VALUE -rb_f_caller(argc, argv) - int argc; - VALUE *argv; -{ - VALUE level; - int lev; - - rb_scan_args(argc, argv, "01", &level); - - if (NIL_P(level)) lev = 1; - else lev = NUM2INT(level); - if (lev < 0) rb_raise(rb_eArgError, "negative level (%d)", lev); - - return backtrace(lev); -} - -void -rb_backtrace() -{ - long i; - VALUE ary; - - ary = backtrace(-1); - for (i=0; i<RARRAY(ary)->len; i++) { - printf("\tfrom %s\n", RSTRING(RARRAY(ary)->ptr[i])->ptr); - } -} - -static VALUE -make_backtrace() -{ - return backtrace(-1); -} - -ID -rb_frame_this_func() -{ - return ruby_frame->this_func; -} - -static NODE* -compile(src, file, line) - VALUE src; - char *file; - int line; -{ - NODE *node; - int critical; - - ruby_nerrs = 0; - StringValue(src); - critical = rb_thread_critical; - rb_thread_critical = Qtrue; - node = rb_compile_string(file, src, line); - rb_thread_critical = critical; - - if (ruby_nerrs == 0) return node; - return 0; -} - -static VALUE -eval(self, src, scope, file, line) - VALUE self, src, scope; - char *file; - int line; -{ - struct BLOCK *data = NULL; - volatile VALUE result = Qnil; - struct SCOPE * volatile old_scope; - struct BLOCK * volatile old_block; - struct RVarmap * volatile old_dyna_vars; - VALUE volatile old_cref; - int volatile old_vmode; - volatile VALUE old_wrapper; - struct FRAME frame; - NODE *nodesave = ruby_current_node; - volatile int iter = ruby_frame->iter; - volatile int safe = ruby_safe_level; - int state; - - if (!NIL_P(scope)) { - if (!rb_obj_is_proc(scope)) { - rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc/Binding)", - rb_obj_classname(scope)); - } - - Data_Get_Struct(scope, struct BLOCK, data); - /* PUSH BLOCK from data */ - frame = data->frame; - frame.tmp = ruby_frame; /* gc protection */ - ruby_frame = &(frame); - old_scope = ruby_scope; - ruby_scope = data->scope; - old_block = ruby_block; - ruby_block = data->prev; - old_dyna_vars = ruby_dyna_vars; - ruby_dyna_vars = data->dyna_vars; - old_vmode = scope_vmode; - scope_vmode = data->vmode; - old_cref = (VALUE)ruby_cref; - ruby_cref = data->cref; - old_wrapper = ruby_wrapper; - ruby_wrapper = data->wrapper; - if ((file == 0 || (line == 1 && strcmp(file, "(eval)") == 0)) && data->frame.node) { - file = data->frame.node->nd_file; - if (!file) file = "__builtin__"; - line = nd_line(data->frame.node); - } - - self = data->self; - ruby_frame->iter = data->iter; - } - else { - if (ruby_frame->prev) { - ruby_frame->iter = ruby_frame->prev->iter; - } - } - if (file == 0) { - ruby_set_current_source(); - file = ruby_sourcefile; - line = ruby_sourceline; - } - PUSH_CLASS(ruby_cbase); - ruby_in_eval++; - if (TYPE(ruby_class) == T_ICLASS) { - ruby_class = RBASIC(ruby_class)->klass; - } - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - NODE *node; - - ruby_safe_level = 0; - result = ruby_errinfo; - ruby_errinfo = Qnil; - node = compile(src, file, line); - ruby_safe_level = safe; - if (ruby_nerrs > 0) { - compile_error(0); - } - if (!NIL_P(result)) ruby_errinfo = result; - result = eval_node(self, node); - } - POP_TAG(); - POP_CLASS(); - ruby_in_eval--; - ruby_safe_level = safe; - if (!NIL_P(scope)) { - int dont_recycle = ruby_scope->flags & SCOPE_DONT_RECYCLE; - - ruby_wrapper = old_wrapper; - ruby_cref = (NODE*)old_cref; - ruby_frame = frame.tmp; - ruby_scope = old_scope; - ruby_block = old_block; - ruby_dyna_vars = old_dyna_vars; - data->vmode = scope_vmode; /* write back visibility mode */ - scope_vmode = old_vmode; - if (dont_recycle) { - struct tag *tag; - struct RVarmap *vars; - - scope_dup(ruby_scope); - for (tag=prot_tag; tag; tag=tag->prev) { - scope_dup(tag->scope); - } - for (vars = ruby_dyna_vars; vars; vars = vars->next) { - FL_SET(vars, DVAR_DONT_RECYCLE); - } - } - } - else { - ruby_frame->iter = iter; - } - ruby_current_node = nodesave; - ruby_set_current_source(); - if (state) { - if (state == TAG_RAISE) { - if (strcmp(file, "(eval)") == 0) { - VALUE mesg, errat; - - errat = get_backtrace(ruby_errinfo); - mesg = rb_attr_get(ruby_errinfo, rb_intern("mesg")); - if (!NIL_P(errat) && TYPE(errat) == T_ARRAY) { - if (!NIL_P(mesg) && TYPE(mesg) == T_STRING) { - rb_str_update(mesg, 0, 0, rb_str_new2(": ")); - rb_str_update(mesg, 0, 0, RARRAY(errat)->ptr[0]); - } - RARRAY(errat)->ptr[0] = RARRAY(backtrace(-2))->ptr[0]; - } - } - rb_exc_raise(ruby_errinfo); - } - JUMP_TAG(state); - } - - return result; -} - -/* - * call-seq: - * eval(string [, binding [, filename [,lineno]]]) => obj - * - * Evaluates the Ruby expression(s) in <em>string</em>. If - * <em>binding</em> is given, the evaluation is performed in its - * context. The binding may be a <code>Binding</code> object or a - * <code>Proc</code> object. If the optional <em>filename</em> and - * <em>lineno</em> parameters are present, they will be used when - * reporting syntax errors. - * - * def getBinding(str) - * return binding - * end - * str = "hello" - * eval "str + ' Fred'" #=> "hello Fred" - * eval "str + ' Fred'", getBinding("bye") #=> "bye Fred" - */ - -static VALUE -rb_f_eval(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ - VALUE src, scope, vfile, vline; - char *file = "(eval)"; - int line = 1; - - rb_scan_args(argc, argv, "13", &src, &scope, &vfile, &vline); - if (ruby_safe_level >= 4) { - StringValue(src); - if (!NIL_P(scope) && !OBJ_TAINTED(scope)) { - rb_raise(rb_eSecurityError, "Insecure: can't modify trusted binding"); - } - } - else { - SafeStringValue(src); - } - if (argc >= 3) { - StringValue(vfile); - } - if (argc >= 4) { - line = NUM2INT(vline); - } - - if (!NIL_P(vfile)) file = RSTRING(vfile)->ptr; - if (NIL_P(scope) && ruby_frame->prev) { - struct FRAME *prev; - VALUE val; - - prev = ruby_frame; - PUSH_FRAME(); - *ruby_frame = *prev->prev; - ruby_frame->prev = prev; - val = eval(self, src, scope, file, line); - POP_FRAME(); - - return val; - } - return eval(self, src, scope, file, line); -} - -/* function to call func under the specified class/module context */ -static VALUE -exec_under(func, under, cbase, args) - VALUE (*func)(); - VALUE under, cbase; - void *args; -{ - VALUE val = Qnil; /* OK */ - int state; - int mode; - - PUSH_CLASS(under); - PUSH_FRAME(); - ruby_frame->self = _frame.prev->self; - ruby_frame->callee = _frame.prev->callee; - ruby_frame->this_func = _frame.prev->this_func; - ruby_frame->this_class = _frame.prev->this_class; - ruby_frame->argc = _frame.prev->argc; - if (cbase) { - PUSH_CREF(cbase); - } - - mode = scope_vmode; - SCOPE_SET(SCOPE_PUBLIC); - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - val = (*func)(args); - } - POP_TAG(); - if (cbase) POP_CREF(); - SCOPE_SET(mode); - POP_FRAME(); - POP_CLASS(); - if (state) JUMP_TAG(state); - - return val; -} - -static VALUE -eval_under_i(args) - VALUE *args; -{ - return eval(args[0], args[1], Qnil, (char*)args[2], (int)args[3]); -} - -/* string eval under the class/module context */ -static VALUE -eval_under(under, self, src, file, line) - VALUE under, self, src; - const char *file; - int line; -{ - VALUE args[4]; - - if (ruby_safe_level >= 4) { - StringValue(src); - } - else { - SafeStringValue(src); - } - args[0] = self; - args[1] = src; - args[2] = (VALUE)file; - args[3] = (VALUE)line; - return exec_under(eval_under_i, under, under, args); -} - -static VALUE -yield_under_i(self) - VALUE self; -{ - return rb_yield_0(self, self, ruby_class, YIELD_PUBLIC_DEF, Qfalse); -} - -/* block eval under the class/module context */ -static VALUE -yield_under(under, self) - VALUE under, self; -{ - return exec_under(yield_under_i, under, 0, self); -} - -static VALUE -specific_eval(argc, argv, klass, self) - int argc; - VALUE *argv; - VALUE klass, self; -{ - if (rb_block_given_p()) { - if (argc > 0) { - rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc); - } - return yield_under(klass, self); - } - else { - char *file = "(eval)"; - int line = 1; - - if (argc == 0) { - rb_raise(rb_eArgError, "block not supplied"); - } - else { - if (ruby_safe_level >= 4) { - StringValue(argv[0]); - } - else { - SafeStringValue(argv[0]); - } - if (argc > 3) { - rb_raise(rb_eArgError, "wrong number of arguments: %s(src) or %s{..}", - rb_id2name(ruby_frame->callee), - rb_id2name(ruby_frame->callee)); - } - if (argc > 2) line = NUM2INT(argv[2]); - if (argc > 1) { - file = StringValuePtr(argv[1]); - } - } - return eval_under(klass, self, argv[0], file, line); - } -} - -/* - * call-seq: - * obj.instance_eval(string [, filename [, lineno]] ) => obj - * obj.instance_eval {| | block } => obj - * - * Evaluates a string containing Ruby source code, or the given block, - * within the context of the receiver (_obj_). In order to set the - * context, the variable +self+ is set to _obj_ while - * the code is executing, giving the code access to _obj_'s - * instance variables. In the version of <code>instance_eval</code> - * that takes a +String+, the optional second and third - * parameters supply a filename and starting line number that are used - * when reporting compilation errors. - * - * class Klass - * def initialize - * @secret = 99 - * end - * end - * k = Klass.new - * k.instance_eval { @secret } #=> 99 - */ - -VALUE -rb_obj_instance_eval(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ - VALUE klass; - - if (FIXNUM_P(self) || SYMBOL_P(self)) { - klass = Qnil; - } - else { - klass = rb_singleton_class(self); - } - return specific_eval(argc, argv, klass, self); -} - -/* - * call-seq: - * mod.class_eval(string [, filename [, lineno]]) => obj - * mod.module_eval {|| block } => obj - * - * Evaluates the string or block in the context of _mod_. This can - * be used to add methods to a class. <code>module_eval</code> returns - * the result of evaluating its argument. The optional _filename_ - * and _lineno_ parameters set the text for error messages. - * - * class Thing - * end - * a = %q{def hello() "Hello there!" end} - * Thing.module_eval(a) - * puts Thing.new.hello() - * Thing.module_eval("invalid code", "dummy", 123) - * - * <em>produces:</em> - * - * Hello there! - * dummy:123:in `module_eval': undefined local variable - * or method `code' for Thing:Class - */ - -VALUE -rb_mod_module_eval(argc, argv, mod) - int argc; - VALUE *argv; - VALUE mod; -{ - return specific_eval(argc, argv, mod, mod); -} - -VALUE rb_load_path; - -NORETURN(static void load_failed _((VALUE))); - -void -rb_load(fname, wrap) - VALUE fname; - int wrap; -{ - VALUE tmp; - int state; - volatile int prohibit_int = rb_prohibit_interrupt; - volatile ID callee, this_func; - volatile VALUE wrapper = ruby_wrapper; - volatile VALUE self = ruby_top_self; - NODE * volatile last_node; - NODE *saved_cref = ruby_cref; - TMP_PROTECT; - - if (!wrap) rb_secure(4); - FilePathValue(fname); - fname = rb_str_new4(fname); - tmp = rb_find_file(fname); - if (!tmp) { - load_failed(fname); - } - fname = tmp; - - ruby_errinfo = Qnil; /* ensure */ - PUSH_VARS(); - PUSH_CLASS(ruby_wrapper); - ruby_cref = top_cref; - if (!wrap) { - rb_secure(4); /* should alter global state */ - ruby_class = rb_cObject; - ruby_wrapper = 0; - } - else { - /* load in anonymous module as toplevel */ - ruby_class = ruby_wrapper = rb_module_new(); - self = rb_obj_clone(ruby_top_self); - rb_extend_object(self, ruby_wrapper); - PUSH_CREF(ruby_wrapper); - } - PUSH_ITER(ITER_NOT); - PUSH_FRAME(); - ruby_frame->callee = 0; - ruby_frame->this_func = 0; - ruby_frame->this_class = 0; - ruby_frame->self = self; - PUSH_SCOPE(); - /* default visibility is private at loading toplevel */ - SCOPE_SET(SCOPE_PRIVATE); - PUSH_TAG(PROT_NONE); - state = EXEC_TAG(); - callee = ruby_frame->callee; - this_func = ruby_frame->this_func; - last_node = ruby_current_node; - if (!ruby_current_node && ruby_sourcefile) { - last_node = NEW_BEGIN(0); - } - ruby_current_node = 0; - if (state == 0) { - NODE * volatile node; - volatile int critical; - - DEFER_INTS; - ruby_in_eval++; - critical = rb_thread_critical; - rb_thread_critical = Qtrue; - rb_load_file(RSTRING(fname)->ptr); - ruby_in_eval--; - node = ruby_eval_tree; - rb_thread_critical = critical; - ALLOW_INTS; - if (ruby_nerrs == 0) { - eval_node(self, node); - } - } - ruby_frame->callee = callee; - ruby_frame->this_func = this_func; - ruby_current_node = last_node; - ruby_sourcefile = 0; - ruby_set_current_source(); - if (ruby_scope->flags == SCOPE_ALLOCA && ruby_class == rb_cObject) { - if (ruby_scope->local_tbl) /* toplevel was empty */ - free(ruby_scope->local_tbl); - } - POP_TAG(); - rb_prohibit_interrupt = prohibit_int; - ruby_cref = saved_cref; - POP_SCOPE(); - POP_FRAME(); - POP_ITER(); - POP_CLASS(); - POP_VARS(); - ruby_wrapper = wrapper; - if (ruby_nerrs > 0) { - ruby_nerrs = 0; - rb_exc_raise(ruby_errinfo); - } - if (state) jump_tag_but_local_jump(state, Qundef); - if (!NIL_P(ruby_errinfo)) /* exception during load */ - rb_exc_raise(ruby_errinfo); -} - -void -rb_load_protect(fname, wrap, state) - VALUE fname; - int wrap; - int *state; -{ - int status; - - PUSH_THREAD_TAG(); - if ((status = EXEC_TAG()) == 0) { - rb_load(fname, wrap); - } - else if (status == TAG_THREAD) { - rb_thread_start_1(); - } - POP_THREAD_TAG(); - if (state) *state = status; -} - -/* - * call-seq: - * load(filename, wrap=false) => true - * - * Loads and executes the Ruby - * program in the file _filename_. If the filename does not - * resolve to an absolute path, the file is searched for in the library - * directories listed in <code>$:</code>. If the optional _wrap_ - * parameter is +true+, the loaded script will be executed - * under an anonymous module, protecting the calling program's global - * namespace. In no circumstance will any local variables in the loaded - * file be propagated to the loading environment. - */ - - -static VALUE -rb_f_load(argc, argv) - int argc; - VALUE *argv; -{ - VALUE fname, wrap; - - rb_scan_args(argc, argv, "11", &fname, &wrap); - rb_load(fname, RTEST(wrap)); - return Qtrue; -} - -VALUE ruby_dln_librefs; -static VALUE rb_features; -static st_table *loading_tbl; - -#define IS_SOEXT(e) (strcmp(e, ".so") == 0 || strcmp(e, ".o") == 0) -#ifdef DLEXT2 -#define IS_DLEXT(e) (strcmp(e, DLEXT) == 0 || strcmp(e, DLEXT2) == 0) -#else -#define IS_DLEXT(e) (strcmp(e, DLEXT) == 0) -#endif - -static char * -rb_feature_p(feature, ext, rb) - const char *feature, *ext; - int rb; -{ - VALUE v; - char *f, *e; - long i, len, elen; - - if (ext) { - len = ext - feature; - elen = strlen(ext); - } - else { - len = strlen(feature); - elen = 0; - } - for (i = 0; i < RARRAY(rb_features)->len; ++i) { - v = RARRAY(rb_features)->ptr[i]; - f = StringValuePtr(v); - if (strncmp(f, feature, len) != 0) continue; - if (!*(e = f + len)) { - if (ext) continue; - return e; - } - if (*e != '.') continue; - if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) { - return e; - } - if ((rb || !ext) && (strcmp(e, ".rb") == 0)) { - return e; - } - } - return 0; -} - -static const char *const loadable_ext[] = { - ".rb", DLEXT, -#ifdef DLEXT2 - DLEXT2, -#endif - 0 -}; - -static int search_required _((VALUE, VALUE *)); - -int -rb_provided(feature) - const char *feature; -{ - int i; - char *buf; - VALUE fname; - - if (rb_feature_p(feature, 0, Qfalse)) - return Qtrue; - if (loading_tbl) { - if (st_lookup(loading_tbl, (st_data_t)feature, 0)) return Qtrue; - buf = ALLOCA_N(char, strlen(feature)+8); - strcpy(buf, feature); - for (i=0; loadable_ext[i]; i++) { - strcpy(buf+strlen(feature), loadable_ext[i]); - if (st_lookup(loading_tbl, (st_data_t)buf, 0)) return Qtrue; - } - } - if (search_required(rb_str_new2(feature), &fname)) { - feature = RSTRING(fname)->ptr; - if (rb_feature_p(feature, 0, Qfalse)) - return Qtrue; - if (loading_tbl && st_lookup(loading_tbl, (st_data_t)feature, 0)) - return Qtrue; - } - return Qfalse; -} - -static void -rb_provide_feature(feature) - VALUE feature; -{ - rb_ary_push(rb_features, feature); -} - -void -rb_provide(feature) - const char *feature; -{ - rb_provide_feature(rb_str_new2(feature)); -} - -static int -load_wait(ftptr) - char *ftptr; -{ - st_data_t th; - - if (!loading_tbl) return Qfalse; - if (!st_lookup(loading_tbl, (st_data_t)ftptr, &th)) return Qfalse; - if ((rb_thread_t)th == curr_thread) return Qtrue; - do { - CHECK_INTS; - rb_thread_schedule(); - } while (st_lookup(loading_tbl, (st_data_t)ftptr, &th)); - return Qtrue; -} - -/* - * call-seq: - * require(string) => true or false - * - * Ruby tries to load the library named _string_, returning - * +true+ if successful. If the filename does not resolve to - * an absolute path, it will be searched for in the directories listed - * in <code>$:</code>. If the file has the extension ``.rb'', it is - * loaded as a source file; if the extension is ``.so'', ``.o'', or - * ``.dll'', or whatever the default shared library extension is on - * the current platform, Ruby loads the shared library as a Ruby - * extension. Otherwise, Ruby tries adding ``.rb'', ``.so'', and so on - * to the name. The name of the loaded feature is added to the array in - * <code>$"</code>. A feature will not be loaded if it's name already - * appears in <code>$"</code>. However, the file name is not converted - * to an absolute path, so that ``<code>require 'a';require - * './a'</code>'' will load <code>a.rb</code> twice. - * - * require "my-library.rb" - * require "db-driver" - */ - -VALUE -rb_f_require(obj, fname) - VALUE obj, fname; -{ - return rb_require_safe(fname, ruby_safe_level); -} - -static int -search_required(fname, path) - VALUE fname, *path; -{ - VALUE tmp; - char *ext, *ftptr; - int type; - - *path = 0; - ext = strrchr(ftptr = RSTRING(fname)->ptr, '.'); - if (ext && !strchr(ext, '/')) { - if (strcmp(".rb", ext) == 0) { - if (rb_feature_p(ftptr, ext, Qtrue)) return 'r'; - if (tmp = rb_find_file(fname)) { - tmp = rb_file_expand_path(tmp, Qnil); - ext = strrchr(ftptr = RSTRING(tmp)->ptr, '.'); - if (!rb_feature_p(ftptr, ext, Qtrue)) - *path = tmp; - return 'r'; - } - return 0; - } - else if (IS_SOEXT(ext)) { - if (rb_feature_p(ftptr, ext, Qfalse)) return 's'; - tmp = rb_str_new(RSTRING(fname)->ptr, ext-RSTRING(fname)->ptr); -#ifdef DLEXT2 - OBJ_FREEZE(tmp); - if (rb_find_file_ext(&tmp, loadable_ext+1)) { - tmp = rb_file_expand_path(tmp, Qnil); - ext = strrchr(ftptr = RSTRING(tmp)->ptr, '.'); - if (!rb_feature_p(ftptr, ext, Qfalse)) - *path = tmp; - return 's'; - } -#else - rb_str_cat2(tmp, DLEXT); - OBJ_FREEZE(tmp); - if (tmp = rb_find_file(tmp)) { - tmp = rb_file_expand_path(tmp, Qnil); - ext = strrchr(ftptr = RSTRING(tmp)->ptr, '.'); - if (!rb_feature_p(ftptr, ext, Qfalse)) - *path = tmp; - return 's'; - } -#endif - } - else if (IS_DLEXT(ext)) { - if (rb_feature_p(ftptr, ext, Qfalse)) return 's'; - if (tmp = rb_find_file(fname)) { - tmp = rb_file_expand_path(tmp, Qnil); - ext = strrchr(ftptr = RSTRING(tmp)->ptr, '.'); - if (!rb_feature_p(ftptr, ext, Qfalse)) - *path = tmp; - return 's'; - } - } - } - else if (ext = rb_feature_p(ftptr, 0, Qfalse)) { - return (*ext && (IS_SOEXT(ext) || IS_DLEXT(ext))) ? 's' : 'r'; - } - tmp = fname; - type = rb_find_file_ext(&tmp, loadable_ext); - tmp = rb_file_expand_path(tmp, Qnil); - switch (type) { - case 0: - ftptr = RSTRING(tmp)->ptr; - if ((ext = rb_feature_p(ftptr, 0, Qfalse))) { - type = strcmp(".rb", ext); - break; - } - return 0; - - default: - ext = strrchr(ftptr = RSTRING(tmp)->ptr, '.'); - if (rb_feature_p(ftptr, ext, !--type)) break; - *path = tmp; - } - return type ? 's' : 'r'; -} - -static void -load_failed(fname) - VALUE fname; -{ - rb_raise(rb_eLoadError, "no such file to load -- %s", RSTRING(fname)->ptr); -} - -VALUE -rb_require_safe(fname, safe) - VALUE fname; - int safe; -{ - VALUE result = Qnil; - volatile VALUE errinfo = ruby_errinfo; - int state; - struct { - NODE *node; - ID this_func, callee; - int vmode, safe; - } volatile saved; - char *volatile ftptr = 0; - - saved.vmode = scope_vmode; - saved.node = ruby_current_node; - saved.callee = ruby_frame->callee; - saved.this_func = ruby_frame->this_func; - saved.safe = ruby_safe_level; - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - VALUE path; - long handle; - int found; - - ruby_safe_level = safe; - FilePathValue(fname); - *(volatile VALUE *)&fname = rb_str_new4(fname); - found = search_required(fname, &path); - if (found) { - if (!path || load_wait(RSTRING(path)->ptr)) { - result = Qfalse; - } - else { - ruby_safe_level = 0; - switch (found) { - case 'r': - /* loading ruby library should be serialized. */ - if (!loading_tbl) { - loading_tbl = st_init_strtable(); - } - /* partial state */ - ftptr = ruby_strdup(RSTRING(path)->ptr); - st_insert(loading_tbl, (st_data_t)ftptr, (st_data_t)curr_thread); - rb_load(path, 0); - break; - - case 's': - ruby_current_node = 0; - ruby_sourcefile = rb_source_filename(RSTRING(path)->ptr); - ruby_sourceline = 0; - ruby_frame->callee = 0; - ruby_frame->this_func = 0; - SCOPE_SET(SCOPE_PUBLIC); - handle = (long)dln_load(RSTRING(path)->ptr); - rb_ary_push(ruby_dln_librefs, LONG2NUM(handle)); - break; - } - rb_provide_feature(path); - result = Qtrue; - } - } - } - POP_TAG(); - ruby_current_node = saved.node; - ruby_set_current_source(); - ruby_frame->this_func = saved.this_func; - ruby_frame->callee = saved.callee; - SCOPE_SET(saved.vmode); - ruby_safe_level = saved.safe; - if (ftptr) { - if (st_delete(loading_tbl, (st_data_t *)&ftptr, 0)) { /* loading done */ - free(ftptr); - } - } - if (state) JUMP_TAG(state); - if (NIL_P(result)) { - load_failed(fname); - } - ruby_errinfo = errinfo; - - return result; -} - -VALUE -rb_require(fname) - const char *fname; -{ - VALUE fn = rb_str_new2(fname); - OBJ_FREEZE(fn); - return rb_require_safe(fn, ruby_safe_level); -} - -static void -secure_visibility(self) - VALUE self; -{ - if (ruby_safe_level >= 4 && !OBJ_TAINTED(self)) { - rb_raise(rb_eSecurityError, "Insecure: can't change method visibility"); - } -} - -static void -set_method_visibility(self, argc, argv, ex) - VALUE self; - int argc; - VALUE *argv; - ID ex; -{ - int i; - - secure_visibility(self); - for (i=0; i<argc; i++) { - rb_export_method(self, rb_to_id(argv[i]), ex); - } - rb_clear_cache_by_class(self); -} - -/* - * call-seq: - * public => self - * public(symbol, ...) => self - * - * With no arguments, sets the default visibility for subsequently - * defined methods to public. With arguments, sets the named methods to - * have public visibility. - */ - -static VALUE -rb_mod_public(argc, argv, module) - int argc; - VALUE *argv; - VALUE module; -{ - secure_visibility(module); - if (argc == 0) { - SCOPE_SET(SCOPE_PUBLIC); - } - else { - set_method_visibility(module, argc, argv, NOEX_PUBLIC); - } - return module; -} - -/* - * call-seq: - * protected => self - * protected(symbol, ...) => self - * - * With no arguments, sets the default visibility for subsequently - * defined methods to protected. With arguments, sets the named methods - * to have protected visibility. - */ - -static VALUE -rb_mod_protected(argc, argv, module) - int argc; - VALUE *argv; - VALUE module; -{ - secure_visibility(module); - if (argc == 0) { - SCOPE_SET(SCOPE_PROTECTED); - } - else { - set_method_visibility(module, argc, argv, NOEX_PROTECTED); - } - return module; -} - -/* - * call-seq: - * private => self - * private(symbol, ...) => self - * - * With no arguments, sets the default visibility for subsequently - * defined methods to private. With arguments, sets the named methods - * to have private visibility. - * - * module Mod - * def a() end - * def b() end - * private - * def c() end - * private :a - * end - * Mod.private_instance_methods #=> ["a", "c"] - */ - -static VALUE -rb_mod_private(argc, argv, module) - int argc; - VALUE *argv; - VALUE module; -{ - secure_visibility(module); - if (argc == 0) { - SCOPE_SET(SCOPE_PRIVATE); - } - else { - set_method_visibility(module, argc, argv, NOEX_PRIVATE); - } - return module; -} - -/* - * call-seq: - * mod.public_class_method(symbol, ...) => mod - * - * Makes a list of existing class methods public. - */ - -static VALUE -rb_mod_public_method(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PUBLIC); - return obj; -} - -/* - * call-seq: - * mod.private_class_method(symbol, ...) => mod - * - * Makes existing class methods private. Often used to hide the default - * constructor <code>new</code>. - * - * class SimpleSingleton # Not thread safe - * private_class_method :new - * def SimpleSingleton.create(*args, &block) - * @me = new(*args, &block) if ! @me - * @me - * end - * end - */ - -static VALUE -rb_mod_private_method(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PRIVATE); - return obj; -} - -/* - * call-seq: - * public - * public(symbol, ...) - * - * With no arguments, sets the default visibility for subsequently - * defined methods to public. With arguments, sets the named methods to - * have public visibility. - */ - -static VALUE -top_public(argc, argv) - int argc; - VALUE *argv; -{ - return rb_mod_public(argc, argv, rb_cObject); -} - -static VALUE -top_private(argc, argv) - int argc; - VALUE *argv; -{ - return rb_mod_private(argc, argv, rb_cObject); -} - -/* - * call-seq: - * module_function(symbol, ...) => self - * - * Creates module functions for the named methods. These functions may - * be called with the module as a receiver, and also become available - * as instance methods to classes that mix in the module. Module - * functions are copies of the original, and so may be changed - * independently. The instance-method versions are made private. If - * used with no arguments, subsequently defined methods become module - * functions. - * - * module Mod - * def one - * "This is one" - * end - * module_function :one - * end - * class Cls - * include Mod - * def callOne - * one - * end - * end - * Mod.one #=> "This is one" - * c = Cls.new - * c.callOne #=> "This is one" - * module Mod - * def one - * "This is the new one" - * end - * end - * Mod.one #=> "This is one" - * c.callOne #=> "This is the new one" - */ - -static VALUE -rb_mod_modfunc(argc, argv, module) - int argc; - VALUE *argv; - VALUE module; -{ - int i; - ID id; - NODE *body; - - if (TYPE(module) != T_MODULE) { - rb_raise(rb_eTypeError, "module_function must be called for modules"); - } - - secure_visibility(module); - if (argc == 0) { - SCOPE_SET(SCOPE_MODFUNC); - return module; - } - - set_method_visibility(module, argc, argv, NOEX_PRIVATE); - for (i=0; i<argc; i++) { - VALUE m = module; - - id = rb_to_id(argv[i]); - for (;;) { - body = search_method(m, id, &m); - if (body == 0) { - body = search_method(rb_cObject, id, &m); - } - if (body == 0 || body->nd_body == 0) { - rb_bug("undefined method `%s'; can't happen", rb_id2name(id)); - } - if (nd_type(body->nd_body) != NODE_ZSUPER) { - break; /* normal case: need not to follow 'super' link */ - } - m = RCLASS(m)->super; - if (!m) break; - } - rb_add_method(rb_singleton_class(module), id, body->nd_body, NOEX_PUBLIC); - } - return module; -} - -/* - * call-seq: - * append_features(mod) => mod - * - * When this module is included in another, Ruby calls - * <code>append_features</code> in this module, passing it the - * receiving module in _mod_. Ruby's default implementation is - * to add the constants, methods, and module variables of this module - * to _mod_ if this module has not already been added to - * _mod_ or one of its ancestors. See also <code>Module#include</code>. - */ - -static VALUE -rb_mod_append_features(module, include) - VALUE module, include; -{ - switch (TYPE(include)) { - case T_CLASS: - case T_MODULE: - break; - default: - Check_Type(include, T_CLASS); - break; - } - rb_include_module(include, module); - - return module; -} - -/* - * call-seq: - * include(module, ...) => self - * - * Invokes <code>Module.append_features</code> on each parameter in turn. - */ - -static VALUE -rb_mod_include(argc, argv, module) - int argc; - VALUE *argv; - VALUE module; -{ - int i; - - for (i=0; i<argc; i++) Check_Type(argv[i], T_MODULE); - while (argc--) { - rb_funcall(argv[argc], rb_intern("append_features"), 1, module); - rb_funcall(argv[argc], rb_intern("included"), 1, module); - } - return module; -} - -void -rb_obj_call_init(obj, argc, argv) - VALUE obj; - int argc; - VALUE *argv; -{ - PUSH_ITER(rb_block_given_p()?ITER_PRE:ITER_NOT); - rb_funcall2(obj, init, argc, argv); - POP_ITER(); -} - -void -rb_extend_object(obj, module) - VALUE obj, module; -{ - rb_include_module(rb_singleton_class(obj), module); -} - -/* - * call-seq: - * extend_object(obj) => obj - * - * Extends the specified object by adding this module's constants and - * methods (which are added as singleton methods). This is the callback - * method used by <code>Object#extend</code>. - * - * module Picky - * def Picky.extend_object(o) - * if String === o - * puts "Can't add Picky to a String" - * else - * puts "Picky added to #{o.class}" - * super - * end - * end - * end - * (s = Array.new).extend Picky # Call Object.extend - * (s = "quick brown fox").extend Picky - * - * <em>produces:</em> - * - * Picky added to Array - * Can't add Picky to a String - */ - -static VALUE -rb_mod_extend_object(mod, obj) - VALUE mod, obj; -{ - rb_extend_object(obj, mod); - return obj; -} - -/* - * call-seq: - * obj.extend(module, ...) => obj - * - * Adds to _obj_ the instance methods from each module given as a - * parameter. - * - * module Mod - * def hello - * "Hello from Mod.\n" - * end - * end - * - * class Klass - * def hello - * "Hello from Klass.\n" - * end - * end - * - * k = Klass.new - * k.hello #=> "Hello from Klass.\n" - * k.extend(Mod) #=> #<Klass:0x401b3bc8> - * k.hello #=> "Hello from Mod.\n" - */ - -static VALUE -rb_obj_extend(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - int i; - - if (argc == 0) { - rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)"); - } - for (i=0; i<argc; i++) Check_Type(argv[i], T_MODULE); - while (argc--) { - rb_funcall(argv[argc], rb_intern("extend_object"), 1, obj); - rb_funcall(argv[argc], rb_intern("extended"), 1, obj); - } - return obj; -} - -/* - * call-seq: - * include(module, ...) => self - * - * Invokes <code>Module.append_features</code> - * on each parameter in turn. Effectively adds the methods and constants - * in each module to the receiver. - */ - -static VALUE -top_include(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ - rb_secure(4); - if (ruby_wrapper) { - rb_warning("main#include in the wrapped load is effective only in wrapper module"); - return rb_mod_include(argc, argv, ruby_wrapper); - } - return rb_mod_include(argc, argv, rb_cObject); -} - -VALUE rb_f_trace_var(); -VALUE rb_f_untrace_var(); - -static void -errinfo_setter(val, id, var) - VALUE val; - ID id; - VALUE *var; -{ - if (!NIL_P(val) && !rb_obj_is_kind_of(val, rb_eException)) { - rb_raise(rb_eTypeError, "assigning non-exception to $!"); - } - *var = val; -} - -static VALUE -errat_getter(id) - ID id; -{ - return get_backtrace(ruby_errinfo); -} - -static void -errat_setter(val, id, var) - VALUE val; - ID id; - VALUE *var; -{ - if (NIL_P(ruby_errinfo)) { - rb_raise(rb_eArgError, "$! not set"); - } - set_backtrace(ruby_errinfo, val); -} - -/* - * call-seq: - * local_variables => array - * - * Returns the names of the current local variables. - * - * fred = 1 - * for i in 1..10 - * # ... - * end - * local_variables #=> ["fred", "i"] - */ - -static VALUE -rb_f_local_variables() -{ - ID *tbl; - int n, i; - VALUE ary = rb_ary_new(); - struct RVarmap *vars; - - tbl = ruby_scope->local_tbl; - if (tbl) { - n = *tbl++; - for (i=2; i<n; i++) { /* skip first 2 ($_ and $~) */ - if (!rb_is_local_id(tbl[i])) continue; /* skip flip states */ - rb_ary_push(ary, rb_str_new2(rb_id2name(tbl[i]))); - } - } - - vars = ruby_dyna_vars; - while (vars) { - if (vars->id && rb_is_local_id(vars->id)) { /* skip $_, $~ and flip states */ - rb_ary_push(ary, rb_str_new2(rb_id2name(vars->id))); - } - vars = vars->next; - } - - return ary; -} - -static VALUE rb_f_catch _((VALUE,VALUE)); -NORETURN(static VALUE rb_f_throw _((int,VALUE*))); - -struct end_proc_data { - void (*func)(); - VALUE data; - int safe; - struct end_proc_data *next; -}; - -static struct end_proc_data *end_procs, *ephemeral_end_procs, *tmp_end_procs; - -void -rb_set_end_proc(func, data) - void (*func) _((VALUE)); - VALUE data; -{ - struct end_proc_data *link = ALLOC(struct end_proc_data); - struct end_proc_data **list; - - if (ruby_wrapper) list = &ephemeral_end_procs; - else list = &end_procs; - link->next = *list; - link->func = func; - link->data = data; - link->safe = ruby_safe_level; - *list = link; -} - -void -rb_mark_end_proc() -{ - struct end_proc_data *link; - - link = end_procs; - while (link) { - rb_gc_mark(link->data); - link = link->next; - } - link = ephemeral_end_procs; - while (link) { - rb_gc_mark(link->data); - link = link->next; - } - link = tmp_end_procs; - while (link) { - rb_gc_mark(link->data); - link = link->next; - } -} - -static void call_end_proc _((VALUE data)); - -static void -call_end_proc(data) - VALUE data; -{ - PUSH_ITER(ITER_NOT); - PUSH_FRAME(); - ruby_frame->self = ruby_frame->prev->self; - ruby_frame->node = 0; - ruby_frame->callee = 0; - ruby_frame->this_func = 0; - ruby_frame->this_class = 0; - proc_invoke(data, rb_ary_new2(0), Qundef, 0); - POP_FRAME(); - POP_ITER(); -} - -static void -rb_f_END() -{ - PUSH_FRAME(); - ruby_frame->argc = 0; - ruby_frame->iter = ITER_CUR; - rb_set_end_proc(call_end_proc, rb_block_proc()); - POP_FRAME(); -} - -/* - * call-seq: - * at_exit { block } -> proc - * - * Converts _block_ to a +Proc+ object (and therefore - * binds it at the point of call) and registers it for execution when - * the program exits. If multiple handlers are registered, they are - * executed in reverse order of registration. - * - * def do_at_exit(str1) - * at_exit { print str1 } - * end - * at_exit { puts "cruel world" } - * do_at_exit("goodbye ") - * exit - * - * <em>produces:</em> - * - * goodbye cruel world - */ - -static VALUE -rb_f_at_exit() -{ - VALUE proc; - - if (!rb_block_given_p()) { - rb_raise(rb_eArgError, "called without a block"); - } - proc = rb_block_proc(); - rb_set_end_proc(call_end_proc, proc); - return proc; -} - -void -rb_exec_end_proc() -{ - struct end_proc_data *link, *tmp; - int status; - volatile int safe = ruby_safe_level; - - while (ephemeral_end_procs) { - tmp_end_procs = link = ephemeral_end_procs; - ephemeral_end_procs = 0; - while (link) { - PUSH_TAG(PROT_NONE); - if ((status = EXEC_TAG()) == 0) { - ruby_safe_level = link->safe; - (*link->func)(link->data); - } - POP_TAG(); - if (status) { - error_handle(status); - } - tmp = link; - tmp_end_procs = link = link->next; - free(tmp); - } - } - while (end_procs) { - tmp_end_procs = link = end_procs; - end_procs = 0; - while (link) { - PUSH_TAG(PROT_NONE); - if ((status = EXEC_TAG()) == 0) { - ruby_safe_level = link->safe; - (*link->func)(link->data); - } - POP_TAG(); - if (status) { - error_handle(status); - } - tmp = link; - tmp_end_procs = link = link->next; - free(tmp); - } - } - ruby_safe_level = safe; -} - -void -Init_eval() -{ - init = rb_intern("initialize"); - eqq = rb_intern("==="); - each = rb_intern("each"); - - aref = rb_intern("[]"); - aset = rb_intern("[]="); - match = rb_intern("=~"); - missing = rb_intern("method_missing"); - added = rb_intern("method_added"); - singleton_added = rb_intern("singleton_method_added"); - removed = rb_intern("method_removed"); - singleton_removed = rb_intern("singleton_method_removed"); - undefined = rb_intern("method_undefined"); - singleton_undefined = rb_intern("singleton_method_undefined"); - - __id__ = rb_intern("__id__"); - __send__ = rb_intern("__send__"); - - rb_global_variable((VALUE*)&top_scope); - rb_global_variable((VALUE*)&ruby_eval_tree); - rb_global_variable((VALUE*)&ruby_dyna_vars); - - rb_define_virtual_variable("$@", errat_getter, errat_setter); - rb_define_hooked_variable("$!", &ruby_errinfo, 0, errinfo_setter); - - rb_define_global_function("eval", rb_f_eval, -1); - rb_define_global_function("iterator?", rb_f_block_given_p, 0); - rb_define_global_function("block_given?", rb_f_block_given_p, 0); - rb_define_global_function("method_missing", rb_method_missing, -1); - rb_define_global_function("loop", rb_f_loop, 0); - - rb_define_method(rb_mKernel, "respond_to?", rb_obj_respond_to, -1); - respond_to = rb_intern("respond_to?"); - basic_respond_to = rb_method_node(rb_cObject, respond_to); - rb_global_variable((VALUE*)&basic_respond_to); - - rb_define_global_function("raise", rb_f_raise, -1); - rb_define_global_function("fail", rb_f_raise, -1); - - rb_define_global_function("caller", rb_f_caller, -1); - - rb_define_global_function("exit", rb_f_exit, -1); - rb_define_global_function("abort", rb_f_abort, -1); - - rb_define_global_function("at_exit", rb_f_at_exit, 0); - - rb_define_global_function("catch", rb_f_catch, 1); - rb_define_global_function("throw", rb_f_throw, -1); - rb_define_global_function("global_variables", rb_f_global_variables, 0); /* in variable.c */ - rb_define_global_function("local_variables", rb_f_local_variables, 0); - - rb_define_method(rb_mKernel, "send", rb_f_send, -1); - rb_define_method(rb_mKernel, "__send__", rb_f_send, -1); - rb_define_method(rb_mKernel, "instance_eval", rb_obj_instance_eval, -1); - - rb_define_private_method(rb_cModule, "append_features", rb_mod_append_features, 1); - rb_define_private_method(rb_cModule, "extend_object", rb_mod_extend_object, 1); - rb_define_private_method(rb_cModule, "include", rb_mod_include, -1); - rb_define_private_method(rb_cModule, "public", rb_mod_public, -1); - rb_define_private_method(rb_cModule, "protected", rb_mod_protected, -1); - rb_define_private_method(rb_cModule, "private", rb_mod_private, -1); - rb_define_private_method(rb_cModule, "module_function", rb_mod_modfunc, -1); - rb_define_method(rb_cModule, "method_defined?", rb_mod_method_defined, 1); - rb_define_method(rb_cModule, "public_method_defined?", rb_mod_public_method_defined, 1); - rb_define_method(rb_cModule, "private_method_defined?", rb_mod_private_method_defined, 1); - rb_define_method(rb_cModule, "protected_method_defined?", rb_mod_protected_method_defined, 1); - rb_define_method(rb_cModule, "public_class_method", rb_mod_public_method, -1); - rb_define_method(rb_cModule, "private_class_method", rb_mod_private_method, -1); - rb_define_method(rb_cModule, "module_eval", rb_mod_module_eval, -1); - rb_define_method(rb_cModule, "class_eval", rb_mod_module_eval, -1); - - rb_undef_method(rb_cClass, "module_function"); - - rb_define_private_method(rb_cModule, "remove_method", rb_mod_remove_method, -1); - rb_define_private_method(rb_cModule, "undef_method", rb_mod_undef_method, -1); - rb_define_private_method(rb_cModule, "alias_method", rb_mod_alias_method, 2); - rb_define_private_method(rb_cModule, "define_method", rb_mod_define_method, -1); - - rb_define_singleton_method(rb_cModule, "nesting", rb_mod_nesting, 0); - rb_define_singleton_method(rb_cModule, "constants", rb_mod_s_constants, 0); - - rb_define_singleton_method(ruby_top_self, "include", top_include, -1); - rb_define_singleton_method(ruby_top_self, "public", top_public, -1); - rb_define_singleton_method(ruby_top_self, "private", top_private, -1); - - rb_define_method(rb_mKernel, "extend", rb_obj_extend, -1); - - rb_define_global_function("trace_var", rb_f_trace_var, -1); /* in variable.c */ - rb_define_global_function("untrace_var", rb_f_untrace_var, -1); /* in variable.c */ - - rb_define_global_function("set_trace_func", set_trace_func, 1); - rb_global_variable(&trace_func); - - rb_define_virtual_variable("$SAFE", safe_getter, safe_setter); -} - -/* - * call-seq: - * mod.autoload(name, filename) => nil - * - * Registers _filename_ to be loaded (using <code>Kernel::require</code>) - * the first time that _module_ (which may be a <code>String</code> or - * a symbol) is accessed in the namespace of _mod_. - * - * module A - * end - * A.autoload(:B, "b") - * A::B.doit # autoloads "b" - */ - -static VALUE -rb_mod_autoload(mod, sym, file) - VALUE mod; - VALUE sym; - VALUE file; -{ - ID id = rb_to_id(sym); - - Check_SafeStr(file); - rb_autoload(mod, id, RSTRING(file)->ptr); - return Qnil; -} - -/* - * MISSING: documentation - */ - -static VALUE -rb_mod_autoload_p(mod, sym) - VALUE mod, sym; -{ - return rb_autoload_p(mod, rb_to_id(sym)); -} - -/* - * call-seq: - * autoload(module, filename) => nil - * - * Registers _filename_ to be loaded (using <code>Kernel::require</code>) - * the first time that _module_ (which may be a <code>String</code> or - * a symbol) is accessed. - * - * autoload(:MyModule, "/usr/local/lib/modules/my_module.rb") - */ - -static VALUE -rb_f_autoload(obj, sym, file) - VALUE obj; - VALUE sym; - VALUE file; -{ - return rb_mod_autoload(ruby_cbase, sym, file); -} - - -/* - * MISSING: documentation - */ - -static VALUE -rb_f_autoload_p(obj, sym) - VALUE obj; - VALUE sym; -{ - /* use ruby_cbase as same as rb_f_autoload. */ - return rb_mod_autoload_p(ruby_cbase, sym); -} - -void -Init_load() -{ - rb_load_path = rb_ary_new(); - rb_define_readonly_variable("$:", &rb_load_path); - rb_define_readonly_variable("$-I", &rb_load_path); - rb_define_readonly_variable("$LOAD_PATH", &rb_load_path); - - rb_features = rb_ary_new(); - rb_define_readonly_variable("$\"", &rb_features); - rb_define_readonly_variable("$LOADED_FEATURES", &rb_features); - - rb_define_global_function("load", rb_f_load, -1); - rb_define_global_function("require", rb_f_require, 1); - rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2); - rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, 1); - rb_define_global_function("autoload", rb_f_autoload, 2); - rb_define_global_function("autoload?", rb_f_autoload_p, 1); - rb_global_variable(&ruby_wrapper); - - ruby_dln_librefs = rb_ary_new(); - rb_global_variable(&ruby_dln_librefs); -} - -static void -scope_dup(scope) - struct SCOPE *scope; -{ - volatile ID *tbl; - VALUE *vars; - - scope->flags |= SCOPE_DONT_RECYCLE; - if (scope->flags & SCOPE_MALLOC) return; - - if (scope->local_tbl) { - tbl = scope->local_tbl; - vars = ALLOC_N(VALUE, tbl[0]+1); - *vars++ = scope->local_vars[-1]; - MEMCPY(vars, scope->local_vars, VALUE, tbl[0]); - scope->local_vars = vars; - scope->flags |= SCOPE_MALLOC; - } -} - -static void -blk_mark(data) - struct BLOCK *data; -{ - while (data) { - rb_gc_mark_frame(&data->frame); - rb_gc_mark((VALUE)data->scope); - rb_gc_mark((VALUE)data->var); - rb_gc_mark((VALUE)data->body); - rb_gc_mark((VALUE)data->self); - rb_gc_mark((VALUE)data->dyna_vars); - rb_gc_mark((VALUE)data->cref); - rb_gc_mark(data->wrapper); - rb_gc_mark(data->block_obj); - data = data->prev; - } -} - -static void -frame_free(frame) - struct FRAME *frame; -{ - struct FRAME *tmp; - - frame = frame->prev; - while (frame) { - tmp = frame; - frame = frame->prev; - free(tmp); - } -} - -static void -blk_free(data) - struct BLOCK *data; -{ - void *tmp; - - while (data) { - frame_free(&data->frame); - tmp = data; - data = data->prev; - free(tmp); - } -} - -static void -frame_dup(frame) - struct FRAME *frame; -{ - struct FRAME *tmp; - - for (;;) { - frame->tmp = 0; /* should not preserve tmp */ - if (!frame->prev) break; - tmp = ALLOC(struct FRAME); - *tmp = *frame->prev; - frame->prev = tmp; - frame = tmp; - } -} - -static void -blk_copy_prev(block) - struct BLOCK *block; -{ - struct BLOCK *tmp; - struct RVarmap* vars; - - while (block->prev) { - tmp = ALLOC_N(struct BLOCK, 1); - MEMCPY(tmp, block->prev, struct BLOCK, 1); - scope_dup(tmp->scope); - frame_dup(&tmp->frame); - - for (vars = tmp->dyna_vars; vars; vars = vars->next) { - if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; - FL_SET(vars, DVAR_DONT_RECYCLE); - } - - block->prev = tmp; - block = tmp; - } -} - - -static void -blk_dup(dup, orig) - struct BLOCK *dup, *orig; -{ - MEMCPY(dup, orig, struct BLOCK, 1); - frame_dup(&dup->frame); - - if (dup->iter) { - blk_copy_prev(dup); - } - else { - dup->prev = 0; - } -} - -/* - * MISSING: documentation - */ - -static VALUE -proc_clone(self) - VALUE self; -{ - struct BLOCK *orig, *data; - VALUE bind; - - Data_Get_Struct(self, struct BLOCK, orig); - bind = Data_Make_Struct(rb_obj_class(self),struct BLOCK,blk_mark,blk_free,data); - CLONESETUP(bind, self); - blk_dup(data, orig); - - return bind; -} - -/* - * MISSING: documentation - */ - -static VALUE -proc_dup(self) - VALUE self; -{ - struct BLOCK *orig, *data; - VALUE bind; - - Data_Get_Struct(self, struct BLOCK, orig); - bind = Data_Make_Struct(rb_obj_class(self),struct BLOCK,blk_mark,blk_free,data); - blk_dup(data, orig); - - return bind; -} - -/* - * call-seq: - * binding -> a_binding - * - * Returns a +Binding+ object, describing the variable and - * method bindings at the point of call. This object can be used when - * calling +eval+ to execute the evaluated command in this - * environment. Also see the description of class +Binding+. - * - * def getBinding(param) - * return binding - * end - * b = getBinding("hello") - * eval("param", b) #=> "hello" - */ - -static VALUE -rb_f_binding(self) - VALUE self; -{ - struct BLOCK *data, *p; - struct RVarmap *vars; - VALUE bind; - - PUSH_BLOCK(0,0); - bind = Data_Make_Struct(rb_cBinding,struct BLOCK,blk_mark,blk_free,data); - *data = *ruby_block; - - data->orig_thread = rb_thread_current(); - data->wrapper = ruby_wrapper; - data->iter = rb_f_block_given_p(); - frame_dup(&data->frame); - if (ruby_frame->prev) { - data->frame.callee = ruby_frame->prev->callee; - data->frame.this_func = ruby_frame->prev->this_func; - data->frame.this_class = ruby_frame->prev->this_class; - } - - if (data->iter) { - blk_copy_prev(data); - } - else { - data->prev = 0; - } - - for (p = data; p; p = p->prev) { - for (vars = p->dyna_vars; vars; vars = vars->next) { - if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; - FL_SET(vars, DVAR_DONT_RECYCLE); - } - } - scope_dup(data->scope); - POP_BLOCK(); - - return bind; -} - -/* - * call-seq: - * binding.eval(string [, filename [,lineno]]) => obj - * - * Evaluates the Ruby expression(s) in <em>string</em>, in the - * <em>binding</em>'s context. If the optional <em>filename</em> and - * <em>lineno</em> parameters are present, they will be used when - * reporting syntax errors. - * - * def getBinding(param) - * return binding - * end - * b = getBinding("hello") - * b.eval("param") #=> "hello" - */ - -static VALUE -bind_eval(argc, argv, bind) - int argc; - VALUE *argv; - VALUE bind; -{ - struct BLOCK *data; - VALUE args[4]; - - rb_scan_args(argc, argv, "12", &args[0], &args[2], &args[3]); - args[1] = bind; - Data_Get_Struct(bind, struct BLOCK, data); - - return rb_f_eval(argc+1, args, data->self); -} - -#define PROC_TSHIFT (FL_USHIFT+1) -#define PROC_TMASK (FL_USER1|FL_USER2|FL_USER3) -#define PROC_TMAX (PROC_TMASK >> PROC_TSHIFT) -#define PROC_NOSAFE FL_USER4 - -#define SAFE_LEVEL_MAX PROC_TMASK - -#define proc_safe_level_p(data) (!(RBASIC(data)->flags & PROC_NOSAFE)) - -static void -proc_save_safe_level(data) - VALUE data; -{ - int safe = ruby_safe_level; - if (safe > PROC_TMAX) safe = PROC_TMAX; - FL_SET(data, (safe << PROC_TSHIFT) & PROC_TMASK); -} - -static int -proc_get_safe_level(data) - VALUE data; -{ - return (RBASIC(data)->flags & PROC_TMASK) >> PROC_TSHIFT; -} - -static void -proc_set_safe_level(data) - VALUE data; -{ - if (!proc_safe_level_p(data)) return; - ruby_safe_level = proc_get_safe_level(data); -} - -static VALUE -proc_alloc(klass, proc) - VALUE klass; - int proc; -{ - volatile VALUE block; - struct BLOCK *data, *p; - struct RVarmap *vars; - - if (!rb_block_given_p() && !rb_f_block_given_p()) { - rb_raise(rb_eArgError, "tried to create Proc object without a block"); - } - if (proc && !rb_block_given_p()) { - rb_warn("tried to create Proc object without a block"); - } - - if (!proc && ruby_block->block_obj) { - VALUE obj = ruby_block->block_obj; - if (CLASS_OF(obj) != klass) { - obj = proc_clone(obj); - RBASIC(obj)->klass = klass; - } - return obj; - } - block = Data_Make_Struct(klass, struct BLOCK, blk_mark, blk_free, data); - *data = *ruby_block; - - data->orig_thread = rb_thread_current(); - data->wrapper = ruby_wrapper; - data->iter = data->prev?Qtrue:Qfalse; - data->block_obj = block; - frame_dup(&data->frame); - if (data->iter) { - blk_copy_prev(data); - } - else { - data->prev = 0; - } - - for (p = data; p; p = p->prev) { - for (vars = p->dyna_vars; vars; vars = vars->next) { - if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; - FL_SET(vars, DVAR_DONT_RECYCLE); - } - } - scope_dup(data->scope); - proc_save_safe_level(block); - if (proc) { - data->flags |= BLOCK_LAMBDA; - } - else { - ruby_block->block_obj = block; - } - - return block; -} - -/* - * call-seq: - * Proc.new {|...| block } => a_proc - * Proc.new => a_proc - * - * Creates a new <code>Proc</code> object, bound to the current - * context. <code>Proc::new</code> may be called without a block only - * within a method with an attached block, in which case that block is - * converted to the <code>Proc</code> object. - * - * def proc_from - * Proc.new - * end - * proc = proc_from { "hello" } - * proc.call #=> "hello" - */ - -static VALUE -proc_s_new(argc, argv, klass) - int argc; - VALUE *argv; - VALUE klass; -{ - VALUE block = proc_alloc(klass, Qfalse); - - rb_obj_call_init(block, argc, argv); - return block; -} - -/* - * call-seq: - * proc { |...| block } => a_proc - * - * Equivalent to <code>Proc.new</code>. - */ - -VALUE -rb_block_proc() -{ - return proc_alloc(rb_cProc, Qfalse); -} - -VALUE -rb_f_lambda() -{ - rb_warn("rb_f_lambda() is deprecated; use rb_block_proc() instead"); - return proc_alloc(rb_cProc, Qtrue); -} - -/* - * call-seq: - * lambda { |...| block } => a_proc - * - * Equivalent to <code>Proc.new</code>, except the resulting Proc objects - * check the number of parameters passed when called. - */ - -static VALUE -proc_lambda() -{ - return proc_alloc(rb_cProc, Qtrue); -} - -static int -block_orphan(data) - struct BLOCK *data; -{ - if (data->scope->flags & SCOPE_NOSTACK) { - return 1; - } - if (data->orig_thread != rb_thread_current()) { - return 1; - } - return 0; -} - -static VALUE -proc_invoke(proc, args, self, klass) - VALUE proc, args; /* OK */ - VALUE self, klass; -{ - struct BLOCK * volatile old_block; - struct BLOCK _block; - struct BLOCK *data; - volatile VALUE result = Qundef; - int state; - volatile int safe = ruby_safe_level; - volatile VALUE old_wrapper = ruby_wrapper; - volatile int pcall, avalue = Qtrue; - VALUE bvar = Qnil, tmp = args; - - Data_Get_Struct(proc, struct BLOCK, data); - pcall = (data->flags & BLOCK_LAMBDA) ? YIELD_LAMBDA_CALL : 0; - if (!pcall && RARRAY(args)->len == 1) { - avalue = Qfalse; - args = RARRAY(args)->ptr[0]; - } - if (rb_block_given_p() && ruby_frame->callee) { - if (klass != ruby_frame->this_class) - klass = rb_obj_class(proc); - bvar = rb_block_proc(); - } - - PUSH_VARS(); - ruby_wrapper = data->wrapper; - ruby_dyna_vars = data->dyna_vars; - /* PUSH BLOCK from data */ - old_block = ruby_block; - _block = *data; - _block.block_obj = bvar; - if (self != Qundef) _block.frame.self = self; - if (klass) _block.frame.this_class = klass; - _block.frame.argc = RARRAY(tmp)->len; - if (_block.frame.argc && (ruby_frame->flags & FRAME_DMETH)) { - NEWOBJ(scope, struct SCOPE); - OBJSETUP(scope, tmp, T_SCOPE); - scope->local_tbl = _block.scope->local_tbl; - scope->local_vars = _block.scope->local_vars; - _block.scope = scope; - } - ruby_block = &_block; - - PUSH_ITER(ITER_CUR); - ruby_frame->iter = ITER_CUR; - PUSH_TAG((pcall&YIELD_LAMBDA_CALL) ? PROT_LAMBDA : PROT_NONE); - state = EXEC_TAG(); - if (state == 0) { - proc_set_safe_level(proc); - result = rb_yield_0(args, self, (self!=Qundef)?CLASS_OF(self):0, - pcall | YIELD_PROC_CALL, avalue); - } - else if (TAG_DST()) { - result = prot_tag->retval; - } - POP_TAG(); - POP_ITER(); - ruby_block = old_block; - ruby_wrapper = old_wrapper; - POP_VARS(); - if (proc_safe_level_p(proc)) ruby_safe_level = safe; - - switch (state) { - case 0: - break; - case TAG_RETRY: - proc_jump_error(TAG_RETRY, Qnil); /* xxx */ - JUMP_TAG(state); - break; - case TAG_BREAK: - if (!pcall && result != Qundef) { - proc_jump_error(state, result); - } - case TAG_RETURN: - if (result != Qundef) { - if (pcall) break; - return_jump(result); - } - default: - JUMP_TAG(state); - } - return result; -} - -/* CHECKME: are the argument checking semantics correct? */ - -/* - * call-seq: - * prc.call(params,...) => obj - * prc[params,...] => obj - * - * Invokes the block, setting the block's parameters to the values in - * <i>params</i> using something close to method calling semantics. - * Generates a warning if multiple values are passed to a proc that - * expects just one (previously this silently converted the parameters - * to an array). - * - * For procs created using <code>Kernel.proc</code>, generates an - * error if the wrong number of parameters - * are passed to a proc with multiple parameters. For procs created using - * <code>Proc.new</code>, extra parameters are silently discarded. - * - * Returns the value of the last expression evaluated in the block. See - * also <code>Proc#yield</code>. - * - * a_proc = Proc.new {|a, *b| b.collect {|i| i*a }} - * a_proc.call(9, 1, 2, 3) #=> [9, 18, 27] - * a_proc[9, 1, 2, 3] #=> [9, 18, 27] - * a_proc = Proc.new {|a,b| a} - * a_proc.call(1,2,3) - * - * <em>produces:</em> - * - * prog.rb:5: wrong number of arguments (3 for 2) (ArgumentError) - * from prog.rb:4:in `call' - * from prog.rb:5 - */ - -static VALUE -proc_call(proc, args) - VALUE proc, args; /* OK */ -{ - return proc_invoke(proc, args, Qundef, 0); -} - -int -rb_proc_arity(proc) - VALUE proc; -{ - struct BLOCK *data; - NODE *var, *list; - int n; - - Data_Get_Struct(proc, struct BLOCK, data); - var = data->var; - if (var == 0) { - if (data->body && nd_type(data->body) == NODE_IFUNC && - data->body->nd_cfnc == bmcall) { - return method_arity(data->body->nd_tval); - } - return 0; - } - if (var == (NODE*)1) return 0; - if (var == (NODE*)2) return 0; - if (nd_type(var) == NODE_BLOCK_ARG) { - var = var->nd_args; - if (var == (NODE*)1) return 0; - if (var == (NODE*)2) return 0; - } - switch (nd_type(var)) { - default: - return 1; - case NODE_MASGN: - list = var->nd_head; - n = 0; - while (list) { - n++; - list = list->nd_next; - } - if (var->nd_args) return -n-1; - return n; - } -} - -/* - * call-seq: - * prc.arity -> fixnum - * - * Returns the number of arguments that would not be ignored. If the block - * is declared to take no arguments, returns 0. If the block is known - * to take exactly n arguments, returns n. If the block has optional - * arguments, return -n-1, where n is the number of mandatory - * arguments. A <code>proc</code> with no argument declarations - * is the same a block declaring <code>||</code> as its arguments. - * - * Proc.new {}.arity #=> 0 - * Proc.new {||}.arity #=> 0 - * Proc.new {|a|}.arity #=> 1 - * Proc.new {|a,b|}.arity #=> 2 - * Proc.new {|a,b,c|}.arity #=> 3 - * Proc.new {|*a|}.arity #=> -1 - * Proc.new {|a,*b|}.arity #=> -2 - */ - -static VALUE -proc_arity(proc) - VALUE proc; -{ - int arity = rb_proc_arity(proc); - return INT2FIX(arity); -} - -/* - * call-seq: - * prc == other_proc => true or false - * - * Return <code>true</code> if <i>prc</i> is the same object as - * <i>other_proc</i>, or if they are both procs with the same body. - */ - -static VALUE -proc_eq(self, other) - VALUE self, other; -{ - struct BLOCK *data, *data2; - - if (self == other) return Qtrue; - if (TYPE(other) != T_DATA) return Qfalse; - if (RDATA(other)->dmark != (RUBY_DATA_FUNC)blk_mark) return Qfalse; - if (CLASS_OF(self) != CLASS_OF(other)) return Qfalse; - Data_Get_Struct(self, struct BLOCK, data); - Data_Get_Struct(other, struct BLOCK, data2); - if (data->body != data2->body) return Qfalse; - if (data->var != data2->var) return Qfalse; - if (data->scope != data2->scope) return Qfalse; - if (data->dyna_vars != data2->dyna_vars) return Qfalse; - if (data->flags != data2->flags) return Qfalse; - - return Qtrue; -} - -/* - * call-seq: - * prc.hash => integer - * - * Return hash value corresponding to proc body. - */ - -static VALUE -proc_hash(self) - VALUE self; -{ - struct BLOCK *data; - long hash; - - Data_Get_Struct(self, struct BLOCK, data); - hash = (long)data->body; - hash ^= (long)data->var; - hash ^= data->frame.uniq << 16; - hash ^= data->flags; - - return INT2FIX(hash); -} - -/* - * call-seq: - * prc.to_s => string - * - * Shows the unique identifier for this proc, along with - * an indication of where the proc was defined. - */ - -static VALUE -proc_to_s(self) - VALUE self; -{ - struct BLOCK *data; - NODE *node; - char *cname = rb_obj_classname(self); - const int w = (SIZEOF_LONG * CHAR_BIT) / 4; - long len = strlen(cname)+6+w; /* 6:tags 16:addr */ - VALUE str; - - Data_Get_Struct(self, struct BLOCK, data); - if ((node = data->frame.node) || (node = data->body)) { - len += strlen(node->nd_file) + 2 + (SIZEOF_LONG*CHAR_BIT-NODE_LSHIFT)/3; - str = rb_str_new(0, len); - sprintf(RSTRING(str)->ptr, "#<%s:0x%.*lx@%s:%d>", cname, w, (VALUE)data->body, - node->nd_file, nd_line(node)); - } - else { - str = rb_str_new(0, len); - sprintf(RSTRING(str)->ptr, "#<%s:0x%.*lx>", cname, w, (VALUE)data->body); - } - RSTRING(str)->len = strlen(RSTRING(str)->ptr); - if (OBJ_TAINTED(self)) OBJ_TAINT(str); - - return str; -} - -/* - * call-seq: - * prc.to_proc -> prc - * - * Part of the protocol for converting objects to <code>Proc</code> - * objects. Instances of class <code>Proc</code> simply return - * themselves. - */ - -static VALUE -proc_to_self(self) - VALUE self; -{ - return self; -} - -/* - * call-seq: - * prc.binding => binding - * - * Returns the binding associated with <i>prc</i>. Note that - * <code>Kernel#eval</code> accepts either a <code>Proc</code> or a - * <code>Binding</code> object as its second parameter. - * - * def fred(param) - * proc {} - * end - * - * b = fred(99) - * eval("param", b.binding) #=> 99 - * eval("param", b) #=> 99 - */ - -static VALUE -proc_binding(proc) - VALUE proc; -{ - struct BLOCK *orig, *data; - VALUE bind; - - Data_Get_Struct(proc, struct BLOCK, orig); - bind = Data_Make_Struct(rb_cBinding,struct BLOCK,blk_mark,blk_free,data); - MEMCPY(data, orig, struct BLOCK, 1); - frame_dup(&data->frame); - - if (data->iter) { - blk_copy_prev(data); - } - else { - data->prev = 0; - } - - return bind; -} - -static VALUE -rb_block_pass(func, arg, proc) - VALUE (*func) _((VALUE)); - VALUE arg; - VALUE proc; -{ - VALUE b; - struct BLOCK * volatile old_block; - struct BLOCK _block; - struct BLOCK *data; - volatile VALUE result = Qnil; - int state; - volatile int orphan; - volatile int safe = ruby_safe_level; - - if (NIL_P(proc)) { - PUSH_ITER(ITER_NOT); - result = (*func)(arg); - POP_ITER(); - return result; - } - if (!rb_obj_is_proc(proc)) { - b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"); - if (!rb_obj_is_proc(b)) { - rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc)", - rb_obj_classname(proc)); - } - proc = b; - } - - if (ruby_safe_level >= 1 && OBJ_TAINTED(proc)) { - if (ruby_safe_level > proc_get_safe_level(proc)) { - rb_raise(rb_eSecurityError, "Insecure: tainted block value"); - } - } - - if (ruby_block && ruby_block->block_obj == proc) { - PUSH_ITER(ITER_PRE); - result = (*func)(arg); - POP_ITER(); - return result; - } - - Data_Get_Struct(proc, struct BLOCK, data); - orphan = block_orphan(data); - - /* PUSH BLOCK from data */ - _block = *data; - _block.outer = ruby_block; - if (orphan) _block.uniq = block_unique++; - ruby_block = &_block; - PUSH_ITER(ITER_PRE); - if (ruby_frame->iter == ITER_NOT) - ruby_frame->iter = ITER_PRE; - - PUSH_TAG(PROT_LOOP); - state = EXEC_TAG(); - if (state == 0) { - retry: - proc_set_safe_level(proc); - if (safe > ruby_safe_level) - ruby_safe_level = safe; - result = (*func)(arg); - } - else if (state == TAG_BREAK && TAG_DST()) { - result = prot_tag->retval; - state = 0; - } - else if (state == TAG_RETRY) { - state = 0; - goto retry; - } - POP_TAG(); - POP_ITER(); - ruby_block = _block.outer; - if (proc_safe_level_p(proc)) ruby_safe_level = safe; - - switch (state) {/* escape from orphan block */ - case 0: - break; - case TAG_RETURN: - if (orphan) { - proc_jump_error(state, prot_tag->retval); - } - default: - JUMP_TAG(state); - } - - return result; -} - -struct block_arg { - VALUE self; - NODE *iter; -}; - -static VALUE -call_block(arg) - struct block_arg *arg; -{ - return rb_eval(arg->self, arg->iter); -} - -static VALUE -block_pass(self, node) - VALUE self; - NODE *node; -{ - struct block_arg arg; - arg.self = self; - arg.iter = node->nd_iter; - return rb_block_pass((VALUE (*)_((VALUE)))call_block, - (VALUE)&arg, rb_eval(self, node->nd_body)); -} - -struct METHOD { - VALUE klass, rklass; - VALUE recv; - ID id, oid; - NODE *body; -}; - -static void -bm_mark(data) - struct METHOD *data; -{ - rb_gc_mark(data->rklass); - rb_gc_mark(data->klass); - rb_gc_mark(data->recv); - rb_gc_mark((VALUE)data->body); -} - -static VALUE -mnew(klass, obj, id, mklass) - VALUE klass, obj, mklass; - ID id; -{ - VALUE method; - NODE *body; - int noex; - struct METHOD *data; - VALUE rklass = klass; - ID oid = id; - - again: - if ((body = rb_get_method_body(&klass, &id, &noex)) == 0) { - print_undef(rklass, oid); - } - - if (nd_type(body) == NODE_ZSUPER) { - klass = RCLASS(klass)->super; - goto again; - } - - while (rklass != klass && - (FL_TEST(rklass, FL_SINGLETON) || TYPE(rklass) == T_ICLASS)) { - rklass = RCLASS(rklass)->super; - } - if (TYPE(klass) == T_ICLASS) klass = RBASIC(klass)->klass; - method = Data_Make_Struct(mklass, struct METHOD, bm_mark, -1, data); - data->klass = klass; - data->recv = obj; - data->id = id; - data->body = body; - data->rklass = rklass; - data->oid = oid; - OBJ_INFECT(method, klass); - - return method; -} - - -/********************************************************************** - * - * Document-class : Method - * - * Method objects are created by <code>Object#method</code>, and are - * associated with a particular object (not just with a class). They - * may be used to invoke the method within the object, and as a block - * associated with an iterator. They may also be unbound from one - * object (creating an <code>UnboundMethod</code>) and bound to - * another. - * - * class Thing - * def square(n) - * n*n - * end - * end - * thing = Thing.new - * meth = thing.method(:square) - * - * meth.call(9) #=> 81 - * [ 1, 2, 3 ].collect(&meth) #=> [1, 4, 9] - * - */ - -/* - * call-seq: - * meth == other_meth => true or false - * - * Two method objects are equal if that are bound to the same - * object and contain the same body. - */ - - -static VALUE -method_eq(method, other) - VALUE method, other; -{ - struct METHOD *m1, *m2; - - if (TYPE(other) != T_DATA || RDATA(other)->dmark != (RUBY_DATA_FUNC)bm_mark) - return Qfalse; - if (CLASS_OF(method) != CLASS_OF(other)) - return Qfalse; - - Data_Get_Struct(method, struct METHOD, m1); - Data_Get_Struct(other, struct METHOD, m2); - - if (m1->klass != m2->klass || m1->rklass != m2->rklass || - m1->recv != m2->recv || m1->body != m2->body) - return Qfalse; - - return Qtrue; -} - -/* - * call-seq: - * meth.hash => integer - * - * Return a hash value corresponding to the method object. - */ - -static VALUE -method_hash(method) - VALUE method; -{ - struct METHOD *m; - long hash; - - Data_Get_Struct(method, struct METHOD, m); - hash = (long)m->klass; - hash ^= (long)m->rklass; - hash ^= (long)m->recv; - hash ^= (long)m->body; - - return INT2FIX(hash); -} - -/* - * call-seq: - * meth.unbind => unbound_method - * - * Dissociates <i>meth</i> from it's current receiver. The resulting - * <code>UnboundMethod</code> can subsequently be bound to a new object - * of the same class (see <code>UnboundMethod</code>). - */ - -static VALUE -method_unbind(obj) - VALUE obj; -{ - VALUE method; - struct METHOD *orig, *data; - - Data_Get_Struct(obj, struct METHOD, orig); - method = Data_Make_Struct(rb_cUnboundMethod, struct METHOD, bm_mark, free, data); - data->klass = orig->klass; - data->recv = Qundef; - data->id = orig->id; - data->body = orig->body; - data->rklass = orig->rklass; - data->oid = orig->oid; - OBJ_INFECT(method, obj); - - return method; -} - -/* - * call-seq: - * obj.method(sym) => method - * - * Looks up the named method as a receiver in <i>obj</i>, returning a - * <code>Method</code> object (or raising <code>NameError</code>). The - * <code>Method</code> object acts as a closure in <i>obj</i>'s object - * instance, so instance variables and the value of <code>self</code> - * remain available. - * - * class Demo - * def initialize(n) - * @iv = n - * end - * def hello() - * "Hello, @iv = #{@iv}" - * end - * end - * - * k = Demo.new(99) - * m = k.method(:hello) - * m.call #=> "Hello, @iv = 99" - * - * l = Demo.new('Fred') - * m = l.method("hello") - * m.call #=> "Hello, @iv = Fred" - */ - -static VALUE -rb_obj_method(obj, vid) - VALUE obj; - VALUE vid; -{ - return mnew(CLASS_OF(obj), obj, rb_to_id(vid), rb_cMethod); -} - -/* - * call-seq: - * mod.instance_method(symbol) => unbound_method - * - * Returns an +UnboundMethod+ representing the given - * instance method in _mod_. - * - * class Interpreter - * def do_a() print "there, "; end - * def do_d() print "Hello "; end - * def do_e() print "!\n"; end - * def do_v() print "Dave"; end - * Dispatcher = { - * ?a => instance_method(:do_a), - * ?d => instance_method(:do_d), - * ?e => instance_method(:do_e), - * ?v => instance_method(:do_v) - * } - * def interpret(string) - * string.each_byte {|b| Dispatcher[b].bind(self).call } - * end - * end - * - * - * interpreter = Interpreter.new - * interpreter.interpret('dave') - * - * <em>produces:</em> - * - * Hello there, Dave! - */ - -static VALUE -rb_mod_method(mod, vid) - VALUE mod; - VALUE vid; -{ - return mnew(mod, Qundef, rb_to_id(vid), rb_cUnboundMethod); -} - -/* - * MISSING: documentation - */ - -static VALUE -method_clone(self) - VALUE self; -{ - VALUE clone; - struct METHOD *orig, *data; - - Data_Get_Struct(self, struct METHOD, orig); - clone = Data_Make_Struct(CLASS_OF(self),struct METHOD, bm_mark, free, data); - CLONESETUP(clone, self); - *data = *orig; - - return clone; -} - -/* - * call-seq: - * meth.call(args, ...) => obj - * meth[args, ...] => obj - * - * Invokes the <i>meth</i> with the specified arguments, returning the - * method's return value. - * - * m = 12.method("+") - * m.call(3) #=> 15 - * m.call(20) #=> 32 - */ - -static VALUE -method_call(argc, argv, method) - int argc; - VALUE *argv; - VALUE method; -{ - VALUE result = Qnil; /* OK */ - struct METHOD *data; - int state; - volatile int safe = -1; - - Data_Get_Struct(method, struct METHOD, data); - if (data->recv == Qundef) { - rb_raise(rb_eTypeError, "can't call unbound method; bind first"); - } - PUSH_ITER(rb_block_given_p()?ITER_PRE:ITER_NOT); - PUSH_TAG(PROT_NONE); - if (OBJ_TAINTED(method)) { - safe = ruby_safe_level; - if (ruby_safe_level < 4) ruby_safe_level = 4; - } - if ((state = EXEC_TAG()) == 0) { - result = rb_call0(data->klass,data->recv,data->id,data->oid,argc,argv,data->body,0); - } - POP_TAG(); - POP_ITER(); - if (safe >= 0) ruby_safe_level = safe; - if (state) JUMP_TAG(state); - return result; -} - -/********************************************************************** - * - * Document-class: UnboundMethod - * - * Ruby supports two forms of objectified methods. Class - * <code>Method</code> is used to represent methods that are associated - * with a particular object: these method objects are bound to that - * object. Bound method objects for an object can be created using - * <code>Object#method</code>. - * - * Ruby also supports unbound methods; methods objects that are not - * associated with a particular object. These can be created either by - * calling <code>Module#instance_method</code> or by calling - * <code>unbind</code> on a bound method object. The result of both of - * these is an <code>UnboundMethod</code> object. - * - * Unbound methods can only be called after they are bound to an - * object. That object must be be a kind_of? the method's original - * class. - * - * class Square - * def area - * @side * @side - * end - * def initialize(side) - * @side = side - * end - * end - * - * area_un = Square.instance_method(:area) - * - * s = Square.new(12) - * area = area_un.bind(s) - * area.call #=> 144 - * - * Unbound methods are a reference to the method at the time it was - * objectified: subsequent changes to the underlying class will not - * affect the unbound method. - * - * class Test - * def test - * :original - * end - * end - * um = Test.instance_method(:test) - * class Test - * def test - * :modified - * end - * end - * t = Test.new - * t.test #=> :modified - * um.bind(t).call #=> :original - * - */ - -/* - * call-seq: - * umeth.bind(obj) -> method - * - * Bind <i>umeth</i> to <i>obj</i>. If <code>Klass</code> was the class - * from which <i>umeth</i> was obtained, - * <code>obj.kind_of?(Klass)</code> must be true. - * - * class A - * def test - * puts "In test, class = #{self.class}" - * end - * end - * class B < A - * end - * class C < B - * end - * - * - * um = B.instance_method(:test) - * bm = um.bind(C.new) - * bm.call - * bm = um.bind(B.new) - * bm.call - * bm = um.bind(A.new) - * bm.call - * - * <em>produces:</em> - * - * In test, class = C - * In test, class = B - * prog.rb:16:in `bind': bind argument must be an instance of B (TypeError) - * from prog.rb:16 - */ - -static VALUE -umethod_bind(method, recv) - VALUE method, recv; -{ - struct METHOD *data, *bound; - - Data_Get_Struct(method, struct METHOD, data); - if (data->rklass != CLASS_OF(recv)) { - if (FL_TEST(data->rklass, FL_SINGLETON)) { - rb_raise(rb_eTypeError, "singleton method called for a different object"); - } - if(!rb_obj_is_kind_of(recv, data->rklass)) { - rb_raise(rb_eTypeError, "bind argument must be an instance of %s", - rb_class2name(data->rklass)); - } - } - - method = Data_Make_Struct(rb_cMethod,struct METHOD,bm_mark,free,bound); - *bound = *data; - bound->recv = recv; - bound->rklass = CLASS_OF(recv); - - return method; -} - -int -rb_node_arity(body) - NODE *body; -{ - int n; - - switch (nd_type(body)) { - case NODE_CFUNC: - if (body->nd_argc < 0) return -1; - return body->nd_argc; - case NODE_ZSUPER: - return -1; - case NODE_ATTRSET: - return 1; - case NODE_IVAR: - return 0; - case NODE_BMETHOD: - return rb_proc_arity(body->nd_cval); - case NODE_SCOPE: - body = body->nd_next; /* skip NODE_SCOPE */ - if (nd_type(body) == NODE_BLOCK) - body = body->nd_head; - if (!body) return 0; - n = body->nd_cnt; - if (body->nd_opt || body->nd_rest != -1) - n = -n-1; - return n; - default: - rb_raise(rb_eArgError, "invalid node 0x%x", nd_type(body)); - } -} - -/* - * call-seq: - * meth.arity => fixnum - * - * Returns an indication of the number of arguments accepted by a - * method. Returns a nonnegative integer for methods that take a fixed - * number of arguments. For Ruby methods that take a variable number of - * arguments, returns -n-1, where n is the number of required - * arguments. For methods written in C, returns -1 if the call takes a - * variable number of arguments. - * - * class C - * def one; end - * def two(a); end - * def three(*a); end - * def four(a, b); end - * def five(a, b, *c); end - * def six(a, b, *c, &d); end - * end - * c = C.new - * c.method(:one).arity #=> 0 - * c.method(:two).arity #=> 1 - * c.method(:three).arity #=> -1 - * c.method(:four).arity #=> 2 - * c.method(:five).arity #=> -3 - * c.method(:six).arity #=> -3 - * - * "cat".method(:size).arity #=> 0 - * "cat".method(:replace).arity #=> 1 - * "cat".method(:squeeze).arity #=> -1 - * "cat".method(:count).arity #=> -1 - */ - -static VALUE -method_arity_m(method) - VALUE method; -{ - int n = method_arity(method); - return INT2FIX(n); -} - -static int -method_arity(method) - VALUE method; -{ - struct METHOD *data; - - Data_Get_Struct(method, struct METHOD, data); - return rb_node_arity(data->body); -} - -int -rb_mod_method_arity(mod, id) - VALUE mod; - ID id; -{ - NODE *node = rb_method_node(mod, id); - return rb_node_arity(node); -} - -int -rb_obj_method_arity(obj, id) - VALUE obj; - ID id; -{ - return rb_mod_method_arity(CLASS_OF(obj), id); -} - -/* - * call-seq: - * meth.to_s => string - * meth.inspect => string - * - * Show the name of the underlying method. - * - * "cat".method(:count).inspect #=> "#<Method: String#count>" - */ - -static VALUE -method_inspect(method) - VALUE method; -{ - struct METHOD *data; - VALUE str; - const char *s; - char *sharp = "#"; - - Data_Get_Struct(method, struct METHOD, data); - str = rb_str_buf_new2("#<"); - s = rb_obj_classname(method); - rb_str_buf_cat2(str, s); - rb_str_buf_cat2(str, ": "); - - if (FL_TEST(data->klass, FL_SINGLETON)) { - VALUE v = rb_iv_get(data->klass, "__attached__"); - - if (data->recv == Qundef) { - rb_str_buf_append(str, rb_inspect(data->klass)); - } - else if (data->recv == v) { - rb_str_buf_append(str, rb_inspect(v)); - sharp = "."; - } - else { - rb_str_buf_append(str, rb_inspect(data->recv)); - rb_str_buf_cat2(str, "("); - rb_str_buf_append(str, rb_inspect(v)); - rb_str_buf_cat2(str, ")"); - sharp = "."; - } - } - else { - rb_str_buf_cat2(str, rb_class2name(data->rklass)); - if (data->rklass != data->klass) { - rb_str_buf_cat2(str, "("); - rb_str_buf_cat2(str, rb_class2name(data->klass)); - rb_str_buf_cat2(str, ")"); - } - } - rb_str_buf_cat2(str, sharp); - rb_str_buf_cat2(str, rb_id2name(data->oid)); - rb_str_buf_cat2(str, ">"); - - return str; -} - -static VALUE -mproc(method) - VALUE method; -{ - VALUE proc; - - /* emulate ruby's method call */ - PUSH_ITER(ITER_CUR); - PUSH_FRAME(); - proc = rb_block_proc(); - POP_FRAME(); - POP_ITER(); - - return proc; -} - -static VALUE -bmcall(args, method) - VALUE args, method; -{ - volatile VALUE a; - - a = svalue_to_avalue(args); - return method_call(RARRAY(a)->len, RARRAY(a)->ptr, method); -} - -VALUE -rb_proc_new(func, val) - VALUE (*func)(ANYARGS); /* VALUE yieldarg[, VALUE procarg] */ - VALUE val; -{ - struct BLOCK *data; - VALUE proc = rb_iterate((VALUE(*)_((VALUE)))mproc, 0, func, val); - - Data_Get_Struct(proc, struct BLOCK, data); - data->body->nd_state = YIELD_FUNC_AVALUE; - return proc; -} - -/* - * call-seq: - * meth.to_proc => prc - * - * Returns a <code>Proc</code> object corresponding to this method. - */ - -static VALUE -method_proc(method) - VALUE method; -{ - VALUE proc; - struct METHOD *mdata; - struct BLOCK *bdata; - - Data_Get_Struct(method, struct METHOD, mdata); - if (nd_type(mdata->body) == NODE_BMETHOD) { - return mdata->body->nd_cval; - } - proc = rb_iterate((VALUE(*)_((VALUE)))mproc, 0, bmcall, method); - Data_Get_Struct(proc, struct BLOCK, bdata); - bdata->body->nd_file = mdata->body->nd_file; - nd_set_line(bdata->body, nd_line(mdata->body)); - bdata->body->nd_state = YIELD_FUNC_SVALUE; - bdata->flags |= BLOCK_FROM_METHOD; - - return proc; -} - -static VALUE -rb_obj_is_method(m) - VALUE m; -{ - if (TYPE(m) == T_DATA && RDATA(m)->dmark == (RUBY_DATA_FUNC)bm_mark) { - return Qtrue; - } - return Qfalse; -} - -/* - * call-seq: - * define_method(symbol, method) => new_method - * define_method(symbol) { block } => proc - * - * Defines an instance method in the receiver. The _method_ - * parameter can be a +Proc+ or +Method+ object. - * If a block is specified, it is used as the method body. This block - * is evaluated using <code>instance_eval</code>, a point that is - * tricky to demonstrate because <code>define_method</code> is private. - * (This is why we resort to the +send+ hack in this example.) - * - * class A - * def fred - * puts "In Fred" - * end - * def create_method(name, &block) - * self.class.send(:define_method, name, &block) - * end - * define_method(:wilma) { puts "Charge it!" } - * end - * class B < A - * define_method(:barney, instance_method(:fred)) - * end - * a = B.new - * a.barney - * a.wilma - * a.create_method(:betty) { p self } - * a.betty - * - * <em>produces:</em> - * - * In Fred - * Charge it! - * #<B:0x401b39e8> - */ - -static VALUE -rb_mod_define_method(argc, argv, mod) - int argc; - VALUE *argv; - VALUE mod; -{ - ID id; - VALUE body; - NODE *node; - int noex; - - if (argc == 1) { - id = rb_to_id(argv[0]); - body = proc_lambda(); - } - else if (argc == 2) { - id = rb_to_id(argv[0]); - body = argv[1]; - if (!rb_obj_is_method(body) && !rb_obj_is_proc(body)) { - rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc/Method)", - rb_obj_classname(body)); - } - } - else { - rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc); - } - if (RDATA(body)->dmark == (RUBY_DATA_FUNC)bm_mark) { - struct METHOD *method = (struct METHOD *)DATA_PTR(body); - VALUE rklass = method->rklass; - if (rklass != mod) { - if (FL_TEST(rklass, FL_SINGLETON)) { - rb_raise(rb_eTypeError, "can't bind singleton method to a different class"); - } - if (!RTEST(rb_class_inherited_p(mod, rklass))) { - rb_raise(rb_eTypeError, "bind argument must be a subclass of %s", - rb_class2name(rklass)); - } - } - node = method->body; - } - else if (RDATA(body)->dmark == (RUBY_DATA_FUNC)blk_mark) { - struct BLOCK *block; - - body = proc_clone(body); - RBASIC(body)->flags |= PROC_NOSAFE; - Data_Get_Struct(body, struct BLOCK, block); - block->frame.callee = id; - block->frame.this_func = id; - block->frame.this_class = mod; - node = NEW_BMETHOD(body); - } - else { - /* type error */ - rb_raise(rb_eTypeError, "wrong argument type (expected Proc/Method)"); - } - - if (SCOPE_TEST(SCOPE_PRIVATE)) { - noex = NOEX_PRIVATE; - } - else if (SCOPE_TEST(SCOPE_PROTECTED)) { - noex = NOEX_PROTECTED; - } - else { - noex = NOEX_PUBLIC; - } - rb_add_method(mod, id, node, noex); - return body; -} - -/* - * <code>Proc</code> objects are blocks of code that have been bound to - * a set of local variables. Once bound, the code may be called in - * different contexts and still access those variables. - * - * def gen_times(factor) - * return Proc.new {|n| n*factor } - * end - * - * times3 = gen_times(3) - * times5 = gen_times(5) - * - * times3.call(12) #=> 36 - * times5.call(5) #=> 25 - * times3.call(times5.call(4)) #=> 60 - * - */ - -void -Init_Proc() -{ - rb_eLocalJumpError = rb_define_class("LocalJumpError", rb_eStandardError); - rb_define_method(rb_eLocalJumpError, "exit_value", localjump_xvalue, 0); - rb_define_method(rb_eLocalJumpError, "reason", localjump_reason, 0); - - exception_error = rb_exc_new2(rb_eFatal, "exception reentered"); - rb_global_variable(&exception_error); - - rb_eSysStackError = rb_define_class("SystemStackError", rb_eException); - sysstack_error = rb_exc_new2(rb_eSysStackError, "stack level too deep"); - OBJ_TAINT(sysstack_error); - rb_global_variable(&sysstack_error); - - rb_cProc = rb_define_class("Proc", rb_cObject); - rb_undef_alloc_func(rb_cProc); - rb_define_singleton_method(rb_cProc, "new", proc_s_new, -1); - - rb_define_method(rb_cProc, "clone", proc_clone, 0); - rb_define_method(rb_cProc, "dup", proc_dup, 0); - rb_define_method(rb_cProc, "call", proc_call, -2); - rb_define_method(rb_cProc, "arity", proc_arity, 0); - rb_define_method(rb_cProc, "[]", proc_call, -2); - rb_define_method(rb_cProc, "==", proc_eq, 1); - rb_define_method(rb_cProc, "eql?", proc_eq, 1); - rb_define_method(rb_cProc, "hash", proc_hash, 0); - rb_define_method(rb_cProc, "to_s", proc_to_s, 0); - rb_define_method(rb_cProc, "to_proc", proc_to_self, 0); - rb_define_method(rb_cProc, "binding", proc_binding, 0); - - rb_define_global_function("proc", rb_block_proc, 0); - rb_define_global_function("lambda", proc_lambda, 0); - - rb_cMethod = rb_define_class("Method", rb_cObject); - rb_undef_alloc_func(rb_cMethod); - rb_undef_method(CLASS_OF(rb_cMethod), "new"); - rb_define_method(rb_cMethod, "==", method_eq, 1); - rb_define_method(rb_cMethod, "eql?", method_eq, 1); - rb_define_method(rb_cMethod, "hash", method_hash, 0); - rb_define_method(rb_cMethod, "clone", method_clone, 0); - rb_define_method(rb_cMethod, "call", method_call, -1); - rb_define_method(rb_cMethod, "[]", method_call, -1); - rb_define_method(rb_cMethod, "arity", method_arity_m, 0); - rb_define_method(rb_cMethod, "inspect", method_inspect, 0); - rb_define_method(rb_cMethod, "to_s", method_inspect, 0); - rb_define_method(rb_cMethod, "to_proc", method_proc, 0); - rb_define_method(rb_cMethod, "unbind", method_unbind, 0); - rb_define_method(rb_mKernel, "method", rb_obj_method, 1); - - rb_cUnboundMethod = rb_define_class("UnboundMethod", rb_cObject); - rb_undef_alloc_func(rb_cUnboundMethod); - rb_undef_method(CLASS_OF(rb_cUnboundMethod), "new"); - rb_define_method(rb_cUnboundMethod, "==", method_eq, 1); - rb_define_method(rb_cUnboundMethod, "eql?", method_eq, 1); - rb_define_method(rb_cUnboundMethod, "hash", method_hash, 0); - rb_define_method(rb_cUnboundMethod, "clone", method_clone, 0); - rb_define_method(rb_cUnboundMethod, "arity", method_arity_m, 0); - rb_define_method(rb_cUnboundMethod, "inspect", method_inspect, 0); - rb_define_method(rb_cUnboundMethod, "to_s", method_inspect, 0); - rb_define_method(rb_cUnboundMethod, "bind", umethod_bind, 1); - rb_define_method(rb_cModule, "instance_method", rb_mod_method, 1); -} - -/* - * Objects of class <code>Binding</code> encapsulate the execution - * context at some particular place in the code and retain this context - * for future use. The variables, methods, value of <code>self</code>, - * and possibly an iterator block that can be accessed in this context - * are all retained. Binding objects can be created using - * <code>Kernel#binding</code>, and are made available to the callback - * of <code>Kernel#set_trace_func</code>. - * - * These binding objects can be passed as the second argument of the - * <code>Kernel#eval</code> method, establishing an environment for the - * evaluation. - * - * class Demo - * def initialize(n) - * @secret = n - * end - * def getBinding - * return binding() - * end - * end - * - * k1 = Demo.new(99) - * b1 = k1.getBinding - * k2 = Demo.new(-3) - * b2 = k2.getBinding - * - * eval("@secret", b1) #=> 99 - * eval("@secret", b2) #=> -3 - * eval("@secret") #=> nil - * - * Binding objects have no class-specific methods. - * - */ - -void -Init_Binding() -{ - rb_cBinding = rb_define_class("Binding", rb_cObject); - rb_undef_alloc_func(rb_cBinding); - rb_undef_method(CLASS_OF(rb_cBinding), "new"); - rb_define_method(rb_cBinding, "clone", proc_clone, 0); - rb_define_method(rb_cBinding, "eval", bind_eval, -1); - rb_define_global_function("binding", rb_f_binding, 0); -} - -#ifdef __ia64__ -#if defined(__FreeBSD__) -/* - * FreeBSD/ia64 currently does not have a way for a process to get the - * base address for the RSE backing store, so hardcode it. - */ -#define __libc_ia64_register_backing_store_base (4ULL<<61) -#else -#ifdef HAVE_UNWIND_H -#include <unwind.h> -#else -#pragma weak __libc_ia64_register_backing_store_base -extern unsigned long __libc_ia64_register_backing_store_base; -#endif -#endif -#endif - -/* Windows SEH refers data on the stack. */ -#undef SAVE_WIN32_EXCEPTION_LIST -#if defined _WIN32 || defined __CYGWIN__ -#if defined __CYGWIN__ -typedef unsigned long DWORD; -#endif - -static inline DWORD -win32_get_exception_list() -{ - DWORD p; -# if defined _MSC_VER -# ifdef _M_IX86 -# define SAVE_WIN32_EXCEPTION_LIST -# if _MSC_VER >= 1310 - /* warning: unsafe assignment to fs:0 ... this is ok */ -# pragma warning(disable: 4733) -# endif - __asm mov eax, fs:[0]; - __asm mov p, eax; -# endif -# elif defined __GNUC__ -# ifdef __i386__ -# define SAVE_WIN32_EXCEPTION_LIST - __asm__("movl %%fs:0,%0" : "=r"(p)); -# endif -# elif defined __BORLANDC__ -# define SAVE_WIN32_EXCEPTION_LIST - __emit__(0x64, 0xA1, 0, 0, 0, 0); /* mov eax, fs:[0] */ - p = _EAX; -# endif - return p; -} - -static inline void -win32_set_exception_list(p) - DWORD p; -{ -# if defined _MSC_VER -# ifdef _M_IX86 - __asm mov eax, p; - __asm mov fs:[0], eax; -# endif -# elif defined __GNUC__ -# ifdef __i386__ - __asm__("movl %0,%%fs:0" :: "r"(p)); -# endif -# elif defined __BORLANDC__ - _EAX = p; - __emit__(0x64, 0xA3, 0, 0, 0, 0); /* mov fs:[0], eax */ -# endif -} - -#if !defined SAVE_WIN32_EXCEPTION_LIST && !defined _WIN32_WCE -# error unsupported platform -#endif -#endif - -int rb_thread_pending = 0; - -VALUE rb_cThread; - -extern VALUE rb_last_status; - -enum thread_status { - THREAD_TO_KILL, - THREAD_RUNNABLE, - THREAD_STOPPED, - THREAD_KILLED, -}; - -#define WAIT_FD (1<<0) -#define WAIT_SELECT (1<<1) -#define WAIT_TIME (1<<2) -#define WAIT_JOIN (1<<3) -#define WAIT_PID (1<<4) - -/* +infty, for this purpose */ -#define DELAY_INFTY 1E30 - -#if !defined HAVE_PAUSE -# if defined _WIN32 && !defined __CYGWIN__ -# define pause() Sleep(INFINITE) -# else -# define pause() sleep(0x7fffffff) -# endif -#endif - -/* typedef struct thread * rb_thread_t; */ - -struct thread { - struct thread *next, *prev; - rb_jmpbuf_t context; -#ifdef SAVE_WIN32_EXCEPTION_LIST - DWORD win32_exception_list; -#endif - - VALUE result; - - long stk_len; - long stk_max; - VALUE *stk_ptr; - VALUE *stk_pos; -#ifdef __ia64__ - VALUE *bstr_ptr; - long bstr_len; -#endif - - struct FRAME *frame; - struct SCOPE *scope; - struct RVarmap *dyna_vars; - struct BLOCK *block; - struct iter *iter; - struct tag *tag; - VALUE klass; - VALUE wrapper; - NODE *cref; - struct ruby_env *anchor; - - int flags; /* misc. states (vmode/rb_trap_immediate/raised) */ - - NODE *node; - - int tracing; - VALUE errinfo; - VALUE last_status; - VALUE last_line; - VALUE last_match; - - int safe; - - enum thread_status status; - int wait_for; - int fd; - fd_set readfds; - fd_set writefds; - fd_set exceptfds; - int select_value; - double delay; - rb_thread_t join; - - int abort; - int priority; - VALUE thgroup; - - st_table *locals; - - VALUE thread; -}; - -#define THREAD_RAISED 0x200 /* temporary flag */ -#define THREAD_TERMINATING 0x400 /* persistent flag */ -#define THREAD_FLAGS_MASK 0x400 /* mask for persistent flags */ - -#define FOREACH_THREAD_FROM(f,x) x = f; do { x = x->next; -#define END_FOREACH_FROM(f,x) } while (x != f) - -#define FOREACH_THREAD(x) FOREACH_THREAD_FROM(curr_thread,x) -#define END_FOREACH(x) END_FOREACH_FROM(curr_thread,x) - -struct thread_status_t { - NODE *node; - - int tracing; - VALUE errinfo; - VALUE last_status; - VALUE last_line; - VALUE last_match; - - int safe; - - enum thread_status status; - int wait_for; - int fd; - fd_set readfds; - fd_set writefds; - fd_set exceptfds; - int select_value; - double delay; - rb_thread_t join; -}; - -#define THREAD_COPY_STATUS(src, dst) (void)( \ - (dst)->node = (src)->node, \ - \ - (dst)->tracing = (src)->tracing, \ - (dst)->errinfo = (src)->errinfo, \ - (dst)->last_status = (src)->last_status, \ - (dst)->last_line = (src)->last_line, \ - (dst)->last_match = (src)->last_match, \ - \ - (dst)->safe = (src)->safe, \ - \ - (dst)->status = (src)->status, \ - (dst)->wait_for = (src)->wait_for, \ - (dst)->fd = (src)->fd, \ - (dst)->readfds = (src)->readfds, \ - (dst)->writefds = (src)->writefds, \ - (dst)->exceptfds = (src)->exceptfds, \ - (dst)->select_value = (src)->select_value, \ - (dst)->delay = (src)->delay, \ - (dst)->join = (src)->join, \ - 0) - -static int -thread_set_raised() -{ - if (curr_thread->flags & THREAD_RAISED) return 1; - curr_thread->flags |= THREAD_RAISED; - return 0; -} - -static int -thread_reset_raised() -{ - if (!(curr_thread->flags & THREAD_RAISED)) return 0; - curr_thread->flags &= ~THREAD_RAISED; - return 1; -} - -static void rb_thread_ready _((rb_thread_t)); - -static VALUE run_trap_eval _((VALUE)); -static VALUE -run_trap_eval(arg) - VALUE arg; -{ - VALUE *p = (VALUE *)arg; - return rb_eval_cmd(p[0], p[1], (int)p[2]); -} - -static VALUE -rb_trap_eval(cmd, sig, safe) - VALUE cmd; - int sig, safe; -{ - int state; - VALUE val = Qnil; /* OK */ - volatile struct thread_status_t save; - VALUE arg[3]; - - arg[0] = cmd; - arg[1] = rb_ary_new3(1, INT2FIX(sig)); - arg[2] = (VALUE)safe; - THREAD_COPY_STATUS(curr_thread, &save); - rb_thread_ready(curr_thread); - PUSH_ITER(ITER_NOT); - val = rb_protect(run_trap_eval, (VALUE)&arg, &state); - POP_ITER(); - THREAD_COPY_STATUS(&save, curr_thread); - - if (state) { - rb_trap_immediate = 0; - JUMP_TAG(state); - } - - if (curr_thread->status == THREAD_STOPPED) { - rb_thread_schedule(); - } - errno = EINTR; - - return val; -} - -static const char * -thread_status_name(status) - enum thread_status status; -{ - switch (status) { - case THREAD_RUNNABLE: - return "run"; - case THREAD_STOPPED: - return "sleep"; - case THREAD_TO_KILL: - return "aborting"; - case THREAD_KILLED: - return "dead"; - default: - return "unknown"; - } -} - -/* $SAFE accessor */ -void -rb_set_safe_level(level) - int level; -{ - if (level > ruby_safe_level) { - if (level > SAFE_LEVEL_MAX) level = SAFE_LEVEL_MAX; - ruby_safe_level = level; - curr_thread->safe = level; - } -} - -static VALUE -safe_getter() -{ - return INT2NUM(ruby_safe_level); -} - -static void -safe_setter(val) - VALUE val; -{ - int level = NUM2INT(val); - - if (level < ruby_safe_level) { - rb_raise(rb_eSecurityError, "tried to downgrade safe level from %d to %d", - ruby_safe_level, level); - } - if (level > SAFE_LEVEL_MAX) level = SAFE_LEVEL_MAX; - ruby_safe_level = level; - curr_thread->safe = level; -} - -/* Return the current time as a floating-point number */ -static double -timeofday() -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6; -} - -#define STACK(addr) (th->stk_pos<(VALUE*)(addr) && (VALUE*)(addr)<th->stk_pos+th->stk_len) -#define ADJ(addr) (void*)(STACK(addr)?(((VALUE*)(addr)-th->stk_pos)+th->stk_ptr):(VALUE*)(addr)) - -static void -thread_mark(th) - rb_thread_t th; -{ - struct FRAME *frame; - struct BLOCK *block; - - rb_gc_mark(th->result); - rb_gc_mark(th->thread); - if (th->join) rb_gc_mark(th->join->thread); - - rb_gc_mark(th->klass); - rb_gc_mark(th->wrapper); - rb_gc_mark((VALUE)th->cref); - - rb_gc_mark((VALUE)th->scope); - rb_gc_mark((VALUE)th->dyna_vars); - rb_gc_mark(th->errinfo); - rb_gc_mark(th->last_line); - rb_gc_mark(th->last_match); - rb_mark_tbl(th->locals); - rb_gc_mark(th->thgroup); - - /* mark data in copied stack */ - if (th == curr_thread) return; - if (th->status == THREAD_KILLED) return; - if (th->stk_len == 0) return; /* stack not active, no need to mark. */ - if (th->stk_ptr) { - rb_gc_mark_locations(th->stk_ptr, th->stk_ptr+th->stk_len); -#if defined(THINK_C) || defined(__human68k__) - rb_gc_mark_locations(th->stk_ptr+2, th->stk_ptr+th->stk_len+2); -#endif -#ifdef __ia64__ - if (th->bstr_ptr) { - rb_gc_mark_locations(th->bstr_ptr, th->bstr_ptr+th->bstr_len); - } -#endif - } - frame = th->frame; - while (frame && frame != top_frame) { - frame = ADJ(frame); - rb_gc_mark_frame(frame); - if (frame->tmp) { - struct FRAME *tmp = frame->tmp; - - while (tmp && tmp != top_frame) { - tmp = ADJ(tmp); - rb_gc_mark_frame(tmp); - tmp = tmp->prev; - } - } - frame = frame->prev; - } - block = th->block; - while (block) { - block = ADJ(block); - rb_gc_mark_frame(&block->frame); - block = block->prev; - } -} - -static struct { - rb_thread_t thread; - VALUE proc, arg; -} new_thread; - -void -rb_gc_mark_threads() -{ - rb_thread_t th; - - /* static global mark */ - rb_gc_mark((VALUE)ruby_cref); - - if (!curr_thread) return; - FOREACH_THREAD(th) { - rb_gc_mark(th->thread); - } END_FOREACH(th); - if (new_thread.thread) { - rb_gc_mark(new_thread.thread->thread); - rb_gc_mark(new_thread.proc); - rb_gc_mark(new_thread.arg); - } -} - -static void -thread_free(th) - rb_thread_t th; -{ - if (th->stk_ptr) free(th->stk_ptr); - th->stk_ptr = 0; -#ifdef __ia64__ - if (th->bstr_ptr) free(th->bstr_ptr); - th->bstr_ptr = 0; -#endif - if (th->locals) st_free_table(th->locals); - if (th->status != THREAD_KILLED) { - if (th->prev) th->prev->next = th->next; - if (th->next) th->next->prev = th->prev; - } - if (th != main_thread) free(th); -} - -static rb_thread_t -rb_thread_check(data) - VALUE data; -{ - if (TYPE(data) != T_DATA || RDATA(data)->dmark != (RUBY_DATA_FUNC)thread_mark) { - rb_raise(rb_eTypeError, "wrong argument type %s (expected Thread)", - rb_obj_classname(data)); - } - return (rb_thread_t)RDATA(data)->data; -} - -static VALUE rb_thread_raise _((int, VALUE*, rb_thread_t)); - -static VALUE th_raise_exception; -static NODE *th_raise_node; -static VALUE th_cmd; -static int th_sig, th_safe; -static char *th_signm; - -#define RESTORE_NORMAL 1 -#define RESTORE_FATAL 2 -#define RESTORE_INTERRUPT 3 -#define RESTORE_TRAP 4 -#define RESTORE_RAISE 5 -#define RESTORE_SIGNAL 6 -#define RESTORE_EXIT 7 - -extern VALUE *rb_gc_stack_start; - -static void -rb_thread_save_context(th) - rb_thread_t th; -{ - VALUE *pos; - int len; - static VALUE tval; - - len = ruby_stack_length(&pos); - th->stk_len = 0; - th->stk_pos = pos; - if (len > th->stk_max) { - REALLOC_N(th->stk_ptr, VALUE, len); - th->stk_max = len; - } - th->stk_len = len; - FLUSH_REGISTER_WINDOWS; - MEMCPY(th->stk_ptr, th->stk_pos, VALUE, th->stk_len); -#ifdef __ia64__ - { - VALUE *top, *bot; -#ifdef HAVE_UNWIND_H - _Unwind_Context *unwctx = _UNW_createContextForSelf(); - - _UNW_currentContext(unwctx); - bot = (VALUE*)(long)_UNW_getAR(unwctx, _UNW_AR_BSP); - top = (VALUE*)(long)_UNW_getAR(unwctx, _UNW_AR_BSPSTORE); - _UNW_destroyContext(unwctx); -#else - ucontext_t ctx; - - getcontext(&ctx); - bot = (VALUE*)__libc_ia64_register_backing_store_base; - top = (VALUE*)ctx.uc_mcontext.IA64_BSPSTORE; -#endif - th->bstr_len = top - bot; - REALLOC_N(th->bstr_ptr, VALUE, th->bstr_len); - MEMCPY(th->bstr_ptr, bot, VALUE, th->bstr_len); - } -#endif -#ifdef SAVE_WIN32_EXCEPTION_LIST - th->win32_exception_list = win32_get_exception_list(); -#endif - - th->frame = ruby_frame; - th->scope = ruby_scope; - th->klass = ruby_class; - th->wrapper = ruby_wrapper; - th->cref = ruby_cref; - th->dyna_vars = ruby_dyna_vars; - th->block = ruby_block; - th->flags &= THREAD_FLAGS_MASK; - th->flags |= (rb_trap_immediate<<8) | scope_vmode; - th->iter = ruby_iter; - th->tag = prot_tag; - th->tracing = tracing; - th->errinfo = ruby_errinfo; - th->last_status = rb_last_status; - tval = rb_lastline_get(); - rb_lastline_set(th->last_line); - th->last_line = tval; - tval = rb_backref_get(); - rb_backref_set(th->last_match); - th->last_match = tval; - th->safe = ruby_safe_level; - - th->node = ruby_current_node; -} - -static int -rb_thread_switch(n) - int n; -{ - rb_trap_immediate = (curr_thread->flags&(1<<8))?1:0; - switch (n) { - case 0: - return 0; - case RESTORE_FATAL: - JUMP_TAG(TAG_FATAL); - break; - case RESTORE_INTERRUPT: - rb_interrupt(); - break; - case RESTORE_TRAP: - rb_trap_eval(th_cmd, th_sig, th_safe); - break; - case RESTORE_RAISE: - ruby_frame->callee = 0; - ruby_frame->this_func = 0; - ruby_current_node = th_raise_node; - rb_raise_jump(th_raise_exception); - break; - case RESTORE_SIGNAL: - rb_raise(rb_eSignal, "SIG%s", th_signm); - break; - case RESTORE_EXIT: - ruby_errinfo = th_raise_exception; - ruby_current_node = th_raise_node; - error_print(); - terminate_process(EXIT_FAILURE, 0, 0); - break; - case RESTORE_NORMAL: - default: - break; - } - return 1; -} - -#define THREAD_SAVE_CONTEXT(th) \ - (rb_thread_save_context(th),\ - rb_thread_switch((FLUSH_REGISTER_WINDOWS, setjmp((th)->context)))) - -NORETURN(static void rb_thread_restore_context _((rb_thread_t,int))); -NOINLINE(static void stack_extend _((rb_thread_t, int))); - -static void -stack_extend(th, exit) - rb_thread_t th; - int exit; -{ - VALUE space[1024]; - - memset(space, 0, 1); /* prevent array from optimization */ - rb_thread_restore_context(th, exit); -} - -static void -rb_thread_restore_context(th, exit) - rb_thread_t th; - int exit; -{ - VALUE v; - static rb_thread_t tmp; - static int ex; - static VALUE tval; - - if (!th->stk_ptr) rb_bug("unsaved context"); - -#if STACK_GROW_DIRECTION < 0 - if (&v > th->stk_pos) stack_extend(th, exit); -#elif STACK_GROW_DIRECTION > 0 - if (&v < th->stk_pos + th->stk_len) stack_extend(th, exit); -#else - if (&v < rb_gc_stack_start) { - /* Stack grows downward */ - if (&v > th->stk_pos) stack_extend(th, exit); - } - else { - /* Stack grows upward */ - if (&v < th->stk_pos + th->stk_len) stack_extend(th, exit); - } -#endif - - rb_trap_immediate = 0; /* inhibit interrupts from here */ - ruby_frame = th->frame; - ruby_scope = th->scope; - ruby_class = th->klass; - ruby_wrapper = th->wrapper; - ruby_cref = th->cref; - ruby_dyna_vars = th->dyna_vars; - ruby_block = th->block; - scope_vmode = th->flags&SCOPE_MASK; - ruby_iter = th->iter; - prot_tag = th->tag; - tracing = th->tracing; - ruby_errinfo = th->errinfo; - rb_last_status = th->last_status; - ruby_safe_level = th->safe; - - ruby_current_node = th->node; - -#ifdef SAVE_WIN32_EXCEPTION_LIST - win32_set_exception_list(th->win32_exception_list); -#endif - tmp = th; - ex = exit; - FLUSH_REGISTER_WINDOWS; - MEMCPY(tmp->stk_pos, tmp->stk_ptr, VALUE, tmp->stk_len); -#ifdef __ia64__ - { - VALUE *base; -#ifdef HAVE_UNWIND_H - _Unwind_Context *unwctx = _UNW_createContextForSelf(); - - _UNW_currentContext(unwctx); - base = (VALUE*)(long)_UNW_getAR(unwctx, _UNW_AR_BSP); - _UNW_destroyContext(unwctx); -#else - base = (VALUE*)__libc_ia64_register_backing_store_base; -#endif - MEMCPY(base, tmp->bstr_ptr, VALUE, tmp->bstr_len); - } -#endif - - tval = rb_lastline_get(); - rb_lastline_set(tmp->last_line); - tmp->last_line = tval; - tval = rb_backref_get(); - rb_backref_set(tmp->last_match); - tmp->last_match = tval; - - longjmp(tmp->context, ex); -} - -static void -rb_thread_ready(th) - rb_thread_t th; -{ - th->wait_for = 0; - if (th->status != THREAD_TO_KILL) { - th->status = THREAD_RUNNABLE; - } -} - -static void -rb_thread_die(th) - rb_thread_t th; -{ - th->thgroup = 0; - th->status = THREAD_KILLED; - if (th->stk_ptr) free(th->stk_ptr); - th->stk_ptr = 0; -} - -static void -rb_thread_remove(th) - rb_thread_t th; -{ - if (th->status == THREAD_KILLED) return; - - rb_thread_ready(th); - rb_thread_die(th); - th->prev->next = th->next; - th->next->prev = th->prev; -} - -static int -rb_thread_dead(th) - rb_thread_t th; -{ - return th->status == THREAD_KILLED; -} - -void -rb_thread_fd_close(fd) - int fd; -{ - rb_thread_t th; - - FOREACH_THREAD(th) { - if (((th->wait_for & WAIT_FD) && fd == th->fd) || - ((th->wait_for & WAIT_SELECT) && (fd < th->fd) && - (FD_ISSET(fd, &th->readfds) || - FD_ISSET(fd, &th->writefds) || - FD_ISSET(fd, &th->exceptfds)))) { - VALUE exc = rb_exc_new2(rb_eIOError, "stream closed"); - rb_thread_raise(1, &exc, th); - } - } - END_FOREACH(th); -} - -NORETURN(static void rb_thread_main_jump _((VALUE, int))); -static void -rb_thread_main_jump(err, tag) - VALUE err; - int tag; -{ - curr_thread = main_thread; - th_raise_exception = err; - th_raise_node = ruby_current_node; - rb_thread_restore_context(main_thread, tag); -} - -NORETURN(static void rb_thread_deadlock _((void))); -static void -rb_thread_deadlock() -{ - char msg[21+SIZEOF_LONG*2]; - VALUE e; - - sprintf(msg, "Thread(0x%lx): deadlock", curr_thread->thread); - e = rb_exc_new2(rb_eFatal, msg); - if (curr_thread == main_thread) { - rb_exc_raise(e); - } - rb_thread_main_jump(e, RESTORE_RAISE); -} - -static void -copy_fds(dst, src, max) - fd_set *dst, *src; - int max; -{ - int n = 0; - int i; - - for (i=0; i<=max; i++) { - if (FD_ISSET(i, src)) { - n = i; - FD_SET(i, dst); - } - } -} - -static int -match_fds(dst, src, max) - fd_set *dst, *src; - int max; -{ - int i; - - for (i=0; i<=max; i++) { - if (FD_ISSET(i, src) && FD_ISSET(i, dst)) { - return Qtrue; - } - } - return Qfalse; -} - -static int -intersect_fds(src, dst, max) - fd_set *src, *dst; - int max; -{ - int i, n = 0; - - for (i=0; i<=max; i++) { - if (FD_ISSET(i, dst)) { - if (FD_ISSET(i, src)) { - /* Wake up only one thread per fd. */ - FD_CLR(i, src); - n++; - } - else { - FD_CLR(i, dst); - } - } - } - return n; -} - -static int -find_bad_fds(dst, src, max) - fd_set *dst, *src; - int max; -{ - int i, test = Qfalse; - - for (i=0; i<=max; i++) { - if (FD_ISSET(i, src) && !FD_ISSET(i, dst)) { - FD_CLR(i, src); - test = Qtrue; - } - } - return test; -} - -void -rb_thread_schedule() -{ - rb_thread_t next; /* OK */ - rb_thread_t th; - rb_thread_t curr; - int found = 0; - - fd_set readfds; - fd_set writefds; - fd_set exceptfds; - struct timeval delay_tv, *delay_ptr; - double delay, now; /* OK */ - int n, max; - int need_select = 0; - int select_timeout = 0; - -#ifdef HAVE_NATIVETHREAD - if (!is_ruby_native_thread()) { - rb_bug("cross-thread violation on rb_thread_schedule()"); - } -#endif - rb_thread_pending = 0; - if (curr_thread == curr_thread->next - && curr_thread->status == THREAD_RUNNABLE) - return; - - next = 0; - curr = curr_thread; /* starting thread */ - - while (curr->status == THREAD_KILLED) { - curr = curr->prev; - } - - again: - max = -1; - FD_ZERO(&readfds); - FD_ZERO(&writefds); - FD_ZERO(&exceptfds); - delay = DELAY_INFTY; - now = -1.0; - - FOREACH_THREAD_FROM(curr, th) { - if (!found && th->status <= THREAD_RUNNABLE) { - found = 1; - } - if (th->status != THREAD_STOPPED) continue; - if (th->wait_for & WAIT_JOIN) { - if (rb_thread_dead(th->join)) { - th->status = THREAD_RUNNABLE; - found = 1; - } - } - if (th->wait_for & WAIT_FD) { - FD_SET(th->fd, &readfds); - if (max < th->fd) max = th->fd; - need_select = 1; - } - if (th->wait_for & WAIT_SELECT) { - copy_fds(&readfds, &th->readfds, th->fd); - copy_fds(&writefds, &th->writefds, th->fd); - copy_fds(&exceptfds, &th->exceptfds, th->fd); - if (max < th->fd) max = th->fd; - need_select = 1; - if (th->wait_for & WAIT_TIME) { - select_timeout = 1; - } - th->select_value = 0; - } - if (th->wait_for & WAIT_TIME) { - double th_delay; - - if (now < 0.0) now = timeofday(); - th_delay = th->delay - now; - if (th_delay <= 0.0) { - th->status = THREAD_RUNNABLE; - found = 1; - } - else if (th_delay < delay) { - delay = th_delay; - need_select = 1; - } - else if (th->delay == DELAY_INFTY) { - need_select = 1; - } - } - } - END_FOREACH_FROM(curr, th); - - /* Do the select if needed */ - if (need_select) { - /* Convert delay to a timeval */ - /* If a thread is runnable, just poll */ - if (found) { - delay_tv.tv_sec = 0; - delay_tv.tv_usec = 0; - delay_ptr = &delay_tv; - } - else if (delay == DELAY_INFTY) { - delay_ptr = 0; - } - else { - delay_tv.tv_sec = delay; - delay_tv.tv_usec = (delay - (double)delay_tv.tv_sec)*1e6; - delay_ptr = &delay_tv; - } - - n = select(max+1, &readfds, &writefds, &exceptfds, delay_ptr); - if (n < 0) { - int e = errno; - - if (rb_trap_pending) rb_trap_exec(); - if (e == EINTR) goto again; -#ifdef ERESTART - if (e == ERESTART) goto again; -#endif - FOREACH_THREAD_FROM(curr, th) { - if (th->wait_for & WAIT_SELECT) { - int v = 0; - - v |= find_bad_fds(&readfds, &th->readfds, th->fd); - v |= find_bad_fds(&writefds, &th->writefds, th->fd); - v |= find_bad_fds(&exceptfds, &th->exceptfds, th->fd); - if (v) { - th->select_value = n; - n = max; - } - } - } - END_FOREACH_FROM(curr, th); - } - if (select_timeout && n == 0) { - if (now < 0.0) now = timeofday(); - FOREACH_THREAD_FROM(curr, th) { - if (((th->wait_for&(WAIT_SELECT|WAIT_TIME)) == (WAIT_SELECT|WAIT_TIME)) && - th->delay <= now) { - th->status = THREAD_RUNNABLE; - th->wait_for = 0; - th->select_value = 0; - found = 1; - intersect_fds(&readfds, &th->readfds, max); - intersect_fds(&writefds, &th->writefds, max); - intersect_fds(&exceptfds, &th->exceptfds, max); - } - } - END_FOREACH_FROM(curr, th); - } - if (n > 0) { - now = -1.0; - /* Some descriptors are ready. - Make the corresponding threads runnable. */ - FOREACH_THREAD_FROM(curr, th) { - if ((th->wait_for&WAIT_FD) && FD_ISSET(th->fd, &readfds)) { - /* Wake up only one thread per fd. */ - FD_CLR(th->fd, &readfds); - th->status = THREAD_RUNNABLE; - th->fd = 0; - th->wait_for = 0; - found = 1; - } - if ((th->wait_for&WAIT_SELECT) && - (match_fds(&readfds, &th->readfds, max) || - match_fds(&writefds, &th->writefds, max) || - match_fds(&exceptfds, &th->exceptfds, max))) { - /* Wake up only one thread per fd. */ - th->status = THREAD_RUNNABLE; - th->wait_for = 0; - n = intersect_fds(&readfds, &th->readfds, max) + - intersect_fds(&writefds, &th->writefds, max) + - intersect_fds(&exceptfds, &th->exceptfds, max); - th->select_value = n; - found = 1; - } - } - END_FOREACH_FROM(curr, th); - } - /* The delays for some of the threads should have expired. - Go through the loop once more, to check the delays. */ - if (!found && delay != DELAY_INFTY) - goto again; - } - - FOREACH_THREAD_FROM(curr, th) { - if (th->status == THREAD_TO_KILL) { - next = th; - break; - } - if (th->status == THREAD_RUNNABLE && th->stk_ptr) { - if (!next || next->priority < th->priority) - next = th; - } - } - END_FOREACH_FROM(curr, th); - - if (!next) { - /* raise fatal error to main thread */ - curr_thread->node = ruby_current_node; - if (curr->next == curr) { - TRAP_BEG; - pause(); - TRAP_END; - } - FOREACH_THREAD_FROM(curr, th) { - warn_printf("deadlock 0x%lx: %s:", - th->thread, thread_status_name(th->status)); - if (th->wait_for & WAIT_FD) warn_printf("F(%d)", th->fd); - if (th->wait_for & WAIT_SELECT) warn_printf("S"); - if (th->wait_for & WAIT_TIME) warn_printf("T(%f)", th->delay); - if (th->wait_for & WAIT_JOIN) - warn_printf("J(0x%lx)", th->join ? th->join->thread : 0); - if (th->wait_for & WAIT_PID) warn_printf("P"); - if (!th->wait_for) warn_printf("-"); - warn_printf(" %s - %s:%d\n", - th==main_thread ? "(main)" : "", - th->node->nd_file, nd_line(th->node)); - } - END_FOREACH_FROM(curr, th); - next = main_thread; - rb_thread_ready(next); - next->status = THREAD_TO_KILL; - if (!rb_thread_dead(curr_thread)) { - rb_thread_save_context(curr_thread); - } - rb_thread_deadlock(); - } - next->wait_for = 0; - if (next->status == THREAD_RUNNABLE && next == curr_thread) { - return; - } - - /* context switch */ - if (curr == curr_thread) { - if (THREAD_SAVE_CONTEXT(curr)) { - return; - } - } - - curr_thread = next; - if (next->status == THREAD_TO_KILL) { - if (!(next->flags & THREAD_TERMINATING)) { - next->flags |= THREAD_TERMINATING; - /* terminate; execute ensure-clause if any */ - rb_thread_restore_context(next, RESTORE_FATAL); - } - } - rb_thread_restore_context(next, RESTORE_NORMAL); -} - -void -rb_thread_wait_fd(fd) - int fd; -{ - if (rb_thread_critical) return; - if (curr_thread == curr_thread->next) return; - if (curr_thread->status == THREAD_TO_KILL) return; - - curr_thread->status = THREAD_STOPPED; - curr_thread->fd = fd; - curr_thread->wait_for = WAIT_FD; - rb_thread_schedule(); -} - -int -rb_thread_fd_writable(fd) - int fd; -{ - if (rb_thread_critical) return Qtrue; - if (curr_thread == curr_thread->next) return Qtrue; - if (curr_thread->status == THREAD_TO_KILL) return Qtrue; - - curr_thread->status = THREAD_STOPPED; - FD_ZERO(&curr_thread->readfds); - FD_ZERO(&curr_thread->writefds); - FD_SET(fd, &curr_thread->writefds); - FD_ZERO(&curr_thread->exceptfds); - curr_thread->fd = fd+1; - curr_thread->wait_for = WAIT_SELECT; - rb_thread_schedule(); - return Qfalse; -} - -void -rb_thread_wait_for(time) - struct timeval time; -{ - double date; - - if (rb_thread_critical || - curr_thread == curr_thread->next || - curr_thread->status == THREAD_TO_KILL) { - int n; - int thr_critical = rb_thread_critical; -#ifndef linux - double d, limit; - limit = timeofday()+(double)time.tv_sec+(double)time.tv_usec*1e-6; -#endif - for (;;) { - rb_thread_critical = Qtrue; - TRAP_BEG; - n = select(0, 0, 0, 0, &time); - rb_thread_critical = thr_critical; - TRAP_END; - if (n == 0) return; - if (n < 0) { - switch (errno) { - case EINTR: -#ifdef ERESTART - case ERESTART: -#endif - return; - default: - rb_sys_fail("sleep"); - } - } -#ifndef linux - d = limit - timeofday(); - - time.tv_sec = (int)d; - time.tv_usec = (int)((d - (int)d)*1e6); - if (time.tv_usec < 0) { - time.tv_usec += (long)1e6; - time.tv_sec -= 1; - } - if (time.tv_sec < 0) return; -#endif - } - } - - date = timeofday() + (double)time.tv_sec + (double)time.tv_usec*1e-6; - curr_thread->status = THREAD_STOPPED; - curr_thread->delay = date; - curr_thread->wait_for = WAIT_TIME; - rb_thread_schedule(); -} - -void rb_thread_sleep_forever _((void)); - -int -rb_thread_alone() -{ - return curr_thread == curr_thread->next; -} - -int -rb_thread_select(max, read, write, except, timeout) - int max; - fd_set *read, *write, *except; - struct timeval *timeout; -{ - double limit; - int n; - - if (!read && !write && !except) { - if (!timeout) { - rb_thread_sleep_forever(); - return 0; - } - rb_thread_wait_for(*timeout); - return 0; - } - - if (timeout) { - limit = timeofday()+ - (double)timeout->tv_sec+(double)timeout->tv_usec*1e-6; - } - - if (rb_thread_critical || - curr_thread == curr_thread->next || - curr_thread->status == THREAD_TO_KILL) { -#ifndef linux - struct timeval tv, *tvp = timeout; - - if (timeout) { - tv = *timeout; - tvp = &tv; - } -#else - struct timeval *const tvp = timeout; -#endif - for (;;) { - TRAP_BEG; - n = select(max, read, write, except, tvp); - TRAP_END; - if (n < 0) { - switch (errno) { - case EINTR: -#ifdef ERESTART - case ERESTART: -#endif -#ifndef linux - if (timeout) { - double d = limit - timeofday(); - - tv.tv_sec = (unsigned int)d; - tv.tv_usec = (long)((d-(double)tv.tv_sec)*1e6); - if (tv.tv_sec < 0) tv.tv_sec = 0; - if (tv.tv_usec < 0) tv.tv_usec = 0; - } -#endif - continue; - default: - break; - } - } - return n; - } - } - - curr_thread->status = THREAD_STOPPED; - if (read) curr_thread->readfds = *read; - else FD_ZERO(&curr_thread->readfds); - if (write) curr_thread->writefds = *write; - else FD_ZERO(&curr_thread->writefds); - if (except) curr_thread->exceptfds = *except; - else FD_ZERO(&curr_thread->exceptfds); - curr_thread->fd = max; - curr_thread->wait_for = WAIT_SELECT; - if (timeout) { - curr_thread->delay = timeofday() + - (double)timeout->tv_sec + (double)timeout->tv_usec*1e-6; - curr_thread->wait_for |= WAIT_TIME; - } - rb_thread_schedule(); - if (read) *read = curr_thread->readfds; - if (write) *write = curr_thread->writefds; - if (except) *except = curr_thread->exceptfds; - return curr_thread->select_value; -} - -static int rb_thread_join _((rb_thread_t, double)); - -static int -rb_thread_join(th, limit) - rb_thread_t th; - double limit; -{ - enum thread_status last_status = THREAD_RUNNABLE; - - if (rb_thread_critical) rb_thread_deadlock(); - if (!rb_thread_dead(th)) { - if (th == curr_thread) - rb_raise(rb_eThreadError, "thread 0x%lx tried to join itself", - th->thread); - if ((th->wait_for & WAIT_JOIN) && th->join == curr_thread) - rb_raise(rb_eThreadError, "Thread#join: deadlock 0x%lx - mutual join(0x%lx)", - curr_thread->thread, th->thread); - if (curr_thread->status == THREAD_TO_KILL) - last_status = THREAD_TO_KILL; - if (limit == 0) return Qfalse; - curr_thread->status = THREAD_STOPPED; - curr_thread->join = th; - curr_thread->wait_for = WAIT_JOIN; - curr_thread->delay = timeofday() + limit; - if (limit < DELAY_INFTY) curr_thread->wait_for |= WAIT_TIME; - rb_thread_schedule(); - curr_thread->status = last_status; - if (!rb_thread_dead(th)) return Qfalse; - } - - if (!NIL_P(th->errinfo) && (th->flags & THREAD_RAISED)) { - VALUE oldbt = get_backtrace(th->errinfo); - VALUE errat = make_backtrace(); - VALUE errinfo = rb_obj_dup(th->errinfo); - - if (TYPE(oldbt) == T_ARRAY && RARRAY(oldbt)->len > 0) { - rb_ary_unshift(errat, rb_ary_entry(oldbt, 0)); - } - set_backtrace(errinfo, errat); - rb_exc_raise(errinfo); - } - - return Qtrue; -} - - -/* - * call-seq: - * thr.join => thr - * thr.join(limit) => thr - * - * The calling thread will suspend execution and run <i>thr</i>. Does not - * return until <i>thr</i> exits or until <i>limit</i> seconds have passed. If - * the time limit expires, <code>nil</code> will be returned, otherwise - * <i>thr</i> is returned. - * - * Any threads not joined will be killed when the main program exits. If - * <i>thr</i> had previously raised an exception and the - * <code>abort_on_exception</code> and <code>$DEBUG</code> flags are not set - * (so the exception has not yet been processed) it will be processed at this - * time. - * - * a = Thread.new { print "a"; sleep(10); print "b"; print "c" } - * x = Thread.new { print "x"; Thread.pass; print "y"; print "z" } - * x.join # Let x thread finish, a will be killed on exit. - * - * <em>produces:</em> - * - * axyz - * - * The following example illustrates the <i>limit</i> parameter. - * - * y = Thread.new { 4.times { sleep 0.1; puts 'tick... ' }} - * puts "Waiting" until y.join(0.15) - * - * <em>produces:</em> - * - * tick... - * Waiting - * tick... - * Waitingtick... - * - * - * tick... - */ - -static VALUE -rb_thread_join_m(argc, argv, thread) - int argc; - VALUE *argv; - VALUE thread; -{ - VALUE limit; - double delay = DELAY_INFTY; - rb_thread_t th = rb_thread_check(thread); - - rb_scan_args(argc, argv, "01", &limit); - if (!NIL_P(limit)) delay = rb_num2dbl(limit); - if (!rb_thread_join(th, delay)) - return Qnil; - return thread; -} - - -/* - * call-seq: - * Thread.current => thread - * - * Returns the currently executing thread. - * - * Thread.current #=> #<Thread:0x401bdf4c run> - */ - -VALUE -rb_thread_current() -{ - return curr_thread->thread; -} - - -/* - * call-seq: - * Thread.main => thread - * - * Returns the main thread for the process. - * - * Thread.main #=> #<Thread:0x401bdf4c run> - */ - -VALUE -rb_thread_main() -{ - return main_thread->thread; -} - - -/* - * call-seq: - * Thread.list => array - * - * Returns an array of <code>Thread</code> objects for all threads that are - * either runnable or stopped. - * - * Thread.new { sleep(200) } - * Thread.new { 1000000.times {|i| i*i } } - * Thread.new { Thread.stop } - * Thread.list.each {|t| p t} - * - * <em>produces:</em> - * - * #<Thread:0x401b3e84 sleep> - * #<Thread:0x401b3f38 run> - * #<Thread:0x401b3fb0 sleep> - * #<Thread:0x401bdf4c run> - */ - -VALUE -rb_thread_list() -{ - rb_thread_t th; - VALUE ary = rb_ary_new(); - - FOREACH_THREAD(th) { - switch (th->status) { - case THREAD_RUNNABLE: - case THREAD_STOPPED: - case THREAD_TO_KILL: - rb_ary_push(ary, th->thread); - default: - break; - } - } - END_FOREACH(th); - - return ary; -} - - -/* - * call-seq: - * thr.wakeup => thr - * - * Marks <i>thr</i> as eligible for scheduling (it may still remain blocked on - * I/O, however). Does not invoke the scheduler (see <code>Thread#run</code>). - * - * c = Thread.new { Thread.stop; puts "hey!" } - * c.wakeup - * - * <em>produces:</em> - * - * hey! - */ - -VALUE -rb_thread_wakeup(thread) - VALUE thread; -{ - rb_thread_t th = rb_thread_check(thread); - - if (th->status == THREAD_KILLED) - rb_raise(rb_eThreadError, "killed thread"); - rb_thread_ready(th); - - return thread; -} - - -/* - * call-seq: - * thr.run => thr - * - * Wakes up <i>thr</i>, making it eligible for scheduling. If not in a critical - * section, then invokes the scheduler. - * - * a = Thread.new { puts "a"; Thread.stop; puts "c" } - * Thread.pass - * puts "Got here" - * a.run - * a.join - * - * <em>produces:</em> - * - * a - * Got here - * c - */ - -VALUE -rb_thread_run(thread) - VALUE thread; -{ - rb_thread_wakeup(thread); - if (!rb_thread_critical) rb_thread_schedule(); - - return thread; -} - - -/* - * call-seq: - * thr.exit => thr or nil - * thr.kill => thr or nil - * thr.terminate => thr or nil - * - * Terminates <i>thr</i> and schedules another thread to be run. If this thread - * is already marked to be killed, <code>exit</code> returns the - * <code>Thread</code>. If this is the main thread, or the last thread, exits - * the process. - */ - -VALUE -rb_thread_kill(thread) - VALUE thread; -{ - rb_thread_t th = rb_thread_check(thread); - - if (th != curr_thread && th->safe < 4) { - rb_secure(4); - } - if (th->status == THREAD_TO_KILL || th->status == THREAD_KILLED) - return thread; - if (th == th->next || th == main_thread) rb_exit(EXIT_SUCCESS); - - rb_thread_ready(th); - th->status = THREAD_TO_KILL; - if (!rb_thread_critical) rb_thread_schedule(); - return thread; -} - - -/* - * call-seq: - * Thread.kill(thread) => thread - * - * Causes the given <em>thread</em> to exit (see <code>Thread::exit</code>). - * - * count = 0 - * a = Thread.new { loop { count += 1 } } - * sleep(0.1) #=> 0 - * Thread.kill(a) #=> #<Thread:0x401b3d30 dead> - * count #=> 93947 - * a.alive? #=> false - */ - -static VALUE -rb_thread_s_kill(obj, th) - VALUE obj, th; -{ - return rb_thread_kill(th); -} - - -/* - * call-seq: - * Thread.exit => thread - * - * Terminates the currently running thread and schedules another thread to be - * run. If this thread is already marked to be killed, <code>exit</code> - * returns the <code>Thread</code>. If this is the main thread, or the last - * thread, exit the process. - */ - -static VALUE -rb_thread_exit() -{ - return rb_thread_kill(curr_thread->thread); -} - - -/* - * call-seq: - * Thread.pass => nil - * - * Invokes the thread scheduler to pass execution to another thread. - * - * a = Thread.new { print "a"; Thread.pass; - * print "b"; Thread.pass; - * print "c" } - * b = Thread.new { print "x"; Thread.pass; - * print "y"; Thread.pass; - * print "z" } - * a.join - * b.join - * - * <em>produces:</em> - * - * axbycz - */ - -static VALUE -rb_thread_pass() -{ - rb_thread_schedule(); - return Qnil; -} - - -/* - * call-seq: - * Thread.stop => nil - * - * Stops execution of the current thread, putting it into a ``sleep'' state, - * and schedules execution of another thread. Resets the ``critical'' condition - * to <code>false</code>. - * - * a = Thread.new { print "a"; Thread.stop; print "c" } - * Thread.pass - * print "b" - * a.run - * a.join - * - * <em>produces:</em> - * - * abc - */ - -VALUE -rb_thread_stop() -{ - enum thread_status last_status = THREAD_RUNNABLE; - - rb_thread_critical = 0; - if (curr_thread == curr_thread->next) { - rb_raise(rb_eThreadError, "stopping only thread\n\tnote: use sleep to stop forever"); - } - if (curr_thread->status == THREAD_TO_KILL) - last_status = THREAD_TO_KILL; - curr_thread->status = THREAD_STOPPED; - rb_thread_schedule(); - curr_thread->status = last_status; - - return Qnil; -} - -struct timeval rb_time_timeval(); - -void -rb_thread_polling() -{ - if (curr_thread != curr_thread->next) { - curr_thread->status = THREAD_STOPPED; - curr_thread->delay = timeofday() + (double)0.06; - curr_thread->wait_for = WAIT_TIME; - rb_thread_schedule(); - } -} - -void -rb_thread_sleep(sec) - int sec; -{ - if (curr_thread == curr_thread->next) { - TRAP_BEG; - sleep(sec); - TRAP_END; - return; - } - rb_thread_wait_for(rb_time_timeval(INT2FIX(sec))); -} - -void -rb_thread_sleep_forever() -{ - int thr_critical = rb_thread_critical; - if (curr_thread == curr_thread->next || - curr_thread->status == THREAD_TO_KILL) { - rb_thread_critical = Qtrue; - TRAP_BEG; - pause(); - rb_thread_critical = thr_critical; - TRAP_END; - return; - } - - curr_thread->delay = DELAY_INFTY; - curr_thread->wait_for = WAIT_TIME; - curr_thread->status = THREAD_STOPPED; - rb_thread_schedule(); -} - - -/* - * call-seq: - * thr.priority => integer - * - * Returns the priority of <i>thr</i>. Default is zero; higher-priority threads - * will run before lower-priority threads. - * - * Thread.current.priority #=> 0 - */ - -static VALUE -rb_thread_priority(thread) - VALUE thread; -{ - return INT2NUM(rb_thread_check(thread)->priority); -} - - -/* - * call-seq: - * thr.priority= integer => thr - * - * Sets the priority of <i>thr</i> to <i>integer</i>. Higher-priority threads - * will run before lower-priority threads. - * - * count1 = count2 = 0 - * a = Thread.new do - * loop { count1 += 1 } - * end - * a.priority = -1 - * - * b = Thread.new do - * loop { count2 += 1 } - * end - * b.priority = -2 - * sleep 1 #=> 1 - * Thread.critical = 1 - * count1 #=> 622504 - * count2 #=> 5832 - */ - -static VALUE -rb_thread_priority_set(thread, prio) - VALUE thread, prio; -{ - rb_thread_t th; - - rb_secure(4); - th = rb_thread_check(thread); - - th->priority = NUM2INT(prio); - rb_thread_schedule(); - return prio; -} - - -/* - * call-seq: - * thr.safe_level => integer - * - * Returns the safe level in effect for <i>thr</i>. Setting thread-local safe - * levels can help when implementing sandboxes which run insecure code. - * - * thr = Thread.new { $SAFE = 3; sleep } - * Thread.current.safe_level #=> 0 - * thr.safe_level #=> 3 - */ - -static VALUE -rb_thread_safe_level(thread) - VALUE thread; -{ - rb_thread_t th; - - th = rb_thread_check(thread); - if (th == curr_thread) { - return INT2NUM(ruby_safe_level); - } - return INT2NUM(th->safe); -} - -static int ruby_thread_abort; -static VALUE thgroup_default; - - -/* - * call-seq: - * Thread.abort_on_exception => true or false - * - * Returns the status of the global ``abort on exception'' condition. The - * default is <code>false</code>. When set to <code>true</code>, or if the - * global <code>$DEBUG</code> flag is <code>true</code> (perhaps because the - * command line option <code>-d</code> was specified) all threads will abort - * (the process will <code>exit(0)</code>) if an exception is raised in any - * thread. See also <code>Thread::abort_on_exception=</code>. - */ - -static VALUE -rb_thread_s_abort_exc() -{ - return ruby_thread_abort?Qtrue:Qfalse; -} - - -/* - * call-seq: - * Thread.abort_on_exception= boolean => true or false - * - * When set to <code>true</code>, all threads will abort if an exception is - * raised. Returns the new state. - * - * Thread.abort_on_exception = true - * t1 = Thread.new do - * puts "In new thread" - * raise "Exception from thread" - * end - * sleep(1) - * puts "not reached" - * - * <em>produces:</em> - * - * In new thread - * prog.rb:4: Exception from thread (RuntimeError) - * from prog.rb:2:in `initialize' - * from prog.rb:2:in `new' - * from prog.rb:2 - */ - -static VALUE -rb_thread_s_abort_exc_set(self, val) - VALUE self, val; -{ - rb_secure(4); - ruby_thread_abort = RTEST(val); - return val; -} - - -/* - * call-seq: - * thr.abort_on_exception => true or false - * - * Returns the status of the thread-local ``abort on exception'' condition for - * <i>thr</i>. The default is <code>false</code>. See also - * <code>Thread::abort_on_exception=</code>. - */ - -static VALUE -rb_thread_abort_exc(thread) - VALUE thread; -{ - return rb_thread_check(thread)->abort?Qtrue:Qfalse; -} - - -/* - * call-seq: - * thr.abort_on_exception= boolean => true or false - * - * When set to <code>true</code>, causes all threads (including the main - * program) to abort if an exception is raised in <i>thr</i>. The process will - * effectively <code>exit(0)</code>. - */ - -static VALUE -rb_thread_abort_exc_set(thread, val) - VALUE thread, val; -{ - rb_secure(4); - rb_thread_check(thread)->abort = RTEST(val); - return val; -} - - -/* - * call-seq: - * thr.group => thgrp or nil - * - * Returns the <code>ThreadGroup</code> which contains <i>thr</i>, or nil if - * the thread is not a member of any group. - * - * Thread.main.group #=> #<ThreadGroup:0x4029d914> - */ - -VALUE -rb_thread_group(thread) - VALUE thread; -{ - VALUE group = rb_thread_check(thread)->thgroup; - if (!group) { - group = Qnil; - } - return group; -} - -#ifdef __ia64__ -# define IA64_INIT(x) x -#else -# define IA64_INIT(x) -#endif - -#define THREAD_ALLOC(th) do {\ - th = ALLOC(struct thread);\ -\ - th->next = 0;\ - th->prev = 0;\ -\ - th->status = THREAD_RUNNABLE;\ - th->result = 0;\ - th->flags = 0;\ -\ - th->stk_ptr = 0;\ - th->stk_len = 0;\ - th->stk_max = 0;\ - th->wait_for = 0;\ - IA64_INIT(th->bstr_ptr = 0);\ - IA64_INIT(th->bstr_len = 0);\ - FD_ZERO(&th->readfds);\ - FD_ZERO(&th->writefds);\ - FD_ZERO(&th->exceptfds);\ - th->delay = 0.0;\ - th->join = 0;\ -\ - th->frame = 0;\ - th->scope = 0;\ - th->klass = 0;\ - th->wrapper = 0;\ - th->cref = ruby_cref;\ - th->dyna_vars = ruby_dyna_vars;\ - th->block = 0;\ - th->iter = 0;\ - th->tag = 0;\ - th->tracing = 0;\ - th->errinfo = Qnil;\ - th->last_status = 0;\ - th->last_line = 0;\ - th->last_match = Qnil;\ - th->abort = 0;\ - th->priority = 0;\ - th->thgroup = thgroup_default;\ - th->locals = 0;\ - th->thread = 0;\ - th->anchor = 0;\ -} while (0) - -static rb_thread_t -rb_thread_alloc(klass) - VALUE klass; -{ - rb_thread_t th; - struct RVarmap *vars; - - THREAD_ALLOC(th); - th->thread = Data_Wrap_Struct(klass, thread_mark, thread_free, th); - - for (vars = th->dyna_vars; vars; vars = vars->next) { - if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; - FL_SET(vars, DVAR_DONT_RECYCLE); - } - return th; -} - -static int thread_init = 0; - -#if defined(_THREAD_SAFE) -static void -catch_timer(sig) - int sig; -{ -#if !defined(POSIX_SIGNAL) && !defined(BSD_SIGNAL) - signal(sig, catch_timer); -#endif - /* cause EINTR */ -} - -static pthread_t time_thread; - -static void* -thread_timer(dummy) - void *dummy; -{ - for (;;) { -#ifdef HAVE_NANOSLEEP - struct timespec req, rem; - - req.tv_sec = 0; - req.tv_nsec = 10000000; - nanosleep(&req, &rem); -#else - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 10000; - select(0, NULL, NULL, NULL, &tv); -#endif - if (!rb_thread_critical) { - rb_thread_pending = 1; - if (rb_trap_immediate) { - pthread_kill(ruby_thid, SIGVTALRM); - } - } - } -} - -void -rb_thread_start_timer() -{ -} - -void -rb_thread_stop_timer() -{ -} -#elif defined(HAVE_SETITIMER) -static void -catch_timer(sig) - int sig; -{ -#if !defined(POSIX_SIGNAL) && !defined(BSD_SIGNAL) - signal(sig, catch_timer); -#endif - if (!rb_thread_critical) { - rb_thread_pending = 1; - } - /* cause EINTR */ -} - -void -rb_thread_start_timer() -{ - struct itimerval tval; - - if (!thread_init) return; - tval.it_interval.tv_sec = 0; - tval.it_interval.tv_usec = 10000; - tval.it_value = tval.it_interval; - setitimer(ITIMER_VIRTUAL, &tval, NULL); -} - -void -rb_thread_stop_timer() -{ - struct itimerval tval; - - if (!thread_init) return; - tval.it_interval.tv_sec = 0; - tval.it_interval.tv_usec = 0; - tval.it_value = tval.it_interval; - setitimer(ITIMER_VIRTUAL, &tval, NULL); -} -#else /* !(_THREAD_SAFE || HAVE_SETITIMER) */ -int rb_thread_tick = THREAD_TICK; -#endif - -NORETURN(static void rb_thread_terminated _((rb_thread_t, int, enum thread_status))); -static VALUE rb_thread_yield _((VALUE, rb_thread_t)); - -static void -push_thread_anchor(ip) - struct ruby_env *ip; -{ - ip->tag = prot_tag; - ip->frame = ruby_frame; - ip->block = ruby_block; - ip->scope = ruby_scope; - ip->iter = ruby_iter; - ip->cref = ruby_cref; - ip->prev = curr_thread->anchor; - curr_thread->anchor = ip; -} - -static void -pop_thread_anchor(ip) - struct ruby_env *ip; -{ - curr_thread->anchor = ip->prev; -} - -static void -thread_insert(th) - rb_thread_t th; -{ - if (!th->next) { - /* merge in thread list */ - th->prev = curr_thread; - curr_thread->next->prev = th; - th->next = curr_thread->next; - curr_thread->next = th; - th->priority = curr_thread->priority; - th->thgroup = curr_thread->thgroup; - } -} - -static VALUE -rb_thread_start_0(fn, arg, th) - VALUE (*fn)(); - void *arg; - rb_thread_t th; -{ - volatile rb_thread_t th_save = th; - volatile VALUE thread = th->thread; - struct BLOCK *volatile saved_block = 0; - enum thread_status status; - int state; - - if (OBJ_FROZEN(curr_thread->thgroup)) { - rb_raise(rb_eThreadError, - "can't start a new thread (frozen ThreadGroup)"); - } - - if (!thread_init) { - thread_init = 1; -#if defined(HAVE_SETITIMER) || defined(_THREAD_SAFE) -#if defined(POSIX_SIGNAL) - posix_signal(SIGVTALRM, catch_timer); -#else - signal(SIGVTALRM, catch_timer); -#endif - -#ifdef _THREAD_SAFE - pthread_create(&time_thread, 0, thread_timer, 0); -#else - rb_thread_start_timer(); -#endif -#endif - } - - if (THREAD_SAVE_CONTEXT(curr_thread)) { - return thread; - } - - if (fn == rb_thread_yield && curr_thread->anchor) { - struct ruby_env *ip = curr_thread->anchor; - new_thread.thread = th; - new_thread.proc = rb_block_proc(); - new_thread.arg = (VALUE)arg; - th->anchor = ip; - thread_insert(th); - curr_thread = th; - longjmp((prot_tag = ip->tag)->buf, TAG_THREAD); - } - - if (ruby_block) { /* should nail down higher blocks */ - struct BLOCK dummy; - - dummy.prev = ruby_block; - blk_copy_prev(&dummy); - saved_block = ruby_block = dummy.prev; - } - scope_dup(ruby_scope); - - thread_insert(th); - - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - if (THREAD_SAVE_CONTEXT(th) == 0) { - curr_thread = th; - th->result = (*fn)(arg, th); - } - th = th_save; - } - else if (TAG_DST()) { - th = th_save; - th->result = prot_tag->retval; - } - POP_TAG(); - status = th->status; - - if (th == main_thread) ruby_stop(state); - rb_thread_remove(th); - - if (saved_block) { - blk_free(saved_block); - } - - rb_thread_terminated(th, state, status); - return 0; /* not reached */ -} - -static void -rb_thread_terminated(th, state, status) - rb_thread_t th; - int state; - enum thread_status status; -{ - if (state && status != THREAD_TO_KILL && !NIL_P(ruby_errinfo)) { - th->flags |= THREAD_RAISED; - if (state == TAG_FATAL) { - /* fatal error within this thread, need to stop whole script */ - main_thread->errinfo = ruby_errinfo; - rb_thread_cleanup(); - } - else if (rb_obj_is_kind_of(ruby_errinfo, rb_eSystemExit)) { - if (th->safe >= 4) { - char buf[32]; - - sprintf(buf, "Insecure exit at level %d", th->safe); - th->errinfo = rb_exc_new2(rb_eSecurityError, buf); - } - else { - /* delegate exception to main_thread */ - rb_thread_main_jump(ruby_errinfo, RESTORE_RAISE); - } - } - else if (th->safe < 4 && (ruby_thread_abort || th->abort || RTEST(ruby_debug))) { - /* exit on main_thread */ - rb_thread_main_jump(ruby_errinfo, RESTORE_EXIT); - } - else { - th->errinfo = ruby_errinfo; - } - } - rb_thread_schedule(); - ruby_stop(0); /* last thread termination */ -} - -static VALUE -rb_thread_yield_0(arg) - VALUE arg; -{ - return rb_thread_yield(arg, curr_thread); -} - -static void -rb_thread_start_1() -{ - rb_thread_t th = new_thread.thread; - volatile rb_thread_t th_save = th; - VALUE proc = new_thread.proc; - VALUE arg = new_thread.arg; - struct ruby_env *ip = th->anchor; - enum thread_status status; - int state; - - ruby_frame = ip->frame; - ruby_block = ip->block; - ruby_scope = ip->scope; - ruby_iter = ip->iter; - ruby_cref = ip->cref; - ruby_dyna_vars = ((struct BLOCK *)DATA_PTR(proc))->dyna_vars; - PUSH_FRAME(); - *ruby_frame = *ip->frame; - ruby_frame->prev = ip->frame; - ruby_frame->iter = ITER_CUR; - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - if (THREAD_SAVE_CONTEXT(th) == 0) { - new_thread.thread = 0; - th->result = rb_block_pass(rb_thread_yield_0, arg, proc); - } - th = th_save; - } - else if (TAG_DST()) { - th = th_save; - th->result = prot_tag->retval; - } - POP_TAG(); - POP_FRAME(); - status = th->status; - - if (th == main_thread) ruby_stop(state); - rb_thread_remove(th); - rb_thread_terminated(th, state, status); -} - -VALUE -rb_thread_create(fn, arg) - VALUE (*fn)(); - void *arg; -{ - Init_stack((VALUE*)&arg); - return rb_thread_start_0(fn, arg, rb_thread_alloc(rb_cThread)); -} - -static VALUE -rb_thread_yield(arg, th) - VALUE arg; - rb_thread_t th; -{ - const ID *tbl; - - scope_dup(ruby_block->scope); - - tbl = ruby_scope->local_tbl; - if (tbl) { - int n = *tbl++; - for (tbl += 2, n -= 2; n > 0; --n) { /* skip first 2 ($_ and $~) */ - ID id = *tbl++; - if (id != 0 && !rb_is_local_id(id)) /* push flip states */ - rb_dvar_push(id, Qfalse); - } - } - rb_dvar_push('_', Qnil); - rb_dvar_push('~', Qnil); - ruby_block->dyna_vars = ruby_dyna_vars; - - return rb_yield_0(arg, 0, 0, YIELD_LAMBDA_CALL, Qtrue); -} - -/* - * call-seq: - * Thread.new([arg]*) {|args| block } => thread - * - * Creates and runs a new thread to execute the instructions given in - * <i>block</i>. Any arguments passed to <code>Thread::new</code> are passed - * into the block. - * - * x = Thread.new { sleep 0.1; print "x"; print "y"; print "z" } - * a = Thread.new { print "a"; print "b"; sleep 0.2; print "c" } - * x.join # Let the threads finish before - * a.join # main thread exits... - * - * <em>produces:</em> - * - * abxyzc - */ - -static VALUE -rb_thread_s_new(argc, argv, klass) - int argc; - VALUE *argv; - VALUE klass; -{ - rb_thread_t th = rb_thread_alloc(klass); - volatile VALUE *pos; - - pos = th->stk_pos; - rb_obj_call_init(th->thread, argc, argv); - if (th->stk_pos == 0) { - rb_raise(rb_eThreadError, "uninitialized thread - check `%s#initialize'", - rb_class2name(klass)); - } - - return th->thread; -} - - -/* - * call-seq: - * Thread.new([arg]*) {|args| block } => thread - * - * Creates and runs a new thread to execute the instructions given in - * <i>block</i>. Any arguments passed to <code>Thread::new</code> are passed - * into the block. - * - * x = Thread.new { sleep 0.1; print "x"; print "y"; print "z" } - * a = Thread.new { print "a"; print "b"; sleep 0.2; print "c" } - * x.join # Let the threads finish before - * a.join # main thread exits... - * - * <em>produces:</em> - * - * abxyzc - */ - -static VALUE -rb_thread_initialize(thread, args) - VALUE thread, args; -{ - rb_thread_t th; - - if (!rb_block_given_p()) { - rb_raise(rb_eThreadError, "must be called with a block"); - } - th = rb_thread_check(thread); - if (th->stk_max) { - NODE *node = th->node; - if (!node) { - rb_raise(rb_eThreadError, "already initialized thread"); - } - rb_raise(rb_eThreadError, "already initialized thread - %s:%d", - node->nd_file, nd_line(node)); - } - return rb_thread_start_0(rb_thread_yield, args, th); -} - - -/* - * call-seq: - * Thread.start([args]*) {|args| block } => thread - * Thread.fork([args]*) {|args| block } => thread - * - * Basically the same as <code>Thread::new</code>. However, if class - * <code>Thread</code> is subclassed, then calling <code>start</code> in that - * subclass will not invoke the subclass's <code>initialize</code> method. - */ - -static VALUE -rb_thread_start(klass, args) - VALUE klass, args; -{ - if (!rb_block_given_p()) { - rb_raise(rb_eThreadError, "must be called with a block"); - } - return rb_thread_start_0(rb_thread_yield, args, rb_thread_alloc(klass)); -} - - -/* - * call-seq: - * thr.value => obj - * - * Waits for <i>thr</i> to complete (via <code>Thread#join</code>) and returns - * its value. - * - * a = Thread.new { 2 + 2 } - * a.value #=> 4 - */ - -static VALUE -rb_thread_value(thread) - VALUE thread; -{ - rb_thread_t th = rb_thread_check(thread); - - while (!rb_thread_join(th, DELAY_INFTY)); - - return th->result; -} - - -/* - * call-seq: - * thr.status => string, false or nil - * - * Returns the status of <i>thr</i>: ``<code>sleep</code>'' if <i>thr</i> is - * sleeping or waiting on I/O, ``<code>run</code>'' if <i>thr</i> is executing, - * ``<code>aborting</code>'' if <i>thr</i> is aborting, <code>false</code> if - * <i>thr</i> terminated normally, and <code>nil</code> if <i>thr</i> - * terminated with an exception. - * - * a = Thread.new { raise("die now") } - * b = Thread.new { Thread.stop } - * c = Thread.new { Thread.exit } - * d = Thread.new { sleep } - * Thread.critical = true - * d.kill #=> #<Thread:0x401b3678 aborting> - * a.status #=> nil - * b.status #=> "sleep" - * c.status #=> false - * d.status #=> "aborting" - * Thread.current.status #=> "run" - */ - -static VALUE -rb_thread_status(thread) - VALUE thread; -{ - rb_thread_t th = rb_thread_check(thread); - - if (rb_thread_dead(th)) { - if (!NIL_P(th->errinfo) && (th->flags & THREAD_RAISED)) - return Qnil; - return Qfalse; - } - - return rb_str_new2(thread_status_name(th->status)); -} - - -/* - * call-seq: - * thr.alive? => true or false - * - * Returns <code>true</code> if <i>thr</i> is running or sleeping. - * - * thr = Thread.new { } - * thr.join #=> #<Thread:0x401b3fb0 dead> - * Thread.current.alive? #=> true - * thr.alive? #=> false - */ - -static VALUE -rb_thread_alive_p(thread) - VALUE thread; -{ - rb_thread_t th = rb_thread_check(thread); - - if (rb_thread_dead(th)) return Qfalse; - return Qtrue; -} - - -/* - * call-seq: - * thr.stop? => true or false - * - * Returns <code>true</code> if <i>thr</i> is dead or sleeping. - * - * a = Thread.new { Thread.stop } - * b = Thread.current - * a.stop? #=> true - * b.stop? #=> false - */ - -static VALUE -rb_thread_stop_p(thread) - VALUE thread; -{ - rb_thread_t th = rb_thread_check(thread); - - if (rb_thread_dead(th)) return Qtrue; - if (th->status == THREAD_STOPPED) return Qtrue; - return Qfalse; -} - -static void -rb_thread_wait_other_threads() -{ - rb_thread_t th; - int found; - - /* wait other threads to terminate */ - while (curr_thread != curr_thread->next) { - found = 0; - FOREACH_THREAD(th) { - if (th != curr_thread && th->status != THREAD_STOPPED) { - found = 1; - break; - } - } - END_FOREACH(th); - if (!found) return; - rb_thread_schedule(); - } -} - -static void -rb_thread_cleanup() -{ - rb_thread_t curr, th; - - curr = curr_thread; - while (curr->status == THREAD_KILLED) { - curr = curr->prev; - } - - FOREACH_THREAD_FROM(curr, th) { - if (th->status != THREAD_KILLED) { - rb_thread_ready(th); - if (th != main_thread) { - th->thgroup = 0; - th->priority = 0; - th->status = THREAD_TO_KILL; - RDATA(th->thread)->dfree = NULL; - } - } - } - END_FOREACH_FROM(curr, th); -} - -int rb_thread_critical; - - -/* - * call-seq: - * Thread.critical => true or false - * - * Returns the status of the global ``thread critical'' condition. - */ - -static VALUE -rb_thread_critical_get() -{ - return rb_thread_critical?Qtrue:Qfalse; -} - - -/* - * call-seq: - * Thread.critical= boolean => true or false - * - * Sets the status of the global ``thread critical'' condition and returns - * it. When set to <code>true</code>, prohibits scheduling of any existing - * thread. Does not block new threads from being created and run. Certain - * thread operations (such as stopping or killing a thread, sleeping in the - * current thread, and raising an exception) may cause a thread to be scheduled - * even when in a critical section. <code>Thread::critical</code> is not - * intended for daily use: it is primarily there to support folks writing - * threading libraries. - */ - -static VALUE -rb_thread_critical_set(obj, val) - VALUE obj, val; -{ - rb_thread_critical = RTEST(val); - return val; -} - -void -rb_thread_interrupt() -{ - rb_thread_critical = 0; - rb_thread_ready(main_thread); - if (curr_thread == main_thread) { - rb_interrupt(); - } - if (!rb_thread_dead(curr_thread)) { - if (THREAD_SAVE_CONTEXT(curr_thread)) { - return; - } - } - curr_thread = main_thread; - rb_thread_restore_context(curr_thread, RESTORE_INTERRUPT); -} - -void -rb_thread_signal_raise(sig) - char *sig; -{ - if (sig == 0) return; /* should not happen */ - rb_thread_critical = 0; - if (curr_thread == main_thread) { - rb_thread_ready(curr_thread); - rb_raise(rb_eSignal, "SIG%s", sig); - } - rb_thread_ready(main_thread); - if (!rb_thread_dead(curr_thread)) { - if (THREAD_SAVE_CONTEXT(curr_thread)) { - return; - } - } - th_signm = sig; - curr_thread = main_thread; - rb_thread_restore_context(curr_thread, RESTORE_SIGNAL); -} - -void -rb_thread_trap_eval(cmd, sig, safe) - VALUE cmd; - int sig, safe; -{ - rb_thread_critical = 0; - if (curr_thread == main_thread) { - rb_trap_eval(cmd, sig, safe); - return; - } - if (!rb_thread_dead(curr_thread)) { - if (THREAD_SAVE_CONTEXT(curr_thread)) { - return; - } - } - th_cmd = cmd; - th_sig = sig; - th_safe = safe; - curr_thread = main_thread; - rb_thread_restore_context(curr_thread, RESTORE_TRAP); -} - -static VALUE -rb_thread_raise(argc, argv, th) - int argc; - VALUE *argv; - rb_thread_t th; -{ - volatile rb_thread_t th_save = th; - VALUE exc; - - if (!th->next) { - rb_raise(rb_eArgError, "unstarted thread"); - } - if (rb_thread_dead(th)) return Qnil; - exc = rb_make_exception(argc, argv); - if (curr_thread == th) { - rb_raise_jump(exc); - } - - if (!rb_thread_dead(curr_thread)) { - if (THREAD_SAVE_CONTEXT(curr_thread)) { - return th_save->thread; - } - } - - rb_thread_ready(th); - curr_thread = th; - - th_raise_exception = exc; - th_raise_node = ruby_current_node; - rb_thread_restore_context(curr_thread, RESTORE_RAISE); - return Qnil; /* not reached */ -} - - -/* - * call-seq: - * thr.raise(exception) - * - * Raises an exception (see <code>Kernel::raise</code>) from <i>thr</i>. The - * caller does not have to be <i>thr</i>. - * - * Thread.abort_on_exception = true - * a = Thread.new { sleep(200) } - * a.raise("Gotcha") - * - * <em>produces:</em> - * - * prog.rb:3: Gotcha (RuntimeError) - * from prog.rb:2:in `initialize' - * from prog.rb:2:in `new' - * from prog.rb:2 - */ - -static VALUE -rb_thread_raise_m(argc, argv, thread) - int argc; - VALUE *argv; - VALUE thread; -{ - rb_thread_t th = rb_thread_check(thread); - - if (ruby_safe_level > th->safe) { - rb_secure(4); - } - rb_thread_raise(argc, argv, th); - return Qnil; /* not reached */ -} - -VALUE -rb_thread_local_aref(thread, id) - VALUE thread; - ID id; -{ - rb_thread_t th; - VALUE val; - - th = rb_thread_check(thread); - if (ruby_safe_level >= 4 && th != curr_thread) { - rb_raise(rb_eSecurityError, "Insecure: thread locals"); - } - if (!th->locals) return Qnil; - if (st_lookup(th->locals, id, &val)) { - return val; - } - return Qnil; -} - - -/* - * call-seq: - * thr[sym] => obj or nil - * - * Attribute Reference---Returns the value of a thread-local variable, using - * either a symbol or a string name. If the specified variable does not exist, - * returns <code>nil</code>. - * - * a = Thread.new { Thread.current["name"] = "A"; Thread.stop } - * b = Thread.new { Thread.current[:name] = "B"; Thread.stop } - * c = Thread.new { Thread.current["name"] = "C"; Thread.stop } - * Thread.list.each {|x| puts "#{x.inspect}: #{x[:name]}" } - * - * <em>produces:</em> - * - * #<Thread:0x401b3b3c sleep>: C - * #<Thread:0x401b3bc8 sleep>: B - * #<Thread:0x401b3c68 sleep>: A - * #<Thread:0x401bdf4c run>: - */ - -static VALUE -rb_thread_aref(thread, id) - VALUE thread, id; -{ - return rb_thread_local_aref(thread, rb_to_id(id)); -} - -VALUE -rb_thread_local_aset(thread, id, val) - VALUE thread; - ID id; - VALUE val; -{ - rb_thread_t th = rb_thread_check(thread); - - if (ruby_safe_level >= 4 && th != curr_thread) { - rb_raise(rb_eSecurityError, "Insecure: can't modify thread locals"); - } - if (OBJ_FROZEN(thread)) rb_error_frozen("thread locals"); - - if (!th->locals) { - th->locals = st_init_numtable(); - } - if (NIL_P(val)) { - st_delete(th->locals, (st_data_t*)&id, 0); - return Qnil; - } - st_insert(th->locals, id, val); - - return val; -} - - -/* - * call-seq: - * thr[sym] = obj => obj - * - * Attribute Assignment---Sets or creates the value of a thread-local variable, - * using either a symbol or a string. See also <code>Thread#[]</code>. - */ - -static VALUE -rb_thread_aset(thread, id, val) - VALUE thread, id, val; -{ - return rb_thread_local_aset(thread, rb_to_id(id), val); -} - - -/* - * call-seq: - * thr.key?(sym) => true or false - * - * Returns <code>true</code> if the given string (or symbol) exists as a - * thread-local variable. - * - * me = Thread.current - * me[:oliver] = "a" - * me.key?(:oliver) #=> true - * me.key?(:stanley) #=> false - */ - -static VALUE -rb_thread_key_p(thread, id) - VALUE thread, id; -{ - rb_thread_t th = rb_thread_check(thread); - - if (!th->locals) return Qfalse; - if (st_lookup(th->locals, rb_to_id(id), 0)) - return Qtrue; - return Qfalse; -} - -static int -thread_keys_i(key, value, ary) - ID key; - VALUE value, ary; -{ - rb_ary_push(ary, ID2SYM(key)); - return ST_CONTINUE; -} - - -/* - * call-seq: - * thr.keys => array - * - * Returns an an array of the names of the thread-local variables (as Symbols). - * - * thr = Thread.new do - * Thread.current[:cat] = 'meow' - * Thread.current["dog"] = 'woof' - * end - * thr.join #=> #<Thread:0x401b3f10 dead> - * thr.keys #=> [:dog, :cat] - */ - -static VALUE -rb_thread_keys(thread) - VALUE thread; -{ - rb_thread_t th = rb_thread_check(thread); - VALUE ary = rb_ary_new(); - - if (th->locals) { - st_foreach(th->locals, thread_keys_i, ary); - } - return ary; -} - -/* - * call-seq: - * thr.inspect => string - * - * Dump the name, id, and status of _thr_ to a string. - */ - -static VALUE -rb_thread_inspect(thread) - VALUE thread; -{ - char *cname = rb_obj_classname(thread); - rb_thread_t th = rb_thread_check(thread); - const char *status = thread_status_name(th->status); - VALUE str; - - str = rb_str_new(0, strlen(cname)+7+16+9+1); /* 7:tags 16:addr 9:status 1:nul */ - sprintf(RSTRING(str)->ptr, "#<%s:0x%lx %s>", cname, thread, status); - RSTRING(str)->len = strlen(RSTRING(str)->ptr); - OBJ_INFECT(str, thread); - - return str; -} - -void -rb_thread_atfork() -{ - rb_thread_t th; - - if (rb_thread_alone()) return; - FOREACH_THREAD(th) { - if (th != curr_thread) { - rb_thread_die(th); - } - } - END_FOREACH(th); - main_thread = curr_thread; - curr_thread->next = curr_thread; - curr_thread->prev = curr_thread; -} - - -/* - * Document-class: Continuation - * - * Continuation objects are generated by - * <code>Kernel#callcc</code>. They hold a return address and execution - * context, allowing a nonlocal return to the end of the - * <code>callcc</code> block from anywhere within a program. - * Continuations are somewhat analogous to a structured version of C's - * <code>setjmp/longjmp</code> (although they contain more state, so - * you might consider them closer to threads). - * - * For instance: - * - * arr = [ "Freddie", "Herbie", "Ron", "Max", "Ringo" ] - * callcc{|$cc|} - * puts(message = arr.shift) - * $cc.call unless message =~ /Max/ - * - * <em>produces:</em> - * - * Freddie - * Herbie - * Ron - * Max - * - * This (somewhat contrived) example allows the inner loop to abandon - * processing early: - * - * callcc {|cont| - * for i in 0..4 - * print "\n#{i}: " - * for j in i*5...(i+1)*5 - * cont.call() if j == 17 - * printf "%3d", j - * end - * end - * } - * print "\n" - * - * <em>produces:</em> - * - * 0: 0 1 2 3 4 - * 1: 5 6 7 8 9 - * 2: 10 11 12 13 14 - * 3: 15 16 - */ - -static VALUE rb_cCont; - -/* - * call-seq: - * callcc {|cont| block } => obj - * - * Generates a <code>Continuation</code> object, which it passes to the - * associated block. Performing a <em>cont</em><code>.call</code> will - * cause the <code>callcc</code> to return (as will falling through the - * end of the block). The value returned by the <code>callcc</code> is - * the value of the block, or the value passed to - * <em>cont</em><code>.call</code>. See class <code>Continuation</code> - * for more details. Also see <code>Kernel::throw</code> for - * an alternative mechanism for unwinding a call stack. - */ - -static VALUE -rb_callcc(self) - VALUE self; -{ - volatile VALUE cont; - rb_thread_t th; - volatile rb_thread_t th_save; - struct tag *tag; - struct RVarmap *vars; - - THREAD_ALLOC(th); - cont = Data_Wrap_Struct(rb_cCont, thread_mark, thread_free, th); - - scope_dup(ruby_scope); - for (tag=prot_tag; tag; tag=tag->prev) { - scope_dup(tag->scope); - } - th->thread = curr_thread->thread; - th->thgroup = cont_protect; - - for (vars = ruby_dyna_vars; vars; vars = vars->next) { - if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; - FL_SET(vars, DVAR_DONT_RECYCLE); - } - th_save = th; - if (THREAD_SAVE_CONTEXT(th)) { - return th_save->result; - } - else { - return rb_yield(cont); - } -} - -/* - * call-seq: - * cont.call(args, ...) - * cont[args, ...] - * - * Invokes the continuation. The program continues from the end of the - * <code>callcc</code> block. If no arguments are given, the original - * <code>callcc</code> returns <code>nil</code>. If one argument is - * given, <code>callcc</code> returns it. Otherwise, an array - * containing <i>args</i> is returned. - * - * callcc {|cont| cont.call } #=> nil - * callcc {|cont| cont.call 1 } #=> 1 - * callcc {|cont| cont.call 1, 2, 3 } #=> [1, 2, 3] - */ - -static VALUE -rb_cont_call(argc, argv, cont) - int argc; - VALUE *argv; - VALUE cont; -{ - rb_thread_t th = rb_thread_check(cont); - - if (th->thread != curr_thread->thread) { - rb_raise(rb_eRuntimeError, "continuation called across threads"); - } - if (th->thgroup != cont_protect) { - rb_raise(rb_eRuntimeError, "continuation called across trap"); - } - switch (argc) { - case 0: - th->result = Qnil; - break; - case 1: - th->result = argv[0]; - break; - default: - th->result = rb_ary_new4(argc, argv); - break; - } - - rb_thread_restore_context(th, RESTORE_NORMAL); - return Qnil; -} - -struct thgroup { - int enclosed; - VALUE group; -}; - - -/* - * Document-class: ThreadGroup - * - * <code>ThreadGroup</code> provides a means of keeping track of a number of - * threads as a group. A <code>Thread</code> can belong to only one - * <code>ThreadGroup</code> at a time; adding a thread to a new group will - * remove it from any previous group. - * - * Newly created threads belong to the same group as the thread from which they - * were created. - */ - -static VALUE thgroup_s_alloc _((VALUE)); -static VALUE -thgroup_s_alloc(klass) - VALUE klass; -{ - VALUE group; - struct thgroup *data; - - group = Data_Make_Struct(klass, struct thgroup, 0, free, data); - data->enclosed = 0; - data->group = group; - - return group; -} - - -/* - * call-seq: - * thgrp.list => array - * - * Returns an array of all existing <code>Thread</code> objects that belong to - * this group. - * - * ThreadGroup::Default.list #=> [#<Thread:0x401bdf4c run>] - */ - -static VALUE -thgroup_list(group) - VALUE group; -{ - struct thgroup *data; - rb_thread_t th; - VALUE ary; - - Data_Get_Struct(group, struct thgroup, data); - ary = rb_ary_new(); - - FOREACH_THREAD(th) { - if (th->thgroup == data->group) { - rb_ary_push(ary, th->thread); - } - } - END_FOREACH(th); - - return ary; -} - - -/* - * call-seq: - * thgrp.enclose => thgrp - * - * Prevents threads from being added to or removed from the receiving - * <code>ThreadGroup</code>. New threads can still be started in an enclosed - * <code>ThreadGroup</code>. - * - * ThreadGroup::Default.enclose #=> #<ThreadGroup:0x4029d914> - * thr = Thread::new { Thread.stop } #=> #<Thread:0x402a7210 sleep> - * tg = ThreadGroup::new #=> #<ThreadGroup:0x402752d4> - * tg.add thr - * - * <em>produces:</em> - * - * ThreadError: can't move from the enclosed thread group - */ - -VALUE -thgroup_enclose(group) - VALUE group; -{ - struct thgroup *data; - - Data_Get_Struct(group, struct thgroup, data); - data->enclosed = 1; - - return group; -} - - -/* - * call-seq: - * thgrp.enclosed? => true or false - * - * Returns <code>true</code> if <em>thgrp</em> is enclosed. See also - * ThreadGroup#enclose. - */ - -static VALUE -thgroup_enclosed_p(group) - VALUE group; -{ - struct thgroup *data; - - Data_Get_Struct(group, struct thgroup, data); - if (data->enclosed) return Qtrue; - return Qfalse; -} - - -/* - * call-seq: - * thgrp.add(thread) => thgrp - * - * Adds the given <em>thread</em> to this group, removing it from any other - * group to which it may have previously belonged. - * - * puts "Initial group is #{ThreadGroup::Default.list}" - * tg = ThreadGroup.new - * t1 = Thread.new { sleep } - * t2 = Thread.new { sleep } - * puts "t1 is #{t1}" - * puts "t2 is #{t2}" - * tg.add(t1) - * puts "Initial group now #{ThreadGroup::Default.list}" - * puts "tg group now #{tg.list}" - * - * <em>produces:</em> - * - * Initial group is #<Thread:0x401bdf4c> - * t1 is #<Thread:0x401b3c90> - * t2 is #<Thread:0x401b3c18> - * Initial group now #<Thread:0x401b3c18>#<Thread:0x401bdf4c> - * tg group now #<Thread:0x401b3c90> - */ - -static VALUE -thgroup_add(group, thread) - VALUE group, thread; -{ - rb_thread_t th; - struct thgroup *data; - - rb_secure(4); - th = rb_thread_check(thread); - if (!th->next || !th->prev) { - rb_raise(rb_eTypeError, "wrong argument type %s (expected Thread)", - rb_obj_classname(thread)); - } - - if (OBJ_FROZEN(group)) { - rb_raise(rb_eThreadError, "can't move to the frozen thread group"); - } - Data_Get_Struct(group, struct thgroup, data); - if (data->enclosed) { - rb_raise(rb_eThreadError, "can't move to the enclosed thread group"); - } - - if (!th->thgroup) { - return Qnil; - } - if (OBJ_FROZEN(th->thgroup)) { - rb_raise(rb_eThreadError, "can't move from the frozen thread group"); - } - Data_Get_Struct(th->thgroup, struct thgroup, data); - if (data->enclosed) { - rb_raise(rb_eThreadError, "can't move from the enclosed thread group"); - } - - th->thgroup = group; - return group; -} - -/* variables for recursive traversals */ -static ID recursive_key; -static VALUE recursive_tbl; - - -/* - * +Thread+ encapsulates the behavior of a thread of - * execution, including the main thread of the Ruby script. - * - * In the descriptions of the methods in this class, the parameter _sym_ - * refers to a symbol, which is either a quoted string or a - * +Symbol+ (such as <code>:name</code>). - */ - -void -Init_Thread() -{ - VALUE cThGroup; - - rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError); - rb_cThread = rb_define_class("Thread", rb_cObject); - rb_undef_alloc_func(rb_cThread); - - rb_define_singleton_method(rb_cThread, "new", rb_thread_s_new, -1); - rb_define_method(rb_cThread, "initialize", rb_thread_initialize, -2); - rb_define_singleton_method(rb_cThread, "start", rb_thread_start, -2); - rb_define_singleton_method(rb_cThread, "fork", rb_thread_start, -2); - - rb_define_singleton_method(rb_cThread, "stop", rb_thread_stop, 0); - rb_define_singleton_method(rb_cThread, "kill", rb_thread_s_kill, 1); - rb_define_singleton_method(rb_cThread, "exit", rb_thread_exit, 0); - rb_define_singleton_method(rb_cThread, "pass", rb_thread_pass, 0); - rb_define_singleton_method(rb_cThread, "current", rb_thread_current, 0); - rb_define_singleton_method(rb_cThread, "main", rb_thread_main, 0); - rb_define_singleton_method(rb_cThread, "list", rb_thread_list, 0); - - rb_define_singleton_method(rb_cThread, "critical", rb_thread_critical_get, 0); - rb_define_singleton_method(rb_cThread, "critical=", rb_thread_critical_set, 1); - - rb_define_singleton_method(rb_cThread, "abort_on_exception", rb_thread_s_abort_exc, 0); - rb_define_singleton_method(rb_cThread, "abort_on_exception=", rb_thread_s_abort_exc_set, 1); - - rb_define_method(rb_cThread, "run", rb_thread_run, 0); - rb_define_method(rb_cThread, "wakeup", rb_thread_wakeup, 0); - rb_define_method(rb_cThread, "kill", rb_thread_kill, 0); - rb_define_method(rb_cThread, "terminate", rb_thread_kill, 0); - rb_define_method(rb_cThread, "exit", rb_thread_kill, 0); - rb_define_method(rb_cThread, "value", rb_thread_value, 0); - rb_define_method(rb_cThread, "status", rb_thread_status, 0); - rb_define_method(rb_cThread, "join", rb_thread_join_m, -1); - rb_define_method(rb_cThread, "alive?", rb_thread_alive_p, 0); - rb_define_method(rb_cThread, "stop?", rb_thread_stop_p, 0); - rb_define_method(rb_cThread, "raise", rb_thread_raise_m, -1); - - rb_define_method(rb_cThread, "abort_on_exception", rb_thread_abort_exc, 0); - rb_define_method(rb_cThread, "abort_on_exception=", rb_thread_abort_exc_set, 1); - - rb_define_method(rb_cThread, "priority", rb_thread_priority, 0); - rb_define_method(rb_cThread, "priority=", rb_thread_priority_set, 1); - rb_define_method(rb_cThread, "safe_level", rb_thread_safe_level, 0); - rb_define_method(rb_cThread, "group", rb_thread_group, 0); - - rb_define_method(rb_cThread, "[]", rb_thread_aref, 1); - rb_define_method(rb_cThread, "[]=", rb_thread_aset, 2); - rb_define_method(rb_cThread, "key?", rb_thread_key_p, 1); - rb_define_method(rb_cThread, "keys", rb_thread_keys, 0); - - rb_define_method(rb_cThread, "inspect", rb_thread_inspect, 0); - - rb_cCont = rb_define_class("Continuation", rb_cObject); - rb_undef_alloc_func(rb_cCont); - rb_undef_method(CLASS_OF(rb_cCont), "new"); - rb_define_method(rb_cCont, "call", rb_cont_call, -1); - rb_define_method(rb_cCont, "[]", rb_cont_call, -1); - rb_define_global_function("callcc", rb_callcc, 0); - rb_global_variable(&cont_protect); - - cThGroup = rb_define_class("ThreadGroup", rb_cObject); - rb_define_alloc_func(cThGroup, thgroup_s_alloc); - rb_define_method(cThGroup, "list", thgroup_list, 0); - rb_define_method(cThGroup, "enclose", thgroup_enclose, 0); - rb_define_method(cThGroup, "enclosed?", thgroup_enclosed_p, 0); - rb_define_method(cThGroup, "add", thgroup_add, 1); - thgroup_default = rb_obj_alloc(cThGroup); - rb_define_const(cThGroup, "Default", thgroup_default); - rb_global_variable(&thgroup_default); - - /* allocate main thread */ - main_thread = rb_thread_alloc(rb_cThread); - curr_thread = main_thread->prev = main_thread->next = main_thread; - recursive_key = rb_intern("__recursive_key__"); -} - -/* - * call-seq: - * catch(symbol) {| | block } > obj - * - * +catch+ executes its block. If a +throw+ is - * executed, Ruby searches up its stack for a +catch+ block - * with a tag corresponding to the +throw+'s - * _symbol_. If found, that block is terminated, and - * +catch+ returns the value given to +throw+. If - * +throw+ is not called, the block terminates normally, and - * the value of +catch+ is the value of the last expression - * evaluated. +catch+ expressions may be nested, and the - * +throw+ call need not be in lexical scope. - * - * def routine(n) - * puts n - * throw :done if n <= 0 - * routine(n-1) - * end - * - * - * catch(:done) { routine(3) } - * - * <em>produces:</em> - * - * 3 - * 2 - * 1 - * 0 - */ - -static VALUE -rb_f_catch(dmy, tag) - VALUE dmy, tag; -{ - int state; - VALUE val = Qnil; /* OK */ - - tag = ID2SYM(rb_to_id(tag)); - PUSH_TAG(tag); - if ((state = EXEC_TAG()) == 0) { - val = rb_yield_0(tag, 0, 0, 0, Qfalse); - } - else if (state == TAG_THROW && tag == prot_tag->dst) { - val = prot_tag->retval; - state = 0; - } - POP_TAG(); - if (state) JUMP_TAG(state); - - return val; -} - -static VALUE -catch_i(tag) - VALUE tag; -{ - return rb_funcall(Qnil, rb_intern("catch"), 1, tag); -} - -VALUE -rb_catch(tag, func, data) - const char *tag; - VALUE (*func)(); - VALUE data; -{ - return rb_iterate((VALUE(*)_((VALUE)))catch_i, ID2SYM(rb_intern(tag)), func, data); -} - -/* - * call-seq: - * throw(symbol [, obj]) - * - * Transfers control to the end of the active +catch+ block - * waiting for _symbol_. Raises +NameError+ if there - * is no +catch+ block for the symbol. The optional second - * parameter supplies a return value for the +catch+ block, - * which otherwise defaults to +nil+. For examples, see - * <code>Kernel::catch</code>. - */ - -static VALUE -rb_f_throw(argc, argv) - int argc; - VALUE *argv; -{ - VALUE tag, value; - struct tag *tt = prot_tag; - - rb_scan_args(argc, argv, "11", &tag, &value); - tag = ID2SYM(rb_to_id(tag)); - - while (tt) { - if (tt->tag == tag) { - tt->dst = tag; - tt->retval = value; - break; - } - if (tt->tag == PROT_THREAD) { - rb_raise(rb_eThreadError, "uncaught throw `%s' in thread 0x%lx", - rb_id2name(SYM2ID(tag)), - curr_thread); - } - tt = tt->prev; - } - if (!tt) { - rb_name_error(SYM2ID(tag), "uncaught throw `%s'", rb_id2name(SYM2ID(tag))); - } - rb_trap_restore_mask(); - JUMP_TAG(TAG_THROW); -#ifndef __GNUC__ - return Qnil; /* not reached */ -#endif -} - -void -rb_throw(tag, val) - const char *tag; - VALUE val; -{ - VALUE argv[2]; - - argv[0] = ID2SYM(rb_intern(tag)); - argv[1] = val; - rb_f_throw(2, argv); -} - -static VALUE -recursive_check(obj) - VALUE obj; -{ - VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key); - - if (NIL_P(hash) || TYPE(hash) != T_HASH) { - return Qfalse; - } - else { - VALUE list = rb_hash_aref(hash, ID2SYM(ruby_frame->this_func)); - - if (NIL_P(list) || TYPE(list) != T_ARRAY) return Qfalse; - return rb_ary_includes(list, rb_obj_id(obj)); - } -} - -static void -recursive_push(obj) - VALUE obj; -{ - VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key); - VALUE list, sym; - - sym = ID2SYM(ruby_frame->this_func); - if (NIL_P(hash) || TYPE(hash) != T_HASH) { - hash = rb_hash_new(); - rb_thread_local_aset(rb_thread_current(), recursive_key, hash); - list = Qnil; - } - else { - list = rb_hash_aref(hash, sym); - } - if (NIL_P(list) || TYPE(list) != T_ARRAY) { - list = rb_ary_new(); - rb_hash_aset(hash, sym, list); - } - rb_ary_push(list, rb_obj_id(obj)); -} - -static void -recursive_pop() -{ - VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key); - VALUE list, sym; - - sym = ID2SYM(ruby_frame->this_func); - if (NIL_P(hash) || TYPE(hash) != T_HASH) { - VALUE symname = rb_inspect(sym); - VALUE thrname = rb_inspect(rb_thread_current()); - rb_raise(rb_eTypeError, "invalid inspect_tbl hash for %s in %s", - StringValuePtr(symname), StringValuePtr(thrname)); - } - list = rb_hash_aref(hash, sym); - if (NIL_P(list) || TYPE(list) != T_ARRAY) { - VALUE symname = rb_inspect(sym); - VALUE thrname = rb_inspect(rb_thread_current()); - rb_raise(rb_eTypeError, "invalid inspect_tbl list for %s in %s", - StringValuePtr(symname), StringValuePtr(thrname)); - } - rb_ary_pop(list); -} - -VALUE -rb_exec_recursive(func, obj, arg) - VALUE (*func)(ANYARGS); /* VALUE obj, VALUE arg, int flag */ - VALUE obj, arg; -{ - if (recursive_check(obj)) { - return (*func)(obj, arg, Qtrue); - } - else { - VALUE result; - int state; - - recursive_push(obj); - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - result = (*func)(obj, arg, Qfalse); - } - POP_TAG(); - recursive_pop(); - if (state) JUMP_TAG(state); - return result; - } -} -/********************************************************************** - - file.c - - - $Author: murphy $ - $Date: 2005-11-05 04:33:55 +0100 (Sa, 05 Nov 2005) $ - created at: Mon Nov 15 12:24:34 JST 1993 - - Copyright (C) 1993-2003 Yukihiro Matsumoto - Copyright (C) 2000 Network Applied Communication Laboratory, Inc. - Copyright (C) 2000 Information-technology Promotion Agency, Japan - -**********************************************************************/ - -#ifdef _WIN32 -#include "missing/file.h" -#endif - -#include "ruby.h" -#include "rubyio.h" -#include "rubysig.h" -#include "util.h" -#include "dln.h" - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#ifdef HAVE_SYS_FILE_H -# include <sys/file.h> -#else -int flock _((int, int)); -#endif - -#ifdef HAVE_SYS_PARAM_H -# include <sys/param.h> -#endif -#ifndef MAXPATHLEN -# define MAXPATHLEN 1024 -#endif - -#include <time.h> - -VALUE rb_time_new _((time_t, time_t)); - -#ifdef HAVE_UTIME_H -#include <utime.h> -#elif defined HAVE_SYS_UTIME_H -#include <sys/utime.h> -#endif - -#ifdef HAVE_PWD_H -#include <pwd.h> -#endif - -#ifndef HAVE_STRING_H -char *strrchr _((const char*,const char)); -#endif - -#include <sys/types.h> -#include <sys/stat.h> - -#ifdef HAVE_SYS_MKDEV_H -#include <sys/mkdev.h> -#endif - -#if !defined HAVE_LSTAT && !defined lstat -#define lstat stat -#endif - -VALUE rb_cFile; -VALUE rb_mFileTest; -static VALUE rb_cStat; - -VALUE -rb_get_path(obj) - VALUE obj; -{ - VALUE tmp; - static ID to_path; - - rb_check_safe_obj(obj); - tmp = rb_check_string_type(obj); - if (!NIL_P(tmp)) goto exit; - - if (!to_path) { - to_path = rb_intern("to_path"); - } - if (rb_respond_to(obj, to_path)) { - obj = rb_funcall(obj, to_path, 0, 0); - } - tmp = rb_str_to_str(obj); - exit: - if (obj != tmp) { - rb_check_safe_obj(tmp); - } - return tmp; -} - -static long -apply2files(func, vargs, arg) - void (*func)(); - VALUE vargs; - void *arg; -{ - long i; - VALUE path; - struct RArray *args = RARRAY(vargs); - - rb_secure(4); - for (i=0; i<args->len; i++) { - path = rb_get_path(args->ptr[i]); - (*func)(StringValueCStr(path), arg); - } - - return args->len; -} - -/* - * call-seq: - * file.path -> filename - * - * Returns the pathname used to create <i>file</i> as a string. Does - * not normalize the name. - * - * File.new("testfile").path #=> "testfile" - * File.new("/tmp/../tmp/xxx", "w").path #=> "/tmp/../tmp/xxx" - * - */ - -static VALUE -rb_file_path(obj) - VALUE obj; -{ - OpenFile *fptr; - - fptr = RFILE(rb_io_taint_check(obj))->fptr; - rb_io_check_initialized(fptr); - if (!fptr->path) return Qnil; - return rb_tainted_str_new2(fptr->path); -} - -static VALUE -stat_new_0(klass, st) - VALUE klass; - struct stat *st; -{ - struct stat *nst = 0; - - if (st) { - nst = ALLOC(struct stat); - *nst = *st; - } - return Data_Wrap_Struct(klass, NULL, free, nst); -} - -static VALUE -stat_new(st) - struct stat *st; -{ - return stat_new_0(rb_cStat, st); -} - -static struct stat* -get_stat(self) - VALUE self; -{ - struct stat* st; - Data_Get_Struct(self, struct stat, st); - if (!st) rb_raise(rb_eTypeError, "uninitialized File::Stat"); - return st; -} - -/* - * call-seq: - * stat <=> other_stat => -1, 0, 1 - * - * Compares <code>File::Stat</code> objects by comparing their - * respective modification times. - * - * f1 = File.new("f1", "w") - * sleep 1 - * f2 = File.new("f2", "w") - * f1.stat <=> f2.stat #=> -1 - */ - -static VALUE -rb_stat_cmp(self, other) - VALUE self, other; -{ - if (rb_obj_is_kind_of(other, rb_obj_class(self))) { - time_t t1 = get_stat(self)->st_mtime; - time_t t2 = get_stat(other)->st_mtime; - if (t1 == t2) - return INT2FIX(0); - else if (t1 < t2) - return INT2FIX(-1); - else - return INT2FIX(1); - } - return Qnil; -} - -/* - * call-seq: - * stat.dev => fixnum - * - * Returns an integer representing the device on which <i>stat</i> - * resides. - * - * File.stat("testfile").dev #=> 774 - */ - -static VALUE -rb_stat_dev(self) - VALUE self; -{ - return INT2NUM(get_stat(self)->st_dev); -} - -/* - * call-seq: - * stat.dev_major => fixnum - * - * Returns the major part of <code>File_Stat#dev</code> or - * <code>nil</code>. - * - * File.stat("/dev/fd1").dev_major #=> 2 - * File.stat("/dev/tty").dev_major #=> 5 - */ - -static VALUE -rb_stat_dev_major(self) - VALUE self; -{ -#if defined(major) - long dev = get_stat(self)->st_dev; - return ULONG2NUM(major(dev)); -#else - return Qnil; -#endif -} - -/* - * call-seq: - * stat.dev_minor => fixnum - * - * Returns the minor part of <code>File_Stat#dev</code> or - * <code>nil</code>. - * - * File.stat("/dev/fd1").dev_minor #=> 1 - * File.stat("/dev/tty").dev_minor #=> 0 - */ - -static VALUE -rb_stat_dev_minor(self) - VALUE self; -{ -#if defined(minor) - long dev = get_stat(self)->st_dev; - return ULONG2NUM(minor(dev)); -#else - return Qnil; -#endif -} - - -/* - * call-seq: - * stat.ino => fixnum - * - * Returns the inode number for <i>stat</i>. - * - * File.stat("testfile").ino #=> 1083669 - * - */ - -static VALUE -rb_stat_ino(self) - VALUE self; -{ -#ifdef HUGE_ST_INO - return ULL2NUM(get_stat(self)->st_ino); -#else - return ULONG2NUM(get_stat(self)->st_ino); -#endif -} - -/* - * call-seq: - * stat.mode => fixnum - * - * Returns an integer representing the permission bits of - * <i>stat</i>. The meaning of the bits is platform dependent; on - * Unix systems, see <code>stat(2)</code>. - * - * File.chmod(0644, "testfile") #=> 1 - * s = File.stat("testfile") - * sprintf("%o", s.mode) #=> "100644" - */ - -static VALUE -rb_stat_mode(self) - VALUE self; -{ -#ifdef __BORLANDC__ - return UINT2NUM((unsigned short)(get_stat(self)->st_mode)); -#else - return UINT2NUM(get_stat(self)->st_mode); -#endif -} - -/* - * call-seq: - * stat.nlink => fixnum - * - * Returns the number of hard links to <i>stat</i>. - * - * File.stat("testfile").nlink #=> 1 - * File.link("testfile", "testfile.bak") #=> 0 - * File.stat("testfile").nlink #=> 2 - * - */ - -static VALUE -rb_stat_nlink(self) - VALUE self; -{ - return UINT2NUM(get_stat(self)->st_nlink); -} - - -/* - * call-seq: - * stat.uid => fixnum - * - * Returns the numeric user id of the owner of <i>stat</i>. - * - * File.stat("testfile").uid #=> 501 - * - */ - -static VALUE -rb_stat_uid(self) - VALUE self; -{ - return UINT2NUM(get_stat(self)->st_uid); -} - -/* - * call-seq: - * stat.gid => fixnum - * - * Returns the numeric group id of the owner of <i>stat</i>. - * - * File.stat("testfile").gid #=> 500 - * - */ - -static VALUE -rb_stat_gid(self) - VALUE self; -{ - return UINT2NUM(get_stat(self)->st_gid); -} - - -/* - * call-seq: - * stat.rdev => fixnum or nil - * - * Returns an integer representing the device type on which - * <i>stat</i> resides. Returns <code>nil</code> if the operating - * system doesn't support this feature. - * - * File.stat("/dev/fd1").rdev #=> 513 - * File.stat("/dev/tty").rdev #=> 1280 - */ - -static VALUE -rb_stat_rdev(self) - VALUE self; -{ -#ifdef HAVE_ST_RDEV - return ULONG2NUM(get_stat(self)->st_rdev); -#else - return Qnil; -#endif -} - -/* - * call-seq: - * stat.rdev_major => fixnum - * - * Returns the major part of <code>File_Stat#rdev</code> or - * <code>nil</code>. - * - * File.stat("/dev/fd1").rdev_major #=> 2 - * File.stat("/dev/tty").rdev_major #=> 5 - */ - -static VALUE -rb_stat_rdev_major(self) - VALUE self; -{ -#if defined(HAVE_ST_RDEV) && defined(major) - long rdev = get_stat(self)->st_rdev; - return ULONG2NUM(major(rdev)); -#else - return Qnil; -#endif -} - -/* - * call-seq: - * stat.rdev_minor => fixnum - * - * Returns the minor part of <code>File_Stat#rdev</code> or - * <code>nil</code>. - * - * File.stat("/dev/fd1").rdev_minor #=> 1 - * File.stat("/dev/tty").rdev_minor #=> 0 - */ - -static VALUE -rb_stat_rdev_minor(self) - VALUE self; -{ -#if defined(HAVE_ST_RDEV) && defined(minor) - long rdev = get_stat(self)->st_rdev; - return ULONG2NUM(minor(rdev)); -#else - return Qnil; -#endif -} - -/* - * call-seq: - * stat.size => fixnum - * - * Returns the size of <i>stat</i> in bytes. - * - * File.stat("testfile").size #=> 66 - */ - -static VALUE -rb_stat_size(self) - VALUE self; -{ - return OFFT2NUM(get_stat(self)->st_size); -} - -/* - * call-seq: - * stat.blksize => integer or nil - * - * Returns the native file system's block size. Will return <code>nil</code> - * on platforms that don't support this information. - * - * File.stat("testfile").blksize #=> 4096 - * - */ - -static VALUE -rb_stat_blksize(self) - VALUE self; -{ -#ifdef HAVE_ST_BLKSIZE - return ULONG2NUM(get_stat(self)->st_blksize); -#else - return Qnil; -#endif -} - -/* - * call-seq: - * stat.blocks => integer or nil - * - * Returns the number of native file system blocks allocated for this - * file, or <code>nil</code> if the operating system doesn't - * support this feature. - * - * File.stat("testfile").blocks #=> 2 - */ - -static VALUE -rb_stat_blocks(self) - VALUE self; -{ -#ifdef HAVE_ST_BLOCKS - return ULONG2NUM(get_stat(self)->st_blocks); -#else - return Qnil; -#endif -} - - -/* - * call-seq: - * stat.atime => time - * - * Returns the last access time for this file as an object of class - * <code>Time</code>. - * - * File.stat("testfile").atime #=> Wed Dec 31 18:00:00 CST 1969 - * - */ - -static VALUE -rb_stat_atime(self) - VALUE self; -{ - return rb_time_new(get_stat(self)->st_atime, 0); -} - -/* - * call-seq: - * stat.mtime -> aTime - * - * Returns the modification time of <i>stat</i>. - * - * File.stat("testfile").mtime #=> Wed Apr 09 08:53:14 CDT 2003 - * - */ - -static VALUE -rb_stat_mtime(self) - VALUE self; -{ - return rb_time_new(get_stat(self)->st_mtime, 0); -} - -/* - * call-seq: - * stat.ctime -> aTime - * - * Returns the change time for <i>stat</i> (that is, the time - * directory information about the file was changed, not the file - * itself). - * - * File.stat("testfile").ctime #=> Wed Apr 09 08:53:14 CDT 2003 - * - */ - -static VALUE -rb_stat_ctime(self) - VALUE self; -{ - return rb_time_new(get_stat(self)->st_ctime, 0); -} - -/* - * call-seq: - * stat.inspect => string - * - * Produce a nicely formatted description of <i>stat</i>. - * - * File.stat("/etc/passwd").inspect - * #=> "#<File::Stat dev=0xe000005, ino=1078078, mode=0100644, - * nlink=1, uid=0, gid=0, rdev=0x0, size=1374, blksize=4096, - * blocks=8, atime=Wed Dec 10 10:16:12 CST 2003, - * mtime=Fri Sep 12 15:41:41 CDT 2003, - * ctime=Mon Oct 27 11:20:27 CST 2003>" - */ - -static VALUE -rb_stat_inspect(self) - VALUE self; -{ - VALUE str; - int i; - static struct { - char *name; - VALUE (*func)(); - } member[] = { - {"dev", rb_stat_dev}, - {"ino", rb_stat_ino}, - {"mode", rb_stat_mode}, - {"nlink", rb_stat_nlink}, - {"uid", rb_stat_uid}, - {"gid", rb_stat_gid}, - {"rdev", rb_stat_rdev}, - {"size", rb_stat_size}, - {"blksize", rb_stat_blksize}, - {"blocks", rb_stat_blocks}, - {"atime", rb_stat_atime}, - {"mtime", rb_stat_mtime}, - {"ctime", rb_stat_ctime}, - }; - - str = rb_str_buf_new2("#<"); - rb_str_buf_cat2(str, rb_obj_classname(self)); - rb_str_buf_cat2(str, " "); - - for (i = 0; i < sizeof(member)/sizeof(member[0]); i++) { - VALUE v; - - if (i > 0) { - rb_str_buf_cat2(str, ", "); - } - rb_str_buf_cat2(str, member[i].name); - rb_str_buf_cat2(str, "="); - v = (*member[i].func)(self); - if (i == 2) { /* mode */ - char buf[32]; - - sprintf(buf, "0%lo", NUM2ULONG(v)); - rb_str_buf_cat2(str, buf); - } - else if (i == 0 || i == 6) { /* dev/rdev */ - char buf[32]; - - sprintf(buf, "0x%lx", NUM2ULONG(v)); - rb_str_buf_cat2(str, buf); - } - else { - rb_str_append(str, rb_inspect(v)); - } - } - rb_str_buf_cat2(str, ">"); - OBJ_INFECT(str, self); - - return str; -} - -static int -rb_stat(file, st) - VALUE file; - struct stat *st; -{ - VALUE tmp; - - rb_secure(2); - tmp = rb_check_convert_type(file, T_FILE, "IO", "to_io"); - if (!NIL_P(tmp)) { - OpenFile *fptr; - - GetOpenFile(tmp, fptr); - return fstat(fptr->fd, st); - } - FilePathValue(file); - return stat(StringValueCStr(file), st); -} - -/* - * call-seq: - * File.stat(file_name) => stat - * - * Returns a <code>File::Stat</code> object for the named file (see - * <code>File::Stat</code>). - * - * File.stat("testfile").mtime #=> Tue Apr 08 12:58:04 CDT 2003 - * - */ - -static VALUE -rb_file_s_stat(klass, fname) - VALUE klass, fname; -{ - struct stat st; - - rb_secure(4); - FilePathValue(fname); - if (rb_stat(fname, &st) < 0) { - rb_sys_fail(StringValueCStr(fname)); - } - return stat_new(&st); -} - -/* - * call-seq: - * ios.stat => stat - * - * Returns status information for <em>ios</em> as an object of type - * <code>File::Stat</code>. - * - * f = File.new("testfile") - * s = f.stat - * "%o" % s.mode #=> "100644" - * s.blksize #=> 4096 - * s.atime #=> Wed Apr 09 08:53:54 CDT 2003 - * - */ - -static VALUE -rb_io_stat(obj) - VALUE obj; -{ - OpenFile *fptr; - struct stat st; - - GetOpenFile(obj, fptr); - if (fstat(fptr->fd, &st) == -1) { - rb_sys_fail(fptr->path); - } - return stat_new(&st); -} - -/* - * call-seq: - * File.lstat(file_name) => stat - * - * Same as <code>File::stat</code>, but does not follow the last symbolic - * link. Instead, reports on the link itself. - * - * File.symlink("testfile", "link2test") #=> 0 - * File.stat("testfile").size #=> 66 - * File.lstat("link2test").size #=> 8 - * File.stat("link2test").size #=> 66 - * - */ - -static VALUE -rb_file_s_lstat(klass, fname) - VALUE klass, fname; -{ -#ifdef HAVE_LSTAT - struct stat st; - - rb_secure(2); - FilePathValue(fname); - if (lstat(StringValueCStr(fname), &st) == -1) { - rb_sys_fail(RSTRING(fname)->ptr); - } - return stat_new(&st); -#else - return rb_file_s_stat(klass, fname); -#endif -} - - -/* - * call-seq: - * file.lstat => stat - * - * Same as <code>IO#stat</code>, but does not follow the last symbolic - * link. Instead, reports on the link itself. - * - * File.symlink("testfile", "link2test") #=> 0 - * File.stat("testfile").size #=> 66 - * f = File.new("link2test") - * f.lstat.size #=> 8 - * f.stat.size #=> 66 - */ - -static VALUE -rb_file_lstat(obj) - VALUE obj; -{ -#ifdef HAVE_LSTAT - OpenFile *fptr; - struct stat st; - - rb_secure(2); - GetOpenFile(obj, fptr); - if (!fptr->path) return Qnil; - if (lstat(fptr->path, &st) == -1) { - rb_sys_fail(fptr->path); - } - return stat_new(&st); -#else - return rb_io_stat(obj); -#endif -} - -static int -group_member(gid) - GETGROUPS_T gid; -{ -#ifndef _WIN32 - if (getgid() == gid) - return Qtrue; - -# ifdef HAVE_GETGROUPS -# ifndef NGROUPS -# ifdef NGROUPS_MAX -# define NGROUPS NGROUPS_MAX -# else -# define NGROUPS 32 -# endif -# endif - { - GETGROUPS_T gary[NGROUPS]; - int anum; - - anum = getgroups(NGROUPS, gary); - while (--anum >= 0) - if (gary[anum] == gid) - return Qtrue; - } -# endif -#endif - return Qfalse; -} - -#ifndef S_IXUGO -# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) -#endif - -int -eaccess(path, mode) - const char *path; - int mode; -{ -#if defined(S_IXGRP) && !defined(_WIN32) && !defined(__CYGWIN__) - struct stat st; - int euid; - - if (stat(path, &st) < 0) return -1; - - euid = geteuid(); - - if (euid == 0) { - /* Root can read or write any file. */ - if (!(mode & X_OK)) - return 0; - - /* Root can execute any file that has any one of the execute - bits set. */ - if (st.st_mode & S_IXUGO) - return 0; - - return -1; - } - - if (st.st_uid == euid) /* owner */ - mode <<= 6; - else if (getegid() == st.st_gid || group_member(st.st_gid)) - mode <<= 3; - - if ((st.st_mode & mode) == mode) return 0; - - return -1; -#else -# if _MSC_VER >= 1400 - mode &= 6; -# endif - return access(path, mode); -#endif -} - - -/* - * Document-class: FileTest - * - * <code>FileTest</code> implements file test operations similar to - * those used in <code>File::Stat</code>. It exists as a standalone - * module, and its methods are also insinuated into the <code>File</code> - * class. (Note that this is not done by inclusion: the interpreter cheats). - * - */ - - -/* - * call-seq: - * File.directory?(file_name) => true or false - * - * Returns <code>true</code> if the named file is a directory, - * <code>false</code> otherwise. - * - * File.directory?(".") - */ - -static VALUE -test_d(obj, fname) - VALUE obj, fname; -{ -#ifndef S_ISDIR -# define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) -#endif - - struct stat st; - - if (rb_stat(fname, &st) < 0) return Qfalse; - if (S_ISDIR(st.st_mode)) return Qtrue; - return Qfalse; -} - -/* - * call-seq: - * File.pipe?(file_name) => true or false - * - * Returns <code>true</code> if the named file is a pipe. - */ - -static VALUE -test_p(obj, fname) - VALUE obj, fname; -{ -#ifdef S_IFIFO -# ifndef S_ISFIFO -# define S_ISFIFO(m) ((m & S_IFMT) == S_IFIFO) -# endif - - struct stat st; - - if (rb_stat(fname, &st) < 0) return Qfalse; - if (S_ISFIFO(st.st_mode)) return Qtrue; - -#endif - return Qfalse; -} - -/* - * call-seq: - * File.symlink?(file_name) => true or false - * - * Returns <code>true</code> if the named file is a symbolic link. - */ - -static VALUE -test_l(obj, fname) - VALUE obj, fname; -{ -#ifndef S_ISLNK -# ifdef _S_ISLNK -# define S_ISLNK(m) _S_ISLNK(m) -# else -# ifdef _S_IFLNK -# define S_ISLNK(m) ((m & S_IFMT) == _S_IFLNK) -# else -# ifdef S_IFLNK -# define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK) -# endif -# endif -# endif -#endif - -#ifdef S_ISLNK - struct stat st; - - rb_secure(2); - FilePathValue(fname); - if (lstat(StringValueCStr(fname), &st) < 0) return Qfalse; - if (S_ISLNK(st.st_mode)) return Qtrue; -#endif - - return Qfalse; -} - -/* - * call-seq: - * File.socket?(file_name) => true or false - * - * Returns <code>true</code> if the named file is a socket. - */ - -static VALUE -test_S(obj, fname) - VALUE obj, fname; -{ -#ifndef S_ISSOCK -# ifdef _S_ISSOCK -# define S_ISSOCK(m) _S_ISSOCK(m) -# else -# ifdef _S_IFSOCK -# define S_ISSOCK(m) ((m & S_IFMT) == _S_IFSOCK) -# else -# ifdef S_IFSOCK -# define S_ISSOCK(m) ((m & S_IFMT) == S_IFSOCK) -# endif -# endif -# endif -#endif - -#ifdef S_ISSOCK - struct stat st; - - if (rb_stat(fname, &st) < 0) return Qfalse; - if (S_ISSOCK(st.st_mode)) return Qtrue; - -#endif - return Qfalse; -} - -/* - * call-seq: - * File.blockdev?(file_name) => true or false - * - * Returns <code>true</code> if the named file is a block device. - */ - -static VALUE -test_b(obj, fname) - VALUE obj, fname; -{ -#ifndef S_ISBLK -# ifdef S_IFBLK -# define S_ISBLK(m) ((m & S_IFMT) == S_IFBLK) -# else -# define S_ISBLK(m) (0) /* anytime false */ -# endif -#endif - -#ifdef S_ISBLK - struct stat st; - - if (rb_stat(fname, &st) < 0) return Qfalse; - if (S_ISBLK(st.st_mode)) return Qtrue; - -#endif - return Qfalse; -} - -/* - * call-seq: - * File.chardev?(file_name) => true or false - * - * Returns <code>true</code> if the named file is a character device. - */ -static VALUE -test_c(obj, fname) - VALUE obj, fname; -{ -#ifndef S_ISCHR -# define S_ISCHR(m) ((m & S_IFMT) == S_IFCHR) -#endif - - struct stat st; - - if (rb_stat(fname, &st) < 0) return Qfalse; - if (S_ISCHR(st.st_mode)) return Qtrue; - - return Qfalse; -} - - -/* - * call-seq: - * File.exist?(file_name) => true or false - * File.exists?(file_name) => true or false (obsolete) - * - * Return <code>true</code> if the named file exists. - */ - -static VALUE -test_e(obj, fname) - VALUE obj, fname; -{ - struct stat st; - - if (rb_stat(fname, &st) < 0) return Qfalse; - return Qtrue; -} - -/* - * call-seq: - * File.readable?(file_name) => true or false - * - * Returns <code>true</code> if the named file is readable by the effective - * user id of this process. - */ - -static VALUE -test_r(obj, fname) - VALUE obj, fname; -{ - rb_secure(2); - FilePathValue(fname); - if (eaccess(StringValueCStr(fname), R_OK) < 0) return Qfalse; - return Qtrue; -} - -/* - * call-seq: - * File.readable_real?(file_name) => true or false - * - * Returns <code>true</code> if the named file is readable by the real - * user id of this process. - */ - -static VALUE -test_R(obj, fname) - VALUE obj, fname; -{ - rb_secure(2); - FilePathValue(fname); - if (access(StringValueCStr(fname), R_OK) < 0) return Qfalse; - return Qtrue; -} - -#ifndef S_IRUGO -# define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH) -#endif - -#ifndef S_IWUGO -# define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH) -#endif - -/* - * call-seq: - * File.world_readable?(file_name) => fixnum or nil - * - * If <i>file_name</i> is readable by others, returns an integer - * representing the file permission bits of <i>file_name</i>. Returns - * <code>nil</code> otherwise. The meaning of the bits is platform - * dependent; on Unix systems, see <code>stat(2)</code>. - * - * File.world_readable?("/etc/passwd") # => 420 - * m = File.world_readable?("/etc/passwd") - * sprintf("%o", m) # => "644" - */ - -static VALUE -test_wr(obj, fname) - VALUE obj, fname; -{ -#ifdef S_IROTH - struct stat st; - - if (rb_stat(fname, &st) < 0) return Qnil; - if ((st.st_mode & (S_IROTH)) == S_IROTH) { - return UINT2NUM(st.st_mode & (S_IRUGO|S_IWUGO|S_IXUGO)); - } -#endif - return Qnil; -} - -/* - * call-seq: - * File.writable?(file_name) => true or false - * - * Returns <code>true</code> if the named file is writable by the effective - * user id of this process. - */ - -static VALUE -test_w(obj, fname) - VALUE obj, fname; -{ - rb_secure(2); - FilePathValue(fname); - if (eaccess(StringValueCStr(fname), W_OK) < 0) return Qfalse; - return Qtrue; -} - -/* - * call-seq: - * File.writable_real?(file_name) => true or false - * - * Returns <code>true</code> if the named file is writable by the real - * user id of this process. - */ - -static VALUE -test_W(obj, fname) - VALUE obj, fname; -{ - rb_secure(2); - FilePathValue(fname); - if (access(StringValueCStr(fname), W_OK) < 0) return Qfalse; - return Qtrue; -} - -/* - * call-seq: - * File.world_writable?(file_name) => fixnum or nil - * - * If <i>file_name</i> is writable by others, returns an integer - * representing the file permission bits of <i>file_name</i>. Returns - * <code>nil</code> otherwise. The meaning of the bits is platform - * dependent; on Unix systems, see <code>stat(2)</code>. - * - * File.world_writable?("/tmp") #=> 511 - * m = File.world_writable?("/tmp") - * sprintf("%o", m) #=> "777" - */ - -static VALUE -test_ww(obj, fname) - VALUE obj, fname; -{ -#ifdef S_IWOTH - struct stat st; - - if (rb_stat(fname, &st) < 0) return Qfalse; - if ((st.st_mode & (S_IWOTH)) == S_IWOTH) { - return UINT2NUM(st.st_mode & (S_IRUGO|S_IWUGO|S_IXUGO)); - } -#endif - return Qnil; -} - -/* - * call-seq: - * File.executable?(file_name) => true or false - * - * Returns <code>true</code> if the named file is executable by the effective - * user id of this process. - */ - -static VALUE -test_x(obj, fname) - VALUE obj, fname; -{ - rb_secure(2); - FilePathValue(fname); - if (eaccess(StringValueCStr(fname), X_OK) < 0) return Qfalse; - return Qtrue; -} - -/* - * call-seq: - * File.executable_real?(file_name) => true or false - * - * Returns <code>true</code> if the named file is executable by the real - * user id of this process. - */ - -static VALUE -test_X(obj, fname) - VALUE obj, fname; -{ - rb_secure(2); - FilePathValue(fname); - if (access(StringValueCStr(fname), X_OK) < 0) return Qfalse; - return Qtrue; -} - -#ifndef S_ISREG -# define S_ISREG(m) ((m & S_IFMT) == S_IFREG) -#endif - -/* - * call-seq: - * File.file?(file_name) => true or false - * - * Returns <code>true</code> if the named file exists and is a - * regular file. - */ - -static VALUE -test_f(obj, fname) - VALUE obj, fname; -{ - struct stat st; - - if (rb_stat(fname, &st) < 0) return Qfalse; - if (S_ISREG(st.st_mode)) return Qtrue; - return Qfalse; -} - -/* - * call-seq: - * File.zero?(file_name) => true or false - * - * Returns <code>true</code> if the named file exists and has - * a zero size. - */ - -static VALUE -test_z(obj, fname) - VALUE obj, fname; -{ - struct stat st; - - if (rb_stat(fname, &st) < 0) return Qfalse; - if (st.st_size == 0) return Qtrue; - return Qfalse; -} - -/* - * call-seq: - * File.file?(file_name) => integer or nil - * - * Returns <code>nil</code> if <code>file_name</code> doesn't - * exist or has zero size, the size of the file otherwise. - */ - -static VALUE -test_s(obj, fname) - VALUE obj, fname; -{ - struct stat st; - - if (rb_stat(fname, &st) < 0) return Qnil; - if (st.st_size == 0) return Qnil; - return OFFT2NUM(st.st_size); -} - -/* - * call-seq: - * File.owned?(file_name) => true or false - * - * Returns <code>true</code> if the named file exists and the - * effective used id of the calling process is the owner of - * the file. - */ - -static VALUE -test_owned(obj, fname) - VALUE obj, fname; -{ - struct stat st; - - if (rb_stat(fname, &st) < 0) return Qfalse; - if (st.st_uid == geteuid()) return Qtrue; - return Qfalse; -} - -static VALUE -test_rowned(obj, fname) - VALUE obj, fname; -{ - struct stat st; - - if (rb_stat(fname, &st) < 0) return Qfalse; - if (st.st_uid == getuid()) return Qtrue; - return Qfalse; -} - -/* - * call-seq: - * File.grpowned?(file_name) => true or false - * - * Returns <code>true</code> if the named file exists and the - * effective group id of the calling process is the owner of - * the file. Returns <code>false</code> on Windows. - */ - -static VALUE -test_grpowned(obj, fname) - VALUE obj, fname; -{ -#ifndef _WIN32 - struct stat st; - - if (rb_stat(fname, &st) < 0) return Qfalse; - if (st.st_gid == getegid()) return Qtrue; -#endif - return Qfalse; -} - -#if defined(S_ISUID) || defined(S_ISGID) || defined(S_ISVTX) -static VALUE -check3rdbyte(fname, mode) - VALUE fname; - int mode; -{ - struct stat st; - - rb_secure(2); - FilePathValue(fname); - if (stat(StringValueCStr(fname), &st) < 0) return Qfalse; - if (st.st_mode & mode) return Qtrue; - return Qfalse; -} -#endif - -/* - * call-seq: - * File.setuid?(file_name) => true or false - * - * Returns <code>true</code> if the named file is a has the setuid bit set. - */ - -static VALUE -test_suid(obj, fname) - VALUE obj, fname; -{ -#ifdef S_ISUID - return check3rdbyte(fname, S_ISUID); -#else - return Qfalse; -#endif -} - -/* - * call-seq: - * File.setgid?(file_name) => true or false - * - * Returns <code>true</code> if the named file is a has the setgid bit set. - */ - -static VALUE -test_sgid(obj, fname) - VALUE obj, fname; -{ -#ifdef S_ISGID - return check3rdbyte(fname, S_ISGID); -#else - return Qfalse; -#endif -} - -/* - * call-seq: - * File.sticky?(file_name) => true or false - * - * Returns <code>true</code> if the named file is a has the sticky bit set. - */ - -static VALUE -test_sticky(obj, fname) - VALUE obj, fname; -{ -#ifdef S_ISVTX - return check3rdbyte(fname, S_ISVTX); -#else - return Qnil; -#endif -} - -/* - * call-seq: - * File.size(file_name) => integer - * - * Returns the size of <code>file_name</code>. - */ - -static VALUE -rb_file_s_size(klass, fname) - VALUE klass, fname; -{ - struct stat st; - - if (rb_stat(fname, &st) < 0) - rb_sys_fail(StringValueCStr(fname)); - return OFFT2NUM(st.st_size); -} - -static VALUE -rb_file_ftype(st) - struct stat *st; -{ - char *t; - - if (S_ISREG(st->st_mode)) { - t = "file"; - } - else if (S_ISDIR(st->st_mode)) { - t = "directory"; - } - else if (S_ISCHR(st->st_mode)) { - t = "characterSpecial"; - } -#ifdef S_ISBLK - else if (S_ISBLK(st->st_mode)) { - t = "blockSpecial"; - } -#endif -#ifdef S_ISFIFO - else if (S_ISFIFO(st->st_mode)) { - t = "fifo"; - } -#endif -#ifdef S_ISLNK - else if (S_ISLNK(st->st_mode)) { - t = "link"; - } -#endif -#ifdef S_ISSOCK - else if (S_ISSOCK(st->st_mode)) { - t = "socket"; - } -#endif - else { - t = "unknown"; - } - - return rb_str_new2(t); -} - -/* - * call-seq: - * File.ftype(file_name) => string - * - * Identifies the type of the named file; the return string is one of - * ``<code>file</code>'', ``<code>directory</code>'', - * ``<code>characterSpecial</code>'', ``<code>blockSpecial</code>'', - * ``<code>fifo</code>'', ``<code>link</code>'', - * ``<code>socket</code>'', or ``<code>unknown</code>''. - * - * File.ftype("testfile") #=> "file" - * File.ftype("/dev/tty") #=> "characterSpecial" - * File.ftype("/tmp/.X11-unix/X0") #=> "socket" - */ - -static VALUE -rb_file_s_ftype(klass, fname) - VALUE klass, fname; -{ - struct stat st; - - rb_secure(2); - FilePathValue(fname); - if (lstat(StringValueCStr(fname), &st) == -1) { - rb_sys_fail(RSTRING(fname)->ptr); - } - - return rb_file_ftype(&st); -} - -/* - * call-seq: - * File.atime(file_name) => time - * - * Returns the last access time for the named file as a Time object). - * - * File.atime("testfile") #=> Wed Apr 09 08:51:48 CDT 2003 - * - */ - -static VALUE -rb_file_s_atime(klass, fname) - VALUE klass, fname; -{ - struct stat st; - - if (rb_stat(fname, &st) < 0) - rb_sys_fail(StringValueCStr(fname)); - return rb_time_new(st.st_atime, 0); -} - -/* - * call-seq: - * file.atime => time - * - * Returns the last access time (a <code>Time</code> object) - * for <i>file</i>, or epoch if <i>file</i> has not been accessed. - * - * File.new("testfile").atime #=> Wed Dec 31 18:00:00 CST 1969 - * - */ - -static VALUE -rb_file_atime(obj) - VALUE obj; -{ - OpenFile *fptr; - struct stat st; - - GetOpenFile(obj, fptr); - if (fstat(fptr->fd, &st) == -1) { - rb_sys_fail(fptr->path); - } - return rb_time_new(st.st_atime, 0); -} - -/* - * call-seq: - * File.mtime(file_name) => time - * - * Returns the modification time for the named file as a Time object. - * - * File.mtime("testfile") #=> Tue Apr 08 12:58:04 CDT 2003 - * - */ - -static VALUE -rb_file_s_mtime(klass, fname) - VALUE klass, fname; -{ - struct stat st; - - if (rb_stat(fname, &st) < 0) - rb_sys_fail(RSTRING(fname)->ptr); - return rb_time_new(st.st_mtime, 0); -} - -/* - * call-seq: - * file.mtime -> time - * - * Returns the modification time for <i>file</i>. - * - * File.new("testfile").mtime #=> Wed Apr 09 08:53:14 CDT 2003 - * - */ - -static VALUE -rb_file_mtime(obj) - VALUE obj; -{ - OpenFile *fptr; - struct stat st; - - GetOpenFile(obj, fptr); - if (fstat(fptr->fd, &st) == -1) { - rb_sys_fail(fptr->path); - } - return rb_time_new(st.st_mtime, 0); -} - -/* - * call-seq: - * File.ctime(file_name) => time - * - * Returns the change time for the named file (the time at which - * directory information about the file was changed, not the file - * itself). - * - * File.ctime("testfile") #=> Wed Apr 09 08:53:13 CDT 2003 - * - */ - -static VALUE -rb_file_s_ctime(klass, fname) - VALUE klass, fname; -{ - struct stat st; - - if (rb_stat(fname, &st) < 0) - rb_sys_fail(RSTRING(fname)->ptr); - return rb_time_new(st.st_ctime, 0); -} - -/* - * call-seq: - * file.ctime -> time - * - * Returns the change time for <i>file</i> (that is, the time directory - * information about the file was changed, not the file itself). - * - * File.new("testfile").ctime #=> Wed Apr 09 08:53:14 CDT 2003 - * - */ - -static VALUE -rb_file_ctime(obj) - VALUE obj; -{ - OpenFile *fptr; - struct stat st; - - GetOpenFile(obj, fptr); - if (fstat(fptr->fd, &st) == -1) { - rb_sys_fail(fptr->path); - } - return rb_time_new(st.st_ctime, 0); -} - -static void -chmod_internal(path, mode) - const char *path; - int mode; -{ - if (chmod(path, mode) < 0) - rb_sys_fail(path); -} - -/* - * call-seq: - * File.chmod(mode_int, file_name, ... ) -> integer - * - * Changes permission bits on the named file(s) to the bit pattern - * represented by <i>mode_int</i>. Actual effects are operating system - * dependent (see the beginning of this section). On Unix systems, see - * <code>chmod(2)</code> for details. Returns the number of files - * processed. - * - * File.chmod(0644, "testfile", "out") #=> 2 - */ - -static VALUE -rb_file_s_chmod(argc, argv) - int argc; - VALUE *argv; -{ - VALUE vmode; - VALUE rest; - int mode; - long n; - - rb_secure(2); - rb_scan_args(argc, argv, "1*", &vmode, &rest); - mode = NUM2INT(vmode); - - n = apply2files(chmod_internal, rest, (void *)(long)mode); - return LONG2FIX(n); -} - -/* - * call-seq: - * file.chmod(mode_int) => 0 - * - * Changes permission bits on <i>file</i> to the bit pattern - * represented by <i>mode_int</i>. Actual effects are platform - * dependent; on Unix systems, see <code>chmod(2)</code> for details. - * Follows symbolic links. Also see <code>File#lchmod</code>. - * - * f = File.new("out", "w"); - * f.chmod(0644) #=> 0 - */ - -static VALUE -rb_file_chmod(obj, vmode) - VALUE obj, vmode; -{ - OpenFile *fptr; - int mode; - - rb_secure(2); - mode = NUM2INT(vmode); - - GetOpenFile(obj, fptr); -#ifdef HAVE_FCHMOD - if (fchmod(fptr->fd, mode) == -1) - rb_sys_fail(fptr->path); -#else - if (!fptr->path) return Qnil; - if (chmod(fptr->path, mode) == -1) - rb_sys_fail(fptr->path); -#endif - - return INT2FIX(0); -} - -#if defined(HAVE_LCHMOD) -static void -lchmod_internal(path, mode) - const char *path; - int mode; -{ - if (lchmod(path, mode) < 0) - rb_sys_fail(path); -} - -/* - * call-seq: - * File.lchmod(mode_int, file_name, ...) => integer - * - * Equivalent to <code>File::chmod</code>, but does not follow symbolic - * links (so it will change the permissions associated with the link, - * not the file referenced by the link). Often not available. - * - */ - -static VALUE -rb_file_s_lchmod(argc, argv) - int argc; - VALUE *argv; -{ - VALUE vmode; - VALUE rest; - long mode, n; - - rb_secure(2); - rb_scan_args(argc, argv, "1*", &vmode, &rest); - mode = NUM2INT(vmode); - - n = apply2files(lchmod_internal, rest, (void *)(long)mode); - return LONG2FIX(n); -} -#else -static VALUE -rb_file_s_lchmod(argc, argv) - int argc; - VALUE *argv; -{ - rb_notimplement(); - return Qnil; /* not reached */ -} -#endif - -struct chown_args { - int owner, group; -}; - -static void -chown_internal(path, args) - const char *path; - struct chown_args *args; -{ - if (chown(path, args->owner, args->group) < 0) - rb_sys_fail(path); -} - -/* - * call-seq: - * File.chown(owner_int, group_int, file_name,... ) -> integer - * - * Changes the owner and group of the named file(s) to the given - * numeric owner and group id's. Only a process with superuser - * privileges may change the owner of a file. The current owner of a - * file may change the file's group to any group to which the owner - * belongs. A <code>nil</code> or -1 owner or group id is ignored. - * Returns the number of files processed. - * - * File.chown(nil, 100, "testfile") - * - */ - -static VALUE -rb_file_s_chown(argc, argv) - int argc; - VALUE *argv; -{ - VALUE o, g, rest; - struct chown_args arg; - long n; - - rb_secure(2); - rb_scan_args(argc, argv, "2*", &o, &g, &rest); - if (NIL_P(o)) { - arg.owner = -1; - } - else { - arg.owner = NUM2INT(o); - } - if (NIL_P(g)) { - arg.group = -1; - } - else { - arg.group = NUM2INT(g); - } - - n = apply2files(chown_internal, rest, &arg); - return LONG2FIX(n); -} - -/* - * call-seq: - * file.chown(owner_int, group_int ) => 0 - * - * Changes the owner and group of <i>file</i> to the given numeric - * owner and group id's. Only a process with superuser privileges may - * change the owner of a file. The current owner of a file may change - * the file's group to any group to which the owner belongs. A - * <code>nil</code> or -1 owner or group id is ignored. Follows - * symbolic links. See also <code>File#lchown</code>. - * - * File.new("testfile").chown(502, 1000) - * - */ - -static VALUE -rb_file_chown(obj, owner, group) - VALUE obj, owner, group; -{ - OpenFile *fptr; - int o, g; - - rb_secure(2); - o = NUM2INT(owner); - g = NUM2INT(group); - GetOpenFile(obj, fptr); -#if defined(DJGPP) || defined(__CYGWIN32__) || defined(_WIN32) || defined(__EMX__) - if (!fptr->path) return Qnil; - if (chown(fptr->path, o, g) == -1) - rb_sys_fail(fptr->path); -#else - if (fchown(fptr->fd, o, g) == -1) - rb_sys_fail(fptr->path); -#endif - - return INT2FIX(0); -} - -#if defined(HAVE_LCHOWN) && !defined(__CHECKER__) -static void -lchown_internal(path, args) - const char *path; - struct chown_args *args; -{ - if (lchown(path, args->owner, args->group) < 0) - rb_sys_fail(path); -} - - -/* - * call-seq: - * file.lchown(owner_int, group_int, file_name,..) => integer - * - * Equivalent to <code>File::chown</code>, but does not follow symbolic - * links (so it will change the owner associated with the link, not the - * file referenced by the link). Often not available. Returns number - * of files in the argument list. - * - */ - -static VALUE -rb_file_s_lchown(argc, argv) - int argc; - VALUE *argv; -{ - VALUE o, g, rest; - struct chown_args arg; - long n; - - rb_secure(2); - rb_scan_args(argc, argv, "2*", &o, &g, &rest); - if (NIL_P(o)) { - arg.owner = -1; - } - else { - arg.owner = NUM2INT(o); - } - if (NIL_P(g)) { - arg.group = -1; - } - else { - arg.group = NUM2INT(g); - } - - n = apply2files(lchown_internal, rest, &arg); - return LONG2FIX(n); -} -#else -static VALUE -rb_file_s_lchown(argc, argv) - int argc; - VALUE *argv; -{ - rb_notimplement(); -} -#endif - -struct timeval rb_time_timeval(); - -#if defined(HAVE_UTIMES) && !defined(__CHECKER__) - -static void -utime_internal(path, tvp) - char *path; - struct timeval tvp[]; -{ - if (utimes(path, tvp) < 0) - rb_sys_fail(path); -} - -/* - * call-seq: - * File.utime(atime, mtime, file_name,...) => integer - * - * Sets the access and modification times of each - * named file to the first two arguments. Returns - * the number of file names in the argument list. - */ - -static VALUE -rb_file_s_utime(argc, argv) - int argc; - VALUE *argv; -{ - VALUE atime, mtime, rest; - struct timeval tvp[2]; - long n; - - rb_scan_args(argc, argv, "2*", &atime, &mtime, &rest); - - tvp[0] = rb_time_timeval(atime); - tvp[1] = rb_time_timeval(mtime); - - n = apply2files(utime_internal, rest, tvp); - return LONG2FIX(n); -} - -#else - -#if !defined HAVE_UTIME_H && !defined HAVE_SYS_UTIME_H -struct utimbuf { - long actime; - long modtime; -}; -#endif - -static void -utime_internal(path, utp) - const char *path; - struct utimbuf *utp; -{ - if (utime(path, utp) < 0) - rb_sys_fail(path); -} - -static VALUE -rb_file_s_utime(argc, argv) - int argc; - VALUE *argv; -{ - VALUE atime, mtime, rest; - long n; - struct timeval tv; - struct utimbuf utbuf; - - rb_scan_args(argc, argv, "2*", &atime, &mtime, &rest); - - tv = rb_time_timeval(atime); - utbuf.actime = tv.tv_sec; - tv = rb_time_timeval(mtime); - utbuf.modtime = tv.tv_sec; - - n = apply2files(utime_internal, rest, &utbuf); - return LONG2FIX(n); -} - -#endif - -NORETURN(static void sys_fail2 _((VALUE,VALUE))); -static void -sys_fail2(s1, s2) - VALUE s1, s2; -{ - char *buf; - int len; - - len = RSTRING(s1)->len + RSTRING(s2)->len + 5; - buf = ALLOCA_N(char, len); - snprintf(buf, len, "%s or %s", RSTRING(s1)->ptr, RSTRING(s2)->ptr); - rb_sys_fail(buf); -} - -/* - * call-seq: - * File.link(old_name, new_name) => 0 - * - * Creates a new name for an existing file using a hard link. Will not - * overwrite <i>new_name</i> if it already exists (raising a subclass - * of <code>SystemCallError</code>). Not available on all platforms. - * - * File.link("testfile", ".testfile") #=> 0 - * IO.readlines(".testfile")[0] #=> "This is line one\n" - */ - -static VALUE -rb_file_s_link(klass, from, to) - VALUE klass, from, to; -{ -#ifdef HAVE_LINK - rb_secure(2); - FilePathValue(from); - FilePathValue(to); - - if (link(StringValueCStr(from), StringValueCStr(to)) < 0) { - sys_fail2(from, to); - } - return INT2FIX(0); -#else - rb_notimplement(); - return Qnil; /* not reached */ -#endif -} - -/* - * call-seq: - * File.symlink(old_name, new_name) => 0 - * - * Creates a symbolic link called <i>new_name</i> for the existing file - * <i>old_name</i>. Raises a <code>NotImplemented</code> exception on - * platforms that do not support symbolic links. - * - * File.symlink("testfile", "link2test") #=> 0 - * - */ - -static VALUE -rb_file_s_symlink(klass, from, to) - VALUE klass, from, to; -{ -#ifdef HAVE_SYMLINK - rb_secure(2); - FilePathValue(from); - FilePathValue(to); - - if (symlink(StringValueCStr(from), StringValueCStr(to)) < 0) { - sys_fail2(from, to); - } - return INT2FIX(0); -#else - rb_notimplement(); - return Qnil; /* not reached */ -#endif -} - -/* - * call-seq: - * File.readlink(link_name) -> file_name - * - * Returns the name of the file referenced by the given link. - * Not available on all platforms. - * - * File.symlink("testfile", "link2test") #=> 0 - * File.readlink("link2test") #=> "testfile" - */ - -static VALUE -rb_file_s_readlink(klass, path) - VALUE klass, path; -{ -#ifdef HAVE_READLINK - char *buf; - int size = 100; - int rv; - VALUE v; - - rb_secure(2); - FilePathValue(path); - buf = xmalloc(size); - while ((rv = readlink(StringValueCStr(path), buf, size)) == size) { - size *= 2; - buf = xrealloc(buf, size); - } - if (rv < 0) { - free(buf); - rb_sys_fail(RSTRING(path)->ptr); - } - v = rb_tainted_str_new(buf, rv); - free(buf); - - return v; -#else - rb_notimplement(); - return Qnil; /* not reached */ -#endif -} - -static void -unlink_internal(path) - const char *path; -{ - if (unlink(path) < 0) - rb_sys_fail(path); -} - -/* - * call-seq: - * File.delete(file_name, ...) => integer - * File.unlink(file_name, ...) => integer - * - * Deletes the named files, returning the number of names - * passed as arguments. Raises an exception on any error. - * See also <code>Dir::rmdir</code>. - */ - -static VALUE -rb_file_s_unlink(klass, args) - VALUE klass, args; -{ - long n; - - rb_secure(2); - n = apply2files(unlink_internal, args, 0); - return LONG2FIX(n); -} - -/* - * call-seq: - * File.rename(old_name, new_name) => 0 - * - * Renames the given file to the new name. Raises a - * <code>SystemCallError</code> if the file cannot be renamed. - * - * File.rename("afile", "afile.bak") #=> 0 - */ - -static VALUE -rb_file_s_rename(klass, from, to) - VALUE klass, from, to; -{ - const char *src, *dst; - - rb_secure(2); - FilePathValue(from); - FilePathValue(to); - src = StringValueCStr(from); - dst = StringValueCStr(to); - if (rename(src, dst) < 0) { -#if defined __CYGWIN__ - extern unsigned long __attribute__((stdcall)) GetLastError(); - errno = GetLastError(); /* This is a Cygwin bug */ -#elif defined DOSISH && !defined _WIN32 - if (errno == EEXIST -#if defined (__EMX__) - || errno == EACCES -#endif - ) { - if (chmod(dst, 0666) == 0 && - unlink(dst) == 0 && - rename(src, dst) == 0) - return INT2FIX(0); - } -#endif - sys_fail2(from, to); - } - - return INT2FIX(0); -} - -/* - * call-seq: - * File.umask() => integer - * File.umask(integer) => integer - * - * Returns the current umask value for this process. If the optional - * argument is given, set the umask to that value and return the - * previous value. Umask values are <em>subtracted</em> from the - * default permissions, so a umask of <code>0222</code> would make a - * file read-only for everyone. - * - * File.umask(0006) #=> 18 - * File.umask #=> 6 - */ - -static VALUE -rb_file_s_umask(argc, argv) - int argc; - VALUE *argv; -{ - int omask = 0; - - rb_secure(2); - if (argc == 0) { - omask = umask(0); - umask(omask); - } - else if (argc == 1) { - omask = umask(NUM2INT(argv[0])); - } - else { - rb_raise(rb_eArgError, "wrong number of arguments"); - } - return INT2FIX(omask); -} - -#if defined DOSISH -#define DOSISH_UNC -#define isdirsep(x) ((x) == '/' || (x) == '\\') -#else -#define isdirsep(x) ((x) == '/') -#endif -#ifndef CharNext /* defined as CharNext[AW] on Windows. */ -# if defined(DJGPP) -# define CharNext(p) ((p) + mblen(p, RUBY_MBCHAR_MAXSIZE)) -# else -# define CharNext(p) ((p) + 1) -# endif -#endif - -#ifdef __CYGWIN__ -#undef DOSISH -#define DOSISH_UNC -#define DOSISH_DRIVE_LETTER -#endif - -#ifdef DOSISH_DRIVE_LETTER -static inline int -has_drive_letter(buf) - const char *buf; -{ - if (ISALPHA(buf[0]) && buf[1] == ':') { - return 1; - } - else { - return 0; - } -} - -static char* -getcwdofdrv(drv) - int drv; -{ - char drive[4]; - char *drvcwd, *oldcwd; - - drive[0] = drv; - drive[1] = ':'; - drive[2] = '\0'; - - /* the only way that I know to get the current directory - of a particular drive is to change chdir() to that drive, - so save the old cwd before chdir() - */ - oldcwd = my_getcwd(); - if (chdir(drive) == 0) { - drvcwd = my_getcwd(); - chdir(oldcwd); - free(oldcwd); - } - else { - /* perhaps the drive is not exist. we return only drive letter */ - drvcwd = strdup(drive); - } - return drvcwd; -} -#endif - -static inline char * -skiproot(path) - const char *path; -{ -#ifdef DOSISH_DRIVE_LETTER - if (has_drive_letter(path)) path += 2; -#endif - while (isdirsep(*path)) path++; - return (char *)path; -} - -#define nextdirsep rb_path_next -char * -rb_path_next(s) - const char *s; -{ - while (*s && !isdirsep(*s)) { - s = CharNext(s); - } - return (char *)s; -} - -#define skipprefix rb_path_skip_prefix -char * -rb_path_skip_prefix(path) - const char *path; -{ -#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER) -#ifdef DOSISH_UNC - if (isdirsep(path[0]) && isdirsep(path[1])) { - if (*(path = nextdirsep(path + 2))) - path = nextdirsep(path + 1); - return (char *)path; - } -#endif -#ifdef DOSISH_DRIVE_LETTER - if (has_drive_letter(path)) - return (char *)(path + 2); -#endif -#endif - return (char *)path; -} - -#define strrdirsep rb_path_last_separator -char * -rb_path_last_separator(path) - const char *path; -{ - char *last = NULL; - while (*path) { - if (isdirsep(*path)) { - const char *tmp = path++; - while (isdirsep(*path)) path++; - if (!*path) break; - last = (char *)tmp; - } - else { - path = CharNext(path); - } - } - return last; -} - -#define chompdirsep rb_path_end -char * -rb_path_end(path) - const char *path; -{ - while (*path) { - if (isdirsep(*path)) { - const char *last = path++; - while (isdirsep(*path)) path++; - if (!*path) return (char *)last; - } - else { - path = CharNext(path); - } - } - return (char *)path; -} - -#define BUFCHECK(cond) do {\ - long bdiff = p - buf;\ - while (cond) {\ - buflen *= 2;\ - }\ - rb_str_resize(result, buflen);\ - buf = RSTRING(result)->ptr;\ - p = buf + bdiff;\ - pend = buf + buflen;\ -} while (0) - -#define BUFINIT() (\ - p = buf = RSTRING(result)->ptr,\ - buflen = RSTRING(result)->len,\ - pend = p + buflen) - -#if !defined(TOLOWER) -#define TOLOWER(c) (ISUPPER(c) ? tolower(c) : (c)) -#endif - -static int is_absolute_path _((const char*)); - -static VALUE -file_expand_path(fname, dname, result) - VALUE fname, dname, result; -{ - char *s, *buf, *b, *p, *pend, *root; - long buflen, dirlen; - int tainted; - - s = StringValuePtr(fname); - BUFINIT(); - tainted = OBJ_TAINTED(fname); - - if (s[0] == '~') { - if (isdirsep(s[1]) || s[1] == '\0') { - char *dir = getenv("HOME"); - - if (!dir) { - rb_raise(rb_eArgError, "couldn't find HOME environment -- expanding `%s'", s); - } - dirlen = strlen(dir); - BUFCHECK(dirlen > buflen); - strcpy(buf, dir); -#if defined DOSISH || defined __CYGWIN__ - for (p = buf; *p; p = CharNext(p)) { - if (*p == '\\') { - *p = '/'; - } - } -#else - p = buf + strlen(dir); -#endif - s++; - tainted = 1; - } - else { -#ifdef HAVE_PWD_H - struct passwd *pwPtr; - s++; -#endif - s = nextdirsep(b = s); - BUFCHECK(bdiff + (s-b) >= buflen); - memcpy(p, b, s-b); - p += s-b; - *p = '\0'; -#ifdef HAVE_PWD_H - pwPtr = getpwnam(buf); - if (!pwPtr) { - endpwent(); - rb_raise(rb_eArgError, "user %s doesn't exist", buf); - } - dirlen = strlen(pwPtr->pw_dir); - BUFCHECK(dirlen > buflen); - strcpy(buf, pwPtr->pw_dir); - p = buf + strlen(pwPtr->pw_dir); - endpwent(); -#endif - } - } -#ifdef DOSISH_DRIVE_LETTER - /* skip drive letter */ - else if (has_drive_letter(s)) { - if (isdirsep(s[2])) { - /* specified drive letter, and full path */ - /* skip drive letter */ - BUFCHECK(bdiff + 2 >= buflen); - memcpy(p, s, 2); - p += 2; - s += 2; - } - else { - /* specified drive, but not full path */ - int same = 0; - if (!NIL_P(dname)) { - file_expand_path(dname, Qnil, result); - BUFINIT(); - if (has_drive_letter(p) && TOLOWER(p[0]) == TOLOWER(s[0])) { - /* ok, same drive */ - same = 1; - } - } - if (!same) { - char *dir = getcwdofdrv(*s); - - tainted = 1; - dirlen = strlen(dir); - BUFCHECK(dirlen > buflen); - strcpy(buf, dir); - free(dir); - } - p = chompdirsep(skiproot(buf)); - s += 2; - } - } -#endif - else if (!is_absolute_path(s)) { - if (!NIL_P(dname)) { - file_expand_path(dname, Qnil, result); - BUFINIT(); - } - else { - char *dir = my_getcwd(); - - tainted = 1; - dirlen = strlen(dir); - BUFCHECK(dirlen > buflen); - strcpy(buf, dir); - free(dir); - } -#if defined DOSISH || defined __CYGWIN__ - if (isdirsep(*s)) { - /* specified full path, but not drive letter nor UNC */ - /* we need to get the drive letter or UNC share name */ - p = skipprefix(buf); - } - else -#endif - p = chompdirsep(skiproot(buf)); - } - else { - b = s; - do s++; while (isdirsep(*s)); - p = buf + (s - b); - BUFCHECK(bdiff >= buflen); - memset(buf, '/', p - buf); - } - if (p > buf && p[-1] == '/') - --p; - else - *p = '/'; - - p[1] = 0; - root = skipprefix(buf); - - b = s; - while (*s) { - switch (*s) { - case '.': - if (b == s++) { /* beginning of path element */ - switch (*s) { - case '\0': - b = s; - break; - case '.': - if (*(s+1) == '\0' || isdirsep(*(s+1))) { - /* We must go back to the parent */ - *p = '\0'; - if (!(b = strrdirsep(root))) { - *p = '/'; - } - else { - p = b; - } - b = ++s; - } - break; - case '/': -#if defined DOSISH || defined __CYGWIN__ - case '\\': -#endif - b = ++s; - break; - default: - /* ordinary path element, beginning don't move */ - break; - } - } - break; - case '/': -#if defined DOSISH || defined __CYGWIN__ - case '\\': -#endif - if (s > b) { - long rootdiff = root - buf; - BUFCHECK(bdiff + (s-b+1) >= buflen); - root = buf + rootdiff; - memcpy(++p, b, s-b); - p += s-b; - *p = '/'; - } - b = ++s; - break; - default: - s = CharNext(s); - break; - } - } - - if (s > b) { - BUFCHECK(bdiff + (s-b) >= buflen); - memcpy(++p, b, s-b); - p += s-b; - } - if (p == skiproot(buf) - 1) p++; - - if (tainted) OBJ_TAINT(result); - RSTRING(result)->len = p - buf; - *p = '\0'; - return result; -} - -VALUE -rb_file_expand_path(fname, dname) - VALUE fname, dname; -{ - return file_expand_path(fname, dname, rb_str_new(0, MAXPATHLEN + 2)); -} - -/* - * call-seq: - * File.expand_path(file_name [, dir_string] ) -> abs_file_name - * - * Converts a pathname to an absolute pathname. Relative paths are - * referenced from the current working directory of the process unless - * <i>dir_string</i> is given, in which case it will be used as the - * starting point. The given pathname may start with a - * ``<code>~</code>'', which expands to the process owner's home - * directory (the environment variable <code>HOME</code> must be set - * correctly). ``<code>~</code><i>user</i>'' expands to the named - * user's home directory. - * - * File.expand_path("~oracle/bin") #=> "/home/oracle/bin" - * File.expand_path("../../bin", "/tmp/x") #=> "/bin" - */ - -VALUE -rb_file_s_expand_path(argc, argv) - int argc; - VALUE *argv; -{ - VALUE fname, dname; - - if (argc == 1) { - return rb_file_expand_path(argv[0], Qnil); - } - rb_scan_args(argc, argv, "11", &fname, &dname); - - return rb_file_expand_path(fname, dname); -} - -static int -rmext(p, e) - const char *p, *e; -{ - int l1, l2; - - if (!e) return 0; - - l1 = chompdirsep(p) - p; - l2 = strlen(e); - if (l2 == 2 && e[1] == '*') { - e = strrchr(p, *e); - if (!e) return 0; - return e - p; - } - if (l1 < l2) return l1; - - if (strncmp(p+l1-l2, e, l2) == 0) { - return l1-l2; - } - return 0; -} - -/* - * call-seq: - * File.basename(file_name [, suffix] ) -> base_name - * - * Returns the last component of the filename given in <i>file_name</i>, - * which must be formed using forward slashes (``<code>/</code>'') - * regardless of the separator used on the local file system. If - * <i>suffix</i> is given and present at the end of <i>file_name</i>, - * it is removed. - * - * File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb" - * File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby" - */ - -static VALUE -rb_file_s_basename(argc, argv) - int argc; - VALUE *argv; -{ - VALUE fname, fext, basename; - char *name, *p; - int f; - - if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) { - StringValue(fext); - } - StringValue(fname); - if (RSTRING(fname)->len == 0 || !*(name = RSTRING(fname)->ptr)) - return fname; - if (!*(name = skiproot(name))) { - p = name - 1; - f = 1; -#ifdef DOSISH_DRIVE_LETTER - if (*p == ':') { - p++; - f = 0; - } -#endif - } - else if (!(p = strrdirsep(name))) { - if (NIL_P(fext) || !(f = rmext(name, StringValueCStr(fext)))) { - f = chompdirsep(name) - name; - if (f == RSTRING(fname)->len) return fname; - } - p = name; - } - else { - while (isdirsep(*p)) p++; /* skip last / */ - if (NIL_P(fext) || !(f = rmext(p, StringValueCStr(fext)))) { - f = chompdirsep(p) - p; - } - } - basename = rb_str_new(p, f); - OBJ_INFECT(basename, fname); - return basename; -} - -/* - * call-seq: - * File.dirname(file_name ) -> dir_name - * - * Returns all components of the filename given in <i>file_name</i> - * except the last one. The filename must be formed using forward - * slashes (``<code>/</code>'') regardless of the separator used on the - * local file system. - * - * File.dirname("/home/gumby/work/ruby.rb") #=> "/home/gumby/work" - */ - -static VALUE -rb_file_s_dirname(klass, fname) - VALUE klass, fname; -{ - char *name, *root, *p; - VALUE dirname; - - name = StringValueCStr(fname); - root = skiproot(name); -#ifdef DOSISH_UNC - if (root > name + 2 && isdirsep(*name)) - name = root - 2; -#else - if (root > name + 1) - name = root - 1; -#endif - p = strrdirsep(root); - if (!p) { - p = root; - } - if (p == name) - return rb_str_new2("."); - dirname = rb_str_new(name, p - name); -#ifdef DOSISH_DRIVE_LETTER - if (root == name + 2 && name[1] == ':') - rb_str_cat(dirname, ".", 1); -#endif - OBJ_INFECT(dirname, fname); - return dirname; -} - -/* - * call-seq: - * File.extname(path) -> string - * - * Returns the extension (the portion of file name in <i>path</i> - * after the period). - * - * File.extname("test.rb") #=> ".rb" - * File.extname("a/b/d/test.rb") #=> ".rb" - * File.extname("test") #=> "" - * File.extname(".profile") #=> "" - * - */ - -static VALUE -rb_file_s_extname(klass, fname) - VALUE klass, fname; -{ - char *name, *p, *e; - VALUE extname; - - name = StringValueCStr(fname); - p = strrdirsep(name); /* get the last path component */ - if (!p) - p = name; - else - p++; - - e = strrchr(p, '.'); /* get the last dot of the last component */ - if (!e || e == p) /* no dot, or the only dot is first? */ - return rb_str_new2(""); - extname = rb_str_new(e, chompdirsep(e) - e); /* keep the dot, too! */ - OBJ_INFECT(extname, fname); - return extname; -} - -/* - * call-seq: - * File.path(path) -> string - * - * Returns the string representation of the path - * - * File.path("/dev/null") #=> "/dev/null" - * File.path(Pathname.new("/tmp")) #=> "/tmp" - * - */ - -static VALUE -rb_file_s_path(klass, fname) - VALUE klass, fname; -{ - return rb_get_path(fname); -} - -/* - * call-seq: - * File.split(file_name) => array - * - * Splits the given string into a directory and a file component and - * returns them in a two-element array. See also - * <code>File::dirname</code> and <code>File::basename</code>. - * - * File.split("/home/gumby/.profile") #=> ["/home/gumby", ".profile"] - */ - -static VALUE -rb_file_s_split(klass, path) - VALUE klass, path; -{ - StringValue(path); /* get rid of converting twice */ - return rb_assoc_new(rb_file_s_dirname(Qnil, path), rb_file_s_basename(1,&path)); -} - -static VALUE separator; - -static VALUE rb_file_join _((VALUE ary, VALUE sep)); - -static VALUE -file_inspect_join(ary, arg, recur) - VALUE ary; - VALUE *arg; -{ - if (recur) return rb_str_new2("[...]"); - return rb_file_join(arg[0], arg[1]); -} - -static VALUE -rb_file_join(ary, sep) - VALUE ary, sep; -{ - long len, i; - int taint = 0; - VALUE result, tmp; - char *name; - - if (RARRAY(ary)->len == 0) return rb_str_new(0, 0); - if (OBJ_TAINTED(ary)) taint = 1; - if (OBJ_TAINTED(sep)) taint = 1; - - len = 1; - for (i=0; i<RARRAY(ary)->len; i++) { - if (TYPE(RARRAY(ary)->ptr[i]) == T_STRING) { - len += RSTRING(RARRAY(ary)->ptr[i])->len; - } - else { - len += 10; - } - } - if (!NIL_P(sep) && TYPE(sep) == T_STRING) { - len += RSTRING(sep)->len * RARRAY(ary)->len - 1; - } - result = rb_str_buf_new(len); - for (i=0; i<RARRAY(ary)->len; i++) { - tmp = RARRAY(ary)->ptr[i]; - switch (TYPE(tmp)) { - case T_STRING: - break; - case T_ARRAY: - { - VALUE args[2]; - - args[0] = tmp; - args[1] = sep; - tmp = rb_exec_recursive(file_inspect_join, ary, (VALUE)args); - } - break; - default: - tmp = rb_obj_as_string(tmp); - } - name = StringValueCStr(result); - if (i > 0 && !NIL_P(sep) && !*chompdirsep(name)) - rb_str_buf_append(result, sep); - rb_str_buf_append(result, tmp); - if (OBJ_TAINTED(tmp)) taint = 1; - } - - if (taint) OBJ_TAINT(result); - return result; -} - -/* - * call-seq: - * File.join(string, ...) -> path - * - * Returns a new string formed by joining the strings using - * <code>File::SEPARATOR</code>. - * - * File.join("usr", "mail", "gumby") #=> "usr/mail/gumby" - * - */ - -static VALUE -rb_file_s_join(klass, args) - VALUE klass, args; -{ - return rb_file_join(args, separator); -} - -/* - * call-seq: - * File.truncate(file_name, integer) => 0 - * - * Truncates the file <i>file_name</i> to be at most <i>integer</i> - * bytes long. Not available on all platforms. - * - * f = File.new("out", "w") - * f.write("1234567890") #=> 10 - * f.close #=> nil - * File.truncate("out", 5) #=> 0 - * File.size("out") #=> 5 - * - */ - -static VALUE -rb_file_s_truncate(klass, path, len) - VALUE klass, path, len; -{ - off_t pos; - - rb_secure(2); - pos = NUM2OFFT(len); - FilePathValue(path); -#ifdef HAVE_TRUNCATE - if (truncate(StringValueCStr(path), pos) < 0) - rb_sys_fail(RSTRING(path)->ptr); -#else -# ifdef HAVE_CHSIZE - { - int tmpfd; - -# ifdef _WIN32 - if ((tmpfd = open(StringValueCStr(path), O_RDWR)) < 0) { - rb_sys_fail(RSTRING(path)->ptr); - } -# else - if ((tmpfd = open(StringValueCStr(path), 0)) < 0) { - rb_sys_fail(RSTRING(path)->ptr); - } -# endif - if (chsize(tmpfd, pos) < 0) { - close(tmpfd); - rb_sys_fail(RSTRING(path)->ptr); - } - close(tmpfd); - } -# else - rb_notimplement(); -# endif -#endif - return INT2FIX(0); -} - -/* - * call-seq: - * file.truncate(integer) => 0 - * - * Truncates <i>file</i> to at most <i>integer</i> bytes. The file - * must be opened for writing. Not available on all platforms. - * - * f = File.new("out", "w") - * f.syswrite("1234567890") #=> 10 - * f.truncate(5) #=> 0 - * f.close() #=> nil - * File.size("out") #=> 5 - */ - -static VALUE -rb_file_truncate(obj, len) - VALUE obj, len; -{ - OpenFile *fptr; - off_t pos; - - rb_secure(2); - pos = NUM2OFFT(len); - GetOpenFile(obj, fptr); - if (!(fptr->mode & FMODE_WRITABLE)) { - rb_raise(rb_eIOError, "not opened for writing"); - } - rb_io_flush(obj); -#ifdef HAVE_TRUNCATE - if (ftruncate(fptr->fd, pos) < 0) - rb_sys_fail(fptr->path); -#else -# ifdef HAVE_CHSIZE - if (chsize(fptr->fd, pos) < 0) - rb_sys_fail(fptr->path); -# else - rb_notimplement(); -# endif -#endif - return INT2FIX(0); -} - -# ifndef LOCK_SH -# define LOCK_SH 1 -# endif -# ifndef LOCK_EX -# define LOCK_EX 2 -# endif -# ifndef LOCK_NB -# define LOCK_NB 4 -# endif -# ifndef LOCK_UN -# define LOCK_UN 8 -# endif - -#if 1 -static int -rb_thread_flock(fd, op, fptr) - int fd, op; - OpenFile *fptr; -{ - if (rb_thread_alone() || (op & LOCK_NB)) { - return flock(fd, op); - } - op |= LOCK_NB; - while (flock(fd, op) < 0) { - switch (errno) { - case EAGAIN: - case EACCES: -#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN - case EWOULDBLOCK: -#endif - rb_thread_polling(); /* busy wait */ - rb_io_check_closed(fptr); - continue; - default: - return -1; - } - } - return 0; -} -#define flock(fd, op) rb_thread_flock(fd, op, fptr) -#endif - -/* - * call-seq: - * file.flock (locking_constant ) => 0 or false - * - * Locks or unlocks a file according to <i>locking_constant</i> (a - * logical <em>or</em> of the values in the table below). - * Returns <code>false</code> if <code>File::LOCK_NB</code> is - * specified and the operation would otherwise have blocked. Not - * available on all platforms. - * - * Locking constants (in class File): - * - * LOCK_EX | Exclusive lock. Only one process may hold an - * | exclusive lock for a given file at a time. - * ----------+------------------------------------------------ - * LOCK_NB | Don't block when locking. May be combined - * | with other lock options using logical or. - * ----------+------------------------------------------------ - * LOCK_SH | Shared lock. Multiple processes may each hold a - * | shared lock for a given file at the same time. - * ----------+------------------------------------------------ - * LOCK_UN | Unlock. - * - * Example: - * - * File.new("testfile").flock(File::LOCK_UN) #=> 0 - * - */ - -static VALUE -rb_file_flock(obj, operation) - VALUE obj; - VALUE operation; -{ -#ifndef __CHECKER__ - OpenFile *fptr; - int op; - - rb_secure(2); - op = NUM2INT(operation); - GetOpenFile(obj, fptr); - - if (fptr->mode & FMODE_WRITABLE) { - rb_io_flush(obj); - } - retry: - if (flock(fptr->fd, op) < 0) { - switch (errno) { - case EAGAIN: - case EACCES: -#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN - case EWOULDBLOCK: -#endif - return Qfalse; - case EINTR: -#if defined(ERESTART) - case ERESTART: -#endif - goto retry; - } - rb_sys_fail(fptr->path); - } -#endif - return INT2FIX(0); -} -#undef flock - -static void -test_check(n, argc, argv) - int n, argc; - VALUE *argv; -{ - int i; - - rb_secure(2); - n+=1; - if (n != argc) rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, n); - for (i=1; i<n; i++) { - switch (TYPE(argv[i])) { - case T_STRING: - default: - FilePathValue(argv[i]); - break; - case T_FILE: - break; - } - } -} - -#define CHECK(n) test_check((n), argc, argv) - -/* - * call-seq: - * test(int_cmd, file1 [, file2] ) => obj - * - * Uses the integer <i>aCmd</i> to perform various tests on - * <i>file1</i> (first table below) or on <i>file1</i> and - * <i>file2</i> (second table). - * - * File tests on a single file: - * - * Test Returns Meaning - * ?A | Time | Last access time for file1 - * ?b | boolean | True if file1 is a block device - * ?c | boolean | True if file1 is a character device - * ?C | Time | Last change time for file1 - * ?d | boolean | True if file1 exists and is a directory - * ?e | boolean | True if file1 exists - * ?f | boolean | True if file1 exists and is a regular file - * ?g | boolean | True if files has the \CF{setgid} bit - * | | set (false under NT) - * ?G | boolean | True if file1 exists and has a group - * | | ownership equal to the caller's group - * ?k | boolean | True if file1 exists and has the sticky bit set - * ?l | boolean | True if files exists and is a symbolic link - * ?M | Time | Last modification time for file1 - * ?o | boolean | True if files exists and is owned by - * | | the caller's effective uid - * ?O | boolean | True if file1 exists and is owned by - * | | the caller's real uid - * ?p | boolean | True if file1 exists and is a fifo - * ?r | boolean | True if file1 is readable by the effective - * | | uid/gid of the caller - * ?R | boolean | True if file is readable by the real - * | | uid/gid of the caller - * ?s | int/nil | If files has nonzero size, return the size, - * | | otherwise return nil - * ?S | boolean | True if file1 exists and is a socket - * ?u | boolean | True if file1 has the setuid bit set - * ?w | boolean | True if file1 exists and is writable by - * | | the effective uid/gid - * ?W | boolean | True if file1 exists and is writable by - * | | the real uid/gid - * ?x | boolean | True if file1 exists and is executable by - * | | the effective uid/gid - * ?X | boolean | True if file1 exists and is executable by - * | | the real uid/gid - * ?z | boolean | True if file1 exists and has a zero length - * - * Tests that take two files: - * - * ?- | boolean | True if file1 is a hard link to file2 - * ?= | boolean | True if the modification times of file1 - * | | and file2 are equal - * ?< | boolean | True if the modification time of file1 - * | | is prior to that of file2 - * ?> | boolean | True if the modification time of file1 - * | | is after that of file2 - */ - -static VALUE -rb_f_test(argc, argv) - int argc; - VALUE *argv; -{ - int cmd; - - if (argc == 0) rb_raise(rb_eArgError, "wrong number of arguments"); -#if 0 /* 1.7 behavior? */ - if (argc == 1) { - return RTEST(argv[0]) ? Qtrue : Qfalse; - } -#endif - cmd = NUM2CHR(argv[0]); - if (cmd == 0) return Qfalse; - if (strchr("bcdefgGkloOprRsSuwWxXz", cmd)) { - CHECK(1); - switch (cmd) { - case 'b': - return test_b(0, argv[1]); - - case 'c': - return test_c(0, argv[1]); - - case 'd': - return test_d(0, argv[1]); - - case 'a': - case 'e': - return test_e(0, argv[1]); - - case 'f': - return test_f(0, argv[1]); - - case 'g': - return test_sgid(0, argv[1]); - - case 'G': - return test_grpowned(0, argv[1]); - - case 'k': - return test_sticky(0, argv[1]); - - case 'l': - return test_l(0, argv[1]); - - case 'o': - return test_owned(0, argv[1]); - - case 'O': - return test_rowned(0, argv[1]); - - case 'p': - return test_p(0, argv[1]); - - case 'r': - return test_r(0, argv[1]); - - case 'R': - return test_R(0, argv[1]); - - case 's': - return test_s(0, argv[1]); - - case 'S': - return test_S(0, argv[1]); - - case 'u': - return test_suid(0, argv[1]); - - case 'w': - return test_w(0, argv[1]); - - case 'W': - return test_W(0, argv[1]); - - case 'x': - return test_x(0, argv[1]); - - case 'X': - return test_X(0, argv[1]); - - case 'z': - return test_z(0, argv[1]); - } - } - - if (strchr("MAC", cmd)) { - struct stat st; - - CHECK(1); - if (rb_stat(argv[1], &st) == -1) { - rb_sys_fail(RSTRING(argv[1])->ptr); - } - - switch (cmd) { - case 'A': - return rb_time_new(st.st_atime, 0); - case 'M': - return rb_time_new(st.st_mtime, 0); - case 'C': - return rb_time_new(st.st_ctime, 0); - } - } - - if (strchr("-=<>", cmd)) { - struct stat st1, st2; - - CHECK(2); - if (rb_stat(argv[1], &st1) < 0) return Qfalse; - if (rb_stat(argv[2], &st2) < 0) return Qfalse; - - switch (cmd) { - case '-': - if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino) - return Qtrue; - return Qfalse; - - case '=': - if (st1.st_mtime == st2.st_mtime) return Qtrue; - return Qfalse; - - case '>': - if (st1.st_mtime > st2.st_mtime) return Qtrue; - return Qfalse; - - case '<': - if (st1.st_mtime < st2.st_mtime) return Qtrue; - return Qfalse; - } - } - /* unknown command */ - rb_raise(rb_eArgError, "unknown command ?%c", cmd); - return Qnil; /* not reached */ -} - - - -/* - * Document-class: File::Stat - * - * Objects of class <code>File::Stat</code> encapsulate common status - * information for <code>File</code> objects. The information is - * recorded at the moment the <code>File::Stat</code> object is - * created; changes made to the file after that point will not be - * reflected. <code>File::Stat</code> objects are returned by - * <code>IO#stat</code>, <code>File::stat</code>, - * <code>File#lstat</code>, and <code>File::lstat</code>. Many of these - * methods return platform-specific values, and not all values are - * meaningful on all systems. See also <code>Kernel#test</code>. - */ - -static VALUE rb_stat_s_alloc _((VALUE)); -static VALUE -rb_stat_s_alloc(klass) - VALUE klass; -{ - return stat_new_0(klass, 0); -} - -/* - * call-seq: - * - * File::Stat.new(file_name) => stat - * - * Create a File::Stat object for the given file name (raising an - * exception if the file doesn't exist). - */ - -static VALUE -rb_stat_init(obj, fname) - VALUE obj, fname; -{ - struct stat st, *nst; - - rb_secure(2); - FilePathValue(fname); - if (stat(StringValueCStr(fname), &st) == -1) { - rb_sys_fail(RSTRING(fname)->ptr); - } - if (DATA_PTR(obj)) { - free(DATA_PTR(obj)); - DATA_PTR(obj) = NULL; - } - nst = ALLOC(struct stat); - *nst = st; - DATA_PTR(obj) = nst; - - return Qnil; -} - -/* :nodoc: */ -static VALUE -rb_stat_init_copy(copy, orig) - VALUE copy, orig; -{ - struct stat *nst; - - if (copy == orig) return orig; - rb_check_frozen(copy); - /* need better argument type check */ - if (!rb_obj_is_instance_of(orig, rb_obj_class(copy))) { - rb_raise(rb_eTypeError, "wrong argument class"); - } - if (DATA_PTR(copy)) { - free(DATA_PTR(copy)); - DATA_PTR(copy) = 0; - } - if (DATA_PTR(orig)) { - nst = ALLOC(struct stat); - *nst = *(struct stat*)DATA_PTR(orig); - DATA_PTR(copy) = nst; - } - - return copy; -} - -/* - * call-seq: - * stat.ftype => string - * - * Identifies the type of <i>stat</i>. The return string is one of: - * ``<code>file</code>'', ``<code>directory</code>'', - * ``<code>characterSpecial</code>'', ``<code>blockSpecial</code>'', - * ``<code>fifo</code>'', ``<code>link</code>'', - * ``<code>socket</code>'', or ``<code>unknown</code>''. - * - * File.stat("/dev/tty").ftype #=> "characterSpecial" - * - */ - -static VALUE -rb_stat_ftype(obj) - VALUE obj; -{ - return rb_file_ftype(get_stat(obj)); -} - -/* - * call-seq: - * stat.directory? => true or false - * - * Returns <code>true</code> if <i>stat</i> is a directory, - * <code>false</code> otherwise. - * - * File.stat("testfile").directory? #=> false - * File.stat(".").directory? #=> true - */ - -static VALUE -rb_stat_d(obj) - VALUE obj; -{ - if (S_ISDIR(get_stat(obj)->st_mode)) return Qtrue; - return Qfalse; -} - -/* - * call-seq: - * stat.pipe? => true or false - * - * Returns <code>true</code> if the operating system supports pipes and - * <i>stat</i> is a pipe; <code>false</code> otherwise. - */ - -static VALUE -rb_stat_p(obj) - VALUE obj; -{ -#ifdef S_IFIFO - if (S_ISFIFO(get_stat(obj)->st_mode)) return Qtrue; - -#endif - return Qfalse; -} - -/* - * call-seq: - * stat.symlink? => true or false - * - * Returns <code>true</code> if <i>stat</i> is a symbolic link, - * <code>false</code> if it isn't or if the operating system doesn't - * support this feature. As <code>File::stat</code> automatically - * follows symbolic links, <code>symlink?</code> will always be - * <code>false</code> for an object returned by - * <code>File::stat</code>. - * - * File.symlink("testfile", "alink") #=> 0 - * File.stat("alink").symlink? #=> false - * File.lstat("alink").symlink? #=> true - * - */ - -static VALUE -rb_stat_l(obj) - VALUE obj; -{ -#ifdef S_ISLNK - if (S_ISLNK(get_stat(obj)->st_mode)) return Qtrue; -#endif - return Qfalse; -} - -/* - * call-seq: - * stat.socket? => true or false - * - * Returns <code>true</code> if <i>stat</i> is a socket, - * <code>false</code> if it isn't or if the operating system doesn't - * support this feature. - * - * File.stat("testfile").socket? #=> false - * - */ - -static VALUE -rb_stat_S(obj) - VALUE obj; -{ -#ifdef S_ISSOCK - if (S_ISSOCK(get_stat(obj)->st_mode)) return Qtrue; - -#endif - return Qfalse; -} - diff --git a/tests/examplefiles/example.cpp b/tests/examplefiles/example.cpp index 316c1420..4dffc3f7 100644 --- a/tests/examplefiles/example.cpp +++ b/tests/examplefiles/example.cpp @@ -6242,7303 +6242,3 @@ void CodeGenerator::openKWTag(unsigned int kwClassID){ currentState=KEYWORD; } - -/////////////////////////////////////////////////////////////////////////////// - -void CodeGenerator::processRootState() -{ - if (langInfo.highlightingDisabled()){ - string line; - while (getline(*in, line)){ - *out << maskString(line) << getNewLine(); - } - *out << flush; - return; - } - - State state=STANDARD; - - bool eof=false, - firstLine=true; // avoid newline before printing the first output line - openTag(STANDARD); - do { - // determine next state - state= getCurrentState(state==NUMBER); - // handle current state - switch(state) - { - case KEYWORD: - case KEYWORD_BEGIN: - closeTag(STANDARD); - eof=processKeywordState(state); - openTag(STANDARD); - break; - case NUMBER: - closeTag(STANDARD); - eof=processNumberState(); - openTag(STANDARD); - break; - case ML_COMMENT_BEGIN: - closeTag(STANDARD); - eof=processMultiLineCommentState(); - openTag(STANDARD); - break; - case SL_COMMENT: - closeTag(STANDARD); - eof=processSingleLineCommentState(); - openTag(STANDARD); - break; - case STRING: - closeTag(STANDARD); - eof=processStringState(STANDARD); - openTag(STANDARD); - break; - case DIRECTIVE_LINE: - closeTag(STANDARD); - eof=processDirectiveState(); - openTag(STANDARD); - break; - case TAG_BEGIN: - closeTag(STANDARD); - eof=processTagState(); - openTag(STANDARD); - break; - case ESC_CHAR: - if (langInfo.allowExtEscSeq()){ - closeTag(STANDARD); - eof=processEscapeCharState(); - openTag(STANDARD); - } else { - printMaskedToken(); - } - break; - case SYMBOL: - closeTag(STANDARD); - eof=processSymbolState(); - openTag(STANDARD); - break; - case _EOL: - insertLineNumber(!firstLine); - firstLine=false; - break; - case _EOF: - eof=true; - break; - case _WS: - processWsState(); - break; - default: - printMaskedToken(); - break; - } - } - while (!eof); - closeTag(STANDARD); - *out << getNewLine(); - *out << flush; -} - -bool CodeGenerator::processKeywordState(State myState){ - State newState=STANDARD; - unsigned int myClassID=currentKeywordClass; - bool eof=false, - exitState=false; - - openKWTag(myClassID); - do { - printMaskedToken(newState!=_WS); - newState= getCurrentState(); - switch(newState) - { - case _WS: - processWsState(); - break; - case _EOL: - insertLineNumber(); - exitState=true; - break; - case _EOF: - eof = true; - break; - case KEYWORD_END: - if (myState==KEYWORD_BEGIN){ - printMaskedToken(); - } - exitState=true; - break; - default: - exitState= myState!=KEYWORD_BEGIN - &&((myClassID!=currentKeywordClass)||(myState!=newState)); - break; - } - } while ((!exitState) && (!eof)); - - closeKWTag(myClassID); - - currentKeywordClass=0; - return eof; -} - -bool CodeGenerator::processNumberState(){ - State newState=STANDARD; - bool eof=false, - exitState=false; - - openTag(NUMBER); - do { - printMaskedToken(newState!=_WS); - newState= getCurrentState(true); - switch(newState) - { - case _WS: - processWsState(); - break; - case _EOL: - insertLineNumber(); - exitState=true; - break; - case _EOF: - eof = true; - break; - default: - exitState=newState!=NUMBER; - break; - } - } while ((!exitState) && (!eof)); - - closeTag(NUMBER); - return eof; -} - -bool CodeGenerator::processMultiLineCommentState() -{ - int commentCount=1; - State newState=STANDARD; - bool eof=false, exitState=false; - - openTag(ML_COMMENT_BEGIN); - do { - printMaskedToken(newState!=_WS); - newState= getCurrentState(); - - switch(newState) - { - case _WS: - processWsState(); - break; - case _EOL: - wsBuffer += styleTagClose[ML_COMMENT_BEGIN]; - insertLineNumber(); - wsBuffer += styleTagOpen[ML_COMMENT_BEGIN]; - break; - case _EOF: - eof = true; - break; - case ML_COMMENT_BEGIN: - if (langInfo.allowNestedMLComments()) { - ++commentCount; - } - break; - case ML_COMMENT_END: - commentCount--; - if (!commentCount){ - printMaskedToken(); - exitState=true; - } - break; - default: - break; - } - } while ((!exitState) && (!eof)); - - closeTag(ML_COMMENT_BEGIN); - return eof; -} - -bool CodeGenerator::processSingleLineCommentState() -{ - - //if ( checkSpecialCmd()) return false; - - State newState=STANDARD; - bool eof=false, exitState=false; - - openTag(SL_COMMENT); - do { - printMaskedToken(newState!=_WS); - newState= getCurrentState(); - - switch(newState) - { - case _WS: - processWsState(); - break; - case _EOL: - printMaskedToken(); - insertLineNumber(); - exitState=true; - break; - case _EOF: - eof = true; - break; - default: - break; - } - } while ((!exitState) && (!eof)); - - closeTag(SL_COMMENT); - return eof; -} - -bool CodeGenerator::processDirectiveState() -{ - State newState=STANDARD; - bool eof=false, exitState=false; - - openTag(DIRECTIVE_LINE); - do { - printMaskedToken(newState!=_WS); - newState= getCurrentState(); - switch(newState) - { - case _WS: - processWsState(); - break; - case DIRECTIVE_LINE_END: - printMaskedToken(); - exitState=true; - break; - case _EOL: - printMaskedToken(); - exitState=(terminatingChar!=langInfo.getContinuationChar()); - if (!exitState) wsBuffer += styleTagClose[DIRECTIVE_LINE]; - insertLineNumber(); - if (!exitState) wsBuffer += styleTagOpen[DIRECTIVE_LINE]; - break; - case ML_COMMENT_BEGIN: - closeTag(DIRECTIVE_LINE); - eof= processMultiLineCommentState(); - openTag(DIRECTIVE_LINE); - break; - case SL_COMMENT: - closeTag(DIRECTIVE_LINE); - eof= processSingleLineCommentState(); - openTag(DIRECTIVE_LINE); - exitState=true; - break; - case STRING: - closeTag(DIRECTIVE_LINE); - eof=processStringState(DIRECTIVE_LINE); - openTag(DIRECTIVE_LINE); - break; - case _EOF: - eof = true; - break; - default: - break; - } - } while ((!exitState) && (!eof)); - - closeTag(DIRECTIVE_LINE); - return eof; -} - -bool CodeGenerator::processStringState(State oldState) -{ - State newState=STANDARD; - bool eof=false, exitState=false; - bool returnedFromOtherState=false; - // Test if character before string open delimiter token equals to the - // raw string prefix (Example: r" ", r""" """ in Python) - bool isRawString= - line[lineIndex-token.length()-1]==langInfo.getRawStringPrefix(); - - string openStringDelimiter=token; - - State myState= (oldState==DIRECTIVE_LINE) ? DIRECTIVE_STRING : STRING; - openTag(myState); - do { - // true if last token was an escape char - if (!returnedFromOtherState) { - printMaskedToken(newState!=_WS); - } - returnedFromOtherState=false; - newState= getCurrentState(); - - switch(newState) - { - case _WS: - processWsState(); - break; - case _EOL: - wsBuffer += styleTagClose[myState]; - insertLineNumber(); - wsBuffer += styleTagOpen[myState]; - //exitState=true; - break; - case ML_COMMENT_END: - printMaskedToken(); - break; - case STRING: - exitState= openStringDelimiter==token; - printMaskedToken(); - break; - case ESC_CHAR: - if (!isRawString){ - closeTag(myState); - eof=processEscapeCharState(); - openTag(myState); - returnedFromOtherState=true; - } - break; - case _EOF: - eof = true; - break; - default: - printMaskedToken(); - break; - } - } while ((!exitState) && (!eof)); - - closeTag(myState); - return eof; -} - -bool CodeGenerator::processTagState() -{ - State newState=STANDARD; - bool eof=false, exitState=false, returnedFromOtherState=false; - unsigned int myKeywordClass=currentKeywordClass; - - openTag(KEYWORD); - do { - if (!returnedFromOtherState) { - printMaskedToken(newState!=_WS); - } - returnedFromOtherState = false; - newState= getCurrentState(); - - switch(newState) - { - case _WS: - processWsState(); - break; - case _EOL: - insertLineNumber(); - exitState=true; - break; - case TAG_END: - printMaskedToken(); - exitState=true; - break; - case STRING: - closeTag(KEYWORD); - eof=processStringState(KEYWORD); - currentKeywordClass=myKeywordClass; - openTag(KEYWORD); - returnedFromOtherState = true; - break; - case ESC_CHAR: - closeTag(KEYWORD); - eof=processEscapeCharState(); - currentKeywordClass=myKeywordClass; - openTag(KEYWORD); - returnedFromOtherState = true; - break; - case NUMBER: - closeTag(KEYWORD); - eof=processNumberState(); - currentKeywordClass=myKeywordClass; - openTag(KEYWORD); - returnedFromOtherState = true; - break; - case _EOF: - eof = true; - break; - default: - printMaskedToken(); - break; - } - } while ((!exitState) && (!eof)); - - closeTag(KEYWORD); - currentKeywordClass=0; - - return eof; -} - -bool CodeGenerator::processSymbolState(){ - - State newState=STANDARD; - bool eof=false, - exitState=false; - - openTag(SYMBOL); - do { - printMaskedToken(newState!=_WS); - newState= getCurrentState(true); - switch(newState) - { - case _WS: - processWsState(); - break; - case _EOL: - insertLineNumber(); - exitState=true; - break; - case _EOF: - eof = true; - break; - default: - exitState=newState!=SYMBOL; - break; - } - } while ((!exitState) && (!eof)); - - closeTag(SYMBOL); - return eof; -} - -bool CodeGenerator::processEscapeCharState() -{ - State newState=STANDARD; - bool eof=false, exitState=false; - - openTag(ESC_CHAR); - do { - printMaskedToken(newState!=_WS); - skipEscapeSequence(); - newState= getCurrentState(); - switch(newState) - { - case _EOL: - insertLineNumber(); - exitState=true; - break; - case _WS: - processWsState(); - --lineIndex; - break; - case _EOF: - eof = true; - break; - default: - exitState=newState!=ESC_CHAR; - break; - } - } while ((!exitState) && (!eof)); - - closeTag(ESC_CHAR); - return eof; -} - -void CodeGenerator::skipEscapeSequence(){ - if (lineIndex<line.length()){ - char c=line[lineIndex]; - int charsToSkip=1; - // Escape Sequenz /ooo Oktal, /x000 hex, /u00xx Java unicode - if (isdigit(c) ){ - // \0 abfangen - while ( isdigit(line[lineIndex+charsToSkip]) && charsToSkip<4) { - ++charsToSkip; - } - } else if (tolower(c)=='x'){ - charsToSkip=langInfo.isJava() ? 4 : 3; - } else if (tolower(c)=='u'){ - charsToSkip=5; - } - while (charsToSkip-- && lineIndex++<line.length()){ - *out <<maskCharacter(line[lineIndex-1]); - } - } -} - - -void CodeGenerator::processWsState() -{ - if (!maskWs) { - wsBuffer += token; - token.clear(); - return; - } - flushWs(); - int cntWs=0; - lineIndex--; - - while (isspace(line[lineIndex]) ) { - ++cntWs; - ++lineIndex; - } - - if (cntWs>1) { - unsigned int styleID=getStyleID(currentState, currentKeywordClass); - if (excludeWs && styleID!=_UNKNOWN) { - *out << styleTagClose[styleID]; - } - *out << maskWsBegin; - for (int i=0; i<cntWs; i++){ - *out << spacer; - } - *out << maskWsEnd; - if (excludeWs && styleID!=_UNKNOWN){ - *out << styleTagOpen[styleID]; - } - } else { - *out << token; - } - token.clear(); -} - -void CodeGenerator::flushWs(){ - *out<<wsBuffer; - wsBuffer.clear(); -} - -bool CodeGenerator::isFirstNonWsChar() { - unsigned int i=lineIndex-1; - while (i--){ - if (!isspace(line[i])){ - return false; - } - } - return true; -} - -string CodeGenerator::getNewLine(){ - return newLineTag; -} - -void CodeGenerator::insertLineNumber(bool insertNewLine) { - if (insertNewLine){ - wsBuffer += getNewLine(); - } - if (showLineNumbers) { - ostringstream os; - ostringstream numberPrefix; - if (lineNumberFillZeroes) { - os.fill('0'); - } - os <<setw(LINE_NUMBER_WIDTH) << right << lineNumber; - - numberPrefix << styleTagOpen[LINENUMBER] - << maskString(os.str()) << spacer - << styleTagClose[LINENUMBER]; - - wsBuffer += numberPrefix.str(); - } -} - -unsigned int CodeGenerator::getLineIndex(){ - return lineIndex; -} - -bool CodeGenerator::printExternalStyle(const string &outFile) -{ - if (!includeStyleDef && langInfo.getSyntaxHighlight()) { - ofstream cssOutFile(outFile.c_str()); - if (cssOutFile) { - cssOutFile << styleCommentOpen - <<" Style definition file generated by highlight " - << HIGHLIGHT_VERSION << ", " << HIGHLIGHT_URL - << " " << styleCommentClose << "\n"; - cssOutFile << "\n"<<styleCommentOpen<<" Highlighting theme definition: " - << styleCommentClose << "\n\n" - << getStyleDefinition() - << "\n"; - cssOutFile << readUserStyleDef(); - cssOutFile.close(); - } else { - return false; - } - } - return true; -} - -string CodeGenerator::readUserStyleDef(){ - ostringstream ostr; - if (!styleInputPath.empty()){ - ifstream userStyleDef(styleInputPath.c_str()); - if (userStyleDef) { - ostr << "\n"<<styleCommentOpen<<" Content of "<<styleInputPath<<": "<<styleCommentClose<<"\n"; - string line; - while (getline(userStyleDef, line)){ - ostr << line << "\n"; - } - userStyleDef.close(); - } else { - ostr << styleCommentOpen<<" ERROR: Could not include " - << styleInputPath - << "."<<styleCommentClose<<"\n"; - } - } - return ostr.str(); -} - -bool CodeGenerator::checkSpecialCmd(){ - bool insertNL = (lineIndex-token.length()); - cerr << "token: "<<token<< " index"<< lineIndex << " "<<line [ lineIndex ]<<endl; - - if (line [ lineIndex ]=='!'){ - // find cmd - size_t cmdPos1 = line.find('@', lineIndex+1); - - cerr << "cmdPos"<<cmdPos1<<endl; - if(cmdPos1==string::npos) return false; - size_t cmdPos2=cmdPos1+1; - while (cmdPos2 < line.length() && StringTools::isAlpha(line[cmdPos2])) cmdPos2++; - cerr << "cmdPos2"<<cmdPos2<<endl; - cerr << line.substr(cmdPos1, cmdPos2)<<endl; - - // hide comment line - token.clear(); - lineIndex=line.length(); - getInputChar(); lineNumber--; - if (insertNL) { lineNumber++;insertLineNumber();}; - // end hide - - return true; - } - - return false; -} - -} -/*************************************************************************** - codeparser.h - description - ------------------- - begin : Die Jul 9 2002 - copyright : (C) 2002 by Andre Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef CODEPARSER_H -#define CODEPARSER_H - -#include <iostream> -#include <sstream> -#include <string> -#include <iomanip> -#include <cctype> - -#include "languagedefinition.h" -#include "documentstyle.h" -#include "ASFormatter.h" -#include "preformatter.h" -#include "enums.h" - - -#define NUMBER_BUILTIN_STYLES 10 -#define LINE_NUMBER_WIDTH 5 -#define MAX_LINE__WIDTH 80 - -#define OUTPUT_FLAG_LN 1 -#define OUTPUT_FLAG_LNZ 2 -#define OUTPUT_FLAG_FRAG 4 - -/** The highlight namespace contains all classes and data structures - needed for parsing input data. -*/ -namespace highlight { - -/** \brief Base class for parsing. Works similar to a Turing machine. - - The virtual class provides source code parsing functioality, based on - information stored in language definitions.<br> - Deriving classes have to define the output format.<br> - Codegenerator is a singleton class. - -* @author Andre Simon -*/ - -class CodeGenerator - { - - public: - - virtual ~CodeGenerator(); - - /** - Get appropriate Codegenerator instance - \param type Output file type (HTML, XHTML, RTF, LATEX, TEX, XSLFO, ANSI) - \param styleInfoPath Path to formatting style information - \param styleInPath Path to style definition input file (to be included in styleOutPath) - \param styleOutPath Path to style definition output file (CSS path for HTML output) - \param encoding Output file encoding name - \param includeStyle Switch to include style information in output file (only XHTML, HTML) - \param attachAnchors Switch to attach anchors to line numbers (only XHTML, HTML) - \param replaceQuotes Switch to replace quotes by \dq{} (only LATEX) - \param fopCompatible Switch to generate FO for Apache FOP (only XSLFO) - \param omitEncoding Switch to omit encoding info in output document - \param ln Set true if line numbers should be printed - \param lnz Set true if leading space of line numbers should be filled with 0's - \param fragment Set true if document header and footer should be omitted - \param numSpaces Number of spaces which replace a tab - \param lineWrappingMode Line wrapping mode - */ - static CodeGenerator* getInstance(OutputType type, - const string& styleInfoPath, - const string& styleInPath, - const string& styleOutPath, - const string& encoding, - bool includeStyle, - bool attachAnchors, - bool replaceQuotes, - bool fopCompatible, - int numSpaces, - WrapMode lineWrappingMode, - bool ln, - bool lnz, - bool fragment, - bool omitEncoding ); - - /** Deletes the singleton CodeGenerator instance. - Call this method if getInstance was already called, or if you want to - free the momory after usage.*/ - static void deleteInstance(); - - /** - Generates output - \param inFileName Path of input file (if empty use stdin) - \param outFileName Path of input file (if empty use stdout) - - \return ParseError - */ - ParseError printOutput(const string &inFileName, const string &outFileName); - - /** \return True if document style was found */ - bool styleFound(); - - /** \return True if reformatting of current input is disabled */ - bool formattingDisabled(); - - /** \return True if reformatting of current input is possible */ - bool formattingIsPossible(); - - /** \param langDefPath Absolute path to language definition - \return Failure: LOAD_FAILED; Reload necessary: LOAD_NEW, - no reload necessary: LOAD_NONE */ - LoadResult initLanguage(const string& langDefPath); - - /** \return Language definition*/ - LanguageDefinition &getLanguage(); - - /** tell parser to output line numbers - \param flag true if line numbers should be printed - */ - void setPrintLineNumbers(bool flag); - - /** \return line number flag */ - bool getPrintLineNumbers(); - - - /** tell parser to output line numbers filled with zeroes - \param flag true if zeroes should be printed - */ - void setPrintZeroes(bool flag); - - /** \return print zeroes flag */ - bool getPrintZeroes(); - - /** tell parser to omit document header and footer - \param flag true if output should be fragmented - */ - void setFragmentCode(bool flag); - - /** \return fragment flag */ - bool getFragmentCode(); - - /** tell parser the style name - \param s path to style definition - */ - void setStyleName(const string& s); - - /** \return style path */ - const string& getStyleName(); - - /** tell parser the wrapping mode - \param lineWrappingStyle wrapping style - \param lineLength max line length - \param numberSpaces number of spaces which replace a tab - */ - void setPreformatting(WrapMode lineWrappingStyle, unsigned int lineLength,int numberSpaces); - - /** \return wrapping style */ - WrapMode getLineWrapping(); - - /** tell parser the include style definition in output - \param flag true if style should be included - */ - void setIncludeStyle(bool flag); - - /** Print style definitions to external file - \param outFile Path of external style definition - */ - bool printExternalStyle(const string &outFile); - - /** Print index file with all input file names - \param fileList List of output file names - \param outPath Output path - */ - virtual bool printIndexFile(const vector<string> & fileList, - const string &outPath); - - /** initialize source code indentation - \param indentSchemePath Path of indentation scheme - \return true id successfull - */ - bool initIndentationScheme(const string&indentSchemePath); - - /** Set style input path - \param s path to style input file - */ - void setStyleInputPath(const string& path); - - /** Set style output path - \param s path to style output file - */ - void setStyleOutputPath(const string& path); - -/** Set output type - \param s output type - */ - void setType(OutputType t); - - /** - \return style input file path - */ - const string& getStyleInputPath(); - - /** - \return style output file path - */ - const string& getStyleOutputPath(); - -protected: - - CodeGenerator(); - - //! CodeGenerator Constructor - /** - \param colourTheme Name of coloring style being used - */ - CodeGenerator(const string &colourTheme); - - /** \param c Character to be masked - \return Escape sequence of output format */ - virtual string maskCharacter(unsigned char c) = 0; - - /** \param s string - \return Copy of s with all escaped characters */ - string maskString(const string &s ) ; - - /** \param s Symbol string - \param searchPos Position where search starts - \return Found state (integer value) */ - State getState(const string &s, unsigned int searchPos); - - /** \return Next identifier in current line of code */ - string getIdentifier(); - - /** \return Next number in current line of code */ - string getNumber(); - - /** Insert line number at the beginning of current output line */ - virtual void insertLineNumber(bool insertNewLine=true); - - /** Prints document footer*/ - virtual string getFooter() = 0; - - /** Prints document body*/ - virtual void printBody() = 0; - - /** prints document header - \param title Title of the document - */ - virtual string getHeader(const string &title) = 0; - - /** Get current line number - \return line number */ - unsigned int getLineNumber(); - - - /** Tag Delimiters for every colour style*/ - vector <string> styleTagOpen, styleTagClose; - - /** Description of document colour style*/ - DocumentStyle docStyle; - - /** Language definition*/ - LanguageDefinition langInfo; - - /** Tag for inserting line feeds*/ - string newLineTag; - - /** String that represents a white space in output */ - string spacer; - - /** file input*/ - istream *in; - - /** file output*/ - ostream *out; - - /** Tags which enclose white space indentation blocks */ - string maskWsBegin, maskWsEnd; - - /** Style comment delimiters */ - string styleCommentOpen, styleCommentClose; - - /** Test if maskWsBegin and maskWsEnd should be applied */ - bool maskWs; - - /** Test if whitespace sould always be separated from enclosing tokens */ - bool excludeWs; - - /** Test if header and footer should be omitted */ - bool fragmentOutput; - - /** Test if line numbers should be printed */ - bool showLineNumbers; - - /** Test if leading spyce of line number should be filled with zeroes*/ - bool lineNumberFillZeroes; - - /** Current line of input file*/ - string line; - - /** Current line number */ - unsigned int lineNumber; - - // Zeigt den aktuellen Zustand an - // wird nicht in getCurrentState gesetzt, da nur Zustände interessant - // sind, die als Index auf die styleCloseTags und styleOpenTags verwendet - // werden können - /** Current state*/ - State currentState; - - /** keyword class id, used to apply the corresponding keyword style*/ - unsigned int currentKeywordClass; - - /** Processes origin state */ - void processRootState(); - - /** return line break sequence */ - virtual string getNewLine(); - - /** - \param s current state - \return Index of style tag corresponding to the states - */ - unsigned int getStyleID(State s, unsigned int kwClassID = 0); - - /** \return line index */ - unsigned int getLineIndex(); - - /** print all remaining white space*/ - void flushWs(); - - /** - \return Content of user defined input style - */ - string readUserStyleDef(); - - /** - \return Style definition of the chosen output format - */ - virtual string getStyleDefinition() {return "";}; - - /** contains white space, which will be printed after a closing tag */ - string wsBuffer; - - /** - Flag to test if style definition should be included in output document - */ - bool includeStyleDef; - -private: - - CodeGenerator(const CodeGenerator&){} - CodeGenerator& operator=(CodeGenerator&){ return *this;} - - static CodeGenerator* generator; - - /** return matching open and close tags of the given state */ - virtual string getMatchingOpenTag(unsigned int) = 0; - virtual string getMatchingCloseTag(unsigned int) = 0; - - /** open a new tag, set current state to s*/ - void openTag(State s); - - /** close opened tag, clear current state */ - void closeTag(State s); - - void closeTag(unsigned int styleID); - - void openTag(unsigned int styleID); - - // path to style definition file - string stylePath; - - // contains current position in line - unsigned int lineIndex; - - /**last character of the last line*/ - unsigned char terminatingChar; - - /** Class for reformatting */ - astyle::ASFormatter *formatter; - - /** Class for line wrapping and tab replacement*/ - PreFormatter *preFormatter; - - /** Flag to test if formatting is enabled with current input document*/ - bool formattingEnabled; - - - /** Flag to test if formatting is possible with current input document*/ - bool formattingPossible; - - /** contains the current token*/ - string token; - - string styleInputPath, styleOutputPath; - - /** Resets parser to origin state, call this after every file conversion */ - void reset(); - - /** read new line from in stream */ - bool readNewLine(string &newLine); - - /** return next character from in stream */ - unsigned char getInputChar(); - - OutputType outputType; - - /** return new state */ - State getCurrentState ( bool lastStateWasNumber=false); - - /** Methods that represent a parsing state */ - bool processKeywordState(State myState) ; - bool processNumberState() ; - bool processMultiLineCommentState(); - bool processSingleLineCommentState(); - bool processStringState(State oldState); - bool processEscapeCharState(); - bool processDirectiveState(); - bool processTagState(); - bool processSymbolState(); - void processWsState(); - - /** gibt true zurck, falls c ein erlaubter Character innerhalb von Keyword - oder Typbezeichner ist */ - bool isAllowedChar(char c) ; - - /** returns true if curret token is the first in line and no whitespace */ - bool isFirstNonWsChar() ; - - /** print escaped token and clears it */ - void printMaskedToken(bool flushWhiteSpace=true); - - /** print escape sequence */ - void skipEscapeSequence(); - - void closeKWTag(unsigned int styleID); - void openKWTag(unsigned int styleID); - - /** look for special commands in comments, take action in derived class - \return true if command was found - */ - bool checkSpecialCmd(); - - }; -} - -#endif - -/* - * Copyright (c) 1998,1999,2000,2001,2002 Tal Davidson. All rights reserved. - * - * compiler_defines.h (1 January 1999) - * by Tal Davidson (davidsont@bigfoot.com) - * This file is a part of "Artistic Style" - an indentater and reformatter - * of C, C++, C# and Java source files. - * - * The "Artistic Style" project, including all files needed to compile it, - * is free software; you can redistribute it and/or use it and/or modify it - * under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2 of the License, - * or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public - * License along with this program. - */ - - - - - -/* - * comment out the line below if your compiler does NOT understand NAMESPACES - */ -#define USES_NAMESPACE - - -#if defined(__GNUC__) && __GNUC__ < 3 -// for G++ implementation of string.compare: -#define COMPARE(place, length, str) compare((str), (place), (length)) -#else -// for standard implementation of string.compare: -#define COMPARE(place, length, str) compare((place), (length), (str)) -#endif - - -// Fix by John A. McNamara -// Get rid of annoying MSVC warnings on debug builds about lengths of -// identifiers in template instantiations. -#ifdef _MSC_VER -#pragma warning( disable:4786 ) -#endif - -/*************************************************************************** - configurationreader.cpp - description - ------------------- - begin : Son Nov 10 2002 - copyright : (C) 2002 by André Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "configurationreader.h" - -using namespace std; - -ConfigurationReader::ConfigurationReader(const string & configuration_path) -{ - ifstream in (configuration_path.c_str()); - fileFound=in; - if (fileFound) { - string line; - line.reserve(500); - unsigned int lineBegin; - size_t delimPos; - string paramName, paramValue; - while (getline(in, line)) { - lineBegin=line.find_first_not_of("\t "); - if ((line.size()>2) && (lineBegin!=string::npos) - && (line.at(lineBegin)!='#')) { //comment? - if (line[lineBegin]=='$') { // neuer Parametername? - delimPos=line.find("=",lineBegin)-1; - if (delimPos!=string::npos) { - paramName=StringTools::trimRight( - StringTools::lowerCase(line.substr(lineBegin+1, delimPos))); - parameterNames.push_back(paramName); - paramValue=line.substr(delimPos+2, line.length()); - } - } else { // line belongs to last parameter - paramValue=line; - } - if (parameterMap[paramName].empty()) { - parameterMap[paramName] = paramValue; - } else { - parameterMap[paramName]+= (" "+paramValue); - } - } //if ((lineBegin!=string::npos) && (line.at(lineBegin)!='#')) - } //while - in.close(); - } //if (in) -} - -ConfigurationReader::~ConfigurationReader() -{ -} - -bool ConfigurationReader::found() -{ - return fileFound; -} - -string &ConfigurationReader::getParameter(const string & paramName) -{ - return parameterMap[paramName] ; -} - -const char* ConfigurationReader::getCParameter(const string & paramName) -{ - return parameterMap[paramName].c_str() ; -} - -vector<string> &ConfigurationReader::getParameterNames() -{ - return parameterNames; -} -/*************************************************************************** - configurationreader.h - description - ------------------- - begin : Son Nov 10 2002 - copyright : (C) 2002 by Andr�Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef CONFIGURATIONREADER_H -#define CONFIGURATIONREADER_H - -#include <string> -#include <sstream> -#include <map> -#include <iostream> -#include <fstream> -#include <vector> - -#include "stringtools.h" - -using namespace std; - -/** Maps parameter keys to values*/ -typedef map<string, string> ParameterMap; - - -/** \brief Class to handle ASCII config files - - Configuration file format:<br> - $ParamName=ParamValue<br> - ParamValue may be splittet over multiple lines<br> - ParamName is not case sensitive<br> - Comments start with # as the first character of a line - - **/ - -class ConfigurationReader - { - public: - /** Constructor - \param configuration_path Path to configuration file - */ - ConfigurationReader(const string & configuration_path); - ~ConfigurationReader(); - - /** \param paramName Name of parameter - \return Value of parameter */ - string &getParameter(const string & paramName); - - /** \param paramName Name of parameter - \return Value of parameter */ - const char* getCParameter(const string & paramName); - - /** \return True if config file exists */ - bool found(); - - /** \return List of parameter names */ - vector<string> &getParameterNames(); - - private: - ParameterMap parameterMap; - bool fileFound; - vector<string> parameterNames; - }; - -#endif -/*************************************************************************** - dataDir.cpp - description - ------------------- - begin : Sam M� 1 2003 - copyright : (C) 2003 by André Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "datadir.h" - -using namespace std; - -bool DataDir::searchDataDir(const string &userDefinedDir){ -#ifndef _WIN32 - - bool found = false; - //falls kein Datenverzeichnis angegeben, startIndex auf 1 setzen - int searchStartIndex=(userDefinedDir.empty()); - - string possibleDirs[] ={ userDefinedDir, - #ifdef HL_DATA_DIR - HL_DATA_DIR, - #endif - "/usr/share/highlight/" - }; - - for (int i=searchStartIndex;i< - #ifdef HL_DATA_DIR - 3 - #else - 2 - #endif - ;i++) - { - if (fileExists(possibleDirs[i])) - { - dataDir=possibleDirs[i]; - found = true; - } - if (found) { - break; - } - else { - if (!searchStartIndex) - cerr << "highlight: directory " - << userDefinedDir - << " specified by data-dir option not found.\n" - << " Searching another standard directory.\n"; - - } - } - return found; -#else - dataDir=userDefinedDir; - return true; -#endif - -} - -DataDir::DataDir() -{ -} - -void DataDir::setAdditionalDataDir(const string& dir){ - additionalDataDir=dir; -} - -const string &DataDir::getDir() -{ - return dataDir; -} - -const string DataDir::getLangDefDir() -{ - return dataDir+"langDefs"+Platform::pathSeparator; -} - -const string DataDir::getThemeDir() -{ - return dataDir+"themes"+Platform::pathSeparator; -} - -const string DataDir::getIndentSchemesDir() -{ - return dataDir+"indentSchemes"+Platform::pathSeparator; -} - - -const string DataDir::getAdditionalLangDefDir() -{ - return additionalDataDir+"langDefs"+Platform::pathSeparator; -} - -const string DataDir::getAdditionalThemeDir() -{ - return additionalDataDir+"themes"+Platform::pathSeparator; -} -const string DataDir::getAdditionalIndentSchemesDir() -{ - return additionalDataDir+"indentSchemes"+Platform::pathSeparator; -} - - -const string DataDir::getHelpMsgDir() -{ - return dataDir+"helpmsg"+Platform::pathSeparator; -} - -const string DataDir::searchForLangDef(const string & langDef){ - if (!additionalDataDir.empty()){ - string path=getAdditionalLangDefDir()+langDef; - if (fileExists(path)){ - return path; - } - } - return getLangDefDir()+langDef; -} - -const string DataDir::searchForTheme(const string & theme){ - if (!additionalDataDir.empty()){ - string path=getAdditionalThemeDir()+theme; - if (fileExists(path)){ - return path; - } - } - return getThemeDir()+theme; -} - -const string DataDir::searchForIndentScheme(const string & scheme){ - if (!additionalDataDir.empty()){ - string path=getAdditionalIndentSchemesDir()+scheme; - if (fileExists(path)){ - return path; - } - } - return getIndentSchemesDir()+scheme; -} - - -bool DataDir::fileExists(const string&f){ - ifstream file(f.c_str()); - bool exists=!file.fail(); - file.close(); - return exists; -} -/*************************************************************************** - datadir.h - description - ------------------- - begin : Sam M� 1 2003 - copyright : (C) 2003 by Andre Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef DATADIR_H -#define DATADIR_H - -#include <string> -#include <fstream> -#include <iostream> -//#include "stringtools.h" -#include "platform_fs.h" - -using namespace std; - - /** \brief Manages access to installation directories. - - Apart from the standard installation directory, one can define additional - search paths. - **/ - -class DataDir - { - string dataDir; - string additionalDataDir; - bool fileExists(const string&f); - - public: - - DataDir(); - - /** search for a valid installation directory - \param userDefinedDir Directory defined by user - \return True if directory was found */ - bool searchDataDir(const string &userDefinedDir); - - /** add another installation directory, which is added to search path - \param dir Directory defined by user */ - void setAdditionalDataDir(const string& dir); - - /** \return Data installation directory */ - const string & getDir() ; - - /** \return Location of languafe definitions */ - const string getLangDefDir() ; - - /** \return Location of themes */ - const string getThemeDir() ; - - /** \return Location of indentation schemes */ - const string getIndentSchemesDir(); - - /** \return User defined location of indentation schemes */ - const string getAdditionalIndentSchemesDir(); - - /** \return User defined location of languafe definitions */ - const string getAdditionalLangDefDir() ; - - /** \return User defined location of themes */ - const string getAdditionalThemeDir() ; - - /** \return Location of help files */ - const string getHelpMsgDir() ; - - /** \param langDef Name of language definition - \return Absolute path of definiton found in a data directory */ - const string searchForLangDef(const string & langDef); - - /** \param theme Name of colour theme file - \return Absolute path of theme found in a data directory */ - const string searchForTheme(const string & theme); - - /** \param scheme Name of indent scheme file - \return Absolute path of theme found in a data directory */ - const string searchForIndentScheme(const string & scheme); - }; - -#endif -/*************************************************************************** - documentstyle.cpp - description - ------------------- - begin : Son Nov 10 2002 - copyright : (C) 2002 by Andre Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "documentstyle.h" - -namespace highlight { - -DocumentStyle::DocumentStyle(const string &styleDefinitionFile) -{ - fileFound=load(styleDefinitionFile); -} -DocumentStyle::DocumentStyle():fileFound(false) -{} - -bool DocumentStyle::load(const string &styleDefinitionPath) -{ - ConfigurationReader styleConfig(styleDefinitionPath); - if (styleConfig.found()){ - fontsize = styleConfig.getParameter("fontsize"); - bgColour.setRGBValues(styleConfig.getParameter("bgcolour")); - defaultElem.set(styleConfig.getParameter("defaultcolour")); - comment.set(styleConfig.getParameter("comment")); - directive.set(styleConfig.getParameter("directive")); - str.set(styleConfig.getParameter("string")); - escapeChar.set(styleConfig.getParameter("escapechar")); - number.set(styleConfig.getParameter("number")); - dstr.set(styleConfig.getParameter("string_directive")); - line.set(styleConfig.getParameter("line")); - - - string tmpstr; - // TODO: Remove this check as soon as all themes have a brackets attribute - tmpstr=styleConfig.getParameter("symbol"); - if (tmpstr.empty()) { - tmpstr=styleConfig.getParameter("defaultcolour"); - } - symbol.set(tmpstr); - -// TODO: Remove this check as soon as all themes have a sl-comment attribute - tmpstr=styleConfig.getParameter("sl-comment"); - if (tmpstr.empty()) { - tmpstr=styleConfig.getParameter("comment"); - } - slcomment.set(tmpstr); - - string paramVal; - vector<string> paramNames=styleConfig.getParameterNames(); - - //collect keyword classes, save corresponding style definition - for (unsigned int i=0;i<paramNames.size();i++){ - paramVal=paramNames[i]; - if (paramVal.find("kw_class") != string::npos){ - keywordStyles.insert(make_pair(StringTools::getParantheseVal(paramVal), - new ElementStyle(styleConfig.getParameter(paramVal)))); - } - } - - fileFound = true; - } - else { - fileFound = false; - } - return fileFound; -} - -DocumentStyle::~DocumentStyle() -{ - for(KSIterator iter = keywordStyles.begin(); iter != keywordStyles.end(); iter++){ - delete (*iter).second; //remove ElementStyle* - } -} - -string& DocumentStyle::getFontSize() - { - return fontsize; - } -StyleColour& DocumentStyle::getBgColour() - { - return bgColour; - } -ElementStyle& DocumentStyle::getDefaultStyle() - { - return defaultElem; - } -ElementStyle& DocumentStyle::getCommentStyle() - { - return comment; - } -ElementStyle& DocumentStyle::getSingleLineCommentStyle() - { - return slcomment; - } - - -ElementStyle& DocumentStyle::getStringStyle() - { - return str; - } -ElementStyle& DocumentStyle::getDirectiveStringStyle() - { - return dstr; - } -ElementStyle& DocumentStyle::getEscapeCharStyle() - { - return escapeChar; - } -ElementStyle& DocumentStyle::getNumberStyle() - { - return number; - } -ElementStyle& DocumentStyle::getDirectiveStyle() - { - return directive; - } -ElementStyle& DocumentStyle::getLineStyle() - { - return line; - } -ElementStyle& DocumentStyle::getSymbolStyle() - { - return symbol; - } -bool DocumentStyle::found () const - { - return fileFound; - } -ElementStyle& DocumentStyle::getKeywordStyle(const string &className){ - if (!keywordStyles.count(className)) return defaultElem; - return *keywordStyles[className]; -} - -vector <string> DocumentStyle::getClassNames(){ - vector <string> kwClassNames; - for(KSIterator iter = keywordStyles.begin(); iter != keywordStyles.end(); iter++){ - kwClassNames.push_back( (*iter).first); - } - return kwClassNames; -} - -KeywordStyles& DocumentStyle::getKeywordStyles(){ - return keywordStyles; -} - -} -/*************************************************************************** - documentstyle.h - description - ------------------- - begin : Son Nov 10 2002 - copyright : (C) 2002 by Andre Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef DOCUMENTSTYLE_H -#define DOCUMENTSTYLE_H - -#include <string> -#include <iostream> -#include "configurationreader.h" -#include "elementstyle.h" -#include "stylecolour.h" - -using namespace std; - -namespace highlight { - -/** maps keyword class names and the corresponding formatting information*/ -typedef map <string, ElementStyle*> KeywordStyles; - -/** iterator for keyword styles*/ -typedef KeywordStyles::iterator KSIterator; - -/** \brief Contains information about document formatting properties. - -* @author Andre Simon -*/ - -class DocumentStyle - { - private: - ElementStyle comment, slcomment, str, dstr, - escapeChar, number, directive, line, symbol; - ElementStyle defaultElem; - StyleColour bgColour; - - string fontsize; - bool fileFound; - - KeywordStyles keywordStyles; - - public: - /** Constructor - \param styleDefinitionPath Style definition path */ - DocumentStyle(const string & styleDefinitionPath); - DocumentStyle(); - ~DocumentStyle(); - - /** load sytle definition - \param styleDefinitionFile Style definition path - \return True if successfull */ - bool load(const string & styleDefinitionFile); - - /** \return class names defined in the theme file */ - vector <string> getClassNames(); - - /** \return keyword styles */ - KeywordStyles& getKeywordStyles(); - - /** \return Font size */ - string &getFontSize() ; - - /** \return Background colour*/ - StyleColour& getBgColour(); - - /** \return Style of default (unrecognized) strings */ - ElementStyle & getDefaultStyle() ; - - /** \return Comment style*/ - ElementStyle & getCommentStyle() ; - - /** \return Single line comment style*/ - ElementStyle& getSingleLineCommentStyle() ; - - /** \return Keyword style*/ - ElementStyle & getKeywordStyle() ; - - /** \return String style*/ - ElementStyle & getStringStyle() ; - - /** \return Directive line string style*/ - ElementStyle & getDirectiveStringStyle() ; - - /** \return Escape character style*/ - ElementStyle & getEscapeCharStyle() ; - - /** \return Number style*/ - ElementStyle & getNumberStyle() ; - - /** \return Directive style*/ - ElementStyle & getDirectiveStyle() ; - - /** \return Type style*/ - ElementStyle & getTypeStyle() ; - - /** \return Line number style*/ - ElementStyle & getLineStyle() ; - - /** \return Bracket style*/ - ElementStyle & getSymbolStyle() ; - - /** - \param className Name of keyword class - \return keyword style of the given className - */ - ElementStyle & getKeywordStyle(const string &className); - - /** \return True if language definition was found */ - bool found() const ; - }; - -} - -#endif -/*************************************************************************** - elementstyle.cpp - description - ------------------- - begin : Son Nov 10 2002 - copyright : (C) 2002 by André Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "elementstyle.h" - -namespace highlight { - -ElementStyle::ElementStyle(StyleColour col, bool b, bool i, bool u) - : colour(col) , bold(b), italic(i), underline(u) -{} - -ElementStyle:: ElementStyle(const string & elementStyleString) - : bold(false), italic(false), underline(false) -{ - set(elementStyleString); -} - -ElementStyle::ElementStyle() - : bold(false), italic(false), underline(false) -{} - -void ElementStyle::set(const string & elementStyleString){ - - istringstream valueStream(elementStyleString.c_str()); - string r, g, b, attr; - valueStream >> r; - valueStream >> g; - valueStream >> b; - colour.setRedValue(r); - colour.setGreenValue(g); - colour.setBlueValue(b); - while ( valueStream >> attr) - { - if (attr=="italic") - { - italic = true; - } - else if (attr=="bold") - { - bold = true; - } - else if (attr=="underline") - { - underline = true; - } - } -} - -ElementStyle::~ElementStyle() -{} - -bool ElementStyle::isItalic() const -{ - return italic; -} -bool ElementStyle::isBold() const -{ - return bold; -} -bool ElementStyle::isUnderline() const -{ - return underline; -} -StyleColour ElementStyle::getColour() const -{ - return colour; -} - -} -/*************************************************************************** - elementstyle.h - description - ------------------- - begin : Son Nov 10 2002 - copyright : (C) 2002 by Andre Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef ELEMENTSTYLE_H -#define ELEMENTSTYLE_H - -#include <sstream> - -#include "stylecolour.h" - -using namespace std; - -namespace highlight { - -/** \brief The class stores the basic text formatting properties. - -* @author Andre Simon -*/ - -class ElementStyle { - public: - - /** Constructor - \param col Style colour - \param b Bold flag - \param i Italic flag - \param u Underline flag */ - ElementStyle(StyleColour col, bool b, bool i, bool u); - - /** Constuctor - \param elementStyleString String with fotmatting information */ - ElementStyle(const string & elementStyleString); - - ElementStyle(); - - ~ElementStyle(); - - /** initialize object - \param elementStyleString String which contains formatting attributes - */ - void set(const string & elementStyleString); - - /** \return True if italic */ - bool isItalic() const; - - /** \return True if bold */ - bool isBold() const; - - /** \return True if underline */ - bool isUnderline() const; - - /** \return Element colour */ - StyleColour getColour() const; - - private: - StyleColour colour; - bool bold, italic, underline; - }; - -} - -#endif -// -// C++ Interface: enums -// -// Description: -// -// -// Author: Andre Simon <andre.simon1@gmx.de>, (C) 2004 -// -// Copyright: See COPYING file that comes with this distribution -// -// - -#ifndef ENUMS_H -#define ENUMS_H - -namespace highlight { - -/** states which may occour during input file parsing*/ -enum State { - STANDARD=0, - STRING, - NUMBER, - SL_COMMENT, - ML_COMMENT_BEGIN, - ESC_CHAR, - DIRECTIVE_LINE, - DIRECTIVE_STRING, - LINENUMBER, - SYMBOL, - - // Konstanten ab hier duefen nicht mehr als Array-Indizes benutzt werden!! - KEYWORD, - ML_COMMENT_END, - DIRECTIVE_LINE_END, - TAG_BEGIN, - TAG_END, - KEYWORD_BEGIN, - KEYWORD_END, - - _UNKNOWN=100, - _EOL, - _EOF, - _WS -} ; - -/** Parser return values*/ -enum ParseError{ - PARSE_OK, - BAD_INPUT=1, - BAD_OUTPUT=2, - BAD_STYLE=4 -}; - -/** line wrapping modes*/ -enum WrapMode { - WRAP_DISABLED, - WRAP_SIMPLE, - WRAP_DEFAULT -}; - -/** language definition loading results*/ -enum LoadResult{ - LOAD_FAILED, - LOAD_NEW, - LOAD_NONE -}; - -/** output formats */ -enum OutputType { - HTML, - XHTML, - TEX, - LATEX, - RTF, - XSLFO, - XML, - ANSI -}; - -} - -#endif -/* Getopt for GNU. - NOTE: getopt is now part of the C library, so if you don't know what - "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu - before changing it! - - Copyright (C) 1987, 88, 89, 90, 91, 92, 1993 - Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifndef __STDC__ -# ifndef const -# define const -# endif -#endif - -/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */ -#ifndef _NO_PROTO -#define _NO_PROTO -#endif - -#include <cstdio> -#include <cstring> -//#include "tailor.h" - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#if defined (_LIBC) || !defined (__GNU_LIBRARY__) - - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -/* Don't include stdlib.h for non-GNU C libraries because some of them - contain conflicting prototypes for getopt. */ -#include <stdlib.h> -#endif /* GNU C library. */ - -/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a - long-named option. Because this is not POSIX.2 compliant, it is - being phased out. */ -/* #define GETOPT_COMPAT */ - -/* This version of `getopt' appears to the caller like standard Unix `getopt' - but it behaves differently for the user, since it allows the user - to intersperse the options with the other arguments. - - As `getopt' works, it permutes the elements of ARGV so that, - when it is done, all the options precede everything else. Thus - all application programs are extended to handle flexible argument order. - - Setting the environment variable POSIXLY_CORRECT disables permutation. - Then the behavior is completely standard. - - GNU application programs can use a third alternative mode in which - they can distinguish the relative order of options and other arguments. */ - -#include "getopt.h" - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -char *optarg = 0; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns EOF, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -/* XXX 1003.2 says this must be 1 before any call. */ -int optind = 0; - -/* The next char to be scanned in the option-element - in which the last option character we returned was found. - This allows us to pick up the scan where we left off. - - If this is zero, or a null string, it means resume the scan - by advancing to the next ARGV-element. */ - -static char *nextchar; - -/* Callers store zero here to inhibit the error message - for unrecognized options. */ - -int opterr = 1; - -/* Set to an option character which was unrecognized. - This must be initialized on some systems to avoid linking in the - system's own getopt implementation. */ - -#define BAD_OPTION '\0' -int optopt = BAD_OPTION; - -/* Describe how to deal with options that follow non-option ARGV-elements. - - If the caller did not specify anything, - the default is REQUIRE_ORDER if the environment variable - POSIXLY_CORRECT is defined, PERMUTE otherwise. - - REQUIRE_ORDER means don't recognize them as options; - stop option processing when the first non-option is seen. - This is what Unix does. - This mode of operation is selected by either setting the environment - variable POSIXLY_CORRECT, or using `+' as the first character - of the list of option characters. - - PERMUTE is the default. We permute the contents of ARGV as we scan, - so that eventually all the non-options are at the end. This allows options - to be given in any order, even with programs that were not written to - expect this. - - RETURN_IN_ORDER is an option available to programs that were written - to expect options and other ARGV-elements in any order and that care about - the ordering of the two. We describe each non-option ARGV-element - as if it were the argument of an option with character code 1. - Using `-' as the first character of the list of option characters - selects this mode of operation. - - The special argument `--' forces an end of option-scanning regardless - of the value of `ordering'. In the case of RETURN_IN_ORDER, only - `--' can cause `getopt' to return EOF with `optind' != ARGC. */ - -static enum -{ - REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER -} ordering; - -#ifdef __GNU_LIBRARY__ -/* We want to avoid inclusion of string.h with non-GNU libraries - because there are many ways it can cause trouble. - On some systems, it contains special magic macros that don't work - in GCC. */ -#include <string.h> -#define my_index strchr -#define my_strlen strlen -#else - -/* Avoid depending on library functions or files - whose names are inconsistent. */ - -#if __STDC__ || defined(PROTO) - #ifndef _WIN32 - // Solaris compilation fix - extern "C" { - char *getenv(const char *name); - int strncmp(const char *s1, const char *s2, int n); - } - // extern char *getenv(const char *name); - // extern int strncmp(const char *s1, const char *s2, int n); - #endif - extern int strcmp (const char *s1, const char *s2); - static int my_strlen(const char *s); - static char *my_index (const char *str, int chr); -#else - #ifndef _WIN32 - extern char *getenv (); - #endif -#endif - -static int -my_strlen (const char *str) - -{ - int n = 0; - while (*str++) - n++; - return n; -} - -static char * -my_index ( const char *str, - int chr) - -{ - while (*str) - { - if (*str == chr) - return (char *) str; - str++; - } - return 0; -} - -#endif /* GNU C library. */ - -/* Handle permutation of arguments. */ - -/* Describe the part of ARGV that contains non-options that have - been skipped. `first_nonopt' is the index in ARGV of the first of them; - `last_nonopt' is the index after the last of them. */ - -static int first_nonopt; -static int last_nonopt; - -/* Exchange two adjacent subsequences of ARGV. - One subsequence is elements [first_nonopt,last_nonopt) - which contains all the non-options that have been skipped so far. - The other is elements [last_nonopt,optind), which contains all - the options processed since those non-options were skipped. - - `first_nonopt' and `last_nonopt' are relocated so that they describe - the new indices of the non-options in ARGV after they are moved. - - To perform the swap, we first reverse the order of all elements. So - all options now come before all non options, but they are in the - wrong order. So we put back the options and non options in original - order by reversing them again. For example: - original input: a b c -x -y - reverse all: -y -x c b a - reverse options: -x -y c b a - reverse non options: -x -y a b c -*/ - -#if __STDC__ || defined(PROTO) -static void exchange (char **argv); -#endif - -static void -exchange (char **argv) - -{ - char *temp, **first, **last; - - /* Reverse all the elements [first_nonopt, optind) */ - first = &argv[first_nonopt]; - last = &argv[optind-1]; - while (first < last) { - temp = *first; *first = *last; *last = temp; first++; last--; - } - /* Put back the options in order */ - first = &argv[first_nonopt]; - first_nonopt += (optind - last_nonopt); - last = &argv[first_nonopt - 1]; - while (first < last) { - temp = *first; *first = *last; *last = temp; first++; last--; - } - - /* Put back the non options in order */ - first = &argv[first_nonopt]; - last_nonopt = optind; - last = &argv[last_nonopt-1]; - while (first < last) { - temp = *first; *first = *last; *last = temp; first++; last--; - } -} - -/* Scan elements of ARGV (whose length is ARGC) for option characters - given in OPTSTRING. - - If an element of ARGV starts with '-', and is not exactly "-" or "--", - then it is an option element. The characters of this element - (aside from the initial '-') are option characters. If `getopt' - is called repeatedly, it returns successively each of the option characters - from each of the option elements. - - If `getopt' finds another option character, it returns that character, - updating `optind' and `nextchar' so that the next call to `getopt' can - resume the scan with the following option character or ARGV-element. - - If there are no more option characters, `getopt' returns `EOF'. - Then `optind' is the index in ARGV of the first ARGV-element - that is not an option. (The ARGV-elements have been permuted - so that those that are not options now come last.) - - OPTSTRING is a string containing the legitimate option characters. - If an option character is seen that is not listed in OPTSTRING, - return BAD_OPTION after printing an error message. If you set `opterr' to - zero, the error message is suppressed but we still return BAD_OPTION. - - If a char in OPTSTRING is followed by a colon, that means it wants an arg, - so the following text in the same ARGV-element, or the text of the following - ARGV-element, is returned in `optarg'. Two colons mean an option that - wants an optional arg; if there is text in the current ARGV-element, - it is returned in `optarg', otherwise `optarg' is set to zero. - - If OPTSTRING starts with `-' or `+', it requests different methods of - handling the non-option ARGV-elements. - See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. - - Long-named options begin with `--' instead of `-'. - Their names may be abbreviated as long as the abbreviation is unique - or is an exact match for some defined option. If they have an - argument, it follows the option name in the same ARGV-element, separated - from the option name by a `=', or else the in next ARGV-element. - When `getopt' finds a long-named option, it returns 0 if that option's - `flag' field is nonzero, the value of the option's `val' field - if the `flag' field is zero. - - The elements of ARGV aren't really const, because we permute them. - But we pretend they're const in the prototype to be compatible - with other systems. - - LONGOPTS is a vector of `struct option' terminated by an - element containing a name which is zero. - - LONGIND returns the index in LONGOPT of the long-named option found. - It is only valid when a long-named option has been found by the most - recent call. - - If LONG_ONLY is nonzero, '-' as well as '--' can introduce - long-named options. */ - -int -_getopt_internal ( int argc, - char *const *argv, - const char *optstring, - const struct option *longopts, - int *longind, - int long_only) - -{ - int option_index; - - optarg = 0; - - /* Initialize the internal data when the first call is made. - Start processing options with ARGV-element 1 (since ARGV-element 0 - is the program name); the sequence of previously skipped - non-option ARGV-elements is empty. */ - - if (optind == 0) - { - first_nonopt = last_nonopt = optind = 1; - - nextchar = NULL; - - /* Determine how to handle the ordering of options and nonoptions. */ - - if (optstring[0] == '-') - { - ordering = RETURN_IN_ORDER; - ++optstring; - } - else if (optstring[0] == '+') - { - ordering = REQUIRE_ORDER; - ++optstring; - } - #ifndef _WIN32 - else if (getenv ("POSIXLY_CORRECT") != NULL) - ordering = REQUIRE_ORDER; - #endif - else - ordering = PERMUTE; - } - - if (nextchar == NULL || *nextchar == '\0') - { - if (ordering == PERMUTE) - { - /* If we have just processed some options following some non-options, - exchange them so that the options come first. */ - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (last_nonopt != optind) - first_nonopt = optind; - - /* Now skip any additional non-options - and extend the range of non-options previously skipped. */ - - while (optind < argc - && (argv[optind][0] != '-' || argv[optind][1] == '\0') -#ifdef GETOPT_COMPAT - && (longopts == NULL - || argv[optind][0] != '+' || argv[optind][1] == '\0') -#endif /* GETOPT_COMPAT */ - ) - optind++; - last_nonopt = optind; - } - - /* Special ARGV-element `--' means premature end of options. - Skip it like a null option, - then exchange with previous non-options as if it were an option, - then skip everything else like a non-option. */ - - if (optind != argc && !strcmp (argv[optind], "--")) - { - optind++; - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (first_nonopt == last_nonopt) - first_nonopt = optind; - last_nonopt = argc; - - optind = argc; - } - - /* If we have done all the ARGV-elements, stop the scan - and back over any non-options that we skipped and permuted. */ - - if (optind == argc) - { - /* Set the next-arg-index to point at the non-options - that we previously skipped, so the caller will digest them. */ - if (first_nonopt != last_nonopt) - optind = first_nonopt; - return EOF; - } - - /* If we have come to a non-option and did not permute it, - either stop the scan or describe it to the caller and pass it by. */ - - if ((argv[optind][0] != '-' || argv[optind][1] == '\0') -#ifdef GETOPT_COMPAT - && (longopts == NULL - || argv[optind][0] != '+' || argv[optind][1] == '\0') -#endif /* GETOPT_COMPAT */ - ) - { - if (ordering == REQUIRE_ORDER) - return EOF; - optarg = argv[optind++]; - return 1; - } - - /* We have found another option-ARGV-element. - Start decoding its characters. */ - - nextchar = (argv[optind] + 1 - + (longopts != NULL && argv[optind][1] == '-')); - } - - if (longopts != NULL - && ((argv[optind][0] == '-' - && (argv[optind][1] == '-' || long_only)) -#ifdef GETOPT_COMPAT - || argv[optind][0] == '+' -#endif /* GETOPT_COMPAT */ - )) - { - const struct option *p; - char *s = nextchar; - int exact = 0; - int ambig = 0; - const struct option *pfound = NULL; - int indfound = 0; - - while (*s && *s != '=') - s++; - - /* Test all options for either exact match or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; - p++, option_index++) - if (!strncmp (p->name, nextchar, s - nextchar)) - { - if (s - nextchar == my_strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else - /* Second nonexact match found. */ - ambig = 1; - } - - if (ambig && !exact) - { - if (opterr) - fprintf (stderr, "%s: option `%s' is ambiguous\n", - argv[0], argv[optind]); - nextchar += my_strlen (nextchar); - optind++; - return BAD_OPTION; - } - - if (pfound != NULL) - { - option_index = indfound; - optind++; - if (*s) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = s + 1; - else - { - if (opterr) - { - if (argv[optind - 1][1] == '-') - /* --option */ - fprintf (stderr, - "%s: option `--%s' doesn't allow an argument\n", - argv[0], pfound->name); - else - /* +option or -option */ - fprintf (stderr, - "%s: option `%c%s' doesn't allow an argument\n", - argv[0], argv[optind - 1][0], pfound->name); - } - nextchar += my_strlen (nextchar); - return BAD_OPTION; - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (opterr) - fprintf (stderr, "%s: option `%s' requires an argument\n", - argv[0], argv[optind - 1]); - nextchar += my_strlen (nextchar); - return optstring[0] == ':' ? ':' : BAD_OPTION; - } - } - nextchar += my_strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - /* Can't find it as a long option. If this is not getopt_long_only, - or the option starts with '--' or is not a valid short - option, then it's an error. - Otherwise interpret it as a short option. */ - if (!long_only || argv[optind][1] == '-' -#ifdef GETOPT_COMPAT - || argv[optind][0] == '+' -#endif /* GETOPT_COMPAT */ - || my_index (optstring, *nextchar) == NULL) - { - if (opterr) - { - if (argv[optind][1] == '-') - /* --option */ - fprintf (stderr, "%s: unrecognized option `--%s'\n", - argv[0], nextchar); - else - /* +option or -option */ - fprintf (stderr, "%s: unrecognized option `%c%s'\n", - argv[0], argv[optind][0], nextchar); - } - nextchar = (char *) ""; - optind++; - return BAD_OPTION; - } - } - - /* Look at and handle the next option-character. */ - - { - char c = *nextchar++; - char *temp = my_index (optstring, c); - - /* Increment `optind' when we start to process its last character. */ - if (*nextchar == '\0') - ++optind; - - if (temp == NULL || c == ':') - { - if (opterr) - { -#if 0 - if (c < 040 || c >= 0177) - fprintf (stderr, "%s: unrecognized option, character code 0%o\n", - argv[0], c); - else - fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c); -#else - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); -#endif - } - optopt = c; - return BAD_OPTION; - } - if (temp[1] == ':') - { - if (temp[2] == ':') - { - /* This is an option that accepts an argument optionally. */ - if (*nextchar != '\0') - { - optarg = nextchar; - optind++; - } - else - optarg = 0; - nextchar = NULL; - } - else - { - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (opterr) - { -#if 0 - fprintf (stderr, "%s: option `-%c' requires an argument\n", - argv[0], c); -#else - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, "%s: option requires an argument -- %c\n", - argv[0], c); -#endif - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = BAD_OPTION; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - nextchar = NULL; - } - } - return c; - } -} - -int -getopt ( int argc, - char *const *argv, - const char *optstring) - -{ - return _getopt_internal (argc, argv, optstring, - (const struct option *) 0, - (int *) 0, - 0); -} - -int -getopt_long ( int argc, - char *const *argv, - const char *options, - const struct option *long_options, - int *opt_index) - -{ - return _getopt_internal (argc, argv, options, long_options, opt_index, 0); -} - -#endif /* _LIBC or not __GNU_LIBRARY__. */ - -#ifdef TEST - -/* Compile with -DTEST to make an executable for use in testing - the above definition of `getopt'. */ - -int -main (argc, argv) - int argc; - char **argv; -{ - int c; - int digit_optind = 0; - - while (1) - { - int this_option_optind = optind ? optind : 1; - - c = getopt (argc, argv, "abc:d:0123456789"); - if (c == EOF) - break; - - switch (c) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case BAD_OPTION: - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } - - exit (0); -} - -#endif /* TEST */ - -/* Declarations for getopt. - Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#ifndef _GETOPT_H - -#ifndef __need_getopt -# define _GETOPT_H 1 -#endif - -/* If __GNU_LIBRARY__ is not already defined, either we are being used - standalone, or this is the first header included in the source file. - If we are being used with glibc, we need to include <features.h>, but - that does not exist if we are standalone. So: if __GNU_LIBRARY__ is - not defined, include <ctype.h>, which will pull in <features.h> for us - if it's from glibc. (Why ctype.h? It's guaranteed to exist and it - doesn't flood the namespace with stuff the way some other headers do.) */ -#if !defined __GNU_LIBRARY__ -# include <ctype.h> -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -extern char *optarg; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -extern int optind; - -/* Callers store zero here to inhibit the error message `getopt' prints - for unrecognized options. */ - -extern int opterr; - -/* Set to an option character which was unrecognized. */ - -extern int optopt; - -#ifndef __need_getopt -/* Describe the long-named options requested by the application. - The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector - of `struct option' terminated by an element containing a name which is - zero. - - The field `has_arg' is: - no_argument (or 0) if the option does not take an argument, - required_argument (or 1) if the option requires an argument, - optional_argument (or 2) if the option takes an optional argument. - - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. - - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `getopt' - returns the contents of the `val' field. */ - -struct option -{ -# if (defined __STDC__ && __STDC__) || defined __cplusplus - const char *name; -# else - char *name; -# endif - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; -}; - -/* Names for the values of the `has_arg' field of `struct option'. */ - -# define no_argument 0 -# define required_argument 1 -# define optional_argument 2 -#endif /* need getopt */ - - -/* Get definitions and prototypes for functions to process the - arguments in ARGV (ARGC of them, minus the program name) for - options given in OPTS. - - Return the option character from OPTS just read. Return -1 when - there are no more options. For unrecognized options, or options - missing arguments, `optopt' is set to the option letter, and '?' is - returned. - - The OPTS string is a list of characters which are recognized option - letters, optionally followed by colons, specifying that that letter - takes an argument, to be placed in `optarg'. - - If a letter in OPTS is followed by two colons, its argument is - optional. This behavior is specific to the GNU `getopt'. - - The argument `--' causes premature termination of argument - scanning, explicitly telling `getopt' that there are no more - options. - - If OPTS begins with `--', then non-option arguments are treated as - arguments to the option '\0'. This behavior is specific to the GNU - `getopt'. */ - -#if (defined __STDC__ && __STDC__) || defined __cplusplus -# ifdef __GNU_LIBRARY__ -/* Many other libraries have conflicting prototypes for getopt, with - differences in the consts, in stdlib.h. To avoid compilation - errors, only prototype getopt for the GNU C library. */ -extern int getopt (int ___argc, char *const *___argv, const char *__shortopts); -# else /* not __GNU_LIBRARY__ */ -// Solaris compilation fix -//extern int getopt (); -# endif /* __GNU_LIBRARY__ */ - -# ifndef __need_getopt -extern int getopt_long (int ___argc, char *const *___argv, - const char *__shortopts, - const struct option *__longopts, int *__longind); -extern int getopt_long_only (int ___argc, char *const *___argv, - const char *__shortopts, - const struct option *__longopts, int *__longind); - -/* Internal only. Users should not call this directly. */ -extern int _getopt_internal (int ___argc, char *const *___argv, - const char *__shortopts, - const struct option *__longopts, int *__longind, - int __long_only); -# endif -#else /* not __STDC__ */ -extern int getopt (); -# ifndef __need_getopt -extern int getopt_long (); -extern int getopt_long_only (); - -extern int _getopt_internal (); -# endif -#endif /* __STDC__ */ - -#ifdef __cplusplus -} -#endif - -/* Make sure we later can get all the definitions and declarations. */ -#undef __need_getopt - -#endif /* getopt.h */ -/*************************************************************************** - help.cpp - description - ------------------- - begin : Die Apr 23 2002 - copyright : (C) 2002 by André Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "help.h" - -namespace Help - { - -/** gibt Hilfetext auf Konsole aus */ - - void printHelp(const std::string & helpFilePath) - { - std::ifstream helpFile(helpFilePath.c_str()); - std::string line; - if (helpFile){ - while (getline(helpFile, line)) - std::cout << line << "\n"; - helpFile.close(); - } - else { - std::cerr <<"highlight: Could not read "<< helpFilePath << "\n"; - } - } - -} -/*************************************************************************** - help.h - description - ------------------- - begin : Die Apr 23 2002 - copyright : (C) 2002 by Andé Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef HELP_H -#define HELP_H - -#include <iostream> -#include <fstream> -#include <string> - -/**\ brief COntains methods for printing help messages - *@author Andre Simon - */ -namespace Help - { - /** print help message to stdout */ - void printHelp(const std::string &); - } - -#endif -/*************************************************************************** - htmlcode.cpp - description - ------------------- - begin : Wed Nov 28 2001 - copyright : (C) 2001 by André Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "htmlgenerator.h" - -using namespace std; - -namespace highlight { - - -HtmlGenerator::HtmlGenerator(void) -{} - -string HtmlGenerator::formatStyleAttributes(const string & elemName, - const ElementStyle & elem) -{ - ostringstream s; - s << "."<<elemName<<"\t{ color:#" - << (elem.getColour().getHexRedValue()) - << (elem.getColour().getHexGreenValue()) - << (elem.getColour().getHexBlueValue() ) - << ( elem.isBold() ?"; font-weight:bold" :"" ) - << ( elem.isItalic() ?"; font-style:italic" :"" ) - << ( elem.isUnderline() ?"; text-decoration:underline" :"" ) - << "; }\n" ; - return s.str(); -} - -string HtmlGenerator::getOpenTag(const string& styleName ){ - return "<span class=\""+styleName+"\">"; -} - -HtmlGenerator::HtmlGenerator ( - const string &cssStyle, - const string &enc, - bool omitEnc, - bool withAnchors) - : CodeGenerator( cssStyle), - brTag("<br>"), - hrTag("<hr>"), - idAttr("name"), - fileSuffix(".html"), - encoding(enc), - omitEncoding(omitEnc), - HTML_FOOTER( - "\n</body>\n</html>\n<!--HTML generated by highlight " - HIGHLIGHT_VERSION - ", " - HIGHLIGHT_URL - "-->\n"), - attachAnchors(withAnchors) -{ - styleTagOpen.push_back(""); - styleTagOpen.push_back(getOpenTag("str")); - styleTagOpen.push_back(getOpenTag("num")); - styleTagOpen.push_back(getOpenTag("slc")); - styleTagOpen.push_back(getOpenTag("com")); - styleTagOpen.push_back(getOpenTag("esc")); - styleTagOpen.push_back(getOpenTag("dir")); - styleTagOpen.push_back(getOpenTag("dstr")); - styleTagOpen.push_back(getOpenTag("line")); - styleTagOpen.push_back(getOpenTag("sym")); - - styleTagClose.push_back(""); - for (int i=1;i<NUMBER_BUILTIN_STYLES; i++) { - styleTagClose.push_back("</span>"); - } - - /*assert (styleTagOpen.size()==styleTagClose.size()); - assert (styleTagOpen.size()==NUMBER_BUILTIN_STYLES); -*/ - newLineTag = "\n"; - spacer = " "; - styleCommentOpen="/*"; - styleCommentClose="*/"; -} - -string HtmlGenerator::getStyleDefinition() -{ - if (styleDefinitionCache.empty()){ - ostringstream os; - os << "body.hl\t{ background-color:#" - << (docStyle.getBgColour().getHexRedValue()) - << (docStyle.getBgColour().getHexGreenValue()) - << (docStyle.getBgColour().getHexBlueValue()) - << "; }\n"; - os << "pre.hl\t{ color:#" - << (docStyle.getDefaultStyle().getColour().getHexRedValue()) - << (docStyle.getDefaultStyle().getColour().getHexGreenValue()) - << (docStyle.getDefaultStyle().getColour().getHexBlueValue() ) - << "; background-color:#" - << (docStyle.getBgColour().getHexRedValue()) - << (docStyle.getBgColour().getHexGreenValue()) - << (docStyle.getBgColour().getHexBlueValue()) - << "; font-size:" - << docStyle.getFontSize() - << "pt; font-family:Courier;}\n"; - os << formatStyleAttributes("num", docStyle.getNumberStyle()) - << formatStyleAttributes("esc", docStyle.getEscapeCharStyle()) - << formatStyleAttributes("str", docStyle.getStringStyle()) - << formatStyleAttributes("dstr", docStyle.getDirectiveStringStyle()) - << formatStyleAttributes("slc", docStyle.getSingleLineCommentStyle()) - << formatStyleAttributes("com", docStyle.getCommentStyle()) - << formatStyleAttributes("dir", docStyle.getDirectiveStyle()) - << formatStyleAttributes("sym", docStyle.getSymbolStyle()) - << formatStyleAttributes("line", docStyle.getLineStyle()); - - KeywordStyles styles = docStyle.getKeywordStyles(); - for (KSIterator it=styles.begin(); it!=styles.end(); it++){ - os << formatStyleAttributes(it->first, *(it->second)); - } - styleDefinitionCache=os.str(); - } - return styleDefinitionCache; -} - -string HtmlGenerator::getHeader(const string &title) -{ - ostringstream os; - os << getHeaderStart((title.empty())?"Source file":title ); - if (langInfo.getSyntaxHighlight()) - { - if (includeStyleDef) //CSS-Definition in HTML-<head> einfuegen - { - os << "<style type=\"text/css\">\n"; - os << "<!--\n"; - os << getStyleDefinition(); - os << CodeGenerator::readUserStyleDef(); - os << "//-->\n"; - os << "</style>" << endl; - } - else //Referenz auf CSS-Datei einfuegen - { - os << "<link rel=\"stylesheet\" type=\"text/css\" href=\"" - << getStyleOutputPath() - << "\"" - << ">\n"; - } - } - os << "</head>\n<body class=\"hl\">\n<pre class=\"hl\">"; - return os.str(); -} - -string HtmlGenerator::getFooter() -{ - return "</pre>" + HTML_FOOTER; -} - - -void HtmlGenerator::printBody() -{ - processRootState(); -} - - - -string HtmlGenerator::maskCharacter(unsigned char c) -{ - switch (c) { - case '<' : - return "<"; - break; - case '>' : - return ">"; - break; - case '&' : - return "&"; - break; - case '\"' : - return """; - break; - - case '@' : - return "@"; - break; - - default : - string m; - return m += c; - } -} - -void HtmlGenerator::insertLineNumber (bool insertNewLine) -{ - if (insertNewLine){ - //*out << getNewLine(); - wsBuffer += getNewLine(); - } - if (showLineNumbers) { - ostringstream numberPrefix; - if (attachAnchors) { - numberPrefix << "<a " - << idAttr - << "=\"l_" - << lineNumber - << "\">"; - } - ostringstream os; - if (lineNumberFillZeroes) os.fill('0'); - os <<setw(LINE_NUMBER_WIDTH)<<right<< lineNumber; - numberPrefix<< styleTagOpen[LINENUMBER] - << os.str() - << spacer - << styleTagClose[LINENUMBER]; - - if (attachAnchors) { - numberPrefix << "</a>"; - } - - wsBuffer += numberPrefix.str(); - } -} - -string HtmlGenerator::getHeaderStart(const string &title){ - ostringstream header; - header<< "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">" - << "\n<html>\n<head>\n"; - if (!omitEncoding){ - header << "<meta http-equiv=\"content-type\" content=\"text/html; charset="<<encoding<<"\">\n"; - } - header << "<title>" << title <<"</title>\n"; - return header.str(); -} - -bool HtmlGenerator::printIndexFile(const vector<string> &fileList, - const string &outPath ){ - string suffix = fileSuffix; - string outFilePath = outPath + "index" + suffix; - ofstream indexfile(outFilePath.c_str()); - - if (!indexfile.fail()){ - string inFileName; - string inFilePath, newInFilePath; - indexfile << getHeaderStart("Source Index" ); - indexfile << "</head>\n<body>\n<h1> Source Index</h1>\n" - << hrTag - << "\n<ul>\n"; - string::size_type pos; - for (unsigned int i=0; i < fileList.size(); i++){ - pos=(fileList[i]).find_last_of(Platform::pathSeparator); - if (pos!=string::npos){ - newInFilePath = (fileList[i]).substr(0, pos+1); - } else { - newInFilePath=Platform::pathSeparator; - } - if (newInFilePath!=inFilePath){ - indexfile << "</ul>\n<h2>"; - indexfile << newInFilePath; - indexfile << "</h2>\n<ul>\n"; - inFilePath=newInFilePath; - } - inFileName = (fileList[i]).substr(pos+1); - indexfile << "<li><a href=\"" << inFileName << suffix << "\">"; - indexfile << inFileName << suffix <<"</a></li>\n"; - } - - indexfile << "</ul>\n" - << hrTag << brTag - << "<small>Generated by highlight " - << HIGHLIGHT_VERSION - << ", <a href=\"" << HIGHLIGHT_URL << "\" target=\"new\">" - << HIGHLIGHT_URL << "</a></small>"; - indexfile << HTML_FOOTER; - } else { - return false; - } - return true; -} - -string HtmlGenerator::getMatchingOpenTag(unsigned int styleID){ - return getOpenTag(langInfo.getKeywordClasses()[styleID]); - } - -string HtmlGenerator::getMatchingCloseTag(unsigned int styleID){ - return "</span>"; -} - -} -/*************************************************************************** - htmlgenerator.h - description - ------------------- - begin : Wed Nov 28 2001 - copyright : (C) 2001 by Andre Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - - -#ifndef HTMLGENERATOR_H -#define HTMLGENERATOR_H - -#include <fstream> -#include <iostream> -#include <string> -#include <sstream> - -#include "codegenerator.h" -#include "version.h" -#include "stylecolour.h" -#include "elementstyle.h" -#include "platform_fs.h" - -namespace highlight { - -/** - \brief This class generates HTML. - - It contains information about the resulting document structure (document - header and footer), the colour system, white space handling and text - formatting attributes. - -* @author Andre Simon -*/ - -class HtmlGenerator : public highlight::CodeGenerator - { - public: - - /** Constructor - \param colourTheme Name of Colour theme to use - \param enc encoding name - \param omitEnc switch to omit encoding information - \param withAnchors Test if HTML anchors should be attached to line numbers - */ - HtmlGenerator(const string &colourTheme, - const string &enc, - bool omitEnc=false, - bool withAnchors = false); - - HtmlGenerator(); - - /** Destructor*/ - virtual ~HtmlGenerator() {}; - - /** insert line number in the beginning of the new line - */ - virtual void insertLineNumber(bool insertNewLine=true); - - /** Print document header - \param title Title of the document - */ - string getHeader(const string &title); - - /** Print document body*/ - void printBody(); - - /** Print document footer*/ - string getFooter(); - - /** Print style definitions to external file - \param outFile Path of external style definition - */ - bool printExternalStyle(const string &outFile); - - /** Print index file with all input file names - \param fileList List of output file names - \param outPath Output path - */ - bool printIndexFile(const vector<string> & fileList, const string &outPath); - - protected: - - /** some strings which are similar in HTML and XHTML*/ - string brTag, hrTag, idAttr, fileSuffix; - - /** Output encoding name */ - string encoding; - - /** switch to omit encoding name in file header */ - bool omitEncoding; - - /** HTML footer */ - string HTML_FOOTER; - - /** caches style definition */ - string styleDefinitionCache; - - /** \return CSS definition */ - string getStyleDefinition(); - - /** \return Content of user defined style file */ - string readUserStyleDef(); - - /** \param title Dociment title - \return Start of file header */ - virtual string getHeaderStart(const string &title); - - private: - - /** \param styleName Style name - \return Opening tag of the given style - */ - string getOpenTag(const string& styleName); - - /** \return escaped character*/ - virtual string maskCharacter(unsigned char ); - - /** test if anchors should be appied to line numbers*/ - bool attachAnchors; - - /**\return text formatting attributes in HTML format */ - string formatStyleAttributes(const string & elemName, const ElementStyle & elem); - - /** \param styleID Style ID - \return Opening tag of the given style - */ - string getMatchingOpenTag(unsigned int styleID); - - /** \param styleID Style ID - \return Closing tag of the given style - */ - string getMatchingCloseTag(unsigned int styleID); - }; - -} - -#endif -/*************************************************************************** - languagedefinition.cpp - description - ------------------- - begin : Wed Nov 28 2001 - copyright : (C) 2001 by Andre imon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "languagedefinition.h" - -using namespace std; - -namespace highlight { - -LanguageDefinition::LanguageDefinition(): - ignoreCase(false), - disableHighlighting(false), - allowExtEscape(false), - vhdl_mode(false), - java_mode(false), - allowNestedComments(true), - fullLineComment(false), - reformatCode(false) -{} - -int LanguageDefinition::isKeyword(const string &s) -{ - if (s.length()) - { - if (keywords.count(s)){ - return keywords[s]; - } - else if (prefixes.count(s[0])){ - return prefixes[s[0]]; - } - } - return 0; -} - -bool LanguageDefinition::isPrefix(unsigned char c) -{ - return ( prefixes.count(c)); -} - -void LanguageDefinition::addSimpleSymbol(stringstream& symbolStream, - State state, - const string& paramValues ) { - istringstream valueStream(paramValues); - bool valExists=false; - string value; - while (valueStream >> value) - { - symbolStream << " " << value; - valExists = true; - } - if (valExists) - { - symbolStream << " " << state; - } -} - -void LanguageDefinition::addDelimiterSymbol(stringstream& symbolStream, - State stateBegin, State stateEnd, - const string& paramValues, - unsigned int classID) { - istringstream valueStream(paramValues); - string delimPrefix, delimSuffix; - while (valueStream>>delimPrefix){ - valueStream >> delimSuffix; - symbolStream << " "<<delimPrefix <<" " << stateBegin; - symbolStream <<" "<< delimSuffix<<" "<< stateEnd; - delimiterPrefixes.insert(make_pair(delimPrefix, classID)); - }; -} - -bool LanguageDefinition::getFlag( string& paramValue){ - return (StringTools::lowerCase(paramValue)=="true"); -} - -unsigned char LanguageDefinition::getSymbol(const string& paramValue){ - istringstream valueStream(paramValue); - unsigned char symbol; - valueStream >> symbol; - return symbol; -} - -void LanguageDefinition::addKeywords(const string &kwList, - int classID){ - istringstream valueStream(kwList); - string keyword; - while (valueStream >> keyword){ - keywords.insert(make_pair(keyword, classID)); - } -} - -unsigned int LanguageDefinition::generateNewKWClass(const string& newClassName){ - unsigned int newClassID=0; - bool found=false; - while (newClassID<keywordClasses.size() && !found){ - found= (newClassName==keywordClasses[newClassID++]); - } - if (!found){ - newClassID++; - keywordClasses.push_back(newClassName); - } - return newClassID; -} - -unsigned int LanguageDefinition::getDelimPrefixClassID(const string& prefix){ - if (delimiterPrefixes.count(prefix)){ - return delimiterPrefixes[prefix]; - } - return 0; -} - -bool LanguageDefinition::load(const string& langDefPath, bool clear) -{ - if (clear) reset(); - - ConfigurationReader langDef(langDefPath); - if (langDef.found()) - { - currentPath=langDefPath; - disableHighlighting=false; - string token; - stringstream symbolStrStream; - - //Stringstream zum Einlesen der Token: - istringstream valueStream; - - addDelimiterSymbol(symbolStrStream, ML_COMMENT_BEGIN, ML_COMMENT_END, - langDef.getParameter("ml_comment")); - - addSimpleSymbol(symbolStrStream, SL_COMMENT, - langDef.getParameter("sl_comment")); - - addSimpleSymbol(symbolStrStream, ESC_CHAR, - langDef.getParameter("escchar")); - - addSimpleSymbol(symbolStrStream, DIRECTIVE_LINE, - langDef.getParameter("directive")); - - addSimpleSymbol(symbolStrStream, DIRECTIVE_LINE_END, - langDef.getParameter("directiveend")); - - addSimpleSymbol(symbolStrStream, STRING, - langDef.getParameter("stringdelimiters")); - - ignoreCase=getFlag(langDef.getParameter("ignorecase")); - allowNestedComments=getFlag(langDef.getParameter("allownestedcomments")); - vhdl_mode=getFlag(langDef.getParameter("vhdl_mode")); - java_mode=getFlag(langDef.getParameter("java_mode")); - disableHighlighting=getFlag(langDef.getParameter("disablehighlighting")); - fullLineComment=getFlag(langDef.getParameter("fl_comment")); - reformatCode=getFlag(langDef.getParameter("reformatting")); - rawStringPrefix=getSymbol(langDef.getParameter("rawstringprefix")); - continuationChar=getSymbol(langDef.getParameter("continuationsymbol")); - allowExtEscape=getFlag(langDef.getParameter("allowextescape")); - - string paramName, className, classValue; - vector<string> paramNames=langDef.getParameterNames(); - for (unsigned int i=0;i<paramNames.size();i++){ - paramName=paramNames[i]; - className=StringTools::getParantheseVal(paramName); - classValue=langDef.getParameter(paramName); - if (paramName.find("kw_list") != string::npos ){ - addKeywords(classValue, generateNewKWClass(className)); - } - if (paramName.find("kw_prefix") != string::npos){ - prefixes.insert(make_pair(classValue[0], generateNewKWClass(className))); - } - if (paramName.find("kw_delim") != string::npos ){ - addDelimiterSymbol(symbolStrStream, KEYWORD_BEGIN, KEYWORD_END, - classValue, generateNewKWClass(className)); - } - if (paramName.find("tag_delim") != string::npos ){ - addDelimiterSymbol(symbolStrStream, TAG_BEGIN, TAG_END, - classValue, generateNewKWClass(className)); - } - } - - // zuletzt einlesen, um Probleme mit Delimitern, die Zeichen der - // Symbolliste enthalten, zu vermeiden - addSimpleSymbol(symbolStrStream, SYMBOL, langDef.getParameter("symbols")); - - valueStream.str(langDef.getParameter("allowedchars")); - while (valueStream >> token ) - { - allowedChars += token; - } - symbolString = symbolStrStream.str(); - - string fileToInclude=langDef.getParameter("include"); - if (!fileToInclude.empty()){ - string::size_type Pos = langDefPath.find_last_of(Platform::pathSeparator); - string includeLangDefPath = langDefPath.substr(0, Pos+1) + fileToInclude; - load(includeLangDefPath, false); - } - return true; - } - else - { - currentPath.clear(); - return false; - } -} - -void LanguageDefinition::reset() -{ - keywords.clear(); - keywordClasses.clear(); - delimiterPrefixes.clear();; - prefixes.clear(); - allowedChars.clear(); - ignoreCase= false; - java_mode= vhdl_mode= false; - allowNestedComments= reformatCode = false; - rawStringPrefix = continuationChar = '\0'; - disableHighlighting=false; - fullLineComment=false; -} - -bool LanguageDefinition::isVHDL() -{ - return vhdl_mode; -} - -bool LanguageDefinition::isJava() -{ - return java_mode; -} - -bool LanguageDefinition::allowNestedMLComments(){ - return allowNestedComments; -} - -bool LanguageDefinition::highlightingDisabled(){ - return disableHighlighting; -} - -bool LanguageDefinition::isFullLineComment(){ - return fullLineComment; -} - -bool LanguageDefinition::needsReload(const string &langDefPath){ - return currentPath!=langDefPath; -} - -bool LanguageDefinition::enableReformatting(){ - return reformatCode; -} - -const KeywordMap& LanguageDefinition::getKeywords() const{ - return keywords; -} - -string &LanguageDefinition::getSymbolString() { - return symbolString; -} - -unsigned char LanguageDefinition::getRawStringPrefix(){ - return rawStringPrefix; -} - -unsigned char LanguageDefinition::getContinuationChar(){ - return continuationChar; -} - -string &LanguageDefinition::getAllowedChars() { - return allowedChars; -} - -bool LanguageDefinition::getSyntaxHighlight() { - return !disableHighlighting; -} - -bool LanguageDefinition::isIgnoreCase() { - return ignoreCase; -} - -const vector<string>&LanguageDefinition::getKeywordClasses() const{ - return keywordClasses; -} - -bool LanguageDefinition::allowExtEscSeq() { - return allowExtEscape; -} - -} -/*************************************************************************** - languagedefinition.h - description - ------------------- - begin : Wed Nov 28 2001 - copyright : (C) 2001 by Andre Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef LANGUAGEDEFINITION_H -#define LANGUAGEDEFINITION_H - -#include <string> -#include <map> -#include <iostream> -#include <fstream> -#include <iterator> -#include <sstream> - -#include "configurationreader.h" -//#include "stringtools.h" -#include "platform_fs.h" -#include "enums.h" - - -namespace highlight { - -/** maps keywords and the corresponding class IDs*/ -typedef map <string, int> KeywordMap; - -/** maps keyword prefixes and the corresponding class IDs*/ -typedef map <unsigned char, int> PrefixMap; - -/**\brief Contains specific data of the programming language being processed. - - The load() method will only read a new language definition if the given - file path is not equal to the path of the current language definition. - -* @author Andre Simon -*/ - -class LanguageDefinition { - - public: - - LanguageDefinition(); - - /**\return Symbol string, containg all known symbols with the referencing state ids*/ - string &getSymbolString(); - - /** \return Prefix of raw strings */ - unsigned char getRawStringPrefix(); - - /** \return Continuation Character */ - unsigned char getContinuationChar(); - - /** \return List of characters allowed within identifiers */ - string &getAllowedChars(); - - /** \return true if syntax highlighting is enabled*/ - bool getSyntaxHighlight(); - - /** \return True if language is case sensitive */ - bool isIgnoreCase(); - - /** \param s String - \return class id of keyword, 0 if s is not a keyword */ - int isKeyword(const string &s); - - - /** \return true if c is member of prefix list*/ - bool isPrefix(unsigned char c); - - /** Load new language definition - \param langDefPath Path of language definition - \param clear Test if former data should be deleted - \return True if successfull */ - bool load(const string& langDefPath, bool clear=true); - - /** \return True if programming language is VHDL */ - bool isVHDL(); - - /** \return True if programming language is Java */ - bool isJava(); - - /** \return True if multi line comments may be nested */ - bool allowNestedMLComments(); - - /** \return True if highlighting is disabled */ - bool highlightingDisabled(); - - /** \return True if single line comments must start at coloumn 1 */ - bool isFullLineComment(); - - /** \return True the next load() call will load a new language definition - \param langDefPath Path to language definition */ - bool needsReload(const string &langDefPath); - - /** \return True if current language may be reformatted (c, c++, c#, java) */ - bool enableReformatting(); - - /** \return True if escape sequences are allowed outsde of strings */ - bool allowExtEscSeq(); - - /** \return Class ID of given keyword delimiter prefix - \param prefix Keyword delimiter prefix */ - unsigned int getDelimPrefixClassID(const string& prefix); - - /** \return keywords*/ - const KeywordMap& getKeywords() const; - - /** \return keyword classes*/ - const vector<string>& getKeywordClasses() const; - - private: - // string containing symbols and their IDs of the programming language - string symbolString; - - // string with special characters that may occour in keywords - string allowedChars; - - // path to laoed language definition - string currentPath; - - KeywordMap keywords; - - vector <string> keywordClasses; - - KeywordMap delimiterPrefixes; - - PrefixMap prefixes; - - // keywords are not case sensitive if set - bool ignoreCase, - disableHighlighting, - allowExtEscape, - - // switch to enable VHDL workarounds - vhdl_mode, - - // switch to enable Java workarounds - java_mode, - - // allow nested multi line comment blocks - allowNestedComments, - - // single line comments have to start in coloumn 1 if set - fullLineComment, - - // code formatting is enabled if set - reformatCode; - - // Character, die eine Variable bzw. ein Keyword kennzeichnen - unsigned char rawStringPrefix, - continuationChar; - - /** setzt Membervariablen auf Defaultwerte */ - void reset(); - - // add a symbol sequencs to the symbolStream - void addSimpleSymbol(stringstream& symbolStream, State state, - const string& paramValues ); - - // add a delimiter symbol sequencs to the symbolStream - void addDelimiterSymbol(stringstream& symbolStream, - State stateBegin, State stateEnd, - const string& paramValues, - unsigned int classID=0); - - bool getFlag( string& paramValue); - - unsigned char getSymbol(const string& paramValue); - - // generate a unique class ID if the class name - unsigned int generateNewKWClass(const string& newClassName); - - // add keywords to the given class - void addKeywords(const string &kwList, int classID); - - }; - -} -#endif -/*************************************************************************** - LatexCode.cpp - description - ------------------- - begin : Mit Jul 24 2002 - copyright : (C) 2002 by André Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "latexgenerator.h" - -namespace highlight { - -LatexGenerator::LatexGenerator(const string &colourTheme, - bool replQuotes) - : CodeGenerator(colourTheme), - replaceQuotes(replQuotes) -{ - styleTagOpen.push_back( "\\hlstd{"); - styleTagOpen.push_back( "\\hlstr{"); - styleTagOpen.push_back( "\\hlnum{"); - styleTagOpen.push_back( "\\hlslc{"); - styleTagOpen.push_back( "\\hlcom{"); - styleTagOpen.push_back( "\\hlesc{"); - styleTagOpen.push_back( "\\hldir{"); - styleTagOpen.push_back( "\\hldstr{"); - styleTagOpen.push_back( "\\hlline{"); - styleTagOpen.push_back( "\\hlsym{"); - - for (int i=0;i<NUMBER_BUILTIN_STYLES; i++){ - styleTagClose.push_back( "}"); - } - - // avoid "Underfull \hbox (badness 10000)" warnings - newLineTag = "\\\\\n"; - longLineTag = "\\hspace*{\\fill}" + newLineTag; - - spacer = "\\ "; - - maskWs=true; - maskWsBegin = "\\hlstd{"; - maskWsEnd = "}"; - - excludeWs=true; - - styleCommentOpen="%"; -} - -LatexGenerator::LatexGenerator() -{} -LatexGenerator::~LatexGenerator() -{} - -string LatexGenerator::formatStyleAttributes(const string & elemName, - const ElementStyle &elem) -{ - ostringstream s; - s << "\\newcommand{\\hl" - << elemName - << "}[1]{\\textcolor[rgb]{" - << elem.getColour().getLatexRedValue() << "," - << elem.getColour().getLatexGreenValue() << "," - << elem.getColour().getLatexBlueValue() - << "}{"; - - if (elem.isBold()) - s << "\\bf{"; - if (elem.isItalic()) - s << "\\it{"; - - s <<"#1"; - - if (elem.isBold()) - s << "}"; - if (elem.isItalic()) - s << "}"; - - s <<"}}\n"; - return s.str(); -} - -void LatexGenerator::printBody() -{ - *out << "\\noindent\n" - << "\\ttfamily\n"; - - processRootState(); - - *out << "\\mbox{}\n" - << "\n\\normalfont\n"; -} - -string LatexGenerator::getHeader(const string & title) -{ - ostringstream os; - os << "\\documentclass{article}\n" - << "\\usepackage{color}\n" - << "\\usepackage{alltt}\n"; - - if (langInfo.getSyntaxHighlight()) { - if (includeStyleDef) { - os << "\n"<<getStyleDefinition(); - os << CodeGenerator::readUserStyleDef(); - } else { - os << "\n\\input {" - << getStyleOutputPath() - << "}\n"; - } - } - - os << "\n\\title{" << title << "}\n" - << "\\begin{document}\n" - << "\\pagecolor{bgcolor}\n"; - return os.str(); -} - -string LatexGenerator::getFooter() -{ - ostringstream os; - os << "\\end {document}\n" - << "(* LaTeX generated by highlight " - << HIGHLIGHT_VERSION - << ", " - << HIGHLIGHT_URL - << " *)\n"; - return os.str(); -} - -string LatexGenerator::getNewLine(){ - return (showLineNumbers)? newLineTag:longLineTag; -} - -string LatexGenerator::maskCharacter(unsigned char c) -{ - switch (c) - { - case '<' : - return "$<$"; - break; - case '>' : - return "$>$"; - break; - case '{': - case '}': - case '&': - case '$': - case '#': - case '%': - { - string m; - m ="\\"; - m += c; - return m; - } - break; - case '\"': - return (fragmentOutput && replaceQuotes)?"\\dq{}":"\""; - break; - case '_': - return "\\textunderscore "; - break; - case '^': - return "\\textasciicircum "; - break; - case '\\': - return "$\\backslash$"; - break; - case '~': - return "$\\sim$"; - break; - case '|': - return "\\textbar "; - break; - // avoid latex compilation failure if [ or * follows a line break (\\) - case '*': - case '[': - case ']': - // avoid "merging" of consecutive '-' chars when included in bold font ( \bf ) - case '-': - { - string m; - m= "{"; - m+= c; - m+= "}"; - return m; - } - break; - case ' ': - return spacer; - break; - case AUML_LC: - return "\\\"a"; - break; - case OUML_LC: - return "\\\"o"; - break; - case UUML_LC: - return "\\\"u"; - break; - case AUML_UC: - return "\\\"A"; - break; - case OUML_UC: - return "\\\"O"; - break; - case UUML_UC: - return "\\\"U"; - break; - case AACUTE_LC: - return "\\'a"; - break; - case EACUTE_LC: - return "\\'e"; - break; - case OACUTE_LC: - return "\\'o"; - break; - case UACUTE_LC: - return "\\'u"; - break; - case AGRAVE_LC: - return "\\`a"; - break; - case EGRAVE_LC: - return "\\`e"; - break; - case OGRAVE_LC: - return "\\`o"; - break; - case UGRAVE_LC: - return "\\`u"; - break; - case AACUTE_UC: - return "\\'A"; - break; - case EACUTE_UC: - return "\\'E"; - break; - case OACUTE_UC: - return "\\'O"; - break; - case UACUTE_UC: - return "\\'U"; - break; - case AGRAVE_UC: - return "\\`A"; - break; - case EGRAVE_UC: - return "\\`E"; - break; - case UGRAVE_UC: - return "\\`O"; - break; - case OGRAVE_UC: - return "\\`U"; - break; - case SZLIG: - return "\\ss "; - break; - /* #ifndef _WIN32 - // skip first byte of multibyte chracters - case 195: - return string(""); - break; -#endif*/ - - default : - { - string m; - return m+=c; - } - } -} - -string LatexGenerator::getMatchingOpenTag(unsigned int styleID){ - return "\\hl"+langInfo.getKeywordClasses()[styleID]+"{"; - } - -string LatexGenerator::getMatchingCloseTag(unsigned int styleID){ - return "}"; -} - - -string LatexGenerator::getStyleDefinition() -{ - if (styleDefinitionCache.empty()){ - ostringstream os; - os << formatStyleAttributes("std", docStyle.getDefaultStyle()); - os << formatStyleAttributes("num", docStyle.getNumberStyle()); - os << formatStyleAttributes("esc", docStyle.getEscapeCharStyle()); - os << formatStyleAttributes("str", docStyle.getStringStyle()); - os << formatStyleAttributes("dstr", docStyle.getDirectiveStringStyle()); - os << formatStyleAttributes("slc", docStyle.getSingleLineCommentStyle()); - os << formatStyleAttributes("com", docStyle.getCommentStyle()); - os << formatStyleAttributes("dir", docStyle.getDirectiveStyle()); - os << formatStyleAttributes("sym", docStyle.getSymbolStyle()); - os << formatStyleAttributes("line", docStyle.getLineStyle()); - - KeywordStyles styles = docStyle.getKeywordStyles(); - for (KSIterator it=styles.begin(); it!=styles.end(); it++){ - os << formatStyleAttributes(it->first, *(it->second)); - } - os << "\\definecolor{bgcolor}{rgb}{" - << docStyle.getBgColour().getLatexRedValue() << "," - << docStyle.getBgColour().getLatexGreenValue() << "," - << docStyle.getBgColour().getLatexBlueValue() - << "}\n"; - os << "\\oddsidemargin -3mm\n\\textwidth 165,2truemm\n" - << "\\topmargin 0truept\n\\headheight 0truept\n" - << "\\headsep 0truept\n\\textheight 230truemm\n"; - - styleDefinitionCache=os.str(); - } - return styleDefinitionCache; -} - - -} -/*************************************************************************** - latexgenerator.h - description - ------------------- - begin : Mit Jul 24 2002 - copyright : (C) 2002 by André Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef LATEXGENERATOR_H -#define LATEXGENERATOR_H - -#include <string> -#include <iostream> -#include <sstream> - -#include "codegenerator.h" -#include "version.h" -#include "charcodes.h" - - -namespace highlight { - -/** - \brief This class generates LaTeX. - - It contains information about the resulting document structure (document - header and footer), the colour system, white space handling and text - formatting attributes. - -* @author Andre Simon -*/ - -class LatexGenerator : public highlight::CodeGenerator - { - public: - - /** Constructor - \param colourTheme Name of Colour theme to use - \param replQuotes Test if quotes shold be replaced by \ dq - */ - LatexGenerator(const string &colourTheme, - bool replQuotes=false); - LatexGenerator(); - ~LatexGenerator(); - - /** prints document header - \param title Title of the document - */ - string getHeader(const string & title); - - /** Prints document footer*/ - string getFooter(); - - /** Prints document body*/ - void printBody(); - - private: - - string styleDefinitionCache; - string longLineTag; - - /** \return escaped character*/ - virtual string maskCharacter(unsigned char ); - - /**\return text formatting attributes in LaTeX format */ - string formatStyleAttributes(const string & elemName, - const ElementStyle & elem); - - /** test if double quotes should be replaced by \dq{} */ - bool replaceQuotes; - - string getNewLine(); - - string getStyleDefinition(); - - string getMatchingOpenTag(unsigned int styleID); - string getMatchingCloseTag(unsigned int styleID); - }; - -} - -#endif -/*************************************************************************** - main.cpp - description - ------------------- - begin : Die Apr 23 22:16:35 CEST 2002 - copyright : (C) 2002-2004 by André Simon - email : andre.simon1@gmx.de - - - Highlight is a universal source code to HTML converter. Syntax highlighting - is formatted by Cascading Style Sheets. It's possible to easily enhance - highlight's parsing database. - - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "main.h" - -using namespace std; - -void HighlightApp::printVersionInfo() -{ - cout << "\n highlight version " - << HIGHLIGHT_VERSION - << "\n Copyright (C) 2002-2005 Andre Simon <andre.simon1@gmx.de>" - << "\n\n Artistic Style Classes (1.15.3)" - << "\n Copyright (C) 1998-2002 Tal Davidson <davidsont@bigfoot.com>" - << "\n\n Dirstream Classes (0.4)" - << "\n Copyright (C) 2002-2004 Benjamin Kaufmann <hume@c-plusplus.de>" - << "\n\n This software is released under the terms of the GNU General " - << "Public License." - << "\n For more information about these matters, see the file named " - << "COPYING.\n\n"; - #ifdef USE_LOCAL_GETOPT - cout << " (Built with USE_LOCAL_GETOPT flag set.)\n"; - #endif - #ifdef HL_DATA_DIR - cout << " (HL_DATA_DIR: \"" <<HL_DATA_DIR<< "\" )\n"; - #endif -} - -void HighlightApp::printBadInstallationInfo() -{ - cerr << "highlight: Data directory not found. Bad installation or wrong " - << OPT_DATADIR << " parameter." - << "\n\nCopy the highlight files into one of the directories listed " - << "in INSTALL.\nYou may also set the data directory with " - << OPT_DATADIR << " and " << OPT_ADDDATADIR << ".\n"; -} - -bool HighlightApp::listInstalledFiles(bool showThemes) -{ - vector <string> filePaths; - string wildcard=(showThemes)? "*.style":"*.lang"; - unsigned int suffixLength=wildcard.length()-1; - - string searchDir = ((showThemes) ? dataDir.getThemeDir(): - dataDir.getLangDefDir()) + wildcard; - - bool directoryOK = Platform::getDirectoryEntries(filePaths, searchDir, true); - if (!directoryOK) { - cerr << "highlight: Could not access directory " - << searchDir - << ", aborted.\n"; - return false; - } - - cout << "\n Installed " - << ((showThemes)? "themes":"language definitions ") - << "(located in " - << ((showThemes)?dataDir.getThemeDir():dataDir.getLangDefDir()) - << ") :\n" - << endl; - - sort(filePaths.begin(), filePaths.end()); - string temp; - - for (unsigned int i=0;i< filePaths.size(); i++){ - if (showThemes) - temp = (filePaths[i]).substr(dataDir.getThemeDir().length()); - else - temp = (filePaths[i]).substr(dataDir.getLangDefDir().length()); - cout << " "<<temp.substr(0, temp.length()- suffixLength) << endl; - } - cout <<"\n Use name of the desired " - << ((showThemes)?"theme":"language") - << " with the --" - << ((showThemes)? OPT_STYLE : OPT_SYNTAX) - << " option.\n" << endl; - return true; -} - -void HighlightApp::printDebugInfo(highlight::LanguageDefinition &lang, - const string & langDefPath) -{ - cerr << "\nLoading language definition: " << langDefPath; - cerr << "\n\nSYMBOLS: " - << lang.getSymbolString(); - cerr << "\n\nKEYWORDS: "; - highlight::KeywordMap::iterator it; - highlight::KeywordMap keys=lang.getKeywords(); - cerr << "\n\nID Keyword \n"; - for (it=keys.begin(); it!=keys.end();it++){ - cerr << it->second - << " <- \"" - << it->first <<"\"\n"; - } - cerr <<"\n"; -} - -string HighlightApp::getFileSuffix(const string &fileName) { - size_t ptPos=fileName.rfind("."); - return (ptPos == string::npos) ? - "" : fileName.substr(ptPos+1, fileName.length()); -} - -bool HighlightApp::loadMapConfig(const string& name, StringMap* map){ - string extPath=dataDir.getDir() + name + ".conf"; - ConfigurationReader config(extPath); - if (config.found() ) - { - stringstream values; - string paramName, paramVal; - for (unsigned int i=0;i<config.getParameterNames().size();i++){ - paramName = config.getParameterNames()[i]; - values.str(config.getParameter(paramName)) ; - while (values >> paramVal) { - map->insert(make_pair( paramVal, paramName)); - } - values.clear(); - } - return true; - } else { - cerr << "highlight: Configuration file "<< extPath << " not found.\n"; - return false; - } -} - - -int HighlightApp::getNumDigits(int i){ - int res=0; - while (i){ - i/=10; - ++res; - } - return res; -} - -void HighlightApp::printProgressBar(int total, int count){ - if (!total) return; - int p=100*count / total; - int numProgressItems=p/10; - cout << "\r["; - for (int i=0;i<10;i++){ - cout <<((i<numProgressItems)?"#":" "); - } - cout<< "] " <<setw(3)<<p<<"%, "<<count << " / " << total << " " <<flush; - if (p==100) { - cout << endl; - } -} - -void HighlightApp::printCurrentAction(const string&outfilePath, - int total, int count, int countWidth){ - cout << "Writing file " - << setw(countWidth)<< count - << " of " - << total - << ": " - << outfilePath - << "\n"; -} - -void HighlightApp::printIOErrorReport(unsigned int numberErrorFiles, - vector<string> & fileList, - const string &action){ - cerr << "highlight: Could not " - << action - << " file" - << ((numberErrorFiles>1)?"s":"")<<":\n"; - copy (fileList.begin(), fileList.end(), ostream_iterator<string>(cerr, "\n")); - if (fileList.size() < numberErrorFiles) { - cerr << "... [" - << (numberErrorFiles - fileList.size() ) - << " of " - << numberErrorFiles - << " failures not shown, use --" - << OPT_VERBOSE - << " switch to print all paths]\n"; - } -} - -string HighlightApp::analyzeShebang(const string& file){ - if (scriptShebangs.empty()) loadMapConfig("scriptre", &scriptShebangs); - ifstream inFile(file.c_str()); - string firstLine; - getline (inFile, firstLine); - return scriptShebangs[StringTools::trimRight(firstLine)]; -} - -string HighlightApp::guessFileType(const string& suffix, const string &inputFile) -{ - if (extensions.empty()) loadMapConfig("extensions", &extensions); - string fileType = (extensions.count(suffix)) ? extensions[suffix] : suffix ; - if (!fileType.empty()) return fileType; - return analyzeShebang(inputFile); -} - - -int HighlightApp::run(int argc, char**argv){ - - //get command line options - CmdLineOptions options(argc, argv); - - // set data directory path, where /langDefs and /themes reside - string highlightRootDir = Platform::getAppPath(); - - // determine highlight data directory - if (! dataDir.searchDataDir((options.dataDirGiven())? - options.getDataDir(): highlightRootDir)){ - printBadInstallationInfo(); - return EXIT_FAILURE; - } - - if (options.additionalDataDirGiven()){ - dataDir.setAdditionalDataDir(options.getAdditionalDataDir()); - } - - if (options.printVersion()) { - printVersionInfo(); - return EXIT_SUCCESS; - } - - if (options.printHelp()) { - Help::printHelp(dataDir.getHelpMsgDir() + options.getHelpLang()); - return EXIT_SUCCESS; - } - - if (options.showThemes() || options.showLangdefs()) { - return listInstalledFiles(options.showThemes())?EXIT_SUCCESS:EXIT_FAILURE; - } - - // list of input files - const vector <string> inFileList=options.getInputFileNames(); - - string stylePath=dataDir.searchForTheme(options.getStyleName()); - - highlight::CodeGenerator *generator = - highlight::CodeGenerator::getInstance(options.getOutputType(), - stylePath, - options.getStyleInFilename(), - options.getStyleOutFilename(), - options.getCharSet(), - options.includeStyleDef(), - options.attachLineAnchors(), - options.replaceQuotes(), - options.fopCompatible(), - options.getNumberSpaces(), - options.getWrappingStyle(), - options.printLineNumbers(), - options.fillLineNrZeroes(), - options.fragmentOutput(), - options.omitEncodingName() ); - - assert (generator!=NULL); - - bool styleFileWanted = !options.fragmentOutput() || options.styleOutPathDefined(); - - if (!generator->styleFound() ) { - cerr << "highlight: Could not find style " - << stylePath - << ".\n"; - highlight::CodeGenerator::deleteInstance(); - return EXIT_FAILURE; - } - - if (!options.getIndentScheme().empty()){ - string indentSchemePath = - dataDir.searchForIndentScheme(options.getIndentScheme()+".indent"); - if (!generator->initIndentationScheme(indentSchemePath)){ - cerr << "highlight: Could not find indentation scheme " - << indentSchemePath - << ".\n"; - highlight::CodeGenerator::deleteInstance(); - return EXIT_FAILURE; - } - } - - string outDirectory = options.getOutDirectory(); - if (!outDirectory.empty() && !options.quietMode() && !dirstr::directory_exists(outDirectory) ){ - cerr << "highlight: Output directory \"" - << outDirectory - << "\" does not exist.\n"; - return EXIT_FAILURE; - } - - bool initError=false, IOError=false; - - if ( !options.includeStyleDef() - && (styleFileWanted) - && options.formatSupportsExtStyle()) { - string cssOutFile=outDirectory + options.getStyleOutFilename(); - bool success=generator->printExternalStyle (cssOutFile); - if (!success){ - cerr << "highlight: Could not write " << cssOutFile <<".\n"; - IOError = true; - } - } - - if (options.printIndexFile()){ - bool success=generator -> printIndexFile(inFileList, outDirectory); - if (!success){ - cerr << "highlight: Could not write index file.\n"; - IOError = true; - } - } - - unsigned int fileCount=inFileList.size(), - fileCountWidth=getNumDigits(fileCount), - i=0, - numBadFormatting=0, - numBadInput=0, - numBadOutput=0; - - vector<string> badFormattedFiles, badInputFiles, badOutputFiles; - string outFilePath; - string suffix, lastSuffix; - - if (options.syntaxGiven()) { // user defined language definition, valid for all files - suffix = guessFileType(options.getLanguage()); - } - - while (i < fileCount && !initError) { - if (!options.syntaxGiven()) { // determine file type for each file - suffix = guessFileType(getFileSuffix(inFileList[i]), inFileList[i]); - } - if (suffix.empty()) { - if (!options.enableBatchMode() && !styleFileWanted) - cerr << "highlight: Undefined language definition. Use --" - << OPT_SYNTAX << " option.\n"; - if (!options.forceOutput()){ - initError = true; - break; - } - } - - if (suffix != lastSuffix) { - string langDefPath=dataDir.searchForLangDef(suffix+".lang"); - highlight::LoadResult loadRes= generator->initLanguage(langDefPath); - if (loadRes==highlight::LOAD_FAILED){ - cerr << "highlight: Unknown source file extension \"" - << suffix - << "\".\n"; - if (!options.forceOutput()){ - initError = true; - break; - } - } - if (options.printDebugInfo() && loadRes==highlight::LOAD_NEW){ - printDebugInfo(generator->getLanguage(), langDefPath); - } - lastSuffix = suffix; - } - - if (options.enableBatchMode()){ - string::size_type pos=(inFileList[i]).find_last_of(Platform::pathSeparator); - outFilePath = outDirectory; - outFilePath += inFileList[i].substr(pos+1); - outFilePath += options.getOutFileSuffix(); - - if (!options.quietMode()) { - if (options.printProgress()){ - printProgressBar(fileCount, i+1); - } else { - printCurrentAction(outFilePath, fileCount, i+1, fileCountWidth); - } - } - } else { - outFilePath = options.getSingleOutFilename(); - } - - highlight::ParseError error = generator->printOutput(inFileList[i], outFilePath); - if (error==highlight::BAD_INPUT){ - if (numBadInput++ < IO_ERROR_REPORT_LENGTH || options.printDebugInfo()) { - badInputFiles.push_back(inFileList[i]); - } - } else if (error==highlight::BAD_OUTPUT){ - if (numBadOutput++ < IO_ERROR_REPORT_LENGTH || options.printDebugInfo()) { - badOutputFiles.push_back(outFilePath); - } - } - if (options.formattingEnabled() && !generator->formattingIsPossible()){ - if (numBadFormatting++ < IO_ERROR_REPORT_LENGTH || options.printDebugInfo()) { - badFormattedFiles.push_back(outFilePath); - } - } - ++i; - } - - if (numBadInput){ - printIOErrorReport(numBadInput, badInputFiles, "read input"); - IOError = true; - } - if (numBadOutput){ - printIOErrorReport(numBadOutput, badOutputFiles, "write output"); - IOError = true; - } - if (numBadFormatting){ - printIOErrorReport(numBadFormatting, badFormattedFiles, "reformat"); - } - - highlight::CodeGenerator::deleteInstance(); - return (initError || IOError) ? EXIT_FAILURE : EXIT_SUCCESS; -} - - -int main(int argc, char **argv) { - HighlightApp app; - return app.run(argc, argv); -} -// -// C++ Interface: main -// -// Description: -// -// -// Author: Andre Simon <andre.simon1@gmx.de>, (C) 2004 -// -// Copyright: See COPYING file that comes with this distribution -// -// - -#ifndef HIGHLIGHT_APP -#define HIGHLIGHT_APP - - -#include <iostream> -#include <fstream> -#include <string> -#include <vector> -#include <map> -#include <iomanip> -#include <cassert> - -#include "./dirstream0.4/dirstream.h" -#include "cmdlineoptions.h" -#include "configurationreader.h" -#include "codegenerator.h" -#include "help.h" -#include "datadir.h" -#include "version.h" -#include "platform_fs.h" - -#define IO_ERROR_REPORT_LENGTH 5 -#define SHEBANG_CNT 12 - -typedef map<string, string> StringMap; - -/** Main application class - @author Andre Simon -*/ - -class HighlightApp { - -public: - - HighlightApp(){}; - ~HighlightApp(){}; - - /** Start application - \param argc Number of command line arguments - \param argv values of command line arguments - \return EXIT_SUCCESS or EXIT_FAILURE - */ - int run(int argc, char **argv); - -private: - - DataDir dataDir; - StringMap extensions; - StringMap scriptShebangs; - - /** print version info*/ - void printVersionInfo(); - - /** print error message*/ - void printBadInstallationInfo(); - - /** print input and output errors */ - void printIOErrorReport(unsigned int numberErrorFiles, vector<string> & fileList, const string &action); - - /** print installed files - \param showThemes Print installed themes if true, language definitions otherwise - */ - bool listInstalledFiles(bool showThemes); - - void printDebugInfo(highlight::LanguageDefinition &lang, - const string &langDefPath); - - string getFileSuffix(const string &fileName); - - string guessFileType(const string &suffix, const string &inputFile=""); - - int getNumDigits(int i); - - void printProgressBar(int total, int count); - void printCurrentAction(const string&outfilePath, - int total, int count, int countWidth); - - bool readInputFilePaths(vector<string> &fileList, string wildcard, - bool recursiveSearch); - - string analyzeShebang(const string& file); - bool loadMapConfig(const string& name, StringMap* map); - -}; - -#endif -// -// C++ Implementation: platform_fs -// -// Description: -// -// -// Author: André Simon <andre.simon1@gmx.de>, (C) 2004 -// -// Copyright: See COPYING file that comes with this distribution -// -// - -#include "platform_fs.h" -#include "./dirstream0.4/dirstream.h" - -#include <iostream> - -using namespace std; - -namespace Platform { - -#ifdef _WIN32 - #include <windows.h> - - const char pathSeparator = '\\'; - //const std::string pathSeparatorStr = "\\"; - - std::string getAppPath() - { - char pathAndName[MAX_PATH], path[MAX_PATH], drive[3]; - GetModuleFileName(NULL, pathAndName, MAX_PATH); - _splitpath(pathAndName, drive, path, 0, 0); - return std::string(drive)+path; - } - -#else - const char pathSeparator = '/'; - // const std::string pathSeparatorStr = "/"; - - std::string getAppPath() - { - return ""; - } - -#endif - -bool getDirectoryEntries(vector<string> &fileList, - string wildcard, - bool recursiveSearch) -{ - if (!wildcard.empty()) { - string directory_path; - string::size_type Pos = wildcard.find_last_of(pathSeparator); - if (Pos == string::npos) { - directory_path = "."; - } else { - directory_path = wildcard.substr(0, Pos + 1); - wildcard = wildcard.substr(Pos + 1); - } - - dirstr::dirstream str( directory_path.c_str(), - #ifdef USE_FN_MATCH - dirstr::pred_f(FnMatcher(wildcard.c_str(), 0)), - #else - dirstr::pattern_f(wildcard.c_str()), - #endif - (recursiveSearch)?dirstr::recursive_yes:dirstr::recursive_no); - - - for(string entry; str >> entry;) { - fileList.push_back(dirstr::full_path(entry)); - //std::cout << "Entry " <<entry<<"\n"; - } - } - return !(fileList.empty()); -} - -} - -// -// C++ Interface: platform_fs -// -// Description: -// -// -// Author: André Simon <andre.simon1@gmx.de>, (C) 2004 -// -// Copyright: See COPYING file that comes with this distribution -// -// -#ifndef PLATFORM_FS__H__INCLUDED -#define PLATFORM_FS__H__INCLUDED - -#include <string> -#include <iostream> -#include <vector> - -#ifdef USE_FN_MATCH - #include <fnmatch.h> -#endif - -namespace Platform -{ - extern const char pathSeparator; - //extern const std::string pathSeparatorStr; - - std::string getAppPath(); - - /** \param fileList Vector where found entries will be stored - \param wildcard Directory path and wildcard - \param recursiveSearch Test if directory should be searched recursively */ - bool getDirectoryEntries(std::vector<std::string> &fileList, - std::string wildcard, - bool recursiveSearch=false); - -#ifdef USE_FN_MATCH - struct FnMatcher - { - FnMatcher(const char* pattern, int flags) - : pattern_(pattern) - , flags_(flags) - {} - bool operator()(const std::string& e) const { - // std::cout << "pattern: "<<pattern_<< " entry: "<<e.c_str()<< " Res fn: " <<::fnmatch(pattern_, e.c_str(), FNM_PATHNAME)<< " \n"; - return ! ::fnmatch(pattern_, e.c_str(), flags_); - } - private: - const char* pattern_; - int flags_; - }; -#endif -} -#endif -/*************************************************************************** - PreFormatter.cpp - description - ------------------- - begin : Mo Jan 03 2005 - copyright : (C) 2005 by André Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "preformatter.h" - -namespace highlight { - -PreFormatter::PreFormatter(bool wrap, bool replTabs): - maxLineLength(80), - index(0), - numberSpaces(0), - wsPrefixLength(string::npos), - hasMore(false), - indentAfterOpenBraces(true), - redefineWsPrefix(false), - wrapLines(wrap), - replaceTabs(replTabs) -{ -} - -PreFormatter::PreFormatter(): - maxLineLength(80), - index(0), - numberSpaces(0), - wsPrefixLength(string::npos), - hasMore(false), - indentAfterOpenBraces(true), - redefineWsPrefix(false), - wrapLines(false), - replaceTabs(false) -{ -} - -PreFormatter::~PreFormatter() -{ -} - -bool PreFormatter::hasMoreLines(){ - return hasMore; -} - -bool PreFormatter::indentCode(){ - return indentAfterOpenBraces; -} - -void PreFormatter::setLine(const std::string newLine){ - - line=newLine; - - if (replaceTabs && numberSpaces) { - size_t tabPos=line.find('\t'); - while (tabPos!=string::npos){ - line.replace(tabPos , 1, numberSpaces - (tabPos % numberSpaces) , ' '); - tabPos = line.find('\t', tabPos+1); - } - } - - if (wrapLines){ - wsPrefix.clear(); - index=0; - wsPrefixLength=string::npos; - hasMore=true; - redefineWsPrefix=false; - } -} - -std::string PreFormatter::getNextLine(){ - - if (!wrapLines){ - hasMore = false; - return line; - } - - if (!index && line.length() > maxLineLength){ // erster Durchlauf... - // wenn möglich an öffnender Klammer oder Geichheitszeichen ausrichten - if (indentAfterOpenBraces){ - wsPrefixLength=line.find_first_of(INDENT_MARKERS); - } - // sonst die Einrückung der Originalzeile beibehalten - if (wsPrefixLength==string::npos || wsPrefixLength-index>maxLineLength){ - wsPrefixLength=line.find_first_not_of(WS_CHARS); - } - else { - // wsPrefix in allen neu umgebrochenen Zeilen durch Spaces ersetzen - redefineWsPrefix=true; - // Position hinter öffnende Klammer springen - wsPrefixLength=line.find_first_not_of(WS_CHARS,wsPrefixLength+1); - } - - if (wsPrefixLength!=string::npos){ - index = wsPrefixLength; - // Falls Anzahl der Whitespaces am beginn der ersten zeile größer - // als Max. Zeilenlänge, Whitespaces verwerfen - if (wsPrefixLength>maxLineLength){ - wsPrefixLength=0; - return string(); - } - else{ - wsPrefix=line.substr(0, wsPrefixLength); - } - } - // Zeile enthaelt nur Whitespace; verwerfen - else { - hasMore= false; - return string(); - } - } else { - if (redefineWsPrefix){ - wsPrefix.clear(); - wsPrefix.append(wsPrefixLength, ' '); - } - redefineWsPrefix=false; - } - - string resultString; - - // Position, ab der rckwaerts nach Umbruchmglichkeit gesucht wird - unsigned int searchEndPos = maxLineLength - wsPrefixLength; - - // letztes Teilstueck der Zeile ausgeben; Parsen beenden - if (line.length()-index < searchEndPos) { - hasMore=false; - resultString=(index>0) ? wsPrefix + line.substr(index) : line.substr(index); - return resultString; - } - - // Umbrechposition suchen - size_t lbPos = line.find_last_of(LB_CHARS, index+searchEndPos); - if (lbPos <= index || lbPos == string::npos) { - // nichts gefunden, hart umbrechen - lbPos = index + searchEndPos; - } - // Einrückung der Originalzeile erhalten - resultString+=wsPrefix; - // Neue Zeile erzeugen - resultString += line.substr(index, lbPos-index+1); - - // Whitespace am neuen Zeilenbeginn ignorieren, ausser beim ersten Durchlauf - //unsigned int newIndex=StringTools::getNextNonWsPos(line,lbPos+1); - size_t newIndex=line.find_first_not_of(WS_CHARS, lbPos+1); - index=(newIndex!=string::npos)?newIndex:line.length(); - - hasMore=index!=line.length(); // unnoetigen Leerstring vermeiden - - return resultString; -} - -void PreFormatter::setWrappingProperties(unsigned int maxLineLength, bool indentAfterOpenBraces){ - this->maxLineLength = maxLineLength; - this->indentAfterOpenBraces = indentAfterOpenBraces; -} - -void PreFormatter::setNumberSpaces(unsigned int num){ - numberSpaces = num; -} - -} -/*************************************************************************** - PreFormatter.cpp - description - ------------------- - begin : Mo Jan 03 2005 - copyright : (C) 2005 by André Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef PreFormatter_H -#define PreFormatter_H - -#define LB_CHARS " \t[](){}-+<>.:,;" -#define WS_CHARS " \n\r\t" -#define INDENT_MARKERS "{(=" - -#include <string> -#include <iostream> - -#include "stringtools.h" - -namespace highlight { - -/** \brief Class which provides intelligent line wrapping. -* @author Andre Simon -*/ - -class PreFormatter{ -public: - /** Constructor - */ - PreFormatter(bool wrap, bool replTabs); - - PreFormatter(); - - ~PreFormatter(); - - /** - \return True if current line can be wrapped again - */ - bool hasMoreLines(); - - /** - Sets new line to be wrapped - \param newline New line - */ - void setLine(const std::string newline); - - /** - The method will indent function calls and statements - \return Next line - */ - std::string getNextLine(); - - /** - \return True if lines following open braces should be indented - */ - bool indentCode(); - - /** - \param maxlength max. length of output lines - \param indentAfterOpenBraces set true if lines should be indented after braces - */ - void setWrappingProperties(unsigned int maxlength=80, bool indentAfterOpenBraces=true); - - /** - \param num number of spaces which replace a tab - */ - - void setNumberSpaces(unsigned int num); - - /** - \return true if preformatting is enabled - */ - bool isEnabled(){ - return wrapLines || replaceTabs; - } - -private: - - unsigned int maxLineLength; - - std::string line, wsPrefix; - unsigned int index; - unsigned int numberSpaces; - size_t wsPrefixLength; - bool hasMore, indentAfterOpenBraces; - bool redefineWsPrefix; - bool wrapLines, replaceTabs; -}; - -} - -#endif -/*************************************************************************** - rtfcode.cpp - description - ------------------- - begin : Die Jul 9 2002 - copyright : (C) 2002 by André Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "rtfgenerator.h" - -using namespace std; - -namespace highlight { - -string RtfGenerator::formatStyleAttributes( const ElementStyle & col) -{ - stringstream s; - s << "\\red"<< col.getColour().getRTFRedValue() - << "\\green"<<col.getColour().getRTFGreenValue() - << "\\blue"<<col.getColour().getRTFBlueValue() - << ";"; - - return s.str(); -} - -string RtfGenerator::getOpenTag(int styleNumber,const ElementStyle & elem) -{ - ostringstream s; - s << "{\\cf"<<(styleNumber+1)<<"{"; - if (elem.isBold()) s << "\\b "; - if (elem.isItalic()) s << "\\i "; - if (elem.isUnderline()) s << "\\ul "; - return s.str(); -} - -string RtfGenerator::getCloseTag(const ElementStyle &elem) -{ - ostringstream s; - if (elem.isBold()) s << "\\b0 "; - if (elem.isItalic()) s << "\\i0 "; - if (elem.isUnderline()) s << "\\ul0 "; - s << "}}"; - return s.str(); -} - -RtfGenerator::RtfGenerator(const string &colourTheme) - : CodeGenerator( colourTheme) -{ - styleTagOpen.push_back(getOpenTag(STANDARD, docStyle.getDefaultStyle())); - styleTagOpen.push_back(getOpenTag(STRING, docStyle.getStringStyle())); - styleTagOpen.push_back(getOpenTag(NUMBER, docStyle.getNumberStyle())); - styleTagOpen.push_back(getOpenTag(SL_COMMENT, docStyle.getSingleLineCommentStyle())); - styleTagOpen.push_back(getOpenTag(ML_COMMENT_BEGIN,docStyle.getCommentStyle())); - styleTagOpen.push_back(getOpenTag(ESC_CHAR, docStyle.getEscapeCharStyle())); - styleTagOpen.push_back(getOpenTag(DIRECTIVE_LINE, docStyle.getDirectiveStyle())); - styleTagOpen.push_back(getOpenTag(DIRECTIVE_STRING, docStyle.getDirectiveStringStyle())); - styleTagOpen.push_back(getOpenTag(LINENUMBER, docStyle.getLineStyle())); - styleTagOpen.push_back(getOpenTag(SYMBOL, docStyle.getSymbolStyle())); - - styleTagClose.push_back(getCloseTag(docStyle.getDefaultStyle())); - styleTagClose.push_back(getCloseTag(docStyle.getStringStyle())); - styleTagClose.push_back(getCloseTag(docStyle.getNumberStyle())); - styleTagClose.push_back(getCloseTag(docStyle.getSingleLineCommentStyle())); - styleTagClose.push_back(getCloseTag(docStyle.getCommentStyle())); - styleTagClose.push_back(getCloseTag(docStyle.getEscapeCharStyle())); - styleTagClose.push_back(getCloseTag(docStyle.getDirectiveStyle())); - styleTagClose.push_back(getCloseTag(docStyle.getDirectiveStringStyle())); - styleTagClose.push_back(getCloseTag(docStyle.getLineStyle())); - styleTagClose.push_back(getCloseTag(docStyle.getSymbolStyle())); - - newLineTag = "\\par\\pard\n"; - spacer = " "; -} - -RtfGenerator::RtfGenerator() -{} -RtfGenerator::~RtfGenerator() -{} - -string RtfGenerator::getHeader(const string & title) -{ - return string(); -} - -void RtfGenerator::printBody() -{ - *out << "{\\rtf1\\ansi\\uc0 \\deff1" - << "{\\fonttbl{\\f1\\fmodern\\fprq1\\fcharset0 Courier;}}" - << "{\\colortbl;"; - - *out << formatStyleAttributes(docStyle.getDefaultStyle()); - - *out << formatStyleAttributes(docStyle.getStringStyle()); - *out << formatStyleAttributes(docStyle.getNumberStyle()); - *out << formatStyleAttributes(docStyle.getSingleLineCommentStyle()); - - *out << formatStyleAttributes(docStyle.getCommentStyle()); - *out << formatStyleAttributes(docStyle.getEscapeCharStyle()); - *out << formatStyleAttributes(docStyle.getDirectiveStyle()); - - *out << formatStyleAttributes(docStyle.getDirectiveStringStyle()); - *out << formatStyleAttributes(docStyle.getLineStyle()); - *out << formatStyleAttributes(docStyle.getSymbolStyle()); - - /* For output formats which can refer to external styles it is more safe - to use the colour theme's keyword class names, since the language - definitions (which may change during a batch conversion) do not have to define - all keyword classes, that are needed to highlight all input files correctly. - It is ok for RTF to use the language definition's class names, because RTF - does not refer to external styles. - We cannot use the theme's class names, because KSIterator returns an - alphabetically ordered list, which is not good because RTF is dependent - on the order. We access the keyword style with an ID, which is calculated - ignoring the alphabetic order. - */ - vector<string> keywordClasses = langInfo.getKeywordClasses(); - for (unsigned int i=0;i<keywordClasses.size();i++){ - *out << formatStyleAttributes(docStyle.getKeywordStyle(keywordClasses[i])); - } - - *out << "}\n{\\info }\\paperw11900\\paperh16820\\margl560\\margr560\\margt840" - << "\\margb840\\widowctrl\\ftnbj\\aenddoc\\formshade \\fet0\\sectd" - << "\\linex0\\endnhere\\plain\\f1\\fs20\n\\pard "; - processRootState(); - *out << "}}"<<endl; -} - - -string RtfGenerator::getFooter() -{ - return string(); -} - -/** Gibt RTF-Code der Sonderzeichen zurueck */ -string RtfGenerator::maskCharacter(unsigned char c) -{ - switch (c) - { - case '}' : - case '{' : - case '\\' : - { - string m; - m="\\"; - return m+=c; - } - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - string m; - m="{"; - m+=c; - m+="}"; - return m; - } - break; - case AUML_LC: - return "\\'e4"; - break; - case OUML_LC: - return "\\'f6"; - break; - case UUML_LC: - return "\\'fc"; - break; - case AUML_UC: - return "\\'c4"; - break; - case OUML_UC: - return "\\'d6"; - break; - case UUML_UC: - return "\\'dc"; - break; - - case AACUTE_LC: - return "\\'e1"; - break; - case EACUTE_LC: - return "\\'e9"; - break; - case OACUTE_LC: - return "\\'f3"; - break; - case UACUTE_LC: - return "\\'fa"; - break; - - case AGRAVE_LC: - return "\\'e0"; - break; - case EGRAVE_LC: - return "\\'e8"; - break; - case OGRAVE_LC: - return "\\'f2"; - break; - case UGRAVE_LC: - return "\\'f9"; - break; - - case AACUTE_UC: - return "\\'c1"; - break; - case EACUTE_UC: - return "\\'c9"; - break; - case OACUTE_UC: - return "\\'d3"; - break; - case UACUTE_UC: - return "\\'da"; - break; - case AGRAVE_UC: - return "\\'c0"; - break; - case EGRAVE_UC: - return "\\'c8"; - break; - case OGRAVE_UC: - return "\\'d2"; - break; - case UGRAVE_UC: - return "\\'d9"; - break; - - case SZLIG: - return "\\'df"; - break; - // skip first byte of multibyte chracters - /* #ifndef _WIN32 - case 195: - return string(""); - break; -#endif*/ - - default : - { - string m; - return m += c; - } - } -} - -string RtfGenerator::getMatchingOpenTag(unsigned int styleID){ - return getOpenTag(KEYWORD+styleID, - docStyle.getKeywordStyle(langInfo.getKeywordClasses()[styleID])); -} - -string RtfGenerator::getMatchingCloseTag(unsigned int styleID){ - return getCloseTag(docStyle.getKeywordStyle(langInfo.getKeywordClasses()[styleID])); -} - - -} -/*************************************************************************** - rtfcode.h - description - ------------------- - begin : Die Jul 9 2002 - copyright : (C) 2002 by Andre Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef RTFGENERATOR_H -#define RTFGENERATOR_H - -#include <iostream> -#include <fstream> -#include <string> -#include <sstream> - -#include "codegenerator.h" -#include "charcodes.h" -#include "version.h" - -namespace highlight { - -/** - \brief This class generates RTF. - - It contains information about the resulting document structure (document - header and footer), the colour system, white space handling and text - formatting attributes. - -* @author Andre Simon -*/ - -class RtfGenerator : public highlight::CodeGenerator - { - public: - - /** Constructor - \param colourTheme Name of Colour theme to use - */ - RtfGenerator( const string &colourTheme); - RtfGenerator(); - ~RtfGenerator(); - - /** prints document header - \param title Title of the document - */ - string getHeader(const string & title); - - /** Prints document footer*/ - string getFooter(); - - /** Prints document body*/ - void printBody(); - - private: - - /** \return escaped character*/ - virtual string maskCharacter(unsigned char ); - - /**\return text formatting attributes in RTF format */ - string formatStyleAttributes( const ElementStyle & col); - - /** gibt RTF-"Tags" zurueck (Farbindex+bold+kursiv)*/ - string getOpenTag(int styleNumber,const ElementStyle &); - - string getCloseTag(const ElementStyle &); - - string getMatchingOpenTag(unsigned int styleID); - string getMatchingCloseTag(unsigned int styleID); - }; - -} -#endif -/*************************************************************************** - stringtools.cpp - description - ------------------- - begin : Mon Dec 10 2001 - copyright : (C) 2001 by André Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "stringtools.h" - -#include <sstream> -#include <iostream> -#include <cctype> - -using namespace std; - -namespace StringTools - { -// Make a lowercase copy of s: -// (C) Bruce Eckel, Thinking in C++ Vol 2 - -string lowerCase(const string& s) -{ - char* buf = new char[s.length()]; - s.copy(buf, s.length()); - for(unsigned int i = 0; i < s.length(); i++) - buf[i] = tolower(buf[i]); - string r(buf, s.length()); - delete buf; - return r; -} - -int str2int(string s) -{ - istringstream os(s); - int intVal; - os >> intVal; - return intVal; -} - - bool isAlpha(unsigned char c) - { - return (isalpha(c) || c == '_'); - } - -string trimRight(const string &value) - { - string::size_type where = value.find_last_not_of(" \t\r"); - - if (where == string::npos) - // string has nothing but space - return string(); - - if (where == (value.length() - 1)) - // string has no trailing space, don't copy its contents - return value; - - return value.substr(0, where + 1); - } - -unsigned char getNextNonWs(const string &line, int index) -{ - unsigned char c; - do - { - c=line[index++]; - } - while (isspace(c)); - return c; -} - -string getParantheseVal(const string &s){ - string::size_type openPos=s.find('('); - string::size_type closePos=s.rfind(')'); - if (openPos ==string::npos || closePos==string::npos){ - return string(); - } - return s.substr(openPos+1, closePos-openPos-1); - -} - -} -/*************************************************************************** - stringtools.h - description - ------------------- - begin : Mon Dec 10 2001 - copyright : (C) 2001 by André Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef STRINGTOOLS_H -#define STRINGTOOLS_H - -#include <string> - -using namespace std; - -/**\brief Contains methods for string manipulation - *@author Andre Simon - */ - -namespace StringTools - { - - /** \param s String - \returns lowercase string */ - string lowerCase(const string &s); - - /** \param s String - \returns Integer value */ - int str2int(string s); - - /** \return true if c is alpa or underscore */ - bool isAlpha(unsigned char c); - - /** \param value String - \return string trimmed on the left side - */ - string trimRight(const string &value); - - /** \return next character in line starting from index, which is no whitespace*/ - unsigned char getNextNonWs(const string &line, int index=0); - - /** \param s String, containing a opening and a closing paranthesis - \return value between "(", ")" */ - string getParantheseVal(const string &s); - -} - -#endif -/*************************************************************************** - stylecolour.cpp - description - ------------------- - begin : Die Nov 5 2002 - copyright : (C) 2002 by André Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "stylecolour.h" - -using std::string; - -namespace highlight { - -StyleColour::StyleColour(const string & r_hex, const string & g_hex, const string & b_hex) - : r(r_hex), g(g_hex), b(b_hex) -{} -StyleColour::StyleColour() - : r("00"), g("00"), b("00") -{} - -//Parst PArameter aus style-Datei -StyleColour::StyleColour(const string & styleColourString) -{ - setRGBValues(styleColourString); -} - -void StyleColour::setRGBValues(const string & styleColourString){ - //Stringstream zum Einlesen der Tokens: - istringstream valueStream(styleColourString.c_str()); - valueStream >> r; - valueStream >> g; - valueStream >> b; -} - -void StyleColour::setRedValue(const string & r_hex) -{ - r = r_hex; -} - -void StyleColour::setGreenValue(const string & g_hex) -{ - g = g_hex; -} - -void StyleColour::setBlueValue(const string & b_hex) -{ - b = b_hex; -} - -string& StyleColour::getHexRedValue() -{ - return r; -} -string& StyleColour::getHexGreenValue() -{ - return g; -} -string& StyleColour::getHexBlueValue() -{ - return b; -} - - -string StyleColour::getRTFRedValue() -{ - return int2str(hex2dec(r)); -} -string StyleColour::getRTFGreenValue() -{ - return int2str(hex2dec(g)); -} -string StyleColour::getRTFBlueValue() -{ - return int2str(hex2dec(b)); -} - - -string StyleColour::getLatexRedValue() -{ - return float2str((float)hex2dec(r)/255); -} -string StyleColour::getLatexGreenValue() -{ - return float2str((float)hex2dec(g)/255); -} -string StyleColour::getLatexBlueValue() -{ - return float2str((float)hex2dec(b)/255); -} - -// Konvertieren von RGB nach CYM -string StyleColour::getTexRedValue() -{ - return float2str(1-(float)hex2dec(r)/255); -} -string StyleColour::getTexGreenValue() -{ - return float2str(1-(float)hex2dec(g)/255); -} -string StyleColour::getTexBlueValue() -{ - return float2str(1-(float)hex2dec(b)/255); -} - - -string StyleColour::int2str(const int num) -{ - std::ostringstream outStream; - outStream << num; - - return outStream.str(); -} - -string StyleColour::float2str(const double num) -{ - std::ostringstream outStream; - outStream << ( floor ( num * 100 + .5 ) / 100); - - return outStream.str(); -} - -int StyleColour::hex2dec(const string &hexVal) -{ - - if (hexVal.length() != 2) - return 0; - - unsigned int decVal=0, koeff=16; - - for (int i=0; i<2;i++ ) - { - if ((hexVal[i] >= '0')&& (hexVal[i]<= '9' )) - { - decVal += (koeff * (hexVal[i]-'0')); - - } - if ((hexVal[i] >= 'a')&& (hexVal[i]<= 'f' )) - { - decVal +=( koeff * (hexVal[i]-87)); - } - if ((hexVal[i] >= 'A')&& (hexVal[i]<= 'F' )) - { - decVal += (koeff * (hexVal[i]-55)); - } - koeff=1; - } - return decVal; -} - -} - -/*************************************************************************** - stylecolour.h - description - ------------------- - begin : Die Nov 5 2002 - copyright : (C) 2002 by Andre Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef STYLECOLOUR_H -#define STYLECOLOUR_H - -#include <string> -#include <sstream> -#include <fstream> -#include <cmath> -#include <sstream> - -using namespace std; - -namespace highlight { - -/**\brief Stores colours and returns red, green and blue values in different formats -* @author Andre Simon - */ - -class StyleColour - { - public: - /** Constructor - \param r_hex Red value in hex notation - \param g_hex Blue value in hex notation - \param b_hex Green value in hex notation - */ - StyleColour(const string & r_hex, const string & g_hex, const string & b_hex); - - /** Constructor - \param styleColourString String with rgb values - */ - StyleColour(const string & styleColourString); - - StyleColour(); - ~StyleColour(){}; - - /** Sets red, green and blue values - \param styleColourString String containing colour attributes - */ - void setRGBValues(const string & styleColourString); - - /** Sets red value - \param r_hex New red value */ - void setRedValue(const string & r_hex); - - /** Sets green value - \param g_hex New green value */ - void setGreenValue(const string & g_hex); - - /** Sets blue value - \param b_hex New blue value */ - void setBlueValue(const string & b_hex); - - /** \return Red value in hex format */ - string& getHexRedValue(); - /** \return Green value in hex format */ - string& getHexGreenValue(); - /** \return Blue value in hex format */ - string& getHexBlueValue(); - - /** \return Red value in latex format */ - string getLatexRedValue(); - /** \return Green value in latex format */ - string getLatexGreenValue(); - /** \return Blue value in latex format */ - string getLatexBlueValue(); - - /** \return Red value in tex format */ - string getTexRedValue(); - /** \return Green value in tex format */ - string getTexGreenValue(); - /** \return Blue value in tex format */ - string getTexBlueValue(); - - /** \return Red value in RTF format */ - string getRTFRedValue(); - /** \return Green value in RTF format */ - string getRTFGreenValue(); - /** \return Blue value in RTF format */ - string getRTFBlueValue(); - - private: - string r, g, b; - string int2str(int); - string float2str(double); - int hex2dec(const string &hexVal); - }; - -} - -#endif -/*************************************************************************** - TexGenerator.cpp - description - ------------------- - begin : Mit Jul 24 2002 - copyright : (C) 2002 by André Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "texgenerator.h" - -namespace highlight { - -TexGenerator::TexGenerator(const string &colourTheme): - CodeGenerator( colourTheme) -{ - styleTagOpen.push_back( "{\\hlstd "); - styleTagOpen.push_back( "{\\hlstr "); - styleTagOpen.push_back( "{\\hlnum "); - styleTagOpen.push_back( "{\\hlslc "); - styleTagOpen.push_back( "{\\hlcom "); - styleTagOpen.push_back( "{\\hlesc "); - styleTagOpen.push_back( "{\\hldir "); - styleTagOpen.push_back( "{\\hldstr "); - styleTagOpen.push_back( "{\\hlline "); - styleTagOpen.push_back( "{\\hlsym "); - for (int i=0;i<NUMBER_BUILTIN_STYLES; i++) { - styleTagClose.push_back( "}"); - } - - /*This makes TeX to use every par it encounters (the \\leavevmode has - no effect when TeX is in horizontal mode and when TeX is in vertical - mode, it switches it to horizontal mode).*/ - newLineTag="\\leavevmode\\par\n"; - - spacer = "\\ "; - maskWs=true; - excludeWs=true; - maskWsBegin = "{\\hlstd"; - maskWsEnd = "}"; - styleCommentOpen="%"; -} - -TexGenerator::TexGenerator() -{} -TexGenerator::~TexGenerator() -{} - -string TexGenerator::formatStyleAttributes(const string & elemName,const ElementStyle & elem) -{ - ostringstream s; - s << "\\def\\hl" - << elemName - << "{"; - if (elem.isBold()) - s << "\\bf"; - if (elem.isItalic()) - s << "\\it"; - s << "\\textColor{" - << (elem.getColour().getTexRedValue())<<" " - << (elem.getColour().getTexGreenValue())<<" " - << (elem.getColour().getTexBlueValue())<<" 0.0}}\n"; - return s.str(); -} - -string TexGenerator::getHeader(const string & title) -{ - ostringstream os; - - if (langInfo.getSyntaxHighlight()) { - if (includeStyleDef) { - os << "\n"<<getStyleDefinition(); - os << CodeGenerator::readUserStyleDef(); - } else { - os << "\\input " - << getStyleOutputPath() - << "\n\n"; - } - } - - return os.str(); -} - -void TexGenerator::printBody() -{ - *out << "{\n\\tt\n"; - - processRootState(); - *out << "}\n"; -} - -string TexGenerator::getFooter() -{ - ostringstream os; - os << "\\bye\n" - << "% TeX generated by Highlight " - << HIGHLIGHT_VERSION - << ", " - << HIGHLIGHT_URL - << endl; - return os.str(); -} - -string TexGenerator:: maskCharacter(unsigned char c) -{ - switch (c) - { - case '{': - case '}': - { - string m; - m = "$\\"; - m += c; - m += "$"; - return m; - } - break; - case '^': - return "{\\bf\\^{}}"; - break; - case '_': - return "\\_{}"; - break; - case '&': - case '$': - case '#': - case '%': - { - string m; - m = "\\"; - m += c; - return m; - } - break; - case '\\': - return "$\\backslash$"; - break; - case ' ': - return spacer; - break; - case '+': - case '-': - case '<': - case '>': - case '=': - { - string m; - m = "$\\mathord{"; - m += c; - m += "}$"; - return m; - } - break; - case AUML_LC: - return "\\\"a"; - break; - case OUML_LC: - return "\\\"o"; - break; - case UUML_LC: - return "\\\"u"; - break; - case AUML_UC: - return "\\\"A"; - break; - case OUML_UC: - return "\\\"O"; - break; - case UUML_UC: - return "\\\"U"; - break; - case AACUTE_LC: - return "\\'a"; - break; - case EACUTE_LC: - return "\\'e"; - break; - case OACUTE_LC: - return "\\'o"; - break; - case UACUTE_LC: - return "\\'u"; - break; - case AGRAVE_LC: - return "\\`a"; - break; - case EGRAVE_LC: - return "\\`e"; - break; - case OGRAVE_LC: - return "\\`o"; - break; - case UGRAVE_LC: - return "\\`u"; - break; - case AACUTE_UC: - return "\\'A"; - break; - case EACUTE_UC: - return "\\'E"; - break; - case OACUTE_UC: - return "\\'O"; - break; - case UACUTE_UC: - return "\\'U"; - break; - case AGRAVE_UC: - return "\\`A"; - break; - case EGRAVE_UC: - return "\\`E"; - break; - case UGRAVE_UC: - return "\\`O"; - break; - case OGRAVE_UC: - return "\\`U"; - break; - case SZLIG: - return "\\ss "; - break; - /* #ifndef _WIN32 - // skip first byte of multibyte chracters - case 195: - return string(""); - break; -#endif*/ - - default : - string m; - return m += c; - } -} - -string TexGenerator::getMatchingOpenTag(unsigned int styleID){ - return "{\\hl"+langInfo.getKeywordClasses()[styleID]+" "; - } - -string TexGenerator::getMatchingCloseTag(unsigned int styleID){ - return "}"; -} - - -string TexGenerator::getStyleDefinition() -{ - if (styleDefinitionCache.empty()){ - ostringstream os; - os << formatStyleAttributes("std", docStyle.getDefaultStyle()); - os << formatStyleAttributes("num", docStyle.getNumberStyle()); - os << formatStyleAttributes("esc", docStyle.getEscapeCharStyle()); - os << formatStyleAttributes("str", docStyle.getStringStyle()); - os << formatStyleAttributes("dstr", docStyle.getDirectiveStringStyle()); - os << formatStyleAttributes("slc", docStyle.getSingleLineCommentStyle()); - os << formatStyleAttributes("com", docStyle.getCommentStyle()); - os << formatStyleAttributes("dir", docStyle.getDirectiveStyle()); - os << formatStyleAttributes("line", docStyle.getLineStyle()); - os << formatStyleAttributes("sym", docStyle.getSymbolStyle()); - - KeywordStyles styles = docStyle.getKeywordStyles(); - for (KSIterator it=styles.begin(); it!=styles.end(); it++){ - os << formatStyleAttributes(it->first, *(it->second)); - } - - os << "% The special option is not supported by all dvi drivers\n" - << "\\special{background rgb " - << docStyle.getBgColour().getLatexRedValue() << " " - << docStyle.getBgColour().getLatexGreenValue() << " " - << docStyle.getBgColour().getLatexBlueValue() << "}"; - os << "\n\\nopagenumbers\n" - << "\\input colordvi\n"; - styleDefinitionCache=os.str(); - } - return styleDefinitionCache; -} - - -} -/*************************************************************************** - texcode.h - description - ------------------- - begin : Mit Jul 24 2002 - copyright : (C) 2002 by André Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef TEXGENERATOR_H -#define TEXGENERATOR_H - -#include <string> -#include <iostream> -#include <sstream> - -#include "charcodes.h" -#include "version.h" -#include "codegenerator.h" - - -namespace highlight { - -/** - \brief This class generates TeX. - - It contains information about the resulting document structure (document - header and footer), the colour system, white space handling and text - formatting attributes. - -* @author Andre Simon -*/ - -class TexGenerator : public highlight::CodeGenerator - { - public: - - /** Constructor - \param colourTheme Name of Colour theme to use - */ - TexGenerator(const string &colourTheme); - TexGenerator(); - ~TexGenerator(); - - /** prints document header - \param title Title of the document - */ - string getHeader(const string & title); - - /** Prints document footer*/ - string getFooter(); - - /** Prints document body*/ - void printBody(); - - private: - - string styleDefinitionCache; - - string getStyleDefinition(); - - /** \return escaped character*/ - virtual string maskCharacter(unsigned char ); - - /**\return text formatting attributes in RTF format */ - string formatStyleAttributes(const string & elemName, const ElementStyle & elem); - - string getMatchingOpenTag(unsigned int styleID); - string getMatchingCloseTag(unsigned int styleID); - - }; - -} - -#endif -/*************************************************************************** - version.h - description - ------------------- - begin : Mon March 3 2003 - copyright : (C) 2003 by André Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef VERSION_H -#define VERSION_H - -#define HIGHLIGHT_VERSION "2.2-10" - -#define HIGHLIGHT_URL "http://www.andre-simon.de/" -#define HIGHLIGHT_EMAIL "andre.simon1@gmx.de" - -#endif -/*************************************************************************** - htmlcode.cpp - description - ------------------- - begin : Wed Nov 28 2001 - copyright : (C) 2001 by André Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "xhtmlgenerator.h" - -using namespace std; - -namespace highlight { - -XHtmlGenerator::XHtmlGenerator(void) -{} - -XHtmlGenerator::XHtmlGenerator ( - const string &cssStyle, - const string &enc, - bool omitEnc, - bool withAnchors) - : HtmlGenerator(cssStyle, enc, omitEnc, withAnchors) -{ - fileSuffix=".xhtml"; - brTag="<br />"; - hrTag="<hr />"; - idAttr="id"; - - HTML_FOOTER= - "\n</body>\n</html>\n<!--XHTML generated by highlight " - HIGHLIGHT_VERSION - ", " - HIGHLIGHT_URL - "-->\n"; -} - -string XHtmlGenerator::getHeaderStart(const string &title){ - ostringstream header; - header << "<?xml version=\"1.0\""; - if (!omitEncoding) { - header << " encoding=\"" << encoding << "\""; - } - header << "?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"" - << " \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n" - << "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" - << "<head>\n<title>" << title << "</title>\n"; - - return header.str(); -} - - -string XHtmlGenerator::getHeader(const string &title) -{ - ostringstream osPart1; - osPart1 << getHeaderStart((title.empty())?"Source file":title ); - - if (langInfo.getSyntaxHighlight()) - { - if (includeStyleDef) //CSS-Definition in HTML-<head> einfuegen - { - osPart1 << "<style type=\"text/css\">\n"; - osPart1 << "<![CDATA[\n"; - osPart1 << getStyleDefinition(); - osPart1 << CodeGenerator::readUserStyleDef(); - osPart1 << "]]>\n"; - osPart1 << "</style>\n"; - } - else //Referenz auf CSS-Datei einfuegen - { - osPart1 << "<link rel=\"stylesheet\" type=\"text/css\" href=\"" - << getStyleOutputPath() - << "\"" - << "/" - << ">\n"; - } - } - osPart1 << "</head>\n<body class=\"hl\">\n<pre class=\"hl\">"; - - return osPart1.str(); -} - -} -/*************************************************************************** - xhtmlgenerator.h - description - ------------------- - begin : Mo Jun 21 2004 - copyright : (C) 2004 by Andre Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - - -#ifndef XHTMLGENERATOR_H -#define XHTMLGENERATOR_H - -#include "htmlgenerator.h" - -namespace highlight { - -/** - \brief This class generates XHTML. - - It contains information about the resulting document structure (document - header and footer), the colour system, white space handling and text - formatting attributes. - -* @author Andre Simon -*/ - - -class XHtmlGenerator : public highlight::HtmlGenerator - { - public: - - /** Constructor - \param colourTheme Name of Colour theme to use - \param enc encoding name - \param omitEnc switch to omit encoding information - \param withAnchors Test if HTML anchors should be attached to line numbers - */ - XHtmlGenerator(const string &colourTheme, - const string &enc, - bool omitEnc=false, - bool withAnchors = false); - - XHtmlGenerator(); - - /** Destructor*/ - virtual ~XHtmlGenerator() {}; - - private: - - /** prints document header - \param title Title of the document - */ - string getHeader(const string &title); - - string getHeaderStart(const string &title); - - }; - -} - -#endif -/*************************************************************************** - xmlcode.cpp - description - ------------------- - begin : Do 20.01.2005 - copyright : (C) 2005 by Andre Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "xmlgenerator.h" - -using namespace std; -namespace highlight { - - XmlGenerator::XmlGenerator(const string &colourTheme,const string &enc, bool omitEnc) - : CodeGenerator(colourTheme), - encoding(enc), omitEncoding(omitEnc) -{ - styleTagOpen.push_back(getOpenTag("def")); - styleTagOpen.push_back(getOpenTag("str")); - styleTagOpen.push_back(getOpenTag("num")); - styleTagOpen.push_back(getOpenTag("slc")); - styleTagOpen.push_back(getOpenTag("com")); - styleTagOpen.push_back(getOpenTag("esc")); - styleTagOpen.push_back(getOpenTag("dir")); - styleTagOpen.push_back(getOpenTag("dstr")); - styleTagOpen.push_back(getOpenTag("line")); - styleTagOpen.push_back(getOpenTag("sym")); - - styleTagClose.push_back(getCloseTag("def")); - styleTagClose.push_back(getCloseTag("str")); - styleTagClose.push_back(getCloseTag("num")); - styleTagClose.push_back(getCloseTag("slc")); - styleTagClose.push_back(getCloseTag("com")); - styleTagClose.push_back(getCloseTag("esc")); - styleTagClose.push_back(getCloseTag("dir")); - styleTagClose.push_back(getCloseTag("dstr")); - styleTagClose.push_back(getCloseTag("line")); - styleTagClose.push_back(getCloseTag("sym")); - - spacer = " "; - newLineTag = "<br />\n"; -} - -string XmlGenerator::getStyleDefinition() -{ - if (styleDefinitionCache.empty()) { - ostringstream os; - os << "\n<style>\n" - << "\t<bgcolor value=\"" - << (docStyle.getBgColour().getHexRedValue()) - << (docStyle.getBgColour().getHexGreenValue()) - << (docStyle.getBgColour().getHexBlueValue()) - << "\" />\n" - << "\t<font size=\"" - << docStyle.getFontSize() - << "\" family=\"Courier\" />\n"; - - os << formatStyleAttributes("def", docStyle.getDefaultStyle()) - << formatStyleAttributes("num", docStyle.getNumberStyle()) - << formatStyleAttributes("esc", docStyle.getEscapeCharStyle()) - << formatStyleAttributes("str", docStyle.getStringStyle()) - << formatStyleAttributes("dstr", docStyle.getDirectiveStringStyle()) - << formatStyleAttributes("slc", docStyle.getSingleLineCommentStyle()) - << formatStyleAttributes("com", docStyle.getCommentStyle()) - << formatStyleAttributes("dir", docStyle.getDirectiveStyle()) - << formatStyleAttributes("sym", docStyle.getSymbolStyle()) - << formatStyleAttributes("line", docStyle.getLineStyle()); - - KeywordStyles styles = docStyle.getKeywordStyles(); - for (KSIterator it=styles.begin(); it!=styles.end(); it++){ - os << formatStyleAttributes(it->first, *(it->second)); - } - os << "</style>\n"; - styleDefinitionCache=os.str(); - } - return styleDefinitionCache; -} - - -string XmlGenerator::formatStyleAttributes(const string & elemName, - const ElementStyle & elem) -{ - ostringstream s; - s << "\t<class name=\"" - << elemName - <<"\" color=\"" - << (elem.getColour().getHexRedValue()) - << (elem.getColour().getHexGreenValue()) - << (elem.getColour().getHexBlueValue() ) - << "\" bold=\"" - << ( elem.isBold() ? "true" :"false" ) - << "\" italic=\"" - << ( elem.isItalic() ? "true" :"false" ) - << "\" underline=\"" - << ( elem.isUnderline() ? "true" :"false" ) - << "\" />\n" ; - return s.str(); -} - - -XmlGenerator::XmlGenerator() -{} -XmlGenerator::~XmlGenerator() -{} - -string XmlGenerator::getOpenTag(const string& styleName ){ - return "<"+styleName+">"; -} - -string XmlGenerator::getCloseTag(const string& styleName ){ - return "</"+styleName+">"; -} - -string XmlGenerator::getHeader(const string & title) -{ - ostringstream header; - header << "<?xml version=\"1.0\""; - if (!omitEncoding) { - header << " encoding=\"" << encoding << "\""; - } - header << "?>\n<document>" << getStyleDefinition(); - return header.str(); -} - -void XmlGenerator::printBody() -{ - *out << "<source>\n"; - processRootState(); - *out << "</source>\n"; -} - - -string XmlGenerator::getFooter() -{ - ostringstream os; - os <<"</document>\n"; - os<< "<!-- XML generated by Highlight " - << HIGHLIGHT_VERSION - << ", " - << HIGHLIGHT_URL - <<" -->\n"; - return os.str(); -} - -string XmlGenerator::maskCharacter(unsigned char c) -{ - switch (c) - { - case '<' : - return "<"; - break; - case '>' : - return ">"; - break; - case '&' : - return "&"; - break; - case '\"' : - return """; - break; - -// skip first byte of multibyte chracters - /* #ifndef _WIN32 - case 195: - return string(""); - break; -#endif*/ - - default: - string m; - m += c; - return m; - } -} - -/*string XmlGenerator::getNewLine(){ - string nlStr; - if (currentState!=_UNKNOWN){ - nlStr+=styleTagClose[getStyleID(currentState, currentKeywordClass)]; - } - nlStr += newLineTag; - if (currentState!=_UNKNOWN){ - nlStr+=styleTagOpen[getStyleID(currentState, currentKeywordClass)]; - } - return nlStr; -} -*/ -string XmlGenerator::getMatchingOpenTag(unsigned int styleID){ - return getOpenTag(langInfo.getKeywordClasses()[styleID]); -} - -string XmlGenerator::getMatchingCloseTag(unsigned int styleID){ - return getCloseTag(langInfo.getKeywordClasses()[styleID]); -} - -} -/*************************************************************************** - xmlcode.h - description - ------------------- - begin : Do 20.01.2005 - copyright : (C) 2005 by Andre Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef XMLGENERATOR_H -#define XMLGENERATOR_H - -#include <string> -#include <sstream> -#include <iostream> - -#include "codegenerator.h" -#include "version.h" - -namespace highlight { - -/** - \brief This class generates XML. - - It contains information about the resulting document structure (document - header and footer), the colour system, white space handling and text - formatting attributes. - -* @author Andre Simon -*/ - -class XmlGenerator : public highlight::CodeGenerator - { - public: - - /** Constructor - \param colourTheme Name of Colour theme to use - \param enc encoding name - \param omitEnc switch to omit encoding information - */ - XmlGenerator( const string &colourTheme,const string &enc, bool omitEnc=false); - - XmlGenerator(); - - ~XmlGenerator(); - - /** prints document header - \param title Title of the document - */ - string getHeader(const string & title); - - /** Prints document footer*/ - string getFooter(); - - /** Prints document body*/ - void printBody(); - - private: - - string styleDefinitionCache, encoding; - - bool omitEncoding; - - string getStyleDefinition(); - - string formatStyleAttributes(const string &, const ElementStyle &); - - /** \return escaped character*/ - virtual string maskCharacter(unsigned char ); - - -// string getNewLine(); - - string getOpenTag(const string& ); - string getCloseTag(const string& ); - - string getMatchingOpenTag(unsigned int styleID); - string getMatchingCloseTag(unsigned int styleID); - }; - -} - -#endif -/*************************************************************************** - xslfocode.cpp - description - ------------------- - begin : Do 11.12.2003 - copyright : (C) 2003 by André Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "xslfogenerator.h" - -using namespace std; -namespace highlight { - -XslFoGenerator::XslFoGenerator(const string &colourTheme, - const string &enc, - bool omitEnc, - bool fopCompatible) - : CodeGenerator(colourTheme), - encoding(enc), - fopOutput(fopCompatible), - omitEncoding(omitEnc) -{ - styleTagOpen.push_back( getOpenTag(docStyle.getDefaultStyle())); - styleTagOpen.push_back( getOpenTag(docStyle.getStringStyle())); - styleTagOpen.push_back( getOpenTag(docStyle.getNumberStyle())); - styleTagOpen.push_back( getOpenTag(docStyle.getSingleLineCommentStyle())); - styleTagOpen.push_back( getOpenTag(docStyle.getCommentStyle())); - styleTagOpen.push_back( getOpenTag(docStyle.getEscapeCharStyle())); - styleTagOpen.push_back( getOpenTag(docStyle.getDirectiveStyle())); - styleTagOpen.push_back( getOpenTag(docStyle.getDirectiveStringStyle())); - styleTagOpen.push_back( getOpenTag(docStyle.getLineStyle())); - styleTagOpen.push_back( getOpenTag(docStyle.getSymbolStyle())); - snl << " <fo:block font-size=\"" - << docStyle.getFontSize() - << "pt\" font-family=\"Courier\" white-space-collapse=\"false\" " - << "wrap-option=\"wrap\" line-height=\"12pt\" background-color=\"#" - << (docStyle.getBgColour().getHexRedValue()) - << (docStyle.getBgColour().getHexGreenValue()) - << (docStyle.getBgColour().getHexBlueValue()) - << "\">"; - - for (int i=0;i<NUMBER_BUILTIN_STYLES; i++) - { - styleTagClose.push_back( "</fo:inline>"); - } - if (fopOutput) - newLineTag ="</fo:block>\n<fo:block>"; - else - newLineTag ="</fo:block>\n"+ snl.str(); - - spacer = " "; -} - -XslFoGenerator::XslFoGenerator() -{} -XslFoGenerator::~XslFoGenerator() -{} - -string XslFoGenerator::getOpenTag(const ElementStyle &elem) -{ - ostringstream s; - s << "<fo:inline color=\"#" - << (elem.getColour().getHexRedValue()) - << (elem.getColour().getHexGreenValue()) - << (elem.getColour().getHexBlueValue()) - << "\""; - s << ( elem.isBold() ?" font-weight=\"bold\"" :"" ) - << ( elem.isItalic() ?" font-style=\"italic\"" :"" ) - << ( elem.isUnderline() ?" text-decoration=\"underline\"" :"" ); - s << ">"; - return s.str(); -} - -string XslFoGenerator::getHeader(const string & title) -{ - ostringstream os; - os << "<?xml version=\"1.0\""; - if (!omitEncoding) { - os << " encoding=\"" << encoding << "\""; - } - os << "?>\n<fo:root xmlns:fo=\"http://www.w3.org/1999/XSL/Format\">\n" - << "<fo:layout-master-set>\n" - << "<fo:simple-page-master master-name=\"DINA4\"\n" - << " page-height=\"29.7cm\"\n" - << " page-width=\"21cm\"\n" - << " margin-top=\"1cm\"\n" - << " margin-bottom=\"2cm\"\n" - << " margin-left=\"2.5cm\"\n" - << " margin-right=\"2.5cm\">\n" - << "<fo:region-body />\n" - << "</fo:simple-page-master>\n" - << "<fo:page-sequence-master master-name=\"basic\">\n" - << "<fo:repeatable-page-master-alternatives>\n" - << "<fo:conditional-page-master-reference master-reference=\"DINA4\" />\n" - << "</fo:repeatable-page-master-alternatives>\n" - << "</fo:page-sequence-master>\n" - << "</fo:layout-master-set>\n\n" - << "<fo:page-sequence master-reference=\"basic\">\n" - << " <fo:flow flow-name=\"xsl-region-body\">\n"; - if (fopOutput) - os << snl.str()<< "<fo:block>"; - else - os << snl.str(); - - return os.str(); -} - -/** gibt RTF-Text aus */ -void XslFoGenerator::printBody() -{ - processRootState(); -} - - -string XslFoGenerator::getFooter() -{ - ostringstream os; - if (fopOutput) - os <<"\n</fo:block>"; - os <<"\n</fo:block>\n </fo:flow>\n</fo:page-sequence>\n</fo:root>"<<endl - << "<!-- XSL-FO generated by Highlight " - << HIGHLIGHT_VERSION - << ", " - << HIGHLIGHT_URL - <<" -->\n"; - return os.str(); -} - -/** Gibt RTF-Code der Sonderzeichen zurueck */ -string XslFoGenerator::maskCharacter(unsigned char c) -{ - switch (c) - { - case '<' : - return "<"; - break; - case '>' : - return ">"; - break; - case '&' : - return "&"; - break; - case '\"' : - return """; - break; - -// skip first byte of multibyte chracters - /*#ifndef _WIN32 - case 195: - return string(""); - break; -#endif*/ - - default: - string m; - m += c; - return m; - } -} - -/*string XslFoGenerator::getNewLine(){ - string nlStr; - - if (currentState!=_UNKNOWN){ - nlStr+=styleTagClose[getStyleID(currentState, currentKeywordClass)]; -} - nlStr += newLineTag; - if (currentState!=_UNKNOWN){ - nlStr+=styleTagOpen[getStyleID(currentState, currentKeywordClass)]; -} - return nlStr; -}*/ - -string XslFoGenerator::getMatchingOpenTag(unsigned int styleID){ - return getOpenTag(docStyle.getKeywordStyle(langInfo.getKeywordClasses()[styleID])); -} - -string XslFoGenerator::getMatchingCloseTag(unsigned int styleID){ - return "</fo:inline>"; -} - -} -/*************************************************************************** - xslfocode.h - description - ------------------- - begin : Do 11.12.2003 - copyright : (C) 2003 by Andre Simon - email : andre.simon1@gmx.de - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef XSLFOGENERATOR_H -#define XSLFOGENERATOR_H - - -#include <string> -#include <sstream> -#include <iostream> -#include <fstream> - -#include "codegenerator.h" -#include "version.h" - -namespace highlight { - -/** - \brief This class generates XSL-FO. - - It contains information about the resulting document structure (document - header and footer), the colour system, white space handling and text - formatting attributes. - -* @author Andre Simon -*/ - -class XslFoGenerator : public highlight::CodeGenerator - { - public: - - /** Constructor - \param colourTheme Name of Colour theme to use - \param enc encoding name - \param omitEnc switch to omit encoding information - \param fopCompatible Test if output should be compatible with Apache FOP 0.20.5 - */ - XslFoGenerator( const string &colourTheme, - const string &enc, - bool omitEnc=false, - bool fopCompatible=false); - - XslFoGenerator(); - - ~XslFoGenerator(); - - /** prints document header - \param title Title of the document - */ - string getHeader(const string & title); - - /** Prints document footer*/ - string getFooter(); - - /** Prints document body*/ - void printBody(); - - private: - ostringstream snl; - - string styleDefinition, encoding; - bool fopOutput, omitEncoding; - - /** \return escaped character*/ - virtual string maskCharacter(unsigned char ); - - string getOpenTag(const ElementStyle &); - - // string getNewLine(); - - string getMatchingOpenTag(unsigned int styleID); - string getMatchingCloseTag(unsigned int styleID); - }; - -} - -#endif diff --git a/tests/examplefiles/example.rb b/tests/examplefiles/example.rb index 53c89efe..8a3304ba 100644 --- a/tests/examplefiles/example.rb +++ b/tests/examplefiles/example.rb @@ -7554,2517 +7554,3 @@ trunc_em(nums) # ``chomp'' chomps the record separator and returns what's expected # ``chomp!'' does the same but also modifies the parameter object - -# @@PLEAC@@_10.2 -def somefunc - variable = something # variable is local by default -end - -name, age = ARGV -start = fetch_time - -a, b = pair # will succeed if pair is an Array object (like ARGV is) -c = fetch_time - -# In ruby, run_check can't access a, b, or c until they are -# explicitely defined global (using leading $), even if they are -# both defined in the same scope - -def check_x(x) - y = "whatever" - run_check - if $condition - puts "got $x" - end -end - -# The following will keep a reference to the array, though the -# results will be slightly different from perl: the last element -# of $global_array will be itself an array -def save_array(ary) - $global_array << ary -end - -# The following gives the same results as in Perl for $global_array, -# though it doesn't illustrate anymore the way to keep a reference -# to an object: $global_array is extended with the elements of ary -def save_array(ary) - $global_array += ary -end - - -# @@PLEAC@@_10.3 -# In Ruby, AFAIK a method cannot access "local variables" defined -# upper scope; mostly because everything is an object, so you'll -# do the same by defining an attribute or a static attribute - -# In Ruby the BEGIN also exists: -BEGIN { puts "hello from BEGIN" } -puts "hello from main" -BEGIN { puts "hello from 2nd BEGIN" } -# gives: -# hello from BEGIN -# hello from 2nd BEGIN -# hello from main - -# In Ruby, it can be written as a static method and a static -# variable -class Counter - @@counter = 0 - def Counter.next_counter; @@counter += 1; end -end - -# There is no need of BEGIN since the variable will get -# initialized when parsing -class Counter - @@counter = 42 - def Counter.next_counter; @@counter += 1; end - def Counter.prev_counter; @@counter -= 1; end -end - - -# @@PLEAC@@_10.4 -# You can either get the whole trace as an array of strings, each -# string telling which file, line and method is calling: -caller - -# ...or only the last caller -caller[0] - -# We need to extract just the method name of the backtrace: -def whoami; caller()[0] =~ /in `([^']+)'/ ? $1 : '(anonymous)'; end -def whowasi; caller()[1] =~ /in `([^']+)'/ ? $1 : '(anonymous)'; end - - -# @@PLEAC@@_10.5 -# In Ruby, every value is a reference on an object, thus there is -# no such problem -array_diff(array1, array2) - -def add_vecpair(a1, a2) - results = [] - a1.each_index { |i| results << (a1[i] + a2[i]) } - results -end -a = [1, 2] -b = [5, 8] -c = add_vecpair(a, b) -p c - -# Add this to the beginning of the function to check if we were -# given two arrays -a1.type == Array && a2.type == Array or - raise "usage: add_vecpair array1 array2 (was used with: #{a1.type} #{a2.type})" - - -# @@PLEAC@@_10.6 -# There is no return context in Ruby - - -# @@PLEAC@@_10.7 -# Like in Perl, we need to fake with a hash, but it's dirty :-( -def thefunc(param_args) - args = { 'INCREMENT' => '10s', 'FINISH' => '0', 'START' => 0 } - args.update(param_args) - if (args['INCREMENT'] =~ /m$/ ) - # ..... - end -end - -thefunc({ 'INCREMENT' => '20s', 'START' => '+5m', 'FINISH' => '+30m' }) -thefunc({}) - - -# @@PLEAC@@_10.8 -# there is no "undef" direct equivalent but there is the slice equiv: -a, c = func.indexes(0, 2) - - -# @@PLEAC@@_10.9 -# Ruby has no such limitation: -def somefunc - ary = [] - hash = {} - # ... - return ary, hash -end -arr, dict = somefunc - -array_of_hashes = fn -h1, h2, h3 = fn - - -# @@PLEAC@@_10.10 -return -# or (equivalent) -return nil - - -# @@PLEAC@@_10.11 -# You can't prototype in Ruby regarding types :-( -# Though, you can force the number of arguments: -def func_with_no_arg; end -def func_with_no_arg(); end -def func_with_one_arg(a1); end -def func_with_two_args(a1, a2); end -def func_with_any_number_of_args(*args); end - - -# @@PLEAC@@_10.12 -raise "some message" # raise exception - -begin - val = func -rescue Exception => msg - $stderr.puts "func raised an exception: #{msg}" -end - -# In Ruby the rescue statement uses an exception class, every -# exception which is not matched is still continuing -begin - val = func -rescue FullMoonError - ... -end - - -# @@PLEAC@@_10.13 -# Saving Global Values -# Of course we can just save the value and restore it later: -def print_age - puts "Age is #{$age}" -end - -$age = 18 # global variable -print_age() -if condition - safeage = $age - $age = 23 - print_age() - $age = safeage -end - -# We can also use a method that saves the global variable and -# restores it automatically when the block is left: - -def local(var) - eval("save = #{var.id2name}") - begin - result = yield - ensure - # we want to call this even if we got an exception - eval("#{var.id2name} = save") - end - result -end - -condition = true -$age = 18 -print_age() -if condition - local(:$age) { - $age = 23 - print_age() - } -end -print_age() - -# There is no need to use local() for filehandles or directory -# handles in ruby because filehandles are normal objects. - - -# @@PLEAC@@_10.14 -# In Ruby you may redefine a method [but not overload it :-(] -# just by defining again with the same name. -def foo; puts 'foo'; end -def foo; puts 'bar'; end -foo -#=> bar - -# You can also take a reference to an existing method before -# redefining a new one, using the `alias' keyword -def foo; puts 'foo'; end -alias foo_orig foo -def foo; puts 'bar'; end -foo_orig -foo -#=> foo -#=> bar - -# AFAIK, there is no direct way to create a new method whose name -# comes from a variable, so use "eval" -colors = %w(red blue green yellow orange purple violet) -colors.each { |c| - eval <<-EOS - def #{c}(*a) - "<FONT COLOR='#{c}'>" + a.to_s + "</FONT>" - end - EOS -} - - -# @@PLEAC@@_10.15 -def method_missing(name, *args) - "<FONT COLOR='#{name}'>" + args.join(' ') + "</FONT>" -end -puts chartreuse("stuff") - - -# @@PLEAC@@_10.16 -def outer(arg) - x = arg + 35 - inner = proc { x * 19 } - x + inner.call() -end - - -# @@PLEAC@@_10.17 -#!/usr/bin/ruby -w -# mailsort - sort mbox by different criteria -require 'English' -require 'Date' - -# Objects of class Mail represent a single mail. -class Mail - attr_accessor :no - attr_accessor :subject - attr_accessor :fulltext - attr_accessor :date - - def initialize - @fulltext = "" - @subject = "" - end - - def append(para) - @fulltext << para - end - - # this is called if you call puts(mail) - def to_s - @fulltext - end -end - -# represents a list of mails. -class Mailbox < Array - - Subjectpattern = Regexp.new('Subject:\s*(?:Re:\s*)*(.*)\n') - Datepattern = Regexp.new('Date:\s*(.*)\n') - - # reads mails from open file and stores them - def read(file) - $INPUT_RECORD_SEPARATOR = '' # paragraph reads - msgno = -1 - file.each { |para| - if para =~ /^From/ - mail = Mail.new - mail.no = (msgno += 1) - md = Subjectpattern.match(para) - if md - mail.subject = md[1] - end - md = Datepattern.match(para) - if md - mail.date = DateTime.parse(md[1]) - else - mail.date = DateTime.now - end - self.push(mail) - end - mail.append(para) if mail - } - end - - def sort_by_subject_and_no - self.sort_by { |m| - [m.subject, m.no] - } - end - - # sorts by a list of attributs of mail, given as symbols - def sort_by_attributs(*attrs) - # you can sort an Enumerable by an array of - # values, they would be compared - # from ary[0] to ary[n]t, say: - # ['b',1] > ['a',10] > ['a',9] - self.sort_by { |elem| - attrs.map { |attr| - elem.send(attr) - } - } - end - -end - -mailbox = Mailbox.new -mailbox.read(ARGF) - -# print only subjects sorted by subject and number -for m in mailbox.sort_by_subject_and_no - puts(m.subject) -end - -# print complete mails sorted by date, then subject, then number -for m in mailbox.sort_by_attributs(:date, :subject) - puts(m) -end - - -# @@PLEAC@@_11.7 -def mkcounter(count) - start = count - bundle = { - "NEXT" => proc { count += 1 }, - "PREV" => proc { count -= 1 }, - "RESET" => proc { count = start } - } - bundle["LAST"] = bundle["PREV"] - return bundle -end - -c1 = mkcounter(20) -c2 = mkcounter(77) - -puts "next c1: #{c1["NEXT"].call}" # 21 -puts "next c2: #{c2["NEXT"].call}" # 78 -puts "next c1: #{c1["NEXT"].call}" # 22 -puts "last c1: #{c1["PREV"].call}" # 21 -puts "last c1: #{c1["LAST"].call}" # 20 -puts "old c2: #{c2["RESET"].call}" # 77 - - -# @@PLEAC@@_11.15 -class Binary_tree - def initialize(val) - @value = val - @left = nil - @right = nil - end - - # insert given value into proper point of - # provided tree. If no tree provided, - # use implicit pass by reference aspect of @_ - # to fill one in for our caller. - def insert(val) - if val < @value then - if @left then - @left.insert(val) - else - @left = Binary_tree.new(val) - end - elsif val > @value then - if @right then - @right.insert(val) - else - @right = Binary_tree.new(val) - end - else - puts "double" - # do nothing, no double values - end - end - - # recurse on left child, - # then show current value, - # then recurse on right child. - def in_order - @left.in_order if @left - print @value, " " - @right.in_order if @right - end - - # show current value, - # then recurse on left child, - # then recurse on right child. - def pre_order - print @value, " " - @left.pre_order if @left - @right.pre_order if @right - end - - # recurse on left child, - # then recurse on right child, - # then show current value. - def post_order - @left.post_order if @left - @right.post_order if @right - print @value, " " - end - - # find out whether provided value is in the tree. - # if so, return the node at which the value was found. - # cut down search time by only looking in the correct - # branch, based on current value. - def search(val) - if val == @value then - return self - elsif val < @value then - return @left.search(val) if @left - return nil - else - return @right.search(val) if @right - return nil - end - end -end - -# first generate 20 random inserts -test = Binary_tree.new(0) -for a in 0..20 - test.insert(rand(1000)) -end - -# now dump out the tree all three ways -print "Pre order: "; test.pre_order; puts "" -print "In order: "; test.in_order; puts "" -print "Post order: "; test.post_order; puts "" - -print "search?" -while gets - print test.search($_.to_i) - print "\nsearch?" -end - - -# @@PLEAC@@_12.0 -# class and module names need to have the first letter capitalized -module Alpha - NAME = 'first' -end -module Omega - NAME = 'last' -end -puts "Alpha is #{Alpha::NAME}, Omega is #{Omega::NAME}" - -# ruby doesn't differentiate beteen compile-time and run-time -require 'getoptlong.rb' -require 'getoptlong' # assumes the .rb -require 'cards/poker.rb' -require 'cards/poker' # assumes the .rb -load 'cards/poker' # require only loads the file once - -module Cards - module Poker - @card_deck = Array.new # or @card_deck = [] - def shuffle - end - end -end - - -# @@PLEAC@@_12.1 -# a module exports all of its functions -module Your_Module - def self.function - # this would be called as Your_Module.function - end - - def Your_Module.another - # this is the same as above, but more specific - end -end - -# @@PLEAC@@_12.2 -begin - require 'nonexistent' -rescue LoadError - puts "Couldn't load #{$!}" # $! contains the last error string -end - -# @@PLEAC@@_12.4 -# module variables are private unless access functions are defined -module Alpha - @aa = 10 - @bb = 11 - - def self.put_aa - puts @aa - end - - def self.bb=(val) - @bb = val - end -end - -Alpha.bb = 12 -# Alpha.aa = 10 # error, no aa=method - - -# @@PLEAC@@_12.5 -# caller provides a backtrace of the call stack -module MyModule - def find_caller - caller - end - - def find_caller2(i) - caller(i) # an argument limits the size of the stack returned - end -end - - -# @@PLEAC@@_12.6 -BEGIN { - $logfile = '/tmp/mylog' unless defined? $logfile - $LF = File.open($logfile, 'a') -} - -module Logger - def self.logmsg(msg) - $LF.puts msg - end - - logmsg('startup') -end - -END { - Logger::logmsg('shutdown') - $LF.close -} - - -# @@PLEAC@@_12.7 -#----------------------------- -# results may be different on your system -# % ruby -e "$LOAD_PATH.each_index { |i| printf("%d %s\n", i, $LOAD_PATH[i] } -#0 /usr/local/lib/site_ruby/1.6 -#1 /usr/local/lib/site_ruby/1.6/i386-linux -#2 /usr/local/lib/site_ruby/ -#3 /usr/lib/ruby/1.6 -#4 /usr/lib/ruby/1.6/i136-linux -#5 . -#----------------------------- -# syntax for sh, bash, ksh, or zsh -#$ export RUBYLIB=$HOME/rubylib - -# syntax for csh or tcsh -# % setenv RUBYLIB ~/rubylib -#----------------------------- -$LOAD_PATH.unshift "/projects/spectre/lib"; - - -# @@PLEAC@@_12.8 -# equivalents in ruby are mkmf, SWIG, or Ruby/DL depending on usage - - -# @@PLEAC@@_12.9 -# no equivalent in ruby - - -# @@PLEAC@@_12.10 -# no equivalent in ruby - - -# @@PLEAC@@_12.11 -module FineTime - def self.time - # to be defined later - end -end - - -module FineTime - def self.time - "its a fine time" - end -end - -puts FineTime.time #=> "its a fine time" - - -# @@PLEAC@@_12.12 -def even_only(n) - raise "#{n} is not even" if (n & 1) != 0 # one way to test - # ... -end -def even_only(n) - $stderr.puts "#{n} is not even" if (n & 1) != 0 - # ... -end - - -# @@PLEAC@@_12.17 -# The library archive for ruby is called Ruby Application archive, -# or shorter RAA, and can be found at http://raa.ruby-lang.org. -# A typical library is installed like this: -# % gunzip some-module-4.54.tar.gz -# % tar xf some-module-4.54.tar -# % cd some-module-4.54.tar -# % ruby install.rb config -# % ruby install.rb setup -# get superuser previleges here if needed for next step -# % ruby install.rb install - -# Some modules use a different process, -# you should find details in the documentation -# Here is an example of such a different process -# % ruby extconf.rb -# % make -# % make install - -# If you want the module installed in your own directory: -# For ruby version specific libraries -# % ruby install.rb config --site-ruby=~/lib -# For version independent libraries -# % ruby install.rb config --site-ruby-common=~/lib - -# Information about possible options for config -# % ruby install.rb --help - -# If you have your own complete distribution -# % ruby install.rb --prefix=path=~/ruby-private - - -# @@PLEAC@@_13.0 -# Classes and objects in Ruby are rather straigthforward -class Person - # Class variables (also called static attributes) are prefixed by @@ - @@person_counter=0 - - # object constructor - def initialize(age, name, alive = true) # Default arg like in C++ - @age, @name, @alive = age, name, alive # Object attributes are prefixed by '@' - @@person_counter += 1 - # There is no '++' operator in Ruby. The '++'/'--' operators are in fact - # hidden assignments which affect variables, not objects. You cannot accomplish - # assignment via method. Since everything in Ruby is object, '++' and '--' - # contradict Ruby OO ideology. Instead '-=' and '+=' are used. - end - - attr_accessor :name, :age # This creates setter and getter methods for @name - # and @age. See 13.3 for detailes. - - # methods modifying the receiver object usually have the '!' suffix - def die! - @alive = false - puts "#{@name} has died at the age of #{@age}." - @alive - end - - def kill(anotherPerson) - print @name, ' is killing ', anotherPerson.name, ".\n" - anotherPerson.die! - end - - # methods used as queries - # usually have the '?' suffix - def alive? - @alive && true - end - - def year_of_birth - Time.now.year - @age - end - - # Class method (also called static method) - def Person.number_of_people - @@person_counter - end -end - -# Using the class: -# Create objects of class Person -lecter = Person.new(47, 'Hannibal') -starling = Person.new(29, 'Clarice', true) -pazzi = Person.new(40, 'Rinaldo', true) - -# Calling a class method -print "There are ", Person.number_of_people, " Person objects\n" - -print pazzi.name, ' is ', (pazzi.alive?) ? 'alive' : 'dead', ".\n" -lecter.kill(pazzi) -print pazzi.name, ' is ', (pazzi.alive?) ? 'alive' : 'dead', ".\n" - -print starling.name , ' was born in ', starling.year_of_birth, "\n" - - -# @@PLEAC@@_13.1 -# If you don't need any initialisation in the constructor, -# you don't need to write a constructor. -class MyClass -end - -class MyClass - def initialize - @start = Time.new - @age = 0 - end -end - -class MyClass - def initialize(inithash) - @start = Time.new - @age = 0 - for key, value in inithash - instance_variable_set("@#{key}", value) - end - end -end - -# @@PLEAC@@_13.2 -# Objects are destroyed by the garbage collector. -# The time of destroying is not predictable. -# The ruby garbage collector can handle circular references, -# so there is no need to write destructor for that. - -# There is no direct support for destructor. -# You can call a custom function, or more specific a proc object, when the -# garbage collector is about to destruct the object, but it is unpredictable -# when this occurs. -# Also if such a finalizer object has a reference to the orignal object, -# this may prevent the original object to get garbage collected. -# Because of this problem the finalize method below is -# a class method and not a instance method. -# So if you need to free resources for an object, like -# closing a socket or kill a spawned subprocess, -# you should do it explicitly. - -class MyClass - def initialize - ObjectSpace.define_finalizer(self, - self.class.method(:finalize).to_proc) - end - def MyClass.finalize(id) - puts "Object #{id} dying at #{Time.new}" - end -end - -# test code -3.times { - MyClass.new -} -ObjectSpace.garbage_collect - - -# @@PLEAC@@_13.3 -# You can write getter and setter methods in a natural way: -class Person - def name - @name - end - def name=(name) - @name = name - end -end - -# But there is a better and shorter way -class Person - attr_reader :age - attr_writer :name - # attr_reader and attr_writer are actually methods in class Class - # which set getter and setter methods for you. -end - -# There is also attr_accessor to create both setters and getters -class Person - attr_accessor :age, :name -end - - -# @@PLEAC@@_13.4 -class Person - # Class variables (also called static attributes) are prefixed by @@ - @@person_counter = 0 - - def Person.population - @@person_counter - end - def initialize - @@person_counter += 1 - ObjectSpace.define_finalizer(self, - self.class.method(:finalize).to_proc) - end - def Person.finalize(id) - @@person_counter -= 1 - end -end -people = [] -10.times { - people.push(Person.new) -} -printf("There are %d people alive", Person.population) - - -FixedArray.class_max_bounds = 100 -alpha = FixedArray.new -puts "Bound on alpha is #{alpha.max_bounds}" - -beta = FixedArray.new -beta.max_bounds = 50 # calls the instance method -beta.class.class_max_bounds = 50 # alternative, calls the class method -puts "Bound on alpha is #{alpha.max_bounds}" - -class FixedArray - @@bounds = 7 - - def max_bounds - @@max_bounds - end - # instance method, which sets the class variable - def max_bounds=(value) - @@max_bounds = value - end - # class method. This can only be called on a class, - # but not on the instances - def FixedArray.class_max_bounds=(value) - @@max_bounds = value - end -end - - -# @@PLEAC@@_13.5 -PersonStruct = Struct.new("Person", :name, :age, :peers) -# creates a class "Person::Struct", which is accessiable with the -# constant "PersonStruct" -p = PersonStruct.new -p = Struct::Person.new # alternative using the classname -p.name = "Jason Smythe" -p.age = 13 -p.peers = ["Wilbur", "Ralph", "Fred"] -p[:peers] = ["Wilbur", "Ralph", "Fred"] # alternative access using symbol -p["peers"] = ["Wilbur", "Ralph", "Fred"] # alternative access using name of field -p[2] = ["Wilbur", "Ralph", "Fred"] # alternative access using index of field -puts "At age #{p.age}, #{p.name}'s first friend is #{p.peers[0]}" - -# The fields of a struct have no special type, like other ruby variables -# you can put any objects in. Therefore the discussions how to specify -# the types of the fields do not apply to ruby. - -FamilyStruct = Struct.new("Family", :head, :address, :members) -folks = FamilyStruct.new -folks.head = PersonStruct.new -dad = folks.head -dad.name = "John" -dad.age = 34 - -# supply of own accessor method for the struct for error checking -class PersonStruct - def age=(value) - if !value.kind_of?(Integer) - raise(ArgumentError, "Age #{value} isn't an Integer") - elsif value > 150 - raise(ArgumentError, "Age #{value} is unreasonable") - end - @age = value - end -end - - -# @@PLEAC@@_13.6 -# The ruby Object class defines a dup and a clone method. -# The dup method is recommended for prototype object creation. -# The default implementation makes a shallow copy, -# but each class can override it, for example to make a deep copy. - -# If you want to call 'new' directly on the instances, -# you can create a instance method "new", which returns a new duplicate. -# This method is distinct from the class method new. -# -class A - def new - dup - end -end - -ob1 = A.new -# later on -ob2 = ob1.new - - -# @@PLEAC@@_13.7 -methname = 'flicker' -obj.send(methname, 10) # calls obj.flicker(10) - -# call three methods on the object, by name -['start', 'run', 'stop'].each do |method_string| - obj.send(method_string) -end - -# Another way is to create a Method object -method_obj = obj.method('flicker') -# And then call it -method_obj.call(10) - - -# @@PLEAC@@_13.8 -# All classes in Ruby inherit from class Object -# and thus all objects share methods defined in this class - -# the class of the object -puts any_object.type - -# Ruby classes are actually objects of class Class and they -# respond to methods defined in Object class as well - -# the superclass of this class -puts any_object.class.superclass - -# ask an object whether it is an instance of particular class -n = 4.7 -puts n.instance_of?(Float) # true -puts n.instance_of?(Numeric) # false - -# ask an object whether it is an instance of class, one of the -# superclasses of the object, or modules included in it -puts n.kind_of?(Float) # true (the class) -puts n.kind_of?(Numeric) # true (an ancestor class) -puts n.kind_of?(Comparable) # true (a mixin module) -puts n.kind_of?(String) # false - -# ask an object whether it can respond to a particular method -puts n.respond_to?('+') # true -puts n.respond_to?('length') # false - -# all methods an object can respond to -'just a string'.methods.each { |m| puts m } - - -# @@PLEAC@@_13.9 -# Actually any class in Ruby is inheritable -class Person - attr_accessor :age, :name - def initialize - @name - @age - end -end -#----------------------------- -dude = Person.new -dude.name = 'Jason' -dude.age = 23 -printf "%s is age %d.\n", dude.name, dude.age -#----------------------------- -# Inheriting from Person -class Employee < Person - attr_accessor :salary -end -#----------------------------- -empl = Employee.new -empl.name = 'Jason' -empl.age = 23 -empl.salary = 200 -printf "%s is age %d, the salary is %d.\n", empl.name, empl.age, empl.salary -#----------------------------- -# Any built-in class can be inherited the same way -class WeirdString < String - def initialize(obj) - super obj - end - def +(anotherObj) # + method in this class is overridden - # to return the sum of string lengths - self.length + anotherObj.length # 'self' can be omitted - end -end -#----------------------------- -a = WeirdString.new('hello') -b = WeirdString.new('bye') - -puts a + b # the overridden + -#=> 8 -puts a.length # method from the superclass, String -#=> 5 - - -# @@PLEAC@@_13.11 -# In ruby you can override the method_missing method -# to have a solution similar to perls AUTOLOAD. -class Person - - def initialize - @ok_fields = %w(name age peers parent) - end - - def valid_attribute?(name) - @ok_fields.include?(name) - end - - def method_missing(namesymbol, *params) - name = namesymbol.to_s - return if name =~ /^A-Z/ - if name.to_s[-1] == ('='[0]) # we have a setter - isSetter = true - name.sub!(/=$/, '') - end - if valid_attribute?(name) - if isSetter - instance_variable_set("@#{name}", *params) - else - instance_variable_get("@#{name}", *params) - end - else - # if no annestor is responsible, - # the Object class will throw a NoMethodError exception - super(namesymbol, *params) - end - end - - def new - kid = Person.new - kid.parent = self - kid - end - -end - -dad = Person.new -dad.name = "Jason" -dad.age = 23 -kid = dad.new -kid.name = "Rachel" -kid.age = 2 -puts "Kid's parent is #{kid.parent.name}" -puts dad -puts kid - -class Employee < Person - def initialize - super - @ok_fields.push("salary", "boss") - end - def ok_fields - @ok_fields - end -end - - -# @@PLEAC@@_13.13 -# The ruby garbage collector pretends to cope with circular structures. -# You can test it with this code: -class RingNode - attr_accessor :next - attr_accessor :prev - attr_reader :name - - def initialize(aName) - @name = aName - ObjectSpace.define_finalizer(self, - self.class.method(:finalize).to_proc) - end - - def RingNode.finalize(id) - puts "Node #{id} dying" - end - - def RingNode.show_all_objects - ObjectSpace.each_object {|id| - puts id.name if id.class == RingNode - } - end -end - -def create_test - a = RingNode.new("Node A") - b = RingNode.new("Node B") - c = RingNode.new("Node C") - a.next = b - b.next = c - c.next = a - a.prev = c - c.prev = b - b.prev = a - - a = nil - b = nil - c = nil -end - -create_test -RingNode.show_all_objects -ObjectSpace.garbage_collect -puts "After garbage collection" -RingNode.show_all_objects - - -# @@PLEAC@@_13.14 -class String - def <=>(other) - self.casecmp other - end -end - -# There is no way to directly overload the '""' (stringify) -# operator in Ruby. However, by convention, classes which -# can reasonably be converted to a String will define a -# 'to_s' method as in the TimeNumber class defined below. -# The 'puts' method will automatcally call an object's -# 'to_s' method as is demonstrated below. -# Furthermore, if a class defines a to_str method, an object of that -# class can be used most any place where the interpreter is looking -# for a String value. - -#--------------------------------------- -# NOTE: Ruby has a builtin Time class which would usually be used -# to manipulate time objects, the following is supplied for -# educational purposes to demonstrate operator overloading. -# -class TimeNumber - attr_accessor :hours,:minutes,:seconds - def initialize( hours, minutes, seconds) - @hours = hours - @minutes = minutes - @seconds = seconds - end - - def to_s - return sprintf( "%d:%02d:%02d", @hours, @minutes, @seconds) - end - - def to_str - to_s - end - - def +( other) - seconds = @seconds + other.seconds - minutes = @minutes + other.minutes - hours = @hours + other.hours - if seconds >= 60 - seconds %= 60 - minutes += 1 - end - if minutes >= 60 - minutes %= 60 - hours += 1 - end - return TimeNumber.new(hours, minutes, seconds) - end - - def -(other) - raise NotImplementedError - end - - def *(other) - raise NotImplementedError - end - - def /( other) - raise NotImplementedError - end -end - -t1 = TimeNumber.new(0, 58, 59) -sec = TimeNumber.new(0, 0, 1) -min = TimeNumber.new(0, 1, 0) -puts t1 + sec + min + min - -#----------------------------- -# StrNum class example: Ruby's builtin String class already has the -# capabilities outlined in StrNum Perl example, however the '*' operator -# on Ruby's String class acts differently: It creates a string which -# is the original string repeated N times. -# -# Using Ruby's String class as is in this example: -x = "Red"; y = "Black" -z = x+y -r = z*3 # r is "RedBlackRedBlackRedBlack" -puts "values are #{x}, #{y}, #{z}, and #{r}" -print "#{x} is ", x < y ? "LT" : "GE", " #{y}\n" -# prints: -# values are Red, Black, RedBlack, and RedBlackRedBlackRedBlack -# Red is GE Black - -#----------------------------- -class FixNum - REGEX = /(\.\d*)/ - DEFAULT_PLACES = 0 - attr_accessor :value, :places - def initialize(value, places = nil) - @value = value - if places - @places = places - else - m = REGEX.match(value.to_s) - if m - @places = m[0].length - 1 - else - @places = DEFAULT_PLACES - end - end - end - - def +(other) - FixNum.new(@value + other.value, max(@places, other.places)) - end - - def *(other) - FixNum.new(@value * other.value, max(@places, other.places)) - end - - def /(other) - puts "Divide: #{@value.to_f/other.value.to_f}" - result = FixNum.new(@value.to_f/other.value.to_f) - result.places = max(result.places,other.places) - result - end - - def to_s - sprintf("STR%s: %.*f", self.class.to_s , @places, @value) #. - end - - def to_str - to_s - end - - def to_i #convert to int - @value.to_i - end - - def to_f #convert to float` - @value.to_f - end - - private - def max(a,b) - a > b ? a : b - end -end - -def demo() - x = FixNum.new(40) - y = FixNum.new(12, 0) - - puts "sum of #{x} and #{y} is #{x+y}" - puts "product of #{x} and #{y} is #{x*y}" - - z = x/y - puts "#{z} has #{z.places} places" - unless z.places - z.places = 2 - end - - puts "div of #{x} by #{y} is #{z}" - puts "square of that is #{z*z}" -end - -if __FILE__ == $0 - demo() -end - - -# @@PLEAC@@_14.1 -# There are dbm, sdbm, gdbm modules -# and the bdb module for accessing the berkeley db -# sdbm seem to be available on the most systems, -# so we use it here -# -require "sdbm" -SDBM.open("filename", 0666) { |dbobj| - # raises exception if open error - - # the returned sdbm-dbobj has most of the methods of a hash - v = dbobj["key"] - dbobj["key"] = "newvalue" - if dbobj.has_key?("key") - # ... - end - dbobj.delete("key2") -} -# database is open only inside the block. - -# It is also possible to use a open .. close pair: -dbobj = SDBM.open("filename", 0666) -#.. do something with dbobj -dbobj.close - -#!/usr/bin/ruby -w -# userstats - generate statistics on who is logged in -# call with usernames as argument to display the totals -# for the given usernames, call with "ALL" to display all users - -require "sdbm" -filename = '/tmp/userstats.db' -SDBM.open(filename, 0666) { |dbobj| - if ARGV.length > 0 - if ARGV[0] == "ALL" - # ARGV is constant, so we need the variable userlist - userlist = dbobj.keys().sort() - else - userlist = ARGV - end - userlist.each { |user| - print "#{user}\t#{dbobj[user]}\n" - } - else - who = `who` - who.split("\n").each { |line| - md = /^(\S+)/.match(line) - raise "Bad line from who: #{line}" unless md - # sdbm stores only strings, so "+=" doesn't work, - # we need to convert them expicitly back to integer. - if dbobj.has_key?(md[0]) - dbobj[md[0]] = dbobj[md[0]].to_i + 1 - else - dbobj[md[0]] = "1" - end - } - end -} - - -# @@PLEAC@@_14.2 -# using open and clear -dbobj = SDBM.open("filename", 0666) -dbobj.clear() -dbobj.close() -# deleting file and recreating it -# the filenames depend on the flavor of dbm you use, -# for example sdbm has two files named filename.pag and filename.dir, -# so you need to delete both files -begin - File.delete("filename") - # raises Exception if not exist - dbobj = SDBM.open("filename", 0666) -rescue - # add error handling here -end - - -# @@PLEAC@@_14.3 -# sdbm2gdbm: converts sdbm database to a gdbm database -require "sdbm" -require "gdbm" - -unless ARGV.length == 2 - fail "usage: sdbm2gdbm infile outfile" -end -infile = ARGV[0] -outfile = ARGV[1] - -sdb = SDBM.open(infile) -gdb = GDBM.open(outfile, 0666) -sdb.each { |key, val| - gdb[key] = val -} -gdb.close -sdb.close - - -# @@PLEAC@@_14.4 -#!/usr/bin/ruby -w -# dbmmerge: merges two dbm databases -require "sdbm" - -unless ARGV.length == 3 - fail "usage: dbmmerge indb1 indb2 outdb" -end -infile1 = ARGV[0] -infile2 = ARGV[0] -outfile = ARGV[2] - -in1 = SDBM.open(infile1, nil) -in2 = SDBM.open(infile2, nil) -outdb = SDBM.open(outfile, 0666) - -[in1, in2].each { |indb| - indb.each { |key, val| - if outdb.has_key?(key) - # decide which value to set. - # set outdb[key] if necessary - else - outdb[key] = val - end - } -} -in1.close -in2.close -outdb.close - - -# @@PLEAC@@_14.7 -# we write a tie method that extends the Array class. -# It reads the file into the memory, executes the code block -# in which you can manipulate the array as needed, and writes -# the array back to the file after the end of the block execution -class Array - def tie(filename, flags) - File.open(filename, flags) { |f| - f.each_line { |line| - self.push(line.chomp) - } - yield - f.rewind - each { |line| - if line - f.puts(line) - else - f.puts "" - end - } - } - end -end - -array = Array.new -array.tie("/tmp/textfile.txt", File::RDWR|File::CREAT) { - array[4] = "a new line 4" -} - -# The tied array can be manipulated like a normal array, -# so there is no need for a special API, and the recno_demo program -# to demonstrate is API is useless - - -# tied array demo: show how to use array with a tied file -filename = "db_file.txt" -lines = Array.new -File.unlink(filename) if File.exists?(filename) -lines.tie(filename, File::RDWR | File::CREAT) { - # first create a textfile to play with - lines[0] = "zero" - lines[1] = "one" - lines[2] = "two" - lines[3] = "three" - lines[4] = "four" - - # print the records in order. - # Opposed to perl, the tied array behaves exactly as a normal array - puts "\nOriginal" - for i in 0..(lines.length-1) - puts "#{i}: #{lines[i]}" - end - - #use push and pop - a = lines.pop - lines.push("last") - puts("The last line was [#{a}]") - - #use shift and unshift - a = lines.shift - lines.unshift("first") - puts("The first line was [#{a}]") - - # add record after record 2 - i = 2 - lines.insert(i + 1, "Newbie") - - # add record before record one - i = 1 - lines.insert(i, "New One") - - # delete record 3 - lines.delete_at(3) - - #now print the records in reverse order - puts "\nReverse" - (lines.length - 1).downto(0){ |i| - puts "#{i}: #{lines[i]}" - } - -} - - -# @@PLEAC@@_14.8 -# example to store complex data in a database -# uses marshall from the standard library -require "sdbm" -db = SDBM.open("pleac14-8-database", 0666) - -# convert the Objects into strings and back by using the Marshal module. -# Most normal objects can be converted out of the box, -# but not special things like procedure objects, -# IO instance variables, singleton objects - -db["Tom Christiansen"] = Marshal.dump(["book author", "tchrist@perl.com"]) -db["Tom Boutell"] = Marshal.dump(["shareware author", -"boutell@boutell.com"]) - -name1 = "Tom Christiansen" -name2 = "Tom Boutell" - -tom1 = Marshal.load(db[name1]) -tom2 = Marshal.load(db[name2]) - -puts "Two Toming: #{tom1} #{tom2}" - -if tom1[0] == tom2[0] && tom1[1] == tom2[1] - puts "You're having runtime fun with one Tom made two." -else - puts "No two Toms are ever alike" -end - -# To change parts of an entry, get the whole entry, change the parts, -# and save the whole entry back -entry = Marshal.load(db["Tom Boutell"]) -entry[0] = "Poet Programmer" -db["Tom Boutell"] = Marshal.dump(entry) -db.close - - -# @@PLEAC@@_14.9 -# example to make data persistent -# uses Marshal from the standard lib -# Stores the data in a simple file, -# see 14.8 on how to store it in a dbm file - -# The BEGIN block is executed before the rest of the script -# we use global variables here because local variables -# will go out of scope and are not accessible from the main script - -BEGIN { - $persistent_store = "persitence.dat" - begin - File.open($persistent_store) do |f| - $stringvariable1 = Marshal.load(f) - $arrayvariable2 = Marshal.load(f) - end - rescue - puts "Can not open #{$persistent_store}" - # Initialisation if this script runs the first time - $stringvariable1 = "" - $arrayvariable2 = [] - end -} - -END { - File.open($persistent_store, "w+") do |f| - Marshal.dump($stringvariable1, f) - Marshal.dump($arrayvariable2, f) - end -} - -# simple test program -puts $stringvariable1 -puts $arrayvariable2 -$stringvariable1 = "Hello World" -$arrayvariable2.push(5) -puts $stringvariable1 -puts $arrayvariable2 - - -# @@PLEAC@@_14.10 -#!/usr/bin/ruby -w -# Ruby has a dbi module with an architecture similar -# to the Perl dbi module: the dbi module provides an unified -# interface and uses specialized drivers for each dbms vendor -# -begin - DBI.connect("DBI:driver:driverspecific", "username", "auth") { - |dbh| - - dbh.do(SQL1) - - dbh.prepare(SQL2){ |sth| - sth.execute - sth.fetch {|row| - # ... - } - } # end of block finishes the statement handle - } # end of block closes the database connection -rescue DBI::DatabaseError => e - puts "dbi error occurred" - puts "Error code: #{e.err}" - puts "Error message: #{e.errstr}" -end - -#!/usr/bin/ruby -w -# dbusers - example for mysql which creates a table, -# fills it with values, retrieves the values back, -# and finally destroys the table. - -require "dbi" - -# replacement for the User::pwnt module -def getpwent - result = [] - File.open("/etc/passwd") {|file| - file.each_line {|line| - next if line.match(/^#/) - cols = line.split(":") - result.push([cols[2], cols[0]]) - } - } - result -end - -begin - DBI.connect("DBI:Mysql:pleacdatabase", "pleac", "pleacpassword") { - |conn| - - conn.do("CREATE TABLE users (uid INT, login CHAR(8))") - - users = getpwent - - conn.prepare("INSERT INTO users VALUES (?,?)") {|sth| - users.each {|entry| - sth.execute(entry[0], entry[1]) - } - } - - conn.execute("SELECT uid, login FROM users WHERE uid < 50") {|sth| - sth.fetch {|row| - puts row.collect {|col| - if col.nil? - "(null)" - else - col - end - }.join(", ") - } - } - - conn.do("DROP TABLE users") - } -rescue DBI::DatabaseError => e - puts "dbi error occurred" - puts "Error code: #{e.err}" - puts "Error message: #{e.errstr}" -end - - -# @@PLEAC@@_15.1 -# This test program demonstrates parsing program arguments. -# It uses the optparse library, which is included with ruby 1.8 -# It handles classic unix style and gnu style options -require 'optparse' - -@debugmode = false -@verbose = false - -ARGV.options do |opts| - opts.banner = "Usage: ruby #{$0} [OPTIONS] INPUTFILES" - - opts.on("-h", "--help", "show this message") { - puts opts - exit - } - # The OptionParser#on method is called with a specification of short - # options, of long options, a data type spezification and user help - # messages for this option. - # The method analyses the given parameter and decides what it is, - # so you can leave out the long option if you don't need it - opts.on("-v", "--[no-]verbose=[FLAG]", TrueClass, "run verbosly") { - |@verbose| # sets @verbose to true or false - } - opts.on("-D", "--DEBUG", TrueClass, "turns on debug mode" ){ - |@debugmode| # sets @debugmode to true - } - opts.on("-c", "--count=NUMBER", Integer, "how many times we do it" ){ - |@count| # sets @count to given integer - } - opts.on("-o", "--output=FILE", String, "file to write output to"){ - |@outputfile| # sets @outputfile to given string - } - opts.parse! -end - -# example to use the options in the main program -puts "Verbose is on" if @verbose -puts "Debugmode is on" if @debugmode -puts "Outfile is #{@outputfile}" if defined? @outputfile -puts "Count is #{@count}" if defined? @count -ARGV.each { |param| - puts "Got parameter #{param}" -} - - -# @@PLEAC@@_15.4 -buf = "\0" * 8 -$stdout.ioctl(0x5413, buf) -ws_row, ws_col, ws_xpixel, ws_ypixel = buf.unpack("S4") - -raise "You must have at least 20 characters" unless ws_col >= 20 -max = 0 -values = (1..5).collect { rand(20) } # generate an array[5] of rand values -for i in values - max = i if max < i -end -ratio = Float(ws_col-12)/max # chars per unit -for i in values - printf "%8.1f %s\n", i, "*" * (ratio*i) -end - -# gives, for example: -# 15.0 ******************************* -# 10.0 ********************* -# 5.0 ********** -# 14.0 ***************************** -# 18.0 ************************************** - - -# @@PLEAC@@_16.1 -output = `program args` # collect output into one multiline string -output = `program args`.split # collect output into array, one line per -element - -readme = IO.popen("ls") -output = "" -while readme.gets do - output += $_ -end -readme.close - -`fsck -y /dev/rsd1a` # BAD AND SCARY in Perl because it's managed by the shell - # I donna in Ruby ... - -# so the "clean and secure" version -readme, writeme = IO.pipe -pid = fork { - # child - $stdout = writeme - readme.close - exec('find', '..') -} -# parent -Process.waitpid(pid, 0) -writeme.close -while readme.gets do - # do something with $_ -end - - -# @@PLEAC@@_16.2 -status = system("xemacs #{myfile}") - -status = system("xemacs", myfile) - -system("cmd1 args | cmd2 | cmd3 >outfile") -system("cmd args <infile >outfile 2>errfile") - -# stop if the command fails -raise "$program exited funny: #{$?}" unless system("cmd", "args1", "args2") - -# get the value of the signal sent to the child -# even if it is a SIGINT or SIGQUIT -system(arglist) -raise "program killed by signal #{$?}" if ($? & 127) != 0 - -pid = fork { - trap("SIGINT", "IGNORE") - exec("sleep", "10") -} -trap ("SIGINT") { - puts "Tsk tsk, no process interruptus" -} -Process.waitpid(pid, 0) - -# Ruby doesn't permit to lie to the program called by a 'system'. -# (ie specify what return argv[0] in C, $0 in Perl/Ruby ...) -# A (dirty) way is to create a link (under Unix), run this link and -# erase it. Somebody has a best idea ? - - -# @@PLEAC@@_16.3 -exec("archive *.data") - -exec("archive", "accounting.data") - -exec("archive accounting.data") - - -# @@PLEAC@@_16.4 -# read the output of a program -IO.popen("ls") {|readme| - while readme.gets do - # ... - end -} -# or -readme = IO.popen("ls") -while readme.gets do - # ... -end -readme.close - -# "write" in a program -IO.popen("cmd args","w") {|pipe| - pipe.puts("data") - pipe.puts("foo") -} - -# close wait for the end of the process -read = IO.popen("sleep 10000") # child goes to sleep -read.close # and the parent goes to lala land - -writeme = IO.popen("cmd args", "w") -writeme.puts "hello" # program will get hello\n on STDIN -writeme.close # program will get EOF on STDIN - -# send in a pager (eg less) all output -$stdout = IO.popen("/usr/bin/less","w") -print "huge string\n" * 10000 - - -# @@PLEAC@@_16.5 -#----------------------------- -def head(lines = 20) - pid = open("|-","w") - if pid == nil - return - else - while gets() do - pid.print - lines -= 1 - break if lines == 0 - end - end - exit -end - -head(100) -while gets() do - print -end -#----------------------------- -1: > Welcome to Linux, version 2.0.33 on a i686 - -2: > - -3: > "The software required `Windows 95 or better', - -4: > so I installed Linux." -#----------------------------- -> 1: Welcome to Linux, Kernel version 2.0.33 on a i686 - -> 2: - -> 3: "The software required `Windows 95 or better', - -> 4: so I installed Linux." -#----------------------------- -#!/usr/bin/ruby -# qnumcat - demo additive output filters - -def number() - pid = open("|-","w") - if pid == nil - return - else - while gets() do pid.printf("%d: %s", $., $_); end - end - exit -end - -def quote() - pid = open("|-","w") - if pid == nil - return - else - while gets() do pid.print "> #{$_}" end - end - exit -end - -number() -quote() - -while gets() do - print -end -$stdout.close -exit - - -# @@PLEAC@@_16.6 -ARGV.map! { |arg| - arg =~ /\.(gz|Z)$/ ? "|gzip -dc #{arg}" : arg -} -for file in ARGV - fh = open(file) - while fh.gets() do - # ....... - end -end -#----------------------------- -ARGV.map! { |arg| - arg =~ %r#^\w+://# ? "|GET #{arg}" : arg # -} -for file in ARGV - fh = open(file) - while fh.gets() do - # ....... - end -end -#----------------------------- -pwdinfo = (`domainname` =~ /^(\(none\))?$/) ? '/etc/passwd' : '|ypcat passwd'; -pwd = open(pwdinfo); -#----------------------------- -puts "File, please? "; -file = gets().chomp(); -fh = open(file); - - -# @@PLEAC@@_16.7 -output = `cmd 2>&1` # with backticks -# or -ph = open("|cmd 2>&1") # with an open pipe -while ph.gets() { } # plus a read -#----------------------------- -output = `cmd 2>/dev/null` # with backticks -# or -ph = open("|cmd 2>/dev/null") # with an open pipe -while ph.gets() { } # plus a read -#----------------------------- -output = `cmd 2>&1 1>/dev/null` # with backticks -# or -ph = open("|cmd 2>&1 1>/dev/null") # with an open pipe -while ph.gets() { } # plus a read -#----------------------------- -output = `cmd 3>&1 1>&2 2>&3 3>&-` # with backticks -# or -ph = open("|cmd 3>&1 1>&2 2>&3 3>&-") # with an open pipe -while ph.gets() { } # plus a read -#----------------------------- -system("program args 1>/tmp/program.stdout 2>/tmp/program.stderr") -#----------------------------- -output = `cmd 3>&1 1>&2 2>&3 3>&-` -#----------------------------- -fd3 = fd1 -fd1 = fd2 -fd2 = fd3 -fd3 = undef -#----------------------------- -system("prog args 1>tmpfile 2>&1") -system("prog args 2>&1 1>tmpfile") -#----------------------------- -# system ("prog args 1>tmpfile 2>&1") -fd1 = "tmpfile" # change stdout destination first -fd2 = fd1 # now point stderr there, too -#----------------------------- -# system("prog args 2>&1 1>tmpfile") -fd2 = fd1 # stderr same destination as stdout -fd1 = "tmpfile" # but change stdout destination -#----------------------------- -# It is often better not to rely on the shell, -# because of portability, possible security problems -# and bigger resource usage. So, it is often better to use the open3 library. -# See below for an example. -# opening stdin, stdout, stderr -require "open3" -stdin, stdout, stderr = Open3.popen('cmd') - - -# @@PLEAC@@_16.8 -#----------------------------- -# Contrary to perl, we don't need to use a module in Ruby -fh = Kernel.open("|" + program, "w+") -fh.puts "here's your input\n" -output = fh.gets() -fh.close() -#----------------------------- -Kernel.open("|program"),"w+") # RIGHT ! -#----------------------------- -# Ruby has already object methods for I/O handles -#----------------------------- -begin - fh = Kernel.open("|" + program_and_options, "w+") -rescue - if ($@ ~= /^open/) - $stderr.puts "open failed : #{$!} \n #{$@} \n" - break - end - raise # reraise unforseen exception -end - - -# @@PLEAC@@_16.13 -#% kill -l -#HUP INT QUIT ILL TRAP ABRT BUS FPE KILL USR1 SEGV USR2 PIPE -#ALRM TERM CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM -#PROF WINCH POLL PWR -#----------------------------- -#% ruby -e 'puts Signal.list.keys.join(" ")' -#PWR USR1 BUS USR2 TERM SEGV KILL POLL STOP SYS TRAP IOT HUP INT # -#WINCH XCPU TTIN CLD TSTP FPE IO TTOU PROF CHLD CONT PIPE ABRT -#VTALRM QUIT ILL XFSZ URG ALRM -#----------------------------- -# After that, the perl script create an hash equivalent to Signal.list, -# and an array. The array can be obtained by : -signame = [] -Signal.list.each { |name, i| signame[i] = name } - - -# @@PLEAC@@_16.14 -Process.kill(9, pid) # send $pid a signal 9 -Process.kill(-1, Process.getpgrp()) # send whole job a signal 1 -Process.kill("USR1", $$) # send myself a SIGUSR1 -Process.kill("HUP", pid1, pid2, pid3) # send a SIGHUP to processes in @pids -#----------------------------- -begin - Process.kill(0, minion) - puts "#{minion} is alive!" -rescue Errno::EPERM # changed uid - puts "#{minion} has escaped my control!"; -rescue Errno::ESRCH - puts "#{minion} is deceased."; # or zombied -rescue - puts "Odd; I couldn't check the status of #{minion} : #{$!}" -end - - -# @@PLEAC@@_16.15 -Kernel.trap("QUIT", got_sig_quit) # got_sig_quit = Proc.new { puts "Quit\n" } -trap("PIPE", "got_sig_quit") # def got_sig_pipe ... -trap("INT") { ouch++ } # increment ouch for every SIGINT -#----------------------------- -trap("INT", "IGNORE") # ignore the signal INT -#----------------------------- -trap("STOP", "DEFAULT") # restore default STOP signal handling - - -# @@PLEAC@@_16.16 -# the signal handler -def ding - trap("INT", "ding") - puts "\aEnter your name!" -end - -# prompt for name, overriding SIGINT -def get_name - save = trap("INT", "ding") - - puts "Kindly Stranger, please enter your name: " - name = gets().chomp() - trap("INT", save) - name -end - - -# @@PLEAC@@_16.21 -# implemented thanks to http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/1760 -require 'timeout' - -# we'll do something vastly more useful than cookbook to demonstrate timeouts -begin - timeout(5) { - waitsec = rand(10) - puts "Let's see if a sleep of #{waitsec} seconds is longer than 5 seconds..." - system("sleep #{waitsec}") - } - puts "Timeout didn't occur" -rescue Timeout::Error - puts "Timed out!" -end - - -# @@PLEAC@@_17.1 -# A basic TCP client connection -require 'socket' -begin - t = TCPSocket.new('www.ruby-lang.org', 'www') -rescue - puts "error: #{$!}" -else - # ... do something with the socket - t.print "GET / HTTP/1.0\n\n" - answer = t.gets(nil) - # and terminate the connection when we're done - t.close -end - -# Using the evil low level socket API -require 'socket' -# create a socket -s = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) -# build the address of the remote machine -sockaddr_server = [Socket::AF_INET, 80, - Socket.gethostbyname('www.ruby-lang.org')[3], - 0, 0].pack("snA4NN") -# connect -begin - s.connect(sockaddr_server) -rescue - puts "error: #{$!}" -else - # ... do something with the socket - s.print "GET / HTTP/1.0\n\n" - # and terminate the connection when we're done - s.close -end - -# TCP connection with management of error (DNS) -require 'socket' -begin - client = TCPSocket.new('does not exists', 'www') -rescue - puts "error: #{$!}" -end - -# TCP connection with a time out -require 'socket' -require 'timeout' -begin - timeout(1) do #the server has one second to answer - client = TCPSocket.new('www.host.com', 'www') - end -rescue - puts "error: #{$!}" -end - - -# @@PLEAC@@_17.12 -require 'socket' - -class Preforker - attr_reader (:child_count) - - def initialize(prefork, max_clients_per_child, port, client_handler) - @prefork = prefork - @max_clients_per_child = max_clients_per_child - @port = port - @child_count = 0 - - @reaper = proc { - trap('CHLD', @reaper) - pid = Process.wait - @child_count -= 1 - } - - @huntsman = proc { - trap('CHLD', 'IGNORE') - trap('INT', 'IGNORE') - Process.kill('INT', 0) - exit - } - - @client_handler=client_handler - end - - def child_handler - trap('INT', 'EXIT') - @client_handler.setUp - # wish: sigprocmask UNblock SIGINT - @max_clients_per_child.times { - client = @server.accept or break - @client_handler.handle_request(client) - client.close - } - @client_handler.tearDown - end - - def make_new_child - # wish: sigprocmask block SIGINT - @child_count += 1 - pid = fork do - child_handler - end - # wish: sigprocmask UNblock SIGINT - end - - def run - @server = TCPserver.open(@port) - trap('CHLD', @reaper) - trap('INT', @huntsman) - loop { - (@prefork - @child_count).times { |i| - make_new_child - } - sleep .1 - } - end -end - -#----------------------------- -#!/usr/bin/ruby - -require 'Preforker' - -class ClientHandler - def setUp - end - - def tearDown - end - - def handle_request(client) - # do stuff - end -end - -server = Preforker.new(1, 100, 3102, ClientHandler.new) -server.run - - -# @@PLEAC@@_18.2 -require 'net/ftp' - -begin - ftp = Net::FTP::new("ftp.host.com") - ftp.login(username,password) - ftp.chdir(directory) - ftp.get(filename) - ftp.put(filename) -rescue Net::FTPError - $stderr.print "FTP failed: " + $! -ensure - ftp.close() if ftp -end - -# A better solution for a local use could be : -Net::FTP::new("ftp.host.com") do |ftp| - ftp.login(username,password) - ftp.chdir(directory) - ftp.get(filename) - ftp.put(filename) -end - -# If you have only one file to get, there is a simple solution : -require 'open-uri' -open("ftp://www.ruby-lang.org/path/filename") do |fh| - # read from filehandle fh -end -#-------------------------------------------- -# to wait a defined time for the connection, -# use the timeout module -require 'timeout' -begin - timeout(30){ - ftp = Net::FTP::new("ftp.host.com") - ftp.debug_mode = true - } -rescue Net::FTPError - $stderr.puts "Couldn't connect." -rescue Timeout::Error - $stderr.puts "Timeout while connecting to server." -end - -begin - ftp.login() -rescue Net::FTPError - $stderr.print "Couldn't authentificate.\n" -end - -begin - ftp.login(username) -rescue Net::FTPError - $stderr.print "Still couldn't authenticate.\n" -end - -begin - ftp.login(username, password) -rescue Net::FTPError - $stderr.print "Couldn't authenticate, even with explicit - username and password.\n" -end - -begin - ftp.login(username, password, account) -rescue Net::FTPError - $stderr.print "No dice. It hates me.\n" -end -#----------------------------- -ftp.put(localfile, remotefile) -#----------------------------- -# Sending data from STDIN is not directly supported -# by the ftp library module. A possible way to do it is to use the -# storlines method directly to send raw commands to the ftp server. -#----------------------------- -ftp.get(remotefile, localfile) -#----------------------------- -ftp.get(remotefile) { |data| puts data } -#----------------------------- -ftp.chdir("/pub/ruby") -print "I'm in the directory ", ftp.pwd(), "\n" -#----------------------------- -ftp.mkdir("/pub/ruby/new_dir") -#----------------------------- -lines = ftp.ls("/pub/ruby/") -# => ["drwxr-xr-x 2 matz users 4096 July 17 1998 1.0", ... ] - -latest = ftp.dir("/pub/ruby/*.tgz").sort.last - -ftp.nlst("/pub/ruby") -# => ["/pub/ruby/1.0", ... ] -#----------------------------- -ftp.quit() - - -# @@PLEAC@@_18.6 -require 'net/telnet' -t = Net::Telnet::new( "Timeout" => 10, - "Prompt" => /%/, - "Host" => host ) -t.login(username, password) -files = t.cmd("ls") -t.print("top") -process_string = t.waitfor(/\d+ processes/) -t.close -#----------------------------- -/[$%#>] \z/n -#----------------------------- -# In case of an error, the telnet module throws an exception. -# For control of the behavior in case of an error, -# you just need to catch the exceptions and do your custom -# error handling. -#----------------------------- -begin - telnet.login(username, password) -rescue TimeoutError - fail "Login failed !\n" -end -#----------------------------- -telnet.waitfor('/--more--/') -#----------------------------- -telnet.waitfor(String => 'greasy smoke', Timeout => 30) - - -# @@PLEAC@@_18.7 -require 'ping' - -puts "#{host} is alive.\n" if Ping.pingecho(host); -#----------------------------- -# the ping module only use TCP ping, not ICMP even if we are root -if Ping.pingecho("kingkong.com") - puts "The giant ape lives!\n"; -else - puts "All hail mighty Gamera, friend of children!\n"; -end - - -# @@PLEAC@@_19.1 -#!/usr/local/bin/ruby -w -# hiweb - load CGI class to decode information given by web server - -require 'cgi' - -cgi = CGI.new('html3') - -# get a parameter from a form -value = cgi.params['PARAM_NAME'][0] - -# output a document -cgi.out { - cgi.html { - cgi.head { cgi.title { "Howdy there!" } } + - cgi.body { cgi.p { "You typed: " + cgi.tt { - CGI.escapeHTML(value) } } } - } -} - -require 'cgi' -cgi = CGI.new -who = cgi.param["Name"][0] # first param in list -phone = cgi.param["Number"][0] -picks = cgi.param["Choices"] # complete list - -print cgi.header( 'type' => 'text/plain', - 'expires' => Time.now + (3 * 24 * 60 * 60) ) - - -# @@PLEAC@@_19.3 -#!/usr/local/bin/ruby -w -# webwhoami - show web user's id -require 'etc' -print "Content-Type: text/plain\n\n" -print "Running as " + Etc.getpwuid.name + "\n" - -# % ruby -wc cgi-script # just check syntax - -# % ruby -w cgi-script # params from stdin -# (offline mode: enter name=value pairs on standard input) -# name=joe -# number=10 -# ^D - -# % ruby -w cgi-script name=joe number=10 # run with mock form input -# % ruby -d cgi-script name=joe number=10 # ditto, under the debugger - -# POST method script in csh -# % (setenv HTTP_METHOD POST; ruby -w cgi-script name=joe number=10) -# POST method script in sh -# % HTTP_METHOD=POST perl -w cgi-script name=joe number=10 - - -# @@PLEAC@@_19.4 -# ruby has several security levels, the level "1" is similar to perls taint mode. -# It can be switched on by providing the -T command line parameter -# or by setting $SAFE to 1. Setting $SAFE to 2,3 or 4 restricts possible -# harmful operations further. - -#!/usr/bin/ruby -T -$SAFE = 1 -File.open(ARGV[0], "w") -# ruby warns with: -# taint1.rb:2:in `initialize': Insecure operation - initialize (SecurityError) - -$SAFE = 1 -file = ARGV[0] -unless /^([\w.-]+)$/.match(file) - raise "filename #{file} has invalid characters" -end -file = $1 -# In ruby, even the back reference from a regular expression stays tainted. -# you need to explicitly untaint the variable: -file.untaint -File.open(file, "w") - -# Race condition exists like in perl: -unless File.exists(filename) # Wrong because of race condition - File.open(filename, "w") -end - - - -# @@PLEAC@@_19.10 -preference_value = cgi.cookies["preference name"][0] - -packed_cookie = CGI::Cookie.new("name" => "preference name", - "value" => "whatever you'd like", - "expires" => Time.local(Time.now.year + 2, - Time.now.mon, Time.now.day, Time.now.hour, Time.now.min, Time.now.sec) ) - -cgi.header("cookie" => [packed_cookie]) - -#!/usr/local/bin/ruby -w -# ic_cookies - sample CGI script that uses a cookie -require 'cgi' - -cgi = CGI.new('html3') - -cookname = "favorite ice cream" -favorite = cgi.params["flavor"][0] -tasty = cgi.cookies[cookname][0] || 'mint' - -unless favorite - cgi.out { - cgi.html { - cgi.head { cgi.title { "Ice Cookies" } } + - cgi.body { - cgi.h1 { "Hello Ice Cream" } + - cgi.hr + - cgi.form { - cgi.p { "Please select a flavor: " + - cgi.text_field("flavor", tasty ) } - } + - cgi.hr - } - } - } -else - cookie = CGI::Cookie.new( "name" => cookname, - "value" => favorite, - "expires" => Time.local(Time.now.year + 2, -Time.now.mon, Time.now.day, Time.now.hour, Time.now.min, Time.now.sec) ) - cgi.out("cookie" => [cookie]) { - cgi.html { - cgi.head { cgi.title { "Ice Cookies" } } + - cgi.body { - cgi.h1 { "Hello Ice Cream" } + - cgi.p { "You chose as your favorite flavor `#{favorite}'." } - } - } - } -end - - -# @@PLEAC@@_20.9 -def templatefile(filename, fillings) - aFile = File.new(filename, "r") - text = aFile.read() - aFile.close() - pattern = Regexp.new('%%(.*?)%%') - text.gsub!(pattern) { - fillings[$1] || "" - } - text -end - -fields = { - 'username' => whats_his_name, - 'count' => login_count, - 'total' => minutes_used -} -puts templatefile('simple.template', fields) - -# @@INCOMPLETE@@ -# An example using databases is missing - diff --git a/tests/examplefiles/pleac.in.rb b/tests/examplefiles/pleac.in.rb index 0f967b9b..d74944ad 100644 --- a/tests/examplefiles/pleac.in.rb +++ b/tests/examplefiles/pleac.in.rb @@ -2957,3412 +2957,3 @@ end ARGF.each { |l| puts l.downcase! } -#------------------ -#!/usr/bin/ruby -p -# just like perl's -p -$_.downcase! -# - -# I don't know who should I trust. -# perl's version splits on \w+ while python's on \w. - -chunks = 0 - -File.read(ARGV[0]).split.each do |word| - next if word =~ /^#/ - break if ["__DATA__", "__END__"].member? word - chunks += 1 -end - -print "Found ", chunks, " chunks\n" - - -# @@PLEAC@@_7.8 -old = File.open(old_file) -new = File.open(new_file, "w") -while old.gets do - # change $_, then... - new.print $_ -end -old.close -new.close -File.rename(old_file, "old.orig") -File.rename(new_file, old_file) - -while old.gets do - if $. == 20 then # we are at the 20th line - new.puts "Extra line 1" - new.puts "Extra line 2" - end - new.print $_ -end - -while old.gets do - next if 20..30 # skip the 20th line to the 30th - # Ruby (and Perl) permit to write if 20..30 - # instead of if (20 <= $.) and ($. <= 30) - new.print $_ -end - - -# @@PLEAC@@_7.9 -#% ruby -i.orig -pe 'FILTER COMMAND' file1 file2 file3 ... -# -#----------------------------- -##!/usr/bin/ruby -i.orig -p -# filter commands go here -#----------------------------- - -#% ruby -pi.orig -e 'gsub!(/DATE/){Time.now)' - -# effectively becomes: -ARGV << 'I' -oldfile = "" -while gets - if ARGF.filename != oldfile - newfile = ARGF.filename - File.rename(newfile, newfile + ".orig") - $stdout = File.open(newfile,'w') - oldfile = newfile - end - gsub!(/DATE/){Time.now} - print -end -$stdout = STDOUT -#----------------------------- -#% ruby -i.old -pe 'gsub!(%r{\bhisvar\b}, 'hervar')' *.[Cchy] - -#----------------------------- -# set up to iterate over the *.c files in the current directory, -# editing in place and saving the old file with a .orig extension -$-i = '.orig' # set up -i mode -ARGV.replace(Dir['*.[Cchy]']) -while gets - if $. == 1 - print "This line should appear at the top of each file\n" - end - gsub!(/\b(p)earl\b/i, '\1erl') # Correct typos, preserving case - print - ARGF.close if ARGF.eof -end - - -# @@PLEAC@@_7.10 -File.open('itest', 'r+') do |f| # open file for update - lines = f.readlines # read into array of lines - lines.each do |it| # modify lines - it.gsub!(/foo/, 'QQQ') - end - f.pos = 0 # back to start - f.print lines # write out modified lines - f.truncate(f.pos) # truncate to new length -end # file is automatically closed -#----------------------------- -File.open('itest', 'r+') do |f| - out = "" - f.each do |line| - out << line.gsub(/DATE/) {Time.now} - end - f.pos = 0 - f.print out - f.truncate(f.pos) -end - -# @@PLEAC@@_7.11 -File.open('infile', 'r+') do |f| - f.flock File::LOCK_EX - # update file -end -#----------------------------- -File::LOCK_SH # shared lock (for reading) -File::LOCK_EX # exclusive lock (for writing) -File::LOCK_NB # non-blocking request -File::LOCK_UN # free lock -#----------------------------- -unless f.flock File::LOCK_EX | File::LOCK_NB - warn "can't get immediate lock: blocking ..." - f.flock File::LOCK_EX -end -#----------------------------- -File.open('numfile', File::RDWR|File::CREAT) do |f| - f.flock(File::LOCK_EX) - num = f.gets.to_i || 0 - f.pos = 0 - f.truncate 0 - f.puts num + 1q -end - - -# @@PLEAC@@_7.12 -output_handle.sync = true -# Please note that like in Perl, $stderr is already unbuffered -#----------------------------- -#!/usr/bin/ruby -w -# seeme - demo stdio output buffering -$stdout.sync = ARGV.size > 0 -print "Now you don't see it..." -sleep 2 -puts "now you do" -#----------------------------- -$stderr.sync = true -afile.sync = false -#----------------------------- -# assume 'remote_con' is an interactive socket handle, -# but 'disk_file' is a handle to a regular file. -remote_con.sync = true # unbuffer for clarity -disk_file.sync = false # buffered for speed -#----------------------------- -require 'socket' -sock = TCPSocket.new('www.ruby-lang.org', 80) -sock.sync = true -sock.puts "GET /en/ HTTP/1.0 \n\n" -resp = sock.read -print "DOC IS: #{resp}\n" - - -# @@PLEAC@@_7.13 -#----------------------------- -# assumes fh1, fh2, fh2 are oen IO objects -nfound = select([$stdin, fh1, fh2, fh3], nil, nil, 0) -nfound[0].each do |file| - case file - when fh1 - # do something with fh1 - when fh2 - # do something with fh2 - when fh3 - # do something with fh3 - end -end -#----------------------------- -input_files = [] -# repeat next line for all in-files to poll -input_files << fh1 -if nfound = select(input_files, nil, nil, 0) - # input ready on files in nfound[0] -end - - -# @@PLEAC@@_8.0 -#----------------------------- -# datafile is a file or IO object -datafile.readlines.each { |line| - line.chomp! - size = line.length - puts size -} -#----------------------------- -datafile.readlines.each { |line| - puts line.chomp!.length -} -#----------------------------- -lines = datafile.readlines -#----------------------------- -whole_file = file.read -#----------------------------- -# ruby -040 -e 'word = gets; puts "First word is #{word}"' -#----------------------------- -# ruby -ne 'BEGIN { $/="%%\n" }; $_.chomp; puts $_ if( $_=~/Unix/i)' fortune.dat -#----------------------------- -handle.print "one", "two", "three" # "onetwothree" -puts "Baa baa black sheep." # sent to $stdout -#----------------------------- -buffer = handle.read(4096) -rv = buffer.length -#----------------------------- -handle.truncate(length) -open("/tmp#{$$}.pid", 'w') { |handle| handle.truncate(length) } -#----------------------------- -pos = datafile.pos # tell is an alias of pos -puts "I'm #{pos} bytes from the start of datafile" -#----------------------------- -logfile.seek(0, IO::SEEK_END) -datafile.seek(pos) # IO::SEEK_SET is the default -out.seek(-20, IO::SEEK_CUR) -#----------------------------- -written = datafile.syswrite(mystring) -raise RunTimeError unless written == mystring.length -block = infile.sysread(256) # no equivalent to perl offset parameter in sysread -puts "only read #{block.length} bytes" if 256 != block.length -#----------------------------- -pos = handle.sysseek(0, IO::SEEK_CUR) # don't change position - - -# @@PLEAC@@_8.1 -while (line = fh.gets) - line.chomp! - nextline = nil - line.gsub!(/\\$/) { |match| nextline = fh.gets; '' } - if (nextline != nil) - line += nextline - redo - end - # process full record in line here -end -#----------------------------- -# DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) \ -# $(TEXINFOS) $(INFOS) $(MANS) $(DATA) -# DEP_DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) \ -# $(TEXINFOS) $(INFO_DEPS) $(MANS) $(DATA) \ -# $(EXTRA_DIST) -#----------------------------- -line.gsub!(/\\\s*$/, '') { - # as before -} - - -# @@PLEAC@@_8.2 -#----------------------------- -count = `wc -l < #{filename}` -fail "wc failed: #{$?}" if $? != 0 -count.chomp! -#----------------------------- -count = 0 -File.open(file, 'r') { |fh| - count += 1 while fh.gets -} -# count now holds the number of lines read -#----------------------------- -count = 0 -while (chunk = file.sysread(2**16)) - count += chunk.count("\n") -end rescue EOFError -#----------------------------- -File.open(filename,'r') { |fh| - count += 1 while fh.gets -} -# count now holds the number of lines read -#----------------------------- -# As ruby doesn't quite have an equivalent to using a for -# statement as in perl, I threw this in -count = File.readlines(filename).size -#----------------------------- -1 while file.gets -count = $. -#----------------------------- -$/ = '' -open(filename, 'r') { |fh| - 1 while fh.gets - para_count = $. -} rescue fail("can't open #{filename}: $!") -#----------------------------- - - -# ^^PLEAC^^_8.3 -#----------------------------- -while (gets) - split.each { |chunk| - # do something with chunk - } -end -#----------------------------- -while (gets) - gsub(/(\w[\w'-]*)/) { |word| - # do something with word - } -end -#----------------------------- -# Make a word frequency count -# normally hashes can be created using {} or just Hash.new -# but we want the default value of an entry to be 0 instead -# of nil. (nil can't be incremented) -seen = Hash.new(0) -while (gets) - gsub(/(\w[\w'-]*)/) { |word| - seen[word.downcase] += 1 - } -end -# output hash in a descending numeric sort of its values -seen.sort { |a,b| b[1] <=> a[1] }.each do |k,v| - printf("%5d %s\n", v, k ) -end - -#----------------------------- -# Line frequency count -seen = Hash.new(0) -while (gets) - seen[$_.downcase] += 1 -end -seen.sort { |a,b| b[1] <=> a[1] }.each do |k,v| - printf("%5d %s\n", v, k ) -end -#----------------------------- - - -# @@PLEAC@@_8.4 -#----------------------------- -# instead of file handle FILE, we can just -# use a string containing the filename -File.readlines(file).each { |line| - # do something with line -} -#----------------------------- -File.readlines(file).reverse_each { |line| - # do something with line -} -#----------------------------- -# the variable lines might have been created -# this way -# lines = File.readlines(file) -# -# normally one would use the reverse_each, but -# if you insist on using a numerical index to -# iterate over the lines array... -(lines.size - 1).downto(0) { |i| - line = lines[i] -} -#----------------------------- -# the second readlines argument is a the -# record separator $/, just like perl, a blank -# separator splits the records into paragraphs -File.readlines(file, '').each { |paragraph| - # do something with paragraph - puts "->Paragraph #{paragraph}" -} -#----------------------------- - - -# @@PLEAC@@_8.6 - -$/ = "%\n"; -srand; - -File.open('/usr/share/fortune/humorists').each do |line| - adage = line if rand($.) < 1 -end - -puts adage; - - -# @@PLEAC@@_8.10 -begin - fh = File.open(file, "r+") - addr = fh.tell unless fh.eof while fh.gets - fh.truncate(addr) -rescue SystemCallError - $stderr.puts "#$!" -end - - -# @@PLEAC@@_9.0 -entry = File.stat("/usr/bin/vi") -entry = File.stat("/usr/bin") -entry = File.stat(INFILE) - -entry = File.stat("/usr/bin/vi") -ctime = entry.ctime -size = entry.size - -f = File.open(filename, "r") - -## There is no -T equivalent in Ruby, but we can still test emptiness -if test(?s, filename) - puts "#{filename} doesn't have text in it." - exit -end - -Dir.new("/usr/bin").each do |filename| - puts "Inside /usr/bin is something called #{filename}" -end - - -# @@PLEAC@@_9.1 -file = File.stat("filename") -readtime, writetime = file.atime, file.mtime -file.utime(readtime, writetime) - -SECONDS_PER_DAY = 60 * 60 * 24 -file = File.stat("filename") -atime, mtime = file.atime, file.mtime - -atime -= 7 * SECONDS_PER_DAY -mtime -= 7 * SECONDS_PER_DAY - -File.utime(atime, mtime, file) -mtime = File.stat(file).mtime -File.utime(Time.new, mtime, file) -File.utime(Time.new, File.stat("testfile").mtime, file) - -#----------------------------- -#!/usr/bin/ruby -w -## uvi - vi a file without changing it's access times - -if ARGV.length != 1 - puts "usage: uvi filename" - exit -end -file = ARGV[0] -atime, mtime = File.stat(file).atime, File.stat(file).mtime -system(ENV["EDITOR"] || "vi", file) -File.utime(atime, mtime, file) -#----------------------------- - - -# @@PLEAC@@_9.2 -File.unlink(FILENAME) - -err_flg = false -filenames.each do |file| - begin - File.unlink(file) - rescue - err_flg = $! - end -end -err_flg and raise "Couldn't unlink all of #{filenames.join(" ")}: #{err_flg}" - -File.unlink(file) - -count = filenames.length -filenames.each do |file| - begin - File.unlink(file) - rescue - count -= 1 - end -end -if count != filenames.length - STDERR.puts "could only delete #{count} of #{filenames.length} files" -end - - -# @@PLEAC@@_9.3 -require "ftools" -File.copy(oldfile, newfile) - -infile = File.open(oldfile, "r") -outfile = File.open(newfile, "w") - -blksize = infile.stat.blksize -# This doesn't handle partial writes or ^Z -# like the Perl version does. -while (line = infile.read(blksize)) - outfile.write(line) -end - -infile.close -outfile.close - -system("cp #{oldfile} #{newfile}") # unix -system("copy #{oldfile} #{newfile}") # dos, vms - -require "ftools" -File.copy("datafile.dat", "datafile.bak") -File.move("datafile.new", "datafile.dat") - - -# @@PLEAC@@_9.4 -$seen = {} # must use global var to be seen inside of method below - -def do_my_thing(filename) - dev, ino = File.stat(filename).dev, File.stat(filename).ino - unless $seen[[dev, ino]] - # do something with $filename because we haven't - # seen it before - end - $seen[[dev, ino]] = $seen[[dev, ino]].to_i + 1 -end - -files.each do |filename| - dev, ino = File.stat(filename).dev, File.stat(filename).ino - if !$seen.has_key?([dev, ino]) - $seen[[dev, ino]] = [] - end - $seen[[dev, ino]].push(filename) -end - -$seen.keys.sort.each do |devino| - ino, dev = devino - if $seen[devino].length > 1 - # $seen[devino] is a list of filenames for the same file - end -end - - -# @@PLEAC@@_9.5 -Dir.open(dirname) do |dir| - dir.each do |file| - # do something with dirname/file - puts file - end -end -# Dir.close is automatic - -# No -T equivalent in Ruby - -dir.each do |file| - next if file =~ /^\.\.?$/ - # ... -end - -def plainfiles(dir) - dh = Dir.open(dir) - dh.entries.grep(/^[^.]/). - map {|file| "#{dir}/#{file}"}. - find_all {|file| test(?f, file)}. - sort -end - - -# @@PLEAC@@_9.6 -list = Dir.glob("*.c") - -dir = Dir.open(path) -files = dir.entries.grep(/\.c$/) -dir.close - -files = Dir.glob("*.c") -files = Dir.open(path).entries.grep(/\.[ch]$/i) - -dir = Dir.new(path) -files = dir.entries.grep(/\.[ch]$/i) - -begin - d = Dir.open(dir) -rescue Errno::ENOENT - raise "Couldn't open #{dir} for reading: #{$!}" -end - -files = [] -d.each do |file| - puts file - next unless file =~ /\.[ch]$/i - - filename = "#{dir}/#{file}" - # There is no -T equivalent in Ruby, but we can still test emptiness - files.push(filename) if test(?s, filename) -end - -dirs.entries.grep(/^\d+$/). - map { |file| [file, "#{path}/#{file}"]} . - select { |file| test(?d, file[1]) }. - sort { |a,b| a[0] <=> b[0] }. - map { |file| file[1] } - - -# @@PLEAC@@_9.7 -require 'find' -Find.find(dirlist) do |file| - # do whatever -end - -require 'find' -argv = ARGV.empty? ? %w{.} : ARGV -Find.find(*argv) do |file| - print file, (test(?d, file) ? "/\n" : "\n") -end - -require 'find' -argv = ARGV.empty? ? %w{.} : ARGV -sum = 0 -Find.find(*argv) do |file| - size = test(?s, file) || 0 - sum += size -end -puts "#{argv.join(' ')} contains #{sum} bytes" - -require 'find' -argv = ARGV.empty? ? %w{.} : ARGV -saved_size, saved_name = -1, "" -Find.find(*argv) do |file| - size = test(?s, file) || 0 - next unless test(?f, file) && size > saved_size - saved_size = size - saved_name = file -end -puts "Biggest file #{saved_name} in #{argv.join(' ')} is #{saved_size}" - -require 'find' -argv = ARGV.empty? ? %w{.} : ARGV -age, name = nil -Find.find(*argv) do |file| - mtime = File.stat(file).mtime - next if age && age > mtime - age = mtime - name = file -end -puts "#{name} #{age}" - -#----------------------------- -#!/usr/bin/ruby -w -# fdirs - find all directories -require 'find' -argv = ARGV.empty? ? %w{.} : ARGV -File.find(*argv) { |file| puts file if test(?d, file) } -#----------------------------- - - -# @@PLEAC@@_9.8 -require 'fileutils' - -puts "Usage #{$0} dir ..." if ARGV.empty? -ARGV.each do |dir| - FileUtils.rmtree(dir) -end - - -# @@PLEAC@@_9.9 -require 'ftools' -names.each do |file| - newname = file - begin - File.move(file, newname) - rescue Errno::EPERM - $stderr.puts "Couldn't rename #{file} to #{newname}: #{$!}" - end -end - -require 'ftools' -op = ARGV.empty? ? (raise "Usage: rename expr [files]\n") : ARGV.shift -argv = ARGV.empty? ? $stdin.readlines.map { |f| f.chomp } : ARGV -argv.each do |file| - was = file - file = eval("file.#{op}") - File.move(was, file) unless was == file -end - - -# @@PLEAC@@_9.10 -base = File.basename(path) -dir = File.dirname(path) -# ruby has no fileparse equivalent -dir, base = File.split(path) -ext = base.scan(/\..*$/).to_s - -path = '/usr/lib/libc.a' -file = File.basename(path) -dir = File.dirname(path) - -puts "dir is #{dir}, file is #{file}" -# dir is /usr/lib, file is libc.a - -path = '/usr/lib/libc.a' -dir, filename = File.split(path) -name, ext = filename.split(/(?=\.)/) -puts "dir is #{dir}, name is #{name}, ext is #{ext}" -# NOTE: The Ruby code prints -# dir is /usr/lib, name is libc, extension is .a -# while the Perl code prints a '/' after the directory name -# dir is /usr/lib/, name is libc, extension is .a - -# No fileparse_set_fstype() equivalent in ruby - -def extension(path) - ext = path.scan(/\..*$/).to_s - ext.sub(/^\./, "") -end - - -# @@PLEAC@@_9.11 -#----------------------------- -#!/usr/bin/ruby -w -# symirror - build spectral forest of symlinks - -require 'find' -require 'fileutils' - -raise "usage: #{$0} realdir mirrordir" unless ARGV.size == 2 - -srcdir,dstdir = ARGV -srcmode = File::stat(srcdir).mode -Dir.mkdir(dstdir, srcmode & 07777) unless test(?d, dstdir) - -# fix relative paths -Dir.chdir(srcdir) {srcdir = Dir.pwd} -Dir.chdir(dstdir) {dstdir = Dir.pwd} - -Find.find(srcdir) do |srcfile| - if test(?d, srcfile) - dest = srcfile.sub(/^#{srcdir}/, dstdir) - dmode = File::stat(srcfile).mode & 07777 - Dir.mkdir(dest, dmode) unless test(?d, dest) - a = Dir["#{srcfile}/*"].reject{|f| test(?d, f)} - FileUtils.ln_s(a, dest) - end -end - - -# @@PLEAC@@_9.12 -# we use the Getopt/Declare library here for convenience: -# http://raa.ruby-lang.org/project/getoptdeclare/ -#----------------------------- -#!/usr/bin/ruby -w -# lst - list sorted directory contents (depth first) - -require 'find' -require 'etc' -require "Getopt/Declare" - -# Note: in the option-spec below there must by at least one hard -# tab in between each -option and its description. For example -# -i <tab> read from stdin - -opts = Getopt::Declare.new(<<'EOPARAM') - ============ - Input Format: - -i read from stdin - ============ - Output Format: - -l long listing - -r reverse listing - ============ - Sort on: (one of) - -m mtime (modify time - default) - {$sort_criteria = :mtime} - -u atime (access time) - {$sort_criteria = :atime} - -c ctime (inode change time) - {$sort_criteria = :ctime} - -s size - {$sort_criteria = :size} - [mutex: -m -u -c -s] - -EOPARAM - -$sort_criteria ||= :mtime -files = {} -DIRS = opts['-i'] ? $stdin.readlines.map{|f|f.chomp!} : ARGV -DIRS.each do |dir| - Find.find(dir) do |ent| - files[ent] = File::stat(ent) - end -end -entries = files.keys.sort_by{|f| files[f].send($sort_criteria)} -entries = entries.reverse unless opts['-r'] - -entries.each do |ent| - unless opts['-l'] - puts ent - next - end - stats = files[ent] - ftime = stats.send($sort_criteria == :size ? :mtime : $sort_criteria) - printf "%6d %04o %6d %8s %8s %8d %s %s\n", - stats.ino, - stats.mode & 07777, - stats.nlink, - ETC::PASSWD[stats.uid].name, - ETC::GROUP[stats.gid].name, - stats.size, - ftime.strftime("%a %b %d %H:%M:%S %Y"), - ent -end - - -# @@PLEAC@@_10.0 -def hello - $greeted += 1 # in Ruby, a variable beginning with $ is global (can be any type of course) - puts "hi there!" -end - -# We need to initialize $greeted before it can be used, because "+=" is waiting a Numeric object -$greeted = 0 -hello # note that appending () is optional to function calls with no parameters - - -# @@PLEAC@@_10.1 -# In Ruby, parameters are named anyway -def hypotenuse(side1, side2) - Math.sqrt(side1**2 + side2**2) # the sqrt function comes from the Math module -end -diag = hypotenuse(3, 4) - -puts hypotenuse(3, 4) - -a = [3, 4] -print hypotenuse(*a) # the star operator will magically convert an Array into a "tuple" - -both = men + women - -# In Ruby, all objects are references, so the same problem arises; we then return a new object -nums = [1.4, 3.5, 6.7] -def int_all(n) - n.collect { |v| v.to_i } -end -ints = int_all(nums) - -nums = [1.4, 3.5, 6.7] -def trunc_em(n) - n.collect! { |v| v.to_i } # the bang-version of collect modifies the object -end -trunc_em(nums) - -# Ruby has two chomp version: -# ``chomp'' chomps the record separator and returns what's expected -# ``chomp!'' does the same but also modifies the parameter object - - -# @@PLEAC@@_10.2 -def somefunc - variable = something # variable is local by default -end - -name, age = ARGV -start = fetch_time - -a, b = pair # will succeed if pair is an Array object (like ARGV is) -c = fetch_time - -# In ruby, run_check can't access a, b, or c until they are -# explicitely defined global (using leading $), even if they are -# both defined in the same scope - -def check_x(x) - y = "whatever" - run_check - if $condition - puts "got $x" - end -end - -# The following will keep a reference to the array, though the -# results will be slightly different from perl: the last element -# of $global_array will be itself an array -def save_array(ary) - $global_array << ary -end - -# The following gives the same results as in Perl for $global_array, -# though it doesn't illustrate anymore the way to keep a reference -# to an object: $global_array is extended with the elements of ary -def save_array(ary) - $global_array += ary -end - - -# @@PLEAC@@_10.3 -# In Ruby, AFAIK a method cannot access "local variables" defined -# upper scope; mostly because everything is an object, so you'll -# do the same by defining an attribute or a static attribute - -# In Ruby the BEGIN also exists: -BEGIN { puts "hello from BEGIN" } -puts "hello from main" -BEGIN { puts "hello from 2nd BEGIN" } -# gives: -# hello from BEGIN -# hello from 2nd BEGIN -# hello from main - -# In Ruby, it can be written as a static method and a static -# variable -class Counter - @@counter = 0 - def Counter.next_counter; @@counter += 1; end -end - -# There is no need of BEGIN since the variable will get -# initialized when parsing -class Counter - @@counter = 42 - def Counter.next_counter; @@counter += 1; end - def Counter.prev_counter; @@counter -= 1; end -end - - -# @@PLEAC@@_10.4 -# You can either get the whole trace as an array of strings, each -# string telling which file, line and method is calling: -caller - -# ...or only the last caller -caller[0] - -# We need to extract just the method name of the backtrace: -def whoami; caller()[0] =~ /in `([^']+)'/ ? $1 : '(anonymous)'; end -def whowasi; caller()[1] =~ /in `([^']+)'/ ? $1 : '(anonymous)'; end - - -# @@PLEAC@@_10.5 -# In Ruby, every value is a reference on an object, thus there is -# no such problem -array_diff(array1, array2) - -def add_vecpair(a1, a2) - results = [] - a1.each_index { |i| results << (a1[i] + a2[i]) } - results -end -a = [1, 2] -b = [5, 8] -c = add_vecpair(a, b) -p c - -# Add this to the beginning of the function to check if we were -# given two arrays -a1.type == Array && a2.type == Array or - raise "usage: add_vecpair array1 array2 (was used with: #{a1.type} #{a2.type})" - - -# @@PLEAC@@_10.6 -# There is no return context in Ruby - - -# @@PLEAC@@_10.7 -# Like in Perl, we need to fake with a hash, but it's dirty :-( -def thefunc(param_args) - args = { 'INCREMENT' => '10s', 'FINISH' => '0', 'START' => 0 } - args.update(param_args) - if (args['INCREMENT'] =~ /m$/ ) - # ..... - end -end - -thefunc({ 'INCREMENT' => '20s', 'START' => '+5m', 'FINISH' => '+30m' }) -thefunc({}) - - -# @@PLEAC@@_10.8 -# there is no "undef" direct equivalent but there is the slice equiv: -a, c = func.indexes(0, 2) - - -# @@PLEAC@@_10.9 -# Ruby has no such limitation: -def somefunc - ary = [] - hash = {} - # ... - return ary, hash -end -arr, dict = somefunc - -array_of_hashes = fn -h1, h2, h3 = fn - - -# @@PLEAC@@_10.10 -return -# or (equivalent) -return nil - - -# @@PLEAC@@_10.11 -# You can't prototype in Ruby regarding types :-( -# Though, you can force the number of arguments: -def func_with_no_arg; end -def func_with_no_arg(); end -def func_with_one_arg(a1); end -def func_with_two_args(a1, a2); end -def func_with_any_number_of_args(*args); end - - -# @@PLEAC@@_10.12 -raise "some message" # raise exception - -begin - val = func -rescue Exception => msg - $stderr.puts "func raised an exception: #{msg}" -end - -# In Ruby the rescue statement uses an exception class, every -# exception which is not matched is still continuing -begin - val = func -rescue FullMoonError - ... -end - - -# @@PLEAC@@_10.13 -# Saving Global Values -# Of course we can just save the value and restore it later: -def print_age - puts "Age is #{$age}" -end - -$age = 18 # global variable -print_age() -if condition - safeage = $age - $age = 23 - print_age() - $age = safeage -end - -# We can also use a method that saves the global variable and -# restores it automatically when the block is left: - -def local(var) - eval("save = #{var.id2name}") - begin - result = yield - ensure - # we want to call this even if we got an exception - eval("#{var.id2name} = save") - end - result -end - -condition = true -$age = 18 -print_age() -if condition - local(:$age) { - $age = 23 - print_age() - } -end -print_age() - -# There is no need to use local() for filehandles or directory -# handles in ruby because filehandles are normal objects. - - -# @@PLEAC@@_10.14 -# In Ruby you may redefine a method [but not overload it :-(] -# just by defining again with the same name. -def foo; puts 'foo'; end -def foo; puts 'bar'; end -foo -#=> bar - -# You can also take a reference to an existing method before -# redefining a new one, using the `alias' keyword -def foo; puts 'foo'; end -alias foo_orig foo -def foo; puts 'bar'; end -foo_orig -foo -#=> foo -#=> bar - -# AFAIK, there is no direct way to create a new method whose name -# comes from a variable, so use "eval" -colors = %w(red blue green yellow orange purple violet) -colors.each { |c| - eval <<-EOS - def #{c}(*a) - "<FONT COLOR='#{c}'>" + a.to_s + "</FONT>" - end - EOS -} - - -# @@PLEAC@@_10.15 -def method_missing(name, *args) - "<FONT COLOR='#{name}'>" + args.join(' ') + "</FONT>" -end -puts chartreuse("stuff") - - -# @@PLEAC@@_10.16 -def outer(arg) - x = arg + 35 - inner = proc { x * 19 } - x + inner.call() -end - - -# @@PLEAC@@_10.17 -#!/usr/bin/ruby -w -# mailsort - sort mbox by different criteria -require 'English' -require 'Date' - -# Objects of class Mail represent a single mail. -class Mail - attr_accessor :no - attr_accessor :subject - attr_accessor :fulltext - attr_accessor :date - - def initialize - @fulltext = "" - @subject = "" - end - - def append(para) - @fulltext << para - end - - # this is called if you call puts(mail) - def to_s - @fulltext - end -end - -# represents a list of mails. -class Mailbox < Array - - Subjectpattern = Regexp.new('Subject:\s*(?:Re:\s*)*(.*)\n') - Datepattern = Regexp.new('Date:\s*(.*)\n') - - # reads mails from open file and stores them - def read(file) - $INPUT_RECORD_SEPARATOR = '' # paragraph reads - msgno = -1 - file.each { |para| - if para =~ /^From/ - mail = Mail.new - mail.no = (msgno += 1) - md = Subjectpattern.match(para) - if md - mail.subject = md[1] - end - md = Datepattern.match(para) - if md - mail.date = DateTime.parse(md[1]) - else - mail.date = DateTime.now - end - self.push(mail) - end - mail.append(para) if mail - } - end - - def sort_by_subject_and_no - self.sort_by { |m| - [m.subject, m.no] - } - end - - # sorts by a list of attributs of mail, given as symbols - def sort_by_attributs(*attrs) - # you can sort an Enumerable by an array of - # values, they would be compared - # from ary[0] to ary[n]t, say: - # ['b',1] > ['a',10] > ['a',9] - self.sort_by { |elem| - attrs.map { |attr| - elem.send(attr) - } - } - end - -end - -mailbox = Mailbox.new -mailbox.read(ARGF) - -# print only subjects sorted by subject and number -for m in mailbox.sort_by_subject_and_no - puts(m.subject) -end - -# print complete mails sorted by date, then subject, then number -for m in mailbox.sort_by_attributs(:date, :subject) - puts(m) -end - - -# @@PLEAC@@_11.7 -def mkcounter(count) - start = count - bundle = { - "NEXT" => proc { count += 1 }, - "PREV" => proc { count -= 1 }, - "RESET" => proc { count = start } - } - bundle["LAST"] = bundle["PREV"] - return bundle -end - -c1 = mkcounter(20) -c2 = mkcounter(77) - -puts "next c1: #{c1["NEXT"].call}" # 21 -puts "next c2: #{c2["NEXT"].call}" # 78 -puts "next c1: #{c1["NEXT"].call}" # 22 -puts "last c1: #{c1["PREV"].call}" # 21 -puts "last c1: #{c1["LAST"].call}" # 20 -puts "old c2: #{c2["RESET"].call}" # 77 - - -# @@PLEAC@@_11.15 -class Binary_tree - def initialize(val) - @value = val - @left = nil - @right = nil - end - - # insert given value into proper point of - # provided tree. If no tree provided, - # use implicit pass by reference aspect of @_ - # to fill one in for our caller. - def insert(val) - if val < @value then - if @left then - @left.insert(val) - else - @left = Binary_tree.new(val) - end - elsif val > @value then - if @right then - @right.insert(val) - else - @right = Binary_tree.new(val) - end - else - puts "double" - # do nothing, no double values - end - end - - # recurse on left child, - # then show current value, - # then recurse on right child. - def in_order - @left.in_order if @left - print @value, " " - @right.in_order if @right - end - - # show current value, - # then recurse on left child, - # then recurse on right child. - def pre_order - print @value, " " - @left.pre_order if @left - @right.pre_order if @right - end - - # recurse on left child, - # then recurse on right child, - # then show current value. - def post_order - @left.post_order if @left - @right.post_order if @right - print @value, " " - end - - # find out whether provided value is in the tree. - # if so, return the node at which the value was found. - # cut down search time by only looking in the correct - # branch, based on current value. - def search(val) - if val == @value then - return self - elsif val < @value then - return @left.search(val) if @left - return nil - else - return @right.search(val) if @right - return nil - end - end -end - -# first generate 20 random inserts -test = Binary_tree.new(0) -for a in 0..20 - test.insert(rand(1000)) -end - -# now dump out the tree all three ways -print "Pre order: "; test.pre_order; puts "" -print "In order: "; test.in_order; puts "" -print "Post order: "; test.post_order; puts "" - -print "search?" -while gets - print test.search($_.to_i) - print "\nsearch?" -end - - -# @@PLEAC@@_12.0 -# class and module names need to have the first letter capitalized -module Alpha - NAME = 'first' -end -module Omega - NAME = 'last' -end -puts "Alpha is #{Alpha::NAME}, Omega is #{Omega::NAME}" - -# ruby doesn't differentiate beteen compile-time and run-time -require 'getoptlong.rb' -require 'getoptlong' # assumes the .rb -require 'cards/poker.rb' -require 'cards/poker' # assumes the .rb -load 'cards/poker' # require only loads the file once - -module Cards - module Poker - @card_deck = Array.new # or @card_deck = [] - def shuffle - end - end -end - - -# @@PLEAC@@_12.1 -# a module exports all of its functions -module Your_Module - def self.function - # this would be called as Your_Module.function - end - - def Your_Module.another - # this is the same as above, but more specific - end -end - -# @@PLEAC@@_12.2 -begin - require 'nonexistent' -rescue LoadError - puts "Couldn't load #{$!}" # $! contains the last error string -end - -# @@PLEAC@@_12.4 -# module variables are private unless access functions are defined -module Alpha - @aa = 10 - @bb = 11 - - def self.put_aa - puts @aa - end - - def self.bb=(val) - @bb = val - end -end - -Alpha.bb = 12 -# Alpha.aa = 10 # error, no aa=method - - -# @@PLEAC@@_12.5 -# caller provides a backtrace of the call stack -module MyModule - def find_caller - caller - end - - def find_caller2(i) - caller(i) # an argument limits the size of the stack returned - end -end - - -# @@PLEAC@@_12.6 -BEGIN { - $logfile = '/tmp/mylog' unless defined? $logfile - $LF = File.open($logfile, 'a') -} - -module Logger - def self.logmsg(msg) - $LF.puts msg - end - - logmsg('startup') -end - -END { - Logger::logmsg('shutdown') - $LF.close -} - - -# @@PLEAC@@_12.7 -#----------------------------- -# results may be different on your system -# % ruby -e "$LOAD_PATH.each_index { |i| printf("%d %s\n", i, $LOAD_PATH[i] } -#0 /usr/local/lib/site_ruby/1.6 -#1 /usr/local/lib/site_ruby/1.6/i386-linux -#2 /usr/local/lib/site_ruby/ -#3 /usr/lib/ruby/1.6 -#4 /usr/lib/ruby/1.6/i136-linux -#5 . -#----------------------------- -# syntax for sh, bash, ksh, or zsh -#$ export RUBYLIB=$HOME/rubylib - -# syntax for csh or tcsh -# % setenv RUBYLIB ~/rubylib -#----------------------------- -$LOAD_PATH.unshift "/projects/spectre/lib"; - - -# @@PLEAC@@_12.8 -# equivalents in ruby are mkmf, SWIG, or Ruby/DL depending on usage - - -# @@PLEAC@@_12.9 -# no equivalent in ruby - - -# @@PLEAC@@_12.10 -# no equivalent in ruby - - -# @@PLEAC@@_12.11 -module FineTime - def self.time - # to be defined later - end -end - - -module FineTime - def self.time - "its a fine time" - end -end - -puts FineTime.time #=> "its a fine time" - - -# @@PLEAC@@_12.12 -def even_only(n) - raise "#{n} is not even" if (n & 1) != 0 # one way to test - # ... -end -def even_only(n) - $stderr.puts "#{n} is not even" if (n & 1) != 0 - # ... -end - - -# @@PLEAC@@_12.17 -# The library archive for ruby is called Ruby Application archive, -# or shorter RAA, and can be found at http://raa.ruby-lang.org. -# A typical library is installed like this: -# % gunzip some-module-4.54.tar.gz -# % tar xf some-module-4.54.tar -# % cd some-module-4.54.tar -# % ruby install.rb config -# % ruby install.rb setup -# get superuser previleges here if needed for next step -# % ruby install.rb install - -# Some modules use a different process, -# you should find details in the documentation -# Here is an example of such a different process -# % ruby extconf.rb -# % make -# % make install - -# If you want the module installed in your own directory: -# For ruby version specific libraries -# % ruby install.rb config --site-ruby=~/lib -# For version independent libraries -# % ruby install.rb config --site-ruby-common=~/lib - -# Information about possible options for config -# % ruby install.rb --help - -# If you have your own complete distribution -# % ruby install.rb --prefix=path=~/ruby-private - - -# @@PLEAC@@_13.0 -# Classes and objects in Ruby are rather straigthforward -class Person - # Class variables (also called static attributes) are prefixed by @@ - @@person_counter=0 - - # object constructor - def initialize(age, name, alive = true) # Default arg like in C++ - @age, @name, @alive = age, name, alive # Object attributes are prefixed by '@' - @@person_counter += 1 - # There is no '++' operator in Ruby. The '++'/'--' operators are in fact - # hidden assignments which affect variables, not objects. You cannot accomplish - # assignment via method. Since everything in Ruby is object, '++' and '--' - # contradict Ruby OO ideology. Instead '-=' and '+=' are used. - end - - attr_accessor :name, :age # This creates setter and getter methods for @name - # and @age. See 13.3 for detailes. - - # methods modifying the receiver object usually have the '!' suffix - def die! - @alive = false - puts "#{@name} has died at the age of #{@age}." - @alive - end - - def kill(anotherPerson) - print @name, ' is killing ', anotherPerson.name, ".\n" - anotherPerson.die! - end - - # methods used as queries - # usually have the '?' suffix - def alive? - @alive && true - end - - def year_of_birth - Time.now.year - @age - end - - # Class method (also called static method) - def Person.number_of_people - @@person_counter - end -end - -# Using the class: -# Create objects of class Person -lecter = Person.new(47, 'Hannibal') -starling = Person.new(29, 'Clarice', true) -pazzi = Person.new(40, 'Rinaldo', true) - -# Calling a class method -print "There are ", Person.number_of_people, " Person objects\n" - -print pazzi.name, ' is ', (pazzi.alive?) ? 'alive' : 'dead', ".\n" -lecter.kill(pazzi) -print pazzi.name, ' is ', (pazzi.alive?) ? 'alive' : 'dead', ".\n" - -print starling.name , ' was born in ', starling.year_of_birth, "\n" - - -# @@PLEAC@@_13.1 -# If you don't need any initialisation in the constructor, -# you don't need to write a constructor. -class MyClass -end - -class MyClass - def initialize - @start = Time.new - @age = 0 - end -end - -class MyClass - def initialize(inithash) - @start = Time.new - @age = 0 - for key, value in inithash - instance_variable_set("@#{key}", value) - end - end -end - -# @@PLEAC@@_13.2 -# Objects are destroyed by the garbage collector. -# The time of destroying is not predictable. -# The ruby garbage collector can handle circular references, -# so there is no need to write destructor for that. - -# There is no direct support for destructor. -# You can call a custom function, or more specific a proc object, when the -# garbage collector is about to destruct the object, but it is unpredictable -# when this occurs. -# Also if such a finalizer object has a reference to the orignal object, -# this may prevent the original object to get garbage collected. -# Because of this problem the finalize method below is -# a class method and not a instance method. -# So if you need to free resources for an object, like -# closing a socket or kill a spawned subprocess, -# you should do it explicitly. - -class MyClass - def initialize - ObjectSpace.define_finalizer(self, - self.class.method(:finalize).to_proc) - end - def MyClass.finalize(id) - puts "Object #{id} dying at #{Time.new}" - end -end - -# test code -3.times { - MyClass.new -} -ObjectSpace.garbage_collect - - -# @@PLEAC@@_13.3 -# You can write getter and setter methods in a natural way: -class Person - def name - @name - end - def name=(name) - @name = name - end -end - -# But there is a better and shorter way -class Person - attr_reader :age - attr_writer :name - # attr_reader and attr_writer are actually methods in class Class - # which set getter and setter methods for you. -end - -# There is also attr_accessor to create both setters and getters -class Person - attr_accessor :age, :name -end - - -# @@PLEAC@@_13.4 -class Person - # Class variables (also called static attributes) are prefixed by @@ - @@person_counter = 0 - - def Person.population - @@person_counter - end - def initialize - @@person_counter += 1 - ObjectSpace.define_finalizer(self, - self.class.method(:finalize).to_proc) - end - def Person.finalize(id) - @@person_counter -= 1 - end -end -people = [] -10.times { - people.push(Person.new) -} -printf("There are %d people alive", Person.population) - - -FixedArray.class_max_bounds = 100 -alpha = FixedArray.new -puts "Bound on alpha is #{alpha.max_bounds}" - -beta = FixedArray.new -beta.max_bounds = 50 # calls the instance method -beta.class.class_max_bounds = 50 # alternative, calls the class method -puts "Bound on alpha is #{alpha.max_bounds}" - -class FixedArray - @@bounds = 7 - - def max_bounds - @@max_bounds - end - # instance method, which sets the class variable - def max_bounds=(value) - @@max_bounds = value - end - # class method. This can only be called on a class, - # but not on the instances - def FixedArray.class_max_bounds=(value) - @@max_bounds = value - end -end - - -# @@PLEAC@@_13.5 -PersonStruct = Struct.new("Person", :name, :age, :peers) -# creates a class "Person::Struct", which is accessiable with the -# constant "PersonStruct" -p = PersonStruct.new -p = Struct::Person.new # alternative using the classname -p.name = "Jason Smythe" -p.age = 13 -p.peers = ["Wilbur", "Ralph", "Fred"] -p[:peers] = ["Wilbur", "Ralph", "Fred"] # alternative access using symbol -p["peers"] = ["Wilbur", "Ralph", "Fred"] # alternative access using name of field -p[2] = ["Wilbur", "Ralph", "Fred"] # alternative access using index of field -puts "At age #{p.age}, #{p.name}'s first friend is #{p.peers[0]}" - -# The fields of a struct have no special type, like other ruby variables -# you can put any objects in. Therefore the discussions how to specify -# the types of the fields do not apply to ruby. - -FamilyStruct = Struct.new("Family", :head, :address, :members) -folks = FamilyStruct.new -folks.head = PersonStruct.new -dad = folks.head -dad.name = "John" -dad.age = 34 - -# supply of own accessor method for the struct for error checking -class PersonStruct - def age=(value) - if !value.kind_of?(Integer) - raise(ArgumentError, "Age #{value} isn't an Integer") - elsif value > 150 - raise(ArgumentError, "Age #{value} is unreasonable") - end - @age = value - end -end - - -# @@PLEAC@@_13.6 -# The ruby Object class defines a dup and a clone method. -# The dup method is recommended for prototype object creation. -# The default implementation makes a shallow copy, -# but each class can override it, for example to make a deep copy. - -# If you want to call 'new' directly on the instances, -# you can create a instance method "new", which returns a new duplicate. -# This method is distinct from the class method new. -# -class A - def new - dup - end -end - -ob1 = A.new -# later on -ob2 = ob1.new - - -# @@PLEAC@@_13.7 -methname = 'flicker' -obj.send(methname, 10) # calls obj.flicker(10) - -# call three methods on the object, by name -['start', 'run', 'stop'].each do |method_string| - obj.send(method_string) -end - -# Another way is to create a Method object -method_obj = obj.method('flicker') -# And then call it -method_obj.call(10) - - -# @@PLEAC@@_13.8 -# All classes in Ruby inherit from class Object -# and thus all objects share methods defined in this class - -# the class of the object -puts any_object.type - -# Ruby classes are actually objects of class Class and they -# respond to methods defined in Object class as well - -# the superclass of this class -puts any_object.class.superclass - -# ask an object whether it is an instance of particular class -n = 4.7 -puts n.instance_of?(Float) # true -puts n.instance_of?(Numeric) # false - -# ask an object whether it is an instance of class, one of the -# superclasses of the object, or modules included in it -puts n.kind_of?(Float) # true (the class) -puts n.kind_of?(Numeric) # true (an ancestor class) -puts n.kind_of?(Comparable) # true (a mixin module) -puts n.kind_of?(String) # false - -# ask an object whether it can respond to a particular method -puts n.respond_to?('+') # true -puts n.respond_to?('length') # false - -# all methods an object can respond to -'just a string'.methods.each { |m| puts m } - - -# @@PLEAC@@_13.9 -# Actually any class in Ruby is inheritable -class Person - attr_accessor :age, :name - def initialize - @name - @age - end -end -#----------------------------- -dude = Person.new -dude.name = 'Jason' -dude.age = 23 -printf "%s is age %d.\n", dude.name, dude.age -#----------------------------- -# Inheriting from Person -class Employee < Person - attr_accessor :salary -end -#----------------------------- -empl = Employee.new -empl.name = 'Jason' -empl.age = 23 -empl.salary = 200 -printf "%s is age %d, the salary is %d.\n", empl.name, empl.age, empl.salary -#----------------------------- -# Any built-in class can be inherited the same way -class WeirdString < String - def initialize(obj) - super obj - end - def +(anotherObj) # + method in this class is overridden - # to return the sum of string lengths - self.length + anotherObj.length # 'self' can be omitted - end -end -#----------------------------- -a = WeirdString.new('hello') -b = WeirdString.new('bye') - -puts a + b # the overridden + -#=> 8 -puts a.length # method from the superclass, String -#=> 5 - - -# @@PLEAC@@_13.11 -# In ruby you can override the method_missing method -# to have a solution similar to perls AUTOLOAD. -class Person - - def initialize - @ok_fields = %w(name age peers parent) - end - - def valid_attribute?(name) - @ok_fields.include?(name) - end - - def method_missing(namesymbol, *params) - name = namesymbol.to_s - return if name =~ /^A-Z/ - if name.to_s[-1] == ('='[0]) # we have a setter - isSetter = true - name.sub!(/=$/, '') - end - if valid_attribute?(name) - if isSetter - instance_variable_set("@#{name}", *params) - else - instance_variable_get("@#{name}", *params) - end - else - # if no annestor is responsible, - # the Object class will throw a NoMethodError exception - super(namesymbol, *params) - end - end - - def new - kid = Person.new - kid.parent = self - kid - end - -end - -dad = Person.new -dad.name = "Jason" -dad.age = 23 -kid = dad.new -kid.name = "Rachel" -kid.age = 2 -puts "Kid's parent is #{kid.parent.name}" -puts dad -puts kid - -class Employee < Person - def initialize - super - @ok_fields.push("salary", "boss") - end - def ok_fields - @ok_fields - end -end - - -# @@PLEAC@@_13.13 -# The ruby garbage collector pretends to cope with circular structures. -# You can test it with this code: -class RingNode - attr_accessor :next - attr_accessor :prev - attr_reader :name - - def initialize(aName) - @name = aName - ObjectSpace.define_finalizer(self, - self.class.method(:finalize).to_proc) - end - - def RingNode.finalize(id) - puts "Node #{id} dying" - end - - def RingNode.show_all_objects - ObjectSpace.each_object {|id| - puts id.name if id.class == RingNode - } - end -end - -def create_test - a = RingNode.new("Node A") - b = RingNode.new("Node B") - c = RingNode.new("Node C") - a.next = b - b.next = c - c.next = a - a.prev = c - c.prev = b - b.prev = a - - a = nil - b = nil - c = nil -end - -create_test -RingNode.show_all_objects -ObjectSpace.garbage_collect -puts "After garbage collection" -RingNode.show_all_objects - - -# @@PLEAC@@_13.14 -class String - def <=>(other) - self.casecmp other - end -end - -# There is no way to directly overload the '""' (stringify) -# operator in Ruby. However, by convention, classes which -# can reasonably be converted to a String will define a -# 'to_s' method as in the TimeNumber class defined below. -# The 'puts' method will automatcally call an object's -# 'to_s' method as is demonstrated below. -# Furthermore, if a class defines a to_str method, an object of that -# class can be used most any place where the interpreter is looking -# for a String value. - -#--------------------------------------- -# NOTE: Ruby has a builtin Time class which would usually be used -# to manipulate time objects, the following is supplied for -# educational purposes to demonstrate operator overloading. -# -class TimeNumber - attr_accessor :hours,:minutes,:seconds - def initialize( hours, minutes, seconds) - @hours = hours - @minutes = minutes - @seconds = seconds - end - - def to_s - return sprintf( "%d:%02d:%02d", @hours, @minutes, @seconds) - end - - def to_str - to_s - end - - def +( other) - seconds = @seconds + other.seconds - minutes = @minutes + other.minutes - hours = @hours + other.hours - if seconds >= 60 - seconds %= 60 - minutes += 1 - end - if minutes >= 60 - minutes %= 60 - hours += 1 - end - return TimeNumber.new(hours, minutes, seconds) - end - - def -(other) - raise NotImplementedError - end - - def *(other) - raise NotImplementedError - end - - def /( other) - raise NotImplementedError - end -end - -t1 = TimeNumber.new(0, 58, 59) -sec = TimeNumber.new(0, 0, 1) -min = TimeNumber.new(0, 1, 0) -puts t1 + sec + min + min - -#----------------------------- -# StrNum class example: Ruby's builtin String class already has the -# capabilities outlined in StrNum Perl example, however the '*' operator -# on Ruby's String class acts differently: It creates a string which -# is the original string repeated N times. -# -# Using Ruby's String class as is in this example: -x = "Red"; y = "Black" -z = x+y -r = z*3 # r is "RedBlackRedBlackRedBlack" -puts "values are #{x}, #{y}, #{z}, and #{r}" -print "#{x} is ", x < y ? "LT" : "GE", " #{y}\n" -# prints: -# values are Red, Black, RedBlack, and RedBlackRedBlackRedBlack -# Red is GE Black - -#----------------------------- -class FixNum - REGEX = /(\.\d*)/ - DEFAULT_PLACES = 0 - attr_accessor :value, :places - def initialize(value, places = nil) - @value = value - if places - @places = places - else - m = REGEX.match(value.to_s) - if m - @places = m[0].length - 1 - else - @places = DEFAULT_PLACES - end - end - end - - def +(other) - FixNum.new(@value + other.value, max(@places, other.places)) - end - - def *(other) - FixNum.new(@value * other.value, max(@places, other.places)) - end - - def /(other) - puts "Divide: #{@value.to_f/other.value.to_f}" - result = FixNum.new(@value.to_f/other.value.to_f) - result.places = max(result.places,other.places) - result - end - - def to_s - sprintf("STR%s: %.*f", self.class.to_s , @places, @value) #. - end - - def to_str - to_s - end - - def to_i #convert to int - @value.to_i - end - - def to_f #convert to float` - @value.to_f - end - - private - def max(a,b) - a > b ? a : b - end -end - -def demo() - x = FixNum.new(40) - y = FixNum.new(12, 0) - - puts "sum of #{x} and #{y} is #{x+y}" - puts "product of #{x} and #{y} is #{x*y}" - - z = x/y - puts "#{z} has #{z.places} places" - unless z.places - z.places = 2 - end - - puts "div of #{x} by #{y} is #{z}" - puts "square of that is #{z*z}" -end - -if __FILE__ == $0 - demo() -end - - -# @@PLEAC@@_14.1 -# There are dbm, sdbm, gdbm modules -# and the bdb module for accessing the berkeley db -# sdbm seem to be available on the most systems, -# so we use it here -# -require "sdbm" -SDBM.open("filename", 0666) { |dbobj| - # raises exception if open error - - # the returned sdbm-dbobj has most of the methods of a hash - v = dbobj["key"] - dbobj["key"] = "newvalue" - if dbobj.has_key?("key") - # ... - end - dbobj.delete("key2") -} -# database is open only inside the block. - -# It is also possible to use a open .. close pair: -dbobj = SDBM.open("filename", 0666) -#.. do something with dbobj -dbobj.close - -#!/usr/bin/ruby -w -# userstats - generate statistics on who is logged in -# call with usernames as argument to display the totals -# for the given usernames, call with "ALL" to display all users - -require "sdbm" -filename = '/tmp/userstats.db' -SDBM.open(filename, 0666) { |dbobj| - if ARGV.length > 0 - if ARGV[0] == "ALL" - # ARGV is constant, so we need the variable userlist - userlist = dbobj.keys().sort() - else - userlist = ARGV - end - userlist.each { |user| - print "#{user}\t#{dbobj[user]}\n" - } - else - who = `who` - who.split("\n").each { |line| - md = /^(\S+)/.match(line) - raise "Bad line from who: #{line}" unless md - # sdbm stores only strings, so "+=" doesn't work, - # we need to convert them expicitly back to integer. - if dbobj.has_key?(md[0]) - dbobj[md[0]] = dbobj[md[0]].to_i + 1 - else - dbobj[md[0]] = "1" - end - } - end -} - - -# @@PLEAC@@_14.2 -# using open and clear -dbobj = SDBM.open("filename", 0666) -dbobj.clear() -dbobj.close() -# deleting file and recreating it -# the filenames depend on the flavor of dbm you use, -# for example sdbm has two files named filename.pag and filename.dir, -# so you need to delete both files -begin - File.delete("filename") - # raises Exception if not exist - dbobj = SDBM.open("filename", 0666) -rescue - # add error handling here -end - - -# @@PLEAC@@_14.3 -# sdbm2gdbm: converts sdbm database to a gdbm database -require "sdbm" -require "gdbm" - -unless ARGV.length == 2 - fail "usage: sdbm2gdbm infile outfile" -end -infile = ARGV[0] -outfile = ARGV[1] - -sdb = SDBM.open(infile) -gdb = GDBM.open(outfile, 0666) -sdb.each { |key, val| - gdb[key] = val -} -gdb.close -sdb.close - - -# @@PLEAC@@_14.4 -#!/usr/bin/ruby -w -# dbmmerge: merges two dbm databases -require "sdbm" - -unless ARGV.length == 3 - fail "usage: dbmmerge indb1 indb2 outdb" -end -infile1 = ARGV[0] -infile2 = ARGV[0] -outfile = ARGV[2] - -in1 = SDBM.open(infile1, nil) -in2 = SDBM.open(infile2, nil) -outdb = SDBM.open(outfile, 0666) - -[in1, in2].each { |indb| - indb.each { |key, val| - if outdb.has_key?(key) - # decide which value to set. - # set outdb[key] if necessary - else - outdb[key] = val - end - } -} -in1.close -in2.close -outdb.close - - -# @@PLEAC@@_14.7 -# we write a tie method that extends the Array class. -# It reads the file into the memory, executes the code block -# in which you can manipulate the array as needed, and writes -# the array back to the file after the end of the block execution -class Array - def tie(filename, flags) - File.open(filename, flags) { |f| - f.each_line { |line| - self.push(line.chomp) - } - yield - f.rewind - each { |line| - if line - f.puts(line) - else - f.puts "" - end - } - } - end -end - -array = Array.new -array.tie("/tmp/textfile.txt", File::RDWR|File::CREAT) { - array[4] = "a new line 4" -} - -# The tied array can be manipulated like a normal array, -# so there is no need for a special API, and the recno_demo program -# to demonstrate is API is useless - - -# tied array demo: show how to use array with a tied file -filename = "db_file.txt" -lines = Array.new -File.unlink(filename) if File.exists?(filename) -lines.tie(filename, File::RDWR | File::CREAT) { - # first create a textfile to play with - lines[0] = "zero" - lines[1] = "one" - lines[2] = "two" - lines[3] = "three" - lines[4] = "four" - - # print the records in order. - # Opposed to perl, the tied array behaves exactly as a normal array - puts "\nOriginal" - for i in 0..(lines.length-1) - puts "#{i}: #{lines[i]}" - end - - #use push and pop - a = lines.pop - lines.push("last") - puts("The last line was [#{a}]") - - #use shift and unshift - a = lines.shift - lines.unshift("first") - puts("The first line was [#{a}]") - - # add record after record 2 - i = 2 - lines.insert(i + 1, "Newbie") - - # add record before record one - i = 1 - lines.insert(i, "New One") - - # delete record 3 - lines.delete_at(3) - - #now print the records in reverse order - puts "\nReverse" - (lines.length - 1).downto(0){ |i| - puts "#{i}: #{lines[i]}" - } - -} - - -# @@PLEAC@@_14.8 -# example to store complex data in a database -# uses marshall from the standard library -require "sdbm" -db = SDBM.open("pleac14-8-database", 0666) - -# convert the Objects into strings and back by using the Marshal module. -# Most normal objects can be converted out of the box, -# but not special things like procedure objects, -# IO instance variables, singleton objects - -db["Tom Christiansen"] = Marshal.dump(["book author", "tchrist@perl.com"]) -db["Tom Boutell"] = Marshal.dump(["shareware author", -"boutell@boutell.com"]) - -name1 = "Tom Christiansen" -name2 = "Tom Boutell" - -tom1 = Marshal.load(db[name1]) -tom2 = Marshal.load(db[name2]) - -puts "Two Toming: #{tom1} #{tom2}" - -if tom1[0] == tom2[0] && tom1[1] == tom2[1] - puts "You're having runtime fun with one Tom made two." -else - puts "No two Toms are ever alike" -end - -# To change parts of an entry, get the whole entry, change the parts, -# and save the whole entry back -entry = Marshal.load(db["Tom Boutell"]) -entry[0] = "Poet Programmer" -db["Tom Boutell"] = Marshal.dump(entry) -db.close - - -# @@PLEAC@@_14.9 -# example to make data persistent -# uses Marshal from the standard lib -# Stores the data in a simple file, -# see 14.8 on how to store it in a dbm file - -# The BEGIN block is executed before the rest of the script -# we use global variables here because local variables -# will go out of scope and are not accessible from the main script - -BEGIN { - $persistent_store = "persitence.dat" - begin - File.open($persistent_store) do |f| - $stringvariable1 = Marshal.load(f) - $arrayvariable2 = Marshal.load(f) - end - rescue - puts "Can not open #{$persistent_store}" - # Initialisation if this script runs the first time - $stringvariable1 = "" - $arrayvariable2 = [] - end -} - -END { - File.open($persistent_store, "w+") do |f| - Marshal.dump($stringvariable1, f) - Marshal.dump($arrayvariable2, f) - end -} - -# simple test program -puts $stringvariable1 -puts $arrayvariable2 -$stringvariable1 = "Hello World" -$arrayvariable2.push(5) -puts $stringvariable1 -puts $arrayvariable2 - - -# @@PLEAC@@_14.10 -#!/usr/bin/ruby -w -# Ruby has a dbi module with an architecture similar -# to the Perl dbi module: the dbi module provides an unified -# interface and uses specialized drivers for each dbms vendor -# -begin - DBI.connect("DBI:driver:driverspecific", "username", "auth") { - |dbh| - - dbh.do(SQL1) - - dbh.prepare(SQL2){ |sth| - sth.execute - sth.fetch {|row| - # ... - } - } # end of block finishes the statement handle - } # end of block closes the database connection -rescue DBI::DatabaseError => e - puts "dbi error occurred" - puts "Error code: #{e.err}" - puts "Error message: #{e.errstr}" -end - -#!/usr/bin/ruby -w -# dbusers - example for mysql which creates a table, -# fills it with values, retrieves the values back, -# and finally destroys the table. - -require "dbi" - -# replacement for the User::pwnt module -def getpwent - result = [] - File.open("/etc/passwd") {|file| - file.each_line {|line| - next if line.match(/^#/) - cols = line.split(":") - result.push([cols[2], cols[0]]) - } - } - result -end - -begin - DBI.connect("DBI:Mysql:pleacdatabase", "pleac", "pleacpassword") { - |conn| - - conn.do("CREATE TABLE users (uid INT, login CHAR(8))") - - users = getpwent - - conn.prepare("INSERT INTO users VALUES (?,?)") {|sth| - users.each {|entry| - sth.execute(entry[0], entry[1]) - } - } - - conn.execute("SELECT uid, login FROM users WHERE uid < 50") {|sth| - sth.fetch {|row| - puts row.collect {|col| - if col.nil? - "(null)" - else - col - end - }.join(", ") - } - } - - conn.do("DROP TABLE users") - } -rescue DBI::DatabaseError => e - puts "dbi error occurred" - puts "Error code: #{e.err}" - puts "Error message: #{e.errstr}" -end - - -# @@PLEAC@@_15.1 -# This test program demonstrates parsing program arguments. -# It uses the optparse library, which is included with ruby 1.8 -# It handles classic unix style and gnu style options -require 'optparse' - -@debugmode = false -@verbose = false - -ARGV.options do |opts| - opts.banner = "Usage: ruby #{$0} [OPTIONS] INPUTFILES" - - opts.on("-h", "--help", "show this message") { - puts opts - exit - } - # The OptionParser#on method is called with a specification of short - # options, of long options, a data type spezification and user help - # messages for this option. - # The method analyses the given parameter and decides what it is, - # so you can leave out the long option if you don't need it - opts.on("-v", "--[no-]verbose=[FLAG]", TrueClass, "run verbosly") { - |@verbose| # sets @verbose to true or false - } - opts.on("-D", "--DEBUG", TrueClass, "turns on debug mode" ){ - |@debugmode| # sets @debugmode to true - } - opts.on("-c", "--count=NUMBER", Integer, "how many times we do it" ){ - |@count| # sets @count to given integer - } - opts.on("-o", "--output=FILE", String, "file to write output to"){ - |@outputfile| # sets @outputfile to given string - } - opts.parse! -end - -# example to use the options in the main program -puts "Verbose is on" if @verbose -puts "Debugmode is on" if @debugmode -puts "Outfile is #{@outputfile}" if defined? @outputfile -puts "Count is #{@count}" if defined? @count -ARGV.each { |param| - puts "Got parameter #{param}" -} - - -# @@PLEAC@@_15.4 -buf = "\0" * 8 -$stdout.ioctl(0x5413, buf) -ws_row, ws_col, ws_xpixel, ws_ypixel = buf.unpack("S4") - -raise "You must have at least 20 characters" unless ws_col >= 20 -max = 0 -values = (1..5).collect { rand(20) } # generate an array[5] of rand values -for i in values - max = i if max < i -end -ratio = Float(ws_col-12)/max # chars per unit -for i in values - printf "%8.1f %s\n", i, "*" * (ratio*i) -end - -# gives, for example: -# 15.0 ******************************* -# 10.0 ********************* -# 5.0 ********** -# 14.0 ***************************** -# 18.0 ************************************** - - -# @@PLEAC@@_16.1 -output = `program args` # collect output into one multiline string -output = `program args`.split # collect output into array, one line per -element - -readme = IO.popen("ls") -output = "" -while readme.gets do - output += $_ -end -readme.close - -`fsck -y /dev/rsd1a` # BAD AND SCARY in Perl because it's managed by the shell - # I donna in Ruby ... - -# so the "clean and secure" version -readme, writeme = IO.pipe -pid = fork { - # child - $stdout = writeme - readme.close - exec('find', '..') -} -# parent -Process.waitpid(pid, 0) -writeme.close -while readme.gets do - # do something with $_ -end - - -# @@PLEAC@@_16.2 -status = system("xemacs #{myfile}") - -status = system("xemacs", myfile) - -system("cmd1 args | cmd2 | cmd3 >outfile") -system("cmd args <infile >outfile 2>errfile") - -# stop if the command fails -raise "$program exited funny: #{$?}" unless system("cmd", "args1", "args2") - -# get the value of the signal sent to the child -# even if it is a SIGINT or SIGQUIT -system(arglist) -raise "program killed by signal #{$?}" if ($? & 127) != 0 - -pid = fork { - trap("SIGINT", "IGNORE") - exec("sleep", "10") -} -trap ("SIGINT") { - puts "Tsk tsk, no process interruptus" -} -Process.waitpid(pid, 0) - -# Ruby doesn't permit to lie to the program called by a 'system'. -# (ie specify what return argv[0] in C, $0 in Perl/Ruby ...) -# A (dirty) way is to create a link (under Unix), run this link and -# erase it. Somebody has a best idea ? - - -# @@PLEAC@@_16.3 -exec("archive *.data") - -exec("archive", "accounting.data") - -exec("archive accounting.data") - - -# @@PLEAC@@_16.4 -# read the output of a program -IO.popen("ls") {|readme| - while readme.gets do - # ... - end -} -# or -readme = IO.popen("ls") -while readme.gets do - # ... -end -readme.close - -# "write" in a program -IO.popen("cmd args","w") {|pipe| - pipe.puts("data") - pipe.puts("foo") -} - -# close wait for the end of the process -read = IO.popen("sleep 10000") # child goes to sleep -read.close # and the parent goes to lala land - -writeme = IO.popen("cmd args", "w") -writeme.puts "hello" # program will get hello\n on STDIN -writeme.close # program will get EOF on STDIN - -# send in a pager (eg less) all output -$stdout = IO.popen("/usr/bin/less","w") -print "huge string\n" * 10000 - - -# @@PLEAC@@_16.5 -#----------------------------- -def head(lines = 20) - pid = open("|-","w") - if pid == nil - return - else - while gets() do - pid.print - lines -= 1 - break if lines == 0 - end - end - exit -end - -head(100) -while gets() do - print -end -#----------------------------- -1: > Welcome to Linux, version 2.0.33 on a i686 - -2: > - -3: > "The software required `Windows 95 or better', - -4: > so I installed Linux." -#----------------------------- -> 1: Welcome to Linux, Kernel version 2.0.33 on a i686 - -> 2: - -> 3: "The software required `Windows 95 or better', - -> 4: so I installed Linux." -#----------------------------- -#!/usr/bin/ruby -# qnumcat - demo additive output filters - -def number() - pid = open("|-","w") - if pid == nil - return - else - while gets() do pid.printf("%d: %s", $., $_); end - end - exit -end - -def quote() - pid = open("|-","w") - if pid == nil - return - else - while gets() do pid.print "> #{$_}" end - end - exit -end - -number() -quote() - -while gets() do - print -end -$stdout.close -exit - - -# @@PLEAC@@_16.6 -ARGV.map! { |arg| - arg =~ /\.(gz|Z)$/ ? "|gzip -dc #{arg}" : arg -} -for file in ARGV - fh = open(file) - while fh.gets() do - # ....... - end -end -#----------------------------- -ARGV.map! { |arg| - arg =~ %r#^\w+://# ? "|GET #{arg}" : arg # -} -for file in ARGV - fh = open(file) - while fh.gets() do - # ....... - end -end -#----------------------------- -pwdinfo = (`domainname` =~ /^(\(none\))?$/) ? '/etc/passwd' : '|ypcat passwd'; -pwd = open(pwdinfo); -#----------------------------- -puts "File, please? "; -file = gets().chomp(); -fh = open(file); - - -# @@PLEAC@@_16.7 -output = `cmd 2>&1` # with backticks -# or -ph = open("|cmd 2>&1") # with an open pipe -while ph.gets() { } # plus a read -#----------------------------- -output = `cmd 2>/dev/null` # with backticks -# or -ph = open("|cmd 2>/dev/null") # with an open pipe -while ph.gets() { } # plus a read -#----------------------------- -output = `cmd 2>&1 1>/dev/null` # with backticks -# or -ph = open("|cmd 2>&1 1>/dev/null") # with an open pipe -while ph.gets() { } # plus a read -#----------------------------- -output = `cmd 3>&1 1>&2 2>&3 3>&-` # with backticks -# or -ph = open("|cmd 3>&1 1>&2 2>&3 3>&-") # with an open pipe -while ph.gets() { } # plus a read -#----------------------------- -system("program args 1>/tmp/program.stdout 2>/tmp/program.stderr") -#----------------------------- -output = `cmd 3>&1 1>&2 2>&3 3>&-` -#----------------------------- -fd3 = fd1 -fd1 = fd2 -fd2 = fd3 -fd3 = nil -#----------------------------- -system("prog args 1>tmpfile 2>&1") -system("prog args 2>&1 1>tmpfile") -#----------------------------- -# system ("prog args 1>tmpfile 2>&1") -fd1 = "tmpfile" # change stdout destination first -fd2 = fd1 # now point stderr there, too -#----------------------------- -# system("prog args 2>&1 1>tmpfile") -fd2 = fd1 # stderr same destination as stdout -fd1 = "tmpfile" # but change stdout destination -#----------------------------- -# It is often better not to rely on the shell, -# because of portability, possible security problems -# and bigger resource usage. So, it is often better to use the open3 library. -# See below for an example. -# opening stdin, stdout, stderr -require "open3" -stdin, stdout, stderr = Open3.popen('cmd') - - -# @@PLEAC@@_16.8 -#----------------------------- -# Contrary to perl, we don't need to use a module in Ruby -fh = Kernel.open("|" + program, "w+") -fh.puts "here's your input\n" -output = fh.gets() -fh.close() -#----------------------------- -Kernel.open("|program"),"w+") # RIGHT ! -#----------------------------- -# Ruby has already object methods for I/O handles -#----------------------------- -begin - fh = Kernel.open("|" + program_and_options, "w+") -rescue - if ($@ ~= /^open/) - $stderr.puts "open failed : #{$!} \n #{$@} \n" - break - end - raise # reraise unforseen exception -end - - -# @@PLEAC@@_16.13 -#% kill -l -#HUP INT QUIT ILL TRAP ABRT BUS FPE KILL USR1 SEGV USR2 PIPE -#ALRM TERM CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM -#PROF WINCH POLL PWR -#----------------------------- -#% ruby -e 'puts Signal.list.keys.join(" ")' -#PWR USR1 BUS USR2 TERM SEGV KILL POLL STOP SYS TRAP IOT HUP INT # -#WINCH XCPU TTIN CLD TSTP FPE IO TTOU PROF CHLD CONT PIPE ABRT -#VTALRM QUIT ILL XFSZ URG ALRM -#----------------------------- -# After that, the perl script create an hash equivalent to Signal.list, -# and an array. The array can be obtained by : -signame = [] -Signal.list.each { |name, i| signame[i] = name } - - -# @@PLEAC@@_16.14 -Process.kill(9, pid) # send $pid a signal 9 -Process.kill(-1, Process.getpgrp()) # send whole job a signal 1 -Process.kill("USR1", $$) # send myself a SIGUSR1 -Process.kill("HUP", pid1, pid2, pid3) # send a SIGHUP to processes in @pids -#----------------------------- -begin - Process.kill(0, minion) - puts "#{minion} is alive!" -rescue Errno::EPERM # changed uid - puts "#{minion} has escaped my control!"; -rescue Errno::ESRCH - puts "#{minion} is deceased."; # or zombied -rescue - puts "Odd; I couldn't check the status of #{minion} : #{$!}" -end - - -# @@PLEAC@@_16.15 -Kernel.trap("QUIT", got_sig_quit) # got_sig_quit = Proc.new { puts "Quit\n" } -trap("PIPE", "got_sig_quit") # def got_sig_pipe ... -trap("INT") { ouch++ } # increment ouch for every SIGINT -#----------------------------- -trap("INT", "IGNORE") # ignore the signal INT -#----------------------------- -trap("STOP", "DEFAULT") # restore default STOP signal handling - - -# @@PLEAC@@_16.16 -# the signal handler -def ding - trap("INT", "ding") - puts "\aEnter your name!" -end - -# prompt for name, overriding SIGINT -def get_name - save = trap("INT", "ding") - - puts "Kindly Stranger, please enter your name: " - name = gets().chomp() - trap("INT", save) - name -end - - -# @@PLEAC@@_16.21 -# implemented thanks to http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/1760 -require 'timeout' - -# we'll do something vastly more useful than cookbook to demonstrate timeouts -begin - timeout(5) { - waitsec = rand(10) - puts "Let's see if a sleep of #{waitsec} seconds is longer than 5 seconds..." - system("sleep #{waitsec}") - } - puts "Timeout didn't occur" -rescue Timeout::Error - puts "Timed out!" -end - - -# @@PLEAC@@_17.1 -# A basic TCP client connection -require 'socket' -begin - t = TCPSocket.new('www.ruby-lang.org', 'www') -rescue - puts "error: #{$!}" -else - # ... do something with the socket - t.print "GET / HTTP/1.0\n\n" - answer = t.gets(nil) - # and terminate the connection when we're done - t.close -end - -# Using the evil low level socket API -require 'socket' -# create a socket -s = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) -# build the address of the remote machine -sockaddr_server = [Socket::AF_INET, 80, - Socket.gethostbyname('www.ruby-lang.org')[3], - 0, 0].pack("snA4NN") -# connect -begin - s.connect(sockaddr_server) -rescue - puts "error: #{$!}" -else - # ... do something with the socket - s.print "GET / HTTP/1.0\n\n" - # and terminate the connection when we're done - s.close -end - -# TCP connection with management of error (DNS) -require 'socket' -begin - client = TCPSocket.new('does not exists', 'www') -rescue - puts "error: #{$!}" -end - -# TCP connection with a time out -require 'socket' -require 'timeout' -begin - timeout(1) do #the server has one second to answer - client = TCPSocket.new('www.host.com', 'www') - end -rescue - puts "error: #{$!}" -end - - -# @@PLEAC@@_17.12 -require 'socket' - -class Preforker - attr_reader (:child_count) - - def initialize(prefork, max_clients_per_child, port, client_handler) - @prefork = prefork - @max_clients_per_child = max_clients_per_child - @port = port - @child_count = 0 - - @reaper = proc { - trap('CHLD', @reaper) - pid = Process.wait - @child_count -= 1 - } - - @huntsman = proc { - trap('CHLD', 'IGNORE') - trap('INT', 'IGNORE') - Process.kill('INT', 0) - exit - } - - @client_handler=client_handler - end - - def child_handler - trap('INT', 'EXIT') - @client_handler.setUp - # wish: sigprocmask UNblock SIGINT - @max_clients_per_child.times { - client = @server.accept or break - @client_handler.handle_request(client) - client.close - } - @client_handler.tearDown - end - - def make_new_child - # wish: sigprocmask block SIGINT - @child_count += 1 - pid = fork do - child_handler - end - # wish: sigprocmask UNblock SIGINT - end - - def run - @server = TCPserver.open(@port) - trap('CHLD', @reaper) - trap('INT', @huntsman) - loop { - (@prefork - @child_count).times { |i| - make_new_child - } - sleep .1 - } - end -end - -#----------------------------- -#!/usr/bin/ruby - -require 'Preforker' - -class ClientHandler - def setUp - end - - def tearDown - end - - def handle_request(client) - # do stuff - end -end - -server = Preforker.new(1, 100, 3102, ClientHandler.new) -server.run - - -# @@PLEAC@@_18.2 -require 'net/ftp' - -begin - ftp = Net::FTP::new("ftp.host.com") - ftp.login(username,password) - ftp.chdir(directory) - ftp.get(filename) - ftp.put(filename) -rescue Net::FTPError - $stderr.print "FTP failed: " + $! -ensure - ftp.close() if ftp -end - -# A better solution for a local use could be : -Net::FTP::new("ftp.host.com") do |ftp| - ftp.login(username,password) - ftp.chdir(directory) - ftp.get(filename) - ftp.put(filename) -end - -# If you have only one file to get, there is a simple solution : -require 'open-uri' -open("ftp://www.ruby-lang.org/path/filename") do |fh| - # read from filehandle fh -end -#-------------------------------------------- -# to wait a defined time for the connection, -# use the timeout module -require 'timeout' -begin - timeout(30){ - ftp = Net::FTP::new("ftp.host.com") - ftp.debug_mode = true - } -rescue Net::FTPError - $stderr.puts "Couldn't connect." -rescue Timeout::Error - $stderr.puts "Timeout while connecting to server." -end - -begin - ftp.login() -rescue Net::FTPError - $stderr.print "Couldn't authentificate.\n" -end - -begin - ftp.login(username) -rescue Net::FTPError - $stderr.print "Still couldn't authenticate.\n" -end - -begin - ftp.login(username, password) -rescue Net::FTPError - $stderr.print "Couldn't authenticate, even with explicit - username and password.\n" -end - -begin - ftp.login(username, password, account) -rescue Net::FTPError - $stderr.print "No dice. It hates me.\n" -end -#----------------------------- -ftp.put(localfile, remotefile) -#----------------------------- -# Sending data from STDIN is not directly supported -# by the ftp library module. A possible way to do it is to use the -# storlines method directly to send raw commands to the ftp server. -#----------------------------- -ftp.get(remotefile, localfile) -#----------------------------- -ftp.get(remotefile) { |data| puts data } -#----------------------------- -ftp.chdir("/pub/ruby") -print "I'm in the directory ", ftp.pwd(), "\n" -#----------------------------- -ftp.mkdir("/pub/ruby/new_dir") -#----------------------------- -lines = ftp.ls("/pub/ruby/") -# => ["drwxr-xr-x 2 matz users 4096 July 17 1998 1.0", ... ] - -latest = ftp.dir("/pub/ruby/*.tgz").sort.last - -ftp.nlst("/pub/ruby") -# => ["/pub/ruby/1.0", ... ] -#----------------------------- -ftp.quit() - - -# @@PLEAC@@_18.6 -require 'net/telnet' -t = Net::Telnet::new( "Timeout" => 10, - "Prompt" => /%/, - "Host" => host ) -t.login(username, password) -files = t.cmd("ls") -t.print("top") -process_string = t.waitfor(/\d+ processes/) -t.close -#----------------------------- -/[$%#>] \z/n -#----------------------------- -# In case of an error, the telnet module throws an exception. -# For control of the behavior in case of an error, -# you just need to catch the exceptions and do your custom -# error handling. -#----------------------------- -begin - telnet.login(username, password) -rescue TimeoutError - fail "Login failed !\n" -end -#----------------------------- -telnet.waitfor('/--more--/') -#----------------------------- -telnet.waitfor(String => 'greasy smoke', Timeout => 30) - - -# @@PLEAC@@_18.7 -require 'ping' - -puts "#{host} is alive.\n" if Ping.pingecho(host); -#----------------------------- -# the ping module only use TCP ping, not ICMP even if we are root -if Ping.pingecho("kingkong.com") - puts "The giant ape lives!\n"; -else - puts "All hail mighty Gamera, friend of children!\n"; -end - - -# @@PLEAC@@_19.0 -#----------------------------- -# http://www.perl.com/CPAN/ -# http://www.perl.com:8001/bad/mojo.html -# ftp://gatekeeper.dec.com/pub/misc/netlib.tar.Z -# ftp://anonymous@myplace:gatekeeper.dec.com/pub/misc/netlib.tar.Z -# file:///etc/motd -#----------------------------- -# http://mox.perl.com/cgi-bin/program?name=Johann&born=1685 -#----------------------------- -# http://mox.perl.com/cgi-bin/program -#----------------------------- - - -# @@PLEAC@@_19.1 -#!/usr/local/bin/ruby -w -# hiweb - load CGI class to decode information given by web server - -require 'cgi' - -cgi = CGI.new('html3') - -# get a parameter from a form -value = cgi.params['PARAM_NAME'][0] - -# output a document -cgi.out { - cgi.html { - cgi.head { cgi.title { "Howdy there!" } } + - cgi.body { cgi.p { "You typed: " + cgi.tt { - CGI.escapeHTML(value) } } } - } -} - -require 'cgi' -cgi = CGI.new -who = cgi.param["Name"][0] # first param in list -phone = cgi.param["Number"][0] -picks = cgi.param["Choices"] # complete list - -print cgi.header( 'type' => 'text/plain', - 'expires' => Time.now + (3 * 24 * 60 * 60) ) - - -# @@PLEAC@@_19.3 -#!/usr/local/bin/ruby -w -# webwhoami - show web user's id -require 'etc' -print "Content-Type: text/plain\n\n" -print "Running as " + Etc.getpwuid.name + "\n" - -# % ruby -wc cgi-script # just check syntax - -# % ruby -w cgi-script # params from stdin -# (offline mode: enter name=value pairs on standard input) -# name=joe -# number=10 -# ^D - -# % ruby -w cgi-script name=joe number=10 # run with mock form input -# % ruby -d cgi-script name=joe number=10 # ditto, under the debugger - -# POST method script in csh -# % (setenv HTTP_METHOD POST; ruby -w cgi-script name=joe number=10) -# POST method script in sh -# % HTTP_METHOD=POST perl -w cgi-script name=joe number=10 - - -# @@PLEAC@@_19.4 -# ruby has several security levels, the level "1" is similar to perls taint mode. -# It can be switched on by providing the -T command line parameter -# or by setting $SAFE to 1. Setting $SAFE to 2,3 or 4 restricts possible -# harmful operations further. - -#!/usr/bin/ruby -T -$SAFE = 1 -File.open(ARGV[0], "w") -# ruby warns with: -# taint1.rb:2:in `initialize': Insecure operation - initialize (SecurityError) - -$SAFE = 1 -file = ARGV[0] -unless /^([\w.-]+)$/.match(file) - raise "filename #{file} has invalid characters" -end -file = $1 -# In ruby, even the back reference from a regular expression stays tainted. -# you need to explicitly untaint the variable: -file.untaint -File.open(file, "w") - -# Race condition exists like in perl: -unless File.exists(filename) # Wrong because of race condition - File.open(filename, "w") -end - - -# @@PLEAC@@_19.8 -url = "http://pleac.sourceforge.net/pleac_ruby/" -print "Location: #{url}\r\n\r\n" -exit - -#!/usr/bin/ruby -require 'cgi' - -cgi = CGI.new -oreo = CGI::Cookie.new('name' => 'filling', - 'value' => 'vanilla creme', - 'expires' => Time.now + (3 * 30 * 24 * 60 * 60), - 'domain' => '.pleac.sourceforge.net') - -whither = 'http://pleac.sourceforge.net/pleac_ruby/cgiprogramming.html' - -cgi.out('cookie' => oreo, - 'Location' => whither){""} - -#!/usr/bin/ruby -# os_snipe - redirect to a Jargon File entry about current OS -dir = 'http://www.elsewhere.org/jargon/html/entry' - -agent = ENV['HTTP_USER_AGENT'] - -page = case - when agent =~ /Mac/: 'Macintrash.html' - when agent =~ /Win(dows )?NT/: 'evil_and_rude.html' - when agent =~ /Win|MSIE|WebTV/: 'Microsloth_Windows.html' - when agent =~ /Linux/: 'Linux.html' - when agent =~ /HP-UX/: 'HP-SUX.html' - when agent =~ /SunOS/: 'ScumOS.html' - else 'Appendix_B.html' -end - -print "Location: #{dir}/#{page}\n\n" - -require 'cgi' -cgi = CGI.new -cgi.out('status' => '204 No response'){""} -# this produces: -# Status: 204 No response -# Content-Type: text/html -# Content-Length: 0 -# <blank line here> - - -# @@PLEAC@@_19.10 -preference_value = cgi.cookies["preference name"][0] - -packed_cookie = CGI::Cookie.new("name" => "preference name", - "value" => "whatever you'd like", - "expires" => Time.local(Time.now.year + 2, - Time.now.mon, Time.now.day, Time.now.hour, Time.now.min, Time.now.sec) ) - -cgi.header("cookie" => [packed_cookie]) - -#!/usr/local/bin/ruby -w -# ic_cookies - sample CGI script that uses a cookie -require 'cgi' - -cgi = CGI.new('html3') - -cookname = "favorite ice cream" -favorite = cgi.params["flavor"][0] -tasty = cgi.cookies[cookname][0] || 'mint' - -unless favorite - cgi.out { - cgi.html { - cgi.head { cgi.title { "Ice Cookies" } } + - cgi.body { - cgi.h1 { "Hello Ice Cream" } + - cgi.hr + - cgi.form { - cgi.p { "Please select a flavor: " + - cgi.text_field("flavor", tasty ) } - } + - cgi.hr - } - } - } -else - cookie = CGI::Cookie.new( "name" => cookname, - "value" => favorite, - "expires" => Time.local(Time.now.year + 2, -Time.now.mon, Time.now.day, Time.now.hour, Time.now.min, Time.now.sec) ) - cgi.out("cookie" => [cookie]) { - cgi.html { - cgi.head { cgi.title { "Ice Cookies" } } + - cgi.body { - cgi.h1 { "Hello Ice Cream" } + - cgi.p { "You chose as your favorite flavor `#{favorite}'." } - } - } - } -end - - -# @@PLEAC@@_20.9 -def templatefile(filename, fillings) - aFile = File.new(filename, "r") - text = aFile.read() - aFile.close() - pattern = Regexp.new('%%(.*?)%%') - text.gsub!(pattern) { - fillings[$1] || "" - } - text -end - -fields = { - 'username' => whats_his_name, - 'count' => login_count, - 'total' => minutes_used -} -puts templatefile('simple.template', fields) - -# @@INCOMPLETE@@ -# An example using databases is missing - - diff --git a/tests/examplefiles/test.html b/tests/examplefiles/test.html index 4527a3fb..52adca81 100644 --- a/tests/examplefiles/test.html +++ b/tests/examplefiles/test.html @@ -2783,3559 +2783,6 @@ pre.syntax { padding: 5px; margin-top: 0px; } ) <span class="cm"># -*- coding: utf-8 -*-</span> -<span class="st st-db">"""</span><span class="st"> - pocoo.pkg.core.i18n - ~~~~~~~~~~~~~~~~~~~ - - Pocoo internationalization components. - - :copyright: 2006 by Armin Ronacher. - :license: GNU GPL, see LICENSE for more details. -</span><span class="st st-db">"""</span> -<span class="kw">import </span><span class="cls">gettext</span> -<span class="kw">from </span><span class="cls">pocoo.application</span><span class="kw"> import</span> <span class="name">RequestWrapper</span> - -<span class="kw">from </span><span class="cls">jinja.nodes</span><span class="kw"> import</span> <span class="name">Node</span>, <span class="name">KeywordNode</span>, <span class="name">VariableNode</span>, <span class="name">ValueNode</span>, <span class="name">CollectionNode</span> -<span class="kw">from </span><span class="cls">jinja.base</span><span class="kw"> import</span> <span class="name">TOKEN_TEXT</span>, <span class="name">TOKEN_VAR</span> - -<span class="kw">from </span><span class="cls">jinja.exceptions</span><span class="kw"> import</span> <span class="name">TemplateSyntaxError</span> -<span class="kw">from </span><span class="cls">cStringIO</span><span class="kw"> import</span> <span class="name">StringIO</span> - - -<span class="kw">class </span><span class="cls">TranslatableTag</span>(<span class="name">Node</span>): - <span class="st st-db">"""</span><span class="st"> - - Translatable Tag - ================ - - Usage:: - - {% trans %} - somestring - {% trans %} - - Or:: - - {% trans "string" %} - </span><span class="st st-db">"""</span> - - <span class="name">rules</span> <span class="op">=</span> { - <span class="st st-sg">'</span><span class="st">long</span><span class="st st-sg">'</span>: [<span class="name">KeywordNode</span>(<span class="st st-sg">'</span><span class="st">trans</span><span class="st st-sg">'</span>)], - <span class="st st-sg">'</span><span class="st">plural</span><span class="st st-sg">'</span>: [<span class="name">KeywordNode</span>(<span class="st st-sg">'</span><span class="st">trans</span><span class="st st-sg">'</span>), <span class="name">KeywordNode</span>(<span class="st st-sg">'</span><span class="st">pluralizing</span><span class="st st-sg">'</span>), - <span class="name">VariableNode</span>()], - <span class="st st-sg">'</span><span class="st">short</span><span class="st st-sg">'</span>: [<span class="name">KeywordNode</span>(<span class="st st-sg">'</span><span class="st">trans</span><span class="st st-sg">'</span>), <span class="name">ValueNode</span>(), <span class="name">CollectionNode</span>()] - } - - <span class="kw">def </span><span class="fun">__init__</span>(<span class="bn bn-pseudo">self</span>, <span class="name">parser</span>, <span class="name">matched_tag</span>, <span class="name">handler_args</span>, <span class="name">stack</span>): - <span class="bn bn-pseudo">self</span>.<span class="name">_body_pl</span> <span class="op">=</span> [] - <span class="bn bn-pseudo">self</span>.<span class="name">_vars_pl</span> <span class="op">=</span> {} - <span class="kw">if</span> <span class="name">matched_tag</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">short</span><span class="st st-sg">'</span>: - <span class="bn bn-pseudo">self</span>.<span class="name">_body_sg</span> <span class="op">=</span> [<span class="name">handler_args</span>[<span class="nb nb-int">1</span>].<span class="name">resolve</span>()] - <span class="bn bn-pseudo">self</span>.<span class="name">_vars_sg</span> <span class="op">=</span> <span class="name">handler_args</span>[<span class="nb nb-int">2</span>] - <span class="kw">else</span>: - <span class="bn bn-pseudo">self</span>.<span class="name">_body_sg</span>, <span class="bn bn-pseudo">self</span>.<span class="name">_vars_sg</span>, <span class="bn bn-pseudo">self</span>.<span class="name">_body_pl</span>, <span class="bn bn-pseudo">self</span>.<span class="name">_vars_pl</span> <span class="op">=</span> \ - <span class="bn bn-pseudo">self</span>.<span class="name">_forkparse</span>(<span class="name">parser</span>) - <span class="kw">if</span> <span class="name">matched_tag</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">plural</span><span class="st st-sg">'</span>: - <span class="bn bn-pseudo">self</span>.<span class="name">_indicator</span> <span class="op">=</span> <span class="name">handler_args</span>[<span class="nb nb-int">2</span>] - <span class="bn bn-pseudo">self</span>.<span class="name">msgid</span> <span class="op">=</span> (<span class="st st-sg">''</span>.<span class="name">join</span>(<span class="bn bn-pseudo">self</span>.<span class="name">_body_sg</span>)).<span class="name">strip</span>() - <span class="bn bn-pseudo">self</span>.<span class="name">msgid_plural</span> <span class="op">=</span> (<span class="st st-sg">''</span>.<span class="name">join</span>(<span class="bn bn-pseudo">self</span>.<span class="name">_body_pl</span>)).<span class="name">strip</span>() - <span class="name">Node</span>.<span class="name">__init__</span>(<span class="bn bn-pseudo">self</span>) - - <span class="kw">def </span><span class="fun">_forkparse</span>(<span class="bn bn-pseudo">self</span>, <span class="name">parser</span>): - <span class="name">lib</span> <span class="op">=</span> <span class="name">parser</span>.<span class="name">library</span> - - <span class="name">sg</span> <span class="op">=</span> []; <span class="name">vars_sg</span> <span class="op">=</span> {} - <span class="name">pl</span> <span class="op">=</span> []; <span class="name">vars_pl</span> <span class="op">=</span> {} - <span class="name">out</span> <span class="op">=</span> <span class="name">sg</span>; <span class="name">vars_out</span> <span class="op">=</span> <span class="name">vars_sg</span> - - <span class="kw">while</span> <span class="name">parser</span>.<span class="name">tokens</span>: - <span class="name">token</span> <span class="op">=</span> <span class="name">parser</span>.<span class="name">pop_token</span>() - <span class="kw">if</span> <span class="name">token</span>.<span class="name">token_type</span> <span class="op">==</span> <span class="name">TOKEN_VAR</span>: - <span class="name">var</span> <span class="op">=</span> <span class="name">lib</span>.<span class="name">parse</span>(<span class="name">parser</span>, <span class="name">u</span><span class="st st-sg">'</span><span class="st">print </span><span class="st st-int">%s</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">token</span>.<span class="name">contents</span>) - <span class="name">var_key</span> <span class="op">=</span> <span class="name">token</span>.<span class="name">contents</span>.<span class="name">split</span>(<span class="st st-sg">'</span><span class="st">|</span><span class="st st-sg">'</span>)[<span class="nb nb-int">0</span>].<span class="name">strip</span>() - <span class="name">vars_out</span>[<span class="name">var_key</span>] <span class="op">=</span> <span class="name">var</span> - - <span class="name">out</span>.<span class="name">append</span>(<span class="st st-sg">'</span><span class="st st-int">%%</span><span class="st">(</span><span class="st st-int">%s</span><span class="st">)s</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">var_key</span>) - <span class="kw">elif</span> <span class="name">token</span>.<span class="name">token_type</span> <span class="op">==</span> <span class="name">TOKEN_TEXT</span>: - <span class="name">lines</span> <span class="op">=</span> <span class="name">token</span>.<span class="name">contents</span>.<span class="name">splitlines</span>() - <span class="cm"># XXX: this protects whitespaces between different tokens (really?)</span> - - <span class="name">text</span> <span class="op">=</span> <span class="name">u</span><span class="st st-sg">'</span><span class="st st-esc">\n</span><span class="st st-sg">'</span>.<span class="name">join</span>(<span class="name">lines</span>[:<span class="nb nb-int">1</span>] <span class="op">+</span> [<span class="name">line</span>.<span class="name">lstrip</span>() <span class="kw">for</span> <span class="name">line</span> <span class="op op-word">in</span> <span class="name">lines</span>[<span class="nb nb-int">1</span>:]]) - <span class="name">out</span>.<span class="name">append</span>(<span class="name">text</span>) - <span class="kw">else</span>: - <span class="kw">if</span> <span class="name">token</span>.<span class="name">contents</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">plural</span><span class="st st-sg">'</span>: - <span class="kw">if</span> <span class="name">out</span> <span class="op op-word">is</span> <span class="name">sg</span>: - <span class="name">out</span> <span class="op">=</span> <span class="name">pl</span> - - <span class="name">vars_out</span> <span class="op">=</span> <span class="name">vars_pl</span> - <span class="kw">else</span>: - <span class="kw">raise</span> <span class="name">TemplateSyntaxError</span>(<span class="st st-sg">'</span><span class="st">plural used twice</span><span class="st st-sg">'</span>) - <span class="kw">elif</span> <span class="name">token</span>.<span class="name">contents</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">endtrans</span><span class="st st-sg">'</span>: - <span class="kw">break</span> - - <span class="kw">else</span>: - <span class="kw">raise</span> <span class="name">TemplateSyntaxError</span>(<span class="st st-sg">'</span><span class="st">you can</span><span class="st st-esc">\'</span><span class="st">t use blocks inside of a </span><span class="st st-sg">'</span> - <span class="st st-sg">'</span><span class="st">`trans` tag.</span><span class="st st-sg">'</span>) - <span class="kw">return</span> <span class="name">sg</span>, <span class="name">vars_sg</span>, <span class="name">pl</span>, <span class="name">vars_pl</span> - - <span class="kw">def </span><span class="fun">render</span>(<span class="bn bn-pseudo">self</span>, <span class="name">context</span>): - <span class="name">req</span> <span class="op">=</span> <span class="name">context</span>[<span class="st st-sg">'</span><span class="st">REQUEST</span><span class="st st-sg">'</span>] - <span class="kw">if</span> <span class="bn bn-pseudo">self</span>.<span class="name">msgid_plural</span>: - <span class="name">var</span> <span class="op">=</span> <span class="nb nb-int">1</span> - - <span class="kw">if</span> <span class="bn">hasattr</span>(<span class="bn bn-pseudo">self</span>, <span class="st st-sg">'</span><span class="st">_indicator</span><span class="st st-sg">'</span>): - <span class="name">var</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">_indicator</span>.<span class="name">resolve</span>(<span class="name">context</span>) - <span class="name">rv</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span>(<span class="bn bn-pseudo">self</span>.<span class="name">msgid</span>, <span class="bn bn-pseudo">self</span>.<span class="name">msgid_plural</span>, <span class="name">var</span>) - <span class="kw">else</span>: - <span class="name">rv</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span>(<span class="bn bn-pseudo">self</span>.<span class="name">msgid</span>) - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="bn bn-pseudo">self</span>.<span class="name">_vars_sg</span>, <span class="bn">list</span>): - <span class="kw">return</span> <span class="name">rv</span> <span class="op">%</span> <span class="bn">tuple</span>(<span class="name">v</span>.<span class="name">render</span>(<span class="name">context</span>) <span class="kw">for</span> <span class="name">v</span> <span class="op op-word">in</span> <span class="bn bn-pseudo">self</span>.<span class="name">_vars_sg</span>) - <span class="name">args</span> <span class="op">=</span> <span class="bn">dict</span>((<span class="name">n</span>, <span class="name">v</span>.<span class="name">render</span>(<span class="name">context</span>)) <span class="kw">for</span> <span class="name">n</span>, <span class="name">v</span> <span class="op op-word">in</span> <span class="bn bn-pseudo">self</span>.<span class="name">_vars_sg</span>.<span class="name">iteritems</span>()) - <span class="name">args</span>.<span class="name">update</span>(<span class="bn bn-pseudo">self</span>.<span class="name">_vars_pl</span>) - <span class="kw">return</span> <span class="name">rv</span> <span class="op">%</span> <span class="name">args</span> - - -<span class="kw">def </span><span class="fun">load_translations</span>(<span class="name">ctx</span>, <span class="name">lng</span>): - <span class="st st-db">"""</span><span class="st"> - loads all available translations for the given language. - </span><span class="st st-db">"""</span> - <span class="name">result</span> <span class="op">=</span> [] - <span class="kw">for</span> <span class="name">res</span> <span class="op op-word">in</span> <span class="name">ctx</span>.<span class="name">pkgmanager</span>.<span class="name">get_resources</span>(<span class="st st-sg">'</span><span class="st">i18n</span><span class="st st-sg">'</span>, <span class="st st-sg">''</span>, <span class="name">lng</span>): - <span class="name">f</span> <span class="op">=</span> <span class="name">StringIO</span>(<span class="name">res</span>) - <span class="name">result</span>.<span class="name">append</span>(<span class="name">gettext</span>.<span class="name">GNUTranslations</span>(<span class="name">f</span>)) - <span class="kw">return</span> <span class="name">result</span> - - -<span class="kw">def </span><span class="fun">parse_http_accept_language</span>(<span class="name">s</span>): - <span class="st st-db">"""</span><span class="st"> - Return the accepted languages as set in the user browser. - </span><span class="st st-db">"""</span> - <span class="name">result</span> <span class="op">=</span> [] - <span class="kw">for</span> <span class="name">item</span> <span class="op op-word">in</span> <span class="name">s</span>.<span class="name">split</span>(<span class="st st-sg">'</span><span class="st">,</span><span class="st st-sg">'</span>): - <span class="name">lng</span> <span class="op">=</span> <span class="name">item</span>.<span class="name">split</span>(<span class="st st-sg">'</span><span class="st">;</span><span class="st st-sg">'</span>, <span class="nb nb-int">1</span>)[<span class="nb nb-int">0</span>] - <span class="name">lng</span> <span class="op">=</span> <span class="name">lng</span>.<span class="name">lower</span>() - <span class="name">result</span>.<span class="name">append</span>(<span class="name">lng</span>) - <span class="kw">if</span> <span class="st st-sg">'</span><span class="st">-</span><span class="st st-sg">'</span> <span class="op op-word">in</span> <span class="name">lng</span>: - <span class="name">result</span>.<span class="name">append</span>(<span class="name">lng</span>.<span class="name">split</span>(<span class="st st-sg">'</span><span class="st">-</span><span class="st st-sg">'</span>)[<span class="nb nb-int">0</span>]) - <span class="kw">return</span> <span class="name">result</span> - - -<span class="kw">def </span><span class="fun">get_request_languages</span>(<span class="name">req</span>): - <span class="st st-db">"""</span><span class="st"> - Return the list of languages a request could handle. - </span><span class="st st-db">"""</span> - <span class="kw">if</span> <span class="bn">hasattr</span>(<span class="name">req</span>, <span class="st st-sg">'</span><span class="st">user</span><span class="st st-sg">'</span>) <span class="op op-word">and</span> <span class="name">req</span>.<span class="name">user</span> <span class="op op-word">is</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">None</span> \ - <span class="op op-word">and</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">language</span>: - <span class="name">lng</span> <span class="op">=</span> [<span class="name">req</span>.<span class="name">user</span>.<span class="name">language</span>] - <span class="kw">else</span>: - <span class="name">lng</span> <span class="op">=</span> [] - <span class="cm"># before checking the HTTP_ACCEPT_LANGUAGE check for</span> - - <span class="cm"># a forced language.</span> - <span class="name">forced</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">general</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">language</span><span class="st st-sg">'</span>, <span class="st st-sg">''</span>) - <span class="kw">if</span> <span class="name">forced</span> <span class="op op-word">and</span> <span class="name">forced</span> <span class="op">!=</span> <span class="st st-sg">'</span><span class="st">auto</span><span class="st st-sg">'</span> <span class="op op-word">and</span> <span class="name">forced</span> <span class="op op-word">not</span> <span class="op op-word">in</span> <span class="name">lng</span>: - <span class="name">lng</span>.<span class="name">append</span>(<span class="name">forced</span>) - <span class="cm"># now prase the HTTP_ACCEPT_LANGUAGE string and add</span> - - <span class="cm"># the languages to the list of accepted languages.</span> - <span class="name">language_string</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">environ</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">HTTP_ACCEPT_LANGUAGE</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">en</span><span class="st st-sg">'</span>) - <span class="kw">for</span> <span class="name">item</span> <span class="op op-word">in</span> <span class="name">parse_http_accept_language</span>(<span class="name">language_string</span>): - <span class="kw">if</span> <span class="name">item</span> <span class="op op-word">not</span> <span class="op op-word">in</span> <span class="name">lng</span>: - <span class="name">lng</span>.<span class="name">append</span>(<span class="name">item</span>) - <span class="cm"># add "en" if not set</span> - - <span class="kw">if</span> <span class="st st-sg">'</span><span class="st">en</span><span class="st st-sg">'</span> <span class="op op-word">not</span> <span class="op op-word">in</span> <span class="name">lng</span>: - <span class="name">lng</span>.<span class="name">append</span>(<span class="st st-sg">'</span><span class="st">en</span><span class="st st-sg">'</span>) - <span class="kw">return</span> <span class="name">lng</span> - - -<span class="kw">class </span><span class="cls">Translator</span>(<span class="bn">object</span>): - <span class="st st-db">"""</span><span class="st"> - A callable that allows you to use pluralized and - non pluralized strings. A translator instance always - exists on the request object as ``req.gettext``:: - - _ = req.gettext - _('Hello World!', 'Hello Worlds!', 2) - - The example above defines a singular and pluralized - version of "Hello World". The number two tells the - gettext system that we have two worlds in that case. - Some languages provide more than just one plural form - so this number allows it to decide which plural form - to use. - - If you just have a singular string you can use this:: - - _ = req.gettext - _('This is just a small example') - - Strings marked as ``_()`` automagically get tracked - by the gettext translation generator script. - </span><span class="st st-db">"""</span> - - <span class="kw">def </span><span class="fun">__init__</span>(<span class="bn bn-pseudo">self</span>, <span class="name">translations</span>, <span class="name">languages</span>): - <span class="cm">#XXX: should we cache that?</span> - <span class="bn bn-pseudo">self</span>.<span class="name">translator</span> <span class="op">=</span> <span class="name">gettext</span>.<span class="name">NullTranslations</span>() - <span class="kw">for</span> <span class="name">lng</span> <span class="op op-word">in</span> <span class="name">languages</span>: - <span class="kw">for</span> <span class="name">translation</span> <span class="op op-word">in</span> <span class="name">translations</span>[<span class="name">lng</span>]: - <span class="bn bn-pseudo">self</span>.<span class="name">translator</span>.<span class="name">add_fallback</span>(<span class="name">translation</span>) - <span class="bn bn-pseudo">self</span>.<span class="name">languages</span> <span class="op">=</span> <span class="name">languages</span> - - <span class="kw">def </span><span class="fun">__call__</span>(<span class="bn bn-pseudo">self</span>, <span class="name">msg</span>, <span class="name">plural</span><span class="op">=</span><span class="bn bn-pseudo">None</span>, <span class="name">n</span><span class="op">=</span><span class="nb nb-int">1</span>): - <span class="kw">if</span> <span class="name">plural</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">translator</span>.<span class="name">ugettext</span>(<span class="name">msg</span>) - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">translator</span>.<span class="name">ungettext</span>(<span class="name">msg</span>, <span class="name">plural</span>, <span class="name">n</span>) - - <span class="kw">def </span><span class="fun">__repr__</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="st st-sg">'</span><span class="st"><</span><span class="st st-int">%s</span><span class="st"> </span><span class="st st-int">%r</span><span class="st">></span><span class="st st-sg">'</span> <span class="op">%</span> ( - <span class="bn bn-pseudo">self</span>.<span class="name">__class__</span>.<span class="name">__name__</span>, - <span class="bn bn-pseudo">self</span>.<span class="name">languages</span> - - ) - - -<span class="name">dummy_translate</span> <span class="op">=</span> <span class="name">Translator</span>({}, []) - - -<span class="kw">class </span><span class="cls">I18nWrapper</span>(<span class="name">RequestWrapper</span>): - - <span class="kw">def </span><span class="fun">__init__</span>(<span class="bn bn-pseudo">self</span>, <span class="name">ctx</span>): - <span class="bn">super</span>(<span class="name">I18nWrapper</span>, <span class="bn bn-pseudo">self</span>).<span class="name">__init__</span>(<span class="name">ctx</span>) - <span class="bn bn-pseudo">self</span>.<span class="name">translations</span> <span class="op">=</span> {} - - <span class="kw">def </span><span class="fun">get_priority</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="nb nb-int">4</span> - - <span class="kw">def </span><span class="fun">process_request</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="st st-db">"""</span><span class="st">Attach a gettext and dummy translate method to the request.</span><span class="st st-db">"""</span> - <span class="name">languages</span> <span class="op">=</span> <span class="name">get_request_languages</span>(<span class="name">req</span>) - <span class="name">req</span>.<span class="name">accept_languages</span> <span class="op">=</span> <span class="name">languages</span> - - <span class="kw">for</span> <span class="name">lng</span> <span class="op op-word">in</span> <span class="name">languages</span>: - <span class="kw">if</span> <span class="name">lng</span> <span class="op op-word">not</span> <span class="op op-word">in</span> <span class="bn bn-pseudo">self</span>.<span class="name">translations</span>: - <span class="bn bn-pseudo">self</span>.<span class="name">translations</span>[<span class="name">lng</span>] <span class="op">=</span> <span class="name">load_translations</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, <span class="name">lng</span>) - <span class="name">req</span>.<span class="name">gettext</span> <span class="op">=</span> <span class="name">Translator</span>(<span class="bn bn-pseudo">self</span>.<span class="name">translations</span>, <span class="name">languages</span>) - <span class="name">req</span>.<span class="name">dummy_translate</span> <span class="op">=</span> <span class="name">dummy_translate</span> - - <span class="kw">def </span><span class="fun">process_response</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">resp</span>): - <span class="kw">return</span> <span class="name">resp</span> -<span class="cm"># -*- coding: utf-8 -*-</span> - -<span class="st st-db">"""</span><span class="st"> - pocoo.pkg.core - ~~~~~~~~~~~~~~ - - The Pocoo core component. - - :copyright: 2006 by the Pocoo team. - :license: GNU GPL, see LICENSE for more details. -</span><span class="st st-db">"""</span> -<span class="cm"># -*- coding: utf-8 -*-</span> -<span class="st st-db">"""</span><span class="st"> - pocoo.pkg.core.l10n - ~~~~~~~~~~~~~~~~~~~ - - Pocoo localisation module. - - :copyright: 2006 by Armin Ronacher. - :license: GNU GPL, see LICENSE for more details. -</span><span class="st st-db">"""</span> -<span class="kw">from </span><span class="cls">pocoo.utils.text</span><span class="kw"> import</span> <span class="name">split_format</span> - -<span class="kw">from </span><span class="cls">datetime</span><span class="kw"> import</span> <span class="name">datetime</span> -<span class="kw">import </span><span class="cls">time</span> -<span class="kw">from </span><span class="cls">calendar</span><span class="kw"> import</span> <span class="name">monthrange</span> - -<span class="cm"># Dateformat Constants</span> -<span class="name">DEFAULT_DATE_FORMAT</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">%a, </span><span class="st st-int">%d</span><span class="st"> %b %Y</span><span class="st st-sg">'</span> -<span class="name">DEFAULT_TIME_FORMAT</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">%H:%M</span><span class="st st-sg">'</span> - -<span class="name">DEFAULT_DATETIME_FORMAT</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">%a, </span><span class="st st-int">%d</span><span class="st"> %b %Y %H:%M</span><span class="st st-sg">'</span> - -<span class="cm"># Timedelta Constants</span> -<span class="name">TIME_DELTA_UNITS</span> <span class="op">=</span> [ - (<span class="nb nb-int">3600</span> <span class="op">*</span> <span class="nb nb-int">24</span> <span class="op">*</span> <span class="nb nb-int">365</span>, <span class="st st-sg">'</span><span class="st">y</span><span class="st st-sg">'</span>), - (<span class="nb nb-int">3600</span> <span class="op">*</span> <span class="nb nb-int">24</span> <span class="op">*</span> <span class="nb nb-int">30</span>, <span class="st st-sg">'</span><span class="st">M</span><span class="st st-sg">'</span>), - (<span class="nb nb-int">3600</span> <span class="op">*</span> <span class="nb nb-int">24</span> <span class="op">*</span> <span class="nb nb-int">7</span>, <span class="st st-sg">'</span><span class="st">w</span><span class="st st-sg">'</span>), - (<span class="nb nb-int">3600</span> <span class="op">*</span> <span class="nb nb-int">24</span>, <span class="st st-sg">'</span><span class="st">d</span><span class="st st-sg">'</span>), - (<span class="nb nb-int">3600</span>, <span class="st st-sg">'</span><span class="st">h</span><span class="st st-sg">'</span>), - (<span class="nb nb-int">60</span>, <span class="st st-sg">'</span><span class="st">m</span><span class="st st-sg">'</span>) -] - - -<span class="cm"># Gettext Helper</span> -<span class="name">_</span> <span class="op">=</span> <span class="kw">lambda</span> <span class="name">x</span>: <span class="name">x</span> - -<span class="kw">class </span><span class="cls">DateFormatter</span>(<span class="bn">object</span>): - <span class="st st-db">"""</span><span class="st"> - - TODO: write documentation about the various format codes. - </span><span class="st st-db">"""</span> - <span class="cm"># XXX: use "caching" of lists with static strings (weekdays...)</span> - - <span class="cm"># allow format_X method names</span> - <span class="cm"># pylint: disable-msg=C0103</span> - - <span class="name">WEEKDAYS_ABBR</span> <span class="op">=</span> [<span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Mon</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Tue</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Wed</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Thu</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Fri</span><span class="st st-sg">'</span>), - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Sat</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Sun</span><span class="st st-sg">'</span>)] - <span class="name">WEEKDAYS_FULL</span> <span class="op">=</span> [<span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Monday</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Tuesday</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Wednesday</span><span class="st st-sg">'</span>), - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Thursday</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Friday</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Saturday</span><span class="st st-sg">'</span>), - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Sunday</span><span class="st st-sg">'</span>)] - <span class="name">MONTHS_ABBR</span> <span class="op">=</span> [<span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Jan</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Feb</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Mar</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Apr</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">May:abbr</span><span class="st st-sg">'</span>), - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Jun</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Jul</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Aug</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Sep</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Oct</span><span class="st st-sg">'</span>), - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Nov</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Dec</span><span class="st st-sg">'</span>)] - <span class="name">MONTHS_FULL</span> <span class="op">=</span> [<span class="name">_</span>(<span class="st st-sg">'</span><span class="st">January</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">February</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">March</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">April</span><span class="st st-sg">'</span>), - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">May:full</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">June</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">July</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">August</span><span class="st st-sg">'</span>), - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">September</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">October</span><span class="st st-sg">'</span>), <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">November</span><span class="st st-sg">'</span>), - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">December</span><span class="st st-sg">'</span>)] - - <span class="kw">def </span><span class="fun">__init__</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">dateobj</span>): - <span class="bn bn-pseudo">self</span>.<span class="name">req</span> <span class="op">=</span> <span class="name">req</span> - - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="name">dateobj</span>, <span class="name">datetime</span>): - <span class="bn bn-pseudo">self</span>.<span class="name">date</span> <span class="op">=</span> <span class="name">dateobj</span> - - <span class="kw">elif</span> <span class="bn">isinstance</span>(<span class="name">dateobj</span>, <span class="bn">int</span>): - <span class="bn bn-pseudo">self</span>.<span class="name">date</span> <span class="op">=</span> <span class="name">datetime</span>.<span class="name">utcfromtimestamp</span>(<span class="name">dateobj</span>) - <span class="kw">elif</span> <span class="bn">isinstance</span>(<span class="name">dateobj</span>, <span class="name">time</span>.<span class="name">struct_time</span>): - <span class="bn bn-pseudo">self</span>.<span class="name">date</span> <span class="op">=</span> <span class="name">datetime</span>(<span class="name">dateobj</span>[:<span class="nb nb-int">7</span>]) - <span class="kw">elif</span> <span class="name">dateobj</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="bn bn-pseudo">self</span>.<span class="name">date</span> <span class="op">=</span> <span class="name">datetime</span>(<span class="nb nb-int">1</span>, <span class="nb nb-int">1</span>, <span class="nb nb-int">1</span>) - <span class="kw">else</span>: - <span class="kw">raise</span> <span class="exc">TypeError</span>(<span class="st st-sg">'</span><span class="st st-int">%r</span><span class="st"> is not a valid time object</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">dateobj</span>) - - <span class="kw">def </span><span class="fun">format</span>(<span class="bn bn-pseudo">self</span>, <span class="name">formatstring</span>): - <span class="name">bits</span> <span class="op">=</span> [] - <span class="kw">for</span> <span class="name">bit</span> <span class="op op-word">in</span> <span class="name">split_format</span>(<span class="name">formatstring</span>): - <span class="kw">if</span> <span class="name">bit</span>.<span class="name">startswith</span>(<span class="st st-sg">'</span><span class="st">%</span><span class="st st-sg">'</span>): - <span class="name">handler</span> <span class="op">=</span> <span class="bn">getattr</span>(<span class="bn bn-pseudo">self</span>, <span class="st st-sg">'</span><span class="st">format_</span><span class="st st-sg">'</span> <span class="op">+</span> <span class="name">bit</span>[<span class="nb nb-int">1</span>], <span class="bn bn-pseudo">None</span>) - <span class="kw">if</span> <span class="name">handler</span> <span class="op op-word">is</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">None</span>: - <span class="name">bits</span>.<span class="name">append</span>(<span class="name">handler</span>()) - <span class="kw">else</span>: - <span class="name">bits</span>.<span class="name">append</span>(<span class="name">bit</span>) - <span class="kw">else</span>: - <span class="name">bits</span>.<span class="name">append</span>(<span class="name">bit</span>) - <span class="kw">return</span> <span class="name">u</span><span class="st st-sg">''</span>.<span class="name">join</span>(<span class="name">bits</span>) - - <span class="kw">def </span><span class="fun">format_a</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">abbreviated weekday name.</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">req</span>.<span class="name">gettext</span>(<span class="bn bn-pseudo">self</span>.<span class="name">WEEKDAYS_ABBR</span>[<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">weekday</span>()]) - - <span class="kw">def </span><span class="fun">format_A</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">full weekday name.</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">req</span>.<span class="name">gettext</span>(<span class="bn bn-pseudo">self</span>.<span class="name">WEEKDAYS_FULL</span>[<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">weekday</span>()]) - - <span class="kw">def </span><span class="fun">format_b</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">abbreviated month name.</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">req</span>.<span class="name">gettext</span>(<span class="bn bn-pseudo">self</span>.<span class="name">MONTHS_ABBR</span>[<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">month</span> <span class="op">-</span> <span class="nb nb-int">1</span>]) - - <span class="kw">def </span><span class="fun">format_B</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">full month name.</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">req</span>.<span class="name">gettext</span>(<span class="bn bn-pseudo">self</span>.<span class="name">MONTHS_FULL</span>[<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">month</span> <span class="op">-</span> <span class="nb nb-int">1</span>]) - - <span class="kw">def </span><span class="fun">format_d</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Day of the month as a decimal number [01,31].</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn">unicode</span>(<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">day</span>) - - <span class="kw">def </span><span class="fun">format_H</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Hour (24-hour clock) as a decimal number [00,23].</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn">unicode</span>(<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">hour</span>) - - <span class="kw">def </span><span class="fun">format_I</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Hour (12-hour clock) as a decimal number [01,12].</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn">unicode</span>(<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">hour</span> <span class="op">%</span> <span class="nb nb-int">12</span>) - - <span class="kw">def </span><span class="fun">format_j</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Day of the year as a decimal number [001,366].</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn">unicode</span>(<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">strftime</span>(<span class="st st-sg">'</span><span class="st">%j</span><span class="st st-sg">'</span>)) - - <span class="kw">def </span><span class="fun">format_J</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Day of the year as decimal number [1,366].</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn">unicode</span>(<span class="bn">int</span>(<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">strftime</span>(<span class="st st-sg">'</span><span class="st">%j</span><span class="st st-sg">'</span>))) - - <span class="kw">def </span><span class="fun">format_m</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Month as a decimal number [01,12].</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="name">u</span><span class="st st-sg">'</span><span class="st st-int">%02d</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">month</span> - - <span class="kw">def </span><span class="fun">format_n</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Month as a decimal number [1,12].</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn">unicode</span>(<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">month</span>) - - <span class="kw">def </span><span class="fun">format_M</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Minute as a decimal number [00,59].</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="name">u</span><span class="st st-sg">'</span><span class="st st-int">%02d</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">minute</span> - - <span class="kw">def </span><span class="fun">format_N</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Minute as a decimal number [0,59].</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn">unicode</span>(<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">minute</span>) - - <span class="kw">def </span><span class="fun">format_p</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Locale's equivalent of either AM or PM.</span><span class="st st-db">"""</span> - - <span class="name">_</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">req</span>.<span class="name">gettext</span> - <span class="kw">if</span> <span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">hour</span> <span class="op">></span> <span class="nb nb-int">11</span>: - <span class="kw">return</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">PM</span><span class="st st-sg">'</span>) - <span class="kw">return</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">AM</span><span class="st st-sg">'</span>) - - <span class="kw">def </span><span class="fun">format_P</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Locale's equivalent of either a.m. or p.m.</span><span class="st st-db">"""</span> - - <span class="name">_</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">req</span>.<span class="name">gettext</span> - <span class="kw">if</span> <span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">hour</span> <span class="op">></span> <span class="nb nb-int">11</span>: - <span class="kw">return</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">p.m.</span><span class="st st-sg">'</span>) - <span class="kw">return</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">a.m.</span><span class="st st-sg">'</span>) - - <span class="kw">def </span><span class="fun">format_s</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Second as a decimal number [0,61].</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn">unicode</span>(<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">second</span>) - - <span class="kw">def </span><span class="fun">format_S</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Second as a decimal number [00,61].</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="name">u</span><span class="st st-sg">'</span><span class="st st-int">%02d</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">second</span> - - <span class="kw">def </span><span class="fun">format_U</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Week number of the year (Sunday as the first day of the week) - as a decimal number [00,53]. All days in a new year preceding the - first Sunday are considered to be in week 0.</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn">unicode</span>(<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">strftime</span>(<span class="st st-sg">'</span><span class="st">%U</span><span class="st st-sg">'</span>)) - - <span class="kw">def </span><span class="fun">format_u</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Week number of the year (Sunday as the first day of the week) - as a decimal number [0,53]. All days in a new year preceding the - first Sunday are considered to be in week 0.</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn">unicode</span>(<span class="bn">int</span>(<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">strftime</span>(<span class="st st-sg">'</span><span class="st">%U</span><span class="st st-sg">'</span>))) - - <span class="kw">def </span><span class="fun">format_w</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Weekday as a decimal number [0(Sunday),6].</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn">unicode</span>(<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">strftime</span>(<span class="st st-sg">'</span><span class="st">%w</span><span class="st st-sg">'</span>)) - - <span class="kw">def </span><span class="fun">format_z</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Weekday as a decimal number [0(Monday),6].</span><span class="st st-db">"""</span> - - <span class="cm">#XXX: anyone something better than z?</span> - <span class="kw">return</span> <span class="bn">unicode</span>(<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">weekday</span>) - - <span class="kw">def </span><span class="fun">format_W</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Week number of the year (Monday as the first day of the week) - as a decimal number [00,53]. All days in a new year preceding the - first Monday are considered to be in week 0.</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn">unicode</span>(<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">strftime</span>(<span class="st st-sg">'</span><span class="st">%W</span><span class="st st-sg">'</span>)) - - <span class="kw">def </span><span class="fun">format_v</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Week number of the year (Monday as the first day of the week) - as a decimal number [0,53]. All days in a new year preceding the - first Monday are considered to be in week 0.</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn">unicode</span>(<span class="bn">int</span>(<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">strftime</span>(<span class="st st-sg">'</span><span class="st">%W</span><span class="st st-sg">'</span>))) - - <span class="kw">def </span><span class="fun">format_y</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Year without century as a decimal number [00,99].</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn">unicode</span>(<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">strftime</span>(<span class="st st-sg">'</span><span class="st">%y</span><span class="st st-sg">'</span>)) - - <span class="kw">def </span><span class="fun">format_Y</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Year with century as a decimal number.</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn">unicode</span>(<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">year</span>) - - <span class="kw">def </span><span class="fun">format_r</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">English ordinal suffix for the day of the month, 2 characters; - i.e. 'st', 'nd', 'rd' or 'th'</span><span class="st st-db">"""</span> - - <span class="name">_</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">req</span>.<span class="name">gettext</span> - <span class="kw">if</span> <span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">day</span> <span class="op op-word">in</span> (<span class="nb nb-int">11</span>, <span class="nb nb-int">12</span>, <span class="nb nb-int">13</span>): - <span class="kw">return</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">th</span><span class="st st-sg">'</span>) - <span class="name">last</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">day</span> <span class="op">%</span> <span class="nb nb-int">10</span> - - <span class="kw">if</span> <span class="name">last</span> <span class="op">==</span> <span class="nb nb-int">1</span>: - <span class="kw">return</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">st</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="name">last</span> <span class="op">==</span> <span class="nb nb-int">2</span>: - <span class="kw">return</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">nd</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="name">last</span> <span class="op">==</span> <span class="nb nb-int">3</span>: - <span class="kw">return</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">rd</span><span class="st st-sg">'</span>) - <span class="kw">return</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">th</span><span class="st st-sg">'</span>) - - <span class="kw">def </span><span class="fun">format_t</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Number of days in the given month; i.e. '28' to '31'</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="st st-sg">'</span><span class="st st-int">%02d</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">monthrange</span>(<span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">year</span>, <span class="bn bn-pseudo">self</span>.<span class="name">date</span>.<span class="name">month</span>)[<span class="nb nb-int">1</span>] - - <span class="kw">def </span><span class="fun">__repr__</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="st st-sg">'</span><span class="st"><</span><span class="st st-int">%s</span><span class="st">: [</span><span class="st st-int">%s</span><span class="st">]></span><span class="st st-sg">'</span> <span class="op">%</span> ( - <span class="bn bn-pseudo">self</span>.<span class="name">__class__</span>.<span class="name">__name__</span>, - <span class="st st-sg">'</span><span class="st">, </span><span class="st st-sg">'</span>.<span class="name">join</span>(<span class="bn">str</span>(<span class="name">i</span>[<span class="nb nb-int">7</span>:]) <span class="kw">for</span> <span class="name">i</span> <span class="op op-word">in</span> <span class="bn">dir</span>(<span class="bn bn-pseudo">self</span>) <span class="kw">if</span> <span class="name">i</span>.<span class="name">startswith</span>(<span class="st st-sg">'</span><span class="st">format_</span><span class="st st-sg">'</span>)) - ) - - - -<span class="kw">def </span><span class="fun">format_timedelta</span>(<span class="name">req</span>, <span class="name">time1</span><span class="op">=</span><span class="bn bn-pseudo">None</span>, <span class="name">time2</span><span class="op">=</span><span class="bn bn-pseudo">None</span>): - <span class="st st-db">"""</span><span class="st"> - Format the difference between two datetime or unix timestamp objects:: - - >>> from pocoo.pkg.core.l10n import timedeltaformat - >>> now = datetime.now() - >>> timedeltaformat(req, now) - u'6 seconds ago' - - </span><span class="st st-db">"""</span> - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - <span class="kw">if</span> <span class="name">time1</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="name">time1</span> <span class="op">=</span> <span class="name">datetime</span>.<span class="name">utcnow</span>() - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="name">time1</span>, <span class="name">datetime</span>): - <span class="name">time1</span> <span class="op">=</span> <span class="name">time</span>.<span class="name">mktime</span>(<span class="name">time1</span>.<span class="name">timetuple</span>()) <span class="op">+</span> <span class="name">time1</span>.<span class="name">microsecond</span> <span class="op">/</span> <span class="nb nb-int">1</span><span class="name">e6</span> - - <span class="kw">if</span> <span class="name">time2</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="name">time2</span> <span class="op">=</span> <span class="name">datetime</span>.<span class="name">utcnow</span>() - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="name">time2</span>, <span class="name">datetime</span>): - <span class="name">time2</span> <span class="op">=</span> <span class="name">time</span>.<span class="name">mktime</span>(<span class="name">time2</span>.<span class="name">timetuple</span>()) <span class="op">+</span> <span class="name">time2</span>.<span class="name">microsecond</span> <span class="op">/</span> <span class="nb nb-int">1</span><span class="name">e6</span> - - <span class="kw">if</span> <span class="name">time1</span> <span class="op">></span> <span class="name">time2</span>: - <span class="name">tmpl</span> <span class="op">=</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st st-int">%d</span><span class="st"> </span><span class="st st-int">%s</span><span class="st"> in the future</span><span class="st st-sg">'</span>) - <span class="kw">else</span>: - <span class="name">tmpl</span> <span class="op">=</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st st-int">%d</span><span class="st"> </span><span class="st st-int">%s</span><span class="st"> ago</span><span class="st st-sg">'</span>) - <span class="kw">def </span><span class="fun">trans</span>(<span class="name">s</span>, <span class="name">entity</span>): - <span class="kw">if</span> <span class="name">entity</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">s</span><span class="st st-sg">'</span>: - <span class="name">e</span> <span class="op">=</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">second</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">seconds</span><span class="st st-sg">'</span>, <span class="name">s</span>) - <span class="kw">elif</span> <span class="name">entity</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">m</span><span class="st st-sg">'</span>: - <span class="name">e</span> <span class="op">=</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">minute</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">minutes</span><span class="st st-sg">'</span>, <span class="name">s</span>) - <span class="kw">elif</span> <span class="name">entity</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">h</span><span class="st st-sg">'</span>: - <span class="name">e</span> <span class="op">=</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">hour</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">hours</span><span class="st st-sg">'</span>, <span class="name">s</span>) - <span class="kw">elif</span> <span class="name">entity</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">d</span><span class="st st-sg">'</span>: - <span class="name">e</span> <span class="op">=</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">day</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">days</span><span class="st st-sg">'</span>, <span class="name">s</span>) - <span class="kw">elif</span> <span class="name">entity</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">w</span><span class="st st-sg">'</span>: - <span class="name">e</span> <span class="op">=</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">week</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">weeks</span><span class="st st-sg">'</span>, <span class="name">s</span>) - <span class="kw">elif</span> <span class="name">entity</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">M</span><span class="st st-sg">'</span>: - <span class="name">e</span> <span class="op">=</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">month</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">months</span><span class="st st-sg">'</span>, <span class="name">s</span>) - <span class="kw">else</span>: - <span class="name">e</span> <span class="op">=</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">year</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">years</span><span class="st st-sg">'</span>, <span class="name">s</span>) - <span class="kw">return</span> <span class="name">tmpl</span> <span class="op">%</span> (<span class="name">s</span>, <span class="name">e</span>) - <span class="name">diff</span> <span class="op">=</span> <span class="bn">abs</span>(<span class="bn">int</span>(<span class="name">time2</span> <span class="op">-</span> <span class="name">time1</span>)) - <span class="kw">for</span> <span class="name">u</span>, <span class="name">e</span> <span class="op op-word">in</span> <span class="name">TIME_DELTA_UNITS</span>: - <span class="name">r</span> <span class="op">=</span> <span class="name">diff</span> <span class="op">/</span> <span class="bn">float</span>(<span class="name">u</span>) - <span class="kw">if</span> <span class="name">r</span> <span class="op">>=</span> <span class="nb nb-flt">0.9</span>: - <span class="name">s</span> <span class="op">=</span> <span class="bn">int</span>(<span class="bn">round</span>(<span class="name">r</span>)) - <span class="kw">return</span> <span class="name">trans</span>(<span class="name">s</span>, <span class="name">e</span>) - <span class="kw">return</span> <span class="name">trans</span>(<span class="name">diff</span>, <span class="st st-sg">'</span><span class="st">s</span><span class="st st-sg">'</span>) - - - -<span class="kw">def </span><span class="fun">dateformat</span>(<span class="name">date</span>, <span class="name">context</span>): - <span class="cm">#XXX: load default string from i10n language file</span> - <span class="name">req</span> <span class="op">=</span> <span class="name">context</span>[<span class="st st-sg">'</span><span class="st">REQUEST</span><span class="st st-sg">'</span>] - <span class="name">formatstr</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">settings</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">dateformat</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="name">formatstr</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="name">formatstr</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">general</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">dateformat</span><span class="st st-sg">'</span>, - <span class="name">DEFAULT_DATE_FORMAT</span>) - <span class="name">f</span> <span class="op">=</span> <span class="name">DateFormatter</span>(<span class="name">req</span>, <span class="name">date</span> <span class="op op-word">or</span> <span class="bn bn-pseudo">None</span>) - <span class="kw">return</span> <span class="name">f</span>.<span class="name">format</span>(<span class="name">formatstr</span>) - - - -<span class="kw">def </span><span class="fun">timeformat</span>(<span class="name">date</span>, <span class="name">context</span>): - <span class="cm">#XXX: load default string from l10n language file</span> - <span class="name">req</span> <span class="op">=</span> <span class="name">context</span>[<span class="st st-sg">'</span><span class="st">REQUEST</span><span class="st st-sg">'</span>] - <span class="name">formatstr</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">settings</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">timeformat</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="name">formatstr</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="name">formatstr</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">general</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">timeformat</span><span class="st st-sg">'</span>, - <span class="name">DEFAULT_TIME_FORMAT</span>) - <span class="name">f</span> <span class="op">=</span> <span class="name">DateFormatter</span>(<span class="name">req</span>, <span class="name">date</span> <span class="op op-word">or</span> <span class="bn bn-pseudo">None</span>) - <span class="kw">return</span> <span class="name">f</span>.<span class="name">format</span>(<span class="name">formatstr</span>) - - - -<span class="kw">def </span><span class="fun">datetimeformat</span>(<span class="name">date</span>, <span class="name">context</span>): - <span class="cm">#XXX: load default string from l10n language file</span> - <span class="name">req</span> <span class="op">=</span> <span class="name">context</span>[<span class="st st-sg">'</span><span class="st">REQUEST</span><span class="st st-sg">'</span>] - <span class="name">formatstr</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">settings</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">datetimeformat</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="name">formatstr</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="name">formatstr</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">general</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">datetimeformat</span><span class="st st-sg">'</span>, - <span class="name">DEFAULT_DATETIME_FORMAT</span>) - <span class="name">f</span> <span class="op">=</span> <span class="name">DateFormatter</span>(<span class="name">req</span>, <span class="name">date</span> <span class="op op-word">or</span> <span class="bn bn-pseudo">None</span>) - <span class="kw">return</span> <span class="name">f</span>.<span class="name">format</span>(<span class="name">formatstr</span>) - - - -<span class="kw">def </span><span class="fun">timedeltaformat</span>(<span class="name">date</span>, <span class="name">context</span>, <span class="name">obj2</span><span class="op">=</span><span class="bn bn-pseudo">None</span>): - <span class="name">req</span> <span class="op">=</span> <span class="name">context</span>[<span class="st st-sg">'</span><span class="st">REQUEST</span><span class="st st-sg">'</span>] - <span class="kw">return</span> <span class="name">format_timedelta</span>(<span class="name">req</span>, <span class="name">date</span> <span class="op op-word">or</span> <span class="bn bn-pseudo">None</span>, <span class="name">obj2</span> <span class="op op-word">or</span> <span class="bn bn-pseudo">None</span>) - -<span class="cm"># -*- coding: utf-8 -*-</span> -<span class="st st-db">"""</span><span class="st"> - pocoo.pkg.core.pages - ~~~~~~~~~~~~~~~~~~~~ - - Pocoo core pages. - - :copyright: 2006 by Armin Ronacher, Benjamin Wiegand. - :license: GNU GPL, see LICENSE for more details. -</span><span class="st st-db">"""</span> - -<span class="kw">from </span><span class="cls">pocoo.http</span><span class="kw"> import</span> <span class="name">Response</span>, <span class="name">HttpRedirect</span>, <span class="name">TemplateResponse</span>, \ - <span class="name">AccessDeniedResponse</span>, <span class="name">PageNotFound</span> - -<span class="kw">from </span><span class="cls">pocoo.settings</span><span class="kw"> import</span> <span class="name">cfg</span> -<span class="kw">from </span><span class="cls">pocoo.template</span><span class="kw"> import</span> <span class="name">PagePublisher</span>, <span class="name">render_template</span> -<span class="kw">from </span><span class="cls">pocoo.application</span><span class="kw"> import</span> <span class="name">RequestHandler</span> - -<span class="kw">from </span><span class="cls">pocoo.utils.mail</span><span class="kw"> import</span> <span class="name">Email</span> -<span class="kw">from </span><span class="cls">pocoo.utils.net</span><span class="kw"> import</span> <span class="name">make_url_context_external</span> -<span class="kw">from </span><span class="cls">pocoo.utils.form</span><span class="kw"> import</span> <span class="name">Form</span>, <span class="name">TextField</span>, <span class="name">TextArea</span>, <span class="name">SelectBox</span>, <span class="name">CheckBox</span> - -<span class="kw">from </span><span class="cls">pocoo.utils.validators</span><span class="kw"> import</span> <span class="name">isNotEmpty</span>, <span class="name">isSameValue</span>, <span class="name">isEmail</span>, \ - <span class="name">checkTextLength</span>, <span class="name">isOneLetter</span>, <span class="name">mayEmpty</span>, <span class="name">coppaIsChecked</span> - -<span class="kw">from </span><span class="cls">pocoo.utils.json</span><span class="kw"> import</span> <span class="name">parse_datetime</span> - -<span class="kw">from </span><span class="cls">pocoo.pkg.core.remotecall</span><span class="kw"> import</span> <span class="name">RemoteCallable</span>, <span class="name">export</span> - -<span class="kw">from </span><span class="cls">pocoo.pkg.core.validators</span><span class="kw"> import</span> <span class="name">isAvailableUsername</span>, <span class="name">isStrongPassword</span>, \ - <span class="name">isExistingUsername</span>, <span class="name">isAnonymousUsername</span> -<span class="kw">from </span><span class="cls">pocoo.pkg.core.usersettings</span><span class="kw"> import</span> <span class="name">UserSettingsPage</span> - -<span class="kw">from </span><span class="cls">pocoo.pkg.core.db</span><span class="kw"> import</span> <span class="name">users</span> -<span class="kw">from </span><span class="cls">pocoo.pkg.core.forum</span><span class="kw"> import</span> <span class="name">get_forum_index</span>, <span class="name">get_forum</span>, <span class="name">get_post_tree</span>, \ - <span class="name">get_forum_pathbar</span>, <span class="name">get_view_mode</span>, <span class="name">get_flat_view</span>, <span class="name">quote_post</span>, <span class="name">edit_post</span>, \ - <span class="name">get_post</span>, <span class="name">Thread</span>, <span class="name">get_last_posts</span>, <span class="name">get_last_thread_change</span>, <span class="name">get_post_pathbar</span> - -<span class="kw">from </span><span class="cls">pocoo.pkg.core.user</span><span class="kw"> import</span> <span class="name">User</span>, <span class="name">get_user_list</span>, \ - <span class="name">get_user</span>, <span class="name">get_user_avatar</span>, <span class="name">reset_password</span> -<span class="kw">from </span><span class="cls">pocoo.pkg.core.session</span><span class="kw"> import</span> <span class="name">get_active_sessions</span>, <span class="name">get_sessions_by_action</span> - -<span class="kw">from </span><span class="cls">pocoo.pkg.core.textfmt</span><span class="kw"> import</span> <span class="name">parse_and_render</span>, <span class="name">get_editor</span> - -<span class="name">_</span> <span class="op">=</span> <span class="kw">lambda</span> <span class="name">x</span>: <span class="name">x</span> - - -<span class="kw">class </span><span class="cls">IndexPage</span>(<span class="name">RequestHandler</span>, <span class="name">PagePublisher</span>, <span class="name">RemoteCallable</span>): - <span class="name">page_name</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">index</span><span class="st st-sg">'</span> - - <span class="name">relative_url</span> <span class="op">=</span> <span class="st st-sg">''</span> - <span class="name">handler_regexes</span> <span class="op">=</span> [<span class="name">u</span><span class="st st-sg">'</span><span class="st">$</span><span class="st st-sg">'</span>] - - <span class="kw">def </span><span class="fun">handle_request</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">index.html</span><span class="st st-sg">'</span>, - <span class="name">categories</span><span class="op">=</span><span class="name">get_forum_index</span>(<span class="name">req</span>), - <span class="name">feed_url</span><span class="op">=</span><span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">make_url</span>(<span class="st st-sg">'</span><span class="st">feeds/recent.xml</span><span class="st st-sg">'</span>) - ) - - - -<span class="kw">class </span><span class="cls">ForumPage</span>(<span class="name">RequestHandler</span>): - <span class="name">handler_regexes</span> <span class="op">=</span> [<span class="st st-sg">r'</span><span class="st">forum/(?P<forum_id>\d+)$</span><span class="st st-sg">'</span>] - - <span class="kw">def </span><span class="fun">handle_request</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">forum_id</span>): - <span class="name">forum_id</span> <span class="op">=</span> <span class="bn">int</span>(<span class="name">forum_id</span>) - <span class="kw">try</span>: - <span class="name">page</span> <span class="op">=</span> <span class="bn">int</span>(<span class="name">req</span>.<span class="name">args</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">page</span><span class="st st-sg">'</span>)) - <span class="kw">except</span> (<span class="exc">TypeError</span>, <span class="exc">ValueError</span>): - <span class="name">page</span> <span class="op">=</span> <span class="nb nb-int">1</span> - - <span class="name">forum</span> <span class="op">=</span> <span class="name">get_forum</span>(<span class="name">req</span>, <span class="name">forum_id</span>, <span class="name">page</span>) - <span class="kw">if</span> <span class="name">forum</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="kw">return</span> <span class="name">PageNotFound</span>() - <span class="cm"># Redirect if the forum is a link</span> - - <span class="kw">if</span> <span class="name">forum</span>[<span class="st st-sg">'</span><span class="st">is_external_url</span><span class="st st-sg">'</span>]: - <span class="kw">return</span> <span class="name">HttpRedirect</span>(<span class="name">forum</span>[<span class="st st-sg">'</span><span class="st">link</span><span class="st st-sg">'</span>], <span class="name">local</span><span class="op">=</span><span class="bn bn-pseudo">False</span>) - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">viewforum.html</span><span class="st st-sg">'</span>, - <span class="name">forum</span><span class="op">=</span><span class="name">forum</span>, - <span class="name">pathbar</span><span class="op">=</span><span class="name">get_forum_pathbar</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, <span class="name">forum_id</span>), - <span class="name">feed_url</span><span class="op">=</span><span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">make_url</span>(<span class="st st-sg">'</span><span class="st">feeds/forum/</span><span class="st st-int">%d</span><span class="st">.xml</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">forum_id</span>) - ) - - - -<span class="kw">class </span><span class="cls">PostPage</span>(<span class="name">RequestHandler</span>, <span class="name">RemoteCallable</span>): - <span class="name">handler_regexes</span> <span class="op">=</span> [<span class="st st-sg">r'</span><span class="st">post/(?P<post_id>\d+)$</span><span class="st st-sg">'</span>] - - <span class="kw">def </span><span class="fun">handle_request</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">post_id</span>): - <span class="name">view</span> <span class="op">=</span> <span class="name">get_view_mode</span>(<span class="name">req</span>) - <span class="kw">if</span> <span class="name">view</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">flat</span><span class="st st-sg">'</span>: - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">_flat_view</span>(<span class="name">req</span>, <span class="bn">int</span>(<span class="name">post_id</span>)) - <span class="kw">else</span>: - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">_threaded_view</span>(<span class="name">req</span>, <span class="bn">int</span>(<span class="name">post_id</span>)) - - <span class="kw">def </span><span class="fun">_flat_view</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">post_id</span>): - <span class="name">topic</span> <span class="op">=</span> <span class="name">get_flat_view</span>(<span class="name">req</span>, <span class="name">post_id</span>) - <span class="kw">if</span> <span class="name">topic</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="kw">return</span> <span class="name">PageNotFound</span>() - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">viewtopic.html</span><span class="st st-sg">'</span>, - <span class="name">topic</span><span class="op">=</span><span class="name">topic</span>, - <span class="name">pathbar</span><span class="op">=</span><span class="name">get_post_pathbar</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, <span class="name">topic</span>[<span class="st st-sg">'</span><span class="st">posts</span><span class="st st-sg">'</span>][<span class="nb nb-int">0</span>][<span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>]), - <span class="name">feed_url</span><span class="op">=</span><span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">make_url</span>(<span class="st st-sg">'</span><span class="st">feeds/thread/</span><span class="st st-int">%d</span><span class="st">.xml</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">post_id</span>) - ) - - <span class="kw">def </span><span class="fun">_threaded_view</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">post_id</span>): - <span class="name">thread</span> <span class="op">=</span> <span class="name">get_post_tree</span>(<span class="name">req</span>, <span class="name">post_id</span>) - <span class="kw">if</span> <span class="name">thread</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="kw">return</span> <span class="name">PageNotFound</span>() - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">viewthread.html</span><span class="st st-sg">'</span>, - <span class="name">thread</span><span class="op">=</span><span class="name">thread</span>, - <span class="name">pathbar</span><span class="op">=</span><span class="name">get_post_pathbar</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, <span class="name">thread</span>[<span class="st st-sg">'</span><span class="st">posts</span><span class="st st-sg">'</span>][<span class="nb nb-int">0</span>][<span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>]), - <span class="name">feed_url</span><span class="op">=</span><span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">make_url</span>(<span class="st st-sg">'</span><span class="st">feeds/thread/</span><span class="st st-int">%d</span><span class="st">.xml</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">post_id</span>) - ) - - <span class="deco">@export</span>(<span class="st st-sg">'</span><span class="st">thread.get_post</span><span class="st st-sg">'</span>) - <span class="kw">def </span><span class="fun">_get_post</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">post_id</span>): - <span class="name">post</span> <span class="op">=</span> <span class="name">get_post</span>(<span class="name">req</span>, <span class="name">post_id</span>) - <span class="kw">if</span> <span class="name">post</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="kw">return</span> - - <span class="kw">return</span> <span class="name">render_template</span>(<span class="name">req</span>, <span class="st st-sg">'</span><span class="st">partial/post.html</span><span class="st st-sg">'</span>, { - <span class="st st-sg">'</span><span class="st">post</span><span class="st st-sg">'</span>: <span class="name">post</span> - }) - - <span class="deco">@export</span>(<span class="st st-sg">'</span><span class="st">thread.tree_requires_update</span><span class="st st-sg">'</span>) - <span class="kw">def </span><span class="fun">_tree_requires_update</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">post_id</span>, <span class="name">last_update</span>): - <span class="name">last_update</span> <span class="op">=</span> <span class="name">parse_datetime</span>(<span class="name">last_update</span>) - <span class="name">last_thread_change</span> <span class="op">=</span> <span class="name">get_last_thread_change</span>(<span class="name">req</span>, <span class="name">post_id</span>) - <span class="kw">print</span> <span class="name">last_thread_change</span>, <span class="name">last_update</span> - - <span class="kw">return</span> <span class="name">last_thread_change</span> <span class="op op-word">is</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">None</span> <span class="op op-word">and</span>\ - <span class="name">last_thread_change</span> <span class="op">></span> <span class="name">last_update</span> - - <span class="deco">@export</span>(<span class="st st-sg">'</span><span class="st">thread.get_tree</span><span class="st st-sg">'</span>) - <span class="kw">def </span><span class="fun">_get_tree</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">post_id</span>): - <span class="kw">return</span> <span class="name">render_template</span>(<span class="name">req</span>, <span class="st st-sg">'</span><span class="st">partial/tree.html</span><span class="st st-sg">'</span>, { - <span class="st st-sg">'</span><span class="st">posts</span><span class="st st-sg">'</span>: <span class="name">get_post_tree</span>(<span class="name">req</span>, <span class="name">post_id</span>)[<span class="st st-sg">'</span><span class="st">posts</span><span class="st st-sg">'</span>] - }) - - - -<span class="kw">class </span><span class="cls">LoginPage</span>(<span class="name">RequestHandler</span>, <span class="name">PagePublisher</span>): - <span class="name">page_name</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">login</span><span class="st st-sg">'</span> - <span class="name">relative_url</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">login</span><span class="st st-sg">'</span> - - <span class="name">handler_regexes</span> <span class="op">=</span> [<span class="st st-sg">'</span><span class="st">^login$</span><span class="st st-sg">'</span>] - - <span class="kw">def </span><span class="fun">handle_request</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="name">next</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">values</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">next</span><span class="st st-sg">'</span>, <span class="bn bn-pseudo">None</span>) - <span class="kw">if</span> <span class="name">next</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="name">next</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">environ</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">HTTP_REFERER</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">next</span>: - <span class="name">next</span> <span class="op">=</span> <span class="name">u</span><span class="st st-sg">''</span> - - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - <span class="name">msg</span> <span class="op">=</span> <span class="name">u</span><span class="st st-sg">''</span> - <span class="kw">if</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">identified</span>: - <span class="kw">return</span> <span class="name">HttpRedirect</span>(<span class="name">next</span>) - <span class="name">form</span> <span class="op">=</span> <span class="name">Form</span>(<span class="name">req</span>, <span class="bn bn-pseudo">self</span>, <span class="st st-sg">'</span><span class="st">POST</span><span class="st st-sg">'</span>, - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>, <span class="name">validator</span><span class="op">=</span><span class="name">isNotEmpty</span>()), - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">password</span><span class="st st-sg">'</span>, <span class="name">validator</span><span class="op">=</span><span class="name">isNotEmpty</span>()) - ) - <span class="kw">if</span> <span class="name">req</span>.<span class="name">method</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">POST</span><span class="st st-sg">'</span>: - <span class="name">form</span>.<span class="name">update</span>(<span class="name">req</span>.<span class="name">form</span>, <span class="name">prefix</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">f_</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">form</span>.<span class="name">has_errors</span>: - <span class="name">d</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">to_dict</span>() - <span class="name">login</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">auth</span>.<span class="name">do_login</span>(<span class="name">d</span>[<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>], <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">password</span><span class="st st-sg">'</span>]) - <span class="kw">if</span> <span class="name">login</span>: - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="name">login</span>, <span class="name">Response</span>): - <span class="kw">return</span> <span class="name">login</span> - - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">messages/login.html</span><span class="st st-sg">'</span>, - <span class="name">username</span><span class="op">=</span><span class="name">d</span>[<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>], - <span class="name">next</span><span class="op">=</span><span class="name">next</span> - - ) - <span class="kw">else</span>: - <span class="name">msg</span> <span class="op">=</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Login failed. You may have entered an invalid </span><span class="st st-sg">'</span> - <span class="st st-sg">'</span><span class="st">username or password or your account is not </span><span class="st st-sg">'</span> - <span class="st st-sg">'</span><span class="st">activated yet.</span><span class="st st-sg">'</span>) - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">login.html</span><span class="st st-sg">'</span>, - <span class="name">msg</span><span class="op">=</span><span class="name">msg</span>, - <span class="name">form</span><span class="op">=</span><span class="name">form</span>.<span class="name">generate</span>(<span class="name">prefix</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">f_</span><span class="st st-sg">'</span>), - <span class="name">next</span><span class="op">=</span><span class="name">next</span> - - ) - - -<span class="kw">class </span><span class="cls">LogoutPage</span>(<span class="name">RequestHandler</span>, <span class="name">PagePublisher</span>): - <span class="name">page_name</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">logout</span><span class="st st-sg">'</span> - <span class="name">relative_url</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">logout</span><span class="st st-sg">'</span> - - <span class="name">handler_regexes</span> <span class="op">=</span> [<span class="st st-sg">r'</span><span class="st">logout$</span><span class="st st-sg">'</span>] - - <span class="kw">def </span><span class="fun">handle_request</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="name">back</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">environ</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">HTTP_REFERER</span><span class="st st-sg">'</span>, <span class="name">u</span><span class="st st-sg">''</span>) - <span class="kw">try</span>: - <span class="name">back</span> <span class="op">=</span> <span class="name">make_url_context_external</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, <span class="name">back</span>) - <span class="kw">except</span> <span class="exc">ValueError</span>: - <span class="name">back</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="name">username</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">username</span> - <span class="name">req</span>.<span class="name">auth</span>.<span class="name">do_logout</span>() - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">messages/logout.html</span><span class="st st-sg">'</span>, - <span class="name">username</span><span class="op">=</span><span class="name">username</span>, - <span class="name">back</span><span class="op">=</span><span class="name">back</span> - - ) - - -<span class="kw">class </span><span class="cls">RegisterPage</span>(<span class="name">RequestHandler</span>, <span class="name">PagePublisher</span>): - <span class="name">page_name</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">register</span><span class="st st-sg">'</span> - <span class="name">relative_url</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">register</span><span class="st st-sg">'</span> - - <span class="name">handler_regexes</span> <span class="op">=</span> [<span class="st st-sg">'</span><span class="st">register$</span><span class="st st-sg">'</span>] - - <span class="kw">def </span><span class="fun">handle_request</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="name">coppa</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get_bool</span>(<span class="st st-sg">'</span><span class="st">board</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">enable_coppa</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">identified</span>: - <span class="kw">return</span> <span class="name">HttpRedirect</span>(<span class="st st-sg">''</span>) - <span class="kw">if</span> <span class="st st-sg">'</span><span class="st">activate</span><span class="st st-sg">'</span> <span class="op op-word">in</span> <span class="name">req</span>.<span class="name">args</span> <span class="op op-word">and</span> <span class="st st-sg">'</span><span class="st">user</span><span class="st st-sg">'</span> <span class="op op-word">in</span> <span class="name">req</span>.<span class="name">args</span>: - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">activation</span>(<span class="name">req</span>) - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - - <span class="name">form</span> <span class="op">=</span> <span class="name">Form</span>(<span class="name">req</span>, <span class="bn bn-pseudo">self</span>, <span class="st st-sg">'</span><span class="st">POST</span><span class="st st-sg">'</span>, - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>, <span class="name">validator</span><span class="op">=</span><span class="name">isAvailableUsername</span>()), - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">password</span><span class="st st-sg">'</span>, <span class="name">validator</span><span class="op">=</span><span class="name">isStrongPassword</span>()), - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">password2</span><span class="st st-sg">'</span>, <span class="name">validator</span><span class="op">=</span><span class="name">isSameValue</span>(<span class="st st-sg">'</span><span class="st">password</span><span class="st st-sg">'</span>, - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">The passwords don</span><span class="st st-esc">\'</span><span class="st">t match.</span><span class="st st-sg">'</span>))), - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">email</span><span class="st st-sg">'</span>, <span class="name">validator</span><span class="op">=</span><span class="name">isEmail</span>()), - <span class="name">CheckBox</span>(<span class="st st-sg">'</span><span class="st">coppa</span><span class="st st-sg">'</span>, <span class="name">validator</span><span class="op">=</span><span class="name">coppaIsChecked</span>(<span class="name">coppa</span>)), - ) - <span class="kw">if</span> <span class="name">req</span>.<span class="name">method</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">POST</span><span class="st st-sg">'</span>: - <span class="name">form</span>.<span class="name">update</span>(<span class="name">req</span>.<span class="name">form</span>, <span class="name">prefix</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">f_</span><span class="st st-sg">'</span>) - <span class="name">d</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">to_dict</span>() - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">form</span>.<span class="name">has_errors</span>: - <span class="name">requires_activation</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get_bool</span>(<span class="st st-sg">'</span><span class="st">board</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">email_verification</span><span class="st st-sg">'</span>) - <span class="name">user</span> <span class="op">=</span> <span class="name">User</span>.<span class="name">create</span>(<span class="name">req</span>.<span class="name">ctx</span>, - <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>], - <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">password</span><span class="st st-sg">'</span>], - <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">email</span><span class="st st-sg">'</span>], - <span class="name">requires_activation</span> - - ) - <span class="kw">if</span> <span class="name">requires_activation</span>: - <span class="name">link</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">make_external_url</span>(<span class="st st-sg">'</span><span class="st">register?user=</span><span class="st st-int">%s</span><span class="st">&key</span><span class="st st-int">%s</span><span class="st st-sg">'</span> <span class="op">%</span> - - (<span class="name">user</span>.<span class="name">user_id</span>, <span class="name">user</span>.<span class="name">act_key</span>)) - <span class="name">txt</span> <span class="op">=</span> <span class="name">render_template</span>(<span class="name">req</span>, <span class="st st-sg">'</span><span class="st">mails/welcome_verification.txt</span><span class="st st-sg">'</span>, { - <span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>: <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>], - <span class="st st-sg">'</span><span class="st">password</span><span class="st st-sg">'</span>: <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">password</span><span class="st st-sg">'</span>], - <span class="st st-sg">'</span><span class="st">forum_name</span><span class="st st-sg">'</span>: <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">board</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span>), - <span class="st st-sg">'</span><span class="st">activate_link</span><span class="st st-sg">'</span>: <span class="name">link</span> - - }) - <span class="name">mail</span> <span class="op">=</span> <span class="name">Email</span>(<span class="name">req</span>.<span class="name">ctx</span>, <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Welcome to the </span><span class="st st-int">%s</span><span class="st st-sg">'</span>) <span class="op">%</span> - - <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">board</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span>), - <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">email</span><span class="st st-sg">'</span>], <span class="name">txt</span>) - <span class="name">mail</span>.<span class="name">send</span>() - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">messages/register.html</span><span class="st st-sg">'</span>, - <span class="name">requires_activation</span><span class="op">=</span><span class="name">requires_activation</span>, - <span class="name">username</span><span class="op">=</span><span class="name">d</span>[<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>], - <span class="name">email</span><span class="op">=</span><span class="name">d</span>[<span class="st st-sg">'</span><span class="st">email</span><span class="st st-sg">'</span>] - ) - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">register.html</span><span class="st st-sg">'</span>, - <span class="name">form</span><span class="op">=</span><span class="name">form</span>.<span class="name">generate</span>(<span class="name">prefix</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">f_</span><span class="st st-sg">'</span>), - ) - - <span class="kw">def </span><span class="fun">activation</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - - <span class="name">uid</span> <span class="op">=</span> <span class="bn">int</span>(<span class="name">req</span>.<span class="name">args</span>[<span class="st st-sg">'</span><span class="st">user</span><span class="st st-sg">'</span>]) - <span class="name">activated</span> <span class="op">=</span> <span class="bn bn-pseudo">False</span> - - <span class="name">username</span> <span class="op">=</span> <span class="name">u</span><span class="st st-sg">''</span> - <span class="kw">try</span>: - <span class="name">user</span> <span class="op">=</span> <span class="name">User</span>(<span class="name">req</span>.<span class="name">ctx</span>, <span class="name">uid</span>) - <span class="name">key</span> <span class="op">=</span> <span class="name">user</span>.<span class="name">act_key</span> - - <span class="kw">except</span> <span class="exc">KeyError</span>: - <span class="kw">pass</span> - <span class="kw">else</span>: - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">user</span>.<span class="name">active</span> <span class="op op-word">and</span> <span class="name">req</span>.<span class="name">args</span>[<span class="st st-sg">'</span><span class="st">activate</span><span class="st st-sg">'</span>] <span class="op">==</span> <span class="name">key</span>: - <span class="name">user</span>.<span class="name">activate</span>() - <span class="name">activated</span> <span class="op">=</span> <span class="bn bn-pseudo">True</span> - - <span class="name">username</span> <span class="op">=</span> <span class="name">user</span>.<span class="name">username</span> - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">messages/activation.html</span><span class="st st-sg">'</span>, - <span class="name">username</span><span class="op">=</span><span class="name">username</span>, - <span class="name">activated</span><span class="op">=</span><span class="name">activated</span> - - ) - - -<span class="kw">class </span><span class="cls">NewPostPage</span>(<span class="name">RequestHandler</span>, <span class="name">RemoteCallable</span>): - <span class="name">handler_regexes</span> <span class="op">=</span> [ - (<span class="st st-sg">r'</span><span class="st">post/(?P<post_id>\d+)/reply$</span><span class="st st-sg">'</span>, - {<span class="st st-sg">'</span><span class="st">action</span><span class="st st-sg">'</span>:<span class="st st-sg">'</span><span class="st">reply</span><span class="st st-sg">'</span>}), - (<span class="st st-sg">r'</span><span class="st">post/(?P<post_id>\d+)/quote$</span><span class="st st-sg">'</span>, - {<span class="st st-sg">'</span><span class="st">action</span><span class="st st-sg">'</span>:<span class="st st-sg">'</span><span class="st">quote</span><span class="st st-sg">'</span>}), - (<span class="st st-sg">r'</span><span class="st">post/(?P<post_id>\d+)/edit$</span><span class="st st-sg">'</span>, - {<span class="st st-sg">'</span><span class="st">action</span><span class="st st-sg">'</span>:<span class="st st-sg">'</span><span class="st">edit</span><span class="st st-sg">'</span>}) - ] - - <span class="kw">def </span><span class="fun">handle_request</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">action</span>, <span class="name">post_id</span>): - <span class="kw">try</span>: - <span class="name">thread</span> <span class="op">=</span> <span class="name">Thread</span>.<span class="name">by_child</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, <span class="name">post_id</span>) - <span class="kw">except</span> <span class="exc">ValueError</span>: - <span class="kw">return</span> <span class="name">PageNotFound</span>() - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - - <span class="cm"># note: quote_post can raise a ValueError when a post does</span> - <span class="cm"># not exist. but since we check for that by calling</span> - <span class="cm"># Thread.by_child this shouldn't happen.</span> - <span class="name">username</span> <span class="op">=</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">anonymous</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="name">action</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">reply</span><span class="st st-sg">'</span>: - <span class="name">mode</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">reply</span><span class="st st-sg">'</span> - - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">acl</span>.<span class="name">can_access</span>(<span class="st st-sg">'</span><span class="st">REPLY_POST</span><span class="st st-sg">'</span>, <span class="name">thread</span>): - <span class="kw">return</span> <span class="name">AccessDeniedResponse</span>() - <span class="name">text</span> <span class="op">=</span> <span class="name">u</span><span class="st st-sg">''</span> - - <span class="name">_</span>, <span class="name">title</span> <span class="op">=</span> <span class="name">quote_post</span>(<span class="name">req</span>, <span class="name">post_id</span>) - <span class="kw">elif</span> <span class="name">action</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">quote</span><span class="st st-sg">'</span>: - <span class="name">mode</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">reply</span><span class="st st-sg">'</span> - - <span class="cm">#XXX: maybe we could use REPLY_POST here too</span> - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">acl</span>.<span class="name">can_access</span>(<span class="st st-sg">'</span><span class="st">QUOTE_POST</span><span class="st st-sg">'</span>, <span class="name">thread</span>): - <span class="kw">return</span> <span class="name">AccessDeniedResponse</span>() - <span class="name">text</span>, <span class="name">title</span> <span class="op">=</span> <span class="name">quote_post</span>(<span class="name">req</span>, <span class="name">post_id</span>) - <span class="kw">else</span>: - <span class="name">mode</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">edit</span><span class="st st-sg">'</span> - - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">acl</span>.<span class="name">can_access</span>(<span class="st st-sg">'</span><span class="st">EDIT_POST</span><span class="st st-sg">'</span>, <span class="name">thread</span>): - <span class="kw">return</span> <span class="name">AccessDeniedResponse</span>() - <span class="name">text</span>, <span class="name">title</span>, <span class="name">username</span> <span class="op">=</span> <span class="name">edit_post</span>(<span class="name">req</span>, <span class="name">post_id</span>) - - <span class="name">form</span> <span class="op">=</span> <span class="name">Form</span>(<span class="name">req</span>, <span class="name">req</span>.<span class="name">environ</span>[<span class="st st-sg">'</span><span class="st">APPLICATION_REQUEST</span><span class="st st-sg">'</span>], <span class="st st-sg">'</span><span class="st">POST</span><span class="st st-sg">'</span>, - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>, <span class="name">validator</span><span class="op">=</span><span class="name">isAnonymousUsername</span>(), - <span class="name">default</span><span class="op">=</span><span class="name">username</span>), - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span>, <span class="name">validator</span><span class="op">=</span><span class="name">checkTextLength</span>(<span class="nb nb-int">3</span>, <span class="nb nb-int">60</span>), - <span class="name">default</span><span class="op">=</span><span class="name">title</span>), - <span class="name">TextArea</span>(<span class="st st-sg">'</span><span class="st">text</span><span class="st st-sg">'</span>, <span class="name">validator</span><span class="op">=</span><span class="name">checkTextLength</span>(<span class="nb nb-int">3</span>, <span class="nb nb-int">10000</span>), - <span class="name">default</span><span class="op">=</span><span class="name">text</span>) - ) - <span class="kw">if</span> <span class="name">req</span>.<span class="name">method</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">POST</span><span class="st st-sg">'</span>: - <span class="name">form</span>.<span class="name">update</span>(<span class="name">req</span>.<span class="name">form</span>, <span class="name">prefix</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">f_</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">form</span>.<span class="name">has_errors</span>: - <span class="name">d</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">to_dict</span>() - <span class="kw">if</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">identified</span>: - <span class="name">author</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">user_id</span> - - <span class="kw">else</span>: - <span class="name">author</span> <span class="op">=</span> <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>] - <span class="kw">if</span> <span class="name">action</span> <span class="op op-word">in</span> (<span class="st st-sg">'</span><span class="st">quote</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">reply</span><span class="st st-sg">'</span>): - <span class="name">new_post_id</span> <span class="op">=</span> <span class="name">thread</span>.<span class="name">reply</span>( - <span class="name">post_id</span> <span class="op">=</span> <span class="bn">int</span>(<span class="name">post_id</span>), - <span class="name">author</span> <span class="op">=</span> <span class="name">author</span>, - <span class="name">title</span> <span class="op">=</span> <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span>], - <span class="name">text</span> <span class="op">=</span> <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">text</span><span class="st st-sg">'</span>] - ) - <span class="kw">elif</span> <span class="name">action</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">edit</span><span class="st st-sg">'</span>: - <span class="name">new_post_id</span> <span class="op">=</span> <span class="bn">int</span>(<span class="name">post_id</span>) - <span class="name">thread</span>.<span class="name">edit_reply</span>( - <span class="name">post_id</span> <span class="op">=</span> <span class="name">new_post_id</span>, - <span class="name">author</span> <span class="op">=</span> <span class="name">author</span>, - <span class="name">title</span> <span class="op">=</span> <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span>], - <span class="name">text</span> <span class="op">=</span> <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">text</span><span class="st st-sg">'</span>] - ) - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">messages/post.html</span><span class="st st-sg">'</span>, - <span class="name">mode</span> <span class="op">=</span> <span class="name">mode</span>, - <span class="name">post</span> <span class="op">=</span> { - <span class="st st-sg">'</span><span class="st">id</span><span class="st st-sg">'</span>: <span class="name">new_post_id</span>, - <span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span>: <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span>], - <span class="st st-sg">'</span><span class="st">url</span><span class="st st-sg">'</span>: <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">make_url</span>(<span class="st st-sg">'</span><span class="st">post</span><span class="st st-sg">'</span>, <span class="name">new_post_id</span>), - } - ) - <span class="name">js</span>, <span class="name">options</span> <span class="op">=</span> <span class="name">get_editor</span>(<span class="name">req</span>) - <span class="name">latest_posts</span> <span class="op">=</span> <span class="name">get_last_posts</span>(<span class="name">req</span>, <span class="name">thread</span>.<span class="name">root_post_id</span>, <span class="nb nb-int">5</span>) - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">newpost.html</span><span class="st st-sg">'</span>, - <span class="name">mode</span> <span class="op">=</span> <span class="name">mode</span>, - <span class="name">form</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">generate</span>(<span class="name">prefix</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">f_</span><span class="st st-sg">'</span>), - <span class="name">show_username_entry</span> <span class="op">=</span> <span class="op op-word">not</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">identified</span>, - <span class="name">editor_options</span> <span class="op">=</span> <span class="name">options</span>, - <span class="name">editor_javascript</span> <span class="op">=</span> <span class="name">js</span>, - <span class="name">post_id</span> <span class="op">=</span> <span class="name">thread</span>.<span class="name">root_post_id</span>, - <span class="name">pathbar</span><span class="op">=</span><span class="name">get_post_pathbar</span>(<span class="name">req</span>.<span class="name">ctx</span>, <span class="name">post_id</span>), - <span class="name">latest_posts</span> <span class="op">=</span> <span class="name">latest_posts</span> - - ) - - <span class="deco">@export</span>(<span class="st st-db">"</span><span class="st">newpost.preview</span><span class="st st-db">"</span>) - <span class="kw">def </span><span class="fun">preview</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">text</span>): - <span class="kw">return</span> <span class="name">parse_and_render</span>(<span class="name">req</span>, <span class="name">text</span>) - - <span class="deco">@export</span>(<span class="st st-db">"</span><span class="st">newpost.check</span><span class="st st-db">"</span>) - <span class="kw">def </span><span class="fun">check</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">root_post_id</span>, <span class="name">latest_post</span>, <span class="name">path</span>): - <span class="cm"># check for new posts</span> - - <span class="name">new_posts</span> <span class="op">=</span> <span class="bn bn-pseudo">False</span> - <span class="name">post</span> <span class="op">=</span> <span class="name">get_last_posts</span>(<span class="name">req</span>, <span class="name">root_post_id</span>, <span class="nb nb-int">1</span>)[<span class="nb nb-int">0</span>] - <span class="name">post_list</span> <span class="op">=</span> [] - <span class="kw">if</span> <span class="name">latest_post</span> <span class="op">!=</span> <span class="name">post</span>[<span class="st st-db">"</span><span class="st">post_id</span><span class="st st-db">"</span>]: - <span class="name">z</span> <span class="op">=</span> <span class="nb nb-int">1</span> - - <span class="kw">while</span> <span class="name">post</span>[<span class="st st-db">"</span><span class="st">post_id</span><span class="st st-db">"</span>] <span class="op">!=</span> <span class="name">latest_post</span> <span class="op op-word">and</span> <span class="name">z</span> <span class="op"><</span> <span class="nb nb-int">5</span>: - <span class="name">post_list</span>.<span class="name">append</span>(<span class="name">post</span>) - <span class="name">post</span> <span class="op">=</span> <span class="name">get_last_posts</span>(<span class="name">req</span>, <span class="name">root_post_id</span>, <span class="nb nb-int">1</span>, <span class="name">z</span>)[<span class="nb nb-int">0</span>] - <span class="name">z</span> <span class="op">+=</span> <span class="nb nb-int">1</span> - - <span class="name">new_posts</span> <span class="op">=</span> { - <span class="st st-sg">'</span><span class="st">html</span><span class="st st-sg">'</span>: <span class="name">render_template</span>(<span class="name">req</span>, <span class="st st-sg">'</span><span class="st">latestposts.html</span><span class="st st-sg">'</span>, {<span class="st st-sg">'</span><span class="st">posts</span><span class="st st-sg">'</span>: <span class="name">post_list</span>}), - <span class="st st-sg">'</span><span class="st">last_post</span><span class="st st-sg">'</span>: <span class="name">post_list</span>[<span class="nb nb-int">0</span>][<span class="st st-db">"</span><span class="st">post_id</span><span class="st st-db">"</span>] - } - - <span class="cm"># check for new editors</span> - - <span class="name">new_editors</span> <span class="op">=</span> <span class="name">get_sessions_by_action</span>(<span class="name">req</span>.<span class="name">ctx</span>, <span class="name">path</span>) <span class="op op-word">or</span> <span class="bn bn-pseudo">False</span> - - <span class="kw">return</span> (<span class="name">post_list</span> <span class="op op-word">or</span> <span class="name">new_editors</span>) <span class="op op-word">and</span> { - <span class="st st-sg">'</span><span class="st">posts</span><span class="st st-sg">'</span>: <span class="name">new_posts</span>, - <span class="st st-sg">'</span><span class="st">editors</span><span class="st st-sg">'</span>: <span class="name">new_editors</span> - - } <span class="op op-word">or</span> <span class="bn bn-pseudo">False</span> - - -<span class="kw">class </span><span class="cls">NewThreadPage</span>(<span class="name">RequestHandler</span>): - <span class="name">handler_regexes</span> <span class="op">=</span> [<span class="st st-sg">r'</span><span class="st">forum/(?P<forum_id>\d+)/new$</span><span class="st st-sg">'</span>] - - <span class="kw">def </span><span class="fun">handle_request</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">forum_id</span>): - <span class="cm"># TODO: Check whether user is allowed to do this</span> - - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - <span class="name">forum_id</span> <span class="op">=</span> <span class="bn">int</span>(<span class="name">forum_id</span>) - <span class="name">form</span> <span class="op">=</span> <span class="name">Form</span>(<span class="name">req</span>, <span class="name">req</span>.<span class="name">environ</span>[<span class="st st-sg">'</span><span class="st">APPLICATION_REQUEST</span><span class="st st-sg">'</span>], <span class="st st-sg">'</span><span class="st">POST</span><span class="st st-sg">'</span>, - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>, <span class="name">validator</span><span class="op">=</span><span class="name">isAnonymousUsername</span>(), - <span class="name">default</span><span class="op">=</span><span class="name">_</span>(<span class="st st-sg">'</span><span class="st">anonymous</span><span class="st st-sg">'</span>)), - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span>, <span class="name">validator</span><span class="op">=</span><span class="name">checkTextLength</span>(<span class="nb nb-int">3</span>, <span class="nb nb-int">60</span>)), - <span class="name">TextArea</span>(<span class="st st-sg">'</span><span class="st">text</span><span class="st st-sg">'</span>, <span class="name">validator</span><span class="op">=</span><span class="name">checkTextLength</span>(<span class="nb nb-int">3</span>, <span class="nb nb-int">10000</span>)) - ) - <span class="kw">if</span> <span class="name">req</span>.<span class="name">method</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">POST</span><span class="st st-sg">'</span>: - <span class="name">form</span>.<span class="name">update</span>(<span class="name">req</span>.<span class="name">form</span>, <span class="name">prefix</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">f_</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">form</span>.<span class="name">has_errors</span>: - <span class="name">d</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">to_dict</span>() - <span class="kw">if</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">identified</span>: - <span class="name">author</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">user_id</span> - - <span class="kw">else</span>: - <span class="name">author</span> <span class="op">=</span> <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>] - <span class="name">thread</span> <span class="op">=</span> <span class="name">Thread</span>.<span class="name">create</span>(<span class="name">req</span>.<span class="name">ctx</span>, <span class="name">forum_id</span>, <span class="name">author</span>, - <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span>], <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">text</span><span class="st st-sg">'</span>]) - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">messages/thread.html</span><span class="st st-sg">'</span>, - <span class="name">thread</span> <span class="op">=</span> { - <span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span>: <span class="name">thread</span>.<span class="name">title</span>, - <span class="st st-sg">'</span><span class="st">url</span><span class="st st-sg">'</span>: <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">make_url</span>(<span class="st st-sg">'</span><span class="st">post</span><span class="st st-sg">'</span>, <span class="name">thread</span>.<span class="name">root_post_id</span>), - } - ) - - <span class="name">js</span>, <span class="name">options</span> <span class="op">=</span> <span class="name">get_editor</span>(<span class="name">req</span>) - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">newthread.html</span><span class="st st-sg">'</span>, - <span class="name">form</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">generate</span>(<span class="name">prefix</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">f_</span><span class="st st-sg">'</span>), - <span class="name">show_username_entry</span> <span class="op">=</span> <span class="op op-word">not</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">identified</span>, - <span class="name">editor_options</span> <span class="op">=</span> <span class="name">options</span>, - <span class="name">editor_javascript</span> <span class="op">=</span> <span class="name">js</span>, - <span class="name">pathbar</span> <span class="op">=</span> <span class="name">get_forum_pathbar</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, <span class="name">forum_id</span>) - ) - - - -<span class="kw">class </span><span class="cls">MemberListPage</span>(<span class="name">RequestHandler</span>, <span class="name">PagePublisher</span>): - <span class="name">page_name</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">memberlist</span><span class="st st-sg">'</span> - <span class="name">relative_url</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">users/</span><span class="st st-sg">'</span> - - <span class="name">handler_regexes</span> <span class="op">=</span> [<span class="st st-sg">r'</span><span class="st">users/$</span><span class="st st-sg">'</span>] - - <span class="kw">def </span><span class="fun">handle_request</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - - <span class="name">generate</span> <span class="op">=</span> <span class="bn bn-pseudo">False</span> - - <span class="name">form</span> <span class="op">=</span> <span class="name">Form</span>(<span class="name">req</span>, <span class="bn bn-pseudo">self</span>, <span class="st st-sg">'</span><span class="st">GET</span><span class="st st-sg">'</span>, - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">letter</span><span class="st st-sg">'</span>, <span class="name">validator</span><span class="op">=</span><span class="name">mayEmpty</span>(<span class="name">isOneLetter</span>())), - <span class="name">SelectBox</span>(<span class="st st-sg">'</span><span class="st">order_by</span><span class="st st-sg">'</span>, [ - (<span class="st st-sg">'</span><span class="st">user_id</span><span class="st st-sg">'</span>, <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">User ID</span><span class="st st-sg">'</span>)), - (<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>, <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Username</span><span class="st st-sg">'</span>)), - (<span class="st st-sg">'</span><span class="st">register_date</span><span class="st st-sg">'</span>, <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Register date</span><span class="st st-sg">'</span>)), - (<span class="st st-sg">'</span><span class="st">post_count</span><span class="st st-sg">'</span>, <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Number of Posts</span><span class="st st-sg">'</span>)) - ], <span class="name">default</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">user_id</span><span class="st st-sg">'</span>), - <span class="name">SelectBox</span>(<span class="st st-sg">'</span><span class="st">direction</span><span class="st st-sg">'</span>, [ - (<span class="st st-sg">'</span><span class="st">desc</span><span class="st st-sg">'</span>, <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Descending</span><span class="st st-sg">'</span>)), - (<span class="st st-sg">'</span><span class="st">asc</span><span class="st st-sg">'</span>, <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Ascending</span><span class="st st-sg">'</span>)) - ], <span class="name">default</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">asc</span><span class="st st-sg">'</span>) - ) - - <span class="kw">if</span> <span class="st st-sg">'</span><span class="st">letter</span><span class="st st-sg">'</span> <span class="op op-word">in</span> <span class="name">req</span>.<span class="name">args</span> <span class="op op-word">or</span> <span class="st st-sg">'</span><span class="st">order_by</span><span class="st st-sg">'</span> <span class="op op-word">in</span> <span class="name">req</span>.<span class="name">args</span> \ - <span class="op op-word">or</span> <span class="st st-sg">'</span><span class="st">direction</span><span class="st st-sg">'</span> <span class="op op-word">in</span> <span class="name">req</span>.<span class="name">args</span>: - <span class="name">form</span>.<span class="name">update</span>(<span class="name">req</span>.<span class="name">args</span>) - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">form</span>.<span class="name">has_errors</span>: - <span class="name">generate</span> <span class="op">=</span> <span class="bn bn-pseudo">True</span> - - <span class="kw">else</span>: - <span class="name">generate</span> <span class="op">=</span> <span class="bn bn-pseudo">True</span> - <span class="kw">if</span> <span class="name">generate</span>: - <span class="name">d</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">to_dict</span>() - <span class="name">userlist</span> <span class="op">=</span> <span class="name">get_user_list</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, - <span class="name">order_by</span><span class="op">=</span><span class="bn">getattr</span>(<span class="name">users</span>.<span class="name">c</span>, <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">order_by</span><span class="st st-sg">'</span>]), - <span class="name">order</span><span class="op">=</span><span class="name">d</span>[<span class="st st-sg">'</span><span class="st">direction</span><span class="st st-sg">'</span>], - <span class="name">letter</span><span class="op">=</span><span class="name">d</span>[<span class="st st-sg">'</span><span class="st">letter</span><span class="st st-sg">'</span>] <span class="op op-word">or</span> <span class="bn bn-pseudo">None</span>, - <span class="name">hide_internal</span><span class="op">=</span><span class="bn bn-pseudo">True</span> - - ) - <span class="kw">else</span>: - <span class="name">userlist</span> <span class="op">=</span> [] - - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">memberlist.html</span><span class="st st-sg">'</span>, - <span class="bn">list</span><span class="op">=</span><span class="name">userlist</span>, - <span class="name">form</span><span class="op">=</span><span class="name">form</span>.<span class="name">generate</span>() - ) - - - -<span class="kw">class </span><span class="cls">UserPage</span>(<span class="name">RequestHandler</span>): - <span class="name">handler_regexes</span> <span class="op">=</span> [<span class="st st-sg">r'</span><span class="st">users/(?P<username>.+)$</span><span class="st st-sg">'</span>] - - <span class="kw">def </span><span class="fun">handle_request</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">username</span>): - <span class="cm"># TODO: add a permission CAN_VIEW_PROFILE</span> - - <span class="cm"># check avatar</span> - <span class="kw">if</span> <span class="name">req</span>.<span class="name">args</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">show</span><span class="st st-sg">'</span>) <span class="op">==</span> <span class="st st-sg">'</span><span class="st">avatar</span><span class="st st-sg">'</span>: - <span class="name">avatar</span> <span class="op">=</span> <span class="name">get_user_avatar</span>(<span class="name">req</span>, <span class="name">username</span>) - <span class="kw">if</span> <span class="name">avatar</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="kw">return</span> <span class="name">PageNotFound</span>() - <span class="name">resp</span> <span class="op">=</span> <span class="name">Response</span>(<span class="name">avatar</span>) - <span class="name">resp</span>[<span class="st st-sg">'</span><span class="st">Content-Type</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="st st-sg">'</span><span class="st">image/png</span><span class="st st-sg">'</span> - - <span class="kw">return</span> <span class="name">resp</span> - <span class="cm"># display user</span> - <span class="name">user</span> <span class="op">=</span> <span class="name">get_user</span>(<span class="name">req</span>, <span class="name">username</span>) - <span class="kw">if</span> <span class="name">user</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="kw">return</span> <span class="name">PageNotFound</span>() - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">user.html</span><span class="st st-sg">'</span>, - <span class="name">person</span> <span class="op">=</span> <span class="name">user</span> - - ) - - -<span class="kw">class </span><span class="cls">GotoPage</span>(<span class="name">RequestHandler</span>): - <span class="name">handler_regexes</span> <span class="op">=</span> [<span class="st st-sg">'</span><span class="st">goto$</span><span class="st st-sg">'</span>] - - <span class="kw">def </span><span class="fun">handle_request</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="kw">if</span> <span class="st st-sg">'</span><span class="st">post</span><span class="st st-sg">'</span> <span class="op op-word">in</span> <span class="name">req</span>.<span class="name">args</span>: - <span class="name">post_id</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">args</span>[<span class="st st-sg">'</span><span class="st">post</span><span class="st st-sg">'</span>] - <span class="name">post</span> <span class="op">=</span> <span class="name">get_post</span>(<span class="name">req</span>.<span class="name">ctx</span>, <span class="name">post_id</span>) - <span class="kw">while</span> <span class="name">post</span>.<span class="name">parent</span>: <span class="cm">#get root_post</span> - - <span class="name">post</span> <span class="op">=</span> <span class="name">post</span>.<span class="name">parent</span> <span class="op op-word">or</span> <span class="name">post</span> - <span class="name">thread</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">db</span>.<span class="name">get</span>(<span class="name">Thread</span>, <span class="name">Thread</span>.<span class="name">c</span>.<span class="name">root_post_id</span> <span class="op">==</span> <span class="name">post</span>.<span class="name">post_id</span>) - <span class="kw">return</span> <span class="name">HttpRedirect</span>(<span class="name">thread</span>.<span class="name">url</span>) - <span class="kw">else</span>: - <span class="kw">return</span> <span class="name">HttpRedirect</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">make_external_url</span>(<span class="st st-sg">'</span><span class="st">/</span><span class="st st-sg">'</span>)) - - - -<span class="kw">class </span><span class="cls">SplitPage</span>(<span class="name">RequestHandler</span>, <span class="name">RemoteCallable</span>): - <span class="name">handler_regexes</span> <span class="op">=</span> [<span class="st st-sg">r'</span><span class="st">post/(?P<post_id>\d+)/split$</span><span class="st st-sg">'</span>] - - <span class="kw">def </span><span class="fun">handle_request</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">post_id</span>): - <span class="kw">try</span>: - <span class="name">thread</span> <span class="op">=</span> <span class="name">Thread</span>.<span class="name">by_child</span>(<span class="name">req</span>.<span class="name">ctx</span>, <span class="name">post_id</span>) - <span class="kw">except</span> <span class="exc">ValueError</span>: - <span class="kw">return</span> <span class="name">PageNotFound</span>() - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">acl</span>.<span class="name">can_access</span>(<span class="st st-sg">'</span><span class="st">MODERATOR</span><span class="st st-sg">'</span>, <span class="name">thread</span>.<span class="name">forum_id</span>): - <span class="kw">return</span> <span class="name">AccessDeniedResponse</span>() - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">split.html</span><span class="st st-sg">'</span>, - <span class="name">thread</span> <span class="op">=</span> {<span class="st st-sg">'</span><span class="st">root_post_id</span><span class="st st-sg">'</span>:<span class="name">thread</span>.<span class="name">root_post_id</span>, <span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span>:<span class="name">thread</span>.<span class="name">title</span>} - ) - - <span class="deco">@export</span>(<span class="st st-sg">'</span><span class="st">split.get_post_tree</span><span class="st st-sg">'</span>) - <span class="kw">def </span><span class="fun">split</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">root_post_id</span>): - <span class="kw">def </span><span class="fun">iterate_items</span>(<span class="name">post_list</span>): - <span class="name">tmp</span> <span class="op">=</span> [] - <span class="kw">for</span> <span class="name">post</span> <span class="op op-word">in</span> <span class="name">post_list</span>: - <span class="name">tmp</span>.<span class="name">append</span>({ - <span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>: <span class="name">post</span>[<span class="st st-db">"</span><span class="st">post_id</span><span class="st st-db">"</span>], - <span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span>: <span class="name">post</span>[<span class="st st-db">"</span><span class="st">title</span><span class="st st-db">"</span>], - <span class="st st-sg">'</span><span class="st">children</span><span class="st st-sg">'</span>: <span class="st st-db">"</span><span class="st">children</span><span class="st st-db">"</span> <span class="op op-word">in</span> <span class="name">post</span> <span class="op op-word">and</span> \ - <span class="name">iterate_items</span>(<span class="name">post</span>[<span class="st st-db">"</span><span class="st">children</span><span class="st st-db">"</span>]) <span class="op op-word">or</span> [], - <span class="st st-sg">'</span><span class="st">parent_id</span><span class="st st-sg">'</span>: <span class="name">post</span>[<span class="st st-db">"</span><span class="st">parent_id</span><span class="st st-db">"</span>] - }) - <span class="kw">return</span> <span class="name">tmp</span> - - <span class="name">post_tree</span> <span class="op">=</span> <span class="name">get_post_tree</span>(<span class="name">req</span>, <span class="name">root_post_id</span>) - - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">acl</span>.<span class="name">can_access</span>(<span class="st st-sg">'</span><span class="st">MODERATOR</span><span class="st st-sg">'</span>, <span class="name">post_tree</span>[<span class="st st-db">"</span><span class="st">forum</span><span class="st st-db">"</span>][<span class="st st-db">"</span><span class="st">forum_id</span><span class="st st-db">"</span>]): - <span class="kw">return</span> <span class="name">AccessDeniedResponse</span>() - - <span class="kw">return</span> { - <span class="st st-sg">'</span><span class="st">posts</span><span class="st st-sg">'</span>:<span class="name">iterate_items</span>(<span class="name">post_tree</span>[<span class="st st-db">"</span><span class="st">posts</span><span class="st st-db">"</span>]), - <span class="st st-sg">'</span><span class="st">thread</span><span class="st st-sg">'</span>:{ - <span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>:<span class="name">post_tree</span>[<span class="st st-db">"</span><span class="st">forum</span><span class="st st-db">"</span>][<span class="st st-db">"</span><span class="st">forum_id</span><span class="st st-db">"</span>], - <span class="st st-sg">'</span><span class="st">root_post_id</span><span class="st st-sg">'</span>:<span class="name">post_tree</span>[<span class="st st-db">"</span><span class="st">post_id</span><span class="st st-db">"</span>] - } - } - - <span class="deco">@export</span>(<span class="st st-sg">'</span><span class="st">split.commit</span><span class="st st-sg">'</span>) - <span class="kw">def </span><span class="fun">commit</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">changes</span>): - <span class="cm"># TODO: Check whether operation is allowed at every subforum of a thread</span> - - <span class="cm"># the user changes</span> - <span class="kw">for</span> <span class="name">tmp</span> <span class="op op-word">in</span> <span class="name">changes</span>.<span class="name">iteritems</span>(): - <span class="name">change</span> <span class="op">=</span> <span class="name">tmp</span>[<span class="nb nb-int">1</span>] - <span class="bn">id</span> <span class="op">=</span> <span class="name">change</span>[<span class="st st-sg">'</span><span class="st">id</span><span class="st st-sg">'</span>] - <span class="name">new_pid</span> <span class="op">=</span> <span class="name">change</span>[<span class="st st-sg">'</span><span class="st">new_pid</span><span class="st st-sg">'</span>] - <span class="name">old_pid</span> <span class="op">=</span> <span class="name">change</span>[<span class="st st-sg">'</span><span class="st">old_pid</span><span class="st st-sg">'</span>] - <span class="name">act_tid</span> <span class="op">=</span> <span class="name">change</span>[<span class="st st-sg">'</span><span class="st">act_tid</span><span class="st st-sg">'</span>] - <span class="name">old_tid</span> <span class="op">=</span> <span class="name">change</span>[<span class="st st-sg">'</span><span class="st">old_tid</span><span class="st st-sg">'</span>] - <span class="name">post</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">db</span>.<span class="name">get</span>(<span class="name">Post</span>, <span class="name">Post</span>.<span class="name">c</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="bn">id</span>) - <span class="kw">if</span> <span class="name">new_pid</span> <span class="op">!=</span> <span class="op">-</span><span class="nb nb-int">1</span>: - <span class="name">post</span>.<span class="name">parent_id</span> <span class="op">=</span> <span class="name">new_pid</span> - - <span class="kw">else</span>: - <span class="kw">if</span> <span class="name">act_tid</span> <span class="op">==</span> <span class="op">-</span><span class="nb nb-int">1</span>: - <span class="cm">#XXX: forum_id</span> - <span class="name">thread</span> <span class="op">=</span> <span class="name">Thread</span>( - <span class="name">name</span> <span class="op">=</span> <span class="name">post</span>.<span class="name">name</span>, - <span class="name">forum_id</span> <span class="op">=</span> <span class="nb nb-int">1</span>, - <span class="name">root_post_id</span> <span class="op">=</span> <span class="name">post</span>.<span class="name">post_id</span> - - ) - <span class="name">req</span>.<span class="name">db</span>.<span class="name">save</span>(<span class="name">thread</span>) - <span class="kw">else</span>: - <span class="name">thread</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">db</span>.<span class="name">get</span>(<span class="name">Thread</span>, <span class="name">Thread</span>.<span class="name">c</span>.<span class="name">thread_id</span> <span class="op">==</span> <span class="name">act_tid</span>) - <span class="name">thread</span>.<span class="name">name</span> <span class="op">=</span> <span class="name">post</span>.<span class="name">name</span> - - <span class="name">post</span>.<span class="name">parent_id</span> <span class="op">=</span> <span class="name">thread</span>.<span class="name">thread_id</span> - <span class="name">req</span>.<span class="name">db</span>.<span class="name">flush</span>() - <span class="kw">return</span> <span class="st st-db">""</span> - - -<span class="kw">class </span><span class="cls">WhoIsOnlinePage</span>(<span class="name">RequestHandler</span>, <span class="name">PagePublisher</span>): - <span class="name">page_name</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">whoisonline</span><span class="st st-sg">'</span> - <span class="name">relative_url</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">whoisonline</span><span class="st st-sg">'</span> - - <span class="name">handler_regexes</span> <span class="op">=</span> [<span class="st st-sg">r'</span><span class="st">whoisonline$</span><span class="st st-sg">'</span>] - - <span class="kw">def </span><span class="fun">handle_request</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="name">sessions</span>, <span class="name">users</span>, <span class="name">guests</span>, <span class="name">total</span> <span class="op">=</span> <span class="name">get_active_sessions</span>(<span class="name">req</span>.<span class="name">ctx</span>) - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">whoisonline.html</span><span class="st st-sg">'</span>, - <span class="name">sessions</span><span class="op">=</span><span class="name">sessions</span>, - <span class="name">user_count</span><span class="op">=</span><span class="name">users</span>, - <span class="name">guest_count</span><span class="op">=</span><span class="name">guests</span>, - <span class="name">total_count</span><span class="op">=</span><span class="name">total</span> - - ) - - -<span class="kw">class </span><span class="cls">UserSettings</span>(<span class="name">RequestHandler</span>, <span class="name">PagePublisher</span>): - <span class="name">page_name</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">settings</span><span class="st st-sg">'</span> - <span class="name">relative_url</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">settings/</span><span class="st st-sg">'</span> - - <span class="name">handler_regexes</span> <span class="op">=</span> [ - <span class="st st-sg">r'</span><span class="st">settings/$</span><span class="st st-sg">'</span>, - <span class="st st-sg">r'</span><span class="st">settings/(?P<page>.+?)$</span><span class="st st-sg">'</span> - ] - <span class="name">allow_username_change</span> <span class="op">=</span> <span class="name">cfg</span>.<span class="name">bool</span>(<span class="st st-sg">'</span><span class="st">security</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">username_change</span><span class="st st-sg">'</span>, <span class="bn bn-pseudo">False</span>) - - <span class="kw">def </span><span class="fun">handle_request</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">page</span><span class="op">=</span><span class="bn bn-pseudo">None</span>): - <span class="name">req</span>.<span class="name">user</span>.<span class="name">assert_logged_in</span>() - <span class="name">sidebar</span> <span class="op">=</span> [] - <span class="name">missing</span> <span class="op">=</span> <span class="bn">object</span>() - <span class="name">page_result</span> <span class="op">=</span> <span class="name">missing</span> - - <span class="kw">for</span> <span class="name">comp</span> <span class="op op-word">in</span> <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">get_components</span>(<span class="name">UserSettingsPage</span>): - <span class="name">caption</span> <span class="op">=</span> <span class="name">comp</span>.<span class="name">get_settings_link_title</span>(<span class="name">req</span>) - <span class="cm"># if the caption is None the plugin doesn't want to</span> - - <span class="cm"># be visible in the sidebar, skip</span> - <span class="kw">if</span> <span class="name">caption</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="kw">continue</span> - <span class="name">active</span> <span class="op">=</span> <span class="name">comp</span>.<span class="name">settings_page_identifier</span> <span class="op">==</span> <span class="name">page</span> - - <span class="kw">if</span> <span class="name">active</span>: - <span class="name">page_result</span> <span class="op">=</span> <span class="name">comp</span>.<span class="name">get_settings_page</span>(<span class="name">req</span>) - <span class="cm"># the page really wants to output data on its own</span> - - <span class="cm"># we don't need to create a sidebar, stop here</span> - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="name">page_result</span>, <span class="name">Response</span>): - <span class="kw">return</span> <span class="name">page_result</span> - - <span class="name">sidebar</span>.<span class="name">append</span>({ - <span class="st st-sg">'</span><span class="st">url</span><span class="st st-sg">'</span>: <span class="name">comp</span>.<span class="name">url</span>, - <span class="st st-sg">'</span><span class="st">caption</span><span class="st st-sg">'</span>: <span class="name">caption</span>, - <span class="st st-sg">'</span><span class="st">active</span><span class="st st-sg">'</span>: <span class="name">active</span>, - <span class="st st-sg">'</span><span class="st">identifier</span><span class="st st-sg">'</span>: <span class="name">comp</span>.<span class="name">settings_page_identifier</span> - - }) - <span class="cm"># display error page</span> - <span class="kw">if</span> <span class="name">page_result</span> <span class="op op-word">is</span> <span class="name">missing</span> <span class="op op-word">and</span> <span class="name">page</span> <span class="op op-word">is</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">None</span>: - <span class="kw">return</span> <span class="name">PageNotFound</span>() - <span class="cm"># we have found a page, display it, but first sort the sidebar</span> - - <span class="name">sidebar</span>.<span class="name">sort</span>(<span class="name">key</span><span class="op">=</span><span class="kw">lambda</span> <span class="name">x</span>: <span class="name">x</span>[<span class="st st-sg">'</span><span class="st">caption</span><span class="st st-sg">'</span>].<span class="name">lower</span>()) - <span class="kw">if</span> <span class="name">page</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">settings/index.html</span><span class="st st-sg">'</span>, - <span class="name">setting_pages</span> <span class="op">=</span> <span class="name">sidebar</span> - - ) - <span class="name">template</span>, <span class="name">context</span> <span class="op">=</span> <span class="name">page_result</span> - <span class="name">context</span>[<span class="st st-sg">'</span><span class="st">setting_pages</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">sidebar</span> - - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="name">template</span>, <span class="op">**</span><span class="name">context</span>) - - -<span class="kw">class </span><span class="cls">LostPasswordPage</span>(<span class="name">RequestHandler</span>, <span class="name">PagePublisher</span>): - <span class="name">page_name</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">lostpassword</span><span class="st st-sg">'</span> - - <span class="name">relative_url</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">lostpassword</span><span class="st st-sg">'</span> - <span class="name">handler_regexes</span> <span class="op">=</span> [<span class="st st-sg">'</span><span class="st">lostpassword$</span><span class="st st-sg">'</span>] - - <span class="kw">def </span><span class="fun">handle_request</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="cm"># if the user is identified he has probably not lost has password ;)</span> - - <span class="kw">if</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">identified</span>: - <span class="kw">return</span> <span class="name">HttpRedirect</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">make_external_url</span>(<span class="st st-sg">''</span>)) - - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - - <span class="name">ctx</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span> - <span class="name">msg</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - <span class="name">form</span> <span class="op">=</span> <span class="name">Form</span>(<span class="name">req</span>, <span class="bn bn-pseudo">self</span>, <span class="st st-sg">'</span><span class="st">POST</span><span class="st st-sg">'</span>, - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>, <span class="name">validator</span><span class="op">=</span><span class="name">isExistingUsername</span>()), - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">email</span><span class="st st-sg">'</span>, <span class="name">validator</span><span class="op">=</span><span class="name">isEmail</span>()) - ) - - <span class="kw">if</span> <span class="name">req</span>.<span class="name">method</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">POST</span><span class="st st-sg">'</span>: - <span class="name">form</span>.<span class="name">update</span>(<span class="name">req</span>.<span class="name">form</span>, <span class="name">prefix</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">f_</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">form</span>.<span class="name">has_errors</span>: - <span class="name">d</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">to_dict</span>() - <span class="name">password</span> <span class="op">=</span> <span class="name">reset_password</span>(<span class="name">ctx</span>, <span class="op">**</span><span class="name">d</span>) - <span class="kw">if</span> <span class="name">password</span> <span class="op op-word">is</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">None</span>: - <span class="name">text</span> <span class="op">=</span> <span class="name">render_template</span>(<span class="name">req</span>, <span class="st st-sg">'</span><span class="st">mails/new_password.txt</span><span class="st st-sg">'</span>, { - <span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>: <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>], - <span class="st st-sg">'</span><span class="st">password</span><span class="st st-sg">'</span>: <span class="name">password</span> - - }) - <span class="name">mail</span> <span class="op">=</span> <span class="name">Email</span>(<span class="name">ctx</span>, <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">New password</span><span class="st st-sg">'</span>), <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">email</span><span class="st st-sg">'</span>], <span class="name">text</span>) - <span class="name">mail</span>.<span class="name">send</span>() - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">messages/password.html</span><span class="st st-sg">'</span>, <span class="op">**</span><span class="name">d</span>) - <span class="kw">else</span>: - <span class="name">msg</span> <span class="op">=</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Creation of a new password failed. Username </span><span class="st st-sg">'</span> - - <span class="st st-sg">'</span><span class="st">or email address is invalid.</span><span class="st st-sg">'</span>) - - <span class="kw">return</span> <span class="name">TemplateResponse</span>(<span class="st st-sg">'</span><span class="st">lostpassword.html</span><span class="st st-sg">'</span>, - <span class="name">form</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">generate</span>(<span class="name">prefix</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">f_</span><span class="st st-sg">'</span>), - <span class="name">msg</span> <span class="op">=</span> <span class="name">msg</span> - - ) -<span class="cm"># -*- coding: utf-8 -*-</span> -<span class="st st-db">"""</span><span class="st"> - pocoo.pkg.core.remotecall - ~~~~~~~~~~~~~~~~~~~~~~~~~ - - Pocoo remote call support. - - - Remote Call Implementation - ========================== - - The Pocoo XMLRPC/JSONRPC interface works like this:: - - import time - from pocoo.pkg.core.remotecall import RemoteCallable, export - - class MyClass(RemoteCallable): - - @export("test.hello_world") - def say(self, req, name='World'): - return 'Hello </span><span class="st st-int">%s</span><span class="st">!' % name - - @export("test.get_servertime") - def servertime(self, req): - return time.time() - - By now only jsonrpc is available. You can query the jsonrpc interface - under ``/!jsonrpc``. The exported names are ``packagename.<name>``. - So for the example above the method names are (assumed that the module - is in package ``core``):: - - core.test.hello_world - - and:: - - core.test.get_servertime - - - JavaScript Query - ================= - - You can query those functions using the following syntax:: - - var rpc = new pocoo.lib.async.RPC('!jsonrpc'); - var method = rpc.getMethod('methodname'); - method(arguments, kwarguments, callback); - - The query for the example above would be:: - - var rpc = new pocoo.lib.async.RPC('!jsonrpc'); - var method = rpc.getMethod('core.test.hello_world'); - method(["Benjamin"], {}, function (result) { - alert(result); - // alerts "Hello Benjamin!" - - }); - - - :copyright: 2006 by Armin Ronacher. - :license: GNU GPL, see LICENSE for more details. -</span><span class="st st-db">"""</span> -<span class="kw">import </span><span class="cls">new</span> -<span class="kw">from </span><span class="cls">types</span><span class="kw"> import</span> <span class="name">FunctionType</span> -<span class="kw">from </span><span class="cls">pocoo</span><span class="kw"> import</span> <span class="name">Component</span>, <span class="name">ComponentMeta</span> - -<span class="kw">from </span><span class="cls">pocoo.http</span><span class="kw"> import</span> <span class="name">DirectResponse</span> -<span class="kw">from </span><span class="cls">pocoo.application</span><span class="kw"> import</span> <span class="name">RequestHandler</span> -<span class="kw">from </span><span class="cls">pocoo.http</span><span class="kw"> import</span> <span class="name">Response</span> - -<span class="kw">from </span><span class="cls">pocoo.utils</span><span class="kw"> import</span> <span class="name">json</span> - - -<span class="kw">class </span><span class="cls">_RemoteCallableMeta</span>(<span class="name">ComponentMeta</span>): - - <span class="kw">def </span><span class="fun">__new__</span>(<span class="name">cls</span>, <span class="name">name</span>, <span class="name">bases</span>, <span class="name">dct</span>): - <span class="name">rpc_exports</span> <span class="op">=</span> {} - <span class="name">result</span> <span class="op">=</span> <span class="name">ComponentMeta</span>.<span class="name">__new__</span>(<span class="name">cls</span>, <span class="name">name</span>, <span class="name">bases</span>, <span class="name">dct</span>) - <span class="kw">for</span> <span class="name">name</span>, <span class="name">ref</span> <span class="op op-word">in</span> <span class="name">dct</span>.<span class="name">iteritems</span>(): - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="name">ref</span>, <span class="name">FunctionType</span>) <span class="op op-word">and</span> \ - <span class="bn">getattr</span>(<span class="name">ref</span>, <span class="st st-sg">'</span><span class="st">rpc_exported</span><span class="st st-sg">'</span>, <span class="bn bn-pseudo">False</span>): - <span class="name">name</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st st-int">%s</span><span class="st">.</span><span class="st st-int">%s</span><span class="st st-sg">'</span> <span class="op">%</span> (<span class="name">ref</span>.<span class="name">__module__</span>.<span class="name">split</span>(<span class="st st-sg">'</span><span class="st">.</span><span class="st st-sg">'</span>)[<span class="nb nb-int">2</span>], - <span class="name">ref</span>.<span class="name">rpc_name</span>) - <span class="name">rpc_exports</span>[<span class="name">name</span>] <span class="op">=</span> <span class="name">ref</span> - - <span class="name">result</span>.<span class="name">rpc_exports</span> <span class="op">=</span> <span class="name">rpc_exports</span> - <span class="kw">return</span> <span class="name">result</span> - - -<span class="kw">class </span><span class="cls">RemoteCallable</span>(<span class="name">Component</span>): - <span class="st st-db">"""</span><span class="st"> - - Components inheriting from this base component can export methods - for jsonrpc if they are decorated using `export`. - - Example:: - - from pocoo.pkg.core.remotecall import RemoteCallable, export - - class MyExport(RemoteCallable): - </span><span class="st st-db">"""</span> - <span class="name">__metaclass__</span> <span class="op">=</span> <span class="name">_RemoteCallableMeta</span> - - -<span class="kw">class </span><span class="cls">RemoteCallManager</span>(<span class="name">RequestHandler</span>): - - <span class="name">handler_regexes</span> <span class="op">=</span> [<span class="st st-sg">r'</span><span class="st">!jsonrpc$</span><span class="st st-sg">'</span>] - - <span class="kw">def </span><span class="fun">__init__</span>(<span class="bn bn-pseudo">self</span>, <span class="name">ctx</span>): - <span class="bn">super</span>(<span class="name">RemoteCallManager</span>, <span class="bn bn-pseudo">self</span>).<span class="name">__init__</span>(<span class="name">ctx</span>) - <span class="bn bn-pseudo">self</span>.<span class="name">_mapping</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="kw">def </span><span class="fun">handle_request</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="cm"># TODO: once jsonrpc1.1 is finished: update error codes</span> - <span class="kw">if</span> <span class="bn bn-pseudo">self</span>.<span class="name">_mapping</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="bn bn-pseudo">self</span>.<span class="name">_mapping</span> <span class="op">=</span> {} - <span class="kw">for</span> <span class="name">comp</span> <span class="op op-word">in</span> <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">get_components</span>(<span class="name">RemoteCallable</span>): - <span class="kw">for</span> <span class="name">name</span>, <span class="name">ref</span> <span class="op op-word">in</span> <span class="name">comp</span>.<span class="name">rpc_exports</span>.<span class="name">iteritems</span>(): - <span class="name">handler</span> <span class="op">=</span> <span class="name">new</span>.<span class="name">instancemethod</span>(<span class="name">ref</span>, <span class="name">comp</span>, <span class="name">comp</span>.<span class="name">__class__</span>) - <span class="bn bn-pseudo">self</span>.<span class="name">_mapping</span>[<span class="name">name</span>] <span class="op">=</span> <span class="name">handler</span> - - <span class="bn">id</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - <span class="kw">try</span>: - <span class="name">method</span>, <span class="name">args</span>, <span class="name">kwargs</span>, <span class="bn">id</span> <span class="op">=</span> <span class="name">json</span>.<span class="name">parse_jsonrpc_request</span>(<span class="name">req</span>.<span class="name">data</span>) - <span class="name">handler</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">_mapping</span>[<span class="name">method</span>] - <span class="name">json_data</span> <span class="op">=</span> { - <span class="st st-sg">'</span><span class="st">version</span><span class="st st-sg">'</span>: <span class="st st-sg">'</span><span class="st">1.1</span><span class="st st-sg">'</span>, - <span class="st st-sg">'</span><span class="st">result</span><span class="st st-sg">'</span>: <span class="name">handler</span>(<span class="name">req</span>, <span class="op">*</span><span class="name">args</span>, <span class="op">**</span><span class="name">kwargs</span>) - } - <span class="kw">if</span> <span class="bn">id</span> <span class="op op-word">is</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">None</span>: - <span class="name">json_data</span>[<span class="st st-sg">'</span><span class="st">id</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="bn">id</span> - - <span class="kw">except</span> <span class="name">DirectResponse</span>, <span class="name">e</span>: - <span class="kw">return</span> <span class="name">e</span>.<span class="name">args</span>[<span class="nb nb-int">0</span>] - <span class="kw">except</span> <span class="exc">Exception</span>, <span class="name">e</span>: - <span class="name">error</span> <span class="op">=</span> { - <span class="st st-sg">'</span><span class="st">msg</span><span class="st st-sg">'</span>: <span class="bn">str</span>(<span class="name">e</span>), - <span class="st st-sg">'</span><span class="st">type</span><span class="st st-sg">'</span>: <span class="name">e</span>.<span class="name">__class__</span>.<span class="name">__name__</span> - - } - <span class="kw">for</span> <span class="name">name</span>, <span class="name">ref</span> <span class="op op-word">in</span> <span class="name">e</span>.<span class="name">__dict__</span>.<span class="name">iteritems</span>(): - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">name</span>.<span class="name">startswith</span>(<span class="st st-sg">'</span><span class="st">_</span><span class="st st-sg">'</span>) <span class="op op-word">and</span>\ - <span class="bn">isinstance</span>(<span class="name">ref</span>, (<span class="bn">str</span>, <span class="bn">unicode</span>, <span class="bn">int</span>, <span class="bn">float</span>, <span class="bn">tuple</span>, - <span class="bn">list</span>, <span class="bn">dict</span>)): - <span class="name">error</span>[<span class="name">name</span>] <span class="op">=</span> <span class="name">ref</span> - - <span class="name">json_data</span> <span class="op">=</span> { - <span class="st st-sg">'</span><span class="st">version</span><span class="st st-sg">'</span>: <span class="st st-sg">'</span><span class="st">1.1</span><span class="st st-sg">'</span>, - <span class="st st-sg">'</span><span class="st">error</span><span class="st st-sg">'</span>: { - <span class="st st-sg">'</span><span class="st">name</span><span class="st st-sg">'</span>: <span class="st st-sg">'</span><span class="st">JSONRPCError</span><span class="st st-sg">'</span>, - <span class="st st-sg">'</span><span class="st">code</span><span class="st st-sg">'</span>: <span class="nb nb-oct">000</span>, - <span class="st st-sg">'</span><span class="st">message</span><span class="st st-sg">'</span>: <span class="st st-sg">'</span><span class="st">An error occurred parsing the request object.</span><span class="st st-sg">'</span>, - <span class="st st-sg">'</span><span class="st">error</span><span class="st st-sg">'</span>: <span class="name">error</span> - - } - } - <span class="kw">if</span> <span class="bn">id</span> <span class="op op-word">is</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">None</span>: - <span class="name">json_data</span>[<span class="st st-sg">'</span><span class="st">id</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="bn">id</span> - - <span class="kw">return</span> <span class="name">Response</span>(<span class="name">json</span>.<span class="name">dumps</span>(<span class="name">json_data</span>), - [(<span class="st st-sg">'</span><span class="st">Content-Type</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">text/javascript</span><span class="st st-sg">'</span>)]) - - -<span class="kw">def </span><span class="fun">export</span>(<span class="name">name</span>): - <span class="st st-db">"""</span><span class="st"> - - Exports a function in a RemoteCallable component. - </span><span class="st st-db">"""</span> - <span class="kw">def </span><span class="fun">wrapped</span>(<span class="name">f</span>): - <span class="name">f</span>.<span class="name">rpc_exported</span> <span class="op">=</span> <span class="bn bn-pseudo">True</span> - - <span class="name">f</span>.<span class="name">rpc_name</span> <span class="op">=</span> <span class="name">name</span> - <span class="kw">return</span> <span class="name">f</span> - <span class="kw">return</span> <span class="name">wrapped</span> - -<span class="cm"># -*- coding: utf-8 -*-</span> -<span class="st st-db">"""</span><span class="st"> - pocoo.pkg.core.restformat - ~~~~~~~~~~~~~~~~~~~~~~~~~ - - Pocoo ReST Parser. - - A thin wrapper around the docutils ReST parser. - - :copyright: 2006 by Georg Brandl. - :license: GNU GPL, see LICENSE for more details. -</span><span class="st st-db">"""</span> - -<span class="kw">from </span><span class="cls">pocoo.pkg.core.textfmt</span><span class="kw"> import</span> <span class="name">MarkupFormat</span> -<span class="kw">from </span><span class="cls">pocoo.utils.html</span><span class="kw"> import</span> <span class="name">escape_html</span> - -<span class="kw">from </span><span class="cls">pocoo.pkg.core.smilies</span><span class="kw"> import</span> <span class="name">replace_smilies</span> - - -<span class="kw">class </span><span class="cls">ReST</span>(<span class="name">MarkupFormat</span>): - <span class="st st-db">"""</span><span class="st"> - ReST markup format. - </span><span class="st st-db">"""</span> - - <span class="name">name</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">rest</span><span class="st st-sg">'</span> - - <span class="kw">def </span><span class="fun">parse</span>(<span class="bn bn-pseudo">self</span>, <span class="name">text</span>, <span class="name">signature</span>): - <span class="kw">from </span><span class="cls">docutils.core</span><span class="kw"> import</span> <span class="name">publish_parts</span> - - <span class="kw">try</span>: - <span class="name">parts</span> <span class="op">=</span> <span class="name">publish_parts</span>(<span class="name">source</span><span class="op">=</span><span class="name">text</span>, <span class="name">writer_name</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">html4css1</span><span class="st st-sg">'</span>) - <span class="name">text</span> <span class="op">=</span> <span class="name">parts</span>[<span class="st st-sg">'</span><span class="st">fragment</span><span class="st st-sg">'</span>].<span class="name">strip</span>() - <span class="kw">except</span> <span class="exc">Exception</span>: - <span class="cm"># TODO: figure out which exceptions this can raise</span> - - <span class="name">text</span> <span class="op">=</span> <span class="name">escape_html</span>(<span class="name">text</span>).<span class="name">strip</span>() - <span class="cm">#XXX: render smilies just in text blocks</span> - <span class="kw">return</span> <span class="name">replace_smilies</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, <span class="name">text</span>) - - <span class="kw">def </span><span class="fun">quote_text</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">text</span>, <span class="name">username</span><span class="op">=</span><span class="bn bn-pseudo">None</span>): - <span class="name">lines</span> <span class="op">=</span> [<span class="name">u</span><span class="st st-sg">'</span><span class="st"> </span><span class="st st-int">%s</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">line</span> <span class="kw">for</span> <span class="name">line</span> <span class="op op-word">in</span> <span class="name">text</span>.<span class="name">splitlines</span>()] - <span class="kw">if</span> <span class="name">username</span> <span class="op op-word">is</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">None</span>: - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - - <span class="name">lines</span>.<span class="name">insert</span>(<span class="nb nb-int">0</span>, (<span class="name">u</span><span class="st st-sg">'</span><span class="st"> **</span><span class="st st-int">%s</span><span class="st">**:</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st st-int">%s</span><span class="st"> wrote</span><span class="st st-sg">'</span>)) <span class="op">%</span> <span class="name">username</span>) - <span class="kw">return</span> <span class="name">u</span><span class="st st-sg">'</span><span class="st st-esc">\n</span><span class="st st-sg">'</span>.<span class="name">join</span>(<span class="name">lines</span>) - -<span class="cm"># -*- coding: utf-8 -*-</span> -<span class="st st-db">"""</span><span class="st"> - pocoo.pkg.core.search - ~~~~~~~~~~~~~~~~~~~~~ - - Pocoo Search System - - :copyright: 2006 by Armin Ronacher. - :license: GNU GPL, see LICENSE for more details. -</span><span class="st st-db">"""</span> -<span class="kw">from </span><span class="cls">pocoo</span><span class="kw"> import</span> <span class="name">Component</span> -<span class="kw">from </span><span class="cls">pocoo.application</span><span class="kw"> import</span> <span class="name">LinkableMixin</span> - -<span class="kw">from </span><span class="cls">shlex</span><span class="kw"> import</span> <span class="name">split</span> - - -<span class="cm">#XXX: some kind of early draft</span> -<span class="kw">class </span><span class="cls">Query</span>(<span class="bn">object</span>): - <span class="st st-db">"""</span><span class="st"> - - Search Query Object - </span><span class="st st-db">"""</span> - - <span class="kw">def </span><span class="fun">__init__</span>(<span class="bn bn-pseudo">self</span>, <span class="name">rule</span>): - <span class="bn bn-pseudo">self</span>.<span class="name">text</span> <span class="op">=</span> <span class="name">rule</span> - - <span class="bn bn-pseudo">self</span>.<span class="name">required</span> <span class="op">=</span> [] - <span class="bn bn-pseudo">self</span>.<span class="name">unwanted</span> <span class="op">=</span> [] - <span class="bn bn-pseudo">self</span>.<span class="name">optional</span> <span class="op">=</span> [] - <span class="name">next</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="name">first</span> <span class="op">=</span> <span class="bn bn-pseudo">True</span> - <span class="kw">for</span> <span class="name">token</span> <span class="op op-word">in</span> <span class="name">split</span>(<span class="name">rule</span>): - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">next</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="bn">getattr</span>(<span class="bn bn-pseudo">self</span>, <span class="name">next</span>).<span class="name">append</span>(<span class="name">token</span>) - <span class="name">next</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="kw">if</span> <span class="name">token</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">NOT</span><span class="st st-sg">'</span>: - <span class="name">next</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">unwanted</span><span class="st st-sg">'</span> - <span class="kw">elif</span> <span class="name">token</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">AND</span><span class="st st-sg">'</span>: - <span class="name">next</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">required</span><span class="st st-sg">'</span> - - <span class="kw">elif</span> <span class="name">token</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">OR</span><span class="st st-sg">'</span>: - <span class="name">next</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">optional</span><span class="st st-sg">'</span> - <span class="kw">else</span>: - <span class="kw">if</span> <span class="name">token</span>.<span class="name">startswith</span>(<span class="st st-sg">'</span><span class="st">+</span><span class="st st-sg">'</span>): - <span class="name">token</span> <span class="op">=</span> <span class="name">token</span>[<span class="nb nb-int">1</span>:] - <span class="bn bn-pseudo">self</span>.<span class="name">required</span>.<span class="name">append</span>(<span class="name">token</span>) - <span class="kw">elif</span> <span class="name">token</span>.<span class="name">startswith</span>(<span class="st st-sg">'</span><span class="st">-</span><span class="st st-sg">'</span>): - <span class="name">token</span> <span class="op">=</span> <span class="name">token</span>[<span class="nb nb-int">1</span>:] - <span class="bn bn-pseudo">self</span>.<span class="name">unwanted</span>.<span class="name">append</span>(<span class="name">token</span>) - <span class="kw">elif</span> <span class="name">first</span>: - <span class="bn bn-pseudo">self</span>.<span class="name">required</span>.<span class="name">append</span>(<span class="name">token</span>) - <span class="name">first</span> <span class="op">=</span> <span class="bn bn-pseudo">False</span> - - <span class="kw">else</span>: - <span class="bn bn-pseudo">self</span>.<span class="name">optional</span>.<span class="name">append</span>(<span class="name">token</span>) - <span class="name">first</span> <span class="op">=</span> <span class="bn bn-pseudo">False</span> - - <span class="bn bn-pseudo">self</span>.<span class="name">words</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">required</span> <span class="op">+</span> <span class="bn bn-pseudo">self</span>.<span class="name">unwanted</span> <span class="op">+</span> <span class="bn bn-pseudo">self</span>.<span class="name">optional</span> - - <span class="kw">def </span><span class="fun">__iter__</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="bn">iter</span>(<span class="bn bn-pseudo">self</span>.<span class="name">words</span>) - - <span class="kw">def </span><span class="fun">__len__</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="bn">len</span>(<span class="bn bn-pseudo">self</span>.<span class="name">words</span>) - - <span class="kw">def </span><span class="fun">is_required</span>(<span class="bn bn-pseudo">self</span>, <span class="name">word</span>): - <span class="kw">return</span> <span class="name">word</span> <span class="op op-word">in</span> <span class="bn bn-pseudo">self</span>.<span class="name">required</span> - - <span class="kw">def </span><span class="fun">is_unwanted</span>(<span class="bn bn-pseudo">self</span>, <span class="name">word</span>): - <span class="kw">return</span> <span class="name">word</span> <span class="op op-word">in</span> <span class="bn bn-pseudo">self</span>.<span class="name">unwanted</span> - - <span class="kw">def </span><span class="fun">is_optional</span>(<span class="bn bn-pseudo">self</span>, <span class="name">word</span>): - <span class="kw">return</span> <span class="name">word</span> <span class="op op-word">in</span> <span class="bn bn-pseudo">self</span>.<span class="name">optional</span> - - <span class="kw">def </span><span class="fun">__repr__</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="st st-sg">'</span><span class="st"><</span><span class="st st-int">%s</span><span class="st"> </span><span class="st st-int">%r</span><span class="st">></span><span class="st st-sg">'</span> <span class="op">%</span> ( - <span class="bn bn-pseudo">self</span>.<span class="name">__class__</span>.<span class="name">__name__</span>, - <span class="bn bn-pseudo">self</span>.<span class="name">text</span> - - ) - - -<span class="cm">#XXX: early draft</span> -<span class="kw">class </span><span class="cls">Result</span>(<span class="bn">object</span>, <span class="name">LinkableMixin</span>): - <span class="st st-db">"""</span><span class="st"> - Search result object. - </span><span class="st st-db">"""</span> - - <span class="kw">def </span><span class="fun">__init__</span>(<span class="bn bn-pseudo">self</span>, <span class="name">ctx</span>, <span class="name">title</span>, <span class="name">relative_url</span>, <span class="name">description</span>): - <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span> <span class="op">=</span> <span class="name">ctx</span> - - <span class="bn bn-pseudo">self</span>.<span class="name">title</span> <span class="op">=</span> <span class="name">title</span> - <span class="bn bn-pseudo">self</span>.<span class="name">relative_url</span> <span class="op">=</span> <span class="name">relative_url</span> - - <span class="bn bn-pseudo">self</span>.<span class="name">description</span> <span class="op">=</span> <span class="name">description</span> - - <span class="kw">def </span><span class="fun">__repr__</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="st st-sg">'</span><span class="st"><</span><span class="st st-int">%s</span><span class="st"> </span><span class="st st-int">%r</span><span class="st">></span><span class="st st-sg">'</span> <span class="op">%</span> ( - <span class="bn bn-pseudo">self</span>.<span class="name">__class__</span>.<span class="name">__name__</span>, - <span class="bn bn-pseudo">self</span>.<span class="name">title</span> - - ) - - -<span class="kw">class </span><span class="cls">SearchProvider</span>(<span class="name">Component</span>): - <span class="cm">#: name of the search provider</span> - <span class="name">name</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="kw">def </span><span class="fun">get_title</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="st st-db">"""</span><span class="st">Return a translated version of the search provider name.</span><span class="st st-db">"""</span> - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">__class__</span>.<span class="name">__name__</span> - - <span class="kw">def </span><span class="fun">can_search</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="st st-db">"""</span><span class="st">Return True if a user is allowed to use this search provider.</span><span class="st st-db">"""</span> - <span class="kw">return</span> <span class="bn bn-pseudo">True</span> - - <span class="kw">def </span><span class="fun">query</span>(<span class="bn bn-pseudo">self</span>, <span class="name">query</span>): - <span class="st st-db">"""</span><span class="st">Perform a query, has to return an iterable of result objects.</span><span class="st st-db">"""</span> - <span class="kw">return</span> () -<span class="cm"># -*- coding: utf-8 -*-</span> -<span class="st st-db">"""</span><span class="st"> - - pocoo.pkg.core.session - ~~~~~~~~~~~~~~~~~~~~~~ - - Pocoo session handling. - - :copyright: 2006 by Georg Brandl, Armin Ronacher. - :license: GNU GPL, see LICENSE for more details. -</span><span class="st st-db">"""</span> - -<span class="kw">import </span><span class="cls">md5</span> -<span class="kw">import </span><span class="cls">time</span> -<span class="kw">import </span><span class="cls">random</span> - -<span class="kw">from </span><span class="cls">datetime</span><span class="kw"> import</span> <span class="name">datetime</span>, <span class="name">timedelta</span> - -<span class="kw">from </span><span class="cls">pocoo.application</span><span class="kw"> import</span> <span class="name">RequestWrapper</span> -<span class="kw">from </span><span class="cls">pocoo.settings</span><span class="kw"> import</span> <span class="name">cfg</span> -<span class="kw">from </span><span class="cls">pocoo.db</span><span class="kw"> import</span> <span class="name">meta</span> - -<span class="kw">from </span><span class="cls">pocoo.utils.uri</span><span class="kw"> import</span> <span class="name">urlencode</span> -<span class="kw">from </span><span class="cls">pocoo.pkg.core.db</span><span class="kw"> import</span> <span class="name">sessions</span>, <span class="name">users</span> -<span class="kw">from </span><span class="cls">pocoo.pkg.core.auth</span><span class="kw"> import</span> <span class="name">get_auth_provider</span> - - -<span class="kw">def </span><span class="fun">get_active_sessions</span>(<span class="name">ctx</span>, <span class="name">delta</span><span class="op">=</span><span class="name">timedelta</span>(<span class="name">minutes</span><span class="op">=</span><span class="nb nb-int">5</span>)): - <span class="st st-db">"""</span><span class="st"> - Return a tuple in the following form:: - - (sessions, user_count, guest_count, total) - - sessions is a dict for the template with all relevant - information about the sessions, user_count is the - amount of all logged in users, guest_count is the - amount of all anonymous users and total is the total - number of all sessions being active. - </span><span class="st st-db">"""</span> - - <span class="name">provider</span> <span class="op">=</span> <span class="name">get_auth_provider</span>(<span class="name">ctx</span>) - <span class="name">now</span> <span class="op">=</span> <span class="name">datetime</span>.<span class="name">utcnow</span>() - <span class="kw">def </span><span class="fun">do</span>(<span class="name">con</span>): - <span class="name">session_list</span> <span class="op">=</span> [] - <span class="name">user_count</span> <span class="op">=</span> <span class="nb nb-int">0</span> - - <span class="name">guest_count</span> <span class="op">=</span> <span class="nb nb-int">0</span> - <span class="name">r</span> <span class="op">=</span> <span class="name">con</span>.<span class="name">execute</span>(<span class="name">sessions</span>.<span class="name">select</span>( - <span class="name">sessions</span>.<span class="name">c</span>.<span class="name">last_reload</span> <span class="op">></span> <span class="name">now</span> <span class="op">-</span> <span class="name">delta</span> - - )) - <span class="kw">while</span> <span class="bn bn-pseudo">True</span>: - <span class="name">row</span> <span class="op">=</span> <span class="name">r</span>.<span class="name">fetchone</span>() - <span class="kw">if</span> <span class="name">row</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="kw">break</span> - - <span class="name">user</span> <span class="op">=</span> <span class="name">con</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>([<span class="name">users</span>.<span class="name">c</span>.<span class="name">user_id</span>, <span class="name">users</span>.<span class="name">c</span>.<span class="name">username</span>], - <span class="name">users</span>.<span class="name">c</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">provider</span>.<span class="name">get_user_id</span>(<span class="name">row</span>[<span class="st st-sg">'</span><span class="st">data</span><span class="st st-sg">'</span>]) - )).<span class="name">fetchone</span>() - <span class="kw">if</span> <span class="name">user</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span> <span class="op op-word">or</span> <span class="name">user</span>[<span class="st st-sg">'</span><span class="st">user_id</span><span class="st st-sg">'</span>] <span class="op"><</span> <span class="nb nb-int">1</span>: - <span class="name">guest_count</span> <span class="op">+=</span> <span class="nb nb-int">1</span> - - <span class="name">user_data</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - <span class="kw">else</span>: - <span class="name">user_data</span> <span class="op">=</span> { - <span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>: <span class="name">user</span>[<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>], - <span class="st st-sg">'</span><span class="st">user_id</span><span class="st st-sg">'</span>: <span class="name">user</span>[<span class="st st-sg">'</span><span class="st">user_id</span><span class="st st-sg">'</span>], - <span class="st st-sg">'</span><span class="st">url</span><span class="st st-sg">'</span>: <span class="name">ctx</span>.<span class="name">make_url</span>(<span class="st st-sg">'</span><span class="st">users</span><span class="st st-sg">'</span>, <span class="name">urlencode</span>(<span class="name">user</span>[<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>])), - } - <span class="name">user_count</span> <span class="op">+=</span> <span class="nb nb-int">1</span> - - <span class="name">session_list</span>.<span class="name">append</span>({ - <span class="st st-sg">'</span><span class="st">last_reload</span><span class="st st-sg">'</span>: <span class="name">row</span>[<span class="st st-sg">'</span><span class="st">last_reload</span><span class="st st-sg">'</span>], - <span class="st st-sg">'</span><span class="st">user</span><span class="st st-sg">'</span>: <span class="name">user_data</span> - }) - <span class="name">session_list</span>.<span class="name">sort</span>(<span class="name">key</span><span class="op">=</span><span class="kw">lambda</span> <span class="name">x</span>: <span class="name">x</span>[<span class="st st-sg">'</span><span class="st">last_reload</span><span class="st st-sg">'</span>]) - <span class="kw">return</span> <span class="name">session_list</span>, <span class="name">user_count</span>, <span class="name">guest_count</span>, <span class="name">user_count</span> <span class="op">+</span> <span class="name">guest_count</span> - - <span class="kw">return</span> <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">transaction</span>(<span class="name">do</span>) - - -<span class="kw">def </span><span class="fun">get_sessions_by_action</span>(<span class="name">ctx</span>, <span class="name">url</span>): - <span class="name">provider</span> <span class="op">=</span> <span class="name">get_auth_provider</span>(<span class="name">ctx</span>) - <span class="kw">def </span><span class="fun">do</span>(<span class="name">con</span>): - <span class="name">session_list</span> <span class="op">=</span> [] - <span class="name">r</span> <span class="op">=</span> <span class="name">con</span>.<span class="name">execute</span>(<span class="name">sessions</span>.<span class="name">select</span>( - <span class="name">sessions</span>.<span class="name">c</span>.<span class="name">action</span> <span class="op">==</span> <span class="name">url</span> - - )) - <span class="kw">while</span> <span class="bn bn-pseudo">True</span>: - <span class="name">row</span> <span class="op">=</span> <span class="name">r</span>.<span class="name">fetchone</span>() - <span class="kw">if</span> <span class="name">row</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="kw">break</span> - - <span class="name">user</span> <span class="op">=</span> <span class="name">con</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>([<span class="name">users</span>.<span class="name">c</span>.<span class="name">user_id</span>, <span class="name">users</span>.<span class="name">c</span>.<span class="name">username</span>], - <span class="name">users</span>.<span class="name">c</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">provider</span>.<span class="name">get_user_id</span>(<span class="name">row</span>[<span class="st st-sg">'</span><span class="st">data</span><span class="st st-sg">'</span>]) - )).<span class="name">fetchone</span>() - <span class="kw">if</span> <span class="name">user</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span> <span class="op op-word">or</span> <span class="name">user</span>[<span class="st st-sg">'</span><span class="st">user_id</span><span class="st st-sg">'</span>] <span class="op"><</span> <span class="nb nb-int">1</span>: - <span class="name">user_data</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="kw">else</span>: - <span class="name">user_data</span> <span class="op">=</span> { - <span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>: <span class="name">user</span>[<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>], - <span class="st st-sg">'</span><span class="st">url</span><span class="st st-sg">'</span>: <span class="name">ctx</span>.<span class="name">make_url</span>(<span class="st st-sg">'</span><span class="st">users</span><span class="st st-sg">'</span>, <span class="name">urlencode</span>(<span class="name">user</span>[<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>])), - } - <span class="name">session_list</span>.<span class="name">append</span>(<span class="name">user_data</span>) - <span class="kw">return</span> <span class="name">session_list</span> - - <span class="kw">return</span> <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">transaction</span>(<span class="name">do</span>) - - -<span class="kw">class </span><span class="cls">Session</span>(<span class="bn">dict</span>): - <span class="st st-db">"""</span><span class="st">Session Model</span><span class="st st-db">"""</span> - - <span class="kw">def </span><span class="fun">__init__</span>(<span class="bn bn-pseudo">self</span>, <span class="name">ctx</span>, <span class="name">sid</span>, <span class="name">ip</span>, <span class="name">path</span>): - <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span> <span class="op">=</span> <span class="name">ctx</span> - - <span class="bn bn-pseudo">self</span>.<span class="name">path</span> <span class="op">=</span> <span class="name">path</span> - <span class="name">r</span> <span class="op">=</span> <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">sessions</span>.<span class="name">select</span>( - (<span class="name">sessions</span>.<span class="name">c</span>.<span class="name">session_key</span> <span class="op">==</span> <span class="name">sid</span>) <span class="op">&</span> - - (<span class="name">sessions</span>.<span class="name">c</span>.<span class="name">ip_addr</span> <span class="op">==</span> <span class="name">ip</span>) <span class="op">&</span> - (<span class="name">sessions</span>.<span class="name">c</span>.<span class="name">expires</span> <span class="op">>=</span> <span class="name">datetime</span>.<span class="name">utcnow</span>()) - )) - <span class="name">data</span> <span class="op">=</span> <span class="name">r</span>.<span class="name">fetchone</span>() - <span class="kw">if</span> <span class="name">data</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="bn">super</span>(<span class="name">Session</span>, <span class="bn bn-pseudo">self</span>).<span class="name">__init__</span>() - <span class="bn bn-pseudo">self</span>.<span class="name">sid</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="kw">else</span>: - <span class="bn">super</span>(<span class="name">Session</span>, <span class="bn bn-pseudo">self</span>).<span class="name">__init__</span>(<span class="name">data</span>[<span class="st st-sg">'</span><span class="st">data</span><span class="st st-sg">'</span>]) - <span class="bn bn-pseudo">self</span>.<span class="name">sid</span> <span class="op">=</span> <span class="name">sid</span> - - <span class="bn bn-pseudo">self</span>.<span class="name">ip</span> <span class="op">=</span> <span class="name">ip</span> - - <span class="kw">def </span><span class="fun">__hash__</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="bn">hash</span>(<span class="bn bn-pseudo">self</span>.<span class="name">sid</span>) - - <span class="kw">def </span><span class="fun">to_dict</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Return the session data as normal dict.</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn">dict</span>(<span class="bn bn-pseudo">self</span>) - - <span class="kw">def </span><span class="fun">save</span>(<span class="bn bn-pseudo">self</span>, <span class="name">cookie_expire</span>): - <span class="st st-db">"""</span><span class="st">Save changes back to the database and updates - expires and last_reload. Returns a datetime object - with the time of the session expire.</span><span class="st st-db">"""</span> - <span class="name">now</span> <span class="op">=</span> <span class="name">datetime</span>.<span class="name">utcnow</span>() - <span class="name">expires</span> <span class="op">=</span> <span class="name">now</span> <span class="op">+</span> <span class="name">timedelta</span>(<span class="name">seconds</span><span class="op">=</span><span class="name">cookie_expire</span>) - <span class="kw">if</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">self</span>.<span class="name">sid</span>: - <span class="kw">while</span> <span class="bn bn-pseudo">True</span>: - <span class="name">hashval</span> <span class="op">=</span> <span class="name">md5</span>.<span class="name">new</span>(<span class="st st-sg">'</span><span class="st st-int">%s</span><span class="st">|</span><span class="st st-int">%s</span><span class="st st-sg">'</span> <span class="op">%</span> (<span class="name">random</span>.<span class="name">random</span>(), <span class="name">time</span>.<span class="name">time</span>())) - <span class="name">sid</span> <span class="op">=</span> <span class="name">hashval</span>.<span class="name">hexdigest</span>() - <span class="name">r</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">sessions</span>.<span class="name">select</span>( - <span class="name">sessions</span>.<span class="name">c</span>.<span class="name">session_key</span> <span class="op">==</span> <span class="name">sid</span> - - )) - <span class="kw">if</span> <span class="name">r</span>.<span class="name">fetchone</span>() <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="kw">break</span> - <span class="bn bn-pseudo">self</span>.<span class="name">sid</span> <span class="op">=</span> <span class="name">sid</span> - - <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">sessions</span>.<span class="name">insert</span>(), - <span class="name">session_key</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">sid</span>, - <span class="name">ip_addr</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">ip</span>, - <span class="name">expires</span> <span class="op">=</span> <span class="name">expires</span>, - <span class="name">last_reload</span> <span class="op">=</span> <span class="name">now</span>, - <span class="name">action</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">path</span>, - <span class="name">data</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">to_dict</span>() - ) - <span class="kw">else</span>: - <span class="name">q</span> <span class="op">=</span> <span class="name">sessions</span>.<span class="name">c</span>.<span class="name">session_key</span> <span class="op">==</span> <span class="bn bn-pseudo">self</span>.<span class="name">sid</span> - - <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">sessions</span>.<span class="name">update</span>(<span class="name">q</span>), - <span class="name">expires</span> <span class="op">=</span> <span class="name">expires</span>, - <span class="name">last_reload</span> <span class="op">=</span> <span class="name">now</span>, - <span class="name">action</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">path</span>, - <span class="name">data</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">to_dict</span>() - ) - <span class="kw">return</span> <span class="name">expires</span> - - <span class="kw">def </span><span class="fun">__repr__</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="st st-sg">'</span><span class="st"><</span><span class="st st-int">%s</span><span class="st"> </span><span class="st st-int">%s</span><span class="st">: </span><span class="st st-int">%r</span><span class="st">></span><span class="st st-sg">'</span> <span class="op">%</span> ( - <span class="bn bn-pseudo">self</span>.<span class="name">__class__</span>.<span class="name">__name__</span>, - <span class="bn bn-pseudo">self</span>.<span class="name">sid</span>, - <span class="bn">dict</span>.<span class="name">__repr__</span>(<span class="bn bn-pseudo">self</span>) - ) - - - -<span class="kw">class </span><span class="cls">SessionWrapper</span>(<span class="name">RequestWrapper</span>): - <span class="st st-db">"""</span><span class="st"> - SessionWrapper loads/stores request.session. - </span><span class="st st-db">"""</span> - <span class="name">cookie_name</span> <span class="op">=</span> <span class="name">cfg</span>.<span class="name">str</span>(<span class="st st-sg">'</span><span class="st">board</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">cookiename</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">SESSION</span><span class="st st-sg">'</span>) - <span class="name">cookie_expires</span> <span class="op">=</span> <span class="name">cfg</span>.<span class="name">int</span>(<span class="st st-sg">'</span><span class="st">board</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">cookieexpires</span><span class="st st-sg">'</span>, <span class="nb nb-int">7200</span>) - - <span class="kw">def </span><span class="fun">get_priority</span>(<span class="bn bn-pseudo">self</span>): - <span class="cm"># request.session should be set before anything else,</span> - - <span class="cm"># but after a possible caching system.</span> - <span class="kw">return</span> <span class="nb nb-int">2</span> - - <span class="kw">def </span><span class="fun">process_request</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="name">cookie</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">cookies</span>.<span class="name">get</span>(<span class="bn bn-pseudo">self</span>.<span class="name">cookie_name</span>, <span class="bn bn-pseudo">None</span>) - <span class="name">sid</span> <span class="op">=</span> <span class="name">cookie</span> <span class="op op-word">and</span> <span class="name">cookie</span>.<span class="name">value</span> <span class="op op-word">or</span> <span class="bn bn-pseudo">None</span> - - <span class="name">ip</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">environ</span>[<span class="st st-sg">'</span><span class="st">REMOTE_ADDR</span><span class="st st-sg">'</span>] - <span class="name">req</span>.<span class="name">session</span> <span class="op">=</span> <span class="name">Session</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, <span class="name">sid</span>, <span class="name">ip</span>, <span class="name">req</span>.<span class="name">path</span>) - - <span class="kw">def </span><span class="fun">process_response</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">resp</span>): - <span class="name">expires</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">session</span>.<span class="name">save</span>(<span class="bn bn-pseudo">self</span>.<span class="name">cookie_expires</span>) - <span class="name">resp</span>.<span class="name">set_cookie</span>(<span class="bn">str</span>(<span class="bn bn-pseudo">self</span>.<span class="name">cookie_name</span>), <span class="name">req</span>.<span class="name">session</span>.<span class="name">sid</span>, - <span class="name">max_age</span><span class="op">=</span><span class="bn bn-pseudo">self</span>.<span class="name">cookie_expires</span>, <span class="name">expires</span><span class="op">=</span><span class="name">expires</span>) - <span class="kw">return</span> <span class="name">resp</span> - -<span class="cm"># -*- coding: utf-8 -*-</span> -<span class="st st-db">"""</span><span class="st"> - pocoo.pkg.core.simplehtml - ~~~~~~~~~~~~~~~~~~~~~~~~~ - - This module provides a MarkupFormat that allows the user to use - HTML as markup but strips dangerous tags like ``<script>`` and others. - - It uses the ``secure_html`` method from the ``html`` util. - - :copyright: 2006 by Armin Ronacher. - :license: GNU GPL, see LICENSE for more details. -</span><span class="st st-db">"""</span> - -<span class="kw">from </span><span class="cls">pocoo.utils.html</span><span class="kw"> import</span> <span class="name">secure_html</span> -<span class="kw">from </span><span class="cls">pocoo.pkg.core.textfmt</span><span class="kw"> import</span> <span class="name">MarkupFormat</span> - - -<span class="kw">class </span><span class="cls">SimpleHTML</span>(<span class="name">MarkupFormat</span>): - <span class="name">name</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">simplehtml</span><span class="st st-sg">'</span> - - <span class="kw">def </span><span class="fun">parse</span>(<span class="bn bn-pseudo">self</span>, <span class="name">text</span>): - <span class="kw">return</span> <span class="name">secure_html</span>(<span class="name">text</span>) - - <span class="kw">def </span><span class="fun">quote_text</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">text</span>, <span class="name">username</span><span class="op">=</span><span class="bn bn-pseudo">None</span>): - <span class="kw">if</span> <span class="name">username</span> <span class="op op-word">is</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">None</span>: - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - - <span class="name">text</span> <span class="op">=</span> <span class="name">u</span><span class="st st-sg">'</span><span class="st"><em></span><span class="st st-int">%s</span><span class="st">:</em><br /></span><span class="st st-int">%s</span><span class="st st-sg">'</span> <span class="op">%</span> ((<span class="name">_</span>(<span class="st st-sg">'</span><span class="st st-int">%s</span><span class="st"> wrote</span><span class="st st-sg">'</span>) <span class="op">%</span> <span class="name">username</span>), <span class="name">text</span>) - <span class="kw">return</span> <span class="name">u</span><span class="st st-sg">'</span><span class="st"><blockquote></span><span class="st st-int">%s</span><span class="st"></blockquote></span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">text</span> - -<span class="cm"># -*- coding: utf-8 -*-</span> -<span class="st st-db">"""</span><span class="st"> - pocoo.pkg.core.smilies - ~~~~~~~~~~~~~~~~~~~~~~ - - Pocoo smilies parser. - - :copyright: 2006 by Benjamin Wiegand, Georg Brandl. - :license: GNU GPL, see LICENSE for more details. -</span><span class="st st-db">"""</span> -<span class="kw">from </span><span class="cls">pocoo</span><span class="kw"> import</span> <span class="name">Component</span> -<span class="kw">from </span><span class="cls">pocoo.utils.html</span><span class="kw"> import</span> <span class="name">escape_html</span> - - -<span class="kw">def </span><span class="fun">replace_smilies</span>(<span class="name">ctx</span>, <span class="name">text</span>): - <span class="st st-db">"""</span><span class="st"> - Replace smilies in ``text``, using all providers listed in the - board config. - </span><span class="st st-db">"""</span> - <span class="name">smiley_providers</span> <span class="op">=</span> <span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">board</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">smiley_providers</span><span class="st st-sg">'</span>, [<span class="st st-sg">'</span><span class="st">default</span><span class="st st-sg">'</span>]) - <span class="kw">for</span> <span class="name">provider</span> <span class="op op-word">in</span> <span class="name">ctx</span>.<span class="name">get_components</span>(<span class="name">SmileyProvider</span>): - <span class="kw">if</span> <span class="name">provider</span>.<span class="name">name</span> <span class="op op-word">not</span> <span class="op op-word">in</span> <span class="name">smiley_providers</span>: - <span class="kw">continue</span> - - <span class="kw">for</span> <span class="name">smiley</span> <span class="op op-word">in</span> <span class="name">provider</span>.<span class="name">smilies</span>: - <span class="name">text</span> <span class="op">=</span> <span class="name">text</span>.<span class="name">replace</span>(<span class="name">smiley</span>[<span class="nb nb-int">0</span>], <span class="name">provider</span>.<span class="name">render_smiley</span>(<span class="name">smiley</span>)) - <span class="kw">return</span> <span class="name">text</span> - - -<span class="kw">def </span><span class="fun">get_smiley_buttons</span>(<span class="name">ctx</span>): - <span class="st st-db">"""</span><span class="st"> - Return a list of button dictionaries usable for the BBCodeEditor - JavaScript app. - </span><span class="st st-db">"""</span> - <span class="name">res</span> <span class="op">=</span> [] - <span class="name">smiley_providers</span> <span class="op">=</span> <span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">board</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">smiley_providers</span><span class="st st-sg">'</span>, [<span class="st st-sg">'</span><span class="st">default</span><span class="st st-sg">'</span>]) - <span class="kw">for</span> <span class="name">provider</span> <span class="op op-word">in</span> <span class="name">ctx</span>.<span class="name">get_components</span>(<span class="name">SmileyProvider</span>): - <span class="kw">if</span> <span class="name">provider</span>.<span class="name">name</span> <span class="op op-word">not</span> <span class="op op-word">in</span> <span class="name">smiley_providers</span>: - <span class="kw">continue</span> - - <span class="kw">for</span> <span class="name">smiley</span> <span class="op op-word">in</span> <span class="name">provider</span>.<span class="name">smilies</span>: - <span class="name">res</span>.<span class="name">append</span>(<span class="name">smiley</span> <span class="op">+</span> (<span class="name">ctx</span>.<span class="name">make_url</span>(<span class="name">provider</span>.<span class="name">smiley_dir</span>),)) - <span class="kw">return</span> <span class="name">res</span> - - -<span class="kw">class </span><span class="cls">SmileyProvider</span>(<span class="name">Component</span>): - <span class="st st-db">"""</span><span class="st"> - A SmileyProvider maps small text strings to images. - </span><span class="st st-db">"""</span> - - <span class="cm">#: List of smilies this component provides, in the form</span> - <span class="cm">#: ``('textform', 'imagename')``.</span> - - <span class="cm">#: ``imagename`` is relative to the ``smiley_dir`` below.</span> - <span class="name">smilies</span> <span class="op">=</span> [] - - <span class="cm">#: Directory where smilies of this provider can be found.</span> - <span class="cm">#: Must be relative to the forum root, e.g.</span> - <span class="cm">#: ``!cobalt/pkgname/default/img/smilies/``.</span> - - <span class="name">smiley_dir</span> <span class="op">=</span> <span class="st st-db">""</span> - - <span class="cm">#: Name (can be overwritten, must be lowercase).</span> - <span class="cm">#: Used for the configuration setting.</span> - <span class="deco">@property</span> - <span class="kw">def </span><span class="fun">name</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">__class__</span>.<span class="name">__name__</span>.<span class="name">lower</span>() - - <span class="kw">def </span><span class="fun">render_smiley</span>(<span class="bn bn-pseudo">self</span>, <span class="name">smiley</span>): - <span class="st st-db">"""</span><span class="st"> - - Render a smiley. This doesn't need to be overridden in normal - cases. - - :return: HTML for the smiley image. - </span><span class="st st-db">"""</span> - <span class="kw">return</span> <span class="st st-sg">'</span><span class="st"><img src="</span><span class="st st-int">%s</span><span class="st">" alt="</span><span class="st st-int">%s</span><span class="st">" /></span><span class="st st-sg">'</span> <span class="op">%</span> ( - <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">make_url</span>(<span class="bn bn-pseudo">self</span>.<span class="name">smiley_dir</span>, <span class="name">smiley</span>[<span class="nb nb-int">1</span>]), - <span class="name">escape_html</span>(<span class="name">smiley</span>[<span class="nb nb-int">0</span>]) - ) - - - -<span class="kw">class </span><span class="cls">Default</span>(<span class="name">SmileyProvider</span>): - <span class="st st-db">"""</span><span class="st"> - Default Pocoo smilies. - </span><span class="st st-db">"""</span> - <span class="name">smilies</span> <span class="op">=</span> [ - (<span class="st st-sg">'</span><span class="st">;-)</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">wink.png</span><span class="st st-sg">'</span>), - (<span class="st st-sg">'</span><span class="st">:(</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">sad.png</span><span class="st st-sg">'</span>), - (<span class="st st-sg">'</span><span class="st">:-)</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">smile.png</span><span class="st st-sg">'</span>), - (<span class="st st-sg">'</span><span class="st">:D</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">grin.png</span><span class="st st-sg">'</span>), - ] - - <span class="name">smiley_dir</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">!cobalt/core/default/img/smilies/</span><span class="st st-sg">'</span> - -<span class="cm"># -*- coding: utf-8 -*-</span> -<span class="st st-db">"""</span><span class="st"> - pocoo.pkg.core.template - ~~~~~~~~~~~~~~~~~~~~~~~ - - Templating helpers. - - :copyright: 2006 by Georg Brandl, Armin Ronacher. - :license: GNU GPL, see LICENSE for more details. -</span><span class="st st-db">"""</span> -<span class="kw">import </span><span class="cls">math</span> -<span class="kw">import </span><span class="cls">jinja.exceptions</span> -<span class="kw">from </span><span class="cls">jinja.nodes</span><span class="kw"> import</span> <span class="name">Node</span>, <span class="name">KeywordNode</span>, <span class="name">VariableNode</span>, <span class="name">CollectionNode</span> - -<span class="kw">from </span><span class="cls">pocoo.template</span><span class="kw"> import</span> <span class="name">FileRequirements</span> - - -<span class="kw">class </span><span class="cls">BaseThemeRequirements</span>(<span class="name">FileRequirements</span>): - - <span class="kw">def </span><span class="fun">get_javascript_imports</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> ( - <span class="st st-sg">'</span><span class="st">AJS/AJS.js</span><span class="st st-sg">'</span>, - <span class="st st-sg">'</span><span class="st">pocoo/lib/async.js</span><span class="st st-sg">'</span>, - <span class="st st-sg">'</span><span class="st">pocoo/lib/dom.js</span><span class="st st-sg">'</span>, - <span class="st st-sg">'</span><span class="st">pocoo/lib/effects.js</span><span class="st st-sg">'</span>, - ) - - <span class="kw">def </span><span class="fun">get_stylesheet_imports</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> ( - <span class="st st-sg">'</span><span class="st">default/style/screen.css</span><span class="st st-sg">'</span>, - ) - - - -<span class="kw">class </span><span class="cls">Pagination</span>(<span class="bn">object</span>): - <span class="st st-db">"""</span><span class="st"> - Pagination Controller. Push this into the template so that - the template designer has an object he can use for generating - an pagination. - - Normally you are looking for the ``LazyPagination`` class, this - one is just for posts or if you have many single items which - are combined to a thread etc. The idea is that you don't have - and offset information in the url. - </span><span class="st st-db">"""</span> - - <span class="kw">def </span><span class="fun">__init__</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">idlist</span>, <span class="name">start</span>, <span class="name">per_page</span>, <span class="name">link</span>): - <span class="st st-db">"""</span><span class="st"> - - :param req: the request - :param idlist: a list of all ids for the pagination - :param start: the position of the first item on the page - :param per_page: number of items on each page - :param link: function which takes one id and returns a link for it - - Example:: - - p = Pagination(req, range(50), 20, 20, lambda x: 'post/</span><span class="st st-int">%d</span><span class="st">' </span><span class="st st-int">% x</span><span class="st">) - - In this example the first page would contain the posts 0-19, - the second 20-39 and the first 40-50. - </span><span class="st st-db">"""</span> - <span class="bn bn-pseudo">self</span>.<span class="name">req</span> <span class="op">=</span> <span class="name">req</span> - - <span class="bn bn-pseudo">self</span>.<span class="name">idlist</span> <span class="op">=</span> <span class="name">idlist</span> - <span class="bn bn-pseudo">self</span>.<span class="name">start</span> <span class="op">=</span> <span class="name">start</span> - - <span class="bn bn-pseudo">self</span>.<span class="name">per_page</span> <span class="op">=</span> <span class="name">per_page</span> - <span class="bn bn-pseudo">self</span>.<span class="name">link</span> <span class="op">=</span> <span class="name">link</span> - - <span class="kw">def </span><span class="fun">generate</span>(<span class="bn bn-pseudo">self</span>, <span class="name">normal</span>, <span class="name">active</span>, <span class="name">commata</span>, <span class="name">ellipsis</span>, <span class="name">threshold</span>): - <span class="st st-db">"""</span><span class="st"> - - Generate a Pagination of the data defined in the constructor. - - :param normal: inserted string when the page isn't active - :param active: inserted string when the page is active - :param commata: inserted between links - :param ellipsis: inserted as space indicator for skiped links - :param threshold: number of links around start/current page and - end before they will be replaced by an ellipsis - - ``normal`` and ``active`` can contain out of the following formatting - chars: - - ====================== ================================== - ``</span><span class="st st-int">%(page)s</span><span class="st">`` number of the current page - ``</span><span class="st st-int">%(url)s</span><span class="st">`` absolute url of the current page - ====================== ================================== - - Example:: - - p.generate('<a href="</span><span class="st st-int">%(url)s</span><span class="st">"></span><span class="st st-int">%(page)s</span><span class="st"></a>', - '<strong></span><span class="st st-int">%(page)s</span><span class="st"></strong>', - ', ', - ' ... ', - 3) - </span><span class="st st-db">"""</span> - - <span class="name">current_page_number</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">start</span> <span class="op">/</span> <span class="bn bn-pseudo">self</span>.<span class="name">per_page</span> <span class="op">+</span> <span class="nb nb-int">1</span> - - <span class="name">number_of_pages</span> <span class="op">=</span> <span class="bn">int</span>(<span class="name">math</span>.<span class="name">ceil</span>(<span class="bn">len</span>(<span class="bn bn-pseudo">self</span>.<span class="name">idlist</span>) <span class="op">/</span> (<span class="bn bn-pseudo">self</span>.<span class="name">per_page</span> <span class="op">*</span> <span class="nb nb-flt">1.0</span>))) - <span class="name">was_space</span> <span class="op">=</span> <span class="bn bn-pseudo">False</span> - - <span class="name">result</span> <span class="op">=</span> [] - <span class="kw">for</span> <span class="name">idx</span> <span class="op op-word">in</span> <span class="bn">range</span>(<span class="nb nb-int">1</span>, <span class="name">number_of_pages</span> <span class="op">+</span> <span class="nb nb-int">1</span>): - <span class="kw">if</span> <span class="name">idx</span> <span class="op"><=</span> <span class="name">threshold</span> <span class="op op-word">or</span> <span class="name">idx</span> <span class="op">></span> <span class="name">number_of_pages</span> <span class="op">-</span> <span class="name">threshold</span> <span class="op op-word">or</span>\ - <span class="bn">abs</span>(<span class="name">current_page_number</span> <span class="op">-</span> <span class="name">idx</span>) <span class="op"><</span> <span class="name">math</span>.<span class="name">ceil</span>(<span class="name">threshold</span> <span class="op">/</span> <span class="nb nb-flt">2.0</span>): - <span class="kw">if</span> <span class="name">result</span> <span class="op op-word">and</span> <span class="name">result</span>[<span class="op">-</span><span class="nb nb-int">1</span>] <span class="op">!=</span> <span class="name">ellipsis</span>: - <span class="name">result</span>.<span class="name">append</span>(<span class="name">commata</span>) - <span class="name">was_space</span> <span class="op">=</span> <span class="bn bn-pseudo">False</span> - - <span class="kw">if</span> <span class="name">idx</span> <span class="op">==</span> <span class="name">current_page_number</span>: - <span class="name">schema</span> <span class="op">=</span> <span class="name">active</span> - <span class="kw">else</span>: - <span class="name">schema</span> <span class="op">=</span> <span class="name">normal</span> - - <span class="name">url</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">link</span>(<span class="bn bn-pseudo">self</span>.<span class="name">idlist</span>[(<span class="name">idx</span> <span class="op">-</span> <span class="nb nb-int">1</span>) <span class="op">*</span> <span class="bn bn-pseudo">self</span>.<span class="name">per_page</span>]) - <span class="name">result</span>.<span class="name">append</span>(<span class="name">schema</span> <span class="op">%</span> { - <span class="st st-sg">'</span><span class="st">page</span><span class="st st-sg">'</span>: <span class="name">idx</span>, - <span class="st st-sg">'</span><span class="st">url</span><span class="st st-sg">'</span>: <span class="bn bn-pseudo">self</span>.<span class="name">req</span>.<span class="name">ctx</span>.<span class="name">make_url</span>(<span class="name">url</span>), - }) - <span class="kw">else</span>: - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">was_space</span>: - <span class="name">was_space</span> <span class="op">=</span> <span class="bn bn-pseudo">True</span> - - <span class="name">result</span>.<span class="name">append</span>(<span class="name">ellipsis</span>) - <span class="kw">return</span> <span class="name">u</span><span class="st st-sg">''</span>.<span class="name">join</span>(<span class="name">result</span>) - - <span class="kw">def </span><span class="fun">__repr__</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="st st-sg">'</span><span class="st"><</span><span class="st st-int">%s</span><span class="st"> </span><span class="st st-int">%r</span><span class="st">></span><span class="st st-sg">'</span> <span class="op">%</span> ( - <span class="bn bn-pseudo">self</span>.<span class="name">__class__</span>.<span class="name">__name__</span>, - <span class="bn">str</span>(<span class="bn bn-pseudo">self</span>) - ) - - <span class="kw">def </span><span class="fun">__str__</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">generate</span>(<span class="st st-sg">'</span><span class="st st-int">%(page)s</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">[</span><span class="st st-int">%(page)s</span><span class="st">]</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">, </span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st"> ... </span><span class="st st-sg">'</span>, <span class="nb nb-int">3</span>) - - - -<span class="kw">class </span><span class="cls">LazyPagination</span>(<span class="bn">object</span>): - <span class="st st-db">"""</span><span class="st"> - A lazy pagination controller. Doesn't require a id list like - the ``Pagination`` controller. - - The ``LazyPagination`` is a cheep to calculate pagination based - on the current page, the total amount of pages and the information - about what a link looks like and how many items you have per page. - </span><span class="st st-db">"""</span> - - <span class="kw">def </span><span class="fun">__init__</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">page</span>, <span class="name">per_page</span>, <span class="name">pages</span>, <span class="name">link</span>): - <span class="bn bn-pseudo">self</span>.<span class="name">req</span> <span class="op">=</span> <span class="name">req</span> - - <span class="bn bn-pseudo">self</span>.<span class="name">page</span> <span class="op">=</span> <span class="name">page</span> - <span class="bn bn-pseudo">self</span>.<span class="name">per_page</span> <span class="op">=</span> <span class="name">per_page</span> - - <span class="bn bn-pseudo">self</span>.<span class="name">pages</span> <span class="op">=</span> <span class="name">pages</span> - <span class="bn bn-pseudo">self</span>.<span class="name">link</span> <span class="op">=</span> <span class="name">link</span> - - <span class="kw">def </span><span class="fun">generate</span>(<span class="bn bn-pseudo">self</span>, <span class="name">normal</span>, <span class="name">active</span>, <span class="name">commata</span>, <span class="name">ellipsis</span>, <span class="name">threshold</span>): - <span class="st st-db">"""</span><span class="st"> - - Generate a Pagination of the data defined in the constructor. - - :param normal: inserted string when the page isn't active - :param active: inserted string when the page is active - :param commata: inserted between links - :param ellipsis: inserted as space indicator for skiped links - :param threshold: number of links around start/current page and - end before they will be replaced by an ellipsis - - ``normal`` and ``active`` can contain out of the following formatting - chars: - - ====================== ================================== - ``</span><span class="st st-int">%(page)s</span><span class="st">`` number of the current page - ``</span><span class="st st-int">%(url)s</span><span class="st">`` absolute url of the current page - ====================== ================================== - - Example:: - - p.generate('<a href="</span><span class="st st-int">%(url)s</span><span class="st">"></span><span class="st st-int">%(page)s</span><span class="st"></a>', - '<strong></span><span class="st st-int">%(page)s</span><span class="st"></strong>', - ', ', - ' ... ', - 3) - </span><span class="st st-db">"""</span> - - <span class="name">was_space</span> <span class="op">=</span> <span class="bn bn-pseudo">False</span> - <span class="name">result</span> <span class="op">=</span> [] - <span class="kw">for</span> <span class="name">idx</span> <span class="op op-word">in</span> <span class="bn">range</span>(<span class="nb nb-int">1</span>, <span class="bn bn-pseudo">self</span>.<span class="name">pages</span> <span class="op">+</span> <span class="nb nb-int">1</span>): - <span class="kw">if</span> <span class="name">idx</span> <span class="op"><=</span> <span class="name">threshold</span> <span class="op op-word">or</span> <span class="name">idx</span> <span class="op">></span> <span class="bn bn-pseudo">self</span>.<span class="name">pages</span> <span class="op">-</span> <span class="name">threshold</span> <span class="op op-word">or</span>\ - <span class="bn">abs</span>(<span class="bn bn-pseudo">self</span>.<span class="name">page</span> <span class="op">-</span> <span class="name">idx</span>) <span class="op"><</span> <span class="name">math</span>.<span class="name">ceil</span>(<span class="name">threshold</span> <span class="op">/</span> <span class="nb nb-flt">2.0</span>): - <span class="kw">if</span> <span class="name">result</span> <span class="op op-word">and</span> <span class="name">result</span>[<span class="op">-</span><span class="nb nb-int">1</span>] <span class="op">!=</span> <span class="name">ellipsis</span>: - <span class="name">result</span>.<span class="name">append</span>(<span class="name">commata</span>) - <span class="name">was_space</span> <span class="op">=</span> <span class="bn bn-pseudo">False</span> - - <span class="kw">if</span> <span class="name">idx</span> <span class="op">==</span> <span class="bn bn-pseudo">self</span>.<span class="name">page</span>: - <span class="name">schema</span> <span class="op">=</span> <span class="name">active</span> - - <span class="kw">else</span>: - <span class="name">schema</span> <span class="op">=</span> <span class="name">normal</span> - <span class="name">url</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">link</span>(<span class="name">idx</span>) - <span class="name">result</span>.<span class="name">append</span>(<span class="name">schema</span> <span class="op">%</span> { - <span class="st st-sg">'</span><span class="st">page</span><span class="st st-sg">'</span>: <span class="name">idx</span>, - <span class="st st-sg">'</span><span class="st">url</span><span class="st st-sg">'</span>: <span class="bn bn-pseudo">self</span>.<span class="name">req</span>.<span class="name">ctx</span>.<span class="name">make_url</span>(<span class="name">url</span>), - }) - <span class="kw">else</span>: - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">was_space</span>: - <span class="name">was_space</span> <span class="op">=</span> <span class="bn bn-pseudo">True</span> - - <span class="name">result</span>.<span class="name">append</span>(<span class="name">ellipsis</span>) - <span class="kw">return</span> <span class="name">u</span><span class="st st-sg">''</span>.<span class="name">join</span>(<span class="name">result</span>) - - <span class="kw">def </span><span class="fun">__str__</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">generate</span>(<span class="st st-sg">'</span><span class="st st-int">%(page)s</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">[</span><span class="st st-int">%(page)s</span><span class="st">]</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">, </span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st"> ... </span><span class="st st-sg">'</span>, <span class="nb nb-int">3</span>) - - - -<span class="kw">class </span><span class="cls">PaginationTag</span>(<span class="name">Node</span>): - <span class="st st-db">"""</span><span class="st"> - Generates a pagination. requires a Pagination object at first - argument:: - - {% paginate forum.pagination - '<a href="</span><span class="st st-int">%(link)s</span><span class="st">"></span><span class="st st-int">%(page)s</span><span class="st"></a>', - '<strong></span><span class="st st-int">%(page)s</span><span class="st"></strong>', - ', ', - '...' - - %} - </span><span class="st st-db">"""</span> - <span class="name">rules</span> <span class="op">=</span> { - <span class="st st-sg">'</span><span class="st">default</span><span class="st st-sg">'</span>: [<span class="name">KeywordNode</span>(<span class="st st-sg">'</span><span class="st">paginate</span><span class="st st-sg">'</span>), <span class="name">VariableNode</span>(), - <span class="name">CollectionNode</span>()] - } - <span class="kw">def </span><span class="fun">__init__</span>(<span class="bn bn-pseudo">self</span>, <span class="name">parser</span>, <span class="name">matched_tag</span>, <span class="name">handler_args</span>, <span class="name">stack</span>): - <span class="bn bn-pseudo">self</span>.<span class="name">_variable</span> <span class="op">=</span> <span class="name">handler_args</span>[<span class="nb nb-int">1</span>] - <span class="bn bn-pseudo">self</span>.<span class="name">_arguments</span> <span class="op">=</span> <span class="name">handler_args</span>[<span class="nb nb-int">2</span>] - <span class="name">Node</span>.<span class="name">__init__</span>(<span class="bn bn-pseudo">self</span>) - - <span class="kw">def </span><span class="fun">render</span>(<span class="bn bn-pseudo">self</span>, <span class="name">context</span>): - <span class="name">pagination_controller</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">_variable</span>.<span class="name">resolve</span>(<span class="name">context</span>) - <span class="kw">if</span> <span class="bn">len</span>(<span class="bn bn-pseudo">self</span>.<span class="name">_arguments</span>) <span class="op"><</span> <span class="nb nb-int">4</span>: - <span class="kw">raise</span> <span class="name">jinja</span>.<span class="name">exceptions</span>.<span class="name">TemplateRuntimeError</span>(<span class="st st-sg">'</span><span class="st">invalid argument count </span><span class="st st-sg">'</span> - - <span class="st st-sg">'</span><span class="st">for {% paginate %}</span><span class="st st-sg">'</span>) - <span class="name">link_scheme</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">_arguments</span>[<span class="nb nb-int">0</span>].<span class="name">resolve</span>(<span class="name">context</span>) - <span class="name">active_scheme</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">_arguments</span>[<span class="nb nb-int">1</span>].<span class="name">resolve</span>(<span class="name">context</span>) - <span class="name">commata</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">_arguments</span>[<span class="nb nb-int">2</span>].<span class="name">resolve</span>(<span class="name">context</span>) - <span class="name">ellipsis</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">_arguments</span>[<span class="nb nb-int">3</span>].<span class="name">resolve</span>(<span class="name">context</span>) - <span class="kw">if</span> <span class="bn">len</span>(<span class="bn bn-pseudo">self</span>.<span class="name">_arguments</span>) <span class="op">==</span> <span class="nb nb-int">5</span>: - <span class="name">threshold</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">_arguments</span>[<span class="nb nb-int">4</span>].<span class="name">resolve</span>(<span class="name">context</span>) - <span class="kw">else</span>: - <span class="name">threshold</span> <span class="op">=</span> <span class="nb nb-int">3</span> - - <span class="kw">return</span> <span class="name">pagination_controller</span>.<span class="name">generate</span>(<span class="name">link_scheme</span>, <span class="name">active_scheme</span>, - <span class="name">commata</span>, <span class="name">ellipsis</span>, <span class="name">threshold</span>) - - <span class="kw">def </span><span class="fun">__repr__</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="st st-sg">'</span><span class="st"><</span><span class="st st-int">%s</span><span class="st">></span><span class="st st-sg">'</span> <span class="op">%</span> <span class="bn bn-pseudo">self</span>.<span class="name">__class__</span>.<span class="name">__name__</span> - -<span class="cm"># -*- coding: utf-8 -*-</span> -<span class="st st-db">"""</span><span class="st"> - pocoo.pkg.core.textfmt - ~~~~~~~~~~~~~~~~~~~~~~ - - Pocoo text processing interfaces. - - :copyright: 2006 by Georg Brandl, Armin Ronacher. - :license: GNU GPL, see LICENSE for more details. -</span><span class="st st-db">"""</span> -<span class="kw">import </span><span class="cls">re</span> -<span class="kw">from </span><span class="cls">xml.sax.saxutils</span><span class="kw"> import</span> <span class="name">quoteattr</span> - -<span class="kw">from </span><span class="cls">pocoo.http</span><span class="kw"> import</span> <span class="name">Request</span> -<span class="kw">from </span><span class="cls">pocoo.utils.html</span><span class="kw"> import</span> <span class="name">nl2br</span>, <span class="name">escape_html</span>, <span class="name">unescape_html</span>, <span class="name">urlize</span> - -<span class="kw">from </span><span class="cls">pocoo</span><span class="kw"> import</span> <span class="name">Component</span> -<span class="kw">from </span><span class="cls">pocoo.pkg.core.smilies</span><span class="kw"> import</span> <span class="name">replace_smilies</span> -<span class="kw">from </span><span class="cls">pocoo.utils.activecache</span><span class="kw"> import</span> <span class="name">Node</span>, <span class="name">load_cache</span>, <span class="name">generate_cache</span> - -<span class="kw">from </span><span class="cls">pocoo.utils</span><span class="kw"> import</span> <span class="name">json</span> - - -<span class="name">frozen_translation_re</span> <span class="op">=</span> <span class="name">re</span>.<span class="name">compile</span>(<span class="st st-sg">r'</span><span class="st"><trans(?: value="(.*?)")?>(.*?)</trans></span><span class="st st-sg">'</span>) - - - -<span class="kw">class </span><span class="cls">MarkupFormat</span>(<span class="name">Component</span>): - <span class="st st-db">"""</span><span class="st"> - A text markup format, such as BBCode or HTML. - </span><span class="st st-db">"""</span> - - <span class="cm">#: The relative path to the javascript file for the editor.</span> - <span class="name">editor_javascript</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">!cobalt/core/PocooLib/BaseEditor.js</span><span class="st st-sg">'</span> - - <span class="cm">#: Name for this format. must be lowercase</span> - <span class="deco">@property</span> - <span class="kw">def </span><span class="fun">name</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">__class__</span>.<span class="name">__name__</span>.<span class="name">lower</span>() - - <span class="kw">def </span><span class="fun">get_title</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="st st-db">"""</span><span class="st"> - - Title of this formatter. - </span><span class="st st-db">"""</span> - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">name</span>.<span class="name">title</span>() - - <span class="kw">def </span><span class="fun">parse</span>(<span class="bn bn-pseudo">self</span>, <span class="name">text</span>, <span class="name">signature</span>): - <span class="st st-db">"""</span><span class="st"> - - This method has to return either an activecache Node or an - string/Unicode object. - - :param signature: If this is ``True`` the pocoo wants to parse - a signature. For BBCode there could be special - rules like allowed and disallowed tags etc. - </span><span class="st st-db">"""</span> - - <span class="kw">def </span><span class="fun">render_callback</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">callback</span>, <span class="name">data</span>): - <span class="st st-db">"""</span><span class="st"> - - If the ``parse`` method returns an activecache `CallbackNode` - this method will be called for the define callback. - </span><span class="st st-db">"""</span> - <span class="kw">return</span> <span class="name">u</span><span class="st st-sg">''</span> - - <span class="kw">def </span><span class="fun">quote_text</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">text</span>, <span class="name">username</span><span class="op">=</span><span class="bn bn-pseudo">None</span>): - <span class="st st-db">"""</span><span class="st"> - - This has to quote a given text. For example a BBCode - Markup Formatter should wrap the text in [quote]. - </span><span class="st st-db">"""</span> - <span class="kw">return</span> <span class="name">text</span> - - <span class="kw">def </span><span class="fun">get_editor_options</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">signature</span>): - <span class="st st-db">"""</span><span class="st"> - - This method has to return a dict of JSON - serializable values which get passed to the - function ``initEditor()`` which is defined - in the editor javascript file. - - If `signature` is ``True`` pocoo requested an editor for the - signature and wants just the editor definitions which are - relevant for an working signature editor. See the ``BBCode`` - text formatter for an example. - </span><span class="st st-db">"""</span> - <span class="kw">return</span> {} - - -<span class="kw">class </span><span class="cls">PlainText</span>(<span class="name">MarkupFormat</span>): - <span class="st st-db">"""</span><span class="st"> - This parser just breaks lines and creates links. - </span><span class="st st-db">"""</span> - <span class="name">name</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">plain</span><span class="st st-sg">'</span> - - <span class="kw">def </span><span class="fun">parse</span>(<span class="bn bn-pseudo">self</span>, <span class="name">text</span>, <span class="name">signature</span>): - <span class="name">text</span> <span class="op">=</span> <span class="name">escape_html</span>(<span class="name">text</span>) - <span class="name">text</span> <span class="op">=</span> <span class="name">nl2br</span>(<span class="name">text</span>) - <span class="name">text</span> <span class="op">=</span> <span class="name">replace_smilies</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, <span class="name">text</span>) - <span class="kw">return</span> <span class="name">urlize</span>(<span class="name">text</span>, <span class="nb nb-int">50</span>, <span class="bn bn-pseudo">True</span>) - - <span class="kw">def </span><span class="fun">quote_text</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">text</span>, <span class="name">username</span><span class="op">=</span><span class="bn bn-pseudo">None</span>): - <span class="name">lines</span> <span class="op">=</span> [<span class="name">u</span><span class="st st-sg">'</span><span class="st">> </span><span class="st st-int">%s</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">line</span> <span class="kw">for</span> <span class="name">line</span> <span class="op op-word">in</span> <span class="name">text</span>.<span class="name">splitlines</span>()] - <span class="kw">if</span> <span class="name">username</span> <span class="op op-word">is</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">None</span>: - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - - <span class="name">lines</span>.<span class="name">insert</span>(<span class="nb nb-int">0</span>, (<span class="name">_</span>(<span class="st st-sg">'</span><span class="st st-int">%s</span><span class="st"> wrote</span><span class="st st-sg">'</span>) <span class="op">+</span> <span class="name">u</span><span class="st st-sg">'</span><span class="st">:</span><span class="st st-sg">'</span>) <span class="op">%</span> <span class="name">username</span>) - <span class="kw">return</span> <span class="name">u</span><span class="st st-sg">'</span><span class="st st-esc">\n</span><span class="st st-sg">'</span>.<span class="name">join</span>(<span class="name">lines</span>) - - - -<span class="kw">def </span><span class="fun">parse</span>(<span class="name">ctx</span>, <span class="name">text</span>, <span class="name">signature</span><span class="op">=</span><span class="bn bn-pseudo">False</span>, <span class="name">syntax_parser</span><span class="op">=</span><span class="bn bn-pseudo">None</span>): - <span class="st st-db">"""</span><span class="st"> - Parses an text and returns a marshalled object. You then can - put such an string into the database or push it to the - render function. - </span><span class="st st-db">"""</span> - - <span class="kw">if</span> <span class="op op-word">not</span> <span class="bn">isinstance</span>(<span class="name">text</span>, <span class="bn">unicode</span>): - <span class="name">text</span> <span class="op">=</span> <span class="bn">unicode</span>(<span class="name">text</span>) - <span class="kw">if</span> <span class="name">syntax_parser</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="name">syntax_parser</span> <span class="op">=</span> <span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">board</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">syntax_parser</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">plain</span><span class="st st-sg">'</span>) - <span class="name">syntax_parser</span> <span class="op">=</span> <span class="name">syntax_parser</span>.<span class="name">lower</span>() - <span class="kw">for</span> <span class="name">comp</span> <span class="op op-word">in</span> <span class="name">ctx</span>.<span class="name">get_components</span>(<span class="name">MarkupFormat</span>): - <span class="kw">if</span> <span class="name">comp</span>.<span class="name">name</span> <span class="op">==</span> <span class="name">syntax_parser</span>: - <span class="name">node</span> <span class="op">=</span> <span class="name">comp</span>.<span class="name">parse</span>(<span class="name">text</span>, <span class="name">signature</span>) - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="name">node</span>, <span class="bn">basestring</span>): - <span class="name">node</span> <span class="op">=</span> <span class="name">Node</span>(<span class="name">node</span>) - <span class="kw">return</span> <span class="name">generate_cache</span>(<span class="name">node</span>, <span class="name">syntax_parser</span>) - <span class="kw">else</span>: - <span class="kw">raise</span> <span class="exc">ValueError</span>(<span class="st st-sg">'</span><span class="st">Parser "</span><span class="st st-int">%s</span><span class="st">" not found</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">syntax_parser</span>) - - - -<span class="kw">def </span><span class="fun">render</span>(<span class="name">req</span>, <span class="name">data</span>): - <span class="st st-db">"""</span><span class="st"> - Renders a parsed data - </span><span class="st st-db">"""</span> - <span class="name">node</span>, <span class="name">syntax_parser</span> <span class="op">=</span> <span class="name">load_cache</span>(<span class="name">data</span>) - <span class="kw">for</span> <span class="name">comp</span> <span class="op op-word">in</span> <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">get_components</span>(<span class="name">MarkupFormat</span>): - <span class="kw">if</span> <span class="name">comp</span>.<span class="name">name</span> <span class="op">==</span> <span class="name">syntax_parser</span>: - <span class="kw">break</span> - - <span class="kw">else</span>: - <span class="kw">raise</span> <span class="exc">ValueError</span>(<span class="st st-sg">'</span><span class="st">syntax parser </span><span class="st st-int">%r</span><span class="st"> not found</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">syntax_parser</span>) - <span class="kw">return</span> <span class="name">node</span>.<span class="name">render</span>(<span class="name">req</span>, <span class="name">comp</span>) - - - -<span class="kw">def </span><span class="fun">parse_and_render</span>(<span class="name">req</span>, <span class="name">text</span>, <span class="name">signature</span><span class="op">=</span><span class="bn bn-pseudo">False</span>, <span class="name">syntax_parser</span><span class="op">=</span><span class="bn bn-pseudo">None</span>): - <span class="st st-db">"""</span><span class="st"> - Parses and renders a text. - </span><span class="st st-db">"""</span> - - <span class="kw">if</span> <span class="op op-word">not</span> <span class="bn">isinstance</span>(<span class="name">text</span>, <span class="bn">unicode</span>): - <span class="name">text</span> <span class="op">=</span> <span class="bn">unicode</span>(<span class="name">text</span>) - <span class="kw">if</span> <span class="name">syntax_parser</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="name">syntax_parser</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">board</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">syntax_parser</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">plain</span><span class="st st-sg">'</span>) - <span class="name">syntax_parser</span> <span class="op">=</span> <span class="name">syntax_parser</span>.<span class="name">lower</span>() - <span class="kw">for</span> <span class="name">comp</span> <span class="op op-word">in</span> <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">get_components</span>(<span class="name">MarkupFormat</span>): - <span class="kw">if</span> <span class="name">comp</span>.<span class="name">name</span> <span class="op">==</span> <span class="name">syntax_parser</span>: - <span class="name">node</span> <span class="op">=</span> <span class="name">comp</span>.<span class="name">parse</span>(<span class="name">text</span>, <span class="name">signature</span>) - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="name">node</span>, <span class="bn">basestring</span>): - <span class="name">node</span> <span class="op">=</span> <span class="name">Node</span>(<span class="name">node</span>) - <span class="kw">return</span> <span class="name">node</span>.<span class="name">render</span>(<span class="name">req</span>, <span class="name">comp</span>) - <span class="kw">else</span>: - <span class="kw">raise</span> <span class="exc">ValueError</span>(<span class="st st-sg">'</span><span class="st">Parser "</span><span class="st st-int">%s</span><span class="st">" not found</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">syntax_parser</span>) - - - -<span class="kw">def </span><span class="fun">get_editor</span>(<span class="name">req</span>, <span class="name">signature</span><span class="op">=</span><span class="bn bn-pseudo">False</span>, <span class="name">syntax_parser</span><span class="op">=</span><span class="bn bn-pseudo">None</span>): - <span class="st st-db">"""</span><span class="st"> - Return a tuple in the form (javascript_file, options) - for the template. Both of them are strings which can be - used directly in the template:: - - <script type="text/javascript" src="{{ editorjs }}"></script> - - <script type="text/javascript"> - initEditor('id_of_textarea', 'id_of_toolbar', {{ options }}); - </script> - - If you set `signature` to ``True`` it will just display the - buttons which are relevant for the signature editor. - </span><span class="st st-db">"""</span> - <span class="kw">if</span> <span class="name">syntax_parser</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="name">syntax_parser</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">board</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">syntax_parser</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">plain</span><span class="st st-sg">'</span>).<span class="name">lower</span>() - <span class="kw">for</span> <span class="name">comp</span> <span class="op op-word">in</span> <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">get_components</span>(<span class="name">MarkupFormat</span>): - <span class="kw">if</span> <span class="name">comp</span>.<span class="name">name</span> <span class="op">==</span> <span class="name">syntax_parser</span>: - <span class="name">js</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">make_url</span>(<span class="name">comp</span>.<span class="name">editor_javascript</span>) - <span class="name">options</span> <span class="op">=</span> <span class="name">json</span>.<span class="name">dumps</span>(<span class="name">comp</span>.<span class="name">get_editor_options</span>(<span class="name">req</span>, <span class="name">signature</span>)) - <span class="kw">return</span> <span class="name">js</span>, <span class="name">options</span> - - <span class="kw">raise</span> <span class="exc">ValueError</span>(<span class="st st-sg">'</span><span class="st">Parser "</span><span class="st st-int">%s</span><span class="st">" not found</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">syntax_parser</span>) - - -<span class="kw">def </span><span class="fun">quote_text</span>(<span class="name">req</span>, <span class="name">text</span>, <span class="name">username</span><span class="op">=</span><span class="bn bn-pseudo">None</span>, <span class="name">syntax_parser</span><span class="op">=</span><span class="bn bn-pseudo">None</span>): - <span class="st st-db">"""</span><span class="st">Quote ``text`` with the style defined in the markup parser.</span><span class="st st-db">"""</span> - - <span class="kw">if</span> <span class="name">syntax_parser</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="name">syntax_parser</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">board</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">syntax_parser</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">plain</span><span class="st st-sg">'</span>).<span class="name">lower</span>() - <span class="kw">for</span> <span class="name">comp</span> <span class="op op-word">in</span> <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">get_components</span>(<span class="name">MarkupFormat</span>): - <span class="kw">if</span> <span class="name">comp</span>.<span class="name">name</span> <span class="op">==</span> <span class="name">syntax_parser</span>: - <span class="kw">return</span> <span class="name">comp</span>.<span class="name">quote_text</span>(<span class="name">req</span>, <span class="name">text</span>, <span class="name">username</span>) - <span class="kw">raise</span> <span class="exc">ValueError</span>(<span class="st st-sg">'</span><span class="st">Parser "</span><span class="st st-int">%s</span><span class="st">" not found</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">syntax_parser</span>) - - - -<span class="kw">def </span><span class="fun">get_markup_formatters</span>(<span class="name">req</span>): - <span class="st st-db">"""</span><span class="st"> - Return a list of known formatters - </span><span class="st st-db">"""</span> - <span class="name">result</span> <span class="op">=</span> [] - <span class="kw">for</span> <span class="name">comp</span> <span class="op op-word">in</span> <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">get_components</span>(<span class="name">MarkupFormat</span>): - <span class="name">result</span>.<span class="name">append</span>((<span class="name">comp</span>.<span class="name">name</span>, <span class="name">comp</span>.<span class="name">get_title</span>(<span class="name">req</span>))) - <span class="name">result</span>.<span class="name">sort</span>(<span class="name">key</span><span class="op">=</span><span class="kw">lambda</span> <span class="name">x</span>: <span class="name">x</span>[<span class="nb nb-int">1</span>].<span class="name">lower</span>()) - <span class="kw">return</span> <span class="name">result</span> - -<span class="cm"># -*- coding: utf-8 -*-</span> -<span class="st st-db">"""</span><span class="st"> - pocoo.pkg.core.user - ~~~~~~~~~~~~~~~~~~~ - - User model and utilities. - - :copyright: 2006 by Armin Ronacher. - :license: GNU GPL, see LICENSE for more details. -</span><span class="st st-db">"""</span> - -<span class="kw">from </span><span class="cls">os</span><span class="kw"> import</span> <span class="name">path</span> -<span class="kw">from </span><span class="cls">datetime</span><span class="kw"> import</span> <span class="name">datetime</span> - -<span class="kw">from </span><span class="cls">pocoo.db</span><span class="kw"> import</span> <span class="name">meta</span>, <span class="name">DatabaseModel</span>, <span class="name">lazy_column</span> -<span class="kw">from </span><span class="cls">pocoo.http</span><span class="kw"> import</span> <span class="name">DirectResponse</span>, <span class="name">AccessDeniedResponse</span> - -<span class="kw">from </span><span class="cls">pocoo.application</span><span class="kw"> import</span> <span class="name">LinkableMixin</span> -<span class="kw">from </span><span class="cls">pocoo.utils.text</span><span class="kw"> import</span> <span class="name">gen_password</span>, <span class="name">gen_activation_key</span>, <span class="name">gen_pwhash</span>, \ - <span class="name">check_pwhash</span> - -<span class="kw">from </span><span class="cls">pocoo.utils.uri</span><span class="kw"> import</span> <span class="name">urlencode</span> - -<span class="kw">from </span><span class="cls">pocoo.pkg.core.db</span><span class="kw"> import</span> <span class="name">users</span>, <span class="name">groups</span>, <span class="name">posts</span>, <span class="name">group_members</span> - - -<span class="kw">def </span><span class="fun">get_all_usernames</span>(<span class="name">ctx</span>): - <span class="st st-db">"""</span><span class="st">Return a list of all usernames.</span><span class="st st-db">"""</span> - <span class="name">result</span> <span class="op">=</span> <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>([<span class="name">users</span>.<span class="name">c</span>.<span class="name">username</span>])) - <span class="kw">return</span> [<span class="name">row</span>[<span class="nb nb-int">0</span>] <span class="kw">for</span> <span class="name">row</span> <span class="op op-word">in</span> <span class="name">result</span>] - - - -<span class="kw">def </span><span class="fun">get_id_username_mapping</span>(<span class="name">ctx</span>): - <span class="st st-db">"""</span><span class="st">Return a ``user_id`` -> ``username`` mapping.</span><span class="st st-db">"""</span> - <span class="name">result</span> <span class="op">=</span> <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>([<span class="name">users</span>.<span class="name">c</span>.<span class="name">user_id</span>, <span class="name">users</span>.<span class="name">c</span>.<span class="name">username</span>])) - <span class="kw">return</span> <span class="bn">dict</span>(<span class="bn">tuple</span>(<span class="name">row</span>) <span class="kw">for</span> <span class="name">row</span> <span class="op op-word">in</span> <span class="name">result</span>) - - - -<span class="kw">def </span><span class="fun">get_user_list</span>(<span class="name">ctx</span>, <span class="name">order_by</span><span class="op">=</span><span class="name">users</span>.<span class="name">c</span>.<span class="name">username</span>, <span class="name">order</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">asc</span><span class="st st-sg">'</span>, <span class="name">letter</span><span class="op">=</span><span class="bn bn-pseudo">None</span>, - <span class="name">hide_internal</span><span class="op">=</span><span class="bn bn-pseudo">False</span>): - <span class="st st-db">"""</span><span class="st">Return a list of all users with public details.</span><span class="st st-db">"""</span> - - <span class="cm">#XXX: sorting with databases sucks :-/ if sorted by username, resort</span> - <span class="cm"># with python, and btw, this is ugly</span> - <span class="name">u</span> <span class="op">=</span> <span class="name">users</span>.<span class="name">c</span> - <span class="name">q</span> <span class="op">=</span> [] - <span class="kw">if</span> <span class="name">letter</span>: - <span class="name">q</span>.<span class="name">append</span>(<span class="name">u</span>.<span class="name">username</span>.<span class="name">startswith</span>(<span class="name">letter</span>)) - <span class="kw">if</span> <span class="name">hide_internal</span>: - <span class="name">q</span>.<span class="name">append</span>((<span class="name">u</span>.<span class="name">username</span> <span class="op">!=</span> <span class="st st-sg">'</span><span class="st">default</span><span class="st st-sg">'</span>) <span class="op">&</span> (<span class="name">u</span>.<span class="name">username</span> <span class="op">!=</span> <span class="st st-sg">'</span><span class="st">anonymous</span><span class="st st-sg">'</span>)) - <span class="kw">try</span>: - <span class="name">order</span> <span class="op">=</span> { - <span class="st st-sg">'</span><span class="st">desc</span><span class="st st-sg">'</span>: <span class="name">meta</span>.<span class="name">desc</span>, - <span class="st st-sg">'</span><span class="st">asc</span><span class="st st-sg">'</span>: <span class="name">meta</span>.<span class="name">asc</span> - - }[<span class="name">order</span>] - <span class="kw">except</span> <span class="exc">KeyError</span>: - <span class="kw">raise</span> <span class="exc">ValueError</span>(<span class="st st-sg">'</span><span class="st">order must be either </span><span class="st st-esc">\'</span><span class="st">asc</span><span class="st st-esc">\'</span><span class="st"> or </span><span class="st st-esc">\'</span><span class="st">desc</span><span class="st st-esc">\'</span><span class="st st-sg">'</span>) - <span class="name">result</span> <span class="op">=</span> <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>([<span class="name">u</span>.<span class="name">user_id</span>, <span class="name">u</span>.<span class="name">username</span>, <span class="name">u</span>.<span class="name">email</span>, - <span class="name">u</span>.<span class="name">profile</span>, <span class="name">u</span>.<span class="name">last_login</span>, - <span class="name">u</span>.<span class="name">register_date</span>, <span class="name">u</span>.<span class="name">post_count</span>], - <span class="name">meta</span>.<span class="name">and_</span>(<span class="op">*</span><span class="name">q</span>), - <span class="name">order_by</span><span class="op">=</span>[<span class="name">order</span>(<span class="name">order_by</span>)])) - <span class="kw">def </span><span class="fun">prepare</span>(<span class="name">row</span>): - <span class="name">d</span> <span class="op">=</span> <span class="bn">dict</span>(<span class="name">row</span>) - <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">url</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">ctx</span>.<span class="name">make_url</span>(<span class="st st-sg">'</span><span class="st">users</span><span class="st st-sg">'</span>, <span class="name">urlencode</span>(<span class="name">row</span>[<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>])) - <span class="kw">return</span> <span class="name">d</span> - - <span class="kw">return</span> [<span class="name">prepare</span>(<span class="name">row</span>) <span class="kw">for</span> <span class="name">row</span> <span class="op op-word">in</span> <span class="name">result</span>] - - -<span class="kw">def </span><span class="fun">get_all_groupnames</span>(<span class="name">ctx</span>): - <span class="st st-db">"""</span><span class="st">Return a list of groupnames.</span><span class="st st-db">"""</span> - - <span class="name">result</span> <span class="op">=</span> <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>([<span class="name">groups</span>.<span class="name">c</span>.<span class="name">name</span>])) - <span class="kw">return</span> [<span class="name">row</span>[<span class="nb nb-int">0</span>] <span class="kw">for</span> <span class="name">row</span> <span class="op op-word">in</span> <span class="name">result</span>] - - - -<span class="kw">def </span><span class="fun">get_id_groupname_mapping</span>(<span class="name">ctx</span>): - <span class="st st-db">"""</span><span class="st">Return a group_id -> groupname mapping.</span><span class="st st-db">"""</span> - <span class="name">result</span> <span class="op">=</span> <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>([<span class="name">groups</span>.<span class="name">c</span>.<span class="name">group_id</span>, <span class="name">groups</span>.<span class="name">c</span>.<span class="name">name</span>])) - <span class="kw">return</span> <span class="bn">dict</span>(<span class="bn">tuple</span>(<span class="name">row</span>) <span class="kw">for</span> <span class="name">row</span> <span class="op op-word">in</span> <span class="name">result</span>) - - - -<span class="kw">def </span><span class="fun">get_group_list</span>(<span class="name">ctx</span>, <span class="name">order_by</span><span class="op">=</span><span class="name">groups</span>.<span class="name">c</span>.<span class="name">name</span>, <span class="name">order</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">asc</span><span class="st st-sg">'</span>, <span class="name">letter</span><span class="op">=</span><span class="bn bn-pseudo">None</span>, - <span class="name">show_hidden</span><span class="op">=</span><span class="bn bn-pseudo">True</span>): - <span class="st st-db">"""</span><span class="st">Return a list of all groups with public details.</span><span class="st st-db">"""</span> - - <span class="name">g</span> <span class="op">=</span> <span class="name">groups</span>.<span class="name">c</span> - <span class="name">q</span> <span class="op">=</span> [] - <span class="kw">if</span> <span class="name">letter</span>: - <span class="name">q</span>.<span class="name">append</span>(<span class="name">g</span>.<span class="name">name</span>.<span class="name">startswith</span>(<span class="name">letter</span>)) - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">show_hidden</span>: - <span class="name">q</span>.<span class="name">append</span>(<span class="name">g</span>.<span class="name">hidden</span> <span class="op">==</span> <span class="bn bn-pseudo">True</span>) - <span class="kw">try</span>: - <span class="name">order</span> <span class="op">=</span> { - <span class="st st-sg">'</span><span class="st">desc</span><span class="st st-sg">'</span>: <span class="name">meta</span>.<span class="name">desc</span>, - <span class="st st-sg">'</span><span class="st">asc</span><span class="st st-sg">'</span>: <span class="name">meta</span>.<span class="name">asc</span> - - }[<span class="name">order</span>] - <span class="kw">except</span> <span class="exc">KeyError</span>: - <span class="kw">raise</span> <span class="exc">ValueError</span>(<span class="st st-sg">'</span><span class="st">order must be either </span><span class="st st-esc">\'</span><span class="st">asc</span><span class="st st-esc">\'</span><span class="st"> or </span><span class="st st-esc">\'</span><span class="st">desc</span><span class="st st-esc">\'</span><span class="st st-sg">'</span>) - <span class="name">result</span> <span class="op">=</span> <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>([<span class="name">g</span>.<span class="name">group_id</span>, <span class="name">g</span>.<span class="name">name</span>, <span class="name">g</span>.<span class="name">public</span>, - <span class="name">g</span>.<span class="name">hidden</span>], <span class="name">meta</span>.<span class="name">and_</span>(<span class="op">*</span><span class="name">q</span>), - <span class="name">order_by</span><span class="op">=</span>[<span class="name">order</span>(<span class="name">order_by</span>)])) - <span class="kw">def </span><span class="fun">prepare</span>(<span class="name">row</span>): - <span class="name">d</span> <span class="op">=</span> <span class="bn">dict</span>(<span class="name">row</span>) - <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">url</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">ctx</span>.<span class="name">make_url</span>(<span class="st st-sg">'</span><span class="st">groups</span><span class="st st-sg">'</span>, <span class="name">urlencode</span>(<span class="name">row</span>[<span class="st st-sg">'</span><span class="st">name</span><span class="st st-sg">'</span>])) - <span class="kw">return</span> <span class="name">d</span> - - <span class="kw">return</span> [<span class="name">prepare</span>(<span class="name">row</span>) <span class="kw">for</span> <span class="name">row</span> <span class="op op-word">in</span> <span class="name">result</span>] - - -<span class="kw">def </span><span class="fun">get_user</span>(<span class="name">req</span>, <span class="name">user_id_or_name</span>): - <span class="st st-db">"""</span><span class="st"> - - Return a dict of user information for the template. - </span><span class="st st-db">"""</span> - <span class="name">ctx</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">ctx</span> - <span class="name">u</span> <span class="op">=</span> <span class="name">users</span>.<span class="name">c</span> - - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="name">user_id_or_name</span>, (<span class="bn">int</span>, <span class="bn">long</span>)): - <span class="name">q</span> <span class="op">=</span> (<span class="name">u</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">user_id_or_name</span>) - <span class="kw">else</span>: - <span class="name">q</span> <span class="op">=</span> (<span class="name">u</span>.<span class="name">username</span> <span class="op">==</span> <span class="name">user_id_or_name</span>) - <span class="name">result</span> <span class="op">=</span> <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>([<span class="name">u</span>.<span class="name">user_id</span>, <span class="name">u</span>.<span class="name">username</span>, <span class="name">u</span>.<span class="name">email</span>, - <span class="name">u</span>.<span class="name">profile</span>, <span class="name">u</span>.<span class="name">settings</span>, <span class="name">u</span>.<span class="name">last_login</span>, - <span class="name">u</span>.<span class="name">register_date</span>, <span class="name">u</span>.<span class="name">post_count</span>], <span class="name">q</span>)) - <span class="name">row</span> <span class="op">=</span> <span class="name">result</span>.<span class="name">fetchone</span>() - <span class="kw">if</span> <span class="name">row</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="cm"># XXX: error return needed</span> - - <span class="kw">return</span> - <span class="name">user</span> <span class="op">=</span> <span class="bn">dict</span>(<span class="name">row</span>) - <span class="name">user</span>[<span class="st st-sg">'</span><span class="st">url</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">ctx</span>.<span class="name">make_url</span>(<span class="st st-sg">'</span><span class="st">users</span><span class="st st-sg">'</span>, <span class="name">urlencode</span>(<span class="name">row</span>[<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>])) - <span class="kw">return</span> <span class="name">user</span> - - -<span class="kw">def </span><span class="fun">get_user_avatar</span>(<span class="name">req</span>, <span class="name">user_id_or_name</span>): - <span class="st st-db">"""</span><span class="st"> - Return the user avatar. - </span><span class="st st-db">"""</span> - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="name">user_id_or_name</span>, (<span class="bn">int</span>, <span class="bn">long</span>)): - <span class="name">q</span> <span class="op">=</span> (<span class="name">users</span>.<span class="name">c</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">user_id_or_name</span>) - <span class="kw">else</span>: - <span class="name">q</span> <span class="op">=</span> (<span class="name">users</span>.<span class="name">c</span>.<span class="name">username</span> <span class="op">==</span> <span class="name">user_id_or_name</span>) - <span class="name">result</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>([<span class="name">users</span>.<span class="name">c</span>.<span class="name">user_id</span>], <span class="name">q</span>)) - <span class="name">row</span> <span class="op">=</span> <span class="name">result</span>.<span class="name">fetchone</span>() - <span class="kw">if</span> <span class="name">row</span> <span class="op op-word">is</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">None</span>: - <span class="name">fn</span> <span class="op">=</span> <span class="name">path</span>.<span class="name">join</span>(<span class="name">req</span>.<span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">root</span>, <span class="st st-sg">'</span><span class="st">avatars</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st st-int">%d</span><span class="st">.png</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">row</span>[<span class="nb nb-int">0</span>]) - <span class="kw">if</span> <span class="name">path</span>.<span class="name">exists</span>(<span class="name">fn</span>): - <span class="name">f</span> <span class="op">=</span> <span class="bn">file</span>(<span class="name">fn</span>, <span class="st st-sg">'</span><span class="st">rb</span><span class="st st-sg">'</span>) - <span class="name">result</span> <span class="op">=</span> <span class="name">f</span>.<span class="name">read</span>() - <span class="name">f</span>.<span class="name">close</span>() - <span class="kw">return</span> <span class="name">result</span> - - -<span class="kw">def </span><span class="fun">get_id_by_name</span>(<span class="name">ctx</span>, <span class="name">name</span>): - <span class="name">u</span> <span class="op">=</span> <span class="name">users</span>.<span class="name">c</span> - - <span class="name">result</span> <span class="op">=</span> <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>([<span class="name">u</span>.<span class="name">user_id</span>], - <span class="name">u</span>.<span class="name">username</span> <span class="op">==</span> <span class="name">name</span>)) - <span class="name">row</span> <span class="op">=</span> <span class="name">result</span>.<span class="name">fetchone</span>() - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">row</span>: - <span class="kw">raise</span> <span class="name">UserNotFound</span> - - <span class="kw">return</span> <span class="name">row</span>[<span class="nb nb-int">0</span>] - - -<span class="kw">def </span><span class="fun">check_login_data</span>(<span class="name">ctx</span>, <span class="name">username</span>, <span class="name">password</span>): - <span class="st st-db">"""</span><span class="st"> - - Check if a username and password was found in the - database. Returns None if the user does not exist - or the password is incorrect, otherwise it returns - the user id. - </span><span class="st st-db">"""</span> - <span class="name">u</span> <span class="op">=</span> <span class="name">users</span>.<span class="name">c</span> - <span class="name">result</span> <span class="op">=</span> <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>([<span class="name">u</span>.<span class="name">user_id</span>, <span class="name">u</span>.<span class="name">pwhash</span>, <span class="name">u</span>.<span class="name">act_key</span>], - <span class="name">users</span>.<span class="name">c</span>.<span class="name">username</span> <span class="op">==</span> <span class="name">username</span> - - )) - <span class="name">row</span> <span class="op">=</span> <span class="name">result</span>.<span class="name">fetchone</span>() - <span class="kw">if</span> <span class="name">row</span> <span class="op op-word">is</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">None</span> <span class="op op-word">and</span> <span class="op op-word">not</span> <span class="name">row</span>[<span class="st st-sg">'</span><span class="st">act_key</span><span class="st st-sg">'</span>] <span class="op op-word">and</span> \ - <span class="name">check_pwhash</span>(<span class="name">row</span>[<span class="st st-sg">'</span><span class="st">pwhash</span><span class="st st-sg">'</span>], <span class="name">password</span>): - <span class="kw">return</span> <span class="name">row</span>[<span class="st st-sg">'</span><span class="st">user_id</span><span class="st st-sg">'</span>] - - - -<span class="kw">def </span><span class="fun">sync_post_count</span>(<span class="name">ctx</span>, <span class="name">user_id</span>): - <span class="st st-db">"""</span><span class="st">Sync the user post count with the post tables.</span><span class="st st-db">"""</span> - <span class="kw">def </span><span class="fun">do</span>(<span class="name">con</span>): - <span class="name">result</span> <span class="op">=</span> <span class="name">con</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>([<span class="name">meta</span>.<span class="name">func</span>.<span class="name">count</span>(<span class="name">posts</span>.<span class="name">c</span>.<span class="name">post_id</span>)], - <span class="name">posts</span>.<span class="name">c</span>.<span class="name">author_id</span> <span class="op">==</span> <span class="name">user_id</span> - - )) - <span class="name">con</span>.<span class="name">execute</span>(<span class="name">users</span>.<span class="name">update</span>(<span class="name">users</span>.<span class="name">c</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">user_id</span>), - <span class="name">post_count</span> <span class="op">=</span> <span class="name">result</span>.<span class="name">fetchone</span>()[<span class="nb nb-int">0</span>] - ) - <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">transaction</span>(<span class="name">do</span>) - - - -<span class="kw">def </span><span class="fun">reset_password</span>(<span class="name">ctx</span>, <span class="name">username</span>, <span class="name">email</span>): - <span class="st st-db">"""</span><span class="st"> - Reset the password and returns the new password - if the email matched the username. - If not it will return None. - </span><span class="st st-db">"""</span> - <span class="name">password</span> <span class="op">=</span> <span class="name">gen_password</span>() - <span class="name">result</span> <span class="op">=</span> <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">users</span>.<span class="name">update</span>((<span class="name">users</span>.<span class="name">c</span>.<span class="name">username</span> <span class="op">==</span> <span class="name">username</span>) <span class="op">&</span> - - (<span class="name">users</span>.<span class="name">c</span>.<span class="name">email</span> <span class="op">==</span> <span class="name">email</span>)), - <span class="name">pwhash</span> <span class="op">=</span> <span class="name">gen_pwhash</span>(<span class="name">password</span>) - ) - <span class="kw">if</span> <span class="name">result</span>.<span class="name">rowcount</span>: - <span class="kw">return</span> <span class="name">password</span> - - -<span class="kw">class </span><span class="cls">UserNotFound</span>(<span class="exc">Exception</span>): - <span class="kw">pass</span> - - -<span class="kw">class </span><span class="cls">User</span>(<span class="name">DatabaseModel</span>, <span class="name">LinkableMixin</span>): - <span class="name">NotFound</span> <span class="op">=</span> <span class="name">UserNotFound</span> - - <span class="kw">def </span><span class="fun">__init__</span>(<span class="bn bn-pseudo">self</span>, <span class="name">ctx</span>, <span class="name">user_id</span>): - <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span> <span class="op">=</span> <span class="name">ctx</span> - - <span class="bn bn-pseudo">self</span>.<span class="name">user_id</span> <span class="op">=</span> <span class="name">user_id</span> - <span class="bn">super</span>(<span class="name">User</span>, <span class="bn bn-pseudo">self</span>).<span class="name">__init__</span>(<span class="name">ctx</span>, <span class="name">users</span>, <span class="st st-sg">'</span><span class="st">user_id</span><span class="st st-sg">'</span>) - - <span class="kw">from </span><span class="cls">pocoo.pkg.core.acl</span><span class="kw"> import</span> <span class="name">AclManager</span> - - <span class="bn bn-pseudo">self</span>.<span class="name">acl</span> <span class="op">=</span> <span class="name">AclManager</span>(<span class="name">ctx</span>, <span class="bn bn-pseudo">self</span>) - - <span class="name">subject_id</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">subject_id</span><span class="st st-sg">'</span>) - <span class="name">username</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>) - <span class="name">email</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">email</span><span class="st st-sg">'</span>) - <span class="name">pwhash</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">pwhash</span><span class="st st-sg">'</span>) - <span class="name">act_key</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">act_key</span><span class="st st-sg">'</span>) - <span class="name">language</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">language</span><span class="st st-sg">'</span>) - <span class="name">profile</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">profile</span><span class="st st-sg">'</span>) - <span class="name">settings</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">settings</span><span class="st st-sg">'</span>) - <span class="name">last_login</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">last_login</span><span class="st st-sg">'</span>) - <span class="name">register_date</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">register_date</span><span class="st st-sg">'</span>) - <span class="name">post_count</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">post_count</span><span class="st st-sg">'</span>) - <span class="name">read_threads</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">read_threads</span><span class="st st-sg">'</span>) - <span class="name">read_posts</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">read_posts</span><span class="st st-sg">'</span>) - - <span class="deco">@property</span> - - <span class="kw">def </span><span class="fun">relative_url</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="st st-sg">'</span><span class="st">users/</span><span class="st st-int">%s</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="bn bn-pseudo">self</span>.<span class="name">username</span> - - <span class="deco">@staticmethod</span> - <span class="kw">def </span><span class="fun">create</span>(<span class="name">ctx</span>, <span class="name">username</span>, <span class="name">password</span>, <span class="name">email</span>, <span class="name">activate</span><span class="op">=</span><span class="bn bn-pseudo">False</span>): - <span class="st st-db">"""</span><span class="st">Creates a new user.</span><span class="st st-db">"""</span> - - <span class="kw">if</span> <span class="name">activate</span>: - <span class="name">act_key</span> <span class="op">=</span> <span class="name">gen_activation_key</span>() - <span class="kw">else</span>: - <span class="name">act_key</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="name">result</span> <span class="op">=</span> <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">users</span>.<span class="name">insert</span>(), - <span class="name">username</span><span class="op">=</span><span class="name">username</span>, - <span class="name">email</span><span class="op">=</span><span class="name">email</span>, - <span class="name">act_key</span><span class="op">=</span><span class="name">act_key</span>, - <span class="name">pwhash</span><span class="op">=</span><span class="name">gen_pwhash</span>(<span class="name">password</span>), - <span class="name">register_date</span><span class="op">=</span><span class="name">datetime</span>.<span class="name">utcnow</span>(), - <span class="name">post_count</span><span class="op">=</span><span class="nb nb-int">0</span> - - ) - <span class="kw">return</span> <span class="name">User</span>(<span class="name">ctx</span>, <span class="name">result</span>.<span class="name">last_inserted_ids</span>()[<span class="nb nb-int">0</span>]) - - <span class="kw">def </span><span class="fun">check_password</span>(<span class="bn bn-pseudo">self</span>, <span class="name">password</span>): - <span class="kw">if</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">self</span>.<span class="name">exists</span>: - <span class="kw">return</span> <span class="bn bn-pseudo">False</span> - - <span class="kw">return</span> <span class="name">check_pwhash</span>(<span class="bn bn-pseudo">self</span>.<span class="name">pwhash</span>, <span class="name">password</span>) - - <span class="kw">def </span><span class="fun">set_password</span>(<span class="bn bn-pseudo">self</span>, <span class="name">password</span>): - <span class="bn bn-pseudo">self</span>.<span class="name">pwhash</span> <span class="op">=</span> <span class="name">gen_pwhash</span>(<span class="name">password</span>) - - <span class="kw">def </span><span class="fun">assert_logged_in</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st"> - - Check if the user is logged in and raise a DirectResponse - exception with an AccessDeniedResponse to display the user a - login or "missing permission" page. - </span><span class="st st-db">"""</span> - <span class="kw">if</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">self</span>.<span class="name">identified</span>: - <span class="kw">raise</span> <span class="name">DirectResponse</span>(<span class="name">AccessDeniedResponse</span>()) - - <span class="kw">def </span><span class="fun">iter_groups</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st"> - - Return a generator for all groups this user has joined. - </span><span class="st st-db">"""</span> - <span class="name">result</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>([<span class="name">groups</span>.<span class="name">c</span>.<span class="name">group_id</span>], - (<span class="name">users</span>.<span class="name">c</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="bn bn-pseudo">self</span>.<span class="name">user_id</span>) <span class="op">&</span> - - (<span class="name">group_members</span>.<span class="name">c</span>.<span class="name">group_id</span> <span class="op">==</span> <span class="name">groups</span>.<span class="name">c</span>.<span class="name">group_id</span>) <span class="op">&</span> - - (<span class="name">group_members</span>.<span class="name">c</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">users</span>.<span class="name">c</span>.<span class="name">user_id</span>) - )) - <span class="kw">for</span> <span class="name">row</span> <span class="op op-word">in</span> <span class="name">result</span>: - <span class="kw">yield</span> <span class="name">Group</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, <span class="name">row</span>[<span class="nb nb-int">0</span>]) - - <span class="kw">def </span><span class="fun">activate</span>(<span class="bn bn-pseudo">self</span>): - <span class="bn bn-pseudo">self</span>.<span class="name">act_key</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="kw">def </span><span class="fun">deactivate</span>(<span class="bn bn-pseudo">self</span>): - <span class="bn bn-pseudo">self</span>.<span class="name">act_key</span> <span class="op">=</span> <span class="name">gen_activation_key</span>() - - <span class="deco">@property</span> - - <span class="kw">def </span><span class="fun">identified</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">user_id</span> <span class="op">></span> <span class="nb nb-int">0</span> - - <span class="deco">@property</span> - - <span class="kw">def </span><span class="fun">active</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">self</span>.<span class="name">act_key</span> - - <span class="deco">@property</span> - - <span class="kw">def </span><span class="fun">groups</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="bn">list</span>(<span class="bn bn-pseudo">self</span>.<span class="name">iter_groups</span>()) - - <span class="deco">@property</span> - <span class="kw">def </span><span class="fun">admin</span>(<span class="bn bn-pseudo">self</span>): - <span class="cm">#TODO: from ACL</span> - - <span class="kw">return</span> <span class="bn bn-pseudo">True</span> - - <span class="kw">def </span><span class="fun">__eq__</span>(<span class="bn bn-pseudo">self</span>, <span class="name">other</span>): - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">other</span>.<span class="name">user_id</span> - - <span class="kw">def </span><span class="fun">__ne__</span>(<span class="bn bn-pseudo">self</span>, <span class="name">other</span>): - <span class="kw">return</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">self</span>.<span class="name">__eq__</span>(<span class="name">other</span>) - - <span class="kw">def </span><span class="fun">__repr__</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="st st-sg">'</span><span class="st"><</span><span class="st st-int">%s</span><span class="st"> </span><span class="st st-int">%d</span><span class="st">: </span><span class="st st-int">%r</span><span class="st">></span><span class="st st-sg">'</span> <span class="op">%</span> ( - <span class="bn bn-pseudo">self</span>.<span class="name">__class__</span>.<span class="name">__name__</span>, - <span class="bn bn-pseudo">self</span>.<span class="name">user_id</span>, - <span class="bn bn-pseudo">self</span>.<span class="name">username</span> - - ) - - -<span class="kw">class </span><span class="cls">GroupNotFound</span>(<span class="exc">Exception</span>): - <span class="kw">pass</span> - - -<span class="kw">class </span><span class="cls">Group</span>(<span class="name">DatabaseModel</span>): - - <span class="kw">def </span><span class="fun">__init__</span>(<span class="bn bn-pseudo">self</span>, <span class="name">ctx</span>, <span class="name">group_id</span>): - <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span> <span class="op">=</span> <span class="name">ctx</span> - - <span class="bn bn-pseudo">self</span>.<span class="name">group_id</span> <span class="op">=</span> <span class="name">group_id</span> - <span class="bn">super</span>(<span class="name">Group</span>, <span class="bn bn-pseudo">self</span>).<span class="name">__init__</span>(<span class="name">ctx</span>, <span class="name">groups</span>, <span class="st st-sg">'</span><span class="st">group_id</span><span class="st st-sg">'</span>) - - <span class="kw">from </span><span class="cls">pocoo.pkg.core.acl</span><span class="kw"> import</span> <span class="name">AclManager</span> - - <span class="bn bn-pseudo">self</span>.<span class="name">acl</span> <span class="op">=</span> <span class="name">AclManager</span>(<span class="name">ctx</span>, <span class="bn bn-pseudo">self</span>) - - <span class="name">subject_id</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">subject_id</span><span class="st st-sg">'</span>) - <span class="name">name</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">name</span><span class="st st-sg">'</span>) - <span class="name">public</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">public</span><span class="st st-sg">'</span>) - <span class="name">hidden</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">hidden</span><span class="st st-sg">'</span>) - - <span class="deco">@staticmethod</span> - - <span class="kw">def </span><span class="fun">create</span>(<span class="name">ctx</span>, <span class="name">name</span>, <span class="name">public</span><span class="op">=</span><span class="bn bn-pseudo">True</span>, <span class="name">hidden</span><span class="op">=</span><span class="bn bn-pseudo">False</span>): - <span class="st st-db">"""</span><span class="st">Create a new usergroup.</span><span class="st st-db">"""</span> - - <span class="name">result</span> <span class="op">=</span> <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">groups</span>.<span class="name">insert</span>(), - <span class="name">name</span><span class="op">=</span><span class="name">name</span>, - <span class="name">public</span><span class="op">=</span><span class="name">public</span>, - <span class="name">hidden</span><span class="op">=</span><span class="name">hidden</span> - - ) - <span class="kw">return</span> <span class="name">Group</span>(<span class="name">ctx</span>, <span class="name">result</span>.<span class="name">last_inserted_ids</span>()[<span class="nb nb-int">0</span>]) - - <span class="deco">@property</span> - <span class="kw">def </span><span class="fun">members</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="bn">list</span>(<span class="bn bn-pseudo">self</span>.<span class="name">iter_members</span>()) - - <span class="kw">def </span><span class="fun">iter_members</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">Return a generator for all group members.</span><span class="st st-db">"""</span> - - <span class="name">result</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>([<span class="name">users</span>.<span class="name">c</span>.<span class="name">user_id</span>], - (<span class="name">groups</span>.<span class="name">c</span>.<span class="name">group_id</span> <span class="op">==</span> <span class="bn bn-pseudo">self</span>.<span class="name">group_id</span>) <span class="op">&</span> - - (<span class="name">group_members</span>.<span class="name">c</span>.<span class="name">group_id</span> <span class="op">==</span> <span class="name">groups</span>.<span class="name">c</span>.<span class="name">group_id</span>) <span class="op">&</span> - - (<span class="name">group_members</span>.<span class="name">c</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">users</span>.<span class="name">c</span>.<span class="name">user_id</span>) - )) - <span class="kw">for</span> <span class="name">row</span> <span class="op op-word">in</span> <span class="name">result</span>: - <span class="kw">yield</span> <span class="name">User</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, <span class="name">row</span>[<span class="nb nb-int">0</span>]) - - <span class="kw">def </span><span class="fun">add_member</span>(<span class="bn bn-pseudo">self</span>, <span class="name">user</span>): - <span class="st st-db">"""</span><span class="st">Add a new member to the group.</span><span class="st st-db">"""</span> - - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="name">user</span>, <span class="name">User</span>): - <span class="name">user_id</span> <span class="op">=</span> <span class="name">user</span>.<span class="name">user_id</span> - - <span class="kw">else</span>: - <span class="name">user_id</span> <span class="op">=</span> <span class="name">User</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, <span class="name">user</span>).<span class="name">user_id</span> - - <span class="cm"># check if the user is already a member of the group</span> - <span class="name">result</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>([<span class="name">group_members</span>.<span class="name">c</span>.<span class="name">user_id</span>], - (<span class="name">group_members</span>.<span class="name">c</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">user_id</span>) <span class="op">&</span> - - (<span class="name">group_members</span>.<span class="name">c</span>.<span class="name">group_id</span> <span class="op">==</span> <span class="bn bn-pseudo">self</span>.<span class="name">group_id</span>) - )) - <span class="kw">if</span> <span class="name">result</span>.<span class="name">fetchone</span>() <span class="op op-word">is</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">None</span>: - <span class="kw">raise</span> <span class="exc">ValueError</span>(<span class="st st-sg">'</span><span class="st">The user </span><span class="st st-int">%d</span><span class="st"> is alreay a member of this group</span><span class="st st-sg">'</span> <span class="op">%</span> - - <span class="name">user_id</span>) - <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">group_members</span>.<span class="name">insert</span>(), - <span class="name">user_id</span> <span class="op">=</span> <span class="name">user_id</span>, - <span class="name">group_id</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">group_id</span> - - ) - - <span class="kw">def </span><span class="fun">remove_member</span>(<span class="bn bn-pseudo">self</span>, <span class="name">user</span>): - <span class="st st-db">"""</span><span class="st">Remove a member from the group.</span><span class="st st-db">"""</span> - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="name">user</span>, <span class="name">User</span>): - <span class="name">user_id</span> <span class="op">=</span> <span class="name">user</span>.<span class="name">user_id</span> - - <span class="kw">else</span>: - <span class="name">user_id</span> <span class="op">=</span> <span class="name">User</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, <span class="name">user</span>).<span class="name">user_id</span> - - <span class="cm"># check if the user is not in the group</span> - <span class="name">result</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>([<span class="name">group_members</span>.<span class="name">c</span>.<span class="name">user_id</span>], - (<span class="name">group_members</span>.<span class="name">c</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">user_id</span>) <span class="op">&</span> - - (<span class="name">group_members</span>.<span class="name">c</span>.<span class="name">group_id</span> <span class="op">==</span> <span class="bn bn-pseudo">self</span>.<span class="name">group_id</span>) - )) - <span class="kw">if</span> <span class="name">result</span>.<span class="name">fetchone</span>() <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="kw">raise</span> <span class="exc">ValueError</span>(<span class="st st-sg">'</span><span class="st">The user </span><span class="st st-int">%d</span><span class="st"> is not a member of this group</span><span class="st st-sg">'</span> <span class="op">%</span> - - <span class="name">user_id</span>) - <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">group_members</span>.<span class="name">delete</span>( - (<span class="name">group_members</span>.<span class="name">c</span>.<span class="name">group_id</span> <span class="op">==</span> <span class="bn bn-pseudo">self</span>.<span class="name">group_id</span>) <span class="op">&</span> - - (<span class="name">group_members</span>.<span class="name">c</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">user_id</span>) - )) - - <span class="kw">def </span><span class="fun">is_member</span>(<span class="bn bn-pseudo">self</span>, <span class="name">user</span>): - <span class="st st-db">"""</span><span class="st">Check if a user is a member of this group.</span><span class="st st-db">"""</span> - - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="name">user</span>, <span class="name">User</span>): - <span class="name">user_id</span> <span class="op">=</span> <span class="name">user</span>.<span class="name">user_id</span> - - <span class="kw">else</span>: - <span class="name">user_id</span> <span class="op">=</span> <span class="name">User</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, <span class="name">user</span>).<span class="name">user_id</span> - - <span class="name">result</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>([<span class="name">group_members</span>.<span class="name">c</span>.<span class="name">user_id</span>], - (<span class="name">group_members</span>.<span class="name">c</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">user_id</span>) <span class="op">&</span> - - (<span class="name">group_members</span>.<span class="name">c</span>.<span class="name">group_id</span> <span class="op">==</span> <span class="bn bn-pseudo">self</span>.<span class="name">group_id</span>) - )) - <span class="kw">return</span> <span class="name">result</span>.<span class="name">fetchone</span>() <span class="op op-word">is</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">None</span> - - <span class="kw">def </span><span class="fun">__eq__</span>(<span class="bn bn-pseudo">self</span>, <span class="name">other</span>): - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">group_id</span> <span class="op">==</span> <span class="name">other</span>.<span class="name">group_id</span> - - <span class="kw">def </span><span class="fun">__ne__</span>(<span class="bn bn-pseudo">self</span>, <span class="name">other</span>): - <span class="kw">return</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">self</span>.<span class="name">__eq__</span>(<span class="name">other</span>) - - <span class="kw">def </span><span class="fun">__repr__</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="st st-sg">'</span><span class="st"><</span><span class="st st-int">%s</span><span class="st"> </span><span class="st st-int">%d</span><span class="st">: </span><span class="st st-int">%r</span><span class="st">></span><span class="st st-sg">'</span> <span class="op">%</span> ( - <span class="bn bn-pseudo">self</span>.<span class="name">__class__</span>.<span class="name">__name__</span>, - <span class="bn bn-pseudo">self</span>.<span class="name">group_id</span>, - <span class="bn bn-pseudo">self</span>.<span class="name">name</span> - - ) -<span class="cm"># -*- coding: utf-8 -*-</span> -<span class="st st-db">"""</span><span class="st"> - pocoo.pkg.core.usersettings - ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - User Settings support. - - :copyright: 2006 by Armin Ronacher, Lukas Meuser. - :license: GNU GPL, see LICENSE for more details. -</span><span class="st st-db">"""</span> -<span class="kw">import </span><span class="cls">os</span> -<span class="kw">from </span><span class="cls">os</span><span class="kw"> import</span> <span class="name">path</span> - -<span class="kw">from </span><span class="cls">pocoo</span><span class="kw"> import</span> <span class="name">Component</span> -<span class="kw">from </span><span class="cls">pocoo.http</span><span class="kw"> import</span> <span class="name">PageNotFound</span> -<span class="kw">from </span><span class="cls">pocoo.application</span><span class="kw"> import</span> <span class="name">LinkableMixin</span> - -<span class="kw">from </span><span class="cls">pocoo.utils.image</span><span class="kw"> import</span> <span class="name">resize_image</span> -<span class="kw">from </span><span class="cls">pocoo.utils.uri</span><span class="kw"> import</span> <span class="name">urlencode</span> -<span class="kw">from </span><span class="cls">pocoo.utils.form</span><span class="kw"> import</span> <span class="name">Form</span>, <span class="name">TextField</span>, <span class="name">FileField</span>, <span class="name">TextArea</span>, <span class="name">CheckBox</span>, \ - <span class="name">SelectBox</span> - -<span class="kw">from </span><span class="cls">pocoo.utils.validators</span><span class="kw"> import</span> <span class="name">isSameValue</span>, <span class="name">isEmail</span>, <span class="name">isExistingUrl</span>, \ - <span class="name">checkTextLength</span>, <span class="name">mayEmpty</span>, <span class="name">checkIfOtherNotBlank</span>, <span class="name">isSupportedImage</span>, \ - <span class="name">doMultiCheck</span>, <span class="name">isInRange</span>, <span class="name">isInteger</span> - -<span class="kw">from </span><span class="cls">pocoo.pkg.core.validators</span><span class="kw"> import</span> <span class="name">isStrongPassword</span>, <span class="name">isIcqMessengerId</span>, \ - <span class="name">isMsnMessengerId</span>, <span class="name">isJabberMessengerId</span> -<span class="kw">from </span><span class="cls">pocoo.pkg.core.textfmt</span><span class="kw"> import</span> <span class="name">get_editor</span> - - -<span class="kw">class </span><span class="cls">UserSettingsPage</span>(<span class="name">Component</span>, <span class="name">LinkableMixin</span>): - - <span class="deco">@property</span> - <span class="kw">def </span><span class="fun">settings_page_identifier</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st">The name of the page which is also the url - under which the page will be visible:: - - /settings/$SETTINGS_PAGE_IDENTIFIER$</span><span class="st st-db">"""</span> - - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">__class__</span>.<span class="name">__name__</span> - - <span class="deco">@property</span> - <span class="kw">def </span><span class="fun">relative_url</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="st st-sg">'</span><span class="st">settings/</span><span class="st st-int">%s</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="bn bn-pseudo">self</span>.<span class="name">settings_page_identifier</span> - - <span class="kw">def </span><span class="fun">get_settings_link_title</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="st st-db">"""</span><span class="st">Has to return a text for the link title in the - settings sidebar (this musn't be a sidebar, in fact - it depends on the template. - - If the method returns ``None`` the template wont - render this link.</span><span class="st st-db">"""</span> - - <span class="kw">def </span><span class="fun">get_settings_page</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="st st-db">"""</span><span class="st">This method automatically gets called when a - user requests this settings page. It must either - return a valid Response object or a tuple in the - form (template, context) where template is a string - with the template filename and context is a dict - which automatically gets updated with the generated - sidebar so that templates can access it.</span><span class="st st-db">"""</span> - - - -<span class="kw">class </span><span class="cls">UserSignatureSettings</span>(<span class="name">UserSettingsPage</span>): - <span class="st st-db">"""</span><span class="st"> - This page allows the user to create / edit his signature - using an editor. - </span><span class="st st-db">"""</span> - <span class="name">settings_page_identifier</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">signature</span><span class="st st-sg">'</span> - - <span class="kw">def </span><span class="fun">get_settings_link_title</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - - <span class="kw">return</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Signature</span><span class="st st-sg">'</span>) - - <span class="kw">def </span><span class="fun">get_settings_page</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - - <span class="name">get_setting</span> <span class="op">=</span> <span class="kw">lambda</span> <span class="name">x</span>: <span class="name">req</span>.<span class="name">user</span>.<span class="name">profile</span>.<span class="name">get</span>(<span class="name">x</span>, <span class="name">u</span><span class="st st-sg">''</span>) - <span class="name">msg</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="name">form</span> <span class="op">=</span> <span class="name">Form</span>(<span class="name">req</span>, <span class="bn bn-pseudo">self</span>, <span class="st st-sg">'</span><span class="st">POST</span><span class="st st-sg">'</span>, - <span class="name">TextArea</span>(<span class="st st-sg">'</span><span class="st">signature</span><span class="st st-sg">'</span>, - <span class="name">default</span><span class="op">=</span><span class="name">get_setting</span>(<span class="st st-sg">'</span><span class="st">signature</span><span class="st st-sg">'</span>), - <span class="name">validator</span><span class="op">=</span><span class="name">checkTextLength</span>(<span class="nb nb-int">0</span>, <span class="nb nb-int">255</span>) <span class="cm"># from config!</span> - - ) - ) - <span class="kw">if</span> <span class="name">req</span>.<span class="name">method</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">POST</span><span class="st st-sg">'</span>: - <span class="name">form</span>.<span class="name">update</span>(<span class="name">req</span>.<span class="name">form</span>, <span class="name">prefix</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">f_</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">form</span>.<span class="name">has_errors</span>: - <span class="name">d</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">to_dict</span>() - <span class="name">req</span>.<span class="name">user</span>.<span class="name">profile</span>.<span class="name">update</span>(<span class="name">d</span>) - <span class="name">req</span>.<span class="name">user</span>.<span class="name">save</span>() - <span class="name">msg</span> <span class="op">=</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Signature saved</span><span class="st st-sg">'</span>) - - <span class="name">js</span>, <span class="name">options</span> <span class="op">=</span> <span class="name">get_editor</span>(<span class="name">req</span>, <span class="name">signature</span><span class="op">=</span><span class="bn bn-pseudo">True</span>) - <span class="kw">return</span> <span class="st st-sg">'</span><span class="st">settings/signature.html</span><span class="st st-sg">'</span>, { - <span class="st st-sg">'</span><span class="st">form</span><span class="st st-sg">'</span>: <span class="name">form</span>.<span class="name">generate</span>(<span class="name">prefix</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">f_</span><span class="st st-sg">'</span>), - <span class="st st-sg">'</span><span class="st">msg</span><span class="st st-sg">'</span>: <span class="name">msg</span>, - <span class="st st-sg">'</span><span class="st">editor_options</span><span class="st st-sg">'</span>: <span class="name">options</span>, - <span class="st st-sg">'</span><span class="st">editor_javascript</span><span class="st st-sg">'</span>:<span class="name">js</span> - - } - - -<span class="kw">class </span><span class="cls">UserProfileSettings</span>(<span class="name">UserSettingsPage</span>): - <span class="st st-db">"""</span><span class="st"> - This page allows the user to edit his public information. - - XXX: make this more flexible -- later (LATER!!!!) - </span><span class="st st-db">"""</span> - <span class="name">settings_page_identifier</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">profile</span><span class="st st-sg">'</span> - - <span class="kw">def </span><span class="fun">get_settings_link_title</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - - <span class="kw">return</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Profile</span><span class="st st-sg">'</span>) - - <span class="kw">def </span><span class="fun">get_settings_page</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - - <span class="name">get_setting</span> <span class="op">=</span> <span class="kw">lambda</span> <span class="name">x</span>: <span class="name">req</span>.<span class="name">user</span>.<span class="name">profile</span>.<span class="name">get</span>(<span class="name">x</span>, <span class="name">u</span><span class="st st-sg">''</span>) - <span class="name">msg</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="name">form</span> <span class="op">=</span> <span class="name">Form</span>(<span class="name">req</span>, <span class="bn bn-pseudo">self</span>, <span class="st st-sg">'</span><span class="st">POST</span><span class="st st-sg">'</span>, - <span class="cm"># general information</span> - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">new_password</span><span class="st st-sg">'</span>, - <span class="name">validator</span><span class="op">=</span><span class="name">mayEmpty</span>(<span class="name">isStrongPassword</span>()) - ), - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">new_password2</span><span class="st st-sg">'</span>, - <span class="name">validator</span><span class="op">=</span><span class="name">checkIfOtherNotBlank</span>(<span class="st st-sg">'</span><span class="st">new_password</span><span class="st st-sg">'</span>, - <span class="name">isSameValue</span>(<span class="st st-sg">'</span><span class="st">new_password</span><span class="st st-sg">'</span>, - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">The two passwords must match</span><span class="st st-sg">'</span>)) - ) - ), - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">email</span><span class="st st-sg">'</span>, - <span class="name">default</span><span class="op">=</span><span class="name">req</span>.<span class="name">user</span>.<span class="name">email</span>, - <span class="name">validator</span><span class="op">=</span><span class="name">isEmail</span>() - ), - <span class="name">CheckBox</span>(<span class="st st-sg">'</span><span class="st">show_email</span><span class="st st-sg">'</span>, - <span class="name">default</span><span class="op">=</span><span class="name">req</span>.<span class="name">user</span>.<span class="name">settings</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">show_email</span><span class="st st-sg">'</span>) <span class="op op-word">or</span> <span class="bn bn-pseudo">False</span> - - ), - <span class="cm"># instant messengers</span> - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">aol</span><span class="st st-sg">'</span>, - <span class="name">default</span><span class="op">=</span><span class="name">get_setting</span>(<span class="st st-sg">'</span><span class="st">aol</span><span class="st st-sg">'</span>), - <span class="name">validator</span><span class="op">=</span><span class="name">mayEmpty</span>() - ), <span class="cm"># need a validator</span> - - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">icq</span><span class="st st-sg">'</span>, - <span class="name">default</span><span class="op">=</span><span class="name">get_setting</span>(<span class="st st-sg">'</span><span class="st">icq</span><span class="st st-sg">'</span>), - <span class="name">validator</span><span class="op">=</span><span class="name">mayEmpty</span>(<span class="name">isIcqMessengerId</span>()) - ), <span class="cm"># need a validator</span> - - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">jabber</span><span class="st st-sg">'</span>, - <span class="name">default</span><span class="op">=</span><span class="name">get_setting</span>(<span class="st st-sg">'</span><span class="st">jabber</span><span class="st st-sg">'</span>), - <span class="name">validator</span><span class="op">=</span><span class="name">mayEmpty</span>(<span class="name">isJabberMessengerId</span>()) - ), <span class="cm"># need a validator</span> - - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">msn</span><span class="st st-sg">'</span>, - <span class="name">default</span><span class="op">=</span><span class="name">get_setting</span>(<span class="st st-sg">'</span><span class="st">msn</span><span class="st st-sg">'</span>), - <span class="name">validator</span><span class="op">=</span><span class="name">mayEmpty</span>(<span class="name">isMsnMessengerId</span>()) - ), <span class="cm"># need a validator</span> - - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">yahoo</span><span class="st st-sg">'</span>, - <span class="name">default</span><span class="op">=</span><span class="name">get_setting</span>(<span class="st st-sg">'</span><span class="st">yahoo</span><span class="st st-sg">'</span>), - <span class="name">validator</span><span class="op">=</span><span class="name">mayEmpty</span>() - ), <span class="cm"># need a validator</span> - - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">website</span><span class="st st-sg">'</span>, - <span class="name">default</span><span class="op">=</span><span class="name">get_setting</span>(<span class="st st-sg">'</span><span class="st">website</span><span class="st st-sg">'</span>), - <span class="name">validator</span><span class="op">=</span><span class="name">mayEmpty</span>(<span class="name">isExistingUrl</span>()) - ), - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">location</span><span class="st st-sg">'</span>, - <span class="name">default</span><span class="op">=</span><span class="name">get_setting</span>(<span class="st st-sg">'</span><span class="st">location</span><span class="st st-sg">'</span>), - <span class="name">validator</span><span class="op">=</span><span class="name">checkTextLength</span>(<span class="nb nb-int">0</span>, <span class="nb nb-int">255</span>), - ), - <span class="name">TextArea</span>(<span class="st st-sg">'</span><span class="st">interests</span><span class="st st-sg">'</span>, - <span class="name">default</span><span class="op">=</span><span class="name">get_setting</span>(<span class="st st-sg">'</span><span class="st">interests</span><span class="st st-sg">'</span>), - <span class="name">validator</span><span class="op">=</span><span class="name">checkTextLength</span>(<span class="nb nb-int">0</span>, <span class="nb nb-int">512</span>) - ) - ) - <span class="kw">if</span> <span class="name">req</span>.<span class="name">method</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">POST</span><span class="st st-sg">'</span>: - <span class="name">form</span>.<span class="name">update</span>(<span class="name">req</span>.<span class="name">form</span>, <span class="name">prefix</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">f_</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">form</span>.<span class="name">has_errors</span>: - <span class="name">d</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">to_dict</span>() - <span class="cm"># set special setting values</span> - - <span class="kw">if</span> <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">new_password</span><span class="st st-sg">'</span>]: - <span class="name">req</span>.<span class="name">user</span>.<span class="name">set_password</span>(<span class="name">d</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">new_password</span><span class="st st-sg">'</span>)) - <span class="kw">else</span>: - <span class="kw">del</span> <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">new_password</span><span class="st st-sg">'</span>] - <span class="kw">del</span> <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">new_password2</span><span class="st st-sg">'</span>] - <span class="name">req</span>.<span class="name">user</span>.<span class="name">email</span> <span class="op">=</span> <span class="name">d</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">email</span><span class="st st-sg">'</span>) - <span class="name">req</span>.<span class="name">user</span>.<span class="name">settings</span>.<span class="name">update</span>({<span class="st st-sg">'</span><span class="st">show_email</span><span class="st st-sg">'</span>: <span class="name">d</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">show_email</span><span class="st st-sg">'</span>)}) - <span class="cm"># update other profile fields</span> - - <span class="name">req</span>.<span class="name">user</span>.<span class="name">profile</span>.<span class="name">update</span>(<span class="name">d</span>) - <span class="name">req</span>.<span class="name">user</span>.<span class="name">save</span>() - <span class="name">msg</span> <span class="op">=</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Settings saved</span><span class="st st-sg">'</span>) - <span class="kw">return</span> <span class="st st-sg">'</span><span class="st">settings/profile.html</span><span class="st st-sg">'</span>, { - <span class="st st-sg">'</span><span class="st">form</span><span class="st st-sg">'</span>: <span class="name">form</span>.<span class="name">generate</span>(<span class="name">prefix</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">f_</span><span class="st st-sg">'</span>), - <span class="st st-sg">'</span><span class="st">msg</span><span class="st st-sg">'</span>: <span class="name">msg</span> - - } - - -<span class="kw">class </span><span class="cls">AvatarSettings</span>(<span class="name">UserSettingsPage</span>): - <span class="st st-db">"""</span><span class="st"> - This page allows the user to update his avatar - </span><span class="st st-db">"""</span> - <span class="name">settings_page_identifier</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">avatar</span><span class="st st-sg">'</span> - - <span class="kw">def </span><span class="fun">get_settings_link_title</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="kw">if</span> <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get_bool</span>(<span class="st st-sg">'</span><span class="st">board</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">allow_avatars</span><span class="st st-sg">'</span>, <span class="bn bn-pseudo">True</span>): - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - - <span class="kw">return</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Avatar</span><span class="st st-sg">'</span>) - - <span class="kw">def </span><span class="fun">get_settings_page</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">req</span>.<span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get_bool</span>(<span class="st st-sg">'</span><span class="st">board</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">allow_avatars</span><span class="st st-sg">'</span>, <span class="bn bn-pseudo">True</span>): - <span class="kw">return</span> <span class="name">PageNotFound</span>() - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - - <span class="name">msg</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="kw">def </span><span class="fun">make_small_thumbnail</span>(<span class="name">value</span>): - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">value</span>: - <span class="kw">return</span> - - <span class="name">dim</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get_int</span>(<span class="st st-sg">'</span><span class="st">board</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">avatar_dimension</span><span class="st st-sg">'</span>, <span class="nb nb-int">80</span>) - <span class="kw">return</span> <span class="name">resize_image</span>(<span class="name">value</span>, <span class="name">dim</span>, <span class="name">dim</span>, <span class="st st-sg">'</span><span class="st">image/png</span><span class="st st-sg">'</span>) - - <span class="name">form</span> <span class="op">=</span> <span class="name">Form</span>(<span class="name">req</span>, <span class="bn bn-pseudo">self</span>, <span class="st st-sg">'</span><span class="st">POST</span><span class="st st-sg">'</span>, - <span class="name">FileField</span>(<span class="st st-sg">'</span><span class="st">avatar</span><span class="st st-sg">'</span>, - <span class="name">validator</span><span class="op">=</span><span class="name">mayEmpty</span>(<span class="name">isSupportedImage</span>()), - <span class="name">manipulator</span><span class="op">=</span><span class="name">make_small_thumbnail</span> - - ), - <span class="name">CheckBox</span>(<span class="st st-sg">'</span><span class="st">delete_avatar</span><span class="st st-sg">'</span>) - ) - <span class="name">avatar</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - <span class="kw">if</span> <span class="name">req</span>.<span class="name">method</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">POST</span><span class="st st-sg">'</span>: - <span class="name">form</span>.<span class="name">update</span>(<span class="name">req</span>.<span class="name">files</span>, <span class="name">prefix</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">f_</span><span class="st st-sg">'</span>) - <span class="name">form</span>.<span class="name">update</span>(<span class="name">req</span>.<span class="name">form</span>, <span class="name">prefix</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">f_</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">form</span>.<span class="name">has_errors</span>: - <span class="name">d</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">to_dict</span>() - <span class="name">uid</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">user_id</span> - - <span class="name">fn</span> <span class="op">=</span> <span class="name">path</span>.<span class="name">join</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">root</span>, <span class="st st-sg">'</span><span class="st">avatars</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st st-int">%d</span><span class="st">.png</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">uid</span>) - <span class="kw">if</span> <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">delete_avatar</span><span class="st st-sg">'</span>]: - <span class="name">req</span>.<span class="name">user</span>.<span class="name">profile</span>[<span class="st st-sg">'</span><span class="st">avatar</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="kw">if</span> <span class="name">path</span>.<span class="name">exists</span>(<span class="name">fn</span>): - <span class="name">os</span>.<span class="name">unlink</span>(<span class="name">fn</span>) - <span class="kw">elif</span> <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">avatar</span><span class="st st-sg">'</span>]: - <span class="name">uid</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">user_id</span> - - <span class="name">f</span> <span class="op">=</span> <span class="bn">file</span>(<span class="name">fn</span>, <span class="st st-sg">'</span><span class="st">wb</span><span class="st st-sg">'</span>) - <span class="name">f</span>.<span class="name">write</span>(<span class="name">d</span>[<span class="st st-sg">'</span><span class="st">avatar</span><span class="st st-sg">'</span>]) - <span class="name">f</span>.<span class="name">close</span>() - <span class="name">req</span>.<span class="name">user</span>.<span class="name">profile</span>[<span class="st st-sg">'</span><span class="st">avatar</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">make_url</span>( - <span class="st st-sg">'</span><span class="st">users</span><span class="st st-sg">'</span>, <span class="name">urlencode</span>(<span class="name">req</span>.<span class="name">user</span>.<span class="name">username</span>), <span class="name">show</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">avatar</span><span class="st st-sg">'</span>) - <span class="name">req</span>.<span class="name">user</span>.<span class="name">save</span>() - <span class="name">msg</span> <span class="op">=</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Settings saved</span><span class="st st-sg">'</span>) - <span class="cm"># TODO: support for linked avatars and gravatars</span> - - <span class="kw">elif</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">profile</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">avatar</span><span class="st st-sg">'</span>): - <span class="name">avatar</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">make_url</span>(<span class="st st-sg">'</span><span class="st">users</span><span class="st st-sg">'</span>, <span class="name">urlencode</span>(<span class="name">req</span>.<span class="name">user</span>.<span class="name">username</span>), - <span class="name">show</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">avatar</span><span class="st st-sg">'</span>) - <span class="kw">return</span> <span class="st st-sg">'</span><span class="st">settings/avatar.html</span><span class="st st-sg">'</span>, { - <span class="st st-sg">'</span><span class="st">form</span><span class="st st-sg">'</span>: <span class="name">form</span>.<span class="name">generate</span>(<span class="name">prefix</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">f_</span><span class="st st-sg">'</span>), - <span class="st st-sg">'</span><span class="st">avatar</span><span class="st st-sg">'</span>: <span class="name">avatar</span>, - <span class="st st-sg">'</span><span class="st">msg</span><span class="st st-sg">'</span>: <span class="name">msg</span> - - } - - -<span class="kw">class </span><span class="cls">UserForumSettings</span>(<span class="name">UserSettingsPage</span>): - <span class="st st-db">"""</span><span class="st"> - This page allows the user to update his forum view settings - (ie. view mode and posts and threads per page) - </span><span class="st st-db">"""</span> - - <span class="name">settings_page_identifier</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">forum</span><span class="st st-sg">'</span> - - <span class="kw">def </span><span class="fun">get_settings_link_title</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - - <span class="kw">return</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Forum Settings</span><span class="st st-sg">'</span>) - - <span class="kw">def </span><span class="fun">get_settings_page</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>): - <span class="kw">def </span><span class="fun">int_or_none</span>(<span class="name">x</span>): - <span class="st st-db">"</span><span class="st">manipulator which returns an int or None</span><span class="st st-db">"</span> - - <span class="kw">try</span>: - <span class="kw">return</span> <span class="bn">int</span>(<span class="name">x</span>) - <span class="kw">except</span> <span class="exc">ValueError</span>: - <span class="kw">return</span> <span class="bn bn-pseudo">None</span> - - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - <span class="name">msg</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="name">form</span> <span class="op">=</span> <span class="name">Form</span>(<span class="name">req</span>, <span class="bn bn-pseudo">self</span>, <span class="st st-sg">'</span><span class="st">POST</span><span class="st st-sg">'</span>, - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">posts_per_page</span><span class="st st-sg">'</span>, - <span class="name">default</span><span class="op">=</span><span class="name">req</span>.<span class="name">user</span>.<span class="name">settings</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">posts_per_page</span><span class="st st-sg">'</span>) <span class="op op-word">or</span> <span class="name">u</span><span class="st st-sg">''</span>, - <span class="name">validator</span><span class="op">=</span><span class="name">mayEmpty</span>(<span class="name">doMultiCheck</span>(<span class="name">isInteger</span>(), <span class="name">isInRange</span>(<span class="nb nb-int">5</span>, <span class="nb nb-int">50</span>))), - <span class="name">manipulator</span><span class="op">=</span><span class="name">int_or_none</span> - - ), - <span class="name">TextField</span>(<span class="st st-sg">'</span><span class="st">threads_per_page</span><span class="st st-sg">'</span>, - <span class="name">default</span><span class="op">=</span><span class="name">req</span>.<span class="name">user</span>.<span class="name">settings</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">threads_per_page</span><span class="st st-sg">'</span>) <span class="op op-word">or</span> <span class="name">u</span><span class="st st-sg">''</span>, - <span class="name">validator</span><span class="op">=</span><span class="name">mayEmpty</span>(<span class="name">doMultiCheck</span>(<span class="name">isInteger</span>(), <span class="name">isInRange</span>(<span class="nb nb-int">10</span>, <span class="nb nb-int">80</span>))), - <span class="name">manipulator</span><span class="op">=</span><span class="name">int_or_none</span> - - ), - <span class="name">SelectBox</span>(<span class="st st-sg">'</span><span class="st">view_mode</span><span class="st st-sg">'</span>, [ - (<span class="st st-sg">''</span>, <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">default</span><span class="st st-sg">'</span>)), - (<span class="st st-sg">'</span><span class="st">threaded</span><span class="st st-sg">'</span>, <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">threaded</span><span class="st st-sg">'</span>)), - (<span class="st st-sg">'</span><span class="st">flat</span><span class="st st-sg">'</span>, <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">flat</span><span class="st st-sg">'</span>)) - ], <span class="name">default</span><span class="op">=</span><span class="name">req</span>.<span class="name">user</span>.<span class="name">settings</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">view_mode</span><span class="st st-sg">'</span>) <span class="op op-word">or</span> <span class="name">u</span><span class="st st-sg">''</span> - - ) - ) - - <span class="kw">if</span> <span class="name">req</span>.<span class="name">method</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">POST</span><span class="st st-sg">'</span>: - <span class="name">form</span>.<span class="name">update</span>(<span class="name">req</span>.<span class="name">form</span>, <span class="name">prefix</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">f_</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">form</span>.<span class="name">has_errors</span>: - <span class="name">d</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">to_dict</span>() - <span class="name">req</span>.<span class="name">user</span>.<span class="name">settings</span>.<span class="name">update</span>(<span class="name">d</span>) - <span class="name">req</span>.<span class="name">user</span>.<span class="name">save</span>() - <span class="name">msg</span> <span class="op">=</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Forum settings saved</span><span class="st st-sg">'</span>) - - <span class="kw">return</span> <span class="st st-sg">'</span><span class="st">settings/forumsettings.html</span><span class="st st-sg">'</span>, { - <span class="st st-sg">'</span><span class="st">form</span><span class="st st-sg">'</span>: <span class="name">form</span>.<span class="name">generate</span>(<span class="name">prefix</span><span class="op">=</span><span class="st st-sg">'</span><span class="st">f_</span><span class="st st-sg">'</span>), - <span class="st st-sg">'</span><span class="st">msg</span><span class="st st-sg">'</span>: <span class="name">msg</span> - - } -<span class="cm"># -*- coding: utf-8 -*-</span> -<span class="st st-db">"""</span><span class="st"> - pocoo.pkg.core.validators - ~~~~~~~~~~~~~~~~~~~~~~~~~ - - Special validation, in addition to `pocoo.utils.validators`. - - For a general explanation of the validators system, please - see `pocoo.utils.form`. - - - :copyright: 2006 by Armin Ronacher. - :license: GNU GPL, see LICENSE for more details. -</span><span class="st st-db">"""</span> -<span class="kw">import </span><span class="cls">re</span> -<span class="kw">import </span><span class="cls">unicodedata</span> -<span class="kw">from </span><span class="cls">pocoo.utils.validators</span><span class="kw"> import</span> <span class="name">ValidationError</span>, <span class="name">_mail_re</span> - -<span class="kw">from </span><span class="cls">pocoo.pkg.core.user</span><span class="kw"> import</span> <span class="name">User</span>, <span class="name">get_id_by_name</span> - -<span class="name">_icq_re</span> <span class="op">=</span> <span class="name">re</span>.<span class="name">compile</span>(<span class="st st-sg">r'</span><span class="st">^\d{6,9}$</span><span class="st st-sg">'</span>) - - - -<span class="cm"># pylint: disable-msg=C0103</span> - -<span class="kw">def </span><span class="fun">isValidUsername</span>(): - <span class="st st-db">"""</span><span class="st">Checks if the given string looks like a valid username.</span><span class="st st-db">"""</span> - <span class="kw">def </span><span class="fun">is_valid_username</span>(<span class="name">field</span>, <span class="name">form</span>): - <span class="name">errors</span> <span class="op">=</span> [] - <span class="name">_</span> <span class="op">=</span> <span class="kw">lambda</span> <span class="name">s</span>: <span class="name">errors</span>.<span class="name">append</span>(<span class="name">form</span>.<span class="name">req</span>.<span class="name">gettext</span>(<span class="name">s</span>)) - <span class="name">value</span> <span class="op">=</span> <span class="name">field</span>.<span class="name">value</span>.<span class="name">strip</span>() - <span class="kw">if</span> <span class="bn">len</span>(<span class="name">value</span>) <span class="op"><</span> <span class="nb nb-int">2</span>: - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Please enter a username that is at least 2 characters long.</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="bn">len</span>(<span class="name">value</span>) <span class="op">></span> <span class="nb nb-int">30</span>: - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Please enter a username that is no longer than 30 characters.</span><span class="st st-sg">'</span>) - <span class="kw">for</span> <span class="name">char</span> <span class="op op-word">in</span> <span class="name">value</span>: - <span class="kw">if</span> <span class="name">char</span> <span class="op op-word">in</span> <span class="st st-sg">'</span><span class="st">_-. </span><span class="st st-sg">'</span>: - <span class="kw">continue</span> - - <span class="kw">if</span> <span class="name">unicodedata</span>.<span class="name">category</span>(<span class="name">char</span>)[<span class="nb nb-int">0</span>] <span class="op op-word">not</span> <span class="op op-word">in</span> <span class="st st-sg">'</span><span class="st">LN</span><span class="st st-sg">'</span>: - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Please enter a username without special characters </span><span class="st st-sg">'</span> - - <span class="st st-sg">'</span><span class="st">except "_", "-", ".".</span><span class="st st-sg">'</span>) - <span class="kw">break</span> - <span class="kw">if</span> <span class="name">errors</span>: - <span class="kw">raise</span> <span class="name">ValidationError</span>(<span class="op">*</span><span class="name">errors</span>) - <span class="kw">return</span> <span class="name">is_valid_username</span> - - -<span class="kw">def </span><span class="fun">isAvailableUsername</span>(): - <span class="st st-db">"""</span><span class="st">Checks if the username is valid and available.</span><span class="st st-db">"""</span> - <span class="kw">def </span><span class="fun">is_available_username</span>(<span class="name">field</span>, <span class="name">form</span>): - <span class="name">isValidUsername</span>()(<span class="name">field</span>, <span class="name">form</span>) - <span class="kw">try</span>: - <span class="name">get_id_by_name</span>(<span class="name">form</span>.<span class="name">req</span>.<span class="name">ctx</span>, <span class="name">field</span>.<span class="name">value</span>) - <span class="kw">except</span> <span class="name">User</span>.<span class="name">NotFound</span>: - <span class="kw">return</span> - - <span class="name">_</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">req</span>.<span class="name">gettext</span> - <span class="kw">raise</span> <span class="name">ValidationError</span>(<span class="name">_</span>(<span class="st st-sg">'</span><span class="st">The username is already in use.</span><span class="st st-sg">'</span>)) - <span class="kw">return</span> <span class="name">is_available_username</span> - - -<span class="kw">def </span><span class="fun">isAnonymousUsername</span>(): - <span class="st st-db">"""</span><span class="st">Checks if this is a valid username for anonymous usage.</span><span class="st st-db">"""</span> - <span class="kw">def </span><span class="fun">is_anonymous_username</span>(<span class="name">field</span>, <span class="name">form</span>): - <span class="kw">if</span> <span class="name">field</span>.<span class="name">value</span> <span class="op">!=</span> <span class="st st-sg">'</span><span class="st">anonymous</span><span class="st st-sg">'</span>: - <span class="name">isAvailableUsername</span>()(<span class="name">field</span>, <span class="name">form</span>) - <span class="kw">return</span> <span class="name">is_anonymous_username</span> - - -<span class="kw">def </span><span class="fun">isExistingUsername</span>(): - <span class="st st-db">"""</span><span class="st">Checks if the username does exist.</span><span class="st st-db">"""</span> - <span class="kw">def </span><span class="fun">is_existing_username</span>(<span class="name">field</span>, <span class="name">form</span>): - <span class="kw">try</span>: - <span class="name">get_id_by_name</span>(<span class="name">form</span>.<span class="name">req</span>.<span class="name">ctx</span>, <span class="name">field</span>.<span class="name">value</span>) - <span class="kw">return</span> - - <span class="kw">except</span> <span class="name">User</span>.<span class="name">NotFound</span>: - <span class="name">_</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">req</span>.<span class="name">gettext</span> - - <span class="kw">raise</span> <span class="name">ValidationError</span>(<span class="name">_</span>(<span class="st st-sg">'</span><span class="st">The user </span><span class="st st-int">%s</span><span class="st"> does not exist.</span><span class="st st-sg">'</span>) <span class="op">%</span> <span class="name">field</span>.<span class="name">value</span>) - <span class="kw">return</span> <span class="name">is_existing_username</span> - - -<span class="kw">def </span><span class="fun">isStrongPassword</span>(<span class="name">strength</span><span class="op">=</span><span class="bn bn-pseudo">None</span>): - <span class="st st-db">"""</span><span class="st">Checks if the password is strong enough</span><span class="st st-db">"""</span> - <span class="kw">def </span><span class="fun">is_strong_password</span>(<span class="name">field</span>, <span class="name">form</span>): - <span class="name">errors</span> <span class="op">=</span> [] - <span class="name">_</span> <span class="op">=</span> <span class="kw">lambda</span> <span class="name">s</span>: <span class="name">errors</span>.<span class="name">append</span>(<span class="name">form</span>.<span class="name">req</span>.<span class="name">gettext</span>(<span class="name">s</span>)) - <span class="kw">if</span> <span class="name">strength</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="name">s</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">req</span>.<span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get_int</span>(<span class="st st-sg">'</span><span class="st">security</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">password_strength</span><span class="st st-sg">'</span>, <span class="nb nb-int">3</span>) - <span class="kw">else</span>: - <span class="name">s</span> <span class="op">=</span> <span class="name">strength</span> - - <span class="name">s</span> <span class="op">=</span> <span class="bn">max</span>(<span class="nb nb-int">0</span>, <span class="bn">min</span>(<span class="nb nb-int">4</span>, <span class="name">s</span>)) - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">s</span> <span class="op op-word">and</span> <span class="op op-word">not</span> <span class="name">field</span>.<span class="name">value</span>: - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Please fill out the password field.</span><span class="st st-sg">'</span>) - <span class="kw">elif</span> <span class="name">s</span> <span class="op">==</span> <span class="nb nb-int">1</span>: - <span class="kw">if</span> <span class="bn">len</span>(<span class="name">field</span>.<span class="name">value</span>) <span class="op"><</span> <span class="nb nb-int">4</span>: - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Please enter a password with at least 4 characters.</span><span class="st st-sg">'</span>) - <span class="kw">elif</span> <span class="name">s</span> <span class="op">==</span> <span class="nb nb-int">2</span>: - <span class="kw">if</span> <span class="bn">len</span>(<span class="name">field</span>.<span class="name">value</span>) <span class="op"><</span> <span class="nb nb-int">6</span>: - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Please enter a password with at least 6 characters.</span><span class="st st-sg">'</span>) - <span class="kw">elif</span> <span class="name">s</span> <span class="op">==</span> <span class="nb nb-int">3</span>: - <span class="kw">def </span><span class="fun">test</span>(): - <span class="name">have_letter</span> <span class="op">=</span> <span class="name">have_number</span> <span class="op">=</span> <span class="bn bn-pseudo">False</span> - - <span class="kw">for</span> <span class="name">char</span> <span class="op op-word">in</span> <span class="name">field</span>.<span class="name">value</span>: - <span class="name">c</span> <span class="op">=</span> <span class="name">unicodedata</span>.<span class="name">category</span>(<span class="name">char</span>)[<span class="nb nb-int">0</span>] - <span class="kw">if</span> <span class="name">c</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">L</span><span class="st st-sg">'</span>: - <span class="name">have_letter</span> <span class="op">=</span> <span class="bn bn-pseudo">True</span> - - <span class="kw">elif</span> <span class="name">c</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">N</span><span class="st st-sg">'</span>: - <span class="name">have_number</span> <span class="op">=</span> <span class="bn bn-pseudo">True</span> - <span class="kw">if</span> <span class="name">have_letter</span> <span class="op op-word">and</span> <span class="name">have_number</span>: - <span class="kw">return</span> <span class="bn bn-pseudo">True</span> - - <span class="kw">return</span> <span class="bn bn-pseudo">False</span> - <span class="kw">if</span> <span class="bn">len</span>(<span class="name">field</span>.<span class="name">value</span>) <span class="op"><</span> <span class="nb nb-int">6</span> <span class="op op-word">or</span> <span class="op op-word">not</span> <span class="name">test</span>(): - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Please enter a password with at least 6 characters which </span><span class="st st-sg">'</span> - - <span class="st st-sg">'</span><span class="st">contains both letters and numbers.</span><span class="st st-sg">'</span>) - <span class="kw">elif</span> <span class="name">s</span> <span class="op">==</span> <span class="nb nb-int">4</span>: - <span class="kw">def </span><span class="fun">test</span>(): - <span class="name">have_letter</span> <span class="op">=</span> <span class="name">have_number</span>, <span class="name">have_special</span> <span class="op">=</span> <span class="bn bn-pseudo">False</span> - - <span class="kw">for</span> <span class="name">char</span> <span class="op op-word">in</span> <span class="name">field</span>.<span class="name">value</span>: - <span class="name">c</span> <span class="op">=</span> <span class="name">unicodedata</span>.<span class="name">category</span>(<span class="name">char</span>)[<span class="nb nb-int">0</span>] - <span class="kw">if</span> <span class="name">c</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">L</span><span class="st st-sg">'</span>: - <span class="name">have_letter</span> <span class="op">=</span> <span class="bn bn-pseudo">True</span> - - <span class="kw">elif</span> <span class="name">c</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">N</span><span class="st st-sg">'</span>: - <span class="name">have_number</span> <span class="op">=</span> <span class="bn bn-pseudo">True</span> - <span class="kw">elif</span> <span class="name">c</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">S</span><span class="st st-sg">'</span>: - <span class="name">have_special</span> <span class="op">=</span> <span class="bn bn-pseudo">True</span> - - <span class="kw">if</span> <span class="name">have_letter</span> <span class="op op-word">and</span> <span class="name">have_number</span> <span class="op op-word">and</span> <span class="name">have_special</span>: - <span class="kw">return</span> <span class="bn bn-pseudo">True</span> - - <span class="kw">return</span> <span class="bn bn-pseudo">False</span> - <span class="kw">if</span> <span class="bn">len</span>(<span class="name">field</span>.<span class="name">value</span>) <span class="op"><</span> <span class="nb nb-int">6</span> <span class="op op-word">or</span> <span class="op op-word">not</span> <span class="name">test</span>(): - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Please enter a password with at least 6 characters with </span><span class="st st-sg">'</span> - - <span class="st st-sg">'</span><span class="st">contains of letters, numbers and at least one special </span><span class="st st-sg">'</span> - <span class="st st-sg">'</span><span class="st">character.</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="name">errors</span>: - <span class="kw">raise</span> <span class="name">ValidationError</span>(<span class="op">*</span><span class="name">errors</span>) - <span class="kw">return</span> <span class="name">is_strong_password</span> - - - -<span class="kw">def </span><span class="fun">isValidSignature</span>(): - <span class="st st-db">"""</span><span class="st">Checks if the signature is valid.</span><span class="st st-db">"""</span> - <span class="kw">def </span><span class="fun">is_valid_signature</span>(<span class="name">field</span>, <span class="name">form</span>): - <span class="name">errors</span> <span class="op">=</span> [] - <span class="name">_</span> <span class="op">=</span> <span class="kw">lambda</span> <span class="name">s</span>: <span class="name">errors</span>.<span class="name">append</span>(<span class="name">form</span>.<span class="name">req</span>.<span class="name">gettext</span>(<span class="name">s</span>)) - <span class="name">val</span> <span class="op">=</span> <span class="name">field</span>.<span class="name">value</span>.<span class="name">strip</span>() - <span class="name">max_len</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">req</span>.<span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get_int</span>(<span class="st st-sg">'</span><span class="st">board</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">signature_length</span><span class="st st-sg">'</span>) - <span class="name">max_lines</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">req</span>.<span class="name">ctx</span>.<span class="name">cfg</span>.<span class="name">get_int</span>(<span class="st st-sg">'</span><span class="st">board</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">signature_lines</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="bn">len</span>(<span class="name">val</span>) <span class="op">></span> <span class="name">max_len</span>: - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Your signature must not be longer than </span><span class="st st-int">%d</span><span class="st"> characters.</span><span class="st st-sg">'</span>) <span class="op">%</span> <span class="name">max_len</span> - - <span class="kw">if</span> <span class="bn">len</span>(<span class="name">val</span>.<span class="name">splitlines</span>()) <span class="op">></span> <span class="name">max_lines</span>: - <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Your signature must not be longer than </span><span class="st st-int">%d</span><span class="st"> lines.</span><span class="st st-sg">'</span>) <span class="op">%</span> <span class="name">max_lines</span> - - <span class="kw">if</span> <span class="name">errors</span>: - <span class="kw">raise</span> <span class="name">ValidationError</span>(<span class="op">*</span><span class="name">errors</span>) - <span class="kw">return</span> <span class="name">is_valid_signature</span> - -<span class="kw">def </span><span class="fun">isIcqMessengerId</span>(): - <span class="st st-db">"""</span><span class="st">Checks if the value is a valid ICQ ID</span><span class="st st-db">"""</span> - <span class="kw">def </span><span class="fun">is_icq_messenger_id</span>(<span class="name">field</span>, <span class="name">form</span>): - <span class="kw">if</span> <span class="name">_icq_re</span>.<span class="name">search</span>(<span class="name">field</span>.<span class="name">value</span>) <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="name">_</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">req</span>.<span class="name">gettext</span> - - <span class="kw">raise</span> <span class="name">ValidationError</span>(<span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Please enter a valid ICQ ID</span><span class="st st-sg">'</span>)) - <span class="kw">return</span> <span class="name">is_icq_messenger_id</span> - - -<span class="kw">def </span><span class="fun">isJabberMessengerId</span>(): - <span class="st st-db">"""</span><span class="st">Checks if the value is a valid jabber ID</span><span class="st st-db">"""</span> - - <span class="kw">def </span><span class="fun">is_jabber_messenger_id</span>(<span class="name">field</span>, <span class="name">form</span>): - <span class="kw">if</span> <span class="name">_mail_re</span>.<span class="name">search</span>(<span class="name">field</span>.<span class="name">value</span>) <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="name">_</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">req</span>.<span class="name">gettext</span> - - <span class="kw">raise</span> <span class="name">ValidationError</span>(<span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Please enter a valid jabber ID</span><span class="st st-sg">'</span>)) - <span class="kw">return</span> <span class="name">is_jabber_messenger_id</span> - - -<span class="kw">def </span><span class="fun">isMsnMessengerId</span>(): - <span class="st st-db">"""</span><span class="st">Checks if the value is a valid MSN ID</span><span class="st st-db">"""</span> - - <span class="kw">def </span><span class="fun">is_msn_messenger_id</span>(<span class="name">field</span>, <span class="name">form</span>): - <span class="kw">if</span> <span class="name">_mail_re</span>.<span class="name">search</span>(<span class="name">field</span>.<span class="name">value</span>) <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="name">_</span> <span class="op">=</span> <span class="name">form</span>.<span class="name">req</span>.<span class="name">gettext</span> - - <span class="kw">raise</span> <span class="name">ValidationError</span>(<span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Please enter a valid MSN ID.</span><span class="st st-sg">'</span>)) - <span class="kw">return</span> <span class="name">is_msn_messenger_id</span> - - -<span class="cm"># TODO: I don't know how valid AIM and Y!M IDs look, so I can't write validators</span> - -<span class="cm"># for them. It looks like they are simple strings, but I'm not sure...</span> </pre> <script type="text/javascript">initCodeBlock('code-block')</script> </body> diff --git a/tests/test_basic_api.py b/tests/test_basic_api.py index a4e55366..c929fde8 100644 --- a/tests/test_basic_api.py +++ b/tests/test_basic_api.py @@ -7,6 +7,82 @@ :license: GNU GPL, see LICENSE for more details. """ -from pygments import highlight +import unittest +import StringIO +import random -# ... TODO ... +from pygments import lexers, formatters +from pygments.token import _TokenType + +test_content = [chr(i) for i in xrange(33, 128)] * 5 +random.shuffle(test_content) +test_content = ''.join(test_content) + '\n' + +class LexersTest(unittest.TestCase): + + def test_lexer_classes(self): + a = self.assert_ + ae = self.assertEquals + # test that every lexer class has the correct public API + for lexer in lexers._iter_lexerclasses(): + for attr in 'name', 'aliases', 'filenames', 'alias_filenames', 'mimetypes': + a(hasattr(lexer, attr)) + result = lexer.analyse_text("abc") + a(isinstance(result, float) and 0.0 <= result <= 1.0) + + inst = lexer(opt1="val1", opt2="val2") + tokens = list(inst.get_tokens(test_content)) + txt = "" + for token in tokens: + a(isinstance(token, tuple)) + a(isinstance(token[0], _TokenType)) + a(isinstance(token[1], str)) + txt += token[1] + ae(txt, test_content, "%s lexer roundtrip failed: %r != %r" % + (lexer.name, test_content, txt)) + + def test_get_lexers(self): + a = self.assert_ + ae = self.assertEquals + # test that the lexers functions work + + for func, args in [(lexers.get_lexer_by_name, ("python",)), + (lexers.get_lexer_for_filename, ("test.py",)), + (lexers.get_lexer_for_mimetype, ("text/x-python",)), + (lexers.guess_lexer, ("#!/usr/bin/python -O\nprint",)), + (lexers.guess_lexer_for_filename, ("a.py", "<%= @foo %>")) + ]: + x = func(opt="val", *args) + a(isinstance(x, lexers.PythonLexer)) + ae(x.options["opt"], "val") + + +class FormattersTest(unittest.TestCase): + + def test_public_api(self): + a = self.assert_ + ae = self.assertEquals + ts = list(lexers.PythonLexer().get_tokens("def f(): pass")) + out = StringIO.StringIO() + # test that every formatter class has the correct public API + for formatter, info in formatters.FORMATTERS.iteritems(): + a(len(info) == 4) + a(info[0]) # name + a(info[1]) # aliases + a(info[3]) # doc + + inst = formatter(opt1="val1") + inst.get_style_defs() + inst.format(ts, out) + + def test_get_formatters(self): + a = self.assert_ + ae = self.assertEquals + # test that the formatters functions work + x = formatters.get_formatter_by_name("html", opt="val") + a(isinstance(x, formatters.HtmlFormatter)) + ae(x.options["opt"], "val") + + x = formatters.get_formatter_for_filename("a.html", opt="val") + a(isinstance(x, formatters.HtmlFormatter)) + ae(x.options["opt"], "val") diff --git a/tests/test_clexer.py b/tests/test_clexer.py index 145c6510..ce757890 100644 --- a/tests/test_clexer.py +++ b/tests/test_clexer.py @@ -32,4 +32,4 @@ class CLexerTest(unittest.TestCase): if __name__ == '__main__': - unittest.main(CLexerTest) + unittest.main() |