diff options
-rw-r--r-- | pygments/cmdline.py | 21 | ||||
-rw-r--r-- | pygments/filter.py | 9 | ||||
-rw-r--r-- | pygments/filters/__init__.py | 14 | ||||
-rw-r--r-- | pygments/formatters/__init__.py | 5 | ||||
-rw-r--r-- | pygments/formatters/latex.py | 2 | ||||
-rw-r--r-- | pygments/lexer.py | 12 | ||||
-rw-r--r-- | tests/examplefiles/ceval.c | 1745 | ||||
-rw-r--r-- | tests/examplefiles/example.c | 5334 | ||||
-rw-r--r-- | tests/examplefiles/example.cpp | 3881 | ||||
-rw-r--r-- | tests/examplefiles/example.rb | 5704 | ||||
-rw-r--r-- | tests/examplefiles/ltmain.sh | 4122 | ||||
-rw-r--r-- | tests/examplefiles/perlfunc.1 | 4503 | ||||
-rw-r--r-- | tests/examplefiles/pleac.in.rb | 1736 | ||||
-rw-r--r-- | tests/examplefiles/test.html | 1668 | ||||
-rw-r--r-- | tests/test_examplefiles.py | 2 | ||||
-rw-r--r-- | tests/test_latex_formatter.py | 50 |
16 files changed, 86 insertions, 28722 deletions
diff --git a/pygments/cmdline.py b/pygments/cmdline.py index 53f47206..3e98af39 100644 --- a/pygments/cmdline.py +++ b/pygments/cmdline.py @@ -17,7 +17,8 @@ from pygments.util import ClassNotFound, OptionError, docstring_headline from pygments.lexers import get_all_lexers, get_lexer_by_name, get_lexer_for_filename, \ find_lexer_class from pygments.formatters import get_all_formatters, get_formatter_by_name, \ - get_formatter_for_filename, TerminalFormatter, find_formatter_class + get_formatter_for_filename, find_formatter_class, \ + TerminalFormatter # pylint:disable-msg=E0611 from pygments.filters import get_all_filters, find_filter_class from pygments.styles import get_all_styles, get_style_by_name @@ -102,22 +103,22 @@ def _parse_filters(f_strs): return filters -def _print_help(type, name): +def _print_help(what, name): try: - if type == 'lexer': + if what == 'lexer': cls = find_lexer_class(name) print "Help on the %s lexer:" % cls.name print dedent(cls.__doc__) - elif type == 'formatter': + elif what == 'formatter': cls = find_formatter_class(name) print "Help on the %s formatter:" % cls.name print dedent(cls.__doc__) - elif type == 'filter': + elif what == 'filter': cls = find_filter_class(name) print "Help on the %s filter:" % name print dedent(cls.__doc__) except ClassNotFound: - print >>sys.stderr, "%s not found!" % type + print >>sys.stderr, "%s not found!" % what def _print_list(what): @@ -175,6 +176,8 @@ def main(args): """ Main command line entry point. """ + # pylint: disable-msg=R0911,R0912,R0915 + usage = USAGE % ((args[0],) * 5) try: @@ -226,12 +229,12 @@ def main(args): print >>sys.stderr, usage return 2 - type, name = args - if type not in ('lexer', 'formatter', 'filter'): + what, name = args + if what not in ('lexer', 'formatter', 'filter'): print >>sys.stderr, usage return 2 - _print_help(type, name) + _print_help(what, name) return 0 # parse -O options diff --git a/pygments/filter.py b/pygments/filter.py index f304953c..2da319d1 100644 --- a/pygments/filter.py +++ b/pygments/filter.py @@ -16,11 +16,11 @@ def apply_filters(stream, filters, lexer=None): a stream. If lexer is given it's forwarded to the filter, otherwise the filter receives `None`. """ - def _apply(filter, stream): - for token in filter.filter(lexer, stream): + def _apply(filter_, stream): + for token in filter_.filter(lexer, stream): yield token - for filter in filters: - stream = _apply(filter, stream) + for filter_ in filters: + stream = _apply(filter_, stream) return stream @@ -69,5 +69,6 @@ class FunctionFilter(Filter): Filter.__init__(self, **options) def filter(self, lexer, stream): + # pylint: disable-msg=E1102 for ttype, value in self.function(lexer, stream, self.options): yield ttype, value diff --git a/pygments/filters/__init__.py b/pygments/filters/__init__.py index 524e3bbb..ccb78652 100644 --- a/pygments/filters/__init__.py +++ b/pygments/filters/__init__.py @@ -21,28 +21,28 @@ from pygments.util import get_list_opt, ClassNotFound from pygments.plugin import find_plugin_filters -def find_filter_class(filter): +def find_filter_class(filtername): """ Lookup a filter by name. Return None if not found. """ - if filter in FILTERS: - return FILTERS[filter] + if filtername in FILTERS: + return FILTERS[filtername] for name, cls in find_plugin_filters(): - if name == filter: + if name == filtername: return cls return None -def get_filter_by_name(filter, **options): +def get_filter_by_name(filtername, **options): """ Return an instantiated filter. Options are passed to the filter initializer if wanted. Raise a ClassNotFound if not found. """ - cls = find_filter_class(filter) + cls = find_filter_class(filtername) if cls: return cls(**options) else: - raise ClassNotFound('filter %r not found' % filter) + raise ClassNotFound('filter %r not found' % filtername) def get_all_filters(): diff --git a/pygments/formatters/__init__.py b/pygments/formatters/__init__.py index 397f5027..8d0feaaa 100644 --- a/pygments/formatters/__init__.py +++ b/pygments/formatters/__init__.py @@ -16,8 +16,9 @@ from pygments.plugin import find_plugin_formatters from pygments.util import docstring_headline, ClassNotFound ns = globals() -for cls in FORMATTERS: - ns[cls.__name__] = cls +for fcls in FORMATTERS: + ns[fcls.__name__] = fcls +del fcls __all__ = ['get_formatter_by_name', 'get_formatter_for_filename', 'get_all_formatters'] + [cls.__name__ for cls in FORMATTERS] diff --git a/pygments/formatters/latex.py b/pygments/formatters/latex.py index a1e35c75..bc40cf1b 100644 --- a/pygments/formatters/latex.py +++ b/pygments/formatters/latex.py @@ -216,6 +216,6 @@ class LatexFormatter(Formatter): dict(docclass = self.docclass, preamble = self.preamble, title = self.title, - encoding = self.encoding, + encoding = self.encoding or 'latin1', styledefs = self.get_style_defs(), code = outfile.getvalue())) diff --git a/pygments/lexer.py b/pygments/lexer.py index 6cec28f8..25d36e08 100644 --- a/pygments/lexer.py +++ b/pygments/lexer.py @@ -86,8 +86,8 @@ class Lexer(object): self.encoding = options.get('encoding', 'latin1') # self.encoding = options.get('inencoding', None) or self.encoding self.filters = [] - for filter in get_list_opt(options, 'filters', ()): - self.add_filter(filter) + for filter_ in get_list_opt(options, 'filters', ()): + self.add_filter(filter_) def __repr__(self): if self.options: @@ -96,13 +96,13 @@ class Lexer(object): else: return '<pygments.lexers.%s>' % self.__class__.__name__ - def add_filter(self, filter, **options): + def add_filter(self, filter_, **options): """ Add a new stream filter to this lexer. """ - if not isinstance(filter, Filter): - filter = get_filter_by_name(filter, **options) - self.filters.append(filter) + if not isinstance(filter_, Filter): + filter = get_filter_by_name(filter_, **options) + self.filters.append(filter_) def analyse_text(text): """ diff --git a/tests/examplefiles/ceval.c b/tests/examplefiles/ceval.c index 99e87e81..c6739630 100644 --- a/tests/examplefiles/ceval.c +++ b/tests/examplefiles/ceval.c @@ -2602,1748 +2602,3 @@ fast_yield: return retval; } -/* This is gonna seem *real weird*, but if you put some other code between - PyEval_EvalFrame() and PyEval_EvalCodeEx() you will need to adjust - the test in the if statements in Misc/gdbinit (pystack and pystackv). */ - -PyObject * -PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, - PyObject **args, int argcount, PyObject **kws, int kwcount, - PyObject **defs, int defcount, PyObject *closure) -{ - register PyFrameObject *f; - register PyObject *retval = NULL; - register PyObject **fastlocals, **freevars; - PyThreadState *tstate = PyThreadState_GET(); - PyObject *x, *u; - - if (globals == NULL) { - PyErr_SetString(PyExc_SystemError, - "PyEval_EvalCodeEx: NULL globals"); - return NULL; - } - - assert(tstate != NULL); - assert(globals != NULL); - f = PyFrame_New(tstate, co, globals, locals); - if (f == NULL) - return NULL; - - fastlocals = f->f_localsplus; - freevars = f->f_localsplus + co->co_nlocals; - - if (co->co_argcount > 0 || - co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) { - int i; - int n = argcount; - PyObject *kwdict = NULL; - if (co->co_flags & CO_VARKEYWORDS) { - kwdict = PyDict_New(); - if (kwdict == NULL) - goto fail; - i = co->co_argcount; - if (co->co_flags & CO_VARARGS) - i++; - SETLOCAL(i, kwdict); - } - if (argcount > co->co_argcount) { - if (!(co->co_flags & CO_VARARGS)) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes %s %d " - "%sargument%s (%d given)", - PyString_AsString(co->co_name), - defcount ? "at most" : "exactly", - co->co_argcount, - kwcount ? "non-keyword " : "", - co->co_argcount == 1 ? "" : "s", - argcount); - goto fail; - } - n = co->co_argcount; - } - for (i = 0; i < n; i++) { - x = args[i]; - Py_INCREF(x); - SETLOCAL(i, x); - } - if (co->co_flags & CO_VARARGS) { - u = PyTuple_New(argcount - n); - if (u == NULL) - goto fail; - SETLOCAL(co->co_argcount, u); - for (i = n; i < argcount; i++) { - x = args[i]; - Py_INCREF(x); - PyTuple_SET_ITEM(u, i-n, x); - } - } - for (i = 0; i < kwcount; i++) { - PyObject *keyword = kws[2*i]; - PyObject *value = kws[2*i + 1]; - int j; - if (keyword == NULL || !PyString_Check(keyword)) { - PyErr_Format(PyExc_TypeError, - "%.200s() keywords must be strings", - PyString_AsString(co->co_name)); - goto fail; - } - /* XXX slow -- speed up using dictionary? */ - for (j = 0; j < co->co_argcount; j++) { - PyObject *nm = PyTuple_GET_ITEM( - co->co_varnames, j); - int cmp = PyObject_RichCompareBool( - keyword, nm, Py_EQ); - if (cmp > 0) - break; - else if (cmp < 0) - goto fail; - } - /* Check errors from Compare */ - if (PyErr_Occurred()) - goto fail; - if (j >= co->co_argcount) { - if (kwdict == NULL) { - PyErr_Format(PyExc_TypeError, - "%.200s() got an unexpected " - "keyword argument '%.400s'", - PyString_AsString(co->co_name), - PyString_AsString(keyword)); - goto fail; - } - PyDict_SetItem(kwdict, keyword, value); - } - else { - if (GETLOCAL(j) != NULL) { - PyErr_Format(PyExc_TypeError, - "%.200s() got multiple " - "values for keyword " - "argument '%.400s'", - PyString_AsString(co->co_name), - PyString_AsString(keyword)); - goto fail; - } - Py_INCREF(value); - SETLOCAL(j, value); - } - } - if (argcount < co->co_argcount) { - int m = co->co_argcount - defcount; - for (i = argcount; i < m; i++) { - if (GETLOCAL(i) == NULL) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes %s %d " - "%sargument%s (%d given)", - PyString_AsString(co->co_name), - ((co->co_flags & CO_VARARGS) || - defcount) ? "at least" - : "exactly", - m, kwcount ? "non-keyword " : "", - m == 1 ? "" : "s", i); - goto fail; - } - } - if (n > m) - i = n - m; - else - i = 0; - for (; i < defcount; i++) { - if (GETLOCAL(m+i) == NULL) { - PyObject *def = defs[i]; - Py_INCREF(def); - SETLOCAL(m+i, def); - } - } - } - } - else { - if (argcount > 0 || kwcount > 0) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes no arguments (%d given)", - PyString_AsString(co->co_name), - argcount + kwcount); - goto fail; - } - } - /* Allocate and initialize storage for cell vars, and copy free - vars into frame. This isn't too efficient right now. */ - if (PyTuple_GET_SIZE(co->co_cellvars)) { - int i, j, nargs, found; - char *cellname, *argname; - PyObject *c; - - nargs = co->co_argcount; - if (co->co_flags & CO_VARARGS) - nargs++; - if (co->co_flags & CO_VARKEYWORDS) - nargs++; - - /* Initialize each cell var, taking into account - cell vars that are initialized from arguments. - - Should arrange for the compiler to put cellvars - that are arguments at the beginning of the cellvars - list so that we can march over it more efficiently? - */ - for (i = 0; i < PyTuple_GET_SIZE(co->co_cellvars); ++i) { - cellname = PyString_AS_STRING( - PyTuple_GET_ITEM(co->co_cellvars, i)); - found = 0; - for (j = 0; j < nargs; j++) { - argname = PyString_AS_STRING( - PyTuple_GET_ITEM(co->co_varnames, j)); - if (strcmp(cellname, argname) == 0) { - c = PyCell_New(GETLOCAL(j)); - if (c == NULL) - goto fail; - GETLOCAL(co->co_nlocals + i) = c; - found = 1; - break; - } - } - if (found == 0) { - c = PyCell_New(NULL); - if (c == NULL) - goto fail; - SETLOCAL(co->co_nlocals + i, c); - } - } - } - if (PyTuple_GET_SIZE(co->co_freevars)) { - int i; - for (i = 0; i < PyTuple_GET_SIZE(co->co_freevars); ++i) { - PyObject *o = PyTuple_GET_ITEM(closure, i); - Py_INCREF(o); - freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o; - } - } - - if (co->co_flags & CO_GENERATOR) { - /* Don't need to keep the reference to f_back, it will be set - * when the generator is resumed. */ - Py_XDECREF(f->f_back); - f->f_back = NULL; - - PCALL(PCALL_GENERATOR); - - /* Create a new generator that owns the ready to run frame - * and return that as the value. */ - return PyGen_New(f); - } - - retval = PyEval_EvalFrameEx(f,0); - - fail: /* Jump here from prelude on failure */ - - /* decref'ing the frame can cause __del__ methods to get invoked, - which can call back into Python. While we're done with the - current Python frame (f), the associated C stack is still in use, - so recursion_depth must be boosted for the duration. - */ - assert(tstate != NULL); - ++tstate->recursion_depth; - Py_DECREF(f); - --tstate->recursion_depth; - return retval; -} - - -/* Implementation notes for set_exc_info() and reset_exc_info(): - -- Below, 'exc_ZZZ' stands for 'exc_type', 'exc_value' and - 'exc_traceback'. These always travel together. - -- tstate->curexc_ZZZ is the "hot" exception that is set by - PyErr_SetString(), cleared by PyErr_Clear(), and so on. - -- Once an exception is caught by an except clause, it is transferred - from tstate->curexc_ZZZ to tstate->exc_ZZZ, from which sys.exc_info() - can pick it up. This is the primary task of set_exc_info(). - XXX That can't be right: set_exc_info() doesn't look at tstate->curexc_ZZZ. - -- Now let me explain the complicated dance with frame->f_exc_ZZZ. - - Long ago, when none of this existed, there were just a few globals: - one set corresponding to the "hot" exception, and one set - corresponding to sys.exc_ZZZ. (Actually, the latter weren't C - globals; they were simply stored as sys.exc_ZZZ. For backwards - compatibility, they still are!) The problem was that in code like - this: - - try: - "something that may fail" - except "some exception": - "do something else first" - "print the exception from sys.exc_ZZZ." - - if "do something else first" invoked something that raised and caught - an exception, sys.exc_ZZZ were overwritten. That was a frequent - cause of subtle bugs. I fixed this by changing the semantics as - follows: - - - Within one frame, sys.exc_ZZZ will hold the last exception caught - *in that frame*. - - - But initially, and as long as no exception is caught in a given - frame, sys.exc_ZZZ will hold the last exception caught in the - previous frame (or the frame before that, etc.). - - The first bullet fixed the bug in the above example. The second - bullet was for backwards compatibility: it was (and is) common to - have a function that is called when an exception is caught, and to - have that function access the caught exception via sys.exc_ZZZ. - (Example: traceback.print_exc()). - - At the same time I fixed the problem that sys.exc_ZZZ weren't - thread-safe, by introducing sys.exc_info() which gets it from tstate; - but that's really a separate improvement. - - The reset_exc_info() function in ceval.c restores the tstate->exc_ZZZ - variables to what they were before the current frame was called. The - set_exc_info() function saves them on the frame so that - reset_exc_info() can restore them. The invariant is that - frame->f_exc_ZZZ is NULL iff the current frame never caught an - exception (where "catching" an exception applies only to successful - except clauses); and if the current frame ever caught an exception, - frame->f_exc_ZZZ is the exception that was stored in tstate->exc_ZZZ - at the start of the current frame. - -*/ - -static void -set_exc_info(PyThreadState *tstate, - PyObject *type, PyObject *value, PyObject *tb) -{ - PyFrameObject *frame = tstate->frame; - PyObject *tmp_type, *tmp_value, *tmp_tb; - - assert(type != NULL); - assert(frame != NULL); - if (frame->f_exc_type == NULL) { - assert(frame->f_exc_value == NULL); - assert(frame->f_exc_traceback == NULL); - /* This frame didn't catch an exception before. */ - /* Save previous exception of this thread in this frame. */ - if (tstate->exc_type == NULL) { - /* XXX Why is this set to Py_None? */ - Py_INCREF(Py_None); - tstate->exc_type = Py_None; - } - Py_INCREF(tstate->exc_type); - Py_XINCREF(tstate->exc_value); - Py_XINCREF(tstate->exc_traceback); - frame->f_exc_type = tstate->exc_type; - frame->f_exc_value = tstate->exc_value; - frame->f_exc_traceback = tstate->exc_traceback; - } - /* Set new exception for this thread. */ - tmp_type = tstate->exc_type; - tmp_value = tstate->exc_value; - tmp_tb = tstate->exc_traceback; - Py_INCREF(type); - Py_XINCREF(value); - Py_XINCREF(tb); - tstate->exc_type = type; - tstate->exc_value = value; - tstate->exc_traceback = tb; - Py_XDECREF(tmp_type); - Py_XDECREF(tmp_value); - Py_XDECREF(tmp_tb); - /* For b/w compatibility */ - PySys_SetObject("exc_type", type); - PySys_SetObject("exc_value", value); - PySys_SetObject("exc_traceback", tb); -} - -static void -reset_exc_info(PyThreadState *tstate) -{ - PyFrameObject *frame; - PyObject *tmp_type, *tmp_value, *tmp_tb; - - /* It's a precondition that the thread state's frame caught an - * exception -- verify in a debug build. - */ - assert(tstate != NULL); - frame = tstate->frame; - assert(frame != NULL); - assert(frame->f_exc_type != NULL); - - /* Copy the frame's exception info back to the thread state. */ - tmp_type = tstate->exc_type; - tmp_value = tstate->exc_value; - tmp_tb = tstate->exc_traceback; - Py_INCREF(frame->f_exc_type); - Py_XINCREF(frame->f_exc_value); - Py_XINCREF(frame->f_exc_traceback); - tstate->exc_type = frame->f_exc_type; - tstate->exc_value = frame->f_exc_value; - tstate->exc_traceback = frame->f_exc_traceback; - Py_XDECREF(tmp_type); - Py_XDECREF(tmp_value); - Py_XDECREF(tmp_tb); - - /* For b/w compatibility */ - PySys_SetObject("exc_type", frame->f_exc_type); - PySys_SetObject("exc_value", frame->f_exc_value); - PySys_SetObject("exc_traceback", frame->f_exc_traceback); - - /* Clear the frame's exception info. */ - tmp_type = frame->f_exc_type; - tmp_value = frame->f_exc_value; - tmp_tb = frame->f_exc_traceback; - frame->f_exc_type = NULL; - frame->f_exc_value = NULL; - frame->f_exc_traceback = NULL; - Py_DECREF(tmp_type); - Py_XDECREF(tmp_value); - Py_XDECREF(tmp_tb); -} - -/* Logic for the raise statement (too complicated for inlining). - This *consumes* a reference count to each of its arguments. */ -static enum why_code -do_raise(PyObject *type, PyObject *value, PyObject *tb) -{ - if (type == NULL) { - /* Reraise */ - PyThreadState *tstate = PyThreadState_GET(); - type = tstate->exc_type == NULL ? Py_None : tstate->exc_type; - value = tstate->exc_value; - tb = tstate->exc_traceback; - Py_XINCREF(type); - Py_XINCREF(value); - Py_XINCREF(tb); - } - - /* We support the following forms of raise: - raise <class>, <classinstance> - raise <class>, <argument tuple> - raise <class>, None - raise <class>, <argument> - raise <classinstance>, None - raise <string>, <object> - raise <string>, None - - An omitted second argument is the same as None. - - In addition, raise <tuple>, <anything> is the same as - raising the tuple's first item (and it better have one!); - this rule is applied recursively. - - Finally, an optional third argument can be supplied, which - gives the traceback to be substituted (useful when - re-raising an exception after examining it). */ - - /* First, check the traceback argument, replacing None with - NULL. */ - if (tb == Py_None) { - Py_DECREF(tb); - tb = NULL; - } - else if (tb != NULL && !PyTraceBack_Check(tb)) { - PyErr_SetString(PyExc_TypeError, - "raise: arg 3 must be a traceback or None"); - goto raise_error; - } - - /* Next, replace a missing value with None */ - if (value == NULL) { - value = Py_None; - Py_INCREF(value); - } - - /* Next, repeatedly, replace a tuple exception with its first item */ - while (PyTuple_Check(type) && PyTuple_Size(type) > 0) { - PyObject *tmp = type; - type = PyTuple_GET_ITEM(type, 0); - Py_INCREF(type); - Py_DECREF(tmp); - } - - if (PyString_CheckExact(type)) { - /* Raising builtin string is deprecated but still allowed -- - * do nothing. Raising an instance of a new-style str - * subclass is right out. */ - if (PyErr_Warn(PyExc_DeprecationWarning, - "raising a string exception is deprecated")) - goto raise_error; - } - else if (PyExceptionClass_Check(type)) - PyErr_NormalizeException(&type, &value, &tb); - - else if (PyExceptionInstance_Check(type)) { - /* Raising an instance. The value should be a dummy. */ - if (value != Py_None) { - PyErr_SetString(PyExc_TypeError, - "instance exception may not have a separate value"); - goto raise_error; - } - else { - /* Normalize to raise <class>, <instance> */ - Py_DECREF(value); - value = type; - type = PyExceptionInstance_Class(type); - Py_INCREF(type); - } - } - else { - /* Not something you can raise. You get an exception - anyway, just not what you specified :-) */ - PyErr_Format(PyExc_TypeError, - "exceptions must be classes, instances, or " - "strings (deprecated), not %s", - type->ob_type->tp_name); - goto raise_error; - } - PyErr_Restore(type, value, tb); - if (tb == NULL) - return WHY_EXCEPTION; - else - return WHY_RERAISE; - raise_error: - Py_XDECREF(value); - Py_XDECREF(type); - Py_XDECREF(tb); - return WHY_EXCEPTION; -} - -/* Iterate v argcnt times and store the results on the stack (via decreasing - sp). Return 1 for success, 0 if error. */ - -static int -unpack_iterable(PyObject *v, int argcnt, PyObject **sp) -{ - int i = 0; - PyObject *it; /* iter(v) */ - PyObject *w; - - assert(v != NULL); - - it = PyObject_GetIter(v); - if (it == NULL) - goto Error; - - for (; i < argcnt; i++) { - w = PyIter_Next(it); - if (w == NULL) { - /* Iterator done, via error or exhaustion. */ - if (!PyErr_Occurred()) { - PyErr_Format(PyExc_ValueError, - "need more than %d value%s to unpack", - i, i == 1 ? "" : "s"); - } - goto Error; - } - *--sp = w; - } - - /* We better have exhausted the iterator now. */ - w = PyIter_Next(it); - if (w == NULL) { - if (PyErr_Occurred()) - goto Error; - Py_DECREF(it); - return 1; - } - Py_DECREF(w); - PyErr_SetString(PyExc_ValueError, "too many values to unpack"); - /* fall through */ -Error: - for (; i > 0; i--, sp++) - Py_DECREF(*sp); - Py_XDECREF(it); - return 0; -} - - -#ifdef LLTRACE -static int -prtrace(PyObject *v, char *str) -{ - printf("%s ", str); - if (PyObject_Print(v, stdout, 0) != 0) - PyErr_Clear(); /* Don't know what else to do */ - printf("\n"); - return 1; -} -#endif - -static void -call_exc_trace(Py_tracefunc func, PyObject *self, PyFrameObject *f) -{ - PyObject *type, *value, *traceback, *arg; - int err; - PyErr_Fetch(&type, &value, &traceback); - if (value == NULL) { - value = Py_None; - Py_INCREF(value); - } - arg = PyTuple_Pack(3, type, value, traceback); - if (arg == NULL) { - PyErr_Restore(type, value, traceback); - return; - } - err = call_trace(func, self, f, PyTrace_EXCEPTION, arg); - Py_DECREF(arg); - if (err == 0) - PyErr_Restore(type, value, traceback); - else { - Py_XDECREF(type); - Py_XDECREF(value); - Py_XDECREF(traceback); - } -} - -static void -call_trace_protected(Py_tracefunc func, PyObject *obj, PyFrameObject *frame, - int what, PyObject *arg) -{ - PyObject *type, *value, *traceback; - int err; - PyErr_Fetch(&type, &value, &traceback); - err = call_trace(func, obj, frame, what, arg); - if (err == 0) - PyErr_Restore(type, value, traceback); - else { - Py_XDECREF(type); - Py_XDECREF(value); - Py_XDECREF(traceback); - } -} - -static int -call_trace(Py_tracefunc func, PyObject *obj, PyFrameObject *frame, - int what, PyObject *arg) -{ - register PyThreadState *tstate = frame->f_tstate; - int result; - if (tstate->tracing) - return 0; - tstate->tracing++; - tstate->use_tracing = 0; - result = func(obj, frame, what, arg); - tstate->use_tracing = ((tstate->c_tracefunc != NULL) - || (tstate->c_profilefunc != NULL)); - tstate->tracing--; - return result; -} - -PyObject * -_PyEval_CallTracing(PyObject *func, PyObject *args) -{ - PyFrameObject *frame = PyEval_GetFrame(); - PyThreadState *tstate = frame->f_tstate; - int save_tracing = tstate->tracing; - int save_use_tracing = tstate->use_tracing; - PyObject *result; - - tstate->tracing = 0; - tstate->use_tracing = ((tstate->c_tracefunc != NULL) - || (tstate->c_profilefunc != NULL)); - result = PyObject_Call(func, args, NULL); - tstate->tracing = save_tracing; - tstate->use_tracing = save_use_tracing; - return result; -} - -static int -maybe_call_line_trace(Py_tracefunc func, PyObject *obj, - PyFrameObject *frame, int *instr_lb, int *instr_ub, - int *instr_prev) -{ - int result = 0; - - /* If the last instruction executed isn't in the current - instruction window, reset the window. If the last - instruction happens to fall at the start of a line or if it - represents a jump backwards, call the trace function. - */ - if ((frame->f_lasti < *instr_lb || frame->f_lasti >= *instr_ub)) { - int line; - PyAddrPair bounds; - - line = PyCode_CheckLineNumber(frame->f_code, frame->f_lasti, - &bounds); - if (line >= 0) { - frame->f_lineno = line; - result = call_trace(func, obj, frame, - PyTrace_LINE, Py_None); - } - *instr_lb = bounds.ap_lower; - *instr_ub = bounds.ap_upper; - } - else if (frame->f_lasti <= *instr_prev) { - result = call_trace(func, obj, frame, PyTrace_LINE, Py_None); - } - *instr_prev = frame->f_lasti; - return result; -} - -void -PyEval_SetProfile(Py_tracefunc func, PyObject *arg) -{ - PyThreadState *tstate = PyThreadState_GET(); - PyObject *temp = tstate->c_profileobj; - Py_XINCREF(arg); - tstate->c_profilefunc = NULL; - tstate->c_profileobj = NULL; - /* Must make sure that tracing is not ignored if 'temp' is freed */ - tstate->use_tracing = tstate->c_tracefunc != NULL; - Py_XDECREF(temp); - tstate->c_profilefunc = func; - tstate->c_profileobj = arg; - /* Flag that tracing or profiling is turned on */ - tstate->use_tracing = (func != NULL) || (tstate->c_tracefunc != NULL); -} - -void -PyEval_SetTrace(Py_tracefunc func, PyObject *arg) -{ - PyThreadState *tstate = PyThreadState_GET(); - PyObject *temp = tstate->c_traceobj; - Py_XINCREF(arg); - tstate->c_tracefunc = NULL; - tstate->c_traceobj = NULL; - /* Must make sure that profiling is not ignored if 'temp' is freed */ - tstate->use_tracing = tstate->c_profilefunc != NULL; - Py_XDECREF(temp); - tstate->c_tracefunc = func; - tstate->c_traceobj = arg; - /* Flag that tracing or profiling is turned on */ - tstate->use_tracing = ((func != NULL) - || (tstate->c_profilefunc != NULL)); -} - -PyObject * -PyEval_GetBuiltins(void) -{ - PyFrameObject *current_frame = PyEval_GetFrame(); - if (current_frame == NULL) - return PyThreadState_GET()->interp->builtins; - else - return current_frame->f_builtins; -} - -PyObject * -PyEval_GetLocals(void) -{ - PyFrameObject *current_frame = PyEval_GetFrame(); - if (current_frame == NULL) - return NULL; - PyFrame_FastToLocals(current_frame); - return current_frame->f_locals; -} - -PyObject * -PyEval_GetGlobals(void) -{ - PyFrameObject *current_frame = PyEval_GetFrame(); - if (current_frame == NULL) - return NULL; - else - return current_frame->f_globals; -} - -PyFrameObject * -PyEval_GetFrame(void) -{ - PyThreadState *tstate = PyThreadState_GET(); - return _PyThreadState_GetFrame(tstate); -} - -int -PyEval_GetRestricted(void) -{ - PyFrameObject *current_frame = PyEval_GetFrame(); - return current_frame == NULL ? 0 : PyFrame_IsRestricted(current_frame); -} - -int -PyEval_MergeCompilerFlags(PyCompilerFlags *cf) -{ - PyFrameObject *current_frame = PyEval_GetFrame(); - int result = cf->cf_flags != 0; - - if (current_frame != NULL) { - const int codeflags = current_frame->f_code->co_flags; - const int compilerflags = codeflags & PyCF_MASK; - if (compilerflags) { - result = 1; - cf->cf_flags |= compilerflags; - } -#if 0 /* future keyword */ - if (codeflags & CO_GENERATOR_ALLOWED) { - result = 1; - cf->cf_flags |= CO_GENERATOR_ALLOWED; - } -#endif - } - return result; -} - -int -Py_FlushLine(void) -{ - PyObject *f = PySys_GetObject("stdout"); - if (f == NULL) - return 0; - if (!PyFile_SoftSpace(f, 0)) - return 0; - return PyFile_WriteString("\n", f); -} - - -/* External interface to call any callable object. - The arg must be a tuple or NULL. */ - -#undef PyEval_CallObject -/* for backward compatibility: export this interface */ - -PyObject * -PyEval_CallObject(PyObject *func, PyObject *arg) -{ - return PyEval_CallObjectWithKeywords(func, arg, (PyObject *)NULL); -} -#define PyEval_CallObject(func,arg) \ - PyEval_CallObjectWithKeywords(func, arg, (PyObject *)NULL) - -PyObject * -PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw) -{ - PyObject *result; - - if (arg == NULL) { - arg = PyTuple_New(0); - if (arg == NULL) - return NULL; - } - else if (!PyTuple_Check(arg)) { - PyErr_SetString(PyExc_TypeError, - "argument list must be a tuple"); - return NULL; - } - else - Py_INCREF(arg); - - if (kw != NULL && !PyDict_Check(kw)) { - PyErr_SetString(PyExc_TypeError, - "keyword list must be a dictionary"); - Py_DECREF(arg); - return NULL; - } - - result = PyObject_Call(func, arg, kw); - Py_DECREF(arg); - return result; -} - -const char * -PyEval_GetFuncName(PyObject *func) -{ - if (PyMethod_Check(func)) - return PyEval_GetFuncName(PyMethod_GET_FUNCTION(func)); - else if (PyFunction_Check(func)) - return PyString_AsString(((PyFunctionObject*)func)->func_name); - else if (PyCFunction_Check(func)) - return ((PyCFunctionObject*)func)->m_ml->ml_name; - else if (PyClass_Check(func)) - return PyString_AsString(((PyClassObject*)func)->cl_name); - else if (PyInstance_Check(func)) { - return PyString_AsString( - ((PyInstanceObject*)func)->in_class->cl_name); - } else { - return func->ob_type->tp_name; - } -} - -const char * -PyEval_GetFuncDesc(PyObject *func) -{ - if (PyMethod_Check(func)) - return "()"; - else if (PyFunction_Check(func)) - return "()"; - else if (PyCFunction_Check(func)) - return "()"; - else if (PyClass_Check(func)) - return " constructor"; - else if (PyInstance_Check(func)) { - return " instance"; - } else { - return " object"; - } -} - -static void -err_args(PyObject *func, int flags, int nargs) -{ - if (flags & METH_NOARGS) - PyErr_Format(PyExc_TypeError, - "%.200s() takes no arguments (%d given)", - ((PyCFunctionObject *)func)->m_ml->ml_name, - nargs); - else - PyErr_Format(PyExc_TypeError, - "%.200s() takes exactly one argument (%d given)", - ((PyCFunctionObject *)func)->m_ml->ml_name, - nargs); -} - -#define C_TRACE(x, call) \ -if (tstate->use_tracing && tstate->c_profilefunc) { \ - if (call_trace(tstate->c_profilefunc, \ - tstate->c_profileobj, \ - tstate->frame, PyTrace_C_CALL, \ - func)) { \ - x = NULL; \ - } \ - else { \ - x = call; \ - if (tstate->c_profilefunc != NULL) { \ - if (x == NULL) { \ - call_trace_protected(tstate->c_profilefunc, \ - tstate->c_profileobj, \ - tstate->frame, PyTrace_C_EXCEPTION, \ - func); \ - /* XXX should pass (type, value, tb) */ \ - } else { \ - if (call_trace(tstate->c_profilefunc, \ - tstate->c_profileobj, \ - tstate->frame, PyTrace_C_RETURN, \ - func)) { \ - Py_DECREF(x); \ - x = NULL; \ - } \ - } \ - } \ - } \ -} else { \ - x = call; \ - } - -static PyObject * -call_function(PyObject ***pp_stack, int oparg -#ifdef WITH_TSC - , uint64* pintr0, uint64* pintr1 -#endif - ) -{ - int na = oparg & 0xff; - int nk = (oparg>>8) & 0xff; - int n = na + 2 * nk; - PyObject **pfunc = (*pp_stack) - n - 1; - PyObject *func = *pfunc; - PyObject *x, *w; - - /* Always dispatch PyCFunction first, because these are - presumed to be the most frequent callable object. - */ - if (PyCFunction_Check(func) && nk == 0) { - int flags = PyCFunction_GET_FLAGS(func); - PyThreadState *tstate = PyThreadState_GET(); - - PCALL(PCALL_CFUNCTION); - if (flags & (METH_NOARGS | METH_O)) { - PyCFunction meth = PyCFunction_GET_FUNCTION(func); - PyObject *self = PyCFunction_GET_SELF(func); - if (flags & METH_NOARGS && na == 0) { - C_TRACE(x, (*meth)(self,NULL)); - } - else if (flags & METH_O && na == 1) { - PyObject *arg = EXT_POP(*pp_stack); - C_TRACE(x, (*meth)(self,arg)); - Py_DECREF(arg); - } - else { - err_args(func, flags, na); - x = NULL; - } - } - else { - PyObject *callargs; - callargs = load_args(pp_stack, na); - READ_TIMESTAMP(*pintr0); - C_TRACE(x, PyCFunction_Call(func,callargs,NULL)); - READ_TIMESTAMP(*pintr1); - Py_XDECREF(callargs); - } - } else { - if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { - /* optimize access to bound methods */ - PyObject *self = PyMethod_GET_SELF(func); - PCALL(PCALL_METHOD); - PCALL(PCALL_BOUND_METHOD); - Py_INCREF(self); - func = PyMethod_GET_FUNCTION(func); - Py_INCREF(func); - Py_DECREF(*pfunc); - *pfunc = self; - na++; - n++; - } else - Py_INCREF(func); - READ_TIMESTAMP(*pintr0); - if (PyFunction_Check(func)) - x = fast_function(func, pp_stack, n, na, nk); - else - x = do_call(func, pp_stack, na, nk); - READ_TIMESTAMP(*pintr1); - Py_DECREF(func); - } - - /* Clear the stack of the function object. Also removes - the arguments in case they weren't consumed already - (fast_function() and err_args() leave them on the stack). - */ - while ((*pp_stack) > pfunc) { - w = EXT_POP(*pp_stack); - Py_DECREF(w); - PCALL(PCALL_POP); - } - return x; -} - -/* The fast_function() function optimize calls for which no argument - tuple is necessary; the objects are passed directly from the stack. - For the simplest case -- a function that takes only positional - arguments and is called with only positional arguments -- it - inlines the most primitive frame setup code from - PyEval_EvalCodeEx(), which vastly reduces the checks that must be - done before evaluating the frame. -*/ - -static PyObject * -fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk) -{ - PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); - PyObject *globals = PyFunction_GET_GLOBALS(func); - PyObject *argdefs = PyFunction_GET_DEFAULTS(func); - PyObject **d = NULL; - int nd = 0; - - PCALL(PCALL_FUNCTION); - PCALL(PCALL_FAST_FUNCTION); - if (argdefs == NULL && co->co_argcount == n && nk==0 && - co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { - PyFrameObject *f; - PyObject *retval = NULL; - PyThreadState *tstate = PyThreadState_GET(); - PyObject **fastlocals, **stack; - int i; - - PCALL(PCALL_FASTER_FUNCTION); - assert(globals != NULL); - /* XXX Perhaps we should create a specialized - PyFrame_New() that doesn't take locals, but does - take builtins without sanity checking them. - */ - assert(tstate != NULL); - f = PyFrame_New(tstate, co, globals, NULL); - if (f == NULL) - return NULL; - - fastlocals = f->f_localsplus; - stack = (*pp_stack) - n; - - for (i = 0; i < n; i++) { - Py_INCREF(*stack); - fastlocals[i] = *stack++; - } - retval = PyEval_EvalFrameEx(f,0); - ++tstate->recursion_depth; - Py_DECREF(f); - --tstate->recursion_depth; - return retval; - } - if (argdefs != NULL) { - d = &PyTuple_GET_ITEM(argdefs, 0); - nd = ((PyTupleObject *)argdefs)->ob_size; - } - return PyEval_EvalCodeEx(co, globals, - (PyObject *)NULL, (*pp_stack)-n, na, - (*pp_stack)-2*nk, nk, d, nd, - PyFunction_GET_CLOSURE(func)); -} - -static PyObject * -update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack, - PyObject *func) -{ - PyObject *kwdict = NULL; - if (orig_kwdict == NULL) - kwdict = PyDict_New(); - else { - kwdict = PyDict_Copy(orig_kwdict); - Py_DECREF(orig_kwdict); - } - if (kwdict == NULL) - return NULL; - while (--nk >= 0) { - int err; - PyObject *value = EXT_POP(*pp_stack); - PyObject *key = EXT_POP(*pp_stack); - if (PyDict_GetItem(kwdict, key) != NULL) { - PyErr_Format(PyExc_TypeError, - "%.200s%s got multiple values " - "for keyword argument '%.200s'", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func), - PyString_AsString(key)); - Py_DECREF(key); - Py_DECREF(value); - Py_DECREF(kwdict); - return NULL; - } - err = PyDict_SetItem(kwdict, key, value); - Py_DECREF(key); - Py_DECREF(value); - if (err) { - Py_DECREF(kwdict); - return NULL; - } - } - return kwdict; -} - -static PyObject * -update_star_args(int nstack, int nstar, PyObject *stararg, - PyObject ***pp_stack) -{ - PyObject *callargs, *w; - - callargs = PyTuple_New(nstack + nstar); - if (callargs == NULL) { - return NULL; - } - if (nstar) { - int i; - for (i = 0; i < nstar; i++) { - PyObject *a = PyTuple_GET_ITEM(stararg, i); - Py_INCREF(a); - PyTuple_SET_ITEM(callargs, nstack + i, a); - } - } - while (--nstack >= 0) { - w = EXT_POP(*pp_stack); - PyTuple_SET_ITEM(callargs, nstack, w); - } - return callargs; -} - -static PyObject * -load_args(PyObject ***pp_stack, int na) -{ - PyObject *args = PyTuple_New(na); - PyObject *w; - - if (args == NULL) - return NULL; - while (--na >= 0) { - w = EXT_POP(*pp_stack); - PyTuple_SET_ITEM(args, na, w); - } - return args; -} - -static PyObject * -do_call(PyObject *func, PyObject ***pp_stack, int na, int nk) -{ - PyObject *callargs = NULL; - PyObject *kwdict = NULL; - PyObject *result = NULL; - - if (nk > 0) { - kwdict = update_keyword_args(NULL, nk, pp_stack, func); - if (kwdict == NULL) - goto call_fail; - } - callargs = load_args(pp_stack, na); - if (callargs == NULL) - goto call_fail; -#ifdef CALL_PROFILE - /* At this point, we have to look at the type of func to - update the call stats properly. Do it here so as to avoid - exposing the call stats machinery outside ceval.c - */ - if (PyFunction_Check(func)) - PCALL(PCALL_FUNCTION); - else if (PyMethod_Check(func)) - PCALL(PCALL_METHOD); - else if (PyType_Check(func)) - PCALL(PCALL_TYPE); - else - PCALL(PCALL_OTHER); -#endif - result = PyObject_Call(func, callargs, kwdict); - call_fail: - Py_XDECREF(callargs); - Py_XDECREF(kwdict); - return result; -} - -static PyObject * -ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk) -{ - int nstar = 0; - PyObject *callargs = NULL; - PyObject *stararg = NULL; - PyObject *kwdict = NULL; - PyObject *result = NULL; - - if (flags & CALL_FLAG_KW) { - kwdict = EXT_POP(*pp_stack); - if (!(kwdict && PyDict_Check(kwdict))) { - PyErr_Format(PyExc_TypeError, - "%s%s argument after ** " - "must be a dictionary", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func)); - goto ext_call_fail; - } - } - if (flags & CALL_FLAG_VAR) { - stararg = EXT_POP(*pp_stack); - if (!PyTuple_Check(stararg)) { - PyObject *t = NULL; - t = PySequence_Tuple(stararg); - if (t == NULL) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) { - PyErr_Format(PyExc_TypeError, - "%s%s argument after * " - "must be a sequence", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func)); - } - goto ext_call_fail; - } - Py_DECREF(stararg); - stararg = t; - } - nstar = PyTuple_GET_SIZE(stararg); - } - if (nk > 0) { - kwdict = update_keyword_args(kwdict, nk, pp_stack, func); - if (kwdict == NULL) - goto ext_call_fail; - } - callargs = update_star_args(na, nstar, stararg, pp_stack); - if (callargs == NULL) - goto ext_call_fail; -#ifdef CALL_PROFILE - /* At this point, we have to look at the type of func to - update the call stats properly. Do it here so as to avoid - exposing the call stats machinery outside ceval.c - */ - if (PyFunction_Check(func)) - PCALL(PCALL_FUNCTION); - else if (PyMethod_Check(func)) - PCALL(PCALL_METHOD); - else if (PyType_Check(func)) - PCALL(PCALL_TYPE); - else - PCALL(PCALL_OTHER); -#endif - result = PyObject_Call(func, callargs, kwdict); - ext_call_fail: - Py_XDECREF(callargs); - Py_XDECREF(kwdict); - Py_XDECREF(stararg); - return result; -} - -/* Extract a slice index from a PyInt or PyLong or an object with the - nb_index slot defined, and store in *pi. - Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX, - and silently boost values less than -PY_SSIZE_T_MAX-1 to -PY_SSIZE_T_MAX-1. - Return 0 on error, 1 on success. -*/ -/* Note: If v is NULL, return success without storing into *pi. This - is because_PyEval_SliceIndex() is called by apply_slice(), which can be - called by the SLICE opcode with v and/or w equal to NULL. -*/ -int -_PyEval_SliceIndex(PyObject *v, Py_ssize_t *pi) -{ - if (v != NULL) { - Py_ssize_t x; - if (PyInt_Check(v)) { - /* XXX(nnorwitz): I think PyInt_AS_LONG is correct, - however, it looks like it should be AsSsize_t. - There should be a comment here explaining why. - */ - x = PyInt_AS_LONG(v); - } - else if (PyIndex_Check(v)) { - x = PyNumber_AsSsize_t(v, NULL); - if (x == -1 && PyErr_Occurred()) - return 0; - } - else { - PyErr_SetString(PyExc_TypeError, - "slice indices must be integers or " - "None or have an __index__ method"); - return 0; - } - *pi = x; - } - return 1; -} - -#undef ISINDEX -#define ISINDEX(x) ((x) == NULL || \ - PyInt_Check(x) || PyLong_Check(x) || PyIndex_Check(x)) - -static PyObject * -apply_slice(PyObject *u, PyObject *v, PyObject *w) /* return u[v:w] */ -{ - PyTypeObject *tp = u->ob_type; - PySequenceMethods *sq = tp->tp_as_sequence; - - if (sq && sq->sq_slice && ISINDEX(v) && ISINDEX(w)) { - Py_ssize_t ilow = 0, ihigh = PY_SSIZE_T_MAX; - if (!_PyEval_SliceIndex(v, &ilow)) - return NULL; - if (!_PyEval_SliceIndex(w, &ihigh)) - return NULL; - return PySequence_GetSlice(u, ilow, ihigh); - } - else { - PyObject *slice = PySlice_New(v, w, NULL); - if (slice != NULL) { - PyObject *res = PyObject_GetItem(u, slice); - Py_DECREF(slice); - return res; - } - else - return NULL; - } -} - -static int -assign_slice(PyObject *u, PyObject *v, PyObject *w, PyObject *x) - /* u[v:w] = x */ -{ - PyTypeObject *tp = u->ob_type; - PySequenceMethods *sq = tp->tp_as_sequence; - - if (sq && sq->sq_slice && ISINDEX(v) && ISINDEX(w)) { - Py_ssize_t ilow = 0, ihigh = PY_SSIZE_T_MAX; - if (!_PyEval_SliceIndex(v, &ilow)) - return -1; - if (!_PyEval_SliceIndex(w, &ihigh)) - return -1; - if (x == NULL) - return PySequence_DelSlice(u, ilow, ihigh); - else - return PySequence_SetSlice(u, ilow, ihigh, x); - } - else { - PyObject *slice = PySlice_New(v, w, NULL); - if (slice != NULL) { - int res; - if (x != NULL) - res = PyObject_SetItem(u, slice, x); - else - res = PyObject_DelItem(u, slice); - Py_DECREF(slice); - return res; - } - else - return -1; - } -} - -static PyObject * -cmp_outcome(int op, register PyObject *v, register PyObject *w) -{ - int res = 0; - switch (op) { - case PyCmp_IS: - res = (v == w); - break; - case PyCmp_IS_NOT: - res = (v != w); - break; - case PyCmp_IN: - res = PySequence_Contains(w, v); - if (res < 0) - return NULL; - break; - case PyCmp_NOT_IN: - res = PySequence_Contains(w, v); - if (res < 0) - return NULL; - res = !res; - break; - case PyCmp_EXC_MATCH: - res = PyErr_GivenExceptionMatches(v, w); - break; - default: - return PyObject_RichCompare(v, w, op); - } - v = res ? Py_True : Py_False; - Py_INCREF(v); - return v; -} - -static PyObject * -import_from(PyObject *v, PyObject *name) -{ - PyObject *x; - - x = PyObject_GetAttr(v, name); - if (x == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Format(PyExc_ImportError, - "cannot import name %.230s", - PyString_AsString(name)); - } - return x; -} - -static int -import_all_from(PyObject *locals, PyObject *v) -{ - PyObject *all = PyObject_GetAttrString(v, "__all__"); - PyObject *dict, *name, *value; - int skip_leading_underscores = 0; - int pos, err; - - if (all == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return -1; /* Unexpected error */ - PyErr_Clear(); - dict = PyObject_GetAttrString(v, "__dict__"); - if (dict == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return -1; - PyErr_SetString(PyExc_ImportError, - "from-import-* object has no __dict__ and no __all__"); - return -1; - } - all = PyMapping_Keys(dict); - Py_DECREF(dict); - if (all == NULL) - return -1; - skip_leading_underscores = 1; - } - - for (pos = 0, err = 0; ; pos++) { - name = PySequence_GetItem(all, pos); - if (name == NULL) { - if (!PyErr_ExceptionMatches(PyExc_IndexError)) - err = -1; - else - PyErr_Clear(); - break; - } - if (skip_leading_underscores && - PyString_Check(name) && - PyString_AS_STRING(name)[0] == '_') - { - Py_DECREF(name); - continue; - } - value = PyObject_GetAttr(v, name); - if (value == NULL) - err = -1; - else - err = PyDict_SetItem(locals, name, value); - Py_DECREF(name); - Py_XDECREF(value); - if (err != 0) - break; - } - Py_DECREF(all); - return err; -} - -static PyObject * -build_class(PyObject *methods, PyObject *bases, PyObject *name) -{ - PyObject *metaclass = NULL, *result, *base; - - if (PyDict_Check(methods)) - metaclass = PyDict_GetItemString(methods, "__metaclass__"); - if (metaclass != NULL) - Py_INCREF(metaclass); - else if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) { - base = PyTuple_GET_ITEM(bases, 0); - metaclass = PyObject_GetAttrString(base, "__class__"); - if (metaclass == NULL) { - PyErr_Clear(); - metaclass = (PyObject *)base->ob_type; - Py_INCREF(metaclass); - } - } - else { - PyObject *g = PyEval_GetGlobals(); - if (g != NULL && PyDict_Check(g)) - metaclass = PyDict_GetItemString(g, "__metaclass__"); - if (metaclass == NULL) - metaclass = (PyObject *) &PyClass_Type; - Py_INCREF(metaclass); - } - result = PyObject_CallFunctionObjArgs(metaclass, name, bases, methods, NULL); - Py_DECREF(metaclass); - if (result == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) { - /* A type error here likely means that the user passed - in a base that was not a class (such the random module - instead of the random.random type). Help them out with - by augmenting the error message with more information.*/ - - PyObject *ptype, *pvalue, *ptraceback; - - PyErr_Fetch(&ptype, &pvalue, &ptraceback); - if (PyString_Check(pvalue)) { - PyObject *newmsg; - newmsg = PyString_FromFormat( - "Error when calling the metaclass bases\n %s", - PyString_AS_STRING(pvalue)); - if (newmsg != NULL) { - Py_DECREF(pvalue); - pvalue = newmsg; - } - } - PyErr_Restore(ptype, pvalue, ptraceback); - } - return result; -} - -static int -exec_statement(PyFrameObject *f, PyObject *prog, PyObject *globals, - PyObject *locals) -{ - int n; - PyObject *v; - int plain = 0; - - if (PyTuple_Check(prog) && globals == Py_None && locals == Py_None && - ((n = PyTuple_Size(prog)) == 2 || n == 3)) { - /* Backward compatibility hack */ - globals = PyTuple_GetItem(prog, 1); - if (n == 3) - locals = PyTuple_GetItem(prog, 2); - prog = PyTuple_GetItem(prog, 0); - } - if (globals == Py_None) { - globals = PyEval_GetGlobals(); - if (locals == Py_None) { - locals = PyEval_GetLocals(); - plain = 1; - } - if (!globals || !locals) { - PyErr_SetString(PyExc_SystemError, - "globals and locals cannot be NULL"); - return -1; - } - } - else if (locals == Py_None) - locals = globals; - if (!PyString_Check(prog) && - !PyUnicode_Check(prog) && - !PyCode_Check(prog) && - !PyFile_Check(prog)) { - PyErr_SetString(PyExc_TypeError, - "exec: arg 1 must be a string, file, or code object"); - return -1; - } - if (!PyDict_Check(globals)) { - PyErr_SetString(PyExc_TypeError, - "exec: arg 2 must be a dictionary or None"); - return -1; - } - if (!PyMapping_Check(locals)) { - PyErr_SetString(PyExc_TypeError, - "exec: arg 3 must be a mapping or None"); - return -1; - } - if (PyDict_GetItemString(globals, "__builtins__") == NULL) - PyDict_SetItemString(globals, "__builtins__", f->f_builtins); - if (PyCode_Check(prog)) { - if (PyCode_GetNumFree((PyCodeObject *)prog) > 0) { - PyErr_SetString(PyExc_TypeError, - "code object passed to exec may not contain free variables"); - return -1; - } - v = PyEval_EvalCode((PyCodeObject *) prog, globals, locals); - } - else if (PyFile_Check(prog)) { - FILE *fp = PyFile_AsFile(prog); - char *name = PyString_AsString(PyFile_Name(prog)); - PyCompilerFlags cf; - cf.cf_flags = 0; - if (PyEval_MergeCompilerFlags(&cf)) - v = PyRun_FileFlags(fp, name, Py_file_input, globals, - locals, &cf); - else - v = PyRun_File(fp, name, Py_file_input, globals, - locals); - } - else { - PyObject *tmp = NULL; - char *str; - PyCompilerFlags cf; - cf.cf_flags = 0; -#ifdef Py_USING_UNICODE - if (PyUnicode_Check(prog)) { - tmp = PyUnicode_AsUTF8String(prog); - if (tmp == NULL) - return -1; - prog = tmp; - cf.cf_flags |= PyCF_SOURCE_IS_UTF8; - } -#endif - if (PyString_AsStringAndSize(prog, &str, NULL)) - return -1; - if (PyEval_MergeCompilerFlags(&cf)) - v = PyRun_StringFlags(str, Py_file_input, globals, - locals, &cf); - else - v = PyRun_String(str, Py_file_input, globals, locals); - Py_XDECREF(tmp); - } - if (plain) - PyFrame_LocalsToFast(f, 0); - if (v == NULL) - return -1; - Py_DECREF(v); - return 0; -} - -static void -format_exc_check_arg(PyObject *exc, char *format_str, PyObject *obj) -{ - char *obj_str; - - if (!obj) - return; - - obj_str = PyString_AsString(obj); - if (!obj_str) - return; - - PyErr_Format(exc, format_str, obj_str); -} - -static PyObject * -string_concatenate(PyObject *v, PyObject *w, - PyFrameObject *f, unsigned char *next_instr) -{ - /* This function implements 'variable += expr' when both arguments - are strings. */ - Py_ssize_t v_len = PyString_GET_SIZE(v); - Py_ssize_t w_len = PyString_GET_SIZE(w); - Py_ssize_t new_len = v_len + w_len; - if (new_len < 0) { - PyErr_SetString(PyExc_OverflowError, - "strings are too large to concat"); - return NULL; - } - - if (v->ob_refcnt == 2) { - /* In the common case, there are 2 references to the value - * stored in 'variable' when the += is performed: one on the - * value stack (in 'v') and one still stored in the 'variable'. - * We try to delete the variable now to reduce the refcnt to 1. - */ - switch (*next_instr) { - case STORE_FAST: - { - int oparg = PEEKARG(); - PyObject **fastlocals = f->f_localsplus; - if (GETLOCAL(oparg) == v) - SETLOCAL(oparg, NULL); - break; - } - case STORE_DEREF: - { - PyObject **freevars = f->f_localsplus + f->f_code->co_nlocals; - PyObject *c = freevars[PEEKARG()]; - if (PyCell_GET(c) == v) - PyCell_Set(c, NULL); - break; - } - case STORE_NAME: - { - PyObject *names = f->f_code->co_names; - PyObject *name = GETITEM(names, PEEKARG()); - PyObject *locals = f->f_locals; - if (PyDict_CheckExact(locals) && - PyDict_GetItem(locals, name) == v) { - if (PyDict_DelItem(locals, name) != 0) { - PyErr_Clear(); - } - } - break; - } - } - } - - if (v->ob_refcnt == 1 && !PyString_CHECK_INTERNED(v)) { - /* Now we own the last reference to 'v', so we can resize it - * in-place. - */ - if (_PyString_Resize(&v, new_len) != 0) { - /* XXX if _PyString_Resize() fails, 'v' has been - * deallocated so it cannot be put back into 'variable'. - * The MemoryError is raised when there is no value in - * 'variable', which might (very remotely) be a cause - * of incompatibilities. - */ - return NULL; - } - /* copy 'w' into the newly allocated area of 'v' */ - memcpy(PyString_AS_STRING(v) + v_len, - PyString_AS_STRING(w), w_len); - return v; - } - else { - /* When in-place resizing is not an option. */ - PyString_Concat(&v, w); - return v; - } -} - -#ifdef DYNAMIC_EXECUTION_PROFILE - -static PyObject * -getarray(long a[256]) -{ - int i; - PyObject *l = PyList_New(256); - if (l == NULL) return NULL; - for (i = 0; i < 256; i++) { - PyObject *x = PyInt_FromLong(a[i]); - if (x == NULL) { - Py_DECREF(l); - return NULL; - } - PyList_SetItem(l, i, x); - } - for (i = 0; i < 256; i++) - a[i] = 0; - return l; -} - -PyObject * -_Py_GetDXProfile(PyObject *self, PyObject *args) -{ -#ifndef DXPAIRS - return getarray(dxp); -#else - int i; - PyObject *l = PyList_New(257); - if (l == NULL) return NULL; - for (i = 0; i < 257; i++) { - PyObject *x = getarray(dxpairs[i]); - if (x == NULL) { - Py_DECREF(l); - return NULL; - } - PyList_SetItem(l, i, x); - } - return l; -#endif -} - -#endif diff --git a/tests/examplefiles/example.c b/tests/examplefiles/example.c index 9f9c477d..67b8d17d 100644 --- a/tests/examplefiles/example.c +++ b/tests/examplefiles/example.c @@ -4507,5337 +4507,3 @@ bigsub(x, y) return z; } -static VALUE -bigadd(x, y, sign) - VALUE x, y; - char sign; -{ - VALUE z; - BDIGIT_DBL num; - long i, len; - - sign = (sign == RBIGNUM(y)->sign); - if (RBIGNUM(x)->sign != sign) { - if (sign) return bigsub(y, x); - return bigsub(x, y); - } - - if (RBIGNUM(x)->len > RBIGNUM(y)->len) { - len = RBIGNUM(x)->len + 1; - z = x; x = y; y = z; - } - else { - len = RBIGNUM(y)->len + 1; - } - z = bignew(len, sign); - - len = RBIGNUM(x)->len; - for (i = 0, num = 0; i < len; i++) { - num += (BDIGIT_DBL)BDIGITS(x)[i] + BDIGITS(y)[i]; - BDIGITS(z)[i] = BIGLO(num); - num = BIGDN(num); - } - len = RBIGNUM(y)->len; - while (num && i < len) { - num += BDIGITS(y)[i]; - BDIGITS(z)[i++] = BIGLO(num); - num = BIGDN(num); - } - while (i < len) { - BDIGITS(z)[i] = BDIGITS(y)[i]; - i++; - } - BDIGITS(z)[i] = (BDIGIT)num; - - return z; -} - -/* - * call-seq: - * big + other => Numeric - * - * Adds big and other, returning the result. - */ - -VALUE -rb_big_plus(x, y) - VALUE x, y; -{ - switch (TYPE(y)) { - case T_FIXNUM: - y = rb_int2big(FIX2LONG(y)); - /* fall through */ - case T_BIGNUM: - return bignorm(bigadd(x, y, 1)); - - case T_FLOAT: - return rb_float_new(rb_big2dbl(x) + RFLOAT(y)->value); - - default: - return rb_num_coerce_bin(x, y); - } -} - -/* - * call-seq: - * big - other => Numeric - * - * Subtracts other from big, returning the result. - */ - -VALUE -rb_big_minus(x, y) - VALUE x, y; -{ - switch (TYPE(y)) { - case T_FIXNUM: - y = rb_int2big(FIX2LONG(y)); - /* fall through */ - case T_BIGNUM: - return bignorm(bigadd(x, y, 0)); - - case T_FLOAT: - return rb_float_new(rb_big2dbl(x) - RFLOAT(y)->value); - - default: - return rb_num_coerce_bin(x, y); - } -} - -/* - * call-seq: - * big * other => Numeric - * - * Multiplies big and other, returning the result. - */ - -VALUE -rb_big_mul(x, y) - VALUE x, y; -{ - long i, j; - BDIGIT_DBL n = 0; - VALUE z; - BDIGIT *zds; - - if (FIXNUM_P(x)) x = rb_int2big(FIX2LONG(x)); - switch (TYPE(y)) { - case T_FIXNUM: - y = rb_int2big(FIX2LONG(y)); - break; - - case T_BIGNUM: - break; - - case T_FLOAT: - return rb_float_new(rb_big2dbl(x) * RFLOAT(y)->value); - - default: - return rb_num_coerce_bin(x, y); - } - - j = RBIGNUM(x)->len + RBIGNUM(y)->len + 1; - z = bignew(j, RBIGNUM(x)->sign==RBIGNUM(y)->sign); - zds = BDIGITS(z); - while (j--) zds[j] = 0; - for (i = 0; i < RBIGNUM(x)->len; i++) { - BDIGIT_DBL dd = BDIGITS(x)[i]; - if (dd == 0) continue; - n = 0; - for (j = 0; j < RBIGNUM(y)->len; j++) { - BDIGIT_DBL ee = n + (BDIGIT_DBL)dd * BDIGITS(y)[j]; - n = zds[i + j] + ee; - if (ee) zds[i + j] = BIGLO(n); - n = BIGDN(n); - } - if (n) { - zds[i + j] = n; - } - } - - return bignorm(z); -} - -static void -bigdivrem(x, y, divp, modp) - VALUE x, y; - VALUE *divp, *modp; -{ - long nx = RBIGNUM(x)->len, ny = RBIGNUM(y)->len; - long i, j; - VALUE yy, z; - BDIGIT *xds, *yds, *zds, *tds; - BDIGIT_DBL t2; - BDIGIT_DBL_SIGNED num; - BDIGIT dd, q; - - if (BIGZEROP(y)) rb_num_zerodiv(); - yds = BDIGITS(y); - if (nx < ny || (nx == ny && BDIGITS(x)[nx - 1] < BDIGITS(y)[ny - 1])) { - if (divp) *divp = rb_int2big(0); - if (modp) *modp = x; - return; - } - xds = BDIGITS(x); - if (ny == 1) { - dd = yds[0]; - z = rb_big_clone(x); - zds = BDIGITS(z); - t2 = 0; i = nx; - while (i--) { - t2 = BIGUP(t2) + zds[i]; - zds[i] = (BDIGIT)(t2 / dd); - t2 %= dd; - } - RBIGNUM(z)->sign = RBIGNUM(x)->sign==RBIGNUM(y)->sign; - if (modp) { - *modp = rb_uint2big((unsigned long)t2); - RBIGNUM(*modp)->sign = RBIGNUM(x)->sign; - } - if (divp) *divp = z; - return; - } - z = bignew(nx==ny?nx+2:nx+1, RBIGNUM(x)->sign==RBIGNUM(y)->sign); - zds = BDIGITS(z); - if (nx==ny) zds[nx+1] = 0; - while (!yds[ny-1]) ny--; - - dd = 0; - q = yds[ny-1]; - while ((q & (1<<(BITSPERDIG-1))) == 0) { - q <<= 1; - dd++; - } - if (dd) { - yy = rb_big_clone(y); - tds = BDIGITS(yy); - j = 0; - t2 = 0; - while (j<ny) { - t2 += (BDIGIT_DBL)yds[j]<<dd; - tds[j++] = BIGLO(t2); - t2 = BIGDN(t2); - } - yds = tds; - j = 0; - t2 = 0; - while (j<nx) { - t2 += (BDIGIT_DBL)xds[j]<<dd; - zds[j++] = BIGLO(t2); - t2 = BIGDN(t2); - } - zds[j] = (BDIGIT)t2; - } - else { - zds[nx] = 0; - j = nx; - while (j--) zds[j] = xds[j]; - } - - j = nx==ny?nx+1:nx; - do { - if (zds[j] == yds[ny-1]) q = BIGRAD-1; - else q = (BDIGIT)((BIGUP(zds[j]) + zds[j-1])/yds[ny-1]); - if (q) { - i = 0; num = 0; t2 = 0; - do { /* multiply and subtract */ - BDIGIT_DBL ee; - t2 += (BDIGIT_DBL)yds[i] * q; - ee = num - BIGLO(t2); - num = (BDIGIT_DBL)zds[j - ny + i] + ee; - if (ee) zds[j - ny + i] = BIGLO(num); - num = BIGDN(num); - t2 = BIGDN(t2); - } while (++i < ny); - num += zds[j - ny + i] - t2;/* borrow from high digit; don't update */ - while (num) { /* "add back" required */ - i = 0; num = 0; q--; - do { - BDIGIT_DBL ee = num + yds[i]; - num = (BDIGIT_DBL)zds[j - ny + i] + ee; - if (ee) zds[j - ny + i] = BIGLO(num); - num = BIGDN(num); - } while (++i < ny); - num--; - } - } - zds[j] = q; - } while (--j >= ny); - if (divp) { /* move quotient down in z */ - *divp = rb_big_clone(z); - zds = BDIGITS(*divp); - j = (nx==ny ? nx+2 : nx+1) - ny; - for (i = 0;i < j;i++) zds[i] = zds[i+ny]; - RBIGNUM(*divp)->len = i; - } - if (modp) { /* normalize remainder */ - *modp = rb_big_clone(z); - zds = BDIGITS(*modp); - while (--ny && !zds[ny]); ++ny; - if (dd) { - t2 = 0; i = ny; - while(i--) { - t2 = (t2 | zds[i]) >> dd; - q = zds[i]; - zds[i] = BIGLO(t2); - t2 = BIGUP(q); - } - } - RBIGNUM(*modp)->len = ny; - RBIGNUM(*modp)->sign = RBIGNUM(x)->sign; - } -} - -static void -bigdivmod(x, y, divp, modp) - VALUE x, y; - VALUE *divp, *modp; -{ - VALUE mod; - - bigdivrem(x, y, divp, &mod); - if (RBIGNUM(x)->sign != RBIGNUM(y)->sign && !BIGZEROP(mod)) { - if (divp) *divp = bigadd(*divp, rb_int2big(1), 0); - if (modp) *modp = bigadd(mod, y, 1); - } - else { - if (divp) *divp = *divp; - if (modp) *modp = mod; - } -} - -/* - * call-seq: - * big / other => Numeric - * big.div(other) => Numeric - * - * Divides big by other, returning the result. - */ - -static VALUE -rb_big_div(x, y) - VALUE x, y; -{ - VALUE z; - - switch (TYPE(y)) { - case T_FIXNUM: - y = rb_int2big(FIX2LONG(y)); - break; - - case T_BIGNUM: - break; - - case T_FLOAT: - return rb_float_new(rb_big2dbl(x) / RFLOAT(y)->value); - - default: - return rb_num_coerce_bin(x, y); - } - bigdivmod(x, y, &z, 0); - - return bignorm(z); -} - -/* - * call-seq: - * big % other => Numeric - * big.modulo(other) => Numeric - * - * Returns big modulo other. See Numeric.divmod for more - * information. - */ - -static VALUE -rb_big_modulo(x, y) - VALUE x, y; -{ - VALUE z; - - switch (TYPE(y)) { - case T_FIXNUM: - y = rb_int2big(FIX2LONG(y)); - break; - - case T_BIGNUM: - break; - - default: - return rb_num_coerce_bin(x, y); - } - bigdivmod(x, y, 0, &z); - - return bignorm(z); -} - -/* - * call-seq: - * big.remainder(numeric) => number - * - * Returns the remainder after dividing <i>big</i> by <i>numeric</i>. - * - * -1234567890987654321.remainder(13731) #=> -6966 - * -1234567890987654321.remainder(13731.24) #=> -9906.22531493148 - */ -static VALUE -rb_big_remainder(x, y) - VALUE x, y; -{ - VALUE z; - - switch (TYPE(y)) { - case T_FIXNUM: - y = rb_int2big(FIX2LONG(y)); - break; - - case T_BIGNUM: - break; - - default: - return rb_num_coerce_bin(x, y); - } - bigdivrem(x, y, 0, &z); - - return bignorm(z); -} - -/* - * call-seq: - * big.divmod(numeric) => array - * - * See <code>Numeric#divmod</code>. - * - */ -VALUE -rb_big_divmod(x, y) - VALUE x, y; -{ - VALUE div, mod; - - switch (TYPE(y)) { - case T_FIXNUM: - y = rb_int2big(FIX2LONG(y)); - break; - - case T_BIGNUM: - break; - - default: - return rb_num_coerce_bin(x, y); - } - bigdivmod(x, y, &div, &mod); - - return rb_assoc_new(bignorm(div), bignorm(mod)); -} - -/* - * call-seq: - * big.quo(numeric) -> float - * - * Returns the floating point result of dividing <i>big</i> by - * <i>numeric</i>. - * - * -1234567890987654321.quo(13731) #=> -89910996357705.5 - * -1234567890987654321.quo(13731.24) #=> -89909424858035.7 - * - */ - -static VALUE -rb_big_quo(x, y) - VALUE x, y; -{ - double dx = rb_big2dbl(x); - double dy; - - switch (TYPE(y)) { - case T_FIXNUM: - dy = (double)FIX2LONG(y); - break; - - case T_BIGNUM: - dy = rb_big2dbl(y); - break; - - case T_FLOAT: - dy = RFLOAT(y)->value; - break; - - default: - return rb_num_coerce_bin(x, y); - } - return rb_float_new(dx / dy); -} - -/* - * call-seq: - * big ** exponent #=> numeric - * - * Raises _big_ to the _exponent_ power (which may be an integer, float, - * or anything that will coerce to a number). The result may be - * a Fixnum, Bignum, or Float - * - * 123456789 ** 2 #=> 15241578750190521 - * 123456789 ** 1.2 #=> 5126464716.09932 - * 123456789 ** -2 #=> 6.5610001194102e-17 - */ - -VALUE -rb_big_pow(x, y) - VALUE x, y; -{ - double d; - long yy; - - if (y == INT2FIX(0)) return INT2FIX(1); - switch (TYPE(y)) { - case T_FLOAT: - d = RFLOAT(y)->value; - break; - - case T_BIGNUM: - rb_warn("in a**b, b may be too big"); - d = rb_big2dbl(y); - break; - - case T_FIXNUM: - yy = FIX2LONG(y); - if (yy > 0) { - VALUE z = x; - - for (;;) { - yy -= 1; - if (yy == 0) break; - while (yy % 2 == 0) { - yy /= 2; - x = rb_big_mul(x, x); - } - z = rb_big_mul(z, x); - } - return bignorm(z); - } - d = (double)yy; - break; - - default: - return rb_num_coerce_bin(x, y); - } - return rb_float_new(pow(rb_big2dbl(x), d)); -} - -/* - * call-seq: - * big & numeric => integer - * - * Performs bitwise +and+ between _big_ and _numeric_. - */ - -VALUE -rb_big_and(xx, yy) - VALUE xx, yy; -{ - volatile VALUE x, y, z; - BDIGIT *ds1, *ds2, *zds; - long i, l1, l2; - char sign; - - x = xx; - y = rb_to_int(yy); - if (FIXNUM_P(y)) { - y = rb_int2big(FIX2LONG(y)); - } - if (!RBIGNUM(y)->sign) { - y = rb_big_clone(y); - get2comp(y, Qtrue); - } - if (!RBIGNUM(x)->sign) { - x = rb_big_clone(x); - get2comp(x, Qtrue); - } - if (RBIGNUM(x)->len > RBIGNUM(y)->len) { - l1 = RBIGNUM(y)->len; - l2 = RBIGNUM(x)->len; - ds1 = BDIGITS(y); - ds2 = BDIGITS(x); - sign = RBIGNUM(y)->sign; - } - else { - l1 = RBIGNUM(x)->len; - l2 = RBIGNUM(y)->len; - ds1 = BDIGITS(x); - ds2 = BDIGITS(y); - sign = RBIGNUM(x)->sign; - } - z = bignew(l2, RBIGNUM(x)->sign || RBIGNUM(y)->sign); - zds = BDIGITS(z); - - for (i=0; i<l1; i++) { - zds[i] = ds1[i] & ds2[i]; - } - for (; i<l2; i++) { - zds[i] = sign?0:ds2[i]; - } - if (!RBIGNUM(z)->sign) get2comp(z, Qfalse); - return bignorm(z); -} - -/* - * call-seq: - * big | numeric => integer - * - * Performs bitwise +or+ between _big_ and _numeric_. - */ - -VALUE -rb_big_or(xx, yy) - VALUE xx, yy; -{ - volatile VALUE x, y, z; - BDIGIT *ds1, *ds2, *zds; - long i, l1, l2; - char sign; - - x = xx; - y = rb_to_int(yy); - if (FIXNUM_P(y)) { - y = rb_int2big(FIX2LONG(y)); - } - - if (!RBIGNUM(y)->sign) { - y = rb_big_clone(y); - get2comp(y, Qtrue); - } - if (!RBIGNUM(x)->sign) { - x = rb_big_clone(x); - get2comp(x, Qtrue); - } - if (RBIGNUM(x)->len > RBIGNUM(y)->len) { - l1 = RBIGNUM(y)->len; - l2 = RBIGNUM(x)->len; - ds1 = BDIGITS(y); - ds2 = BDIGITS(x); - sign = RBIGNUM(y)->sign; - } - else { - l1 = RBIGNUM(x)->len; - l2 = RBIGNUM(y)->len; - ds1 = BDIGITS(x); - ds2 = BDIGITS(y); - sign = RBIGNUM(x)->sign; - } - z = bignew(l2, RBIGNUM(x)->sign && RBIGNUM(y)->sign); - zds = BDIGITS(z); - - for (i=0; i<l1; i++) { - zds[i] = ds1[i] | ds2[i]; - } - for (; i<l2; i++) { - zds[i] = sign?ds2[i]:(BIGRAD-1); - } - if (!RBIGNUM(z)->sign) get2comp(z, Qfalse); - - return bignorm(z); -} - -/* - * call-seq: - * big ^ numeric => integer - * - * Performs bitwise +exclusive or+ between _big_ and _numeric_. - */ - -VALUE -rb_big_xor(xx, yy) - VALUE xx, yy; -{ - volatile VALUE x, y; - VALUE z; - BDIGIT *ds1, *ds2, *zds; - long i, l1, l2; - char sign; - - x = xx; - y = rb_to_int(yy); - if (FIXNUM_P(y)) { - y = rb_int2big(FIX2LONG(y)); - } - - if (!RBIGNUM(y)->sign) { - y = rb_big_clone(y); - get2comp(y, Qtrue); - } - if (!RBIGNUM(x)->sign) { - x = rb_big_clone(x); - get2comp(x, Qtrue); - } - if (RBIGNUM(x)->len > RBIGNUM(y)->len) { - l1 = RBIGNUM(y)->len; - l2 = RBIGNUM(x)->len; - ds1 = BDIGITS(y); - ds2 = BDIGITS(x); - sign = RBIGNUM(y)->sign; - } - else { - l1 = RBIGNUM(x)->len; - l2 = RBIGNUM(y)->len; - ds1 = BDIGITS(x); - ds2 = BDIGITS(y); - sign = RBIGNUM(x)->sign; - } - RBIGNUM(x)->sign = RBIGNUM(x)->sign?1:0; - RBIGNUM(y)->sign = RBIGNUM(y)->sign?1:0; - z = bignew(l2, !(RBIGNUM(x)->sign ^ RBIGNUM(y)->sign)); - zds = BDIGITS(z); - - for (i=0; i<l1; i++) { - zds[i] = ds1[i] ^ ds2[i]; - } - for (; i<l2; i++) { - zds[i] = sign?ds2[i]:~ds2[i]; - } - if (!RBIGNUM(z)->sign) get2comp(z, Qfalse); - - return bignorm(z); -} - -static VALUE rb_big_rshift _((VALUE,VALUE)); - -/* - * call-seq: - * big << numeric => integer - * - * Shifts big left _numeric_ positions (right if _numeric_ is negative). - */ - -VALUE -rb_big_lshift(x, y) - VALUE x, y; -{ - BDIGIT *xds, *zds; - int shift = NUM2INT(y); - int s1 = shift/BITSPERDIG; - int s2 = shift%BITSPERDIG; - VALUE z; - BDIGIT_DBL num = 0; - long len, i; - - if (shift < 0) return rb_big_rshift(x, INT2FIX(-shift)); - len = RBIGNUM(x)->len; - z = bignew(len+s1+1, RBIGNUM(x)->sign); - zds = BDIGITS(z); - for (i=0; i<s1; i++) { - *zds++ = 0; - } - xds = BDIGITS(x); - for (i=0; i<len; i++) { - num = num | (BDIGIT_DBL)*xds++<<s2; - *zds++ = BIGLO(num); - num = BIGDN(num); - } - *zds = BIGLO(num); - return bignorm(z); -} - -/* - * call-seq: - * big >> numeric => integer - * - * Shifts big right _numeric_ positions (left if _numeric_ is negative). - */ - -static VALUE -rb_big_rshift(x, y) - VALUE x, y; -{ - BDIGIT *xds, *zds; - int shift = NUM2INT(y); - long s1 = shift/BITSPERDIG; - long s2 = shift%BITSPERDIG; - VALUE z; - BDIGIT_DBL num = 0; - long i, j; - - if (shift < 0) return rb_big_lshift(x, INT2FIX(-shift)); - - if (s1 > RBIGNUM(x)->len) { - if (RBIGNUM(x)->sign) - return INT2FIX(0); - else - return INT2FIX(-1); - } - if (!RBIGNUM(x)->sign) { - x = rb_big_clone(x); - get2comp(x, Qtrue); - } - xds = BDIGITS(x); - i = RBIGNUM(x)->len; j = i - s1; - z = bignew(j, RBIGNUM(x)->sign); - if (!RBIGNUM(x)->sign) { - num = ((BDIGIT_DBL)~0) << BITSPERDIG; - } - zds = BDIGITS(z); - while (i--, j--) { - num = (num | xds[i]) >> s2; - zds[j] = BIGLO(num); - num = BIGUP(xds[i]); - } - if (!RBIGNUM(x)->sign) { - get2comp(z, Qfalse); - } - return bignorm(z); -} - -/* - * call-seq: - * big[n] -> 0, 1 - * - * Bit Reference---Returns the <em>n</em>th bit in the (assumed) binary - * representation of <i>big</i>, where <i>big</i>[0] is the least - * significant bit. - * - * a = 9**15 - * 50.downto(0) do |n| - * print a[n] - * end - * - * <em>produces:</em> - * - * 000101110110100000111000011110010100111100010111001 - * - */ - -static VALUE -rb_big_aref(x, y) - VALUE x, y; -{ - BDIGIT *xds; - int shift; - long s1, s2; - - if (TYPE(y) == T_BIGNUM) { - if (!RBIGNUM(y)->sign || RBIGNUM(x)->sign) - return INT2FIX(0); - return INT2FIX(1); - } - shift = NUM2INT(y); - if (shift < 0) return INT2FIX(0); - s1 = shift/BITSPERDIG; - s2 = shift%BITSPERDIG; - - if (!RBIGNUM(x)->sign) { - if (s1 >= RBIGNUM(x)->len) return INT2FIX(1); - x = rb_big_clone(x); - get2comp(x, Qtrue); - } - else { - if (s1 >= RBIGNUM(x)->len) return INT2FIX(0); - } - xds = BDIGITS(x); - if (xds[s1] & (1<<s2)) - return INT2FIX(1); - return INT2FIX(0); -} - -/* - * call-seq: - * big.hash => fixnum - * - * Compute a hash based on the value of _big_. - */ - -static VALUE -rb_big_hash(x) - VALUE x; -{ - long i, len, key; - BDIGIT *digits; - - key = 0; digits = BDIGITS(x); len = RBIGNUM(x)->len; - for (i=0; i<len; i++) { - key ^= *digits++; - } - return LONG2FIX(key); -} - -/* - * MISSING: documentation - */ - -static VALUE -rb_big_coerce(x, y) - VALUE x, y; -{ - if (FIXNUM_P(y)) { - return rb_assoc_new(rb_int2big(FIX2LONG(y)), x); - } - else { - rb_raise(rb_eTypeError, "can't coerce %s to Bignum", - rb_obj_classname(y)); - } - /* not reached */ - return Qnil; -} - -/* - * call-seq: - * big.abs -> aBignum - * - * Returns the absolute value of <i>big</i>. - * - * -1234567890987654321.abs #=> 1234567890987654321 - */ - -static VALUE -rb_big_abs(x) - VALUE x; -{ - if (!RBIGNUM(x)->sign) { - x = rb_big_clone(x); - RBIGNUM(x)->sign = 1; - } - return x; -} - -VALUE -rb_big_rand(max, rand_buf) - VALUE max; - double *rand_buf; -{ - VALUE v; - long len = RBIGNUM(max)->len; - - if (BIGZEROP(max)) { - return rb_float_new(rand_buf[0]); - } - v = bignew(len,1); - len--; - BDIGITS(v)[len] = BDIGITS(max)[len] * rand_buf[len]; - while (len--) { - BDIGITS(v)[len] = ((BDIGIT)~0) * rand_buf[len]; - } - - return v; -} - -/* - * call-seq: - * big.size -> integer - * - * Returns the number of bytes in the machine representation of - * <i>big</i>. - * - * (256**10 - 1).size #=> 12 - * (256**20 - 1).size #=> 20 - * (256**40 - 1).size #=> 40 - */ - -static VALUE -rb_big_size(big) - VALUE big; -{ - return LONG2FIX(RBIGNUM(big)->len*SIZEOF_BDIGITS); -} - -/* - * Bignum objects hold integers outside the range of - * Fixnum. Bignum objects are created - * automatically when integer calculations would otherwise overflow a - * Fixnum. When a calculation involving - * Bignum objects returns a result that will fit in a - * Fixnum, the result is automatically converted. - * - * For the purposes of the bitwise operations and <code>[]</code>, a - * Bignum is treated as if it were an infinite-length - * bitstring with 2's complement representation. - * - * While Fixnum values are immediate, Bignum - * objects are not---assignment and parameter passing work with - * references to objects, not the objects themselves. - * - */ - -void -Init_Bignum() -{ - rb_cBignum = rb_define_class("Bignum", rb_cInteger); - - rb_define_method(rb_cBignum, "to_s", rb_big_to_s, -1); - rb_define_method(rb_cBignum, "coerce", rb_big_coerce, 1); - rb_define_method(rb_cBignum, "-@", rb_big_uminus, 0); - rb_define_method(rb_cBignum, "+", rb_big_plus, 1); - rb_define_method(rb_cBignum, "-", rb_big_minus, 1); - rb_define_method(rb_cBignum, "*", rb_big_mul, 1); - rb_define_method(rb_cBignum, "/", rb_big_div, 1); - rb_define_method(rb_cBignum, "%", rb_big_modulo, 1); - rb_define_method(rb_cBignum, "div", rb_big_div, 1); - rb_define_method(rb_cBignum, "divmod", rb_big_divmod, 1); - rb_define_method(rb_cBignum, "modulo", rb_big_modulo, 1); - rb_define_method(rb_cBignum, "remainder", rb_big_remainder, 1); - rb_define_method(rb_cBignum, "quo", rb_big_quo, 1); - rb_define_method(rb_cBignum, "**", rb_big_pow, 1); - rb_define_method(rb_cBignum, "&", rb_big_and, 1); - rb_define_method(rb_cBignum, "|", rb_big_or, 1); - rb_define_method(rb_cBignum, "^", rb_big_xor, 1); - rb_define_method(rb_cBignum, "~", rb_big_neg, 0); - rb_define_method(rb_cBignum, "<<", rb_big_lshift, 1); - rb_define_method(rb_cBignum, ">>", rb_big_rshift, 1); - rb_define_method(rb_cBignum, "[]", rb_big_aref, 1); - - rb_define_method(rb_cBignum, "<=>", rb_big_cmp, 1); - rb_define_method(rb_cBignum, "==", rb_big_eq, 1); - rb_define_method(rb_cBignum, "eql?", rb_big_eql, 1); - rb_define_method(rb_cBignum, "hash", rb_big_hash, 0); - rb_define_method(rb_cBignum, "to_f", rb_big_to_f, 0); - rb_define_method(rb_cBignum, "abs", rb_big_abs, 0); - rb_define_method(rb_cBignum, "size", rb_big_size, 0); -} -/********************************************************************** - - class.c - - - $Author: murphy $ - $Date: 2005-11-05 04:33:55 +0100 (Sa, 05 Nov 2005) $ - created at: Tue Aug 10 15:05:44 JST 1993 - - Copyright (C) 1993-2003 Yukihiro Matsumoto - -**********************************************************************/ - -#include "ruby.h" -#include "rubysig.h" -#include "node.h" -#include "st.h" -#include <ctype.h> - -extern st_table *rb_class_tbl; - -VALUE -rb_class_boot(super) - VALUE super; -{ - NEWOBJ(klass, struct RClass); - OBJSETUP(klass, rb_cClass, T_CLASS); - - klass->super = super; - klass->iv_tbl = 0; - klass->m_tbl = 0; /* safe GC */ - klass->m_tbl = st_init_numtable(); - - OBJ_INFECT(klass, super); - return (VALUE)klass; -} - -void -rb_check_inheritable(super) - VALUE super; -{ - if (TYPE(super) != T_CLASS) { - rb_raise(rb_eTypeError, "superclass must be a Class (%s given)", - rb_obj_classname(super)); - } - if (RBASIC(super)->flags & FL_SINGLETON) { - rb_raise(rb_eTypeError, "can't make subclass of singleton class"); - } -} - -VALUE -rb_class_new(super) - VALUE super; -{ - Check_Type(super, T_CLASS); - rb_check_inheritable(super); - if (super == rb_cClass) { - rb_raise(rb_eTypeError, "can't make subclass of Class"); - } - return rb_class_boot(super); -} - -static int -clone_method(mid, body, tbl) - ID mid; - NODE *body; - st_table *tbl; -{ - st_insert(tbl, mid, (st_data_t)NEW_METHOD(body->nd_body, body->nd_noex)); - return ST_CONTINUE; -} - -/* :nodoc: */ -VALUE -rb_mod_init_copy(clone, orig) - VALUE clone, orig; -{ - rb_obj_init_copy(clone, orig); - if (!FL_TEST(CLASS_OF(clone), FL_SINGLETON)) { - RBASIC(clone)->klass = rb_singleton_class_clone(orig); - } - RCLASS(clone)->super = RCLASS(orig)->super; - if (RCLASS(orig)->iv_tbl) { - ID id; - - RCLASS(clone)->iv_tbl = st_copy(RCLASS(orig)->iv_tbl); - id = rb_intern("__classpath__"); - st_delete(RCLASS(clone)->iv_tbl, (st_data_t*)&id, 0); - id = rb_intern("__classid__"); - st_delete(RCLASS(clone)->iv_tbl, (st_data_t*)&id, 0); - } - if (RCLASS(orig)->m_tbl) { - RCLASS(clone)->m_tbl = st_init_numtable(); - st_foreach(RCLASS(orig)->m_tbl, clone_method, - (st_data_t)RCLASS(clone)->m_tbl); - } - - return clone; -} - -/* :nodoc: */ -VALUE -rb_class_init_copy(clone, orig) - VALUE clone, orig; -{ - if (RCLASS(clone)->super != 0) { - rb_raise(rb_eTypeError, "already initialized class"); - } - return rb_mod_init_copy(clone, orig); -} - -VALUE -rb_singleton_class_clone(obj) - VALUE obj; -{ - VALUE klass = RBASIC(obj)->klass; - - if (!FL_TEST(klass, FL_SINGLETON)) - return klass; - else { - /* copy singleton(unnamed) class */ - NEWOBJ(clone, struct RClass); - OBJSETUP(clone, 0, RBASIC(klass)->flags); - - if (BUILTIN_TYPE(obj) == T_CLASS) { - RBASIC(clone)->klass = (VALUE)clone; - } - else { - RBASIC(clone)->klass = rb_singleton_class_clone(klass); - } - - clone->super = RCLASS(klass)->super; - clone->iv_tbl = 0; - clone->m_tbl = 0; - if (RCLASS(klass)->iv_tbl) { - clone->iv_tbl = st_copy(RCLASS(klass)->iv_tbl); - } - clone->m_tbl = st_init_numtable(); - st_foreach(RCLASS(klass)->m_tbl, clone_method, - (st_data_t)clone->m_tbl); - rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone); - FL_SET(clone, FL_SINGLETON); - return (VALUE)clone; - } -} - -void -rb_singleton_class_attached(klass, obj) - VALUE klass, obj; -{ - if (FL_TEST(klass, FL_SINGLETON)) { - if (!RCLASS(klass)->iv_tbl) { - RCLASS(klass)->iv_tbl = st_init_numtable(); - } - st_insert(RCLASS(klass)->iv_tbl, rb_intern("__attached__"), obj); - } -} - -VALUE -rb_make_metaclass(obj, super) - VALUE obj, super; -{ - if (BUILTIN_TYPE(obj) == T_CLASS && FL_TEST(obj, FL_SINGLETON)) { - return RBASIC(obj)->klass = rb_cClass; - } - else { - VALUE metasuper; - VALUE klass = rb_class_boot(super); - - FL_SET(klass, FL_SINGLETON); - RBASIC(obj)->klass = klass; - rb_singleton_class_attached(klass, obj); - - metasuper = RBASIC(rb_class_real(super))->klass; - /* metaclass of a superclass may be NULL at boot time */ - if (metasuper) { - RBASIC(klass)->klass = metasuper; - } - return klass; - } -} - -VALUE -rb_define_class_id(id, super) - ID id; - VALUE super; -{ - VALUE klass; - - if (!super) super = rb_cObject; - klass = rb_class_new(super); - rb_make_metaclass(klass, RBASIC(super)->klass); - - return klass; -} - -VALUE -rb_class_inherited(super, klass) - VALUE super, klass; -{ - if (!super) super = rb_cObject; - return rb_funcall(super, rb_intern("inherited"), 1, klass); -} - -VALUE -rb_define_class(name, super) - const char *name; - VALUE super; -{ - VALUE klass; - ID id; - - id = rb_intern(name); - if (rb_const_defined(rb_cObject, id)) { - klass = rb_const_get(rb_cObject, id); - if (TYPE(klass) != T_CLASS) { - rb_raise(rb_eTypeError, "%s is not a class", name); - } - if (rb_class_real(RCLASS(klass)->super) != super) { - rb_name_error(id, "%s is already defined", name); - } - return klass; - } - if (!super) { - rb_warn("no super class for `%s', Object assumed", name); - } - klass = rb_define_class_id(id, super); - st_add_direct(rb_class_tbl, id, klass); - rb_name_class(klass, id); - rb_const_set(rb_cObject, id, klass); - rb_class_inherited(super, klass); - - return klass; -} - -VALUE -rb_define_class_under(outer, name, super) - VALUE outer; - const char *name; - VALUE super; -{ - VALUE klass; - ID id; - - id = rb_intern(name); - if (rb_const_defined_at(outer, id)) { - klass = rb_const_get_at(outer, id); - if (TYPE(klass) != T_CLASS) { - rb_raise(rb_eTypeError, "%s is not a class", name); - } - if (rb_class_real(RCLASS(klass)->super) != super) { - rb_name_error(id, "%s is already defined", name); - } - return klass; - } - if (!super) { - rb_warn("no super class for `%s::%s', Object assumed", - rb_class2name(outer), name); - } - klass = rb_define_class_id(id, super); - rb_set_class_path(klass, outer, name); - rb_const_set(outer, id, klass); - rb_class_inherited(super, klass); - - return klass; -} - -VALUE -rb_module_new() -{ - NEWOBJ(mdl, struct RClass); - OBJSETUP(mdl, rb_cModule, T_MODULE); - - mdl->super = 0; - mdl->iv_tbl = 0; - mdl->m_tbl = 0; - mdl->m_tbl = st_init_numtable(); - - return (VALUE)mdl; -} - -VALUE -rb_define_module_id(id) - ID id; -{ - VALUE mdl; - - mdl = rb_module_new(); - rb_name_class(mdl, id); - - return mdl; -} - -VALUE -rb_define_module(name) - const char *name; -{ - VALUE module; - ID id; - - id = rb_intern(name); - if (rb_const_defined(rb_cObject, id)) { - module = rb_const_get(rb_cObject, id); - if (TYPE(module) == T_MODULE) - return module; - rb_raise(rb_eTypeError, "%s is not a module", rb_obj_classname(module)); - } - module = rb_define_module_id(id); - st_add_direct(rb_class_tbl, id, module); - rb_const_set(rb_cObject, id, module); - - return module; -} - -VALUE -rb_define_module_under(outer, name) - VALUE outer; - const char *name; -{ - VALUE module; - ID id; - - id = rb_intern(name); - if (rb_const_defined_at(outer, id)) { - module = rb_const_get_at(outer, id); - if (TYPE(module) == T_MODULE) - return module; - rb_raise(rb_eTypeError, "%s::%s is not a module", - rb_class2name(outer), rb_obj_classname(module)); - } - module = rb_define_module_id(id); - rb_const_set(outer, id, module); - rb_set_class_path(module, outer, name); - - return module; -} - -static VALUE -include_class_new(module, super) - VALUE module, super; -{ - NEWOBJ(klass, struct RClass); - OBJSETUP(klass, rb_cClass, T_ICLASS); - - if (BUILTIN_TYPE(module) == T_ICLASS) { - module = RBASIC(module)->klass; - } - if (!RCLASS(module)->iv_tbl) { - RCLASS(module)->iv_tbl = st_init_numtable(); - } - klass->iv_tbl = RCLASS(module)->iv_tbl; - klass->m_tbl = RCLASS(module)->m_tbl; - klass->super = super; - if (TYPE(module) == T_ICLASS) { - RBASIC(klass)->klass = RBASIC(module)->klass; - } - else { - RBASIC(klass)->klass = module; - } - OBJ_INFECT(klass, module); - OBJ_INFECT(klass, super); - - return (VALUE)klass; -} - -void -rb_include_module(klass, module) - VALUE klass, module; -{ - VALUE p, c; - int changed = 0; - - rb_frozen_class_p(klass); - if (!OBJ_TAINTED(klass)) { - rb_secure(4); - } - - if (NIL_P(module)) return; - if (klass == module) return; - - if (TYPE(module) != T_MODULE) { - Check_Type(module, T_MODULE); - } - - OBJ_INFECT(klass, module); - c = klass; - while (module) { - int superclass_seen = Qfalse; - - if (RCLASS(klass)->m_tbl == RCLASS(module)->m_tbl) - rb_raise(rb_eArgError, "cyclic include detected"); - /* ignore if the module included already in superclasses */ - for (p = RCLASS(klass)->super; p; p = RCLASS(p)->super) { - switch (BUILTIN_TYPE(p)) { - case T_ICLASS: - if (RCLASS(p)->m_tbl == RCLASS(module)->m_tbl) { - if (!superclass_seen) { - c = p; /* move insertion point */ - } - goto skip; - } - break; - case T_CLASS: - superclass_seen = Qtrue; - break; - } - } - c = RCLASS(c)->super = include_class_new(module, RCLASS(c)->super); - changed = 1; - skip: - module = RCLASS(module)->super; - } - if (changed) rb_clear_cache(); -} - -/* - * call-seq: - * mod.included_modules -> array - * - * Returns the list of modules included in <i>mod</i>. - * - * module Mixin - * end - * - * module Outer - * include Mixin - * end - * - * Mixin.included_modules #=> [] - * Outer.included_modules #=> [Mixin] - */ - -VALUE -rb_mod_included_modules(mod) - VALUE mod; -{ - VALUE ary = rb_ary_new(); - VALUE p; - - for (p = RCLASS(mod)->super; p; p = RCLASS(p)->super) { - if (BUILTIN_TYPE(p) == T_ICLASS) { - rb_ary_push(ary, RBASIC(p)->klass); - } - } - return ary; -} - -/* - * call-seq: - * mod.include?(module) => true or false - * - * Returns <code>true</code> if <i>module</i> is included in - * <i>mod</i> or one of <i>mod</i>'s ancestors. - * - * module A - * end - * class B - * include A - * end - * class C < B - * end - * B.include?(A) #=> true - * C.include?(A) #=> true - * A.include?(A) #=> false - */ - -VALUE -rb_mod_include_p(mod, mod2) - VALUE mod; - VALUE mod2; -{ - VALUE p; - - Check_Type(mod2, T_MODULE); - for (p = RCLASS(mod)->super; p; p = RCLASS(p)->super) { - if (BUILTIN_TYPE(p) == T_ICLASS) { - if (RBASIC(p)->klass == mod2) return Qtrue; - } - } - return Qfalse; -} - -/* - * call-seq: - * mod.ancestors -> array - * - * Returns a list of modules included in <i>mod</i> (including - * <i>mod</i> itself). - * - * module Mod - * include Math - * include Comparable - * end - * - * Mod.ancestors #=> [Mod, Comparable, Math] - * Math.ancestors #=> [Math] - */ - -VALUE -rb_mod_ancestors(mod) - VALUE mod; -{ - VALUE p, ary = rb_ary_new(); - - for (p = mod; p; p = RCLASS(p)->super) { - if (FL_TEST(p, FL_SINGLETON)) - continue; - if (BUILTIN_TYPE(p) == T_ICLASS) { - rb_ary_push(ary, RBASIC(p)->klass); - } - else { - rb_ary_push(ary, p); - } - } - return ary; -} - -#define VISI(x) ((x)&NOEX_MASK) -#define VISI_CHECK(x,f) (VISI(x) == (f)) - -static int -ins_methods_push(name, type, ary, visi) - ID name; - long type; - VALUE ary; - long visi; -{ - if (type == -1) return ST_CONTINUE; - switch (visi) { - case NOEX_PRIVATE: - case NOEX_PROTECTED: - case NOEX_PUBLIC: - visi = (type == visi); - break; - default: - visi = (type != NOEX_PRIVATE); - break; - } - if (visi) { - rb_ary_push(ary, rb_str_new2(rb_id2name(name))); - } - return ST_CONTINUE; -} - -static int -ins_methods_i(name, type, ary) - ID name; - long type; - VALUE ary; -{ - return ins_methods_push(name, type, ary, -1); /* everything but private */ -} - -static int -ins_methods_prot_i(name, type, ary) - ID name; - long type; - VALUE ary; -{ - return ins_methods_push(name, type, ary, NOEX_PROTECTED); -} - -static int -ins_methods_priv_i(name, type, ary) - ID name; - long type; - VALUE ary; -{ - return ins_methods_push(name, type, ary, NOEX_PRIVATE); -} - -static int -ins_methods_pub_i(name, type, ary) - ID name; - long type; - VALUE ary; -{ - return ins_methods_push(name, type, ary, NOEX_PUBLIC); -} - -static int -method_entry(key, body, list) - ID key; - NODE *body; - st_table *list; -{ - long type; - - if (key == ID_ALLOCATOR) return ST_CONTINUE; - if (!st_lookup(list, key, 0)) { - if (!body->nd_body) type = -1; /* none */ - else type = VISI(body->nd_noex); - st_add_direct(list, key, type); - } - return ST_CONTINUE; -} - -static VALUE -class_instance_method_list(argc, argv, mod, func) - int argc; - VALUE *argv; - VALUE mod; - int (*func) _((ID, long, VALUE)); -{ - VALUE ary; - int recur; - st_table *list; - - if (argc == 0) { - recur = Qtrue; - } - else { - VALUE r; - rb_scan_args(argc, argv, "01", &r); - recur = RTEST(r); - } - - list = st_init_numtable(); - for (; mod; mod = RCLASS(mod)->super) { - st_foreach(RCLASS(mod)->m_tbl, method_entry, (st_data_t)list); - if (BUILTIN_TYPE(mod) == T_ICLASS) continue; - if (FL_TEST(mod, FL_SINGLETON)) continue; - if (!recur) break; - } - ary = rb_ary_new(); - st_foreach(list, func, ary); - st_free_table(list); - - return ary; -} - -/* - * call-seq: - * mod.instance_methods(include_super=true) => array - * - * Returns an array containing the names of public instance methods in - * the receiver. For a module, these are the public methods; for a - * class, they are the instance (not singleton) methods. With no - * argument, or with an argument that is <code>false</code>, the - * instance methods in <i>mod</i> are returned, otherwise the methods - * in <i>mod</i> and <i>mod</i>'s superclasses are returned. - * - * module A - * def method1() end - * end - * class B - * def method2() end - * end - * class C < B - * def method3() end - * end - * - * A.instance_methods #=> ["method1"] - * B.instance_methods(false) #=> ["method2"] - * C.instance_methods(false) #=> ["method3"] - * C.instance_methods(true).length #=> 43 - */ - -VALUE -rb_class_instance_methods(argc, argv, mod) - int argc; - VALUE *argv; - VALUE mod; -{ - return class_instance_method_list(argc, argv, mod, ins_methods_i); -} - -/* - * call-seq: - * mod.protected_instance_methods(include_super=true) => array - * - * Returns a list of the protected instance methods defined in - * <i>mod</i>. If the optional parameter is not <code>false</code>, the - * methods of any ancestors are included. - */ - -VALUE -rb_class_protected_instance_methods(argc, argv, mod) - int argc; - VALUE *argv; - VALUE mod; -{ - return class_instance_method_list(argc, argv, mod, ins_methods_prot_i); -} - -/* - * call-seq: - * mod.private_instance_methods(include_super=true) => array - * - * Returns a list of the private instance methods defined in - * <i>mod</i>. If the optional parameter is not <code>false</code>, the - * methods of any ancestors are included. - * - * module Mod - * def method1() end - * private :method1 - * def method2() end - * end - * Mod.instance_methods #=> ["method2"] - * Mod.private_instance_methods #=> ["method1"] - */ - -VALUE -rb_class_private_instance_methods(argc, argv, mod) - int argc; - VALUE *argv; - VALUE mod; -{ - return class_instance_method_list(argc, argv, mod, ins_methods_priv_i); -} - -/* - * call-seq: - * mod.public_instance_methods(include_super=true) => array - * - * Returns a list of the public instance methods defined in <i>mod</i>. - * If the optional parameter is not <code>false</code>, the methods of - * any ancestors are included. - */ - -VALUE -rb_class_public_instance_methods(argc, argv, mod) - int argc; - VALUE *argv; - VALUE mod; -{ - return class_instance_method_list(argc, argv, mod, ins_methods_pub_i); -} - -/* - * call-seq: - * obj.singleton_methods(all=true) => array - * - * Returns an array of the names of singleton methods for <i>obj</i>. - * If the optional <i>all</i> parameter is true, the list will include - * methods in modules included in <i>obj</i>. - * - * module Other - * def three() end - * end - * - * class Single - * def Single.four() end - * end - * - * a = Single.new - * - * def a.one() - * end - * - * class << a - * include Other - * def two() - * end - * end - * - * Single.singleton_methods #=> ["four"] - * a.singleton_methods(false) #=> ["two", "one"] - * a.singleton_methods #=> ["two", "one", "three"] - */ - -VALUE -rb_obj_singleton_methods(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - VALUE recur, ary, klass; - st_table *list; - - rb_scan_args(argc, argv, "01", &recur); - if (argc == 0) { - recur = Qtrue; - } - klass = CLASS_OF(obj); - list = st_init_numtable(); - if (klass && FL_TEST(klass, FL_SINGLETON)) { - st_foreach(RCLASS(klass)->m_tbl, method_entry, (st_data_t)list); - klass = RCLASS(klass)->super; - } - if (RTEST(recur)) { - while (klass && (FL_TEST(klass, FL_SINGLETON) || TYPE(klass) == T_ICLASS)) { - st_foreach(RCLASS(klass)->m_tbl, method_entry, (st_data_t)list); - klass = RCLASS(klass)->super; - } - } - ary = rb_ary_new(); - st_foreach(list, ins_methods_i, ary); - st_free_table(list); - - return ary; -} - -void -rb_define_method_id(klass, name, func, argc) - VALUE klass; - ID name; - VALUE (*func)(); - int argc; -{ - rb_add_method(klass, name, NEW_CFUNC(func,argc), NOEX_PUBLIC); -} - -void -rb_define_method(klass, name, func, argc) - VALUE klass; - const char *name; - VALUE (*func)(); - int argc; -{ - rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc), NOEX_PUBLIC); -} - -void -rb_define_protected_method(klass, name, func, argc) - VALUE klass; - const char *name; - VALUE (*func)(); - int argc; -{ - rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc), NOEX_PROTECTED); -} - -void -rb_define_private_method(klass, name, func, argc) - VALUE klass; - const char *name; - VALUE (*func)(); - int argc; -{ - rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc), NOEX_PRIVATE); -} - -void -rb_undef_method(klass, name) - VALUE klass; - const char *name; -{ - rb_add_method(klass, rb_intern(name), 0, NOEX_UNDEF); -} - -#define SPECIAL_SINGLETON(x,c) do {\ - if (obj == (x)) {\ - return c;\ - }\ -} while (0) - -VALUE -rb_singleton_class(obj) - VALUE obj; -{ - VALUE klass; - - if (FIXNUM_P(obj) || SYMBOL_P(obj)) { - rb_raise(rb_eTypeError, "can't define singleton"); - } - if (rb_special_const_p(obj)) { - SPECIAL_SINGLETON(Qnil, rb_cNilClass); - SPECIAL_SINGLETON(Qfalse, rb_cFalseClass); - SPECIAL_SINGLETON(Qtrue, rb_cTrueClass); - rb_bug("unknown immediate %ld", obj); - } - - DEFER_INTS; - if (FL_TEST(RBASIC(obj)->klass, FL_SINGLETON) && - rb_iv_get(RBASIC(obj)->klass, "__attached__") == obj) { - klass = RBASIC(obj)->klass; - } - else { - klass = rb_make_metaclass(obj, RBASIC(obj)->klass); - } - if (OBJ_TAINTED(obj)) { - OBJ_TAINT(klass); - } - else { - FL_UNSET(klass, FL_TAINT); - } - if (OBJ_FROZEN(obj)) OBJ_FREEZE(klass); - ALLOW_INTS; - - return klass; -} - -void -rb_define_singleton_method(obj, name, func, argc) - VALUE obj; - const char *name; - VALUE (*func)(); - int argc; -{ - rb_define_method(rb_singleton_class(obj), name, func, argc); -} - -void -rb_define_module_function(module, name, func, argc) - VALUE module; - const char *name; - VALUE (*func)(); - int argc; -{ - rb_define_private_method(module, name, func, argc); - rb_define_singleton_method(module, name, func, argc); -} - -void -rb_define_global_function(name, func, argc) - const char *name; - VALUE (*func)(); - int argc; -{ - rb_define_module_function(rb_mKernel, name, func, argc); -} - -void -rb_define_alias(klass, name1, name2) - VALUE klass; - const char *name1, *name2; -{ - rb_alias(klass, rb_intern(name1), rb_intern(name2)); -} - -void -rb_define_attr(klass, name, read, write) - VALUE klass; - const char *name; - int read, write; -{ - rb_attr(klass, rb_intern(name), read, write, Qfalse); -} - -#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 - -int -#ifdef HAVE_STDARG_PROTOTYPES -rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...) -#else -rb_scan_args(argc, argv, fmt, va_alist) - int argc; - const VALUE *argv; - const char *fmt; - va_dcl -#endif -{ - int n, i = 0; - const char *p = fmt; - VALUE *var; - va_list vargs; - - va_init_list(vargs, fmt); - - if (*p == '*') goto rest_arg; - - if (ISDIGIT(*p)) { - n = *p - '0'; - if (n > argc) - rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, n); - for (i=0; i<n; i++) { - var = va_arg(vargs, VALUE*); - if (var) *var = argv[i]; - } - p++; - } - else { - goto error; - } - - if (ISDIGIT(*p)) { - n = i + *p - '0'; - for (; i<n; i++) { - var = va_arg(vargs, VALUE*); - if (argc > i) { - if (var) *var = argv[i]; - } - else { - if (var) *var = Qnil; - } - } - p++; - } - - if(*p == '*') { - rest_arg: - var = va_arg(vargs, VALUE*); - if (argc > i) { - if (var) *var = rb_ary_new4(argc-i, argv+i); - i = argc; - } - else { - if (var) *var = rb_ary_new(); - } - p++; - } - - if (*p == '&') { - var = va_arg(vargs, VALUE*); - if (rb_block_given_p()) { - *var = rb_block_proc(); - } - else { - *var = Qnil; - } - p++; - } - va_end(vargs); - - if (*p != '\0') { - goto error; - } - - if (argc > i) { - rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, i); - } - - return argc; - - error: - rb_fatal("bad scan arg format: %s", fmt); - return 0; -} -/********************************************************************** - - compar.c - - - $Author: murphy $ - $Date: 2005-11-05 04:33:55 +0100 (Sa, 05 Nov 2005) $ - created at: Thu Aug 26 14:39:48 JST 1993 - - Copyright (C) 1993-2003 Yukihiro Matsumoto - -**********************************************************************/ - -#include "ruby.h" - -VALUE rb_mComparable; - -static ID cmp; - -int -rb_cmpint(val, a, b) - VALUE val, a, b; -{ - if (NIL_P(val)) { - rb_cmperr(a, b); - } - if (FIXNUM_P(val)) return FIX2INT(val); - if (TYPE(val) == T_BIGNUM) { - if (RBIGNUM(val)->sign) return 1; - return -1; - } - if (RTEST(rb_funcall(val, '>', 1, INT2FIX(0)))) return 1; - if (RTEST(rb_funcall(val, '<', 1, INT2FIX(0)))) return -1; - return 0; -} - -void -rb_cmperr(x, y) - VALUE x, y; -{ - const char *classname; - - if (SPECIAL_CONST_P(y)) { - y = rb_inspect(y); - classname = StringValuePtr(y); - } - else { - classname = rb_obj_classname(y); - } - rb_raise(rb_eArgError, "comparison of %s with %s failed", - rb_obj_classname(x), classname); -} - -static VALUE -cmp_eq(a) - VALUE *a; -{ - VALUE c = rb_funcall(a[0], cmp, 1, a[1]); - - if (NIL_P(c)) return Qnil; - if (rb_cmpint(c, a[0], a[1]) == 0) return Qtrue; - return Qfalse; -} - -static VALUE -cmp_failed() -{ - return Qnil; -} - -/* - * call-seq: - * obj == other => true or false - * - * Compares two objects based on the receiver's <code><=></code> - * method, returning true if it returns 0. Also returns true if - * _obj_ and _other_ are the same object. - */ - -static VALUE -cmp_equal(x, y) - VALUE x, y; -{ - VALUE a[2]; - - if (x == y) return Qtrue; - - a[0] = x; a[1] = y; - return rb_rescue(cmp_eq, (VALUE)a, cmp_failed, 0); -} - -/* - * call-seq: - * obj > other => true or false - * - * Compares two objects based on the receiver's <code><=></code> - * method, returning true if it returns 1. - */ - -static VALUE -cmp_gt(x, y) - VALUE x, y; -{ - VALUE c = rb_funcall(x, cmp, 1, y); - - if (rb_cmpint(c, x, y) > 0) return Qtrue; - return Qfalse; -} - -/* - * call-seq: - * obj >= other => true or false - * - * Compares two objects based on the receiver's <code><=></code> - * method, returning true if it returns 0 or 1. - */ - -static VALUE -cmp_ge(x, y) - VALUE x, y; -{ - VALUE c = rb_funcall(x, cmp, 1, y); - - if (rb_cmpint(c, x, y) >= 0) return Qtrue; - return Qfalse; -} - -/* - * call-seq: - * obj < other => true or false - * - * Compares two objects based on the receiver's <code><=></code> - * method, returning true if it returns -1. - */ - -static VALUE -cmp_lt(x, y) - VALUE x, y; -{ - VALUE c = rb_funcall(x, cmp, 1, y); - - if (rb_cmpint(c, x, y) < 0) return Qtrue; - return Qfalse; -} - - -/* - * call-seq: - * obj <= other => true or false - * - * Compares two objects based on the receiver's <code><=></code> - * method, returning true if it returns -1 or 0. - */ - -static VALUE -cmp_le(x, y) - VALUE x, y; -{ - VALUE c = rb_funcall(x, cmp, 1, y); - - if (rb_cmpint(c, x, y) <= 0) return Qtrue; - return Qfalse; -} - -/* - * call-seq: - * obj.between?(min, max) => true or false - * - * Returns <code>false</code> if <i>obj</i> <code><=></code> - * <i>min</i> is less than zero or if <i>anObject</i> <code><=></code> - * <i>max</i> is greater than zero, <code>true</code> otherwise. - * - * 3.between?(1, 5) #=> true - * 6.between?(1, 5) #=> false - * 'cat'.between?('ant', 'dog') #=> true - * 'gnu'.between?('ant', 'dog') #=> false - * - */ - -static VALUE -cmp_between(x, min, max) - VALUE x, min, max; -{ - if (RTEST(cmp_lt(x, min))) return Qfalse; - if (RTEST(cmp_gt(x, max))) return Qfalse; - return Qtrue; -} - -/* - * The <code>Comparable</code> mixin is used by classes whose objects - * may be ordered. The class must define the <code><=></code> operator, - * which compares the receiver against another object, returning -1, 0, - * or +1 depending on whether the receiver is less than, equal to, or - * greater than the other object. <code>Comparable</code> uses - * <code><=></code> to implement the conventional comparison operators - * (<code><</code>, <code><=</code>, <code>==</code>, <code>>=</code>, - * and <code>></code>) and the method <code>between?</code>. - * - * class SizeMatters - * include Comparable - * attr :str - * def <=>(anOther) - * str.size <=> anOther.str.size - * end - * def initialize(str) - * @str = str - * end - * def inspect - * @str - * end - * end - * - * s1 = SizeMatters.new("Z") - * s2 = SizeMatters.new("YY") - * s3 = SizeMatters.new("XXX") - * s4 = SizeMatters.new("WWWW") - * s5 = SizeMatters.new("VVVVV") - * - * s1 < s2 #=> true - * s4.between?(s1, s3) #=> false - * s4.between?(s3, s5) #=> true - * [ s3, s2, s5, s4, s1 ].sort #=> [Z, YY, XXX, WWWW, VVVVV] - * - */ - -void -Init_Comparable() -{ - rb_mComparable = rb_define_module("Comparable"); - rb_define_method(rb_mComparable, "==", cmp_equal, 1); - rb_define_method(rb_mComparable, ">", cmp_gt, 1); - rb_define_method(rb_mComparable, ">=", cmp_ge, 1); - rb_define_method(rb_mComparable, "<", cmp_lt, 1); - rb_define_method(rb_mComparable, "<=", cmp_le, 1); - rb_define_method(rb_mComparable, "between?", cmp_between, 2); - - cmp = rb_intern("<=>"); -} -/********************************************************************** - - dir.c - - - $Author: murphy $ - $Date: 2005-11-05 04:33:55 +0100 (Sa, 05 Nov 2005) $ - created at: Wed Jan 5 09:51:01 JST 1994 - - 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 <sys/types.h> -#include <sys/stat.h> - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#if defined HAVE_DIRENT_H && !defined _WIN32 -# include <dirent.h> -# define NAMLEN(dirent) strlen((dirent)->d_name) -#elif defined HAVE_DIRECT_H && !defined _WIN32 -# include <direct.h> -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# if !defined __NeXT__ -# define NAMLEN(dirent) (dirent)->d_namlen -# else -# /* On some versions of NextStep, d_namlen is always zero, so avoid it. */ -# define NAMLEN(dirent) strlen((dirent)->d_name) -# endif -# if HAVE_SYS_NDIR_H -# include <sys/ndir.h> -# endif -# if HAVE_SYS_DIR_H -# include <sys/dir.h> -# endif -# if HAVE_NDIR_H -# include <ndir.h> -# endif -# ifdef _WIN32 -# include "win32/dir.h" -# endif -#endif - -#include <errno.h> - -#ifndef HAVE_STDLIB_H -char *getenv(); -#endif - -#ifndef HAVE_STRING_H -char *strchr _((char*,char)); -#endif - -#include <ctype.h> - -#include "util.h" - -#if !defined HAVE_LSTAT && !defined lstat -#define lstat stat -#endif - -#define FNM_NOESCAPE 0x01 -#define FNM_PATHNAME 0x02 -#define FNM_DOTMATCH 0x04 -#define FNM_CASEFOLD 0x08 - -#define FNM_NOMATCH 1 -#define FNM_ERROR 2 - -#define downcase(c) (nocase && ISUPPER(c) ? tolower(c) : (c)) -#define compare(c1, c2) (((unsigned char)(c1)) - ((unsigned char)(c2))) - -/* caution: in case *p == '\0' - Next(p) == p + 1 in single byte environment - Next(p) == p in multi byte environment -*/ -#if defined(CharNext) -# define Next(p) CharNext(p) -#elif defined(DJGPP) -# define Next(p) ((p) + mblen(p, RUBY_MBCHAR_MAXSIZE)) -#elif defined(__EMX__) -# define Next(p) ((p) + emx_mblen(p)) -static inline int -emx_mblen(p) - const char *p; -{ - int n = mblen(p, RUBY_MBCHAR_MAXSIZE); - return (n < 0) ? 1 : n; -} -#endif - -#ifndef Next /* single byte environment */ -# define Next(p) ((p) + 1) -# define Inc(p) (++(p)) -# define Compare(p1, p2) (compare(downcase(*(p1)), downcase(*(p2)))) -#else /* multi byte environment */ -# define Inc(p) ((p) = Next(p)) -# define Compare(p1, p2) (CompareImpl(p1, p2, nocase)) -static int -CompareImpl(p1, p2, nocase) - const char *p1; - const char *p2; - int nocase; -{ - const int len1 = Next(p1) - p1; - const int len2 = Next(p2) - p2; -#ifdef _WIN32 - char buf1[10], buf2[10]; /* large enough? */ -#endif - - if (len1 < 0 || len2 < 0) { - rb_fatal("CompareImpl: negative len"); - } - - if (len1 == 0) return len2; - if (len2 == 0) return -len1; - -#ifdef _WIN32 - if (nocase) { - if (len1 > 1) { - if (len1 >= sizeof(buf1)) { - rb_fatal("CompareImpl: too large len"); - } - memcpy(buf1, p1, len1); - buf1[len1] = '\0'; - CharLower(buf1); - p1 = buf1; /* trick */ - } - if (len2 > 1) { - if (len2 >= sizeof(buf2)) { - rb_fatal("CompareImpl: too large len"); - } - memcpy(buf2, p2, len2); - buf2[len2] = '\0'; - CharLower(buf2); - p2 = buf2; /* trick */ - } - } -#endif - if (len1 == 1) - if (len2 == 1) - return compare(downcase(*p1), downcase(*p2)); - else { - const int ret = compare(downcase(*p1), *p2); - return ret ? ret : -1; - } - else - if (len2 == 1) { - const int ret = compare(*p1, downcase(*p2)); - return ret ? ret : 1; - } - else { - const int ret = memcmp(p1, p2, len1 < len2 ? len1 : len2); - return ret ? ret : len1 - len2; - } -} -#endif /* environment */ - -static char * -bracket(p, s, flags) - const char *p; /* pattern (next to '[') */ - const char *s; /* string */ - int flags; -{ - const int nocase = flags & FNM_CASEFOLD; - const int escape = !(flags & FNM_NOESCAPE); - - int ok = 0, not = 0; - - if (*p == '!' || *p == '^') { - not = 1; - p++; - } - - while (*p != ']') { - const char *t1 = p; - if (escape && *t1 == '\\') - t1++; - if (!*t1) - return NULL; - p = Next(t1); - if (p[0] == '-' && p[1] != ']') { - const char *t2 = p + 1; - if (escape && *t2 == '\\') - t2++; - if (!*t2) - return NULL; - p = Next(t2); - if (!ok && Compare(t1, s) <= 0 && Compare(s, t2) <= 0) - ok = 1; - } - else - if (!ok && Compare(t1, s) == 0) - ok = 1; - } - - return ok == not ? NULL : (char *)p + 1; -} - -/* If FNM_PATHNAME is set, only path element will be matched. (upto '/' or '\0') - Otherwise, entire string will be matched. - End marker itself won't be compared. - And if function succeeds, *pcur reaches end marker. -*/ -#define UNESCAPE(p) (escape && *(p) == '\\' ? (p) + 1 : (p)) -#define ISEND(p) (!*(p) || (pathname && *(p) == '/')) -#define RETURN(val) return *pcur = p, *scur = s, (val); - -static int -fnmatch_helper(pcur, scur, flags) - const char **pcur; /* pattern */ - const char **scur; /* string */ - int flags; -{ - const int period = !(flags & FNM_DOTMATCH); - const int pathname = flags & FNM_PATHNAME; - const int escape = !(flags & FNM_NOESCAPE); - const int nocase = flags & FNM_CASEFOLD; - - const char *ptmp = 0; - const char *stmp = 0; - - const char *p = *pcur; - const char *s = *scur; - - if (period && *s == '.' && *UNESCAPE(p) != '.') /* leading period */ - RETURN(FNM_NOMATCH); - - while (1) { - switch (*p) { - case '*': - do { p++; } while (*p == '*'); - if (ISEND(UNESCAPE(p))) { - p = UNESCAPE(p); - RETURN(0); - } - if (ISEND(s)) - RETURN(FNM_NOMATCH); - ptmp = p; - stmp = s; - continue; - - case '?': - if (ISEND(s)) - RETURN(FNM_NOMATCH); - p++; - Inc(s); - continue; - - case '[': { - const char *t; - if (ISEND(s)) - RETURN(FNM_NOMATCH); - if (t = bracket(p + 1, s, flags)) { - p = t; - Inc(s); - continue; - } - goto failed; - } - } - - /* ordinary */ - p = UNESCAPE(p); - if (ISEND(s)) - RETURN(ISEND(p) ? 0 : FNM_NOMATCH); - if (ISEND(p)) - goto failed; - if (Compare(p, s) != 0) - goto failed; - Inc(p); - Inc(s); - continue; - - failed: /* try next '*' position */ - if (ptmp && stmp) { - p = ptmp; - Inc(stmp); /* !ISEND(*stmp) */ - s = stmp; - continue; - } - RETURN(FNM_NOMATCH); - } -} - -static int -fnmatch(p, s, flags) - const char *p; /* pattern */ - const char *s; /* string */ - int flags; -{ - const int period = !(flags & FNM_DOTMATCH); - const int pathname = flags & FNM_PATHNAME; - - const char *ptmp = 0; - const char *stmp = 0; - - if (pathname) { - while (1) { - if (p[0] == '*' && p[1] == '*' && p[2] == '/') { - do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/'); - ptmp = p; - stmp = s; - } - if (fnmatch_helper(&p, &s, flags) == 0) { - while (*s && *s != '/') Inc(s); - if (*p && *s) { - p++; - s++; - continue; - } - if (!*p && !*s) - return 0; - } - /* failed : try next recursion */ - if (ptmp && stmp && !(period && *stmp == '.')) { - while (*stmp && *stmp != '/') Inc(stmp); - if (*stmp) { - p = ptmp; - stmp++; - s = stmp; - continue; - } - } - return FNM_NOMATCH; - } - } - else - return fnmatch_helper(&p, &s, flags); -} - -VALUE rb_cDir; - -struct dir_data { - DIR *dir; - char *path; -}; - -static void -free_dir(dir) - struct dir_data *dir; -{ - if (dir) { - if (dir->dir) closedir(dir->dir); - if (dir->path) free(dir->path); - } - free(dir); -} - -static VALUE dir_close _((VALUE)); - -static VALUE dir_s_alloc _((VALUE)); -static VALUE -dir_s_alloc(klass) - VALUE klass; -{ - struct dir_data *dirp; - VALUE obj = Data_Make_Struct(klass, struct dir_data, 0, free_dir, dirp); - - dirp->dir = NULL; - dirp->path = NULL; - - return obj; -} - -/* - * call-seq: - * Dir.new( string ) -> aDir - * - * Returns a new directory object for the named directory. - */ -static VALUE -dir_initialize(dir, dirname) - VALUE dir, dirname; -{ - struct dir_data *dp; - - FilePathValue(dirname); - Data_Get_Struct(dir, struct dir_data, dp); - if (dp->dir) closedir(dp->dir); - if (dp->path) free(dp->path); - dp->dir = NULL; - dp->path = NULL; - dp->dir = opendir(RSTRING(dirname)->ptr); - if (dp->dir == NULL) { - if (errno == EMFILE || errno == ENFILE) { - rb_gc(); - dp->dir = opendir(RSTRING(dirname)->ptr); - } - if (dp->dir == NULL) { - rb_sys_fail(RSTRING(dirname)->ptr); - } - } - dp->path = strdup(RSTRING(dirname)->ptr); - - return dir; -} - -/* - * call-seq: - * Dir.open( string ) => aDir - * Dir.open( string ) {| aDir | block } => anObject - * - * With no block, <code>open</code> is a synonym for - * <code>Dir::new</code>. If a block is present, it is passed - * <i>aDir</i> as a parameter. The directory is closed at the end of - * the block, and <code>Dir::open</code> returns the value of the - * block. - */ -static VALUE -dir_s_open(klass, dirname) - VALUE klass, dirname; -{ - struct dir_data *dp; - VALUE dir = Data_Make_Struct(klass, struct dir_data, 0, free_dir, dp); - - dir_initialize(dir, dirname); - if (rb_block_given_p()) { - return rb_ensure(rb_yield, dir, dir_close, dir); - } - - return dir; -} - -static void -dir_closed() -{ - rb_raise(rb_eIOError, "closed directory"); -} - -#define GetDIR(obj, dirp) do {\ - Data_Get_Struct(obj, struct dir_data, dirp);\ - if (dirp->dir == NULL) dir_closed();\ -} while (0) - -/* - * call-seq: - * dir.inspect => string - * - * Return a string describing this Dir object. - */ -static VALUE -dir_inspect(dir) - VALUE dir; -{ - struct dir_data *dirp; - - GetDIR(dir, dirp); - if (dirp->path) { - char *c = rb_obj_classname(dir); - int len = strlen(c) + strlen(dirp->path) + 4; - VALUE s = rb_str_new(0, len); - snprintf(RSTRING(s)->ptr, len+1, "#<%s:%s>", c, dirp->path); - return s; - } - return rb_funcall(dir, rb_intern("to_s"), 0, 0); -} - -/* - * call-seq: - * dir.path => string or nil - * - * Returns the path parameter passed to <em>dir</em>'s constructor. - * - * d = Dir.new("..") - * d.path #=> ".." - */ -static VALUE -dir_path(dir) - VALUE dir; -{ - struct dir_data *dirp; - - GetDIR(dir, dirp); - if (!dirp->path) return Qnil; - return rb_str_new2(dirp->path); -} - -/* - * call-seq: - * dir.read => string or nil - * - * Reads the next entry from <em>dir</em> and returns it as a string. - * Returns <code>nil</code> at the end of the stream. - * - * d = Dir.new("testdir") - * d.read #=> "." - * d.read #=> ".." - * d.read #=> "config.h" - */ -static VALUE -dir_read(dir) - VALUE dir; -{ - struct dir_data *dirp; - struct dirent *dp; - - GetDIR(dir, dirp); - errno = 0; - dp = readdir(dirp->dir); - if (dp) { - return rb_tainted_str_new(dp->d_name, NAMLEN(dp)); - } - else if (errno == 0) { /* end of stream */ - return Qnil; - } - else { - rb_sys_fail(0); - } - return Qnil; /* not reached */ -} - -/* - * call-seq: - * dir.each { |filename| block } => dir - * - * Calls the block once for each entry in this directory, passing the - * filename of each entry as a parameter to the block. - * - * d = Dir.new("testdir") - * d.each {|x| puts "Got #{x}" } - * - * <em>produces:</em> - * - * Got . - * Got .. - * Got config.h - * Got main.rb - */ -static VALUE -dir_each(dir) - VALUE dir; -{ - struct dir_data *dirp; - struct dirent *dp; - - GetDIR(dir, dirp); - for (dp = readdir(dirp->dir); dp != NULL; dp = readdir(dirp->dir)) { - rb_yield(rb_tainted_str_new(dp->d_name, NAMLEN(dp))); - if (dirp->dir == NULL) dir_closed(); - } - return dir; -} - -/* - * call-seq: - * dir.pos => integer - * dir.tell => integer - * - * Returns the current position in <em>dir</em>. See also - * <code>Dir#seek</code>. - * - * d = Dir.new("testdir") - * d.tell #=> 0 - * d.read #=> "." - * d.tell #=> 12 - */ -static VALUE -dir_tell(dir) - VALUE dir; -{ -#ifdef HAVE_TELLDIR - struct dir_data *dirp; - long pos; - - GetDIR(dir, dirp); - pos = telldir(dirp->dir); - return rb_int2inum(pos); -#else - rb_notimplement(); -#endif -} - -/* - * call-seq: - * dir.seek( integer ) => dir - * - * Seeks to a particular location in <em>dir</em>. <i>integer</i> - * must be a value returned by <code>Dir#tell</code>. - * - * d = Dir.new("testdir") #=> #<Dir:0x401b3c40> - * d.read #=> "." - * i = d.tell #=> 12 - * d.read #=> ".." - * d.seek(i) #=> #<Dir:0x401b3c40> - * d.read #=> ".." - */ -static VALUE -dir_seek(dir, pos) - VALUE dir, pos; -{ - struct dir_data *dirp; - off_t p = NUM2OFFT(pos); - - GetDIR(dir, dirp); -#ifdef HAVE_SEEKDIR - seekdir(dirp->dir, p); - return dir; -#else - rb_notimplement(); -#endif -} - -/* - * call-seq: - * dir.pos( integer ) => integer - * - * Synonym for <code>Dir#seek</code>, but returns the position - * parameter. - * - * d = Dir.new("testdir") #=> #<Dir:0x401b3c40> - * d.read #=> "." - * i = d.pos #=> 12 - * d.read #=> ".." - * d.pos = i #=> 12 - * d.read #=> ".." - */ -static VALUE -dir_set_pos(dir, pos) - VALUE dir, pos; -{ - dir_seek(dir, pos); - return pos; -} - -/* - * call-seq: - * dir.rewind => dir - * - * Repositions <em>dir</em> to the first entry. - * - * d = Dir.new("testdir") - * d.read #=> "." - * d.rewind #=> #<Dir:0x401b3fb0> - * d.read #=> "." - */ -static VALUE -dir_rewind(dir) - VALUE dir; -{ - struct dir_data *dirp; - - GetDIR(dir, dirp); - rewinddir(dirp->dir); - return dir; -} - -/* - * call-seq: - * dir.close => nil - * - * Closes the directory stream. Any further attempts to access - * <em>dir</em> will raise an <code>IOError</code>. - * - * d = Dir.new("testdir") - * d.close #=> nil - */ -static VALUE -dir_close(dir) - VALUE dir; -{ - struct dir_data *dirp; - - GetDIR(dir, dirp); - closedir(dirp->dir); - dirp->dir = NULL; - - return Qnil; -} - -static void -dir_chdir(path) - VALUE path; -{ - if (chdir(RSTRING(path)->ptr) < 0) - rb_sys_fail(RSTRING(path)->ptr); -} - -static int chdir_blocking = 0; -static VALUE chdir_thread = Qnil; - -struct chdir_data { - VALUE old_path, new_path; - int done; -}; - -static VALUE -chdir_yield(args) - struct chdir_data *args; -{ - dir_chdir(args->new_path); - args->done = Qtrue; - chdir_blocking++; - if (chdir_thread == Qnil) - chdir_thread = rb_thread_current(); - return rb_yield(args->new_path); -} - -static VALUE -chdir_restore(args) - struct chdir_data *args; -{ - if (args->done) { - chdir_blocking--; - if (chdir_blocking == 0) - chdir_thread = Qnil; - dir_chdir(args->old_path); - } - return Qnil; -} - -/* - * call-seq: - * Dir.chdir( [ string] ) => 0 - * Dir.chdir( [ string] ) {| path | block } => anObject - * - * Changes the current working directory of the process to the given - * string. When called without an argument, changes the directory to - * the value of the environment variable <code>HOME</code>, or - * <code>LOGDIR</code>. <code>SystemCallError</code> (probably - * <code>Errno::ENOENT</code>) if the target directory does not exist. - * - * If a block is given, it is passed the name of the new current - * directory, and the block is executed with that as the current - * directory. The original working directory is restored when the block - * exits. The return value of <code>chdir</code> is the value of the - * block. <code>chdir</code> blocks can be nested, but in a - * multi-threaded program an error will be raised if a thread attempts - * to open a <code>chdir</code> block while another thread has one - * open. - * - * Dir.chdir("/var/spool/mail") - * puts Dir.pwd - * Dir.chdir("/tmp") do - * puts Dir.pwd - * Dir.chdir("/usr") do - * puts Dir.pwd - * end - * puts Dir.pwd - * end - * puts Dir.pwd - * - * <em>produces:</em> - * - * /var/spool/mail - * /tmp - * /usr - * /tmp - * /var/spool/mail - */ -static VALUE -dir_s_chdir(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - VALUE path = Qnil; - - rb_secure(2); - if (rb_scan_args(argc, argv, "01", &path) == 1) { - FilePathValue(path); - } - else { - const char *dist = getenv("HOME"); - if (!dist) { - dist = getenv("LOGDIR"); - if (!dist) rb_raise(rb_eArgError, "HOME/LOGDIR not set"); - } - path = rb_str_new2(dist); - } - - if (chdir_blocking > 0) { - if (!rb_block_given_p() || rb_thread_current() != chdir_thread) - rb_warn("conflicting chdir during another chdir block"); - } - - if (rb_block_given_p()) { - struct chdir_data args; - char *cwd = my_getcwd(); - - args.old_path = rb_tainted_str_new2(cwd); free(cwd); - args.new_path = path; - args.done = Qfalse; - return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args); - } - dir_chdir(path); - - return INT2FIX(0); -} - -/* - * call-seq: - * Dir.getwd => string - * Dir.pwd => string - * - * Returns the path to the current working directory of this process as - * a string. - * - * Dir.chdir("/tmp") #=> 0 - * Dir.getwd #=> "/tmp" - */ -static VALUE -dir_s_getwd(dir) - VALUE dir; -{ - char *path; - VALUE cwd; - - rb_secure(4); - path = my_getcwd(); - cwd = rb_tainted_str_new2(path); - - free(path); - return cwd; -} - -static void check_dirname _((volatile VALUE *)); -static void -check_dirname(dir) - volatile VALUE *dir; -{ - char *path, *pend; - - rb_secure(2); - FilePathValue(*dir); - path = RSTRING(*dir)->ptr; - if (path && *(pend = rb_path_end(rb_path_skip_prefix(path)))) { - *dir = rb_str_new(path, pend - path); - } -} - -/* - * call-seq: - * Dir.chroot( string ) => 0 - * - * Changes this process's idea of the file system root. Only a - * privileged process may make this call. Not available on all - * platforms. On Unix systems, see <code>chroot(2)</code> for more - * information. - */ -static VALUE -dir_s_chroot(dir, path) - VALUE dir, path; -{ -#if defined(HAVE_CHROOT) && !defined(__CHECKER__) - check_dirname(&path); - - if (chroot(RSTRING(path)->ptr) == -1) - rb_sys_fail(RSTRING(path)->ptr); - - return INT2FIX(0); -#else - rb_notimplement(); - return Qnil; /* not reached */ -#endif -} - -/* - * call-seq: - * Dir.mkdir( string [, integer] ) => 0 - * - * Makes a new directory named by <i>string</i>, with permissions - * specified by the optional parameter <i>anInteger</i>. The - * permissions may be modified by the value of - * <code>File::umask</code>, and are ignored on NT. Raises a - * <code>SystemCallError</code> if the directory cannot be created. See - * also the discussion of permissions in the class documentation for - * <code>File</code>. - * - */ -static VALUE -dir_s_mkdir(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - VALUE path, vmode; - int mode; - - if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) { - mode = NUM2INT(vmode); - } - else { - mode = 0777; - } - - check_dirname(&path); - if (mkdir(RSTRING(path)->ptr, mode) == -1) - rb_sys_fail(RSTRING(path)->ptr); - - return INT2FIX(0); -} - -/* - * call-seq: - * Dir.delete( string ) => 0 - * Dir.rmdir( string ) => 0 - * Dir.unlink( string ) => 0 - * - * Deletes the named directory. Raises a subclass of - * <code>SystemCallError</code> if the directory isn't empty. - */ -static VALUE -dir_s_rmdir(obj, dir) - VALUE obj, dir; -{ - check_dirname(&dir); - if (rmdir(RSTRING(dir)->ptr) < 0) - rb_sys_fail(RSTRING(dir)->ptr); - - return INT2FIX(0); -} - -/* System call with warning */ -static int -do_stat(path, pst) - const char *path; - struct stat *pst; -{ - int ret = stat(path, pst); - if (ret < 0 && errno != ENOENT) - rb_sys_warning(path); - - return ret; -} - -static int -do_lstat(path, pst) - const char *path; - struct stat *pst; -{ - int ret = lstat(path, pst); - if (ret < 0 && errno != ENOENT) - rb_sys_warning(path); - - return ret; -} - -static DIR * -do_opendir(path) - const char *path; -{ - DIR *dirp = opendir(path); - if (dirp == NULL && errno != ENOENT && errno != ENOTDIR) - rb_sys_warning(path); - - return dirp; -} - -/* Return nonzero if S has any special globbing chars in it. */ -static int -has_magic(s, flags) - const char *s; - int flags; -{ - const int escape = !(flags & FNM_NOESCAPE); - - register const char *p = s; - register char c; - - while (c = *p++) { - switch (c) { - case '*': - case '?': - case '[': - return 1; - - case '\\': - if (escape && !(c = *p++)) - return 0; - continue; - } - - p = Next(p-1); - } - - return 0; -} - -/* Find separator in globbing pattern. */ -static char * -find_dirsep(s, flags) - const char *s; - int flags; -{ - const int escape = !(flags & FNM_NOESCAPE); - - register const char *p = s; - register char c; - int open = 0; - - while (c = *p++) { - switch (c) { - case '[': - open = 1; - continue; - case ']': - open = 0; - continue; - - case '/': - if (!open) - return (char *)p-1; - continue; - - case '\\': - if (escape && !(c = *p++)) - return (char *)p-1; - continue; - } - - p = Next(p-1); - } - - return (char *)p-1; -} - -/* Remove escaping baskclashes */ -static void -remove_backslashes(p) - char *p; -{ - char *t = p; - char *s = p; - - while (*p) { - if (*p == '\\') { - if (t != s) - memmove(t, s, p - s); - t += p - s; - s = ++p; - if (!*p) break; - } - Inc(p); - } - - while (*p++); - - if (t != s) - memmove(t, s, p - s); /* move '\0' too */ -} - -/* Globing pattern */ -enum glob_pattern_type { PLAIN, MAGICAL, RECURSIVE, MATCH_ALL, MATCH_DIR }; - -struct glob_pattern { - char *str; - enum glob_pattern_type type; - struct glob_pattern *next; -}; - -static struct glob_pattern * -glob_make_pattern(p, flags) - const char *p; - int flags; -{ - struct glob_pattern *list, *tmp, **tail = &list; - int dirsep = 0; /* pattern is terminated with '/' */ - - while (*p) { - tmp = ALLOC(struct glob_pattern); - if (p[0] == '*' && p[1] == '*' && p[2] == '/') { - /* fold continuous RECURSIVEs (needed in glob_helper) */ - do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/'); - tmp->type = RECURSIVE; - tmp->str = 0; - dirsep = 1; - } - else { - const char *m = find_dirsep(p, flags); - char *buf = ALLOC_N(char, m-p+1); - memcpy(buf, p, m-p); - buf[m-p] = '\0'; - tmp->type = has_magic(buf, flags) ? MAGICAL : PLAIN; - tmp->str = buf; - if (*m) { - dirsep = 1; - p = m + 1; - } - else { - dirsep = 0; - p = m; - } - } - *tail = tmp; - tail = &tmp->next; - } - - tmp = ALLOC(struct glob_pattern); - tmp->type = dirsep ? MATCH_DIR : MATCH_ALL; - tmp->str = 0; - *tail = tmp; - tmp->next = 0; - - return list; -} - -static void -glob_free_pattern(list) - struct glob_pattern *list; -{ - while (list) { - struct glob_pattern *tmp = list; - list = list->next; - if (tmp->str) - free(tmp->str); - free(tmp); - } -} - -static VALUE -join_path(path, dirsep, name) - VALUE path; - int dirsep; - const char *name; -{ - long len = RSTRING(path)->len; - VALUE buf = rb_str_new(0, RSTRING(path)->len+strlen(name)+(dirsep?1:0)); - - memcpy(RSTRING(buf)->ptr, RSTRING(path)->ptr, len); - if (dirsep) { - strcpy(RSTRING(buf)->ptr+len, "/"); - len++; - } - strcpy(RSTRING(buf)->ptr+len, name); - return buf; -} - -enum answer { YES, NO, UNKNOWN }; - -#ifndef S_ISDIR -# define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) -#endif - -#ifndef S_ISLNK -# ifndef S_IFLNK -# define S_ISLNK(m) (0) -# else -# define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK) -# endif -#endif - -struct glob_args { - void (*func) _((VALUE, VALUE)); - VALUE c; - VALUE v; -}; - -static VALUE glob_func_caller _((VALUE)); - -static VALUE -glob_func_caller(val) - VALUE val; -{ - struct glob_args *args = (struct glob_args *)val; - VALUE path = args->c; - - OBJ_TAINT(path); - (*args->func)(path, args->v); - return Qnil; -} - -static int -glob_call_func(func, path, arg) - void (*func) _((VALUE, VALUE)); - VALUE path; - VALUE arg; -{ - int status; - struct glob_args args; - - args.func = func; - args.c = path; - args.v = arg; - - rb_protect(glob_func_caller, (VALUE)&args, &status); - return status; -} - -static int -glob_helper(path, dirsep, exist, isdir, beg, end, flags, func, arg) - VALUE path; - int dirsep; /* '/' should be placed before appending child entry's name to 'path'. */ - enum answer exist; /* Does 'path' indicate an existing entry? */ - enum answer isdir; /* Does 'path' indicate a directory or a symlink to a directory? */ - struct glob_pattern **beg; - struct glob_pattern **end; - int flags; - void (*func) _((VALUE, VALUE)); - VALUE arg; -{ - struct stat st; - int status = 0; - struct glob_pattern **cur, **new_beg, **new_end; - int plain = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0; - int escape = !(flags & FNM_NOESCAPE); - - for (cur = beg; cur < end; ++cur) { - struct glob_pattern *p = *cur; - if (p->type == RECURSIVE) { - recursive = 1; - p = p->next; - } - switch (p->type) { - case PLAIN: - plain = 1; - break; - case MAGICAL: - magical = 1; - break; - case MATCH_ALL: - match_all = 1; - break; - case MATCH_DIR: - match_dir = 1; - break; - } - } - - if (RSTRING(path)->len > 0) { - if (match_all && exist == UNKNOWN) { - if (do_lstat(RSTRING(path)->ptr, &st) == 0) { - exist = YES; - isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO; - } - else { - exist = NO; - isdir = NO; - } - } - - if (match_dir && isdir == UNKNOWN) { - if (do_stat(RSTRING(path)->ptr, &st) == 0) { - exist = YES; - isdir = S_ISDIR(st.st_mode) ? YES : NO; - } - else { - exist = NO; - isdir = NO; - } - } - - if (match_all && exist == YES) { - status = glob_call_func(func, path, arg); - if (status) return status; - } - - if (match_dir && isdir == YES) { - status = glob_call_func(func, join_path(path, dirsep, ""), arg); - if (status) return status; - } - } - - if (exist == NO || isdir == NO) return 0; - - if (magical || recursive) { - struct dirent *dp; - DIR *dirp = do_opendir(RSTRING(path)->len > 0 ? RSTRING(path)->ptr : "."); - if (dirp == NULL) return 0; - - for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { - VALUE buf = join_path(path, dirsep, dp->d_name); - - enum answer new_isdir = UNKNOWN; - if (recursive && strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0 - && fnmatch("*", dp->d_name, flags) == 0) { -#ifndef _WIN32 - if (do_lstat(RSTRING(buf)->ptr, &st) == 0) - new_isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO; - else - new_isdir = NO; -#else - new_isdir = dp->d_isdir ? (!dp->d_isrep ? YES : UNKNOWN) : NO; -#endif - } - - new_beg = new_end = ALLOC_N(struct glob_pattern *, (end - beg) * 2); - - for (cur = beg; cur < end; ++cur) { - struct glob_pattern *p = *cur; - if (p->type == RECURSIVE) { - if (new_isdir == YES) /* not symlink but real directory */ - *new_end++ = p; /* append recursive pattern */ - p = p->next; /* 0 times recursion */ - } - if (p->type == PLAIN || p->type == MAGICAL) { - if (fnmatch(p->str, dp->d_name, flags) == 0) - *new_end++ = p->next; - } - } - - status = glob_helper(buf, 1, YES, new_isdir, new_beg, new_end, flags, func, arg); - free(new_beg); - if (status) break; - } - - closedir(dirp); - } - else if (plain) { - struct glob_pattern **copy_beg, **copy_end, **cur2; - - copy_beg = copy_end = ALLOC_N(struct glob_pattern *, end - beg); - for (cur = beg; cur < end; ++cur) - *copy_end++ = (*cur)->type == PLAIN ? *cur : 0; - - for (cur = copy_beg; cur < copy_end; ++cur) { - if (*cur) { - VALUE buf; - char *name; - name = ALLOC_N(char, strlen((*cur)->str) + 1); - strcpy(name, (*cur)->str); - if (escape) remove_backslashes(name); - - new_beg = new_end = ALLOC_N(struct glob_pattern *, end - beg); - *new_end++ = (*cur)->next; - for (cur2 = cur + 1; cur2 < copy_end; ++cur2) { - if (*cur2 && fnmatch((*cur2)->str, name, flags) == 0) { - *new_end++ = (*cur2)->next; - *cur2 = 0; - } - } - - buf = join_path(path, dirsep, name); - free(name); - status = glob_helper(buf, 1, UNKNOWN, UNKNOWN, new_beg, new_end, flags, func, arg); - free(new_beg); - if (status) break; - } - } - - free(copy_beg); - } - - return status; -} - -static int -rb_glob2(path, offset, flags, func, arg) - VALUE path; - long offset; - int flags; - void (*func) _((VALUE, VALUE)); - VALUE arg; -{ - struct glob_pattern *list; - const char *root, *start; - VALUE buf; - int n; - int status; - - if (flags & FNM_CASEFOLD) { - rb_warn("Dir.glob() ignores File::FNM_CASEFOLD"); - } - - start = root = StringValuePtr(path) + offset; -#if defined DOSISH - flags |= FNM_CASEFOLD; - root = rb_path_skip_prefix(root); -#else - flags &= ~FNM_CASEFOLD; -#endif - - if (root && *root == '/') root++; - - n = root - start; - buf = rb_str_new(start, n); - - list = glob_make_pattern(root, flags); - status = glob_helper(buf, 0, UNKNOWN, UNKNOWN, &list, &list + 1, flags, func, arg); - glob_free_pattern(list); - - return status; -} - -struct rb_glob_args { - void (*func) _((const char*, VALUE)); - VALUE arg; -}; - -static VALUE -rb_glob_caller(path, a) - VALUE path, a; -{ - struct rb_glob_args *args = (struct rb_glob_args *)a; - (*args->func)(RSTRING(path)->ptr, args->arg); - return Qnil; -} - -void -rb_glob(path, func, arg) - const char *path; - void (*func) _((const char*, VALUE)); - VALUE arg; -{ - struct rb_glob_args args; - int status; - - args.func = func; - args.arg = arg; - status = rb_glob2(rb_str_new2(path), 0, 0, rb_glob_caller, &args); - - if (status) rb_jump_tag(status); -} - -static void -push_pattern(path, ary) - VALUE path, ary; -{ - rb_ary_push(ary, path); -} - -static int -push_glob(VALUE ary, VALUE s, long offset, int flags); - -static int -push_glob(ary, str, offset, flags) - VALUE ary; - VALUE str; - long offset; - int flags; -{ - const int escape = !(flags & FNM_NOESCAPE); - - const char *p = RSTRING(str)->ptr + offset; - const char *s = p; - const char *lbrace = 0, *rbrace = 0; - int nest = 0, status = 0; - - while (*p) { - if (*p == '{' && nest++ == 0) { - lbrace = p; - } - if (*p == '}' && --nest <= 0) { - rbrace = p; - break; - } - if (*p == '\\' && escape) { - if (!*++p) break; - } - Inc(p); - } - - if (lbrace && rbrace) { - VALUE buffer = rb_str_new(0, strlen(s)); - char *buf; - long shift; - - buf = RSTRING(buffer)->ptr; - memcpy(buf, s, lbrace-s); - shift = (lbrace-s); - p = lbrace; - while (p < rbrace) { - const char *t = ++p; - nest = 0; - while (p < rbrace && !(*p == ',' && nest == 0)) { - if (*p == '{') nest++; - if (*p == '}') nest--; - if (*p == '\\' && escape) { - if (++p == rbrace) break; - } - Inc(p); - } - memcpy(buf+shift, t, p-t); - strcpy(buf+shift+(p-t), rbrace+1); - status = push_glob(ary, buffer, offset, flags); - if (status) break; - } - } - else if (!lbrace && !rbrace) { - status = rb_glob2(str, offset, flags, push_pattern, ary); - } - - return status; -} - -static VALUE -rb_push_glob(str, flags) /* '\0' is delimiter */ - VALUE str; - int flags; -{ - long offset = 0; - VALUE ary; - - FilePathValue(str); - - ary = rb_ary_new(); - - while (offset < RSTRING(str)->len) { - int status = push_glob(ary, str, offset, flags); - char *p, *pend; - if (status) rb_jump_tag(status); - p = RSTRING(str)->ptr + offset; - p += strlen(p) + 1; - pend = RSTRING(str)->ptr + RSTRING(str)->len; - while (p < pend && !*p) - p++; - offset = p - RSTRING(str)->ptr; - } - - if (rb_block_given_p()) { - rb_ary_each(ary); - return Qnil; - } - return ary; -} - -/* - * call-seq: - * Dir[ string ] => array - * - * Equivalent to calling - * <em>dir</em>.<code>glob(</code><i>string,</i><code>0)</code>. - * - */ -static VALUE -dir_s_aref(obj, str) - VALUE obj, str; -{ - return rb_push_glob(str, 0); -} - -/* - * call-seq: - * Dir.glob( string, [flags] ) => array - * Dir.glob( string, [flags] ) {| filename | block } => nil - * - * Returns the filenames found by expanding the pattern given in - * <i>string</i>, either as an <i>array</i> or as parameters to the - * block. Note that this pattern is not a regexp (it's closer to a - * shell glob). See <code>File::fnmatch</code> for the meaning of - * the <i>flags</i> parameter. Note that case sensitivity - * depends on your system (so <code>File::FNM_CASEFOLD</code> is ignored) - * - * <code>*</code>:: Matches any file. Can be restricted by - * other values in the glob. <code>*</code> - * will match all files; <code>c*</code> will - * match all files beginning with - * <code>c</code>; <code>*c</code> will match - * all files ending with <code>c</code>; and - * <code>*c*</code> will match all files that - * have <code>c</code> in them (including at - * the beginning or end). Equivalent to - * <code>/ .* /x</code> in regexp. - * <code>**</code>:: Matches directories recursively. - * <code>?</code>:: Matches any one character. Equivalent to - * <code>/.{1}/</code> in regexp. - * <code>[set]</code>:: Matches any one character in +set+. - * Behaves exactly like character sets in - * Regexp, including set negation - * (<code>[^a-z]</code>). - * <code>{p,q}</code>:: Matches either literal <code>p</code> or - * literal <code>q</code>. Matching literals - * may be more than one character in length. - * More than two literals may be specified. - * Equivalent to pattern alternation in - * regexp. - * <code>\</code>:: Escapes the next metacharacter. - * - * Dir["config.?"] #=> ["config.h"] - * Dir.glob("config.?") #=> ["config.h"] - * Dir.glob("*.[a-z][a-z]") #=> ["main.rb"] - * Dir.glob("*.[^r]*") #=> ["config.h"] - * Dir.glob("*.{rb,h}") #=> ["main.rb", "config.h"] - * Dir.glob("*") #=> ["config.h", "main.rb"] - * Dir.glob("*", File::FNM_DOTMATCH) #=> [".", "..", "config.h", "main.rb"] - * - * rbfiles = File.join("**", "*.rb") - * Dir.glob(rbfiles) #=> ["main.rb", - * "lib/song.rb", - * "lib/song/karaoke.rb"] - * libdirs = File.join("**", "lib") - * Dir.glob(libdirs) #=> ["lib"] - * - * librbfiles = File.join("**", "lib", "**", "*.rb") - * Dir.glob(librbfiles) #=> ["lib/song.rb", - * "lib/song/karaoke.rb"] - * - * librbfiles = File.join("**", "lib", "*.rb") - * Dir.glob(librbfiles) #=> ["lib/song.rb"] - */ -static VALUE -dir_s_glob(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - VALUE str, rflags; - int flags; - - if (rb_scan_args(argc, argv, "11", &str, &rflags) == 2) - flags = NUM2INT(rflags); - else - flags = 0; - - return rb_push_glob(str, flags); -} - -static VALUE -dir_open_dir(path) - VALUE path; -{ - struct dir_data *dp; - VALUE dir = rb_funcall(rb_cDir, rb_intern("open"), 1, path); - - if (TYPE(dir) != T_DATA || - RDATA(dir)->dfree != (RUBY_DATA_FUNC)free_dir) { - rb_raise(rb_eTypeError, "wrong argument type %s (expected Dir)", - rb_obj_classname(dir)); - } - return dir; -} - - -/* - * call-seq: - * Dir.foreach( dirname ) {| filename | block } => nil - * - * Calls the block once for each entry in the named directory, passing - * the filename of each entry as a parameter to the block. - * - * Dir.foreach("testdir") {|x| puts "Got #{x}" } - * - * <em>produces:</em> - * - * Got . - * Got .. - * Got config.h - * Got main.rb - * - */ -static VALUE -dir_foreach(io, dirname) - VALUE io, dirname; -{ - VALUE dir; - - dir = dir_open_dir(dirname); - rb_ensure(dir_each, dir, dir_close, dir); - return Qnil; -} - -/* - * call-seq: - * Dir.entries( dirname ) => array - * - * Returns an array containing all of the filenames in the given - * directory. Will raise a <code>SystemCallError</code> if the named - * directory doesn't exist. - * - * Dir.entries("testdir") #=> [".", "..", "config.h", "main.rb"] - * - */ -static VALUE -dir_entries(io, dirname) - VALUE io, dirname; -{ - VALUE dir; - - dir = dir_open_dir(dirname); - return rb_ensure(rb_Array, dir, dir_close, dir); -} - -/* - * call-seq: - * File.fnmatch( pattern, path, [flags] ) => (true or false) - * File.fnmatch?( pattern, path, [flags] ) => (true or false) - * - * Returns true if <i>path</i> matches against <i>pattern</i> The - * pattern is not a regular expression; instead it follows rules - * similar to shell filename globbing. It may contain the following - * metacharacters: - * - * <code>*</code>:: Matches any file. Can be restricted by - * other values in the glob. <code>*</code> - * will match all files; <code>c*</code> will - * match all files beginning with - * <code>c</code>; <code>*c</code> will match - * all files ending with <code>c</code>; and - * <code>*c*</code> will match all files that - * have <code>c</code> in them (including at - * the beginning or end). Equivalent to - * <code>/ .* /x</code> in regexp. - * <code>**</code>:: Matches directories recursively or files - * expansively. - * <code>?</code>:: Matches any one character. Equivalent to - * <code>/.{1}/</code> in regexp. - * <code>[set]</code>:: Matches any one character in +set+. - * Behaves exactly like character sets in - * Regexp, including set negation - * (<code>[^a-z]</code>). - * <code>\</code>:: Escapes the next metacharacter. - * - * <i>flags</i> is a bitwise OR of the <code>FNM_xxx</code> - * parameters. The same glob pattern and flags are used by - * <code>Dir::glob</code>. - * - * File.fnmatch('cat', 'cat') #=> true : match entire string - * File.fnmatch('cat', 'category') #=> false : only match partial string - * File.fnmatch('c{at,ub}s', 'cats') #=> false : { } isn't supported - * - * File.fnmatch('c?t', 'cat') #=> true : '?' match only 1 character - * File.fnmatch('c??t', 'cat') #=> false : ditto - * File.fnmatch('c*', 'cats') #=> true : '*' match 0 or more characters - * File.fnmatch('c*t', 'c/a/b/t') #=> true : ditto - * File.fnmatch('ca[a-z]', 'cat') #=> true : inclusive bracket expression - * File.fnmatch('ca[^t]', 'cat') #=> false : exclusive bracket expression ('^' or '!') - * - * File.fnmatch('cat', 'CAT') #=> false : case sensitive - * File.fnmatch('cat', 'CAT', File::FNM_CASEFOLD) #=> true : case insensitive - * - * File.fnmatch('?', '/', File::FNM_PATHNAME) #=> false : wildcard doesn't match '/' on FNM_PATHNAME - * File.fnmatch('*', '/', File::FNM_PATHNAME) #=> false : ditto - * File.fnmatch('[/]', '/', File::FNM_PATHNAME) #=> false : ditto - * - * File.fnmatch('\?', '?') #=> true : escaped wildcard becomes ordinary - * File.fnmatch('\a', 'a') #=> true : escaped ordinary remains ordinary - * File.fnmatch('\a', '\a', File::FNM_NOESCAPE) #=> true : FNM_NOESACPE makes '\' ordinary - * File.fnmatch('[\?]', '?') #=> true : can escape inside bracket expression - * - * File.fnmatch('*', '.profile') #=> false : wildcard doesn't match leading - * File.fnmatch('*', '.profile', File::FNM_DOTMATCH) #=> true period by default. - * File.fnmatch('.*', '.profile') #=> true - * - * rbfiles = File.join("**", "*.rb") - * File.fnmatch(rbfiles, 'main.rb') #=> false - * File.fnmatch(rbfiles, './main.rb') #=> false - * File.fnmatch(rbfiles, 'lib/song.rb') #=> true - * File.fnmatch('**.rb', 'main.rb') #=> true - * File.fnmatch('**.rb', './main.rb') #=> false - * File.fnmatch('**.rb', 'lib/song.rb') #=> true - * File.fnmatch('*', 'dave/.profile') #=> true - * - * File.fnmatch('* IGNORE /*', 'dave/.profile', File::FNM_PATHNAME) #=> false - * File.fnmatch('* IGNORE /*', 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true - * - * File.fnmatch('** IGNORE /foo', 'a/b/c/foo', File::FNM_PATHNAME) #=> true - * File.fnmatch('** IGNORE /foo', '/a/b/c/foo', File::FNM_PATHNAME) #=> true - * File.fnmatch('** IGNORE /foo', 'c:/a/b/c/foo', File::FNM_PATHNAME) #=> true - * File.fnmatch('** IGNORE /foo', 'a/.b/c/foo', File::FNM_PATHNAME) #=> false - * File.fnmatch('** IGNORE /foo', 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true - */ -static VALUE -file_s_fnmatch(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - VALUE pattern, path; - VALUE rflags; - int flags; - - if (rb_scan_args(argc, argv, "21", &pattern, &path, &rflags) == 3) - flags = NUM2INT(rflags); - else - flags = 0; - - StringValue(pattern); - StringValue(path); - - if (fnmatch(RSTRING(pattern)->ptr, RSTRING(path)->ptr, flags) == 0) - return Qtrue; - - return Qfalse; -} - -/* - * Objects of class <code>Dir</code> are directory streams representing - * directories in the underlying file system. They provide a variety of - * ways to list directories and their contents. See also - * <code>File</code>. - * - * The directory used in these examples contains the two regular files - * (<code>config.h</code> and <code>main.rb</code>), the parent - * directory (<code>..</code>), and the directory itself - * (<code>.</code>). - */ -void -Init_Dir() -{ - rb_cDir = rb_define_class("Dir", rb_cObject); - - rb_include_module(rb_cDir, rb_mEnumerable); - - rb_define_alloc_func(rb_cDir, dir_s_alloc); - rb_define_singleton_method(rb_cDir, "open", dir_s_open, 1); - rb_define_singleton_method(rb_cDir, "foreach", dir_foreach, 1); - rb_define_singleton_method(rb_cDir, "entries", dir_entries, 1); - - rb_define_method(rb_cDir,"initialize", dir_initialize, 1); - rb_define_method(rb_cDir,"path", dir_path, 0); - rb_define_method(rb_cDir,"inspect", dir_inspect, 0); - rb_define_method(rb_cDir,"read", dir_read, 0); - rb_define_method(rb_cDir,"each", dir_each, 0); - rb_define_method(rb_cDir,"rewind", dir_rewind, 0); - rb_define_method(rb_cDir,"tell", dir_tell, 0); - rb_define_method(rb_cDir,"seek", dir_seek, 1); - rb_define_method(rb_cDir,"pos", dir_tell, 0); - rb_define_method(rb_cDir,"pos=", dir_set_pos, 1); - rb_define_method(rb_cDir,"close", dir_close, 0); - - rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1); - rb_define_singleton_method(rb_cDir,"getwd", dir_s_getwd, 0); - rb_define_singleton_method(rb_cDir,"pwd", dir_s_getwd, 0); - rb_define_singleton_method(rb_cDir,"chroot", dir_s_chroot, 1); - rb_define_singleton_method(rb_cDir,"mkdir", dir_s_mkdir, -1); - rb_define_singleton_method(rb_cDir,"rmdir", dir_s_rmdir, 1); - rb_define_singleton_method(rb_cDir,"delete", dir_s_rmdir, 1); - rb_define_singleton_method(rb_cDir,"unlink", dir_s_rmdir, 1); - - rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, -1); - rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, 1); - - rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1); - rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1); - - rb_file_const("FNM_NOESCAPE", INT2FIX(FNM_NOESCAPE)); - rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME)); - rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH)); - rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD)); -} -/********************************************************************** - - dln.c - - - $Author: murphy $ - $Date: 2005-11-05 04:33:55 +0100 (Sa, 05 Nov 2005) $ - created at: Tue Jan 18 17:05:06 JST 1994 - - Copyright (C) 1993-2003 Yukihiro Matsumoto - -**********************************************************************/ - -#include "ruby.h" -#include "dln.h" - -#ifdef HAVE_STDLIB_H -# include <stdlib.h> -#endif - -#ifdef __CHECKER__ -#undef HAVE_DLOPEN -#undef USE_DLN_A_OUT -#undef USE_DLN_DLOPEN -#endif - -#ifdef USE_DLN_A_OUT -char *dln_argv0; -#endif - -#ifdef _AIX -#pragma alloca -#endif - -#if defined(HAVE_ALLOCA_H) -#include <alloca.h> -#endif - -#ifdef HAVE_STRING_H -# include <string.h> -#else -# include <strings.h> -#endif - -#ifndef xmalloc -void *xmalloc(); -void *xcalloc(); -void *xrealloc(); -#endif - -#include <stdio.h> -#if defined(_WIN32) || defined(__VMS) -#include "missing/file.h" -#endif -#include <sys/types.h> -#include <sys/stat.h> - -#ifndef S_ISDIR -# define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) -#endif - -#ifdef HAVE_SYS_PARAM_H -# include <sys/param.h> -#endif -#ifndef MAXPATHLEN -# define MAXPATHLEN 1024 -#endif - -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif - -#ifndef _WIN32 -char *getenv(); -#endif - -#if defined(__VMS) -#pragma builtins -#include <dlfcn.h> -#endif - -#ifdef __MACOS__ -# include <TextUtils.h> -# include <CodeFragments.h> -# include <Aliases.h> -# include "macruby_private.h" -#endif - -#ifdef __BEOS__ -# include <image.h> -#endif - -int eaccess(); - -#ifndef NO_DLN_LOAD - -#if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX) && !defined(__APPLE__) && !defined(_UNICOSMP) -/* dynamic load with dlopen() */ -# define USE_DLN_DLOPEN -#endif - -#ifndef FUNCNAME_PATTERN -# if defined(__hp9000s300) || (defined(__NetBSD__) && !defined(__ELF__)) || defined(__BORLANDC__) || (defined(__FreeBSD__) && !defined(__ELF__)) || (defined(__OpenBSD__) && !defined(__ELF__)) || defined(NeXT) || defined(__WATCOMC__) || defined(__APPLE__) -# define FUNCNAME_PATTERN "_Init_%s" -# else -# define FUNCNAME_PATTERN "Init_%s" -# endif -#endif - -static int -init_funcname_len(buf, file) - char **buf; - const char *file; -{ - char *p; - const char *slash; - int len; - - /* Load the file as an object one */ - for (slash = file-1; *file; file++) /* Find position of last '/' */ -#ifdef __MACOS__ - if (*file == ':') slash = file; -#else - if (*file == '/') slash = file; -#endif - - len = strlen(FUNCNAME_PATTERN) + strlen(slash + 1); - *buf = xmalloc(len); - snprintf(*buf, len, FUNCNAME_PATTERN, slash + 1); - for (p = *buf; *p; p++) { /* Delete suffix if it exists */ - if (*p == '.') { - *p = '\0'; break; - } - } - return p - *buf; -} - -#define init_funcname(buf, file) do {\ - int len = init_funcname_len(buf, file);\ - char *tmp = ALLOCA_N(char, len+1);\ - if (!tmp) {\ - free(*buf);\ - rb_memerror();\ - }\ - strcpy(tmp, *buf);\ - free(*buf);\ - *buf = tmp;\ -} while (0) - -#ifdef USE_DLN_A_OUT - -#ifndef LIBC_NAME -# define LIBC_NAME "libc.a" -#endif - -#ifndef DLN_DEFAULT_LIB_PATH -# define DLN_DEFAULT_LIB_PATH "/lib:/usr/lib:/usr/local/lib:." -#endif - -#include <errno.h> - -static int dln_errno; - -#define DLN_ENOEXEC ENOEXEC /* Exec format error */ -#define DLN_ECONFL 1201 /* Symbol name conflict */ -#define DLN_ENOINIT 1202 /* No initializer given */ -#define DLN_EUNDEF 1203 /* Undefine symbol remains */ -#define DLN_ENOTLIB 1204 /* Not a library file */ -#define DLN_EBADLIB 1205 /* Malformed library file */ -#define DLN_EINIT 1206 /* Not initialized */ - -static int dln_init_p = 0; - -#include <ar.h> -#include <a.out.h> -#ifndef N_COMM -# define N_COMM 0x12 -#endif -#ifndef N_MAGIC -# define N_MAGIC(x) (x).a_magic -#endif - -#define INVALID_OBJECT(h) (N_MAGIC(h) != OMAGIC) - -#include "util.h" -#include "st.h" - -static st_table *sym_tbl; -static st_table *undef_tbl; - -static int load_lib(); - -static int -load_header(fd, hdrp, disp) - int fd; - struct exec *hdrp; - long disp; -{ - int size; - - lseek(fd, disp, 0); - size = read(fd, hdrp, sizeof(struct exec)); - if (size == -1) { - dln_errno = errno; - return -1; - } - if (size != sizeof(struct exec) || N_BADMAG(*hdrp)) { - dln_errno = DLN_ENOEXEC; - return -1; - } - return 0; -} - -#if defined(sequent) -#define RELOC_SYMBOL(r) ((r)->r_symbolnum) -#define RELOC_MEMORY_SUB_P(r) ((r)->r_bsr) -#define RELOC_PCREL_P(r) ((r)->r_pcrel || (r)->r_bsr) -#define RELOC_TARGET_SIZE(r) ((r)->r_length) -#endif - -/* Default macros */ -#ifndef RELOC_ADDRESS -#define RELOC_ADDRESS(r) ((r)->r_address) -#define RELOC_EXTERN_P(r) ((r)->r_extern) -#define RELOC_SYMBOL(r) ((r)->r_symbolnum) -#define RELOC_MEMORY_SUB_P(r) 0 -#define RELOC_PCREL_P(r) ((r)->r_pcrel) -#define RELOC_TARGET_SIZE(r) ((r)->r_length) -#endif - -#if defined(sun) && defined(sparc) -/* Sparc (Sun 4) macros */ -# undef relocation_info -# define relocation_info reloc_info_sparc -# define R_RIGHTSHIFT(r) (reloc_r_rightshift[(r)->r_type]) -# define R_BITSIZE(r) (reloc_r_bitsize[(r)->r_type]) -# define R_LENGTH(r) (reloc_r_length[(r)->r_type]) -static int reloc_r_rightshift[] = { - 0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0, -}; -static int reloc_r_bitsize[] = { - 8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16, -}; -static int reloc_r_length[] = { - 0, 1, 2, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -}; -# define R_PCREL(r) \ - ((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22) -# define R_SYMBOL(r) ((r)->r_index) -#endif - -#if defined(sequent) -#define R_SYMBOL(r) ((r)->r_symbolnum) -#define R_MEMORY_SUB(r) ((r)->r_bsr) -#define R_PCREL(r) ((r)->r_pcrel || (r)->r_bsr) -#define R_LENGTH(r) ((r)->r_length) -#endif - -#ifndef R_SYMBOL -# define R_SYMBOL(r) ((r)->r_symbolnum) -# define R_MEMORY_SUB(r) 0 -# define R_PCREL(r) ((r)->r_pcrel) -# define R_LENGTH(r) ((r)->r_length) -#endif - -static struct relocation_info * -load_reloc(fd, hdrp, disp) - int fd; - struct exec *hdrp; - long disp; -{ - struct relocation_info *reloc; - int size; - - lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0); - size = hdrp->a_trsize + hdrp->a_drsize; - reloc = (struct relocation_info*)xmalloc(size); - if (reloc == NULL) { - dln_errno = errno; - return NULL; - } - - if (read(fd, reloc, size) != size) { - dln_errno = errno; - free(reloc); - return NULL; - } - - return reloc; -} - -static struct nlist * -load_sym(fd, hdrp, disp) - int fd; - struct exec *hdrp; - long disp; -{ - struct nlist * buffer; - struct nlist * sym; - struct nlist * end; - long displ; - int size; - - lseek(fd, N_SYMOFF(*hdrp) + hdrp->a_syms + disp, 0); - if (read(fd, &size, sizeof(int)) != sizeof(int)) { - goto err_noexec; - } - - buffer = (struct nlist*)xmalloc(hdrp->a_syms + size); - if (buffer == NULL) { - dln_errno = errno; - return NULL; - } - - lseek(fd, disp + N_SYMOFF(*hdrp), 0); - if (read(fd, buffer, hdrp->a_syms + size) != hdrp->a_syms + size) { - free(buffer); - goto err_noexec; - } - - sym = buffer; - end = sym + hdrp->a_syms / sizeof(struct nlist); - displ = (long)buffer + (long)(hdrp->a_syms); - - while (sym < end) { - sym->n_un.n_name = (char*)sym->n_un.n_strx + displ; - sym++; - } - return buffer; - - err_noexec: - dln_errno = DLN_ENOEXEC; - return NULL; -} - -static st_table * -sym_hash(hdrp, syms) - struct exec *hdrp; - struct nlist *syms; -{ - st_table *tbl; - struct nlist *sym = syms; - struct nlist *end = syms + (hdrp->a_syms / sizeof(struct nlist)); - - tbl = st_init_strtable(); - if (tbl == NULL) { - dln_errno = errno; - return NULL; - } - - while (sym < end) { - st_insert(tbl, sym->n_un.n_name, sym); - sym++; - } - return tbl; -} - -static int -dln_init(prog) - const char *prog; -{ - char *file; - int fd; - struct exec hdr; - struct nlist *syms; - - if (dln_init_p == 1) return 0; - - file = dln_find_exe(prog, NULL); - if (file == NULL || (fd = open(file, O_RDONLY)) < 0) { - dln_errno = errno; - return -1; - } - - if (load_header(fd, &hdr, 0) == -1) return -1; - syms = load_sym(fd, &hdr, 0); - if (syms == NULL) { - close(fd); - return -1; - } - sym_tbl = sym_hash(&hdr, syms); - if (sym_tbl == NULL) { /* file may be start with #! */ - char c = '\0'; - char buf[MAXPATHLEN]; - char *p; - - free(syms); - lseek(fd, 0L, 0); - if (read(fd, &c, 1) == -1) { - dln_errno = errno; - return -1; - } - if (c != '#') goto err_noexec; - if (read(fd, &c, 1) == -1) { - dln_errno = errno; - return -1; - } - if (c != '!') goto err_noexec; - - p = buf; - /* skip forwarding spaces */ - while (read(fd, &c, 1) == 1) { - if (c == '\n') goto err_noexec; - if (c != '\t' && c != ' ') { - *p++ = c; - break; - } - } - /* read in command name */ - while (read(fd, p, 1) == 1) { - if (*p == '\n' || *p == '\t' || *p == ' ') break; - p++; - if (p-buf >= MAXPATHLEN) { - dln_errno = ENAMETOOLONG; - return -1; - } - } - *p = '\0'; - - return dln_init(buf); - } - dln_init_p = 1; - undef_tbl = st_init_strtable(); - close(fd); - return 0; - - err_noexec: - close(fd); - dln_errno = DLN_ENOEXEC; - return -1; -} - -static long -load_text_data(fd, hdrp, bss, disp) - int fd; - struct exec *hdrp; - int bss; - long disp; -{ - int size; - unsigned char* addr; - - lseek(fd, disp + N_TXTOFF(*hdrp), 0); - size = hdrp->a_text + hdrp->a_data; - - if (bss == -1) size += hdrp->a_bss; - else if (bss > 1) size += bss; - - addr = (unsigned char*)xmalloc(size); - if (addr == NULL) { - dln_errno = errno; - return 0; - } - - if (read(fd, addr, size) != size) { - dln_errno = errno; - free(addr); - return 0; - } - - if (bss == -1) { - memset(addr + hdrp->a_text + hdrp->a_data, 0, hdrp->a_bss); - } - else if (bss > 0) { - memset(addr + hdrp->a_text + hdrp->a_data, 0, bss); - } - - return (long)addr; -} - -static int -undef_print(key, value) - char *key, *value; -{ - fprintf(stderr, " %s\n", key); - return ST_CONTINUE; -} - -static void -dln_print_undef() -{ - fprintf(stderr, " Undefined symbols:\n"); - st_foreach(undef_tbl, undef_print, NULL); -} - -static void -dln_undefined() -{ - if (undef_tbl->num_entries > 0) { - fprintf(stderr, "dln: Calling undefined function\n"); - dln_print_undef(); - rb_exit(1); - } -} - -struct undef { - char *name; - struct relocation_info reloc; - long base; - char *addr; - union { - char c; - short s; - long l; - } u; -}; - -static st_table *reloc_tbl = NULL; -static void -link_undef(name, base, reloc) - const char *name; - long base; - struct relocation_info *reloc; -{ - static int u_no = 0; - struct undef *obj; - char *addr = (char*)(reloc->r_address + base); - - obj = (struct undef*)xmalloc(sizeof(struct undef)); - obj->name = strdup(name); - obj->reloc = *reloc; - obj->base = base; - switch (R_LENGTH(reloc)) { - case 0: /* byte */ - obj->u.c = *addr; - break; - case 1: /* word */ - obj->u.s = *(short*)addr; - break; - case 2: /* long */ - obj->u.l = *(long*)addr; - break; - } - if (reloc_tbl == NULL) { - reloc_tbl = st_init_numtable(); - } - st_insert(reloc_tbl, u_no++, obj); -} - -struct reloc_arg { - const char *name; - long value; -}; - -static int -reloc_undef(no, undef, arg) - int no; - struct undef *undef; - struct reloc_arg *arg; -{ - int datum; - char *address; -#if defined(sun) && defined(sparc) - unsigned int mask = 0; -#endif - - if (strcmp(arg->name, undef->name) != 0) return ST_CONTINUE; - address = (char*)(undef->base + undef->reloc.r_address); - datum = arg->value; - - if (R_PCREL(&(undef->reloc))) datum -= undef->base; -#if defined(sun) && defined(sparc) - datum += undef->reloc.r_addend; - datum >>= R_RIGHTSHIFT(&(undef->reloc)); - mask = (1 << R_BITSIZE(&(undef->reloc))) - 1; - mask |= mask -1; - datum &= mask; - switch (R_LENGTH(&(undef->reloc))) { - case 0: - *address = undef->u.c; - *address &= ~mask; - *address |= datum; - break; - case 1: - *(short *)address = undef->u.s; - *(short *)address &= ~mask; - *(short *)address |= datum; - break; - case 2: - *(long *)address = undef->u.l; - *(long *)address &= ~mask; - *(long *)address |= datum; - break; - } -#else - switch (R_LENGTH(&(undef->reloc))) { - case 0: /* byte */ - if (R_MEMORY_SUB(&(undef->reloc))) - *address = datum - *address; - else *address = undef->u.c + datum; - break; - case 1: /* word */ - if (R_MEMORY_SUB(&(undef->reloc))) - *(short*)address = datum - *(short*)address; - else *(short*)address = undef->u.s + datum; - break; - case 2: /* long */ - if (R_MEMORY_SUB(&(undef->reloc))) - *(long*)address = datum - *(long*)address; - else *(long*)address = undef->u.l + datum; - break; - } -#endif - free(undef->name); - free(undef); - return ST_DELETE; -} - -static void -unlink_undef(name, value) - const char *name; - long value; -{ - struct reloc_arg arg; - - arg.name = name; - arg.value = value; - st_foreach(reloc_tbl, reloc_undef, &arg); -} - -#ifdef N_INDR -struct indr_data { - char *name0, *name1; -}; - -static int -reloc_repl(no, undef, data) - int no; - struct undef *undef; - struct indr_data *data; -{ - if (strcmp(data->name0, undef->name) == 0) { - free(undef->name); - undef->name = strdup(data->name1); - } - return ST_CONTINUE; -} -#endif - -static int -load_1(fd, disp, need_init) - int fd; - long disp; - const char *need_init; -{ - static char *libc = LIBC_NAME; - struct exec hdr; - struct relocation_info *reloc = NULL; - long block = 0; - long new_common = 0; /* Length of new common */ - struct nlist *syms = NULL; - struct nlist *sym; - struct nlist *end; - int init_p = 0; - - if (load_header(fd, &hdr, disp) == -1) return -1; - if (INVALID_OBJECT(hdr)) { - dln_errno = DLN_ENOEXEC; - return -1; - } - reloc = load_reloc(fd, &hdr, disp); - if (reloc == NULL) return -1; - - syms = load_sym(fd, &hdr, disp); - if (syms == NULL) { - free(reloc); - return -1; - } - - sym = syms; - end = syms + (hdr.a_syms / sizeof(struct nlist)); - while (sym < end) { - struct nlist *old_sym; - int value = sym->n_value; - -#ifdef N_INDR - if (sym->n_type == (N_INDR | N_EXT)) { - char *key = sym->n_un.n_name; - - if (st_lookup(sym_tbl, sym[1].n_un.n_name, &old_sym)) { - if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) { - unlink_undef(key, old_sym->n_value); - free(key); - } - } - else { - struct indr_data data; - - data.name0 = sym->n_un.n_name; - data.name1 = sym[1].n_un.n_name; - st_foreach(reloc_tbl, reloc_repl, &data); - - st_insert(undef_tbl, strdup(sym[1].n_un.n_name), NULL); - if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) { - free(key); - } - } - sym += 2; - continue; - } -#endif - if (sym->n_type == (N_UNDF | N_EXT)) { - if (st_lookup(sym_tbl, sym->n_un.n_name, &old_sym) == 0) { - old_sym = NULL; - } - - if (value) { - if (old_sym) { - sym->n_type = N_EXT | N_COMM; - sym->n_value = old_sym->n_value; - } - else { - int rnd = - value >= sizeof(double) ? sizeof(double) - 1 - : value >= sizeof(long) ? sizeof(long) - 1 - : sizeof(short) - 1; - - sym->n_type = N_COMM; - new_common += rnd; - new_common &= ~(long)rnd; - sym->n_value = new_common; - new_common += value; - } - } - else { - if (old_sym) { - sym->n_type = N_EXT | N_COMM; - sym->n_value = old_sym->n_value; - } - else { - sym->n_value = (long)dln_undefined; - st_insert(undef_tbl, strdup(sym->n_un.n_name), NULL); - } - } - } - sym++; - } - - block = load_text_data(fd, &hdr, hdr.a_bss + new_common, disp); - if (block == 0) goto err_exit; - - sym = syms; - while (sym < end) { - struct nlist *new_sym; - char *key; - - switch (sym->n_type) { - case N_COMM: - sym->n_value += hdr.a_text + hdr.a_data; - case N_TEXT|N_EXT: - case N_DATA|N_EXT: - - sym->n_value += block; - - if (st_lookup(sym_tbl, sym->n_un.n_name, &new_sym) != 0 - && new_sym->n_value != (long)dln_undefined) { - dln_errno = DLN_ECONFL; - goto err_exit; - } - - key = sym->n_un.n_name; - if (st_delete(undef_tbl, (st_data_t*)&key, NULL) != 0) { - unlink_undef(key, sym->n_value); - free(key); - } - - new_sym = (struct nlist*)xmalloc(sizeof(struct nlist)); - *new_sym = *sym; - new_sym->n_un.n_name = strdup(sym->n_un.n_name); - st_insert(sym_tbl, new_sym->n_un.n_name, new_sym); - break; - - case N_TEXT: - case N_DATA: - sym->n_value += block; - break; - } - sym++; - } - - /* - * First comes the text-relocation - */ - { - struct relocation_info * rel = reloc; - struct relocation_info * rel_beg = reloc + - (hdr.a_trsize/sizeof(struct relocation_info)); - struct relocation_info * rel_end = reloc + - (hdr.a_trsize+hdr.a_drsize)/sizeof(struct relocation_info); - - while (rel < rel_end) { - char *address = (char*)(rel->r_address + block); - long datum = 0; -#if defined(sun) && defined(sparc) - unsigned int mask = 0; -#endif - - if(rel >= rel_beg) - address += hdr.a_text; - - if (rel->r_extern) { /* Look it up in symbol-table */ - sym = &(syms[R_SYMBOL(rel)]); - switch (sym->n_type) { - case N_EXT|N_UNDF: - link_undef(sym->n_un.n_name, block, rel); - case N_EXT|N_COMM: - case N_COMM: - datum = sym->n_value; - break; - default: - goto err_exit; - } - } /* end.. look it up */ - else { /* is static */ - switch (R_SYMBOL(rel)) { - case N_TEXT: - case N_DATA: - datum = block; - break; - case N_BSS: - datum = block + new_common; - break; - case N_ABS: - break; - } - } /* end .. is static */ - if (R_PCREL(rel)) datum -= block; - -#if defined(sun) && defined(sparc) - datum += rel->r_addend; - datum >>= R_RIGHTSHIFT(rel); - mask = (1 << R_BITSIZE(rel)) - 1; - mask |= mask -1; - datum &= mask; - - switch (R_LENGTH(rel)) { - case 0: - *address &= ~mask; - *address |= datum; - break; - case 1: - *(short *)address &= ~mask; - *(short *)address |= datum; - break; - case 2: - *(long *)address &= ~mask; - *(long *)address |= datum; - break; - } -#else - switch (R_LENGTH(rel)) { - case 0: /* byte */ - if (datum < -128 || datum > 127) goto err_exit; - *address += datum; - break; - case 1: /* word */ - *(short *)address += datum; - break; - case 2: /* long */ - *(long *)address += datum; - break; - } -#endif - rel++; - } - } - - if (need_init) { - int len; - char **libs_to_be_linked = 0; - char *buf; - - if (undef_tbl->num_entries > 0) { - if (load_lib(libc) == -1) goto err_exit; - } - - init_funcname(&buf, need_init); - len = strlen(buf); - - for (sym = syms; sym<end; sym++) { - char *name = sym->n_un.n_name; - if (name[0] == '_' && sym->n_value >= block) { - if (strcmp(name+1, "dln_libs_to_be_linked") == 0) { - libs_to_be_linked = (char**)sym->n_value; - } - else if (strcmp(name+1, buf) == 0) { - init_p = 1; - ((int (*)())sym->n_value)(); - } - } - } - if (libs_to_be_linked && undef_tbl->num_entries > 0) { - while (*libs_to_be_linked) { - load_lib(*libs_to_be_linked); - libs_to_be_linked++; - } - } - } - free(reloc); - free(syms); - if (need_init) { - if (init_p == 0) { - dln_errno = DLN_ENOINIT; - return -1; - } - if (undef_tbl->num_entries > 0) { - if (load_lib(libc) == -1) goto err_exit; - if (undef_tbl->num_entries > 0) { - dln_errno = DLN_EUNDEF; - return -1; - } - } - } - return 0; - - err_exit: - if (syms) free(syms); - if (reloc) free(reloc); - if (block) free((char*)block); - return -1; -} - -static int target_offset; -static int -search_undef(key, value, lib_tbl) - const char *key; - int value; - st_table *lib_tbl; -{ - long offset; - - if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE; - target_offset = offset; - return ST_STOP; -} - -struct symdef { - int rb_str_index; - int lib_offset; -}; - -char *dln_librrb_ary_path = DLN_DEFAULT_LIB_PATH; - -static int -load_lib(lib) - const char *lib; -{ - char *path, *file; - char armagic[SARMAG]; - int fd, size; - struct ar_hdr ahdr; - st_table *lib_tbl = NULL; - int *data, nsym; - struct symdef *base; - char *name_base; - - if (dln_init_p == 0) { - dln_errno = DLN_ENOINIT; - return -1; - } - - if (undef_tbl->num_entries == 0) return 0; - dln_errno = DLN_EBADLIB; - - if (lib[0] == '-' && lib[1] == 'l') { - char *p = alloca(strlen(lib) + 4); - sprintf(p, "lib%s.a", lib+2); - lib = p; - } - - /* library search path: */ - /* look for environment variable DLN_LIBRARY_PATH first. */ - /* then variable dln_librrb_ary_path. */ - /* if path is still NULL, use "." for path. */ - path = getenv("DLN_LIBRARY_PATH"); - if (path == NULL) path = dln_librrb_ary_path; - - file = dln_find_file(lib, path); - fd = open(file, O_RDONLY); - if (fd == -1) goto syserr; - size = read(fd, armagic, SARMAG); - if (size == -1) goto syserr; - - if (size != SARMAG) { - dln_errno = DLN_ENOTLIB; - goto badlib; - } - size = read(fd, &ahdr, sizeof(ahdr)); - if (size == -1) goto syserr; - if (size != sizeof(ahdr) || sscanf(ahdr.ar_size, "%d", &size) != 1) { - goto badlib; - } - - if (strncmp(ahdr.ar_name, "__.SYMDEF", 9) == 0) { - /* make hash table from __.SYMDEF */ - - lib_tbl = st_init_strtable(); - data = (int*)xmalloc(size); - if (data == NULL) goto syserr; - size = read(fd, data, size); - nsym = *data / sizeof(struct symdef); - base = (struct symdef*)(data + 1); - name_base = (char*)(base + nsym) + sizeof(int); - while (nsym > 0) { - char *name = name_base + base->rb_str_index; - - st_insert(lib_tbl, name, base->lib_offset + sizeof(ahdr)); - nsym--; - base++; - } - for (;;) { - target_offset = -1; - st_foreach(undef_tbl, search_undef, lib_tbl); - if (target_offset == -1) break; - if (load_1(fd, target_offset, 0) == -1) { - st_free_table(lib_tbl); - free(data); - goto badlib; - } - if (undef_tbl->num_entries == 0) break; - } - free(data); - st_free_table(lib_tbl); - } - else { - /* linear library, need to scan (FUTURE) */ - - for (;;) { - int offset = SARMAG; - int found = 0; - struct exec hdr; - struct nlist *syms, *sym, *end; - - while (undef_tbl->num_entries > 0) { - found = 0; - lseek(fd, offset, 0); - size = read(fd, &ahdr, sizeof(ahdr)); - if (size == -1) goto syserr; - if (size == 0) break; - if (size != sizeof(ahdr) - || sscanf(ahdr.ar_size, "%d", &size) != 1) { - goto badlib; - } - offset += sizeof(ahdr); - if (load_header(fd, &hdr, offset) == -1) - goto badlib; - syms = load_sym(fd, &hdr, offset); - if (syms == NULL) goto badlib; - sym = syms; - end = syms + (hdr.a_syms / sizeof(struct nlist)); - while (sym < end) { - if (sym->n_type == N_EXT|N_TEXT - && st_lookup(undef_tbl, sym->n_un.n_name, NULL)) { - break; - } - sym++; - } - if (sym < end) { - found++; - free(syms); - if (load_1(fd, offset, 0) == -1) { - goto badlib; - } - } - offset += size; - if (offset & 1) offset++; - } - if (found) break; - } - } - close(fd); - return 0; - - syserr: - dln_errno = errno; - badlib: - if (fd >= 0) close(fd); - return -1; -} - -static int -load(file) - const char *file; -{ - int fd; - int result; - - if (dln_init_p == 0) { - if (dln_init(dln_argv0) == -1) return -1; - } - result = strlen(file); - if (file[result-1] == 'a') { - return load_lib(file); - } - - fd = open(file, O_RDONLY); - if (fd == -1) { - dln_errno = errno; - return -1; - } - result = load_1(fd, 0, file); - close(fd); - - return result; -} - -void* -dln_sym(name) - const char *name; -{ - struct nlist *sym; - - if (st_lookup(sym_tbl, name, &sym)) - return (void*)sym->n_value; - return NULL; -} - -#endif /* USE_DLN_A_OUT */ - -#ifdef USE_DLN_DLOPEN -# include <dlfcn.h> -#endif - -#ifdef __hpux -#include <errno.h> -#include "dl.h" -#endif - -#if defined(_AIX) -#include <ctype.h> /* for isdigit() */ -#include <errno.h> /* for global errno */ -#include <sys/ldr.h> -#endif - -#ifdef NeXT -#if NS_TARGET_MAJOR < 4 -#include <mach-o/rld.h> -#else -#include <mach-o/dyld.h> -#ifndef NSLINKMODULE_OPTION_BINDNOW -#define NSLINKMODULE_OPTION_BINDNOW 1 -#endif -#endif -#else -#ifdef __APPLE__ -#include <mach-o/dyld.h> -#endif -#endif - -#if defined _WIN32 && !defined __CYGWIN__ -#include <windows.h> -#endif - -#ifdef _WIN32_WCE -#undef FormatMessage -#define FormatMessage FormatMessageA -#undef LoadLibrary -#define LoadLibrary LoadLibraryA -#undef GetProcAddress -#define GetProcAddress GetProcAddressA -#endif - -static const char * -dln_strerror() -{ -#ifdef USE_DLN_A_OUT - char *strerror(); - - switch (dln_errno) { - case DLN_ECONFL: - return "Symbol name conflict"; - case DLN_ENOINIT: - return "No initializer given"; - case DLN_EUNDEF: - return "Unresolved symbols"; - case DLN_ENOTLIB: - return "Not a library file"; - case DLN_EBADLIB: - return "Malformed library file"; - case DLN_EINIT: - return "Not initialized"; - default: - return strerror(dln_errno); - } -#endif - -#ifdef USE_DLN_DLOPEN - return (char*)dlerror(); -#endif - -#if defined _WIN32 && !defined __CYGWIN__ - static char message[1024]; - int error = GetLastError(); - char *p = message; - p += sprintf(message, "%d: ", error); - FormatMessage( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - error, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - p, - sizeof message - strlen(message), - NULL); - - for (p = message; *p; p++) { - if (*p == '\n' || *p == '\r') - *p = ' '; - } - return message; -#endif -} - - -#if defined(_AIX) && ! defined(_IA64) -static void -aix_loaderror(const char *pathname) -{ - char *message[8], errbuf[1024]; - int i,j; - - struct errtab { - int errnum; - char *errstr; - } load_errtab[] = { - {L_ERROR_TOOMANY, "too many errors, rest skipped."}, - {L_ERROR_NOLIB, "can't load library:"}, - {L_ERROR_UNDEF, "can't find symbol in library:"}, - {L_ERROR_RLDBAD, - "RLD index out of range or bad relocation type:"}, - {L_ERROR_FORMAT, "not a valid, executable xcoff file:"}, - {L_ERROR_MEMBER, - "file not an archive or does not contain requested member:"}, - {L_ERROR_TYPE, "symbol table mismatch:"}, - {L_ERROR_ALIGN, "text alignment in file is wrong."}, - {L_ERROR_SYSTEM, "System error:"}, - {L_ERROR_ERRNO, NULL} - }; - -#define LOAD_ERRTAB_LEN (sizeof(load_errtab)/sizeof(load_errtab[0])) -#define ERRBUF_APPEND(s) strncat(errbuf, s, sizeof(errbuf)-strlen(errbuf)-1) - - snprintf(errbuf, 1024, "load failed - %s ", pathname); - - if (!loadquery(1, &message[0], sizeof(message))) - ERRBUF_APPEND(strerror(errno)); - for(i = 0; message[i] && *message[i]; i++) { - int nerr = atoi(message[i]); - for (j=0; j<LOAD_ERRTAB_LEN; j++) { - if (nerr == load_errtab[i].errnum && load_errtab[i].errstr) - ERRBUF_APPEND(load_errtab[i].errstr); - } - while (isdigit(*message[i])) message[i]++; - ERRBUF_APPEND(message[i]); - ERRBUF_APPEND("\n"); - } - errbuf[strlen(errbuf)-1] = '\0'; /* trim off last newline */ - rb_loaderror(errbuf); - return; -} -#endif - -#endif /* NO_DLN_LOAD */ - diff --git a/tests/examplefiles/example.cpp b/tests/examplefiles/example.cpp index 4dffc3f7..334e7ca7 100644 --- a/tests/examplefiles/example.cpp +++ b/tests/examplefiles/example.cpp @@ -2361,3884 +2361,3 @@ namespace astyle #ifdef USES_NAMESPACE using namespace std; -namespace astyle - { -#endif - - - bool ASFormatter::calledInitStatic = false; - vector<const string*> ASFormatter::headers; - vector<const string*> ASFormatter::nonParenHeaders; - vector<const string*> ASFormatter::preprocessorHeaders; - vector<const string*> ASFormatter::preDefinitionHeaders; - vector<const string*> ASFormatter::preCommandHeaders; - vector<const string*> ASFormatter::operators; - vector<const string*> ASFormatter::assignmentOperators; - - - /** - * Constructor of ASFormatter - */ - ASFormatter::ASFormatter() - { - staticInit(); - - preBracketHeaderStack = NULL; - bracketTypeStack = NULL; - parenStack = NULL; - - sourceIterator = NULL; - bracketFormatMode = NONE_MODE; - shouldPadOperators = false; - shouldPadParenthesies = false; - shouldBreakOneLineBlocks = true; - shouldBreakOneLineStatements = true; - shouldConvertTabs = false; - shouldBreakBlocks = false; - shouldBreakClosingHeaderBlocks = false; - shouldBreakClosingHeaderBrackets = false; - shouldBreakElseIfs = false; - } - - /** - * Destructor of ASFormatter - */ - ASFormatter::~ASFormatter() - { - DELETE_CONTAINER( preBracketHeaderStack ); - } - - /** - * initialization of static data of ASFormatter. - */ - void ASFormatter::staticInit() - { - if (calledInitStatic) - return; - - calledInitStatic = true; - - headers.push_back(&AS_IF); - headers.push_back(&AS_ELSE); - headers.push_back(&AS_DO); - headers.push_back(&AS_WHILE); - headers.push_back(&AS_FOR); - headers.push_back(&AS_SYNCHRONIZED); - headers.push_back(&AS_TRY); - headers.push_back(&AS_CATCH); - headers.push_back(&AS_FINALLY); - headers.push_back(&AS_SWITCH); - headers.push_back(&AS_TEMPLATE); - headers.push_back(&AS_FOREACH); - headers.push_back(&AS_LOCK); - headers.push_back(&AS_UNSAFE); - headers.push_back(&AS_FIXED); - headers.push_back(&AS_GET); - headers.push_back(&AS_SET); - headers.push_back(&AS_ADD); - headers.push_back(&AS_REMOVE); - - nonParenHeaders.push_back(&AS_ELSE); - nonParenHeaders.push_back(&AS_DO); - nonParenHeaders.push_back(&AS_TRY); - nonParenHeaders.push_back(&AS_FINALLY); - nonParenHeaders.push_back(&AS_UNSAFE); - nonParenHeaders.push_back(&AS_GET); - nonParenHeaders.push_back(&AS_SET); - nonParenHeaders.push_back(&AS_ADD); - nonParenHeaders.push_back(&AS_REMOVE); - - // nonParenHeaders.push_back(&AS_TEMPLATE); - - preDefinitionHeaders.push_back(&AS_CLASS); - preDefinitionHeaders.push_back(&AS_INTERFACE); - preDefinitionHeaders.push_back(&AS_NAMESPACE); - preDefinitionHeaders.push_back(&AS_STRUCT); - - preCommandHeaders.push_back(&AS_EXTERN); - preCommandHeaders.push_back(&AS_THROWS); - preCommandHeaders.push_back(&AS_CONST); - - preprocessorHeaders.push_back(&AS_BAR_DEFINE); - //// DEVEL: removed the folowing lines - ////preprocessorHeaders.push_back(&AS_BAR_INCLUDE); - ////preprocessorHeaders.push_back(&AS_BAR_IF); // #if or #ifdef - ////preprocessorHeaders.push_back(&AS_BAR_EL); // #else or #elif - ////preprocessorHeaders.push_back(&AS_BAR_ENDIF); - - operators.push_back(&AS_PLUS_ASSIGN); - operators.push_back(&AS_MINUS_ASSIGN); - operators.push_back(&AS_MULT_ASSIGN); - operators.push_back(&AS_DIV_ASSIGN); - operators.push_back(&AS_MOD_ASSIGN); - operators.push_back(&AS_OR_ASSIGN); - operators.push_back(&AS_AND_ASSIGN); - operators.push_back(&AS_XOR_ASSIGN); - operators.push_back(&AS_EQUAL); - operators.push_back(&AS_PLUS_PLUS); - operators.push_back(&AS_MINUS_MINUS); - operators.push_back(&AS_NOT_EQUAL); - operators.push_back(&AS_GR_EQUAL); - operators.push_back(&AS_GR_GR_GR_ASSIGN); - operators.push_back(&AS_GR_GR_ASSIGN); - operators.push_back(&AS_GR_GR_GR); - operators.push_back(&AS_GR_GR); - operators.push_back(&AS_LS_EQUAL); - operators.push_back(&AS_LS_LS_LS_ASSIGN); - operators.push_back(&AS_LS_LS_ASSIGN); - operators.push_back(&AS_LS_LS_LS); - operators.push_back(&AS_LS_LS); - operators.push_back(&AS_ARROW); - operators.push_back(&AS_AND); - operators.push_back(&AS_OR); - operators.push_back(&AS_COLON_COLON); - - //// BUGFIX: removed the folowing lines - //// operators.push_back(&AS_PAREN_PAREN); - //// operators.push_back(&AS_BLPAREN_BLPAREN); - - operators.push_back(&AS_PLUS); - operators.push_back(&AS_MINUS); - operators.push_back(&AS_MULT); - operators.push_back(&AS_DIV); - operators.push_back(&AS_MOD); - operators.push_back(&AS_QUESTION); - operators.push_back(&AS_COLON); - operators.push_back(&AS_ASSIGN); - operators.push_back(&AS_LS); - operators.push_back(&AS_GR); - operators.push_back(&AS_NOT); - operators.push_back(&AS_BIT_OR); - operators.push_back(&AS_BIT_AND); - operators.push_back(&AS_BIT_NOT); - operators.push_back(&AS_BIT_XOR); - operators.push_back(&AS_OPERATOR); - operators.push_back(&AS_COMMA); - //BEGIN Content Patch patch1_ssvb_patch.tar.gz - operators.push_back(&AS_SEMICOLON); - //END Content Patch patch1_ssvb_patch.tar.gz - operators.push_back(&AS_RETURN); - - assignmentOperators.push_back(&AS_PLUS_ASSIGN); - assignmentOperators.push_back(&AS_MINUS_ASSIGN); - assignmentOperators.push_back(&AS_MULT_ASSIGN); - assignmentOperators.push_back(&AS_DIV_ASSIGN); - assignmentOperators.push_back(&AS_MOD_ASSIGN); - assignmentOperators.push_back(&AS_XOR_ASSIGN); - assignmentOperators.push_back(&AS_OR_ASSIGN); - assignmentOperators.push_back(&AS_AND_ASSIGN); - assignmentOperators.push_back(&AS_GR_GR_GR_ASSIGN); - assignmentOperators.push_back(&AS_LS_LS_LS_ASSIGN); - assignmentOperators.push_back(&AS_ASSIGN); - } - - /** - * initialize the ASFormatter. - * - * init() should be called every time a ASFormatter object is to start - * formatting a NEW source file. - * init() recieves a pointer to a DYNAMICALLY CREATED ASSourceIterator object - * that will be used to iterate through the source code. This object will be - * deleted during the ASFormatter's destruction, and thus should not be - * deleted elsewhere. - * - * @param iter a pointer to the DYNAMICALLY CREATED ASSourceIterator object. - */ - void ASFormatter::init(ASSourceIterator *si) - { - ASBeautifier::init(si); - sourceIterator = si; - - INIT_CONTAINER( preBracketHeaderStack, new vector<const string*> ); - INIT_CONTAINER( bracketTypeStack, new vector<BracketType> ); - bracketTypeStack->push_back(DEFINITION_TYPE); - INIT_CONTAINER( parenStack, new vector<int> ); - parenStack->push_back(0); - - currentHeader = NULL; - currentLine = string(""); - formattedLine = ""; - currentChar = ' '; - previousCommandChar = ' '; - previousNonWSChar = ' '; - quoteChar = '"'; - charNum = 0; - previousOperator = NULL; - - isVirgin = true; - isInLineComment = false; - isInComment = false; - isInPreprocessor = false; - doesLineStartComment = false; - isInQuote = false; - isSpecialChar = false; - isNonParenHeader = true; - foundPreDefinitionHeader = false; - foundPreCommandHeader = false; - foundQuestionMark = false; - isInLineBreak = false; - endOfCodeReached = false; - isLineReady = false; - isPreviousBracketBlockRelated = true; - isInPotentialCalculation = false; - //foundOneLineBlock = false; - shouldReparseCurrentChar = false; - passedSemicolon = false; - passedColon = false; - isInTemplate = false; - shouldBreakLineAfterComments = false; - isImmediatelyPostComment = false; - isImmediatelyPostLineComment = false; - isImmediatelyPostEmptyBlock = false; - - isPrependPostBlockEmptyLineRequested = false; - isAppendPostBlockEmptyLineRequested = false; - prependEmptyLine = false; - - foundClosingHeader = false; - previousReadyFormattedLineLength = 0; - - isImmediatelyPostHeader = false; - isInHeader = false; - } - - /** - * get the next formatted line. - * - * @return formatted line. - */ - - string ASFormatter::nextLine() - { - const string *newHeader; - bool isCharImmediatelyPostComment = false; - bool isPreviousCharPostComment = false; - bool isCharImmediatelyPostLineComment = false; - bool isInVirginLine = isVirgin; - bool isCharImmediatelyPostOpenBlock = false; - bool isCharImmediatelyPostCloseBlock = false; - bool isCharImmediatelyPostTemplate = false; - bool isCharImmediatelyPostHeader = false; - - if (!isFormattingEnabled()) - return ASBeautifier::nextLine(); - - while (!isLineReady) - { - if (shouldReparseCurrentChar) - shouldReparseCurrentChar = false; - else if (!getNextChar()) - { - breakLine(); - return beautify(readyFormattedLine); - } - else // stuff to do when reading a new character... - { - // make sure that a virgin '{' at the begining ofthe file will be treated as a block... - if (isInVirginLine && currentChar == '{') - previousCommandChar = '{'; - isPreviousCharPostComment = isCharImmediatelyPostComment; - isCharImmediatelyPostComment = false; - isCharImmediatelyPostTemplate = false; - isCharImmediatelyPostHeader = false; - } - - if (isInLineComment) - { - appendCurrentChar(); - - // explicitely break a line when a line comment's end is found. - if (/*bracketFormatMode == ATTACH_MODE &&*/ charNum+1 == currentLine.length()) - { - isInLineBreak = true; - isInLineComment = false; - isImmediatelyPostLineComment = true; - currentChar = 0; //make sure it is a neutral char. - } - continue; - } - else if (isInComment) - { - if (isSequenceReached(AS_CLOSE_COMMENT)) - { - isInComment = false; - isImmediatelyPostComment = true; - appendSequence(AS_CLOSE_COMMENT); - goForward(1); - } - else - appendCurrentChar(); - - continue; - } - - // not in line comment or comment - - else if (isInQuote) - { - if (isSpecialChar) - { - isSpecialChar = false; - appendCurrentChar(); - } - else if (currentChar == '\\') - { - isSpecialChar = true; - appendCurrentChar(); - } - else if (quoteChar == currentChar) - { - isInQuote = false; - appendCurrentChar(); - } - else - { - appendCurrentChar(); - } - - continue; - } - - - - // handle white space - needed to simplify the rest. - if (isWhiteSpace(currentChar) || isInPreprocessor) - { - ////// DEVEL: if (isLegalNameChar(previousChar) && isLegalNameChar(peekNextChar())) - appendCurrentChar(); - continue; - } - - /* not in MIDDLE of quote or comment or white-space of any type ... */ - - if (isSequenceReached(AS_OPEN_LINE_COMMENT)) - { - isInLineComment = true; - if (shouldPadOperators) - appendSpacePad(); - appendSequence(AS_OPEN_LINE_COMMENT); - goForward(1); - continue; - } - else if (isSequenceReached(AS_OPEN_COMMENT)) - { - isInComment = true; - if (shouldPadOperators) - appendSpacePad(); - appendSequence(AS_OPEN_COMMENT); - goForward(1); - continue; - } - else if (currentChar == '"' || currentChar == '\'') - { - isInQuote = true; - quoteChar = currentChar; - //// if (shouldPadOperators) // BUGFIX: these two lines removed. seem to be unneeded, and interfere with L" - //// appendSpacePad(); // BUFFIX: TODO make sure the removal of these lines doesn't reopen old bugs... - appendCurrentChar(); - continue; - } - - /* not in quote or comment or white-space of any type ... */ - - - // check if in preprocessor - // ** isInPreprocessor will be automatically reset at the begining - // of a new line in getnextChar() - if (currentChar == '#') - isInPreprocessor = true; - - if (isInPreprocessor) - { - appendCurrentChar(); - continue; - } - - /* not in preprocessor ... */ - - if (isImmediatelyPostComment) - { - isImmediatelyPostComment = false; - isCharImmediatelyPostComment = true; - } - - if (isImmediatelyPostLineComment) - { - isImmediatelyPostLineComment = false; - isCharImmediatelyPostLineComment = true; - } - - if (shouldBreakLineAfterComments) - { - shouldBreakLineAfterComments = false; - shouldReparseCurrentChar = true; - breakLine(); - continue; - } - - // reset isImmediatelyPostHeader information - if (isImmediatelyPostHeader) - { - isImmediatelyPostHeader = false; - isCharImmediatelyPostHeader = true; - - // Make sure headers are broken from their succeeding blocks - // (e.g. - // if (isFoo) DoBar(); - // should become - // if (isFoo) - // DoBar; - // ) - // But treat else if() as a special case which should not be broken! - if (shouldBreakOneLineStatements) - { - // if may break 'else if()'s, ythen simply break the line - - if (shouldBreakElseIfs) - isInLineBreak = true; - - else - { - // make sure 'else if()'s are not broken. - - bool isInElseIf = false; - const string *upcomingHeader; - - upcomingHeader = findHeader(headers); - if (currentHeader == &AS_ELSE && upcomingHeader == &AS_IF) - isInElseIf = true; - - if (!isInElseIf) - isInLineBreak = true; ////BUGFIX: SHOULD NOT BE breakLine() !!! - } - } - } - - if (passedSemicolon) - { - passedSemicolon = false; - if (parenStack->back() == 0) - { - shouldReparseCurrentChar = true; - isInLineBreak = true; - continue; - } - } - - if (passedColon) - { - passedColon = false; - if (parenStack->back() == 0) - { - shouldReparseCurrentChar = true; - isInLineBreak = true; - continue; - } - } - - // Check if in template declaration, e.g. foo<bar> or foo<bar,fig> - // If so, set isInTemplate to true - // - if (!isInTemplate && currentChar == '<') - { - int templateDepth = 0; - const string *oper; - for (unsigned int i=charNum; - i< currentLine.length(); - i += (oper ? oper->length() : 1) ) - { - oper = ASBeautifier::findHeader(currentLine, i, operators); - - if (oper == &AS_LS) - { - templateDepth++; - } - else if (oper == &AS_GR) - { - templateDepth--; - if (templateDepth == 0) - { - // this is a template! - // - isInTemplate = true; - break; - } - } - else if (oper == &AS_COMMA // comma, e.g. A<int, char> - || oper == &AS_BIT_AND // reference, e.g. A<int&> - || oper == &AS_MULT // pointer, e.g. A<int*> - || oper == &AS_COLON_COLON) // ::, e.g. std::string - { - continue; - } - else if (!isLegalNameChar(currentLine[i]) && !isWhiteSpace(currentLine[i])) - { - // this is not a template -> leave... - // - isInTemplate = false; - break; - } - } - } - - - // handle parenthesies - // - if (currentChar == '(' || currentChar == '[' || (isInTemplate && currentChar == '<')) - { - parenStack->back()++; - } - else if (currentChar == ')' || currentChar == ']' || (isInTemplate && currentChar == '>')) - { - parenStack->back()--; - if (isInTemplate && parenStack->back() == 0) - { - isInTemplate = false; - isCharImmediatelyPostTemplate = true; - } - - // check if this parenthesis closes a header, e.g. if (...), while (...) - // - if (isInHeader && parenStack->back() == 0) - { - isInHeader = false; - isImmediatelyPostHeader = true; - } - - } - - // handle brackets - // - BracketType bracketType = NULL_TYPE; - - if (currentChar == '{') - { - bracketType = getBracketType(); - foundPreDefinitionHeader = false; - foundPreCommandHeader = false; - - bracketTypeStack->push_back(bracketType); - preBracketHeaderStack->push_back(currentHeader); - currentHeader = NULL; - - isPreviousBracketBlockRelated = !IS_A(bracketType, ARRAY_TYPE); - } - else if (currentChar == '}') - { - // if a request has been made to append a post block empty line, - // but the block exists immediately before a closing bracket, - // then there is not need for the post block empty line. - // - isAppendPostBlockEmptyLineRequested = false; - - if (!bracketTypeStack->empty()) - { - bracketType = bracketTypeStack->back(); - bracketTypeStack->pop_back(); - - isPreviousBracketBlockRelated = !IS_A(bracketType, ARRAY_TYPE); - } - - if (!preBracketHeaderStack->empty()) - { - currentHeader = preBracketHeaderStack->back(); - preBracketHeaderStack->pop_back(); - } - else - currentHeader = NULL; - } - - if (!IS_A(bracketType, ARRAY_TYPE)) - { - - if (currentChar == '{') - { - parenStack->push_back(0); - } - else if (currentChar == '}') - { - if (!parenStack->empty()) - { - parenStack->pop_back(); - } - } - - if (bracketFormatMode != NONE_MODE) - { - if (currentChar == '{') - { - if ( ( bracketFormatMode == ATTACH_MODE - || bracketFormatMode == BDAC_MODE && bracketTypeStack->size()>=2 - && IS_A((*bracketTypeStack)[bracketTypeStack->size()-2], COMMAND_TYPE) /*&& isInLineBreak*/) - && !isCharImmediatelyPostLineComment ) - { - appendSpacePad(); - if (!isCharImmediatelyPostComment // do not attach '{' to lines that end with /**/ comments. - && previousCommandChar != '{' - && previousCommandChar != '}' - && previousCommandChar != ';') // '}' , ';' chars added for proper handling of '{' immediately after a '}' or ';' - appendCurrentChar(false); - else - appendCurrentChar(true); - continue; - } - else if (bracketFormatMode == BREAK_MODE - || bracketFormatMode == BDAC_MODE && bracketTypeStack->size()>=2 - && IS_A((*bracketTypeStack)[bracketTypeStack->size()-2], DEFINITION_TYPE)) - { - if ( shouldBreakOneLineBlocks || !IS_A(bracketType, SINGLE_LINE_TYPE) ) - breakLine(); - appendCurrentChar(); - continue; - } - } - else if (currentChar == '}') - { - // bool origLineBreak = isInLineBreak; - - // mark state of immediately after empty block - // this state will be used for locating brackets that appear immedately AFTER an empty block (e.g. '{} \n}'). - if (previousCommandChar == '{') - isImmediatelyPostEmptyBlock = true; - - if ( (!(previousCommandChar == '{' && isPreviousBracketBlockRelated) ) // this '{' does not close an empty block - && (shouldBreakOneLineBlocks || !IS_A(bracketType, SINGLE_LINE_TYPE)) // astyle is allowed to break on line blocks - && !isImmediatelyPostEmptyBlock) // this '}' does not immediately follow an empty block - { - breakLine(); - appendCurrentChar(); - } - else - { - // Content Patch ASFormatter.cpp.patch.bz2 - // if (!isCharImmediatelyPostComment) - if (!isCharImmediatelyPostComment && - !isCharImmediatelyPostLineComment) - isInLineBreak = false; - appendCurrentChar(); - if (shouldBreakOneLineBlocks || !IS_A(bracketType, SINGLE_LINE_TYPE)) - shouldBreakLineAfterComments = true; - } - - if (shouldBreakBlocks) - { - isAppendPostBlockEmptyLineRequested =true; - } - - continue; - } - } - } - - if ( ( (previousCommandChar == '{' - && isPreviousBracketBlockRelated) - - || (previousCommandChar == '}' - && !isImmediatelyPostEmptyBlock // <-- - && isPreviousBracketBlockRelated - && !isPreviousCharPostComment // <-- Fixes wrongly appended newlines after '}' immediately after comments... 10/9/1999 - && peekNextChar() != ' ')) - - && (shouldBreakOneLineBlocks || !IS_A(bracketTypeStack->back(), SINGLE_LINE_TYPE)) ) - { - isCharImmediatelyPostOpenBlock = (previousCommandChar == '{'); - isCharImmediatelyPostCloseBlock = (previousCommandChar == '}'); - - previousCommandChar = ' '; - isInLineBreak = true; //<---- - } - - // reset block handling flags - isImmediatelyPostEmptyBlock = false; - - // look for headers - if (!isInTemplate) - { - if ( (newHeader = findHeader(headers)) != NULL) - { - foundClosingHeader = false; - const string *previousHeader; - - // recognize closing headers of do..while, if..else, try..catch..finally - if ( (newHeader == &AS_ELSE && currentHeader == &AS_IF) - || (newHeader == &AS_WHILE && currentHeader == &AS_DO) - || (newHeader == &AS_CATCH && currentHeader == &AS_TRY) - || (newHeader == &AS_CATCH && currentHeader == &AS_CATCH) - || (newHeader == &AS_FINALLY && currentHeader == &AS_TRY) - || (newHeader == &AS_FINALLY && currentHeader == &AS_CATCH) ) - foundClosingHeader = true; - - previousHeader = currentHeader; - currentHeader = newHeader; - - // If in ATTACH or LINUX bracket modes, attach closing headers (e.g. 'else', 'catch') - // to their preceding bracket, - // But do not perform the attachment if the shouldBreakClosingHeaderBrackets is set! - if (!shouldBreakClosingHeaderBrackets && foundClosingHeader && (bracketFormatMode == ATTACH_MODE || bracketFormatMode == BDAC_MODE) && previousNonWSChar == '}') - { - isInLineBreak = false; - appendSpacePad(); - - if (shouldBreakBlocks) - isAppendPostBlockEmptyLineRequested = false; - } - - //Check if a template definition as been reached, e.g. template<class A> - if (newHeader == &AS_TEMPLATE) - { - isInTemplate = true; - } - - // check if the found header is non-paren header - isNonParenHeader = ( find(nonParenHeaders.begin(), nonParenHeaders.end(), - newHeader) != nonParenHeaders.end() ); - appendSequence(*currentHeader); - goForward(currentHeader->length() - 1); - // if padding is on, and a paren-header is found - // then add a space pad after it. - if (shouldPadOperators && !isNonParenHeader) - appendSpacePad(); - - - // Signal that a header has been reached - // *** But treat a closing while() (as in do...while) - // as if it where NOT a header since a closing while() - // should never have a block after it! - if (!(foundClosingHeader && currentHeader == &AS_WHILE)) - { - isInHeader = true; - if (isNonParenHeader) - { - isImmediatelyPostHeader = true; - isInHeader = false; - } - } - - if (currentHeader == &AS_IF && previousHeader == &AS_ELSE) - isInLineBreak = false; - - if (shouldBreakBlocks) - { - if (previousHeader == NULL - && !foundClosingHeader - && !isCharImmediatelyPostOpenBlock) - { - isPrependPostBlockEmptyLineRequested = true; - } - - if (currentHeader == &AS_ELSE - || currentHeader == &AS_CATCH - || currentHeader == &AS_FINALLY - || foundClosingHeader) - { - isPrependPostBlockEmptyLineRequested = false; - } - - if (shouldBreakClosingHeaderBlocks - && isCharImmediatelyPostCloseBlock) - { - isPrependPostBlockEmptyLineRequested = true; - } - - } - - continue; - } - else if ( (newHeader = findHeader(preDefinitionHeaders)) != NULL) - { - foundPreDefinitionHeader = true; - appendSequence(*newHeader); - goForward(newHeader->length() - 1); - - if (shouldBreakBlocks) - isPrependPostBlockEmptyLineRequested = true; - - continue; - } - else if ( (newHeader = findHeader(preCommandHeaders)) != NULL) - { - foundPreCommandHeader = true; - appendSequence(*newHeader); - goForward(newHeader->length() - 1); - - continue; - } - } - - if (previousNonWSChar == '}' || currentChar == ';') - { - if (shouldBreakOneLineStatements && currentChar == ';' - && (shouldBreakOneLineBlocks || !IS_A(bracketTypeStack->back(), SINGLE_LINE_TYPE))) - { - passedSemicolon = true; - } - - if (shouldBreakBlocks && currentHeader != NULL && parenStack->back() == 0) - { - isAppendPostBlockEmptyLineRequested = true; - } - - if (currentChar != ';') - currentHeader = NULL; //DEVEL: is this ok? - - foundQuestionMark = false; - foundPreDefinitionHeader = false; - foundPreCommandHeader = false; - isInPotentialCalculation = false; - - } - - if (currentChar == ':' - && shouldBreakOneLineStatements - && !foundQuestionMark // not in a ... ? ... : ... sequence - && !foundPreDefinitionHeader // not in a definition block (e.g. class foo : public bar - && previousCommandChar != ')' // not immediately after closing paren of a method header, e.g. ASFormatter::ASFormatter(...) : ASBeautifier(...) - && previousChar != ':' // not part of '::' - && peekNextChar() != ':') // not part of '::' - { - passedColon = true; - if (shouldBreakBlocks) - isPrependPostBlockEmptyLineRequested = true; - } - - if (currentChar == '?') - foundQuestionMark = true; - - if (shouldPadOperators) - { - if ((newHeader = findHeader(operators)) != NULL) - { - bool shouldPad = (newHeader != &AS_COLON_COLON - && newHeader != &AS_PAREN_PAREN - && newHeader != &AS_BLPAREN_BLPAREN - && newHeader != &AS_PLUS_PLUS - && newHeader != &AS_MINUS_MINUS - && newHeader != &AS_NOT - && newHeader != &AS_BIT_NOT - && newHeader != &AS_ARROW - && newHeader != &AS_OPERATOR - && !(newHeader == &AS_MINUS && isInExponent()) - && !(newHeader == &AS_PLUS && isInExponent()) - && previousOperator != &AS_OPERATOR - && !((newHeader == &AS_MULT || newHeader == &AS_BIT_AND) - && isPointerOrReference()) - && !( (isInTemplate || isCharImmediatelyPostTemplate) - && (newHeader == &AS_LS || newHeader == &AS_GR)) - ); - - if (!isInPotentialCalculation) - if (find(assignmentOperators.begin(), assignmentOperators.end(), newHeader) - != assignmentOperators.end()) - isInPotentialCalculation = true; - - // pad before operator - if (shouldPad - && !(newHeader == &AS_COLON && !foundQuestionMark) - && newHeader != &AS_SEMICOLON - && newHeader != &AS_COMMA) - appendSpacePad(); - appendSequence(*newHeader); - goForward(newHeader->length() - 1); - - // since this block handles '()' and '[]', - // the parenStack must be updated here accordingly! - if (newHeader == &AS_PAREN_PAREN - || newHeader == &AS_BLPAREN_BLPAREN) - parenStack->back()--; - - currentChar = (*newHeader)[newHeader->length() - 1]; - // pad after operator - // but do not pad after a '-' that is a urinary-minus. - if ( shouldPad && !(newHeader == &AS_MINUS && isUrinaryMinus()) ) - appendSpacePad(); - - previousOperator = newHeader; - continue; - } - } - //BEGIN Content Patch patch1_ssvb_patch.tar.gz - if (currentChar == '(' || currentChar == '[' ) - isInPotentialCalculation = true; - //END Content Patch patch1_ssvb_patch.tar.gz - if (shouldPadParenthesies) - { - if (currentChar == '(' || currentChar == '[' ) - { - char peekedChar = peekNextChar(); - - isInPotentialCalculation = true; - appendCurrentChar(); - if (!(currentChar == '(' && peekedChar == ')') - && !(currentChar == '[' && peekedChar == ']')) - appendSpacePad(); - continue; - } - else if (currentChar == ')' || currentChar == ']') - { - char peekedChar = peekNextChar(); - - if (!(previousChar == '(' && currentChar == ')') - && !(previousChar == '[' && currentChar == ']')) - appendSpacePad(); - - appendCurrentChar(); - - if (peekedChar != ';' && peekedChar != ',' && peekedChar != '.' - && !(currentChar == ']' && peekedChar == '[')) - appendSpacePad(); - continue; - } - } - - appendCurrentChar(); - } - - // return a beautified (i.e. correctly indented) line. - - string beautifiedLine; - int readyFormattedLineLength = trim(readyFormattedLine).length(); - - if (prependEmptyLine - && readyFormattedLineLength > 0 - && previousReadyFormattedLineLength > 0) - { - isLineReady = true; // signal that a readyFormattedLine is still waiting - beautifiedLine = beautify(""); - } - else - { - isLineReady = false; - beautifiedLine = beautify(readyFormattedLine); - } - - prependEmptyLine = false; - previousReadyFormattedLineLength = readyFormattedLineLength; - - return beautifiedLine; - - } - - - /** - * check if there are any indented lines ready to be read by nextLine() - * - * @return are there any indented lines ready? - */ - bool ASFormatter::hasMoreLines() const - { - if (!isFormattingEnabled()) - return ASBeautifier::hasMoreLines(); - else - return !endOfCodeReached; - } - - /** - * check if formatting options are enabled, in addition to indentation. - * - * @return are formatting options enabled? - */ - bool ASFormatter::isFormattingEnabled() const - { - return (bracketFormatMode != NONE_MODE - || shouldPadOperators - || shouldConvertTabs); - } - - /** - * set the bracket formatting mode. - * options: - * astyle::NONE_MODE no formatting of brackets. - * astyle::ATTACH_MODE Java, K&R style bracket placement. - * astyle::BREAK_MODE ANSI C/C++ style bracket placement. - * - * @param mode the bracket formatting mode. - */ - void ASFormatter::setBracketFormatMode(BracketMode mode) - { - bracketFormatMode = mode; - } - - /** - * set closing header bracket breaking mode - * options: - * true brackets just before closing headers (e.g. 'else', 'catch') - * will be broken, even if standard brackets are attached. - * false closing header brackets will be treated as standard brackets. - * - * @param mode the closing header bracket breaking mode. - */ - void ASFormatter::setBreakClosingHeaderBracketsMode(bool state) - { - shouldBreakClosingHeaderBrackets = state; - } - - /** - * set 'else if()' breaking mode - * options: - * true 'else' headers will be broken from their succeeding 'if' headers. - * false 'else' headers will be attached to their succeeding 'if' headers. - * - * @param mode the 'else if()' breaking mode. - */ - void ASFormatter::setBreakElseIfsMode(bool state) - { - shouldBreakElseIfs = state; - } - - /** - * set operator padding mode. - * options: - * true statement operators will be padded with spaces around them. - * false statement operators will not be padded. - * - * @param mode the padding mode. - */ - void ASFormatter::setOperatorPaddingMode(bool state) - { - shouldPadOperators = state; - } - - /** - * set parentheies padding mode. - * options: - * true statement parenthesies will be padded with spaces around them. - * false statement parenthesies will not be padded. - * - * @param mode the padding mode. - */ - void ASFormatter::setParenthesisPaddingMode(bool state) - { - shouldPadParenthesies = state; - } - - /** - * set option to break/not break one-line blocks - * - * @param state true = break, false = don't break. - */ - void ASFormatter::setBreakOneLineBlocksMode(bool state) - { - shouldBreakOneLineBlocks = state; - } - - /** - * set option to break/not break lines consisting of multiple statements. - * - * @param state true = break, false = don't break. - */ - void ASFormatter::setSingleStatementsMode(bool state) - { - shouldBreakOneLineStatements = state; - } - - /** - * set option to convert tabs to spaces. - * - * @param state true = convert, false = don't convert. - */ - void ASFormatter::setTabSpaceConversionMode(bool state) - { - shouldConvertTabs = state; - } - - - /** - * set option to break unrelated blocks of code with empty lines. - * - * @param state true = convert, false = don't convert. - */ - void ASFormatter::setBreakBlocksMode(bool state) - { - shouldBreakBlocks = state; - } - - /** - * set option to break closing header blocks of code (such as 'else', 'catch', ...) with empty lines. - * - * @param state true = convert, false = don't convert. - */ - void ASFormatter::setBreakClosingHeaderBlocksMode(bool state) - { - shouldBreakClosingHeaderBlocks = state; - } - - /** - * check if a specific sequence exists in the current placement of the current line - * - * @return whether sequence has been reached. - * @param sequence the sequence to be checked - */ - bool ASFormatter::isSequenceReached(const string &sequence) const - { - return currentLine.COMPARE(charNum, sequence.length(), sequence) == 0; - - } - - /** - * jump over several characters. - * - * @param i the number of characters to jump over. - */ - void ASFormatter::goForward(int i) - { - while (--i >= 0) - getNextChar(); - } - - /** - * peek at the next unread character. - * - * @return the next unread character. - */ - char ASFormatter::peekNextChar() const - { - int peekNum = charNum + 1; - int len = currentLine.length(); - char ch = ' '; - - while (peekNum < len) - { - ch = currentLine[peekNum++]; - if (!isWhiteSpace(ch)) - return ch; - } - - if (shouldConvertTabs && ch == '\t') - ch = ' '; - - return ch; - } - - /** - * check if current placement is before a comment or line-comment - * - * @return is before a comment or line-comment. - */ - bool ASFormatter::isBeforeComment() const - { - int peekNum = charNum + 1; - int len = currentLine.length(); - // char ch = ' '; - bool foundComment = false; - - for (peekNum = charNum + 1; - peekNum < len && isWhiteSpace(currentLine[peekNum]); - ++peekNum) - ; - - if (peekNum < len) - foundComment = ( currentLine.COMPARE(peekNum, 2, AS_OPEN_COMMENT) == 0 - || currentLine.COMPARE(peekNum, 2, AS_OPEN_LINE_COMMENT) == 0 ); - - return foundComment; - } - - /** - * get the next character, increasing the current placement in the process. - * the new character is inserted into the variable currentChar. - * - * @return whether succeded to recieve the new character. - */ - bool ASFormatter::getNextChar() - { - isInLineBreak = false; - bool isAfterFormattedWhiteSpace = false; - - if (shouldPadOperators && !isInComment && !isInLineComment - && !isInQuote && !doesLineStartComment && !isInPreprocessor - && !isBeforeComment()) - { - //BEGIN Content Patch patch1_ssvb_patch.tar.gz - char prevchar = ' '; - char nextchar = peekNextChar(); - - int len = formattedLine.length(); - // if (len > 0 && isWhiteSpace(formattedLine[len-1])) - if (len > 0) prevchar = formattedLine[len-1]; - if (isWhiteSpace(prevchar) || prevchar == '(' || prevchar == '[' || - nextchar == ')' || nextchar == ']') - { - isAfterFormattedWhiteSpace = true; - } - //END Content Patch patch1_ssvb_patch.tar.gz - } - - previousChar = currentChar; - if (!isWhiteSpace(currentChar)) - { - previousNonWSChar = currentChar; - if (!isInComment && !isInLineComment && !isInQuote - && !isSequenceReached(AS_OPEN_COMMENT) - && !isSequenceReached(AS_OPEN_LINE_COMMENT) ) - previousCommandChar = previousNonWSChar; - } - - unsigned int currentLineLength = currentLine.length(); - - if (charNum+1 < currentLineLength - && (!isWhiteSpace(peekNextChar()) || isInComment || isInLineComment)) - { - currentChar = currentLine[++charNum]; - if (isAfterFormattedWhiteSpace) - while (isWhiteSpace(currentChar) && charNum+1 < currentLineLength) - currentChar = currentLine[++charNum]; - - if (shouldConvertTabs && currentChar == '\t') - currentChar = ' '; - - return true; - } - // BEGIN Content patch ASFormatter450670.patch.bz2 - else if (isInLineComment && (charNum+1 == currentLineLength)) - { - // fix BUG #450670 - currentChar = ' '; - return true; - } - // END Content patch ASFormatter450670.patch.bz2 - else - { - if (sourceIterator->hasMoreLines()) - { - currentLine = sourceIterator->nextLine(); - if (currentLine.length() == 0) - { - /*think*/ currentLine = string(" "); - } - - // unless reading in the first line of the file, - // break a new line. - if (!isVirgin) - isInLineBreak = true; - else - isVirgin = false; - - if (isInLineComment) - isImmediatelyPostLineComment = true; - isInLineComment = false; - - trimNewLine(); - currentChar = currentLine[charNum]; - - // check if is in preprocessor right after the line break and line trimming - if (previousNonWSChar != '\\') - isInPreprocessor = false; - - if (shouldConvertTabs && currentChar == '\t') - currentChar = ' '; - - return true; - } - else - { - endOfCodeReached = true; - return false; - } - } - } - - /** - * jump over the leading white space in the current line, - * IF the line does not begin a comment or is in a preprocessor definition. - */ - void ASFormatter::trimNewLine() - { - unsigned int len = currentLine.length(); - charNum = 0; - - if (isInComment || isInPreprocessor) - return; - - while (isWhiteSpace(currentLine[charNum]) && charNum+1 < len) - ++charNum; - - doesLineStartComment = false; - if (isSequenceReached(string("/*"))) - { - charNum = 0; - doesLineStartComment = true; - } - } - - /** - * append a character to the current formatted line. - * Unless disabled (via canBreakLine == false), first check if a - * line-break has been registered, and if so break the - * formatted line, and only then append the character into - * the next formatted line. - * - * @param ch the character to append. - * @param canBreakLine if true, a registered line-break - */ - void ASFormatter::appendChar(char ch, bool canBreakLine) - { - if (canBreakLine && isInLineBreak) - breakLine(); - formattedLine.append(1, ch); - } - - /** - * append the CURRENT character (curentChar)to the current - * formatted line. Unless disabled (via canBreakLine == false), - * first check if a line-break has been registered, and if so - * break the formatted line, and only then append the character - * into the next formatted line. - * - * @param canBreakLine if true, a registered line-break - */ - void ASFormatter::appendCurrentChar(bool canBreakLine) - { - appendChar(currentChar, canBreakLine); - } - - /** - * append a string sequence to the current formatted line. - * Unless disabled (via canBreakLine == false), first check if a - * line-break has been registered, and if so break the - * formatted line, and only then append the sequence into - * the next formatted line. - * - * @param sequence the sequence to append. - * @param canBreakLine if true, a registered line-break - */ - void ASFormatter::appendSequence(const string &sequence, bool canBreakLine) - { - if (canBreakLine && isInLineBreak) - breakLine(); - formattedLine.append(sequence); - } - - /** - * append a space to the current formattedline, UNLESS the - * last character is already a white-space character. - */ - void ASFormatter::appendSpacePad() - { - int len = formattedLine.length(); - if (len == 0 || !isWhiteSpace(formattedLine[len-1])) - formattedLine.append(1, ' '); - } - - /** - * register a line break for the formatted line. - */ - void ASFormatter::breakLine() - { - isLineReady = true; - isInLineBreak = false; - - // queue an empty line prepend request if one exists - prependEmptyLine = isPrependPostBlockEmptyLineRequested; - - readyFormattedLine = formattedLine; - if (isAppendPostBlockEmptyLineRequested) - { - isAppendPostBlockEmptyLineRequested = false; - isPrependPostBlockEmptyLineRequested = true; - } - else - { - isPrependPostBlockEmptyLineRequested = false; - } - - formattedLine = ""; - } - - /** - * check if the currently reached open-bracket (i.e. '{') - * opens a: - * - a definition type block (such as a class or namespace), - * - a command block (such as a method block) - * - a static array - * this method takes for granted that the current character - * is an opening bracket. - * - * @return the type of the opened block. - */ - BracketType ASFormatter::getBracketType() const - { - BracketType returnVal; - - if (foundPreDefinitionHeader) - returnVal = DEFINITION_TYPE; - else - { - bool isCommandType; - isCommandType = ( foundPreCommandHeader - || ( currentHeader != NULL && isNonParenHeader ) - || ( previousCommandChar == ')' ) - || ( previousCommandChar == ':' && !foundQuestionMark ) - || ( previousCommandChar == ';' ) - || ( ( previousCommandChar == '{' || previousCommandChar == '}') - && isPreviousBracketBlockRelated ) ); - - returnVal = (isCommandType ? COMMAND_TYPE : ARRAY_TYPE); - } - - if (isOneLineBlockReached()) - returnVal = (BracketType) (returnVal | SINGLE_LINE_TYPE); - - return returnVal; - } - - /** - * check if the currently reached '*' or '&' character is - * a pointer-or-reference symbol, or another operator. - * this method takes for granted that the current character - * is either a '*' or '&'. - * - * @return whether current character is a reference-or-pointer - */ - bool ASFormatter::isPointerOrReference() const - { - bool isPR; - isPR = ( !isInPotentialCalculation - || IS_A(bracketTypeStack->back(), DEFINITION_TYPE) - || (!isLegalNameChar(previousNonWSChar) - && previousNonWSChar != ')' - && previousNonWSChar != ']') - ); - - if (!isPR) - { - char nextChar = peekNextChar(); - isPR |= (!isWhiteSpace(nextChar) - && nextChar != '-' - && nextChar != '(' - && nextChar != '[' - && !isLegalNameChar(nextChar)); - } - - return isPR; - } - - - /** - * check if the currently reached '-' character is - * a urinary minus - * this method takes for granted that the current character - * is a '-'. - * - * @return whether the current '-' is a urinary minus. - */ - bool ASFormatter::isUrinaryMinus() const - { - return ( (previousOperator == &AS_RETURN || !isalnum(previousCommandChar)) - && previousCommandChar != '.' - && previousCommandChar != ')' - && previousCommandChar != ']' ); - } - - - /** - * check if the currently reached '-' or '+' character is - * part of an exponent, i.e. 0.2E-5. - * this method takes for granted that the current character - * is a '-' or '+'. - * - * @return whether the current '-' is in an exponent. - */ - bool ASFormatter::isInExponent() const - { - int formattedLineLength = formattedLine.length(); - if (formattedLineLength >= 2) - { - char prevPrevFormattedChar = formattedLine[formattedLineLength - 2]; - char prevFormattedChar = formattedLine[formattedLineLength - 1]; - - return ( (prevFormattedChar == 'e' || prevFormattedChar == 'E') - && (prevPrevFormattedChar == '.' || isdigit(prevPrevFormattedChar)) ); - } - else - return false; - } - - /** - * check if a one-line bracket has been reached, - * i.e. if the currently reached '{' character is closed - * with a complimentry '}' elsewhere on the current line, - *. - * @return has a one-line bracket been reached? - */ - bool ASFormatter::isOneLineBlockReached() const - { - bool isInComment = false; - bool isInQuote = false; - int bracketCount = 1; - int currentLineLength = currentLine.length(); - int i = 0; - char ch = ' '; - char quoteChar = ' '; - - for (i = charNum + 1; i < currentLineLength; ++i) - { - ch = currentLine[i]; - - if (isInComment) - { - if (currentLine.COMPARE(i, 2, "*/") == 0) - { - isInComment = false; - ++i; - } - continue; - } - - if (ch == '\\') - { - ++i; - continue; - } - - if (isInQuote) - { - if (ch == quoteChar) - isInQuote = false; - continue; - } - - if (ch == '"' || ch == '\'') - { - isInQuote = true; - quoteChar = ch; - continue; - } - - if (currentLine.COMPARE(i, 2, "//") == 0) - break; - - if (currentLine.COMPARE(i, 2, "/*") == 0) - { - isInComment = true; - ++i; - continue; - } - - if (ch == '{') - ++bracketCount; - else if (ch == '}') - --bracketCount; - - if(bracketCount == 0) - return true; - } - - return false; - } - - - /** - * check if one of a set of headers has been reached in the - * current position of the current line. - * - * @return a pointer to the found header. Or a NULL if no header has been reached. - * @param headers a vector of headers - * @param checkBoundry - */ - const string *ASFormatter::findHeader(const vector<const string*> &headers, bool checkBoundry) - { - return ASBeautifier::findHeader(currentLine, charNum, headers, checkBoundry); - } - - - -#ifdef USES_NAMESPACE -} -#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. - */ - - -#ifndef ASFORMATTER_H -#define ASFORMATTER_H - -#include "ASBeautifier.h" -//#include "enums.h" -#include "compiler_defines.h" - -namespace astyle { - - class ASFormatter : public ASBeautifier - { - public: - ASFormatter(); - virtual ~ASFormatter(); - virtual void init(ASSourceIterator* iter); - virtual bool hasMoreLines() const; - virtual string nextLine(); - void setBracketFormatMode(BracketMode mode); - void setBreakClosingHeaderBracketsMode(bool state); - void setOperatorPaddingMode(bool mode); - void setParenthesisPaddingMode(bool mode); - void setBreakOneLineBlocksMode(bool state); - void setSingleStatementsMode(bool state); - void setTabSpaceConversionMode(bool state); - void setBreakBlocksMode(bool state); - void setBreakClosingHeaderBlocksMode(bool state); - void setBreakElseIfsMode(bool state); - - private: - void ASformatter(ASFormatter ©); // not to be imlpemented - void operator=(ASFormatter&); // not to be implemented - void staticInit(); - bool isFormattingEnabled() const; - void goForward(int i); - bool getNextChar(); - char peekNextChar() const; - bool isBeforeComment() const; - void trimNewLine(); - BracketType getBracketType() const; - bool isPointerOrReference() const; - bool isUrinaryMinus() const; - bool isInExponent() const; - bool isOneLineBlockReached() const; - void appendChar(char ch, bool canBreakLine = true); - void appendCurrentChar(bool canBreakLine = true); - void appendSequence(const string &sequence, bool canBreakLine = true); - void appendSpacePad(); - void breakLine(); - inline bool isSequenceReached(const string &sequence) const; - const string *findHeader(const vector<const string*> &headers, bool checkBoundry = true); - - static vector<const string*> headers; - static vector<const string*> nonParenHeaders; - static vector<const string*> preprocessorHeaders; - static vector<const string*> preDefinitionHeaders; - static vector<const string*> preCommandHeaders; - static vector<const string*> operators; - static vector<const string*> assignmentOperators; - static bool calledInitStatic; - - ASSourceIterator *sourceIterator; - vector<const string*> *preBracketHeaderStack; - vector<BracketType> *bracketTypeStack; - vector<int> *parenStack; - string readyFormattedLine; - string currentLine; - string formattedLine; - const string *currentHeader; - const string *previousOperator; - char currentChar; - char previousChar; - char previousNonWSChar; - char previousCommandChar; - char quoteChar; - unsigned int charNum; - BracketMode bracketFormatMode; - bool isVirgin; - bool shouldPadOperators; - bool shouldPadParenthesies; - bool shouldConvertTabs; - bool isInLineComment; - bool isInComment; - bool isInPreprocessor; - bool isInTemplate; // true both in template definitions (e.g. template<class A>) and template usage (e.g. F<int>). - bool doesLineStartComment; - bool isInQuote; - bool isSpecialChar; - bool isNonParenHeader; - bool foundQuestionMark; - bool foundPreDefinitionHeader; - bool foundPreCommandHeader; - bool isInLineBreak; - bool isInClosingBracketLineBreak; - bool endOfCodeReached; - bool isLineReady; - bool isPreviousBracketBlockRelated; - bool isInPotentialCalculation; - //bool foundOneLineBlock; - bool shouldBreakOneLineBlocks; - bool shouldReparseCurrentChar; - bool shouldBreakOneLineStatements; - bool shouldBreakLineAfterComments; - bool shouldBreakClosingHeaderBrackets; - bool shouldBreakElseIfs; - bool passedSemicolon; - bool passedColon; - bool isImmediatelyPostComment; - bool isImmediatelyPostLineComment; - bool isImmediatelyPostEmptyBlock; - - bool shouldBreakBlocks; - bool shouldBreakClosingHeaderBlocks; - bool isPrependPostBlockEmptyLineRequested; - bool isAppendPostBlockEmptyLineRequested; - - bool prependEmptyLine; - bool foundClosingHeader; - int previousReadyFormattedLineLength; - - bool isInHeader; - bool isImmediatelyPostHeader; - - }; - -} - -#endif -/* -* Copyright (c) 1998,1999,2000,2001,2002 Tal Davidson. All rights reserved. -* -* ASResource.cpp -* 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. -*/ - -#include "compiler_defines.h" -#include "ASResource.h" - -#include <string> - - -#ifdef USES_NAMESPACE -using namespace std; - -namespace astyle - { -#endif - - const string ASResource::AS_IF = string("if"); - const string ASResource::AS_ELSE = string ("else"); - const string ASResource::AS_FOR = string("for"); - const string ASResource::AS_DO = string("do"); - const string ASResource::AS_WHILE = string("while"); - const string ASResource::AS_SWITCH = string ("switch"); - const string ASResource::AS_CASE = string ("case"); - const string ASResource::AS_DEFAULT = string("default"); - const string ASResource::AS_CLASS = string("class"); - const string ASResource::AS_STRUCT = string("struct"); - const string ASResource::AS_UNION = string("union"); - const string ASResource::AS_INTERFACE = string("interface"); - const string ASResource::AS_NAMESPACE = string("namespace"); - const string ASResource::AS_EXTERN = string("extern"); - const string ASResource::AS_PUBLIC = string("public"); - const string ASResource::AS_PROTECTED = string("protected"); - const string ASResource::AS_PRIVATE = string("private"); - const string ASResource::AS_STATIC = string("static"); - const string ASResource::AS_SYNCHRONIZED = string("synchronized"); - const string ASResource::AS_OPERATOR = string("operator"); - const string ASResource::AS_TEMPLATE = string("template"); - const string ASResource::AS_TRY = string("try"); - const string ASResource::AS_CATCH = string("catch"); - const string ASResource::AS_FINALLY = string("finally"); - const string ASResource::AS_THROWS = string("throws"); - const string ASResource::AS_CONST = string("const"); - - const string ASResource::AS_ASM = string("asm"); - - const string ASResource::AS_BAR_DEFINE = string("#define"); - const string ASResource::AS_BAR_INCLUDE = string("#include"); - const string ASResource::AS_BAR_IF = string("#if"); - const string ASResource::AS_BAR_EL = string("#el"); - const string ASResource::AS_BAR_ENDIF = string("#endif"); - - const string ASResource::AS_OPEN_BRACKET = string("{"); - const string ASResource::AS_CLOSE_BRACKET = string("}"); - const string ASResource::AS_OPEN_LINE_COMMENT = string("//"); - const string ASResource::AS_OPEN_COMMENT = string("/*"); - const string ASResource::AS_CLOSE_COMMENT = string("*/"); - - const string ASResource::AS_ASSIGN = string("="); - const string ASResource::AS_PLUS_ASSIGN = string("+="); - const string ASResource::AS_MINUS_ASSIGN = string("-="); - const string ASResource::AS_MULT_ASSIGN = string("*="); - const string ASResource::AS_DIV_ASSIGN = string("/="); - const string ASResource::AS_MOD_ASSIGN = string("%="); - const string ASResource::AS_OR_ASSIGN = string("|="); - const string ASResource::AS_AND_ASSIGN = string("&="); - const string ASResource::AS_XOR_ASSIGN = string("^="); - const string ASResource::AS_GR_GR_ASSIGN = string(">>="); - const string ASResource::AS_LS_LS_ASSIGN = string("<<="); - const string ASResource::AS_GR_GR_GR_ASSIGN = string(">>>="); - const string ASResource::AS_LS_LS_LS_ASSIGN = string("<<<="); - const string ASResource::AS_RETURN = string("return"); - - const string ASResource::AS_EQUAL = string("=="); - const string ASResource::AS_PLUS_PLUS = string("++"); - const string ASResource::AS_MINUS_MINUS = string("--"); - const string ASResource::AS_NOT_EQUAL = string("!="); - const string ASResource::AS_GR_EQUAL = string(">="); - const string ASResource::AS_GR_GR = string(">>"); - const string ASResource::AS_GR_GR_GR = string(">>>"); - const string ASResource::AS_LS_EQUAL = string("<="); - const string ASResource::AS_LS_LS = string("<<"); - const string ASResource::AS_LS_LS_LS = string("<<<"); - const string ASResource::AS_ARROW = string("->"); - const string ASResource::AS_AND = string("&&"); - const string ASResource::AS_OR = string("||"); - const string ASResource::AS_COLON_COLON = string("::"); - const string ASResource::AS_PAREN_PAREN = string("()"); - const string ASResource::AS_BLPAREN_BLPAREN = string("[]"); - - const string ASResource::AS_PLUS = string("+"); - const string ASResource::AS_MINUS = string("-"); - const string ASResource::AS_MULT = string("*"); - const string ASResource::AS_DIV = string("/"); - const string ASResource::AS_MOD = string("%"); - const string ASResource::AS_GR = string(">"); - const string ASResource::AS_LS = string("<"); - const string ASResource::AS_NOT = string("!"); - const string ASResource::AS_BIT_OR = string("|"); - const string ASResource::AS_BIT_AND = string("&"); - const string ASResource::AS_BIT_NOT = string("~"); - const string ASResource::AS_BIT_XOR = string("^"); - const string ASResource::AS_QUESTION = string("?"); - const string ASResource::AS_COLON = string(":"); - const string ASResource::AS_COMMA = string(","); - const string ASResource::AS_SEMICOLON = string(";"); - - const string ASResource::AS_FOREACH = string("foreach"); - const string ASResource::AS_LOCK = string("lock"); - const string ASResource::AS_UNSAFE = string("unsafe"); - const string ASResource::AS_FIXED = string("fixed"); - const string ASResource::AS_GET = string("get"); - const string ASResource::AS_SET = string("set"); - const string ASResource::AS_ADD = string("add"); - const string ASResource::AS_REMOVE = string("remove"); - -#ifdef USES_NAMESPACE -} -#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. - */ - - -#ifndef ASRES_H -#define ASRES_H - -#include "compiler_defines.h" -#include "ASStreamIterator.h" - -#include <iostream> -#include <fstream> -#include <string> - -namespace astyle { - -class ASResource - { - public: - static const string AS_IF, AS_ELSE; - static const string AS_DO, AS_WHILE; - static const string AS_FOR; - static const string AS_SWITCH, AS_CASE, AS_DEFAULT; - static const string AS_TRY, AS_CATCH, AS_THROWS, AS_FINALLY; - static const string AS_PUBLIC, AS_PROTECTED, AS_PRIVATE; - static const string AS_CLASS, AS_STRUCT, AS_UNION, AS_INTERFACE, AS_NAMESPACE, AS_EXTERN; - static const string AS_STATIC; - static const string AS_CONST; - static const string AS_SYNCHRONIZED; - static const string AS_OPERATOR, AS_TEMPLATE; - static const string AS_OPEN_BRACKET, AS_CLOSE_BRACKET; - static const string AS_OPEN_LINE_COMMENT, AS_OPEN_COMMENT, AS_CLOSE_COMMENT; - static const string AS_BAR_DEFINE, AS_BAR_INCLUDE, AS_BAR_IF, AS_BAR_EL, AS_BAR_ENDIF; - static const string AS_RETURN; - static const string AS_ASSIGN, AS_PLUS_ASSIGN, AS_MINUS_ASSIGN, AS_MULT_ASSIGN; - static const string AS_DIV_ASSIGN, AS_MOD_ASSIGN, AS_XOR_ASSIGN, AS_OR_ASSIGN, AS_AND_ASSIGN; - static const string AS_GR_GR_ASSIGN, AS_LS_LS_ASSIGN, AS_GR_GR_GR_ASSIGN, AS_LS_LS_LS_ASSIGN; - static const string AS_EQUAL, AS_PLUS_PLUS, AS_MINUS_MINUS, AS_NOT_EQUAL, AS_GR_EQUAL, AS_GR_GR_GR, AS_GR_GR; - static const string AS_LS_EQUAL, AS_LS_LS_LS, AS_LS_LS, AS_ARROW, AS_AND, AS_OR; - static const string AS_COLON_COLON, AS_PAREN_PAREN, AS_BLPAREN_BLPAREN; - static const string AS_PLUS, AS_MINUS, AS_MULT, AS_DIV, AS_MOD, AS_GR, AS_LS; - static const string AS_NOT, AS_BIT_XOR, AS_BIT_OR, AS_BIT_AND, AS_BIT_NOT; - static const string AS_QUESTION, AS_COLON, AS_SEMICOLON, AS_COMMA; - static const string AS_ASM; - static const string AS_FOREACH, AS_LOCK, AS_UNSAFE, AS_FIXED; - static const string AS_GET, AS_SET, AS_ADD, AS_REMOVE; - }; -} -#endif - -#ifndef ASSOURCEITERATOR_H -#define ASSOURCEITERATOR_H - -#include <string> -#include "compiler_defines.h" - -namespace astyle - { - - class ASSourceIterator - { - public: - virtual bool hasMoreLines() const = 0; - virtual std::string nextLine() = 0; - }; -} - -#endif -#include "compiler_defines.h" -#include "ASStreamIterator.h" - -#include <iostream> -#include <fstream> -#include <string> - -using namespace astyle; - -ASStreamIterator::ASStreamIterator(istream *in) -{ - inStream = in; -} - -ASStreamIterator::~ASStreamIterator() -{ - delete inStream; -} - - -bool ASStreamIterator::hasMoreLines() const - { - if (*inStream) - return true; - else - return false; - } - -/* -string ASStreamIterator::nextLine() -{ - char theInChar; - char peekedChar; - int theBufferPosn = 0; - - // - // treat '\n', '\r', '\n\r' and '\r\n' as an endline. - // - while (theBufferPosn < 2047 && inStream->get(theInChar)) - // while not eof - { - if (theInChar != '\n' && theInChar != '\r') - { - buffer[theBufferPosn] = theInChar; - theBufferPosn++; - } - else - { - peekedChar = inStream->peek(); - if (peekedChar != theInChar && (peekedChar == '\r' || peekedChar == '\n') ) - { - inStream->get(theInChar); - } - break; - } - } - buffer[theBufferPosn] = '\0'; - - return string(buffer); -} -*/ - - -string ASStreamIterator::nextLine() -{ - char *srcPtr; - char *filterPtr; - - inStream->getline(buffer, 2047); - srcPtr = filterPtr = buffer; - - while (*srcPtr != 0) - { - if (*srcPtr != '\r') - *filterPtr++ = *srcPtr; - srcPtr++; - } - *filterPtr = 0; - - return string(buffer); -} - -/* - * 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. - */ - - -#ifndef ASSTREAMITERATOR_H -#define ASSTREAMITERATOR_H - -#include "ASSourceIterator.h" - -using namespace std; - -namespace astyle - { - class ASStreamIterator : - public ASSourceIterator - { - public: - ASStreamIterator(istream *in); - virtual ~ASStreamIterator(); - bool hasMoreLines() const; - string nextLine(); - - private: - istream * inStream; - char buffer[2048]; - }; - -} - -#endif -/*************************************************************************** - charcodes.cpp - description - ------------------- - begin : Wed Nov 24 2003 - copyright : (C) 2003 by André 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. * - * * - ***************************************************************************/ - -// FILE SHOULD BE REMOVED FROM PROJECT - -#ifndef CHAR_CODES -#define CHAR_CODES - -#ifdef _WIN32 - -#define AUML_LC 228 -#define OUML_LC 246 -#define UUML_LC 252 - -#define AUML_UC 196 -#define OUML_UC 214 -#define UUML_UC 220 - - -#define AACUTE_LC 225 -#define EACUTE_LC 233 -#define OACUTE_LC 243 -#define UACUTE_LC 250 - -#define AACUTE_UC 193 -#define EACUTE_UC 201 -#define OACUTE_UC 211 -#define UACUTE_UC 218 - -#define AGRAVE_LC 224 -#define EGRAVE_LC 232 -#define OGRAVE_LC 242 -#define UGRAVE_LC 249 - -#define AGRAVE_UC 192 -#define EGRAVE_UC 200 -#define OGRAVE_UC 210 -#define UGRAVE_UC 217 - -#define SZLIG 223 - -/* DOS CONSOLE CODES -#define AUML_LC 132 -#define OUML_LC 148 -#define UUML_LC 129 - -#define AUML_UC 142 -#define OUML_UC 153 -#define UUML_UC 154 - - -#define AACUTE_LC 160 -#define EACUTE_LC 130 -#define OACUTE_LC 162 -#define UACUTE_LC 163 - -#define AACUTE_UC 181 -#define EACUTE_UC 144 -#define OACUTE_UC 224 -#define UACUTE_UC 233 - -#define AGRAVE_LC 133 -#define EGRAVE_LC 138 -#define OGRAVE_LC 149 -#define UGRAVE_LC 151 - -#define AGRAVE_UC 183 -#define EGRAVE_UC 212 -#define OGRAVE_UC 227 -#define UGRAVE_UC 235 - -#define SZLIG 225 -*/ - -#else - -#define AUML_LC 164 -#define OUML_LC 182 -#define UUML_LC 188 - -#define AUML_UC 132 -#define OUML_UC 150 -#define UUML_UC 156 - - -#define AACUTE_LC 161 -#define EACUTE_LC 169 -#define OACUTE_LC 179 -#define UACUTE_LC 186 - -#define AACUTE_UC 129 -#define EACUTE_UC 137 -#define OACUTE_UC 147 -#define UACUTE_UC 154 - -#define AGRAVE_LC 160 -#define EGRAVE_LC 168 -#define OGRAVE_LC 178 -#define UGRAVE_LC 185 - -#define AGRAVE_UC 128 -#define EGRAVE_UC 136 -#define OGRAVE_UC 146 -#define UGRAVE_UC 153 - -#define SZLIG 159 - -#endif - -#endif -/*************************************************************************** - cmdlineoptions.cpp - description - ------------------- - begin : Sun Nov 25 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 "cmdlineoptions.h" - -using namespace std; - -/* Siehe man getopt (3) - Konstruktor legt Optionen und Argumente fest -*/ -CmdLineOptions::CmdLineOptions(int argc, char *argv[]): - numberSpaces(0), - wrappingStyle(highlight::WRAP_DISABLED), - outputType (highlight::HTML), - opt_language (false), - opt_include_style (false), - opt_help (false), - opt_version (false), - opt_verbose (false), - opt_linenumbers (false), - opt_style (false), - opt_batch_mode (false), - opt_fragment (false) , - opt_attach_line_anchors (false), - opt_show_themes (false), - opt_show_langdefs (false), - opt_printindex(false), - opt_quiet(false), - opt_xslfo_fop(false), - opt_replacequotes(false), - opt_print_progress(false), - opt_fill_zeroes(false), - opt_stylepath_explicit(false), - opt_force_output(false), - configFileRead(false), - helpLang("en"), - charset("ISO-8859-1") -{ - - loadConfigurationFile(); - - int c, option_index = 0; - static struct option long_options[] = - { - {OPT_OUT, 1, 0, S_OPT_OUT}, - {OPT_IN, 1, 0, S_OPT_IN}, - {OPT_SYNTAX, 1, 0, S_OPT_SYNTAX}, - {OPT_VERBOSE, 0, 0, S_OPT_VERBOSE}, - {OPT_INC_STYLE, 0, 0, S_OPT_INC_STYLE}, - {OPT_HELP, 0, 0, S_OPT_HELP}, - {OPT_HELPINT, 1, 0, S_OPT_HELPINT}, - {OPT_LINENO,0,0,S_OPT_LINENO}, - {OPT_STYLE, 1,0,S_OPT_STYLE}, - {OPT_STYLE_OUT, 1, 0,S_OPT_STYLE_OUT}, - {OPT_STYLE_IN, 1, 0,S_OPT_STYLE_IN}, - {OPT_DELTABS,1,0,S_OPT_DELTABS}, - {OPT_XHTML, 0,0,S_OPT_XHTML}, - {OPT_RTF, 0,0,S_OPT_RTF}, - {OPT_TEX,0, 0,S_OPT_TEX}, - {OPT_LATEX,0, 0,S_OPT_LATEX}, - {OPT_XSLFO,0, 0,S_OPT_XSLFO}, - {OPT_ANSI,0, 0,S_OPT_ANSI}, - {OPT_XML,0, 0,S_OPT_XML}, - {OPT_BATCHREC,1,0,S_OPT_BATCHREC}, - {OPT_FRAGMENT,0,0,S_OPT_FRAGMENT}, - {OPT_ANCHORS, 0,0,S_OPT_ANCHORS }, - {OPT_LISTTHEMES, 0,0,S_OPT_LISTTHEMES }, - {OPT_LISTLANGS, 0,0,S_OPT_LISTLANGS }, - {OPT_OUTDIR,1,0,S_OPT_OUTDIR}, - {OPT_VERSION,0,0,0}, - {OPT_FORMATSTYLE,1,0,S_OPT_FORMATSTYLE}, - {OPT_DATADIR,1,0,S_OPT_DATADIR}, - {OPT_ADDDATADIR,1,0,S_OPT_ADDDATADIR}, - {OPT_INDEXFILE,0,0,S_OPT_INDEXFILE}, - {OPT_WRAP,0,0,S_OPT_WRAP}, - {OPT_WRAPSIMPLE,0,0,S_OPT_WRAPSIMPLE}, - {OPT_QUIET,0,0,S_OPT_QUIET}, - {OPT_REPLACE_QUOTES,0,0,S_OPT_REPLACE_QUOTES}, - {OPT_PROGRESSBAR,0,0,S_OPT_PROGRESSBAR}, - {OPT_FILLZEROES,0,0,S_OPT_FILLZEROES}, - {OPT_ENCODING,1,0,S_OPT_ENCODING}, - - //remove as soon as APAche fixes the bug in FOP (0.20.5) - {OPT_FOP,0,0,S_OPT_FOP}, - - //deprecated - {OPT_CSSOUT,1,0,0}, - {OPT_CSSIN,1,0,0}, - {OPT_INC_CSS,0,0,0}, - {OPT_FORCE_OUTPUT,0,0,0}, - - {0, 0, 0, 0} - }; - - while (1) - { - c = getopt_long (argc, argv,S_OPTIONS_STRING,long_options, &option_index); - if (c == -1) - break; - - switch (c) - { - case 0: // long options - if (long_options[option_index].name==OPT_VERSION) { - opt_version = true; - } - if (long_options[option_index].name==OPT_CSSOUT) { - styleOutFilename=string(optarg); - printDeprecatedWarning(OPT_CSSOUT, OPT_STYLE_OUT); - } - if (long_options[option_index].name==OPT_CSSIN) { - styleInFilename=string(optarg); - printDeprecatedWarning(OPT_CSSIN, OPT_STYLE_IN); - } - if (long_options[option_index].name==OPT_INC_CSS) { - opt_include_style = true; - printDeprecatedWarning(OPT_INC_CSS, OPT_INC_STYLE); - } - if (long_options[option_index].name==OPT_FORCE_OUTPUT) { - opt_force_output = true; - } - break; - case S_OPT_OUT: - outFilename=string(optarg); - break; - case S_OPT_IN: - inputFileNames.push_back(string(optarg)); - break; - case S_OPT_STYLE_OUT: - styleOutFilename=string(optarg); - opt_stylepath_explicit=true; - break; - case S_OPT_STYLE_IN: - styleInFilename=string(optarg); - break; - case S_OPT_VERBOSE: - opt_verbose = true; - break; - case S_OPT_QUIET: - opt_quiet = true; - break; - case S_OPT_INC_STYLE: - opt_include_style = true; - break; - case S_OPT_HELPINT: - helpLang=string(optarg); - case S_OPT_HELP: - opt_help = true; - break; - case S_OPT_LINENO: - opt_linenumbers = true; - break; - case '?': - //opt_help = true; - break; - case S_OPT_STYLE: - styleName=string(optarg); - opt_style = true; - break; - case S_OPT_SYNTAX: - language=string(optarg); - opt_language = true; - break; - case S_OPT_DELTABS: - numberSpaces = StringTools::str2int (string(optarg)); - break; - case S_OPT_XHTML: - outputType=highlight::XHTML; - break; - case S_OPT_RTF: - outputType=highlight::RTF; - break; - case S_OPT_TEX: - outputType=highlight::TEX; - break; - case S_OPT_LATEX: - outputType=highlight::LATEX; - break; - case S_OPT_XSLFO: - outputType=highlight::XSLFO; - break; - case S_OPT_ANSI: - outputType=highlight::ANSI; - break; - case S_OPT_XML: - outputType=highlight::XML; - break; - case S_OPT_BATCHREC: - opt_batch_mode = true; - readDirectory(string(optarg)); - break; - case S_OPT_FRAGMENT: - opt_fragment = true; - break; - case S_OPT_ANCHORS: - opt_attach_line_anchors = true; - break; - case S_OPT_LISTTHEMES: - opt_show_themes = true; - break; - case S_OPT_LISTLANGS: - opt_show_langdefs = true; - break; - case S_OPT_OUTDIR: - outDirectory = validateDirPath(string(optarg)); - break; - case S_OPT_FORMATSTYLE: - indentScheme =string(optarg); - break; - case S_OPT_ENCODING: - charset =string(optarg); - break; - case S_OPT_DATADIR: - dataDir=validateDirPath(string(optarg)); - break; - case S_OPT_ADDDATADIR: - additionalDataDir=validateDirPath(string(optarg)); - break; - case S_OPT_INDEXFILE: - opt_printindex=true; - break; - case S_OPT_WRAPSIMPLE: - wrappingStyle = highlight::WRAP_SIMPLE; - break; - case S_OPT_WRAP: - wrappingStyle = highlight::WRAP_DEFAULT; - break; - case S_OPT_FOP: - opt_xslfo_fop=true; - break; - case S_OPT_REPLACE_QUOTES: - opt_replacequotes=true; - break; - case S_OPT_PROGRESSBAR: - opt_print_progress=true; - break; - case S_OPT_FILLZEROES: - opt_fill_zeroes=true; - break; - default: - cerr <<"higlight: Unknown option " <<c<< endl; - } - } - - if (optind < argc) //still args left - { - if (inputFileNames.empty()) { - while (optind < argc){ - inputFileNames.push_back(string(argv[optind++])); - } - } - } else if (inputFileNames.empty()) { - inputFileNames.push_back(""); - } - if (printDebugInfo() && configFileRead) { - cout << "Configuration file \""<<configFilePath<<"\" was read.\n"; - } -} - -CmdLineOptions::~CmdLineOptions(){ -} - -const string &CmdLineOptions::getSingleOutFilename() - { - if (!inputFileNames.empty() && !outDirectory.empty()) { - if (outFilename.empty()) { - outFilename = outDirectory; - int delim = getSingleInFilename().find_last_of(Platform::pathSeparator)+1; - outFilename += getSingleInFilename().substr((delim>-1)?delim:0) - + getOutFileSuffix(); - } - } - return outFilename; - } - -const string &CmdLineOptions::getSingleInFilename() const - { - return inputFileNames[0]; - } - -const string &CmdLineOptions::getOutDirectory() - { - if (!outFilename.empty() && !enableBatchMode()){ - outDirectory=getDirName(outFilename); - } - return outDirectory; - } - -const string CmdLineOptions::getStyleOutFilename() const - { - if (!styleOutFilename.empty()) return styleOutFilename; - return (outputType==highlight::HTML || - outputType==highlight::XHTML)? "highlight.css":"highlight.sty"; - } -const string &CmdLineOptions::getStyleInFilename() const - { - return styleInFilename; - } -int CmdLineOptions::getNumberSpaces() const - { - return numberSpaces; - } -bool CmdLineOptions::printVersion()const - { - return opt_version; - } -bool CmdLineOptions::printHelp()const - { - return opt_help; - } -bool CmdLineOptions::printDebugInfo()const - { - return opt_verbose; - } -bool CmdLineOptions::quietMode()const - { - return opt_quiet; - } -bool CmdLineOptions::includeStyleDef()const - { - return opt_include_style; - } - -bool CmdLineOptions::formatSupportsExtStyle(){ - return outputType==highlight::HTML || - outputType==highlight::XHTML || - outputType==highlight::LATEX || - outputType==highlight::TEX; -} - -bool CmdLineOptions::printLineNumbers()const - { - return opt_linenumbers; - } - -string CmdLineOptions::getStyleName()const - { - return ( ( opt_style) ? styleName+".style" : "kwrite.style" ); - } -bool CmdLineOptions::enableBatchMode()const{ - return inputFileNames.size()>1 || opt_batch_mode; -} -bool CmdLineOptions::fragmentOutput()const{ - return opt_fragment; -} -string CmdLineOptions::getOutFileSuffix()const{ - switch (outputType){ - case highlight::XHTML: return ".xhtml"; - case highlight::RTF: return ".rtf"; - case highlight::TEX: - case highlight::LATEX: return ".tex"; - case highlight::XSLFO: return ".fo"; - case highlight::XML: return ".xml"; - default: return ".html"; - } -} -string CmdLineOptions::getDirName(const string & path) { - size_t dirNameLength=path.rfind(Platform::pathSeparator); - return (dirNameLength==string::npos)?string():path.substr(0, dirNameLength+1); -} -bool CmdLineOptions::attachLineAnchors()const{ - return opt_attach_line_anchors; -} -bool CmdLineOptions::showThemes()const{ - return opt_show_themes; -} -bool CmdLineOptions::showLangdefs()const{ - return opt_show_langdefs; -} -bool CmdLineOptions::outDirGiven()const{ - return !outFilename.empty(); -} -bool CmdLineOptions::fopCompatible() const { - return opt_xslfo_fop; -} -bool CmdLineOptions::replaceQuotes() const { - return opt_replacequotes; -} -bool CmdLineOptions::getFlag( const string& paramVal){ - return StringTools::lowerCase(paramVal)=="true"; -} -bool CmdLineOptions::formattingEnabled(){ - return !indentScheme.empty(); -} -bool CmdLineOptions::dataDirGiven()const { - return !dataDir.empty(); -} -bool CmdLineOptions::additionalDataDirGiven()const { - return !additionalDataDir.empty(); -} -const string &CmdLineOptions::getDataDir() const { - return dataDir; -} -const string &CmdLineOptions::getIndentScheme() const { - return indentScheme; -} -const string &CmdLineOptions::getAdditionalDataDir()const{ - return additionalDataDir; -} -const string &CmdLineOptions::getLanguage() const { - return language; -} -const string&CmdLineOptions::getCharSet() const{ - return charset; -} -bool CmdLineOptions::printIndexFile() const{ - return opt_printindex && (outputType==highlight::HTML || - outputType==highlight::XHTML); -} -bool CmdLineOptions::printProgress() const{ - return opt_print_progress; -} -bool CmdLineOptions::fillLineNrZeroes() const{ - return opt_fill_zeroes; -} -bool CmdLineOptions::syntaxGiven() const{ - return opt_language; -} -bool CmdLineOptions::omitEncodingName() const{ - return StringTools::lowerCase(charset)=="none"; -} -bool CmdLineOptions::forceOutput() const{ - return opt_force_output; -} -const string CmdLineOptions::getHelpLang()const{ - return helpLang+".help"; -} -highlight::WrapMode CmdLineOptions::getWrappingStyle() const { - return wrappingStyle; -} -const vector <string> & CmdLineOptions::getInputFileNames() const{ - return inputFileNames; -} -void CmdLineOptions::readDirectory(const string & wildcard){ - // get matching files, use recursive search - bool directoryOK=Platform::getDirectoryEntries(inputFileNames, wildcard, true); - if (!directoryOK) - { - cerr << "highlight: No files matched the pattern \"" - << wildcard << "\"."<< endl; - } -} -void CmdLineOptions::loadConfigurationFile() -{ - #ifndef _WIN32 - #ifdef CONFIG_FILE_PATH - configFilePath=CONFIG_FILE_PATH; - #else - char* homeEnv=getenv("HOME"); - if (homeEnv==NULL) return; - configFilePath=string(homeEnv)+"/.highlightrc"; - #endif - #else - configFilePath = Platform::getAppPath() + "highlight.conf"; - #endif - ConfigurationReader presets(configFilePath); - - if (presets.found()) - { - string paramVal; - configFileRead=true; - - styleOutFilename = presets.getParameter(OPT_STYLE_OUT); - styleInFilename = presets.getParameter(OPT_STYLE_IN); - styleName = presets.getParameter(OPT_STYLE); - opt_style = !styleName.empty(); - language = presets.getParameter(OPT_SYNTAX); - opt_language = !language.empty(); - numberSpaces = StringTools::str2int(presets.getParameter(OPT_DELTABS)); - indentScheme = presets.getParameter(OPT_FORMATSTYLE); - - paramVal = presets.getParameter(OPT_DATADIR); - if (!paramVal.empty()) { - dataDir=validateDirPath( paramVal); - } - paramVal = presets.getParameter(OPT_ADDDATADIR); - if (!paramVal.empty()) { - additionalDataDir=validateDirPath(paramVal); - } - paramVal = presets.getParameter(OPT_OUTDIR); - if (!paramVal.empty()) { - outDirectory=validateDirPath(paramVal); - } - paramVal = presets.getParameter(OPT_ENCODING); - if (!paramVal.empty()) { - charset=paramVal; - } - - opt_include_style=getFlag(presets.getParameter(OPT_INC_STYLE)); - opt_verbose=getFlag(presets.getParameter(OPT_VERBOSE)); - opt_linenumbers=getFlag(presets.getParameter(OPT_LINENO)); - opt_fragment=getFlag(presets.getParameter(OPT_FRAGMENT)); - opt_attach_line_anchors=getFlag(presets.getParameter(OPT_ANCHORS)); - opt_printindex=getFlag(presets.getParameter(OPT_INDEXFILE)); - opt_quiet=getFlag(presets.getParameter(OPT_QUIET)); - opt_xslfo_fop=getFlag(presets.getParameter(OPT_FOP)); - opt_replacequotes=getFlag(presets.getParameter(OPT_REPLACE_QUOTES)); - opt_print_progress=getFlag(presets.getParameter(OPT_PROGRESSBAR)); - opt_fill_zeroes=getFlag(presets.getParameter(OPT_FILLZEROES)); - - if (getFlag(presets.getParameter(OPT_WRAP))) { - wrappingStyle=highlight::WRAP_DEFAULT; - } - if (getFlag(presets.getParameter(OPT_WRAPSIMPLE))) { - wrappingStyle=highlight::WRAP_SIMPLE; - } - if (getFlag(presets.getParameter(OPT_XHTML))) { - outputType=highlight::XHTML; - } else if (getFlag(presets.getParameter(OPT_RTF))) { - outputType=highlight::RTF; - } else if (getFlag(presets.getParameter(OPT_TEX))) { - outputType=highlight::TEX; - } else if (getFlag(presets.getParameter(OPT_LATEX))) { - outputType=highlight::LATEX; - } else if (getFlag(presets.getParameter(OPT_XSLFO))) { - outputType=highlight::XSLFO; - } else if (getFlag(presets.getParameter(OPT_ANSI))) { - outputType=highlight::ANSI; - } else if (getFlag(presets.getParameter(OPT_XML))) { - outputType=highlight::XML; - } - } -} - -string CmdLineOptions::validateDirPath(const string & path){ - return (path[path.length()-1] !=Platform::pathSeparator)? - path+Platform::pathSeparator : path; -} - -highlight::OutputType CmdLineOptions::getOutputType() const { - return outputType; -} - -void CmdLineOptions::printDeprecatedWarning(const char *oldOption, const char *newOption){ - cerr << "Warning: Long option \""<<oldOption << "\" is DEPRECATED."; - cerr << " Use \""<<newOption << "\" instead.\n"; -} -/*************************************************************************** - cmdlineoptions.h - description - ------------------- - begin : Sun Nov 25 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 CMDLINEOPTIONS_H -#define CMDLINEOPTIONS_H - -#include <string> -#include <map> -#include <cstdlib> -#include <iostream> -#include <fstream> - -#include "platform_fs.h" -#include "configurationreader.h" -#include "datadir.h" -#include "enums.h" - -#ifdef _WIN32 - #include <windows.h> -#endif - -// If your system does not know getopt_long, define USE_LOCAL_GETOPT -#if defined(_WIN32) || defined(__SVR4) || defined(__sun__) - // some compilers don't like redefinitions... - #ifndef USE_LOCAL_GETOPT - #define USE_LOCAL_GETOPT - #endif -#endif - -#ifdef USE_LOCAL_GETOPT - #include "getopt.h" -#else - #include <getopt.h> -#endif - -#define OPT_VERBOSE "verbose" -#define OPT_INC_STYLE "include-style" -#define OPT_HELP "help" -#define OPT_LINENO "linenumbers" -#define OPT_XHTML "xhtml" -#define OPT_RTF "rtf" -#define OPT_TEX "tex" -#define OPT_LATEX "latex" -#define OPT_XSLFO "xsl-fo" -#define OPT_FRAGMENT "fragment" -#define OPT_ANCHORS "anchors" -#define OPT_LISTTHEMES "list-themes" -#define OPT_LISTLANGS "list-langs" -#define OPT_VERSION "version" -#define OPT_IN "input" -#define OPT_OUT "output" -#define OPT_SYNTAX "syntax" -#define OPT_STYLE "style" -#define OPT_STYLE_OUT "style-outfile" -#define OPT_STYLE_IN "style-infile" - -#define OPT_DELTABS "replace-tabs" -#define OPT_BATCHREC "batch-recursive" -#define OPT_OUTDIR "outdir" -#define OPT_FORMATSTYLE "format-style" -#define OPT_DATADIR "data-dir" -#define OPT_ADDDATADIR "add-data-dir" -#define OPT_INDEXFILE "print-index" -#define OPT_HELPINT "help-int" -#define OPT_WRAP "wrap" -#define OPT_WRAPSIMPLE "wrap-simple" -#define OPT_QUIET "quiet" -#define OPT_REPLACE_QUOTES "replace-quotes" -#define OPT_FOP "fop-compatible" -#define OPT_PROGRESSBAR "progress" -#define OPT_FILLZEROES "zeroes" -#define OPT_ANSI "ansi" -#define OPT_XML "xml" -#define OPT_ENCODING "encoding" -#define OPT_FORCE_OUTPUT "force" - -#define S_OPT_ANSI 'A' -#define S_OPT_OUT 'o' -#define S_OPT_IN 'i' -#define S_OPT_SYNTAX 'S' -#define S_OPT_VERBOSE 'v' -#define S_OPT_INC_STYLE 'I' -#define S_OPT_HELP 'h' -#define S_OPT_HELPINT 'H' -#define S_OPT_LINENO 'l' -#define S_OPT_STYLE 's' -#define S_OPT_STYLE_OUT 'c' -#define S_OPT_STYLE_IN 'e' -#define S_OPT_DELTABS 't' -#define S_OPT_XHTML 'X' -#define S_OPT_RTF 'R' -#define S_OPT_TEX 'T' -#define S_OPT_LATEX 'L' -#define S_OPT_XSLFO 'Y' -#define S_OPT_XML 'Z' -#define S_OPT_BATCHREC 'B' -#define S_OPT_FRAGMENT 'f' -#define S_OPT_ANCHORS 'a' -#define S_OPT_LISTTHEMES 'w' -#define S_OPT_LISTLANGS 'p' -#define S_OPT_OUTDIR 'O' - -#define S_OPT_FORMATSTYLE 'F' -#define S_OPT_DATADIR 'D' -#define S_OPT_ADDDATADIR 'E' -#define S_OPT_INDEXFILE 'C' -#define S_OPT_WRAP 'W' -#define S_OPT_WRAPSIMPLE 'V' -#define S_OPT_QUIET 'q' -#define S_OPT_FOP 'g' -#define S_OPT_REPLACE_QUOTES 'r' -#define S_OPT_VERSION 'Q' -#define S_OPT_PROGRESSBAR 'P' -#define S_OPT_FILLZEROES 'z' -#define S_OPT_ENCODING 'u' - -// deprecated: -#define OPT_CSSOUT "css-outfile" -#define OPT_CSSIN "css-infile" -#define OPT_INC_CSS "include-css" - - -#define S_OPTIONS_STRING "o:i:S:B:O:s:c:e:t:u:F:D:H:E:afghlvwpqrzACILYRTZXUV::W::P" - -using namespace std; - -/**Command line options*/ - -class CmdLineOptions - { - public: - - /**Constructor - \param argc Argument count - \param argv Argument strings - */ - CmdLineOptions(int argc, char *argv[]); - ~CmdLineOptions(); - - /** \return Single output file name*/ - const string &getSingleOutFilename(); - - /** \return Single input file name*/ - const string &getSingleInFilename() const; - - /** \return Output directory*/ - const string& getOutDirectory() ; - - /** \return Style output file name*/ - const string getStyleOutFilename() const; - - /** \return Style input file name*/ - const string&getStyleInFilename() const; - - /** \return Char set*/ - const string&getCharSet() const; - - /** \return Number of spaces to replace a tab*/ - int getNumberSpaces() const; - - /** \return True if version information should be printed*/ - bool printVersion() const; - - /** \return True if help information should be printed*/ - bool printHelp() const; - - /** \return True if debug information should be printed*/ - bool printDebugInfo()const; - - /** \return True if Style definition should be included in output*/ - bool includeStyleDef() const; - - /** \return True if line numbers should be printed*/ - bool printLineNumbers() const; - - /** \return colour theme name */ - string getStyleName()const ; - - /** gibt true zurck, falls deutsche Hilfe ausgegeben werden soll */ - int helpLanguage() const; - - /** \return True if batch mode is active*/ - bool enableBatchMode() const; - - /** \return True if output shluld be fragmented*/ - bool fragmentOutput() const; - - /** \return output file suffix */ - string getOutFileSuffix() const; - - /** \return True if anchors should be attached to line numbers*/ - bool attachLineAnchors() const; - - /** \return True if list of installed themes should be printed*/ - bool showThemes() const; - - /** \return True if list of installed language definitions should be printed*/ - bool showLangdefs() const; - - /** \return True if loutput directory is given*/ - bool outDirGiven() const; - - /** \return True if refomatting is enabled*/ - bool formattingEnabled(); - - /** \return True if a new data directory is given*/ - bool dataDirGiven()const; - - /** \return True if an additional data directory is given*/ - bool additionalDataDirGiven()const; - - /** \return True if index file should be printed*/ - bool printIndexFile() const; - - /** \return True if quotes should be replaced by /dq in LaTeX*/ - bool replaceQuotes() const; - - /** \return Data directory*/ - const string &getDataDir()const; - - /** \return Additional data directory*/ - const string &getAdditionalDataDir()const; - - /** \return True if language syntax is given*/ - bool syntaxGiven() const; - - /** \return True if quiet mode is active*/ - bool quietMode() const; - - /** \return True if XSL-FO output should be FOP compatible*/ - bool fopCompatible() const; - - /** \return True if progress bar should be printed in batch mode */ - bool printProgress() const; - - /** \return True if line numbers are filled with leading zeroes */ - bool fillLineNrZeroes() const; - - /** \return name of help message file*/ - const string getHelpLang() const; - - /** \return programming language */ - const string &getLanguage()const ; - - /** \return Wrapping style*/ - highlight::WrapMode getWrappingStyle() const; - - /** \return List of input file names*/ - const vector <string> & getInputFileNames() const; - - /** \return Name of indentation scheme file */ - const string &getIndentScheme() const; - - /** \return Output file format */ - highlight::OutputType getOutputType() const; - - /** \return True if chosen output format supports referenced style files */ - bool formatSupportsExtStyle(); - - /** \return True if style output path was defined by user*/ - bool styleOutPathDefined() const{ - return opt_stylepath_explicit; - } - - /** \return True if encoding nasme should be omitted in output*/ - bool omitEncodingName() const; - - /** \return True if output should be generated if languege type is unknown*/ - bool forceOutput() const; - - private: - - int numberSpaces; // number of spaces which replace a tab - highlight::WrapMode wrappingStyle; // line wrapping mode - highlight::OutputType outputType; - - // name of single output file - string outFilename, - // output directory - outDirectory, - // programming language which will be loaded - language, - // name of colour theme - styleName, - // name of external style file - styleOutFilename, - // name of file to be included in external style file - styleInFilename, - // used to define data directories at runtime - dataDir, additionalDataDir; - // name of indenation scheme - string indentScheme; - - bool opt_language; - bool opt_include_style; - bool opt_help; - bool opt_version ; - bool opt_verbose; - bool opt_linenumbers; - bool opt_style; - bool opt_batch_mode; - bool opt_fragment; - bool opt_attach_line_anchors; - bool opt_show_themes; - bool opt_show_langdefs; - bool opt_asformat_output; - bool opt_printindex; - bool opt_quiet; - bool opt_xslfo_fop; - bool opt_replacequotes; - bool opt_print_progress; - bool opt_fill_zeroes; - bool opt_stylepath_explicit; - bool opt_force_output; - - bool configFileRead; - - string helpLang, charset; - string configFilePath; - - // list of all input file names - vector <string> inputFileNames; - - /** load highlight configuration file */ - void loadConfigurationFile(); - - /** \return file suffix */ - string getFileSuffix( const string & fileName) const; - - /** \return directory name of path */ - string getDirName( const string & path); - - /** get all entries in the directory defined by wildcard */ - void readDirectory(const string & wildcard); - - /** \return Boolean value of paramVal */ - bool getFlag(const string& paramVal); - - /** \return Valid path name */ - string validateDirPath(const string & path); - - void printDeprecatedWarning(const char *oldOption, const char *newOption); - }; - -#endif -/*************************************************************************** - codeparser.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 "codegenerator.h" - -#include "htmlgenerator.h" -#include "xhtmlgenerator.h" -#include "rtfgenerator.h" -#include "latexgenerator.h" -#include "texgenerator.h" -#include "xslfogenerator.h" -#include "xmlgenerator.h" -#ifndef __WXMSW__ - #include "ansigenerator.h" -#endif - - -using namespace std; - -namespace highlight { - -CodeGenerator* CodeGenerator::generator=NULL; - -CodeGenerator* 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 - ) { - if (generator==NULL){ - switch (type){ - case TEX: - generator = new TexGenerator (styleInfoPath); - break; - case LATEX: - generator = new LatexGenerator(styleInfoPath, replaceQuotes); - break; - case RTF: - generator = new RtfGenerator (styleInfoPath); - break; - case XSLFO: - generator = new XslFoGenerator(styleInfoPath, encoding, omitEncoding, - fopCompatible); - break; - case XML: - generator = new XmlGenerator(styleInfoPath,encoding, omitEncoding); - break; - case XHTML: - generator = new XHtmlGenerator(styleInfoPath, encoding, omitEncoding, - attachAnchors); - break; - #ifndef __WXMSW__ - case ANSI: - generator = new AnsiGenerator (styleInfoPath); - break; - #endif - default: - generator = new HtmlGenerator(styleInfoPath, encoding, omitEncoding, - attachAnchors); - } - } - generator->setType(type); - generator->setStyleInputPath(styleInPath); - generator->setStyleOutputPath(styleOutPath); - generator->setIncludeStyle(includeStyle); - generator->setPrintLineNumbers(ln); - generator->setPrintZeroes(lnz); - generator->setFragmentCode(fragment); - generator->setPreformatting(lineWrappingMode, - (generator->getPrintLineNumbers()) ? - MAX_LINE__WIDTH - LINE_NUMBER_WIDTH : MAX_LINE__WIDTH, - numSpaces ); - return generator; -} - -void CodeGenerator::deleteInstance(){ - delete generator; - generator=NULL; -} - - -CodeGenerator::CodeGenerator(): - in(NULL), - out(NULL), - maskWs(false), - excludeWs(false), - fragmentOutput(false), - showLineNumbers (false), - lineNumberFillZeroes(false), - lineNumber(0), - includeStyleDef(false), - lineIndex(0), - formatter(NULL), - preFormatter(NULL), - formattingEnabled(false), - formattingPossible(false), - outputType(highlight::HTML) -{} - -CodeGenerator::CodeGenerator(const string &colourTheme) - :in(NULL), - out(NULL), - maskWs(false), - excludeWs(false), - fragmentOutput(false), - showLineNumbers (false), - lineNumberFillZeroes(false), - lineNumber(0), - includeStyleDef(false), - stylePath(colourTheme), - lineIndex(0), - formatter(NULL), - preFormatter(NULL), - formattingEnabled(false), - formattingPossible(false), - outputType(highlight::HTML) -{ - line.reserve(100); - docStyle.load(stylePath); -} - -CodeGenerator::~CodeGenerator() -{ - delete preFormatter; - delete formatter; -} - - -/** Getter and Setter*/ - -void CodeGenerator::setPrintLineNumbers(bool flag){ - showLineNumbers=flag; -} - -bool CodeGenerator::getPrintLineNumbers(){ - return showLineNumbers; -} - -void CodeGenerator::setPrintZeroes(bool flag){ - lineNumberFillZeroes=flag; -} - -bool CodeGenerator::getPrintZeroes(){ - return lineNumberFillZeroes; -} - -void CodeGenerator::setFragmentCode(bool flag){ - fragmentOutput=flag; -} - -void CodeGenerator::setIncludeStyle(bool flag){ - includeStyleDef = flag; -} - -void CodeGenerator::setStyleInputPath(const string& path){ - styleInputPath = path; -} -void CodeGenerator::setStyleOutputPath(const string& path){ - styleOutputPath = path; -} - -const string& CodeGenerator::getStyleInputPath(){ - return styleInputPath; -} -const string& CodeGenerator::getStyleOutputPath(){ - return styleOutputPath; -} - - -bool CodeGenerator::getFragmentCode(){ - return fragmentOutput; -} - -void CodeGenerator::setStyleName(const string& s){ - stylePath=s; -} - -void CodeGenerator::setType(OutputType t){ - outputType = t; -} - -const string& CodeGenerator::getStyleName(){ - return stylePath; -} - -bool CodeGenerator::formattingDisabled(){ - return !formattingEnabled; -} - -bool CodeGenerator::formattingIsPossible(){ - return formattingPossible; -} - -void CodeGenerator::setPreformatting(WrapMode lineWrappingStyle, - unsigned int lineLength, - int numberSpaces ){ - bool enableWrap = lineWrappingStyle!=WRAP_DISABLED; - bool replaceTabs = numberSpaces > 0; - if (enableWrap || replaceTabs) { - preFormatter=new PreFormatter(enableWrap, replaceTabs); - if (enableWrap) - preFormatter->setWrappingProperties(lineLength, lineWrappingStyle==WRAP_DEFAULT); - if (replaceTabs) - preFormatter->setNumberSpaces(numberSpaces); - } -} - -/* -WrapMode CodeGenerator::getLineWrapping(){ - if (preFormatter==NULL) return WRAP_DISABLED; - return (preFormatter->indentCode()?WRAP_DEFAULT:WRAP_SIMPLE); -} -*/ -LanguageDefinition &CodeGenerator::getLanguage(){ - return langInfo; -} - -void CodeGenerator::reset() -{ - lineIndex = lineNumber = 0; - line.clear(); -} - - -/** sucht vorwaerts ab Position searchPos Ziffer in s und liefert Integerwert -der gefundenen Zahl zurueck. -Im SymbolString stehen die den einzelnen Symbolen zugeordneten Konstanten -immer HINTER diesen Symbolen*/ -State CodeGenerator::getState(const string &s, unsigned int searchPos) -{ - unsigned int i= searchPos+1, result=0; - - // nach Ziffer in s suchen - do { - ++i; - } while ((i<s.length()) && !isdigit(s[i])) ; - - // Zahl zusammensetzen - while ((i<s.length()) && isdigit(s[i])){ - result = result *10 + (s[i]-'0'); - ++i; - } - return ((result)? (State)result:_UNKNOWN); -} - -string CodeGenerator::getIdentifier() -{ - --lineIndex; - unsigned int startPos=lineIndex; - char c= line[lineIndex]; - - while ( ( lineIndex < line.length() - && ( StringTools::isAlpha(c) - || isdigit(c)) - || isAllowedChar(c)) - ) - { - ++lineIndex; - c= line[lineIndex]; - } - return string(line, startPos, lineIndex - startPos); -} - -string CodeGenerator::getNumber() -{ - --lineIndex; - unsigned int startPos=lineIndex; - char c=line[lineIndex]; - - while ( lineIndex < line.length() && ( - isdigit(c) - // don't highlight methods applied on numbers as part of the number - // i.e. Ruby: 3.xxx() - || (c == '.' && isdigit(line[lineIndex+1])) - // '-' is accepted as first character - || (c == '-' && lineIndex == startPos) - || (StringTools::isAlpha(c) && line[lineIndex-1]=='0') - || (isxdigit(c) || c=='L' || c=='U' || c=='l' || c=='u') )) - { - ++lineIndex; - c= line[lineIndex]; - } - return string(line,startPos, lineIndex-startPos); -} - -unsigned int CodeGenerator::getLineNumber() -{ - return lineNumber; -} - -bool CodeGenerator::readNewLine(string &newLine){ - bool eof; - terminatingChar=newLine[lineIndex-1]; - if (formattingPossible && formattingEnabled) - { - eof=!formatter->hasMoreLines(); - if (!eof) - { - newLine = formatter->nextLine(); - } - } - else // reformatting not enabled - { - eof = ! getline( *in, newLine); - } - return eof; -} - -unsigned char CodeGenerator::getInputChar() -{ - bool eol = lineIndex == line.length(); - - if (eol) { - bool eof=false; - if (preFormatter!=NULL){ - if (!preFormatter->hasMoreLines()) { - eof=readNewLine(line); - preFormatter->setLine(line); - } - line = preFormatter->getNextLine(); - } else { - eof=readNewLine(line); - } - lineIndex=0; - ++lineNumber; - line=StringTools::trimRight(line); - return (eof)?'\0':'\n'; - } - return line[lineIndex++]; -} - -State CodeGenerator::getCurrentState (bool lastStateWasNumber) -{ - unsigned char c; - - if (token.length()==0) { - c=getInputChar(); - } else { - lineIndex-= (token.length()-1); - c=token[0]; - } - if (c=='\n'){ - return _EOL; // End of line - } - - if (c=='\0') { - return _EOF; // End of file - } - - if (isspace(c)) { - token= c; - return _WS; - } - - // numbers have to be searched before using the symbolstring, - // as numbers are part of this string - if (isdigit(c) - // recognize floats like .5 - || (c=='.' && isdigit(line[lineIndex])) - // test if '-' belongs to a term like "1-2" - || ((c == '-') - && (!lastStateWasNumber) - && isdigit(StringTools::getNextNonWs(line, lineIndex))) ) - { - token = getNumber(); - return NUMBER; - } - unsigned int symbolLength; - size_t symbolPos; - bool found=false; - string symbols=langInfo.getSymbolString(); - - symbolPos = symbols.find(c); - // search symbols (comment delimiters, directives etc.) - // before keywords, because alphabetic chars may be part of symbols, too - while ((symbolPos!= string::npos) && (!found)) - { - symbolLength=symbols.find(' ', symbolPos)-symbolPos; - token = symbols.substr(symbolPos, symbolLength); - - // TODO Ruby =ende, =end bugfix (whitespace after symbol needs to be checked) - - // Abfrage nach Leerzeichen in SymbolString verhindert falsches - // Erkennen von Symbolteilen: - if (lineIndex && token == line.substr(lineIndex-1, symbolLength) - && isspace(symbols[symbolPos-1]) ) { - found = true; - lineIndex += (symbolLength-1); - } else { - symbolPos = symbols.find_first_not_of(' ',symbols.find(' ',symbolPos)); - } - } - - // dirty workaround stuff in here - if (found) { - State foundState = getState(symbols, symbolPos); - - // get the current keyword class id to apply the corresponding formatting style - if (foundState==KEYWORD_BEGIN || foundState==TAG_BEGIN ) { - currentKeywordClass=langInfo.getDelimPrefixClassID(token); - } - - // Full line quotes must start in coloumn 1 (Fortran 77) - if (langInfo.isFullLineComment() && foundState==SL_COMMENT){ - if (lineIndex==1) { - return SL_COMMENT; - } - } - // VHDL Workaround: distinguish string delimiters and event markers - // (same eymbol: ') - else if (langInfo.isVHDL() - && foundState==STRING && currentState!=STRING - && lineIndex > 1 - &&(isdigit(line[lineIndex-2]) || isalpha(line[lineIndex-2]))){ - c=line[lineIndex-1]; - // do not return, continue search... - } else { - return foundState; - } - } - - // Alphanumerisches Token parsen und als Keyword oder Type erkennen - if (StringTools::isAlpha(c) || langInfo.isPrefix(c) || isAllowedChar(c)) - { - if (langInfo.isPrefix(c)){ - token = c; - ++lineIndex; - token += getIdentifier(); - } else { - token = getIdentifier(); - } - string reservedWord=(langInfo.isIgnoreCase()) ? - StringTools::lowerCase(token):token; - currentKeywordClass=langInfo.isKeyword(reservedWord); - return (currentKeywordClass) ? KEYWORD : STANDARD; - } - - // Character not referring to any state - token = c; - return STANDARD; -} - -string CodeGenerator::maskString(const string & s) -{ - ostringstream ss; - for (unsigned int i=0;i< s.length();i++){ - ss << maskCharacter(s[i]); - } - return ss.str(); -} - -void CodeGenerator::printMaskedToken(bool flushWhiteSpace) -{ - if(flushWhiteSpace) flushWs(); - *out << maskString(token); - token.clear(); -} - -bool CodeGenerator::isAllowedChar(char c) -{ - return ( langInfo.getAllowedChars().find(c)!= string::npos); -} - -bool CodeGenerator::styleFound(){ - return docStyle.found(); -} - -bool CodeGenerator::printIndexFile(const vector<string> &fileList, - const string &outPath){ - return true; -} - -bool CodeGenerator::initIndentationScheme(const string &schemePath){ - - if (formatter!=NULL){ - return true; - } - - ConfigurationReader indentScheme(schemePath); - if (indentScheme.found()){ - if (formatter==NULL) { - formatter=new astyle::ASFormatter(); - - string brackets=indentScheme.getParameter("brackets"); - if (!brackets.empty()){ - // Break brackets from pre-block code (i.e. ANSI C/C++ style). - if (brackets=="break"){ - formatter->setBracketFormatMode(astyle::BREAK_MODE); - } - //Attach brackets to pre-block code (i.e. Java/K&R style). - else if (brackets=="attach"){ - formatter->setBracketFormatMode(astyle::ATTACH_MODE); - } - // Break definition-block brackets and attach command-block brackets. - else if (brackets=="linux"){ - formatter->setBracketFormatMode(astyle::BDAC_MODE); - } - // Break brackets before closing headers (e.g. 'else', 'catch', ..). - // Should be appended to --brackets=attach or --brackets=linux. - else if (brackets=="break-closing-headers"){ - formatter->setBreakClosingHeaderBracketsMode(true); - } - } - - string pad=indentScheme.getParameter("pad"); - if (!pad.empty()){ - //Insert space paddings around parenthesies only. - if (pad=="paren"){ - formatter->setParenthesisPaddingMode(true); - } - // Insert space paddings around operators only. - else if (pad=="oper"){ - formatter->setOperatorPaddingMode(true); - } - //Insert space paddings around operators AND parenthesies. - else if (pad=="all"){ - formatter->setOperatorPaddingMode(true); - formatter->setParenthesisPaddingMode(true); - } - } - - string oneLine=indentScheme.getParameter("one-line"); - if (!oneLine.empty()){ - // Don't break one-line blocks. - if (oneLine=="keep-blocks"){ - formatter->setBreakOneLineBlocksMode(false); - } - // Don't break complex statements and multiple statements residing in a - // single line. - else if (oneLine=="keep-statements"){ - formatter->setSingleStatementsMode(false); - } - } - - // Insert empty lines around unrelated blocks, labels, classes, ... - string breakBlocks=indentScheme.getParameter("break-blocks"); - if (!breakBlocks.empty()){ - if (breakBlocks=="all"){ - //Like --break-blocks, except also insert empty lines around closing - //headers (e.g. 'else', 'catch', ...). - formatter->setBreakClosingHeaderBlocksMode(true); - } - formatter->setBreakBlocksMode(true); - } - string trueVal="true"; - - // Other options... - - //Indent using # spaces per indent. Not specifying # will result in a - //default of 4 spaces per indent. - string indentSpaces=indentScheme.getParameter("indent-spaces"); - - // Indent a minimal # spaces in a continuous conditional belonging to a - //conditional header. - string minConditionalIndent=indentScheme.getParameter("min-conditional-indent"); - - // Indent a maximal # spaces in a continuous statement, relatively to the - // previous line. - string maxInStatementIndent=indentScheme.getParameter("max-instatement-indent"); - - // Add extra indentation to '{' and '}' block brackets. - string indentBrackets=indentScheme.getParameter("indent-brackets"); - - // Add extra indentation entire blocks (including brackets). - string indentBlocks=indentScheme.getParameter("indent-blocks"); - - // Indent the contents of namespace blocks. - string indentNamespaces=indentScheme.getParameter("indent-namespaces"); - - // Indent 'class' blocks, so that the inner 'public:','protected:' and - // 'private: headers are indented inrelation to the class block. - string indentClasses=indentScheme.getParameter("indent-classes"); - - // Indent 'switch' blocks, so that the inner 'case XXX:' headers are - // indented in relation to the switch block. - string indentSwitches=indentScheme.getParameter("indent-switches"); - - // Indent 'case XXX:' lines, so that they are flush with their bodies.. - string indentCases=indentScheme.getParameter("indent-cases"); - - // Indent labels so that they appear one indent less than the current - // indentation level, rather than being flushed completely to the left - // (which is the default). - string indentLabels=indentScheme.getParameter("indent-labels"); - - // Indent multi-line #define statements - string indentPreprocessor=indentScheme.getParameter("indent-preprocessor"); - - // Break 'else if()' statements into two different lines. - string breakElseIfs = indentScheme.getParameter("break-elseifs"); - - string javaStyle = indentScheme.getParameter("java-style"); - - // default values in ASBeautifier are false, it is ok to set them false - // if parameter does not exist in scheme file - formatter->setBracketIndent(indentBrackets==trueVal); - formatter->setBlockIndent(indentBlocks==trueVal); - formatter->setNamespaceIndent(indentNamespaces==trueVal); - formatter->setClassIndent(indentClasses==trueVal); - formatter->setSwitchIndent(indentSwitches==trueVal); - formatter->setCaseIndent(indentCases==trueVal); - formatter->setLabelIndent(indentLabels==trueVal); - formatter->setPreprocessorIndent(indentPreprocessor==trueVal); - formatter->setBreakElseIfsMode(breakElseIfs==trueVal); - - if (javaStyle==trueVal){ - formatter->setJavaStyle(); - } - - if (!indentSpaces.empty()){ - formatter->setSpaceIndentation(StringTools::str2int(indentSpaces)); - } - if (!minConditionalIndent.empty()){ - formatter->setMinConditionalIndentLength( - StringTools::str2int(minConditionalIndent)); - } - if (!maxInStatementIndent.empty()){ - formatter->setMinConditionalIndentLength( - StringTools::str2int(maxInStatementIndent)); - } - } - formattingEnabled=(formatter != NULL); - return true; - } else { - return false; - } -} - -LoadResult CodeGenerator::initLanguage(const string& langDefPath){ - bool reloadNecessary= langInfo.needsReload(langDefPath); - if (reloadNecessary){ - bool failure = !langInfo.load(langDefPath); - - if (failure) { - return LOAD_FAILED; - } - - formattingPossible=langInfo.enableReformatting(); - - if (styleTagOpen.size()>NUMBER_BUILTIN_STYLES){ - // remove dynamic keyword tag delimiters of the old language definition - vector<string>::iterator keyStyleOpenBegin = - styleTagOpen.begin() + NUMBER_BUILTIN_STYLES; - vector<string>::iterator keyStyleCloseBegin = - styleTagClose.begin()+ NUMBER_BUILTIN_STYLES; - styleTagOpen.erase(keyStyleOpenBegin, styleTagOpen.end()); - styleTagClose.erase(keyStyleCloseBegin, styleTagClose.end()); - } - // add new keyword delimiters - for (unsigned int i=0;i< langInfo.getKeywordClasses().size(); i++){ - styleTagOpen.push_back(getMatchingOpenTag(i)); - styleTagClose.push_back(getMatchingCloseTag(i)); - } - } - return (reloadNecessary) ? LOAD_NEW : LOAD_NONE; -} - -ParseError CodeGenerator::printOutput (const string & inFileName, - const string &outFileName) -{ - if (!docStyle.found()) { - return BAD_STYLE; - } - reset(); - - ParseError error=PARSE_OK; - - in = (inFileName.empty()? &cin :new ifstream (inFileName.c_str())); - if (!in->fail()) { - out = (outFileName.empty()? &cout :new ofstream (outFileName.c_str())); - if ( out->fail()) { - error=BAD_OUTPUT; - } - } - - if ( in->fail()){ - error=BAD_INPUT; - } - - if (error==PARSE_OK) { - if (formatter != NULL){ - formatter->init(new astyle::ASStreamIterator(in)); - } - if (! fragmentOutput){ - *out << getHeader(inFileName); - } - printBody(); - if (! fragmentOutput){ - *out << getFooter(); - } - } - - if (!outFileName.empty()){ - delete out; out=NULL; - } - if (!inFileName.empty()) { - delete in; in=NULL; - } - return error; -} - - -unsigned int CodeGenerator::getStyleID(State s, unsigned int kwClassID){ - if (s==KEYWORD && kwClassID){ - return NUMBER_BUILTIN_STYLES + kwClassID-1; - } - return (unsigned int) s ; -} - -void CodeGenerator::closeTag(State s){ - *out << styleTagClose[(unsigned int)s]; - flushWs(); - currentState=_UNKNOWN; -} - -void CodeGenerator::openTag(State s){ - *out << styleTagOpen[(unsigned int)s]; - currentState=s; -} - -void CodeGenerator::closeKWTag(unsigned int kwClassID){ - *out << styleTagClose[getStyleID(KEYWORD, kwClassID)]; - - flushWs(); - currentState=_UNKNOWN; -} - -void CodeGenerator::openKWTag(unsigned int kwClassID){ - *out << styleTagOpen[getStyleID(KEYWORD, kwClassID)]; - currentState=KEYWORD; -} - diff --git a/tests/examplefiles/example.rb b/tests/examplefiles/example.rb index 8a3304ba..93f8dc2b 100644 --- a/tests/examplefiles/example.rb +++ b/tests/examplefiles/example.rb @@ -1850,5707 +1850,3 @@ module BBCode end end - class Parser - def Parser.flatten str - # replace mac & dos newlines with unix style - str.gsub(/\r\n?/, "\n") - end - - def initialize input = '' - # input manager - @scanner = StringScanner.new '' - # output manager - @encoder = Encoder.new - @output = '' - # tag manager - @tagstack = TagStack.new(@encoder) - - @do_magic = true - # set the input - feed input - end - - # if you want, you can feed a parser instance after creating, - # or even feed it repeatedly. - def feed food - @scanner.string = Parser.flatten food - end - - # parse through the string using parse_token - def parse - parse_token until @scanner.eos? - @tagstack.close_all - @output = parse_magic @encoder.output - end - - def output - @output - end - - # ok, internals start here - private - # the default output functions. everything should use them or the tags. - def add_text text = @scanner.matched - @encoder.add_text text - end - - # use this carefully - def add_html html - @encoder.add_html html - end - - # highlights the text as error - def add_garbage garbage - add_html '<span class="error">' if DEBUG - add_text garbage - add_html '</span>' if DEBUG - end - - # unknown and incorrectly nested tags are ignored and - # sent as plaintext (garbage in - garbage out). - # in debug mode, garbage is marked with lime background. - def garbage_out start - @scanner.pos = start - garbage = @scanner.scan(/./m) - debug 'GARBAGE: ' + garbage - add_garbage garbage - end - - # simple text; everything but [, \[ allowed - SIMPLE_TEXT_SCAN_ = / - [^\[\\]* # normal* - (?: # ( - \\.? # special - [^\[\\]* # normal* - )* # )* - /mx - SIMPLE_TEXT_SCAN = /[^\[]+/ - -=begin - - WHAT IS A TAG? - ============== - - Tags in BBCode can be much more than just a simple [b]. - I use many terms here to differ the parts of each tag. - - Basic scheme: - [ code ] - TAG START TAG INFO TAG END - - Most tags need a second tag to close the range it opened. - This is done with CLOSING TAGS: - [/code] - or by using empty tags that have no content and close themselfes: - [url=winamp.com /] - You surely know this from HTML. - These slashes define the TAG KIND = normal|closing|empty and - cannot be used together. - - Everything between [ and ] and expluding the slashes is called the - TAG INFO. This info may contain: - - TAG ID - - TAG NAME including the tag id - - attributes - - The TAG ID is the first char of the info: - - TAG | ID - ----------+---- - [quote] | q - [±] | & - ["[b]"] | " - [/url] | u - [---] | - - - As you can see, the tag id shows the TAG TYPE, it can be a - normal tag, a formatting tag or an entity. - Therefor, the parser first scans the id to decide how to go - on with parsing. -=end - # tag - # TODO more complex expression allowing - # [quote="[ladico]"] and [quote=\[ladico\]] to be correct tags - TAG_BEGIN_SCAN = / - \[ # tag start - ( \/ )? # $1 = closing tag? - ( [^\]] ) # $2 = tag id - /x - TAG_END_SCAN = / - [^\]]* # rest that was not handled - \]? # tag end - /x - CLOSE_TAG_SCAN = / - ( [^\]]* ) # $1 = the rest of the tag info - ( \/ )? # $2 = empty tag? - \]? # tag end - /x - UNCLOSED_TAG_SCAN = / \[ /x - - CLASSIC_TAG_SCAN = / [a-z]* /ix - - SEPARATOR_TAG_SCAN = / \** /x - - FORMAT_TAG_SCAN = / -- -* /x - - QUOTED_SCAN = / - ( # $1 = quoted text - [^"\\]* # normal* - (?: # ( - \\. # special - [^"\\]* # normal* - )* # )* - ) - "? # end quote " - /mx - - ENTITY_SCAN = / - ( [^;\]]+ ) # $1 = entity code - ;? # optional ending semicolon - /ix - - SMILEY_SCAN = Smileys::SMILEY_PATTERN - - # this is the main parser loop that separates - # text - everything until "[" - # from - # tags - starting with "[", ending with "]" - def parse_token - if @scanner.scan(SIMPLE_TEXT_SCAN) - add_text - else - handle_tag - end - end - - def handle_tag - tag_start = @scanner.pos - - unless @scanner.scan TAG_BEGIN_SCAN - garbage_out tag_start - return - end - - closing, id = @scanner[1], @scanner[2] - #debug 'handle_tag(%p)' % @scanner.matched - - handled = - case id - - when /[a-z]/i - if @scanner.scan(CLASSIC_TAG_SCAN) - if handle_classic_tag(id + @scanner.matched, closing) - already_closed = true - end - end - - when '*' - if @scanner.scan(SEPARATOR_TAG_SCAN) - handle_asterisk tag_start, id + @scanner.matched - true - end - - when '-' - if @scanner.scan(FORMAT_TAG_SCAN) - #format = id + @scanner.matched - @encoder.add_html "\n<hr>\n" - true - end - - when '"' - if @scanner.scan(QUOTED_SCAN) - @encoder.add_text unescape(@scanner[1]) - true - end - - when '&' - if @scanner.scan(ENTITY_SCAN) - @encoder.add_entity @scanner[1] - true - end - - when Smileys::SMILEY_START_CHARSET - @scanner.pos = @scanner.pos - 1 # (ungetch) - if @scanner.scan(SMILEY_SCAN) - @encoder.add_html Smileys.smiley_to_image(@scanner.matched) - true - end - - end # case - - return garbage_out(tag_start) unless handled - - @scanner.scan(TAG_END_SCAN) unless already_closed - end - - ATTRIBUTES_SCAN = / - ( - [^\]"\\]* - (?: - (?: - \\. - | - " - [^"\\]* - (?: - \\. - [^"\\]* - )* - "? - ) - [^\]"\\]* - )* - ) - \]? - /x - - def handle_classic_tag name, closing - debug 'TAG: ' + (closing ? '/' : '') + name - # flatten - name.downcase! - tag_class = TAG_LIST[name] - return unless tag_class - - #debug((opening ? 'OPEN ' : 'CLOSE ') + tag_class.name) - - # create an attribute object to handle it - @scanner.scan(ATTRIBUTES_SCAN) - #debug name + ':' + @scanner[1] - attr = Attribute.create @scanner[1] - #debug 'ATTRIBUTES %p ' % attr #unless attr.empty? - - #debug 'closing: %p; name=%s, attr=%p' % [closing, name, attr] - - # OPEN - if not closing and tag = @tagstack.try_open_class(tag_class, attr) - #debug 'opening' - tag.do_open @scanner - # this should be done by the tag itself. - if attr.empty_tag? - tag.handle_empty - @tagstack.close_tag - elsif tag.special_content? - handle_special_content(tag) - @tagstack.close_tag - # # ignore asterisks directly after the opening; these are phpBBCode - # elsif tag.respond_to? :asterisk - # debug 'SKIP ASTERISKS: ' if @scanner.skip(ASTERISK_TAGS_SCAN) - end - - # CLOSE - elsif @tagstack.try_close_class(tag_class) - #debug 'closing' - # GARBAGE - else - return - end - - true - end - - def handle_asterisk tag_start, stars - #debug 'ASTERISK: ' + stars.to_s - # rule for asterisk tags: they belong to the last tag - # that handles them. tags opened after this tag are closed. - # if no open tag uses them, all are closed. - tag = @tagstack.close_all_until { |tag| tag.respond_to? :asterisk } - unless tag and tag.asterisk stars, @scanner - garbage_out tag_start - end - end - - def handle_special_content tag - scanned = @scanner.scan_until(tag.closing_tag) - if scanned - scanned.slice!(-(@scanner.matched.size)..-1) - else - scanned = @scanner.scan(/.*/m).to_s - end - #debug 'SPECIAL CONTENT: ' + scanned - tag.handle_content(scanned) - end - - def unescape text - # input: correctly formatted quoted string (without the quotes) - text.gsub(/\\(?:(["\\])|.)/) { $1 or $& } - end - - - # MAGIC FEAUTURES - - URL_PATTERN = /(?:(?:www|ftp)\.|(?>\w{3,}):\/\/)\S+/ - EMAIL_PATTERN = /(?>[\w\-_.]+)@[\w\-\.]+\.\w+/ - - HAS_MAGIC = /[&@#{Smileys::SMILEY_START_CHARS}]|(?i:www|ftp)/ - - MAGIC_PATTERN = Regexp.new('(\W|^)(%s)' % - [Smileys::MAGIC_SMILEY_PATTERN, URL_PATTERN, EMAIL_PATTERN].map { |pattern| - pattern.to_s - }.join('|') ) - - IS_SMILEY_PATTERN = Regexp.new('^%s' % Smileys::SMILEY_START_CHARSET.to_s ) - IS_URL_PATTERN = /^(?:(?i:www|ftp)\.|(?>\w+):\/\/)/ - URL_STARTS_WITH_PROTOCOL = /^\w+:\/\// - IS_EMAIL_PATTERN = /^[\w\-_.]+@/ - - def to_magic text - # debug MAGIC_PATTERN.to_s - text.gsub!(MAGIC_PATTERN) { - magic = $2 - $1 + case magic - when IS_SMILEY_PATTERN - Smileys.smiley_to_img magic - when IS_URL_PATTERN - last = magic.slice_punctation! # no punctation in my URL - href = magic - href.insert(0, 'http://') unless magic =~ URL_STARTS_WITH_PROTOCOL - '<a href="' + href + '">' + magic + '</a>' + last - when IS_EMAIL_PATTERN - last = magic.slice_punctation! - '<a href="mailto:' + magic + '">' + magic + '</a>' + last - else - raise '{{{' + magic + '}}}' - end - } - text - end - - # handles smileys and urls - def parse_magic html - return html unless @do_magic - scanner = StringScanner.new html - out = '' - while scanner.rest? - if scanner.scan(/ < (?: a\s .*? <\/a> | pre\W .*? <\/pre> | [^>]* > ) /mx) - out << scanner.matched - elsif scanner.scan(/ [^<]+ /x) - out << to_magic(scanner.matched) - - # this should never happen - elsif scanner.scan(/./m) - raise 'ERROR: else case reached' - end - end - out - end - end # Parser -end - -class String - def slice_punctation! - slice!(/[.:,!\?]+$/).to_s # return '' instead of nil - end -end - -# -# = Grammar -# -# An implementation of common algorithms on grammars. -# -# This is used by Shinobu, a visualization tool for educating compiler-building. -# -# Thanks to Andreas Kunert for his wonderful LR(k) Pamphlet (German, see http://www.informatik.hu-berlin.de/~kunert/papers/lr-analyse), and Aho/Sethi/Ullman for their Dragon Book. -# -# Homepage:: http://shinobu.cYcnus.de (not existing yet) -# Author:: murphy (Kornelius Kalnbach) -# Copyright:: (cc) 2005 cYcnus -# License:: GPL -# Version:: 0.2.0 (2005-03-27) - -require 'set_hash' -require 'ctype' -require 'tools' -require 'rules' -require 'trace' - -require 'first' -require 'follow' - -# = Grammar -# -# == Syntax -# -# === Rules -# -# Each line is a rule. -# The syntax is -# -# left - right -# -# where +left+ and +right+ can be uppercase and lowercase letters, -# and <code>-</code> can be any combination of <, >, - or whitespace. -# -# === Symbols -# -# Uppercase letters stand for meta symbols, lowercase for terminals. -# -# You can make epsilon-derivations by leaving <code><right></code> empty. -# -# === Example -# S - Ac -# A - Sc -# A - b -# A - -class Grammar - - attr_reader :tracer - # Creates a new Grammar. - # If $trace is true, the algorithms explain (textual) what they do to $stdout. - def initialize data, tracer = Tracer.new - @tracer = tracer - @rules = Rules.new - @terminals, @meta_symbols = SortedSet.new, Array.new - @start_symbol = nil - add_rules data - end - - attr_reader :meta_symbols, :terminals, :rules, :start_symbol - - alias_method :sigma, :terminals - alias_method :alphabet, :terminals - alias_method :variables, :meta_symbols - alias_method :nonterminals, :meta_symbols - - # A string representation of the grammar for debugging. - def inspect productions_too = false - 'Grammar(meta symbols: %s; alphabet: %s; productions: [%s]; start symbol: %s)' % - [ - meta_symbols.join(', '), - terminals.join(', '), - if productions_too - @rules.inspect - else - @rules.size - end, - start_symbol - ] - end - - # Add rules to the grammar. +rules+ should be a String or respond to +scan+ in a similar way. - # - # Syntax: see Grammar. - def add_rules grammar - @rules = Rules.parse grammar do |rule| - @start_symbol ||= rule.left - @meta_symbols << rule.left - @terminals.merge rule.right.split('').select { |s| terminal? s } - end - @meta_symbols.uniq! - update - end - - # Returns a hash acting as FIRST operator, so that - # <code>first["ABC"]</code> is FIRST(ABC). - # See http://en.wikipedia.org/wiki/LL_parser "Constructing an LL(1) parsing table" for details. - def first - first_operator - end - - # Returns a hash acting as FOLLOW operator, so that - # <code>first["A"]</code> is FOLLOW(A). - # See http://en.wikipedia.org/wiki/LL_parser "Constructing an LL(1) parsing table" for details. - def follow - follow_operator - end - - LLError = Class.new(Exception) - LLErrorType1 = Class.new(LLError) - LLErrorType2 = Class.new(LLError) - - # Tests if the grammar is LL(1). - def ll1? - begin - for meta in @meta_symbols - first_sets = @rules[meta].map { |alpha| first[alpha] } - first_sets.inject(Set[]) do |already_used, another_first_set| - unless already_used.disjoint? another_first_set - raise LLErrorType1 - end - already_used.merge another_first_set - end - - if first[meta].include? EPSILON and not first[meta].disjoint? follow[meta] - raise LLErrorType2 - end - end - rescue LLError - false - else - true - end - end - -private - - def first_operator - @first ||= FirstOperator.new self - end - - def follow_operator - @follow ||= FollowOperator.new self - end - - def update - @first = @follow = nil - end - -end - -if $0 == __FILE__ - eval DATA.read, nil, $0, __LINE__+4 -end - -require 'test/unit' - -class TestCaseGrammar < Test::Unit::TestCase - - include Grammar::Symbols - - def fifo s - Set[*s.split('')] - end - - def test_fifo - assert_equal Set[], fifo('') - assert_equal Set[EPSILON, END_OF_INPUT, 'x', 'Y'], fifo('?xY$') - end - - TEST_GRAMMAR_1 = <<-EOG -S - ABCD -A - a -A - -B - b -B - -C - c -C - -D - S -D - - EOG - - def test_symbols - assert EPSILON - assert END_OF_INPUT - end - - def test_first_1 - g = Grammar.new TEST_GRAMMAR_1 - - f = nil - assert_nothing_raised { f = g.first } - assert_equal(Set['a', EPSILON], f['A']) - assert_equal(Set['b', EPSILON], f['B']) - assert_equal(Set['c', EPSILON], f['C']) - assert_equal(Set['a', 'b', 'c', EPSILON], f['D']) - assert_equal(f['D'], f['S']) - end - - def test_follow_1 - g = Grammar.new TEST_GRAMMAR_1 - - f = nil - assert_nothing_raised { f = g.follow } - assert_equal(Set['a', 'b', 'c', END_OF_INPUT], f['A']) - assert_equal(Set['a', 'b', 'c', END_OF_INPUT], f['B']) - assert_equal(Set['a', 'b', 'c', END_OF_INPUT], f['C']) - assert_equal(Set[END_OF_INPUT], f['D']) - assert_equal(Set[END_OF_INPUT], f['S']) - end - - - TEST_GRAMMAR_2 = <<-EOG -S - Ed -E - EpT -E - EmT -E - T -T - TuF -T - TdF -T - F -F - i -F - n -F - aEz - EOG - - def test_first_2 - g = Grammar.new TEST_GRAMMAR_2 - - f = nil - assert_nothing_raised { f = g.first } - assert_equal(Set['a', 'n', 'i'], f['E']) - assert_equal(Set['a', 'n', 'i'], f['F']) - assert_equal(Set['a', 'n', 'i'], f['T']) - assert_equal(Set['a', 'n', 'i'], f['S']) - end - - def test_follow_2 - g = Grammar.new TEST_GRAMMAR_2 - - f = nil - assert_nothing_raised { f = g.follow } - assert_equal(Set['m', 'd', 'z', 'p'], f['E']) - assert_equal(Set['m', 'd', 'z', 'p', 'u'], f['F']) - assert_equal(Set['m', 'd', 'z', 'p', 'u'], f['T']) - assert_equal(Set[END_OF_INPUT], f['S']) - end - - LLError = Grammar::LLError - - TEST_GRAMMAR_3 = <<-EOG -E - TD -D - pTD -D - -T - FS -S - uFS -S - -S - p -F - aEz -F - i - EOG - - NoError = Class.new(Exception) - - def test_first_3 - g = Grammar.new TEST_GRAMMAR_3 - - # Grammar 3 is LL(1), so all first-sets must be disjoint. - f = nil - assert_nothing_raised { f = g.first } - assert_equal(Set['a', 'i'], f['E']) - assert_equal(Set[EPSILON, 'p'], f['D']) - assert_equal(Set['a', 'i'], f['F']) - assert_equal(Set['a', 'i'], f['T']) - assert_equal(Set[EPSILON, 'u', 'p'], f['S']) - for m in g.meta_symbols - r = g.rules[m] - firsts = r.map { |x| f[x] }.to_set - assert_nothing_raised do - firsts.inject(Set.new) do |already_used, another_first_set| - raise LLError, 'not disjoint!' unless already_used.disjoint? another_first_set - already_used.merge another_first_set - end - end - end - end - - def test_follow_3 - g = Grammar.new TEST_GRAMMAR_3 - - # Grammar 3 is not LL(1), because epsilon is in FIRST(S), - # but FIRST(S) and FOLLOW(S) are not disjoint. - f = nil - assert_nothing_raised { f = g.follow } - assert_equal(Set['z', END_OF_INPUT], f['E']) - assert_equal(Set['z', END_OF_INPUT], f['D']) - assert_equal(Set['z', 'p', 'u', END_OF_INPUT], f['F']) - assert_equal(Set['p', 'z', END_OF_INPUT], f['T']) - assert_equal(Set['p', 'z', END_OF_INPUT], f['S']) - for m in g.meta_symbols - first_m = g.first[m] - next unless first_m.include? EPSILON - assert_raise(m == 'S' ? LLError : NoError) do - if first_m.disjoint? f[m] - raise NoError # this is fun :D - else - raise LLError - end - end - end - end - - TEST_GRAMMAR_3b = <<-EOG -E - TD -D - pTD -D - PTD -D - -T - FS -S - uFS -S - -F - aEz -F - i -P - p - EOG - - def test_first_3b - g = Grammar.new TEST_GRAMMAR_3b - - # Grammar 3b is NOT LL(1), since not all first-sets are disjoint. - f = nil - assert_nothing_raised { f = g.first } - assert_equal(Set['a', 'i'], f['E']) - assert_equal(Set[EPSILON, 'p'], f['D']) - assert_equal(Set['p'], f['P']) - assert_equal(Set['a', 'i'], f['F']) - assert_equal(Set['a', 'i'], f['T']) - assert_equal(Set[EPSILON, 'u'], f['S']) - for m in g.meta_symbols - r = g.rules[m] - firsts = r.map { |x| f[x] } - assert_raise(m == 'D' ? LLError : NoError) do - firsts.inject(Set.new) do |already_used, another_first_set| - raise LLError, 'not disjoint!' unless already_used.disjoint? another_first_set - already_used.merge another_first_set - end - raise NoError - end - end - end - - def test_follow_3b - g = Grammar.new TEST_GRAMMAR_3b - - # Although Grammar 3b is NOT LL(1), the FOLLOW-condition is satisfied. - f = nil - assert_nothing_raised { f = g.follow } - assert_equal(fifo('z$'), f['E'], 'E') - assert_equal(fifo('z$'), f['D'], 'D') - assert_equal(fifo('ai'), f['P'], 'P') - assert_equal(fifo('z$pu'), f['F'], 'F') - assert_equal(fifo('z$p'), f['T'], 'T') - assert_equal(fifo('z$p'), f['S'], 'S') - for m in g.meta_symbols - first_m = g.first[m] - next unless first_m.include? EPSILON - assert_raise(NoError) do - if first_m.disjoint? f[m] - raise NoError # this is fun :D - else - raise LLError - end - end - end - end - - def test_ll1? - assert_equal false, Grammar.new(TEST_GRAMMAR_3).ll1?, 'Grammar 3' - assert_equal false, Grammar.new(TEST_GRAMMAR_3b).ll1?, 'Grammar 3b' - end - - def test_new - assert_nothing_raised { Grammar.new '' } - assert_nothing_raised { Grammar.new TEST_GRAMMAR_1 } - assert_nothing_raised { Grammar.new TEST_GRAMMAR_2 } - assert_nothing_raised { Grammar.new TEST_GRAMMAR_3 } - assert_nothing_raised { Grammar.new TEST_GRAMMAR_1 + TEST_GRAMMAR_2 + TEST_GRAMMAR_3 } - assert_raise(ArgumentError) { Grammar.new 'S - ?' } - end -end - -# vim:foldmethod=syntax - -#!/usr/bin/env ruby - -require 'fox12' - -include Fox - -class Window < FXMainWindow - def initialize(app) - super(app, app.appName + ": First Set Calculation", nil, nil, DECOR_ALL, 0, 0, 800, 600, 0, 0) - - # {{{ menubar - menubar = FXMenuBar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X) - - filemenu = FXMenuPane.new(self) - - FXMenuCommand.new(filemenu, "&Start\tCtl-S\tStart the application.", nil, getApp()).connect(SEL_COMMAND, method(:start)) - FXMenuCommand.new(filemenu, "&Quit\tAlt-F4\tQuit the application.", nil, getApp(), FXApp::ID_QUIT) - FXMenuTitle.new(menubar, "&File", nil, filemenu) - # }}} menubar - - # {{{ statusbar - @statusbar = FXStatusBar.new(self, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|STATUSBAR_WITH_DRAGCORNER) - # }}} statusbar - - # {{{ window content - horizontalsplitt = FXSplitter.new(self, SPLITTER_VERTICAL|LAYOUT_SIDE_TOP|LAYOUT_FILL) - - - @productions = FXList.new(horizontalsplitt, nil, 0, LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FIX_HEIGHT|LIST_SINGLESELECT) - @productions.height = 100 - - @result = FXTable.new(horizontalsplitt, nil, 0, LAYOUT_FILL) - @result.height = 200 - @result.setTableSize(2, 2, false) - @result.rowHeaderWidth = 0 - - header = @result.columnHeader - header.setItemText 0, 'X' - header.setItemText 1, 'FIRST(X)' - for item in header - item.justification = FXHeaderItem::CENTER_X - end - - @debug = FXText.new(horizontalsplitt, nil, 0, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|LAYOUT_FIX_HEIGHT) - @debug.height = 200 - - # }}} window content - end - - def load_grammar grammar - @tracer = FirstTracer.new(self) - @grammar = Grammar.new grammar, @tracer - @rules_indexes = Hash.new - @grammar.rules.each_with_index do |rule, i| - @productions.appendItem rule.inspect - @rules_indexes[rule] = i - end - end - - def create - super - show(PLACEMENT_SCREEN) - end - - def rule rule - @productions.selectItem @rules_indexes[rule] - sleep 0.1 - end - - def iterate i - setTitle i.to_s - sleep 0.1 - end - - def missing what - @debug.appendText what + "\n" - sleep 0.1 - end - - def start sender, sel, pointer - Thread.new do - begin - @grammar.first - rescue => boom - @debug.appendText [boom.to_s, *boom.backtrace].join("\n") - end - end - end - -end - -$: << 'grammar' -require 'grammar' - -require 'first_tracer' - -app = FXApp.new("Shinobu", "cYcnus") - -# fenster erzeugen -window = Window.new app - -unless ARGV.empty? - grammar = File.read(ARGV.first) -else - grammar = <<-EOG1 -Z --> S -S --> Sb -S --> bAa -A --> aSc -A --> a -A --> aSb - EOG1 -end - -window.load_grammar grammar - -app.create -app.run - -require 'erb' -require 'ftools' -require 'yaml' -require 'redcloth' - -module WhyTheLuckyStiff - class Book - attr_accessor :author, :title, :terms, :image, :teaser, - :chapters, :expansion_paks, :encoding, :credits - def [] x - @lang.fetch(x) do - warn warning = "[not translated: '#{x}'!]" - warning - end - end - end - - def Book::load( file_name ) - YAML::load( File.open( file_name ) ) - end - - class Section - attr_accessor :index, :header, :content - def initialize( i, h, c ) - @index, @header, @content = i, h, RedCloth::new( c.to_s ) - end - end - - class Sidebar - attr_accessor :title, :content - end - - YAML::add_domain_type( 'whytheluckystiff.net,2003', 'sidebar' ) do |taguri, val| - YAML::object_maker( Sidebar, 'title' => val.keys.first, 'content' => RedCloth::new( val.values.first ) ) - end - class Chapter - attr_accessor :index, :title, :sections - def initialize( i, t, sects ) - @index = i - @title = t - i = 0 - @sections = sects.collect do |s| - if s.respond_to?( :keys ) - i += 1 - Section.new( i, s.keys.first, s.values.first ) - else - s - end - end - end - end - - YAML::add_domain_type( 'whytheluckystiff.net,2003', 'book' ) do |taguri, val| - ['chapters', 'expansion_paks'].each do |chaptype| - i = 0 - val[chaptype].collect! do |c| - i += 1 - Chapter::new( i, c.keys.first, c.values.first ) - end - end - val['teaser'].collect! do |t| - Section::new( 1, t.keys.first, t.values.first ) - end - val['terms'] = RedCloth::new( val['terms'] ) - YAML::object_maker( Book, val ) - end - - class Image - attr_accessor :file_name - end - - YAML::add_domain_type( 'whytheluckystiff.net,2003', 'img' ) do |taguri, val| - YAML::object_maker( Image, 'file_name' => "i/" + val ) - end -end - -# -# Convert the book to HTML -# -if __FILE__ == $0 - unless ARGV[0] - puts "Usage: #{$0} [/path/to/save/html]" - exit - end - - site_path = ARGV[0] - book = WhyTheLuckyStiff::Book::load( 'poignant.yml' ) - chapter = nil - - # Write index page - index_tpl = ERB::new( File.open( 'index.erb' ).read ) - File.open( File.join( site_path, 'index.html' ), 'w' ) do |out| - out << index_tpl.result - end - - book.chapters = book.chapters[0,3] if ARGV.include? '-fast' - - # Write chapter pages - chapter_tpl = ERB::new( File.open( 'chapter.erb' ).read ) - book.chapters.each do |chapter| - File.open( File.join( site_path, "chapter-#{ chapter.index }.html" ), 'w' ) do |out| - out << chapter_tpl.result - end - end - exit if ARGV.include? '-fast' - - # Write expansion pak pages - expak_tpl = ERB::new( File.open( 'expansion-pak.erb' ).read ) - book.expansion_paks.each do |pak| - File.open( File.join( site_path, "expansion-pak-#{ pak.index }.html" ), 'w' ) do |out| - out << expak_tpl.result( binding ) - end - end - - # Write printable version - print_tpl = ERB::new( File.open( 'print.erb' ).read ) - File.open( File.join( site_path, "print.html" ), 'w' ) do |out| - out << print_tpl.result - end - - # Copy css + images into site - copy_list = ["guide.css"] + - Dir["i/*"].find_all { |image| image =~ /\.(gif|jpg|png)$/ } - - File.makedirs( File.join( site_path, "i" ) ) - copy_list.each do |copy_file| - File.copy( copy_file, File.join( site_path, copy_file ) ) - end -end - -#!/usr/bin/env ruby - -require 'fox' -begin - require 'opengl' -rescue LoadError - require 'fox/missingdep' - MSG = <<EOM - Sorry, this example depends on the OpenGL extension. Please - check the Ruby Application Archives for an appropriate - download site. -EOM - missingDependency(MSG) -end - - -include Fox -include Math - -Deg2Rad = Math::PI / 180 - -D_MAX = 6 -SQUARE_SIZE = 2.0 / D_MAX -SQUARE_DISTANCE = 4.0 / D_MAX -AMPLITUDE = SQUARE_SIZE -LAMBDA = D_MAX.to_f / 2 - -class GLTestWindow < FXMainWindow - - # How often our timer will fire (in milliseconds) - TIMER_INTERVAL = 500 - - # Rotate the boxes when a timer message is received - def onTimeout(sender, sel, ptr) - @angle += 10.0 -# @size = 0.5 + 0.2 * Math.cos(Deg2Rad * @angle) - drawScene() - @timer = getApp().addTimeout(TIMER_INTERVAL, method(:onTimeout)) - end - - # Rotate the boxes when a chore message is received - def onChore(sender, sel, ptr) - @angle += 10.0 -# @angle %= 360.0 -# @size = 0.5 + 0.2 * Math.cos(Deg2Rad * @angle) - drawScene() - @chore = getApp().addChore(method(:onChore)) - end - - # Draw the GL scene - def drawScene - lightPosition = [15.0, 10.0, 5.0, 1.0] - lightAmbient = [ 0.1, 0.1, 0.1, 1.0] - lightDiffuse = [ 0.9, 0.9, 0.9, 1.0] - redMaterial = [ 0.0, 0.0, 1.0, 1.0] - blueMaterial = [ 0.0, 1.0, 0.0, 1.0] - - width = @glcanvas.width.to_f - height = @glcanvas.height.to_f - aspect = width/height - - # Make context current - @glcanvas.makeCurrent() - - GL.Viewport(0, 0, @glcanvas.width, @glcanvas.height) - - GL.ClearColor(1.0/256, 0.0, 5.0/256, 1.0) - GL.Clear(GL::COLOR_BUFFER_BIT|GL::DEPTH_BUFFER_BIT) - GL.Enable(GL::DEPTH_TEST) - - GL.Disable(GL::DITHER) - - GL.MatrixMode(GL::PROJECTION) - GL.LoadIdentity() - GLU.Perspective(30.0, aspect, 1.0, 100.0) - - GL.MatrixMode(GL::MODELVIEW) - GL.LoadIdentity() - GLU.LookAt(5.0, 10.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) - - GL.ShadeModel(GL::SMOOTH) - GL.Light(GL::LIGHT0, GL::POSITION, lightPosition) - GL.Light(GL::LIGHT0, GL::AMBIENT, lightAmbient) - GL.Light(GL::LIGHT0, GL::DIFFUSE, lightDiffuse) - GL.Enable(GL::LIGHT0) - GL.Enable(GL::LIGHTING) - - GL.Rotated(0.1*@angle, 0.0, 1.0, 0.0) - for x in -D_MAX..D_MAX - for y in -D_MAX..D_MAX - h1 = (x + y - 2).abs - h2 = (y - x + 1).abs - GL.PushMatrix - c = [1, 0, 0, 1] - GL.Material(GL::FRONT, GL::AMBIENT, c) - GL.Material(GL::FRONT, GL::DIFFUSE, c) - - GL.Translated( - y * SQUARE_DISTANCE, - AMPLITUDE * h1, - x * SQUARE_DISTANCE - ) - - GL.Begin(GL::TRIANGLE_STRIP) - GL.Normal(1.0, 0.0, 0.0) - GL.Vertex(-SQUARE_SIZE, +SQUARE_SIZE, -SQUARE_SIZE) - GL.Vertex(-SQUARE_SIZE, +SQUARE_SIZE, +SQUARE_SIZE) - GL.Vertex(+SQUARE_SIZE, +SQUARE_SIZE, -SQUARE_SIZE) - GL.Vertex(+SQUARE_SIZE, +SQUARE_SIZE, +SQUARE_SIZE) - GL.End - - GL.PopMatrix - - GL.PushMatrix - c = [0, 0, 1, 1] - GL.Material(GL::FRONT, GL::AMBIENT, c) - GL.Material(GL::FRONT, GL::DIFFUSE, c) - - GL.Translated( - y * SQUARE_DISTANCE, - AMPLITUDE * h2, - x * SQUARE_DISTANCE - ) - - GL.Begin(GL::TRIANGLE_STRIP) - GL.Normal(1.0, 0.0, 0.0) - GL.Vertex(-SQUARE_SIZE, +SQUARE_SIZE, -SQUARE_SIZE) - GL.Vertex(-SQUARE_SIZE, +SQUARE_SIZE, +SQUARE_SIZE) - GL.Vertex(+SQUARE_SIZE, +SQUARE_SIZE, -SQUARE_SIZE) - GL.Vertex(+SQUARE_SIZE, +SQUARE_SIZE, +SQUARE_SIZE) - GL.End - - GL.PopMatrix - - GL.PushMatrix - c = [0.0 + (x/10.0), 0.0 + (y/10.0), 0, 1] - GL.Material(GL::FRONT, GL::AMBIENT, c) - GL.Material(GL::FRONT, GL::DIFFUSE, c) - - GL.Translated( - y * SQUARE_DISTANCE, - 0, - x * SQUARE_DISTANCE - ) - - GL.Begin(GL::TRIANGLE_STRIP) - GL.Normal(1.0, 0.0, 0.0) - GL.Vertex(-SQUARE_SIZE, +SQUARE_SIZE, -SQUARE_SIZE) - GL.Vertex(-SQUARE_SIZE, +SQUARE_SIZE, +SQUARE_SIZE) - GL.Vertex(+SQUARE_SIZE, +SQUARE_SIZE, -SQUARE_SIZE) - GL.Vertex(+SQUARE_SIZE, +SQUARE_SIZE, +SQUARE_SIZE) - GL.End - - GL.PopMatrix - end - end - - # Swap if it is double-buffered - if @glvisual.isDoubleBuffer - @glcanvas.swapBuffers - end - - # Make context non-current - @glcanvas.makeNonCurrent - end - - def initialize(app) - # Invoke the base class initializer - super(app, "OpenGL Test Application", nil, nil, DECOR_ALL, 0, 0, 1024, 768) - - # Construct the main window elements - frame = FXHorizontalFrame.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y) - frame.padLeft, frame.padRight = 0, 0 - frame.padTop, frame.padBottom = 0, 0 - - # Left pane to contain the glcanvas - glcanvasFrame = FXVerticalFrame.new(frame, - LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_TOP|LAYOUT_LEFT) - glcanvasFrame.padLeft, glcanvasFrame.padRight = 10, 10 - glcanvasFrame.padTop, glcanvasFrame.padBottom = 10, 10 - - # Label above the glcanvas - FXLabel.new(glcanvasFrame, "OpenGL Canvas Frame", nil, - JUSTIFY_CENTER_X|LAYOUT_FILL_X) - - # Horizontal divider line - FXHorizontalSeparator.new(glcanvasFrame, SEPARATOR_GROOVE|LAYOUT_FILL_X) - - # Drawing glcanvas - glpanel = FXVerticalFrame.new(glcanvasFrame, (FRAME_SUNKEN|FRAME_THICK| - LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_TOP|LAYOUT_LEFT)) - glpanel.padLeft, glpanel.padRight = 0, 0 - glpanel.padTop, glpanel.padBottom = 0, 0 - - # A visual to draw OpenGL - @glvisual = FXGLVisual.new(getApp(), VISUAL_DOUBLEBUFFER) - - # Drawing glcanvas - @glcanvas = FXGLCanvas.new(glpanel, @glvisual, nil, 0, - LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_TOP|LAYOUT_LEFT) - @glcanvas.connect(SEL_PAINT) { - drawScene - } - @glcanvas.connect(SEL_CONFIGURE) { - if @glcanvas.makeCurrent - GL.Viewport(0, 0, @glcanvas.width, @glcanvas.height) - @glcanvas.makeNonCurrent - end - } - - # Right pane for the buttons - buttonFrame = FXVerticalFrame.new(frame, LAYOUT_FILL_Y|LAYOUT_TOP|LAYOUT_LEFT) - buttonFrame.padLeft, buttonFrame.padRight = 10, 10 - buttonFrame.padTop, buttonFrame.padBottom = 10, 10 - - # Label above the buttons - FXLabel.new(buttonFrame, "Button Frame", nil, - JUSTIFY_CENTER_X|LAYOUT_FILL_X) - - # Horizontal divider line - FXHorizontalSeparator.new(buttonFrame, SEPARATOR_RIDGE|LAYOUT_FILL_X) - - # Spin according to timer - spinTimerBtn = FXButton.new(buttonFrame, - "Spin &Timer\tSpin using interval timers\nNote the app - blocks until the interal has elapsed...", nil, - nil, 0, FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_TOP|LAYOUT_LEFT) - spinTimerBtn.padLeft, spinTimerBtn.padRight = 10, 10 - spinTimerBtn.padTop, spinTimerBtn.padBottom = 5, 5 - spinTimerBtn.connect(SEL_COMMAND) { - @spinning = true - @timer = getApp().addTimeout(TIMER_INTERVAL, method(:onTimeout)) - } - spinTimerBtn.connect(SEL_UPDATE) { |sender, sel, ptr| - @spinning ? sender.disable : sender.enable - } - - # Spin according to chore - spinChoreBtn = FXButton.new(buttonFrame, - "Spin &Chore\tSpin as fast as possible using chores\nNote even though the - app is very responsive, it never blocks;\nthere is always something to - do...", nil, - nil, 0, FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_TOP|LAYOUT_LEFT) - spinChoreBtn.padLeft, spinChoreBtn.padRight = 10, 10 - spinChoreBtn.padTop, spinChoreBtn.padBottom = 5, 5 - spinChoreBtn.connect(SEL_COMMAND) { - @spinning = true - @chore = getApp().addChore(method(:onChore)) - } - spinChoreBtn.connect(SEL_UPDATE) { |sender, sel, ptr| - @spinning ? sender.disable : sender.enable - } - - # Stop spinning - stopBtn = FXButton.new(buttonFrame, - "&Stop Spin\tStop this mad spinning, I'm getting dizzy", nil, - nil, 0, FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_TOP|LAYOUT_LEFT) - stopBtn.padLeft, stopBtn.padRight = 10, 10 - stopBtn.padTop, stopBtn.padBottom = 5, 5 - stopBtn.connect(SEL_COMMAND) { - @spinning = false - if @timer - getApp().removeTimeout(@timer) - @timer = nil - end - if @chore - getApp().removeChore(@chore) - @chore = nil - end - } - stopBtn.connect(SEL_UPDATE) { |sender, sel, ptr| - @spinning ? sender.enable : sender.disable - } - - # Exit button - exitBtn = FXButton.new(buttonFrame, "&Exit\tExit the application", nil, - getApp(), FXApp::ID_QUIT, - FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_TOP|LAYOUT_LEFT) - exitBtn.padLeft, exitBtn.padRight = 10, 10 - exitBtn.padTop, exitBtn.padBottom = 5, 5 - - # Make a tooltip - FXTooltip.new(getApp()) - - # Initialize private variables - @spinning = false - @chore = nil - @timer = nil - @angle = 0.0 - @size = 0.5 - end - - # Create and initialize - def create - super - show(PLACEMENT_SCREEN) - end -end - -if __FILE__ == $0 - # Construct the application - application = FXApp.new("GLTest", "FoxTest") - - # To ensure that the chores-based spin will run as fast as possible, - # we can disable the chore in FXRuby's event loop that tries to schedule - # other threads. This is OK for this program because there aren't any - # other Ruby threads running. - - #application.disableThreads - - # Construct the main window - GLTestWindow.new(application) - - # Create the app's windows - application.create - - # Run the application - application.run -end - -class Facelet - attr_accessor :color - def initialize(color) - @color = color - end - - def to_s - @color - end -end - -class Edge - attr_accessor :facelets, :colors - - def initialize(facelets) - @facelets = facelets - @colors = @facelets.map { |fl| fl.color } - end - - def apply(edge) - @facelets.each_with_index { |fl, i| - fl.color = edge.colors[i] - } - end - - def inspect - "\n%s %s\n%s %s %s" % facelets - end -end - -class Side - attr_reader :num, :facelets - attr_accessor :sides - - def initialize(num) - @num = num - @sides = [] - @facelets = [] - @fl_by_side = {} - end - - # facelets & sides - # 0 - # 0 1 2 - # 3 3 4 5 1 - # 6 7 8 - # 2 - - def facelets=(facelets) - @facelets = facelets.map { |c| Facelet.new(c) } - init_facelet 0, 3,0 - init_facelet 1, 0 - init_facelet 2, 0,1 - init_facelet 3, 3 - init_facelet 5, 1 - init_facelet 6, 2,3 - init_facelet 7, 2 - init_facelet 8, 1,2 - end - - def <=>(side) - self.num <=> side.num - end - - def init_facelet(pos, *side_nums) - sides = side_nums.map { |num| @sides[num] }.sort - @fl_by_side[sides] = pos - end - - def []=(color, *sides) - @facelets[@fl_by_side[sides.sort]].color = color - end - - def values_at(*sides) - sides.map { |sides| @facelets[@fl_by_side[sides.sort]] } - end - - def inspect(range=nil) - if range - @facelets.values_at(*(range.to_a)).join(' ') - else - <<-EOS.gsub(/\d/) { |num| @facelets[num.to_i] }.gsub(/[ABCD]/) { |side| @sides[side[0]-?A].num.to_s } - A - 0 1 2 - D 3 4 5 B - 6 7 8 - C - EOS - end - end - - def get_edge(side) - trio = (-1..1).map { |x| (side + x) % 4 } - prev_side, this_side, next_side = @sides.values_at(*trio) - e = Edge.new( - self .values_at( [this_side], [this_side, next_side] ) + - this_side.values_at( [self, prev_side], [self ], [self, next_side] ) - ) - #puts 'Edge created for side %d: ' % side + e.inspect - e - end - - def turn(dir) - #p 'turn side %d in %d' % [num, dir] - edges = (0..3).map { |n| get_edge n } - for i in 0..3 - edges[i].apply edges[(i-dir) % 4] - end - end -end - -class Cube - def initialize - @sides = [] - %w(left front right back top bottom).each_with_index { |side, i| - eval("@sides[#{i}] = @#{side} = Side.new(#{i})") - } - @left.sides = [@top, @front, @bottom, @back] - @front.sides = [@top, @right, @bottom, @left] - @right.sides = [@top, @back, @bottom, @front] - @back.sides = [@top, @left, @bottom, @right] - @top.sides = [@back, @right, @front, @left] - @bottom.sides = [@front, @right, @back, @left] - end - - def read_facelets(fs) - pattern = Regexp.new(<<-EOP.gsub(/\w/, '\w').gsub(/\s+/, '\s*')) - (w w w) - (w w w) - (w w w) -(r r r) (g g g) (b b b) (o o o) -(r r r) (g g g) (b b b) (o o o) -(r r r) (g g g) (b b b) (o o o) - (y y y) - (y y y) - (y y y) - EOP - md = pattern.match(fs).to_a - - @top.facelets = parse_facelets(md.values_at(1,2,3)) - @left.facelets = parse_facelets(md.values_at(4,8,12)) - @front.facelets = parse_facelets(md.values_at(5,9,13)) - @right.facelets = parse_facelets(md.values_at(6,10,14)) - @back.facelets = parse_facelets(md.values_at(7,11,15)) - @bottom.facelets = parse_facelets(md.values_at(16,17,18)) - end - - def turn(side, dir) - #p 'turn %d in %d' % [side, dir] - @sides[side].turn(dir) - #puts inspect - end - - def inspect - <<-EOF.gsub(/(\d):(\d)-(\d)/) { @sides[$1.to_i].inspect(Range.new($2.to_i, $3.to_i)) } - 4:0-2 - 4:3-5 - 4:6-8 -0:0-2 1:0-2 2:0-2 3:0-2 -0:3-5 1:3-5 2:3-5 3:3-5 -0:6-8 1:6-8 2:6-8 3:6-8 - 5:0-2 - 5:3-5 - 5:6-8 - EOF - end - -private - def parse_facelets(rows) - rows.join.delete(' ').split(//) - end -end - -#$stdin = DATA - -gets.to_i.times do |i| - puts "Scenario ##{i+1}:" - fs = '' - 9.times { fs << gets } - cube = Cube.new - cube.read_facelets fs - gets.to_i.times do |t| - side, dir = gets.split.map {|s| s.to_i} - cube.turn(side, dir) - end - puts cube.inspect - puts -end - -# 2004 by murphy <korny@cYcnus.de> -# GPL -class Scenario - class TimePoint - attr_reader :data - def initialize *data - @data = data - end - - def [] i - @data[i] or 0 - end - - include Comparable - def <=> tp - r = 0 - [@data.size, tp.data.size].max.times do |i| - r = self[i] <=> tp[i] - return r if r.nonzero? - end - 0 - end - - def - tp - r = [] - [@data.size, tp.data.size].max.times do |i| - r << self[i] - tp[i] - end - r - end - - def inspect - # 01/01/1800 00:00:00 - '%02d/%02d/%04d %02d:%02d:%02d' % @data.values_at(1, 2, 0, 3, 4, 5) - end - end - - ONE_HOUR = TimePoint.new 0, 0, 0, 1, 0, 0 - - APPOINTMENT_PATTERN = / - ( \d{4} ) \s ( \d{2} ) \s ( \d{2} ) \s ( \d{2} ) \s ( \d{2} ) \s ( \d{2} ) \s - ( \d{4} ) \s ( \d{2} ) \s ( \d{2} ) \s ( \d{2} ) \s ( \d{2} ) \s ( \d{2} ) - /x - - def initialize io - @team_size = io.gets.to_i - @data = [ [TimePoint.new(1800, 01, 01, 00, 00, 00), @team_size] ] - @team_size.times do # each team member - io.gets.to_i.times do # each appointment - m = APPOINTMENT_PATTERN.match io.gets - @data << [TimePoint.new(*m.captures[0,6].map { |x| x.to_i }), -1] - @data << [TimePoint.new(*m.captures[6,6].map { |x| x.to_i }), +1] - end - end - @data << [TimePoint.new(2200, 01, 01, 00, 00, 00), -@team_size] - end - - def print_time_plan - n = 0 - appointment = nil - no_appointment = true - @data.sort_by { |x| x[0] }.each do |x| - tp, action = *x - n += action - # at any time during the meeting, at least two team members need to be there - # and at most one team member is allowed to be absent - if n >= 2 and (@team_size - n) <= 1 - appointment ||= tp - else - if appointment - # the meeting should be at least one hour in length - if TimePoint.new(*(tp - appointment)) >= ONE_HOUR - puts 'appointment possible from %p to %p' % [appointment, tp] - no_appointment = false - end - appointment = false - end - end - end - puts 'no appointment possible' if no_appointment - end -end - -# read the data -DATA.gets.to_i.times do |si| # each scenario - puts 'Scenario #%d:' % (si + 1) - sc = Scenario.new DATA - sc.print_time_plan - puts -end - -#__END__ -2 -3 -3 -2002 06 28 15 00 00 2002 06 28 18 00 00 TUD Contest Practice Session -2002 06 29 10 00 00 2002 06 29 15 00 00 TUD Contest -2002 11 15 15 00 00 2002 11 17 23 00 00 NWERC Delft -4 -2002 06 25 13 30 00 2002 06 25 15 30 00 FIFA World Cup Semifinal I -2002 06 26 13 30 00 2002 06 26 15 30 00 FIFA World Cup Semifinal II -2002 06 29 13 00 00 2002 06 29 15 00 00 FIFA World Cup Third Place -2002 06 30 13 00 00 2002 06 30 15 00 00 FIFA World Cup Final -1 -2002 06 01 00 00 00 2002 06 29 18 00 00 Preparation of Problem Set -2 -1 -1800 01 01 00 00 00 2200 01 01 00 00 00 Solving Problem 8 -0 - -require 'token_consts' -require 'symbol' -require 'ctype' -require 'error' - -class Fixnum - # Treat char as a digit and return it's value as Fixnum. - # Returns nonsense for non-digits. - # Examples: - # <code> - # RUBY_VERSION[0].digit == '1.8.2'[0].digit == 1 - # </code> - # - # <code> - # ?6.digit == 6 - # </code> - # - # <code> - # ?A.digit == 17 - # </code> - def digit - self - ?0 - end -end - -## -# Stellt einen einfachen Scanner für die lexikalische Analyse der Sprache Pas-0 dar. -# -# @author Andreas Kunert -# Ruby port by murphy -class Scanner - - include TokenConsts - - attr_reader :line, :pos - - # To allow Scanner.new without parameters. - DUMMY_INPUT = 'dummy file' - def DUMMY_INPUT.getc - nil - end - - ## - # Erzeugt einen Scanner, der als Eingabe das übergebene IO benutzt. - def initialize input = DUMMY_INPUT - @line = 1 - @pos = 0 - - begin - @input = input - @next_char = @input.getc - rescue IOError # TODO show the reason! - Error.ioError - raise - end - end - - ## - # Liest das n - def read_next_char - begin - @pos += 1 - @current_char = @next_char - @next_char = @input.getc - rescue IOError - Error.ioError - raise - end - end - - ## - # Sucht das nächste Symbol, identifiziert es, instantiiert ein entsprechendes - # PascalSymbol-Objekt und gibt es zurück. - # @see Symbol - # @return das gefundene Symbol als PascalSymbol-Objekt - def get_symbol - current_symbol = nil - until current_symbol - read_next_char - - if @current_char.alpha? - identifier = @current_char.chr - while @next_char.alpha? or @next_char.digit? - identifier << @next_char - read_next_char - end - current_symbol = handle_identifier(identifier.upcase) - elsif @current_char.digit? - current_symbol = number - else - case @current_char - when ?\s - # ignore - when ?\n - new_line - when nil - current_symbol = PascalSymbol.new EOP - when ?{ - comment - - when ?: - if @next_char == ?= - read_next_char - current_symbol = PascalSymbol.new BECOMES - else - current_symbol = PascalSymbol.new COLON - end - - when ?< - if (@next_char == ?=) - read_next_char - current_symbol = PascalSymbol.new LEQSY - elsif (@next_char == ?>) - read_next_char - current_symbol = PascalSymbol.new NEQSY - else - current_symbol = PascalSymbol.new LSSSY - end - - when ?> - if (@next_char == ?=) - read_next_char - current_symbol = PascalSymbol.new GEQSY - else - current_symbol = PascalSymbol.new GRTSY - end - - when ?. then current_symbol = PascalSymbol.new PERIOD - when ?( then current_symbol = PascalSymbol.new LPARENT - when ?, then current_symbol = PascalSymbol.new COMMA - when ?* then current_symbol = PascalSymbol.new TIMES - when ?/ then current_symbol = PascalSymbol.new SLASH - when ?+ then current_symbol = PascalSymbol.new PLUS - when ?- then current_symbol = PascalSymbol.new MINUS - when ?= then current_symbol = PascalSymbol.new EQLSY - when ?) then current_symbol = PascalSymbol.new RPARENT - when ?; then current_symbol = PascalSymbol.new SEMICOLON - else - Error.error(100, @line, @pos) if @current_char > ?\s - end - end - end - current_symbol - end - -private - ## - # Versucht, in dem gegebenen String ein Schlüsselwort zu erkennen. - # Sollte dabei ein Keyword gefunden werden, so gibt er ein PascalSymbol-Objekt zurück, das - # das entsprechende Keyword repräsentiert. Ansonsten besteht die Rückgabe aus - # einem SymbolIdent-Objekt (abgeleitet von PascalSymbol), das den String 1:1 enthält - # @see symbol - # @return falls Keyword gefunden, zugehöriges PascalSymbol, sonst SymbolIdent - def handle_identifier identifier - if sym = KEYWORD_SYMBOLS[identifier] - PascalSymbol.new sym - else - SymbolIdent.new identifier - end - end - - MAXINT = 2**31 - 1 - MAXINT_DIV_10 = MAXINT / 10 - MAXINT_MOD_10 = MAXINT % 10 - ## - # Versucht, aus dem gegebenen Zeichen und den folgenden eine Zahl zusammenzusetzen. - # Dabei wird der relativ intuitive Algorithmus benutzt, die endgültige Zahl bei - # jeder weiteren Ziffer mit 10 zu multiplizieren und diese dann mit der Ziffer zu - # addieren. Sonderfälle bestehen dann nur noch in der Behandlung von reellen Zahlen. - # <BR> - # Treten dabei kein Punkt oder ein E auf, so gibt diese Methode ein SymbolIntCon-Objekt - # zurück, ansonsten (reelle Zahl) ein SymbolRealCon-Objekt. Beide Symbole enthalten - # jeweils die Zahlwerte. - # <BR> - # Anmerkung: Diese Funktion ist mit Hilfe der Java/Ruby-API deutlich leichter zu realisieren. - # Sie wurde dennoch so implementiert, um den Algorithmus zu demonstrieren - # @see symbol - # @return SymbolIntcon- oder SymbolRealcon-Objekt, das den Zahlwert enthält - def number - is_integer = true - integer_too_long = false - exponent = 0 - exp_counter = -1 - exp_sign = 1 - - integer_mantisse = @current_char.digit - - while (@next_char.digit? and integer_mantisse < MAXINT_DIV_10) or - (integer_mantisse == MAXINT_DIV_10 and @next_char.digit <= MAXINT_MOD_10) - integer_mantisse *= 10 - integer_mantisse += @next_char.digit - read_next_char - end - - real_mantisse = integer_mantisse - - while @next_char.digit? - integer_too_long = true - real_mantisse *= 10 - real_mantisse += @next_char.digit - read_next_char - end - if @next_char == ?. - read_next_char - is_integer = false - unless @next_char.digit? - Error.error 101, @line, @pos - end - while @next_char.digit? - real_mantisse += @next_char.digit * (10 ** exp_counter) - read_next_char - exp_counter -= 1 - end - end - if @next_char == ?E - is_integer = false - read_next_char - if @next_char == ?- - exp_sign = -1 - read_next_char - end - unless @next_char.digit? - Error.error 101, @line, @pos - end - while @next_char.digit? - exponent *= 10 - exponent += @next_char.digit - read_next_char - end - end - - if is_integer - if integer_too_long - Error.error 102, @line, @pos - end - SymbolIntcon.new integer_mantisse - else - SymbolRealcon.new real_mantisse * (10 ** (exp_sign * exponent)) - end - end - - ## - # Sorgt für ein Überlesen von Kommentaren. - # Es werden einfach alle Zeichen bis zu einer schließenden Klammer eingelesen - # und verworfen. - def comment - while @current_char != ?} - forbid_eop - new_line if @current_char == ?\n - read_next_char - end - end - - def new_line - @line += 1 - @pos = 0 - end - - def forbid_eop - if eop? - Error.error 103, @line, @pos - end - exit - end - - def eop? - @current_char.nil? - end -end - -## -# Läßt ein Testprogramm ablaufen. -# Dieses erzeugt sich ein Scanner-Objekt und ruft an diesem kontinuierlich bis zum Dateiende -# get_symbol auf. -if $0 == __FILE__ - scan = Scanner.new(File.new(ARGV[0] || 'test.pas')) - loop do - c = scan.get_symbol - puts c - break if c.typ == TokenConsts::EOP - end -end -# -*- ruby -*- - -# Local variables: -# indent-tabs-mode: nil -# ruby-indent-level: 4 -# End: - -# @@PLEAC@@_NAME -# @@SKIP@@ Ruby - -# @@PLEAC@@_WEB -# @@SKIP@@ http://www.ruby-lang.org - - -# @@PLEAC@@_1.0 -string = '\n' # two characters, \ and an n -string = 'Jon \'Maddog\' Orwant' # literal single quotes - -string = "\n" # a "newline" character -string = "Jon \"Maddog\" Orwant" # literal double quotes - -string = %q/Jon 'Maddog' Orwant/ # literal single quotes - -string = %q[Jon 'Maddog' Orwant] # literal single quotes -string = %q{Jon 'Maddog' Orwant} # literal single quotes -string = %q(Jon 'Maddog' Orwant) # literal single quotes -string = %q<Jon 'Maddog' Orwant> # literal single quotes - -a = <<"EOF" -This is a multiline here document -terminated by EOF on a line by itself -EOF - - -# @@PLEAC@@_1.1 -value = string[offset,count] -value = string[offset..-1] - -string[offset,count] = newstring -string[offset..-1] = newtail - -# in Ruby we can also specify intervals by their two offsets -value = string[offset..offs2] -string[offset..offs2] = newstring - -leading, s1, s2, trailing = data.unpack("A5 x3 A8 A8 A*") - -fivers = string.unpack("A5" * (string.length/5)) - -chars = string.unpack("A1" * string.length) - -string = "This is what you have" -# +012345678901234567890 Indexing forwards (left to right) -# 109876543210987654321- Indexing backwards (right to left) -# note that 0 means 10 or 20, etc. above - -first = string[0, 1] # "T" -start = string[5, 2] # "is" -rest = string[13..-1] # "you have" -last = string[-1, 1] # "e" -end_ = string[-4..-1] # "have" -piece = string[-8, 3] # "you" - -string[5, 2] = "wasn't" # change "is" to "wasn't" -string[-12..-1] = "ondrous" # "This wasn't wondrous" -string[0, 1] = "" # delete first character -string[-10..-1] = "" # delete last 10 characters - -if string[-10..-1] =~ /pattern/ - puts "Pattern matches in last 10 characters" -end - -string[0, 5].gsub!(/is/, 'at') - -a = "make a hat" -a[0, 1], a[-1, 1] = a[-1, 1], a[0, 1] - -a = "To be or not to be" -b = a.unpack("x6 A6") - -b, c = a.unpack("x6 A2 X5 A2") -puts "#{b}\n#{c}\n" - -def cut2fmt(*args) - template = '' - lastpos = 1 - for place in args - template += "A" + (place - lastpos).to_s + " " - lastpos = place - end - template += "A*" - return template -end - -fmt = cut2fmt(8, 14, 20, 26, 30) - - -# @@PLEAC@@_1.2 -# careful! "b is true" doesn't mean "b != 0" (0 is true in Ruby) -# thus no problem of "defined" later since only nil is false -# the following sets to `c' if `b' is nil or false -a = b || c - -# if you need Perl's behaviour (setting to `c' if `b' is 0) the most -# effective way is to use Numeric#nonzero? (thanks to Dave Thomas!) -a = b.nonzero? || c - -# you will still want to use defined? in order to test -# for scope existence of a given object -a = defined?(b) ? b : c - -dir = ARGV.shift || "/tmp" - - -# @@PLEAC@@_1.3 -v1, v2 = v2, v1 - -alpha, beta, production = %w(January March August) -alpha, beta, production = beta, production, alpha - - -# @@PLEAC@@_1.4 -num = char[0] -char = num.chr - -# Ruby also supports having a char from character constant -num = ?r - -char = sprintf("%c", num) -printf("Number %d is character %c\n", num, num) - -ascii = string.unpack("C*") -string = ascii.pack("C*") - -hal = "HAL" -ascii = hal.unpack("C*") -# We can't use Array#each since we can't mutate a Fixnum -ascii.collect! { |i| - i + 1 # add one to each ASCII value -} -ibm = ascii.pack("C*") -puts ibm - - -# @@PLEAC@@_1.5 -array = string.split('') - -array = string.unpack("C*") - -string.scan(/./) { |b| - # do something with b -} - -string = "an apple a day" -print "unique chars are: ", string.split('').uniq.sort, "\n" - -sum = 0 -for ascval in string.unpack("C*") # or use Array#each for a pure OO style :) - sum += ascval -end -puts "sum is #{sum & 0xffffffff}" # since Ruby will go Bignum if necessary - -# @@INCLUDE@@ include/ruby/slowcat.rb - - -# @@PLEAC@@_1.6 -revbytes = string.reverse - -revwords = string.split(" ").reverse.join(" ") - -revwords = string.split(/(\s+)/).reverse.join - -# using the fact that IO is Enumerable, you can directly "select" it -long_palindromes = File.open("/usr/share/dict/words"). - select { |w| w.chomp!; w.reverse == w && w.length > 5 } - - -# @@PLEAC@@_1.7 -while string.sub!("\t+") { ' ' * ($&.length * 8 - $`.length % 8) } -end - - -# @@PLEAC@@_1.8 -'You owe #{debt} to me'.gsub(/\#{(\w+)}/) { eval($1) } - -rows, cols = 24, 80 -text = %q(I am #{rows} high and #{cols} long) -text.gsub!(/\#{(\w+)}/) { eval("#{$1}") } -puts text - -'I am 17 years old'.gsub(/\d+/) { 2 * $&.to_i } - - -# @@PLEAC@@_1.9 -e = "bo peep".upcase -e.downcase! -e.capitalize! - -"thIS is a loNG liNE".gsub!(/\w+/) { $&.capitalize } - - -# @@PLEAC@@_1.10 -"I have #{n+1} guanacos." -print "I have ", n+1, " guanacos." - - -# @@PLEAC@@_1.11 -var = <<'EOF'.gsub(/^\s+/, '') - your text - goes here -EOF - - -# @@PLEAC@@_1.12 -string = "Folding and splicing is the work of an editor,\n"+ - "not a mere collection of silicon\n"+ - "and\n"+ - "mobile electrons!" - -def wrap(str, max_size) - all = [] - line = '' - for l in str.split - if (line+l).length >= max_size - all.push(line) - line = '' - end - line += line == '' ? l : ' ' + l - end - all.push(line).join("\n") -end - -print wrap(string, 20) -#=> Folding and -#=> splicing is the -#=> work of an editor, -#=> not a mere -#=> collection of -#=> silicon and mobile -#=> electrons! - - -# @@PLEAC@@_1.13 -string = %q(Mom said, "Don't do that.") -string.gsub(/['"]/) { '\\'+$& } -string.gsub(/['"]/, '\&\&') -string.gsub(/[^A-Z]/) { '\\'+$& } -"is a test!".gsub(/\W/) { '\\'+$& } # no function like quotemeta? - - -# @@PLEAC@@_1.14 -string.strip! - - -# @@PLEAC@@_1.15 -def parse_csv(text) - new = text.scan(/"([^\"\\]*(?:\\.[^\"\\]*)*)",?|([^,]+),?|,/) - new << nil if text[-1] == ?, - new.flatten.compact -end - -line = %q<XYZZY,"","O'Reilly, Inc","Wall, Larry","a \"glug\" bit,",5,"Error, Core Dumped"> -fields = parse_csv(line) -fields.each_with_index { |v,i| - print "#{i} : #{v}\n"; -} - - -# @@PLEAC@@_1.16 -# Use the soundex.rb Library from Michael Neumann. -# http://www.s-direktnet.de/homepages/neumann/rb_prgs/Soundex.rb -require 'Soundex' - -code = Text::Soundex.soundex(string) -codes = Text::Soundex.soundex(array) - -# substitution function for getpwent(): -# returns an array of user entries, -# each entry contains the username and the full name -def login_names - result = [] - File.open("/etc/passwd") { |file| - file.each_line { |line| - next if line.match(/^#/) - cols = line.split(":") - result.push([cols[0], cols[4]]) - } - } - result -end - -puts "Lookup user: " -user = STDIN.gets -user.chomp! -exit unless user -name_code = Text::Soundex.soundex(user) - -splitter = Regexp.new('(\w+)[^,]*\b(\w+)') -for username, fullname in login_names do - firstname, lastname = splitter.match(fullname)[1,2] - if name_code == Text::Soundex.soundex(username) - || name_code == Text::Soundex.soundex(firstname) - || name_code == Text::Soundex.soundex(lastname) - then - puts "#{username}: #{firstname} #{lastname}" - end -end - - -# @@PLEAC@@_1.17 -# @@INCLUDE@@ include/ruby/fixstyle.rb - - -# @@PLEAC@@_1.18 -# @@INCLUDE@@ include/ruby/psgrep.rb - - -# @@PLEAC@@_2.1 -# Matz tells that you can use Integer() for strict checked conversion. -Integer("abc") -#=> `Integer': invalid value for Integer: "abc" (ArgumentError) -Integer("567") -#=> 567 - -# You may use Float() for floating point stuff -Integer("56.7") -#=> `Integer': invalid value for Integer: "56.7" (ArgumentError) -Float("56.7") -#=> 56.7 - -# You may also use a regexp for that -if string =~ /^[+-]?\d+$/ - p 'is an integer' -else - p 'is not' -end - -if string =~ /^-?(?:\d+(?:\.\d*)?|\.\d+)$/ - p 'is a decimal number' -else - p 'is not' -end - - -# @@PLEAC@@_2.2 -# equal(num1, num2, accuracy) : returns true if num1 and num2 are -# equal to accuracy number of decimal places -def equal(i, j, a) - sprintf("%.#{a}g", i) == sprintf("%.#{a}g", j) -end - -wage = 536 # $5.36/hour -week = 40 * wage # $214.40 -printf("One week's wage is: \$%.2f\n", week/100.0) - - -# @@PLEAC@@_2.3 -num.round # rounds to integer - -a = 0.255 -b = sprintf("%.2f", a) -print "Unrounded: #{a}\nRounded: #{b}\n" -printf "Unrounded: #{a}\nRounded: %.2f\n", a - -print "number\tint\tfloor\tceil\n" -a = [ 3.3 , 3.5 , 3.7, -3.3 ] -for n in a - printf("% .1f\t% .1f\t% .1f\t% .1f\n", # at least I don't fake my output :) - n, n.to_i, n.floor, n.ceil) -end - - -# @@PLEAC@@_2.4 -def dec2bin(n) - [n].pack("N").unpack("B32")[0].sub(/^0+(?=\d)/, '') -end - -def bin2dec(n) - [("0"*32+n.to_s)[-32..-1]].pack("B32").unpack("N")[0] -end - - -# @@PLEAC@@_2.5 -for i in x .. y - # i is set to every integer from x to y, inclusive -end - -x.step(y,7) { |i| - # i is set to every integer from x to y, stepsize = 7 -} - -print "Infancy is: " -(0..2).each { |i| - print i, " " -} -print "\n" - - -# @@PLEAC@@_2.6 -# We can add conversion methods to the Integer class, -# this makes a roman number just a representation for normal numbers. -class Integer - - @@romanlist = [["M", 1000], - ["CM", 900], - ["D", 500], - ["CD", 400], - ["C", 100], - ["XC", 90], - ["L", 50], - ["XL", 40], - ["X", 10], - ["IX", 9], - ["V", 5], - ["IV", 4], - ["I", 1]] - - def to_roman - remains = self - roman = "" - for sym, num in @@romanlist - while remains >= num - remains -= num - roman << sym - end - end - roman - end - - def Integer.from_roman(roman) - ustr = roman.upcase - sum = 0 - for entry in @@romanlist - sym, num = entry[0], entry[1] - while sym == ustr[0, sym.length] - sum += num - ustr.slice!(0, sym.length) - end - end - sum - end - -end - - -roman_fifteen = 15.to_roman -puts "Roman for fifteen is #{roman_fifteen}" -i = Integer.from_roman(roman_fifteen) -puts "Converted back, #{roman_fifteen} is #{i}" - -# check -for i in (1..3900) - r = i.to_roman - j = Integer.from_roman(r) - if i != j - puts "error: #{i} : #{r} - #{j}" - end -end - - -# @@PLEAC@@_2.7 -random = rand(y-x+1)+x - -chars = ["A".."Z","a".."z","0".."9"].collect { |r| r.to_a }.join + %q(!@$%^&*) -password = (1..8).collect { chars[rand(chars.size)] }.pack("C*") - - -# @@PLEAC@@_2.8 -srand # uses a combination of the time, the process id, and a sequence number -srand(val) # for repeatable behaviour - - -# @@PLEAC@@_2.9 -# from the randomr lib: -# http://raa.ruby-lang.org/project/randomr/ -----> http://raa.ruby-lang.org/project/randomr/ - -require 'random/mersenne_twister' -mers = Random::MersenneTwister.new 123456789 -puts mers.rand(0) # 0.550321932544541 -puts mers.rand(10) # 2 - -# using online sources of random data via the realrand package: -# http://raa.ruby-lang.org/project/realrand/ -# **Note** -# The following online services are used in this package: -# http://www.random.org - source: atmospheric noise -# http://www.fourmilab.ch/hotbits - source: radioactive decay timings -# http://random.hd.org - source: entropy from local and network noise -# Please visit the sites and respect the rules of each service. - -require 'random/online' - -generator1 = Random::RandomOrg.new -puts generator1.randbyte(5).join(",") -puts generator1.randnum(10, 1, 6).join(",") # Roll dice 10 times. - -generator2 = Random::FourmiLab.new -puts generator2.randbyte(5).join(",") -# randnum is not supported. - -generator3 = Random::EntropyPool.new -puts generator3.randbyte(5).join(",") -# randnum is not supported. - - -# @@PLEAC@@_2.10 -def gaussian_rand - begin - u1 = 2 * rand() - 1 - u2 = 2 * rand() - 1 - w = u1*u1 + u2*u2 - end while (w >= 1) - w = Math.sqrt((-2*Math.log(w))/w) - [ u2*w, u1*w ] -end - -mean = 25 -sdev = 2 -salary = gaussian_rand[0] * sdev + mean -printf("You have been hired at \$%.2f\n", salary) - - -# @@PLEAC@@_2.11 -def deg2rad(d) - (d/180.0)*Math::PI -end - -def rad2deg(r) - (r/Math::PI)*180 -end - - -# @@PLEAC@@_2.12 -sin_val = Math.sin(angle) -cos_val = Math.cos(angle) -tan_val = Math.tan(angle) - -# AFAIK Ruby's Math module doesn't provide acos/asin -# While we're at it, let's also define missing hyperbolic functions -module Math - def Math.asin(x) - atan2(x, sqrt(1 - x**2)) - end - def Math.acos(x) - atan2(sqrt(1 - x**2), x) - end - def Math.atan(x) - atan2(x, 1) - end - def Math.sinh(x) - (exp(x) - exp(-x)) / 2 - end - def Math.cosh(x) - (exp(x) + exp(-x)) / 2 - end - def Math.tanh(x) - sinh(x) / cosh(x) - end -end - -# The support for Complex numbers is not built-in -y = Math.acos(3.7) -#=> in `sqrt': square root for negative number (ArgumentError) - -# There is an implementation of Complex numbers in 'complex.rb' in current -# Ruby distro, but it doesn't support atan2 with complex args, so it doesn't -# solve this problem. - - -# @@PLEAC@@_2.13 -log_e = Math.log(val) -log_10 = Math.log10(val) - -def log_base(base, val) - Math.log(val)/Math.log(base) -end - -answer = log_base(10, 10_000) -puts "log10(10,000) = #{answer}" - - -# @@PLEAC@@_2.14 -require 'matrix.rb' - -a = Matrix[[3, 2, 3], [5, 9, 8]] -b = Matrix[[4, 7], [9, 3], [8, 1]] -c = a * b - -a.row_size -a.column_size - -c.det -a.transpose - - -# @@PLEAC@@_2.15 -require 'complex.rb' -require 'rational.rb' - -a = Complex(3, 5) # 3 + 5i -b = Complex(2, -2) # 2 - 2i -puts "c = #{a*b}" - -c = a * b -d = 3 + 4*Complex::I - -printf "sqrt(#{d}) = %s\n", Math.sqrt(d) - - -# @@PLEAC@@_2.16 -number = hexadecimal.hex -number = octal.oct - -print "Gimme a number in decimal, octal, or hex: " -num = gets.chomp -exit unless defined?(num) -num = num.oct if num =~ /^0/ # does both oct and hex -printf "%d %x %o\n", num, num, num - -print "Enter file permission in octal: " -permissions = gets.chomp -raise "Exiting ...\n" unless defined?(permissions) -puts "The decimal value is #{permissions.oct}" - - -# @@PLEAC@@_2.17 -def commify(n) - n.to_s =~ /([^\.]*)(\..*)?/ - int, dec = $1.reverse, $2 ? $2 : "" - while int.gsub!(/(,|\.|^)(\d{3})(\d)/, '\1\2,\3') - end - int.reverse + dec -end - - -# @@PLEAC@@_2.18 -printf "It took %d hour%s\n", time, time == 1 ? "" : "s" - -# dunno if an equivalent to Lingua::EN::Inflect exists... - - -# @@PLEAC@@_2.19 -#----------------------------- -#!/usr/bin/ruby -# bigfact - calculating prime factors -def factorize(orig) - factors = {} - factors.default = 0 # return 0 instead nil if key not found in hash - n = orig - i = 2 - sqi = 4 # square of i - while sqi <= n do - while n.modulo(i) == 0 do - n /= i - factors[i] += 1 - # puts "Found factor #{i}" - end - # we take advantage of the fact that (i +1)**2 = i**2 + 2*i +1 - sqi += 2 * i + 1 - i += 1 - end - - if (n != 1) && (n != orig) - factors[n] += 1 - end - factors -end - -def printfactorhash(orig, factorcount) - print format("%-10d ", orig) - if factorcount.length == 0 - print "PRIME" - else - # sorts after number, because the hash keys are numbers - factorcount.sort.each { |factor,exponent| - print factor - if exponent > 1 - print "**", exponent - end - print " " - } - end - puts -end - -for arg in ARGV - n = arg.to_i - mfactors = factorize(n) - printfactorhash(n, mfactors) -end -#----------------------------- - - -# @@PLEAC@@_3.0 -puts Time.now - -print "Today is day ", Time.now.yday, " of the current year.\n" -print "Today is day ", Time.now.day, " of the current month.\n" - - -# @@PLEAC@@_3.1 -day, month, year = Time.now.day, Time.now.month, Time.now.year -# or -day, month, year = Time.now.to_a[3..5] - -tl = Time.now.localtime -printf("The current date is %04d %02d %02d\n", tl.year, tl.month, tl.day) - -Time.now.localtime.strftime("%Y-%m-%d") - - -# @@PLEAC@@_3.2 -Time.local(year, month, day, hour, minute, second).tv_sec -Time.gm(year, month, day, hour, minute, second).tv_sec - - -# @@PLEAC@@_3.3 -sec, min, hour, day, month, year, wday, yday, isdst, zone = Time.at(epoch_secs).to_a - - -# @@PLEAC@@_3.4 -when_ = now + difference # now -> Time ; difference -> Numeric (delta in seconds) -then_ = now - difference - - -# @@PLEAC@@_3.5 -bree = 361535725 -nat = 96201950 - -difference = bree - nat -puts "There were #{difference} seconds between Nat and Bree" - -seconds = difference % 60 -difference = (difference - seconds) / 60 -minutes = difference % 60 -difference = (difference - minutes) / 60 -hours = difference % 24 -difference = (difference - hours) / 24 -days = difference % 7 -weeks = (difference - days) / 7 - -puts "(#{weeks} weeks, #{days} days, #{hours}:#{minutes}:#{seconds})" - - -# @@PLEAC@@_3.6 -monthday, weekday, yearday = date.mday, date.wday, date.yday - -# AFAIK the week number is not just a division since week boundaries are on sundays -weeknum = d.strftime("%U").to_i + 1 - -year = 1981 -month = "jun" # or `6' if you want to emulate a broken language -day = 16 -t = Time.mktime(year, month, day) -print "#{month}/#{day}/#{year} was a ", t.strftime("%A"), "\n" - - -# @@PLEAC@@_3.7 -yyyy, mm, dd = $1, $2, $3 if "1998-06-25" =~ /(\d+)-(\d+)-(\d+)/ - -epoch_seconds = Time.mktime(yyyy, mm, dd).tv_sec - -# dunno an equivalent to Date::Manip#ParseDate - - -# @@PLEAC@@_3.8 -string = Time.at(epoch_secs) -Time.at(1234567890).gmtime # gives: Fri Feb 13 23:31:30 UTC 2009 - -time = Time.mktime(1973, "jan", 18, 3, 45, 50) -print "In localtime it gives: ", time.localtime, "\n" - - -# @@PLEAC@@_3.9 -# Ruby provides micro-seconds in Time object -Time.now.usec - -# Ruby gives the seconds in floating format when substracting two Time objects -before = Time.now -line = gets -elapsed = Time.now - before -puts "You took #{elapsed} seconds." - -# On my Celeron-400 with Linux-2.2.19-14mdk, average for three execs are: -# This Ruby version: average 0.00321 sec -# Cookbook's Perl version: average 0.00981 sec -size = 500 -number_of_times = 100 -total_time = 0 -number_of_times.times { - # populate array - array = [] - size.times { array << rand } - # sort it - begin_ = Time.now - array.sort! - time = Time.now - begin_ - total_time += time -} -printf "On average, sorting %d random numbers takes %.5f seconds\n", - size, (total_time/Float(number_of_times)) - - -# @@PLEAC@@_3.10 -sleep(0.005) # Ruby is definitely not as broken as Perl :) -# (may be interrupted by sending the process a SIGALRM) - - -# @@PLEAC@@_3.11 -#!/usr/bin/ruby -w -# hopdelta - feed mail header, produce lines -# showing delay at each hop. -require 'time' -class MailHopDelta - - def initialize(mail) - @head = mail.gsub(/\n\s+/,' ') - @topline = %w-Sender Recipient Time Delta- - @start_from = mail.match(/^From.*\@([^\s>]*)/)[1] - @date = Time.parse(mail.match(/^Date:\s+(.*)/)[1]) - end - - def out(line) - "%-20.20s %-20.20s %-20.20s %s" % line - end - - def hop_date(day) - day.strftime("%I:%M:%S %Y/%m/%d") - end - - def puts_hops - puts out(@topline) - puts out(['Start', @start_from, hop_date(@date),'']) - @head.split(/\n/).reverse.grep(/^Received:/).each do |hop| - hop.gsub!(/\bon (.*?) (id.*)/,'; \1') - whence = hop.match(/;\s+(.*)$/)[1] - unless whence - warn "Bad received line: #{hop}" - next - end - from = $+ if hop =~ /from\s+(\S+)|\((.*?)\)/ - by = $1 if hop =~ /by\s+(\S+\.\S+)/ - next unless now = Time.parse(whence).localtime - delta = now - @date - puts out([from, by, hop_date(now), hop_time(delta)]) - @date = now - end - end - - def hop_time(secs) - sign = secs < 0 ? -1 : 1 - days, secs = secs.abs.divmod(60 * 60 * 24) - hours,secs = secs.abs.divmod(60 * 60) - mins, secs = secs.abs.divmod(60) - rtn = "%3ds" % [secs * sign] - rtn << "%3dm" % [mins * sign] if mins != 0 - rtn << "%3dh" % [hours * sign] if hours != 0 - rtn << "%3dd" % [days * sign] if days != 0 - rtn - end -end - -$/ = "" -mail = MailHopDelta.new(ARGF.gets).puts_hops - - -# @@PLEAC@@_4.0 -single_level = [ "this", "that", "the", "other" ] - -# Ruby directly supports nested arrays -double_level = [ "this", "that", [ "the", "other" ] ] -still_single_level = [ "this", "that", [ "the", "other" ] ].flatten - - -# @@PLEAC@@_4.1 -a = [ "quick", "brown", "fox" ] -a = %w(Why are you teasing me?) - -lines = <<"END_OF_HERE_DOC".gsub(/^\s*(.+)/, '\1') - The boy stood on the burning deck, - It was as hot as glass. -END_OF_HERE_DOC - -bigarray = IO.readlines("mydatafile").collect { |l| l.chomp } - -name = "Gandalf" -banner = %Q(Speak, #{name}, and welcome!) - -host_info = `host #{his_host}` - -%x(ps #{$$}) - -banner = 'Costs only $4.95'.split(' ') - -rax = %w! ( ) < > { } [ ] ! - - -# @@PLEAC@@_4.2 -def commify_series(a) - a.size == 0 ? '' : - a.size == 1 ? a[0] : - a.size == 2 ? a.join(' and ') : - a[0..-2].join(', ') + ', and ' + a[-1] -end - -array = [ "red", "yellow", "green" ] - -print "I have ", array, " marbles\n" -# -> I have redyellowgreen marbles - -# But unlike Perl: -print "I have #{array} marbles\n" -# -> I have redyellowgreen marbles -# So, needs: -print "I have #{array.join(' ')} marbles\n" -# -> I have red yellow green marbles - -def commify_series(a) - sepchar = a.select { |p| p =~ /,/ } != [] ? '; ' : ', ' - a.size == 0 ? '' : - a.size == 1 ? a[0] : - a.size == 2 ? a.join(' and ') : - a[0..-2].join(sepchar) + sepchar + 'and ' + a[-1] -end - - -# @@PLEAC@@_4.3 -# (note: AFAIK Ruby doesn't allow gory change of Array length) -# grow the array by assigning nil to past the end of array -ary[new_size-1] = nil -# shrink the array by slicing it down -ary.slice!(new_size..-1) -# init the array with given size -Array.new(number_of_elems) -# assign to an element past the original end enlarges the array -ary[index_new_last_elem] = value - -def what_about_that_array(a) - print "The array now has ", a.size, " elements.\n" - # Index of last element is not really interesting in Ruby - print "Element #3 is `#{a[3]}'.\n" -end -people = %w(Crosby Stills Nash Young) -what_about_that_array(people) - - -# @@PLEAC@@_4.4 -# OO style -bad_users.each { |user| - complain(user) -} -# or, functional style -for user in bad_users - complain(user) -end - -for var in ENV.keys.sort - puts "#{var}=#{ENV[var]}" -end - -for user in all_users - disk_space = get_usage(user) - if (disk_space > MAX_QUOTA) - complain(user) - end -end - -for l in IO.popen("who").readlines - print l if l =~ /^gc/ -end - -# we can mimic the obfuscated Perl way -while fh.gets # $_ is set to the line just read - chomp # $_ has a trailing \n removed, if it had one - split.each { |w| # $_ is split on whitespace - # but $_ is not set to each chunk as in Perl - print w.reverse - } -end -# ...or use a cleaner way -for l in fh.readlines - l.chomp.split.each { |w| print w.reverse } -end - -# same drawback as in problem 1.4, we can't mutate a Numeric... -array.collect! { |v| v - 1 } - -a = [ .5, 3 ]; b = [ 0, 1 ] -for ary in [ a, b ] - ary.collect! { |v| v * 7 } -end -puts "#{a.join(' ')} #{b.join(' ')}" - -# we can mutate Strings, cool; we need a trick for the scalar -for ary in [ [ scalar ], array, hash.values ] - ary.each { |v| v.strip! } # String#strip rules :) -end - - -# @@PLEAC@@_4.5 -# not relevant in Ruby since we have always references -for item in array - # do somethingh with item -end - - -# @@PLEAC@@_4.6 -unique = list.uniq - -# generate a list of users logged in, removing duplicates -users = `who`.collect { |l| l =~ /(\w+)/; $1 }.sort.uniq -puts("users logged in: #{commify_series(users)}") # see 4.2 for commify_series - - -# @@PLEAC@@_4.7 -a - b -# [ 1, 1, 2, 2, 3, 3, 3, 4, 5 ] - [ 1, 2, 4 ] -> [3, 5] - - -# @@PLEAC@@_4.8 -union = a | b -intersection = a & b -difference = a - b - - -# @@PLEAC@@_4.9 -array1.concat(array2) -# if you will assign to another object, better use: -new_ary = array1 + array2 - -members = [ "Time", "Flies" ] -initiates = [ "An", "Arrow" ] -members += initiates - -members = [ "Time", "Flies" ] -initiates = [ "An", "Arrow" ] -members[2,0] = [ "Like", initiates ].flatten - -members[0] = "Fruit" -members[3,2] = "A", "Banana" - - -# @@PLEAC@@_4.10 -reversed = ary.reverse - -ary.reverse_each { |e| - # do something with e -} - -descending = ary.sort.reverse -descending = ary.sort { |a,b| b <=> a } - - -# @@PLEAC@@_4.11 -# remove n elements from front of ary (shift n) -front = ary.slice!(0, n) - -# remove n elements from the end of ary (pop n) -end_ = ary.slice!(-n .. -1) - -# let's extend the Array class, to make that useful -class Array - def shift2() - slice!(0 .. 1) # more symetric with pop2... - end - def pop2() - slice!(-2 .. -1) - end -end - -friends = %w(Peter Paul Mary Jim Tim) -this, that = friends.shift2 - -beverages = %w(Dew Jolt Cola Sprite Fresca) -pair = beverages.pop2 - - -# @@PLEAC@@_4.12 -# use Enumerable#detect (or the synonym Enumerable#find) -highest_eng = employees.detect { |emp| emp.category == 'engineer' } - - -# @@PLEAC@@_4.13 -# use Enumerable#select (or the synonym Enumerable#find_all) -bigs = nums.select { |i| i > 1_000_000 } -pigs = users.keys.select { |k| users[k] > 1e7 } - -matching = `who`.select { |u| u =~ /^gnat / } - -engineers = employees.select { |e| e.position == 'Engineer' } - -secondary_assistance = applicants.select { |a| - a.income >= 26_000 && a.income < 30_000 -} - - -# @@PLEAC@@_4.14 -# normally you would have an array of Numeric (Float or -# Fixnum or Bignum), so you would use: -sorted = unsorted.sort -# if you have strings representing Integers or Floats -# you may specify another sort method: -sorted = unsorted.sort { |a,b| a.to_f <=> b.to_f } - -# let's use the list of my own PID's -`ps ux`.split("\n")[1..-1]. - select { |i| i =~ /^#{ENV['USER']}/ }. - collect { |i| i.split[1] }. - sort { |a,b| a.to_i <=> b.to_i }.each { |i| puts i } -puts "Select a process ID to kill:" -pid = gets.chomp -raise "Exiting ... \n" unless pid && pid =~ /^\d+$/ -Process.kill('TERM', pid.to_i) -sleep 2 -Process.kill('KILL', pid.to_i) - -descending = unsorted.sort { |a,b| b.to_f <=> a.to_f } - - -# @@PLEAC@@_4.15 -ordered = unordered.sort { |a,b| compare(a,b) } - -precomputed = unordered.collect { |e| [compute, e] } -ordered_precomputed = precomputed.sort { |a,b| a[0] <=> b[0] } -ordered = ordered_precomputed.collect { |e| e[1] } - -ordered = unordered.collect { |e| [compute, e] }. - sort { |a,b| a[0] <=> b[0] }. - collect { |e| e[1] } - -for employee in employees.sort { |a,b| a.name <=> b.name } - print employee.name, " earns \$ ", employee.salary, "\n" -end - -# Beware! `0' is true in Ruby. -# For chaining comparisons, you may use Numeric#nonzero?, which -# returns num if num is not zero, nil otherwise -sorted = employees.sort { |a,b| (a.name <=> b.name).nonzero? || b.age <=> a.age } - -users = [] -# getpwent is not wrapped in Ruby... let's fallback -IO.readlines('/etc/passwd').each { |u| users << u.split(':') } -users.sort! { |a,b| a[0] <=> b[0] } -for user in users - puts user[0] -end - -sorted = names.sort { |a,b| a[1, 1] <=> b[1, 1] } -sorted = strings.sort { |a,b| a.length <=> b.length } - -# let's show only the compact version -ordered = strings.collect { |e| [e.length, e] }. - sort { |a,b| a[0] <=> b[0] }. - collect { |e| e[1] } - -ordered = strings.collect { |e| [/\d+/.match(e)[0].to_i, e] }. - sort { |a,b| a[0] <=> b[0] }. - collect { |e| e[1] } - -print `cat /etc/passwd`.collect { |e| [e, e.split(':').indexes(3,2,0)].flatten }. - sort { |a,b| (a[1] <=> b[1]).nonzero? || (a[2] <=> b[2]).nonzero? || a[3] <=> b[3] }. - collect { |e| e[0] } - - -# @@PLEAC@@_4.16 -circular.unshift(circular.pop) # the last shall be first -circular.push(circular.shift) # and vice versa - -def grab_and_rotate(l) - l.push(ret = l.shift) - ret -end - -processes = [1, 2, 3, 4, 5] -while (1) - process = grab_and_rotate(processes) - puts "Handling process #{process}" - sleep 1 -end - - -# @@PLEAC@@_4.17 -def fisher_yates_shuffle(a) - (a.size-1).downto(1) { |i| - j = rand(i+1) - a[i], a[j] = a[j], a[i] if i != j - } -end - -def naive_shuffle(a) - for i in 0...a.size - j = rand(a.size) - a[i], a[j] = a[j], a[i] - end -end - - -# @@PLEAC@@_4.18 -#!/usr/bin/env ruby -# example 4-2 words -# words - gather lines, present in colums - -# class to encapsulate the word formatting from the input -class WordFormatter - def initialize(cols) - @cols = cols - end - - # helper to return the length of the longest word in the wordlist - def maxlen(wordlist) - max = 1 - for word in wordlist - if word.length > max - max = word.length - end - end - max - end - - # process the wordlist and print it formmated into columns - def output(wordlist) - collen = maxlen(wordlist) + 1 - columns = @cols / collen - columns = 1 if columns == 0 - rows = (wordlist.length + columns - 1) / columns - # now process each item, picking out proper piece for this position - 0.upto(rows * columns - 1) { |item| - target = (item % columns) * rows + (item / columns) - eol = ((item+1) % columns == 0) - piece = wordlist[target] || "" - piece = piece.ljust(collen) unless eol - print piece - puts if eol - } - # no need to finish it up, because eol is always true for the last element - end -end - -# get nr of chars that fit in window or console, see PLEAC 15.4 -# not portable -- linux only (?) -def getWinCharWidth() - buf = "\0" * 8 - $stdout.ioctl(0x5413, buf) - ws_row, ws_col, ws_xpixel, ws_ypixel = buf.unpack("$4") - ws_col || 80 -rescue - 80 -end - -# main program -cols = getWinCharWidth() -formatter = WordFormatter.new(cols) -words = readlines() -words.collect! { |line| - line.chomp -} -formatter.output(words) - - -# @@PLEAC@@_4.19 -# In ruby, Fixnum's are automatically converted to Bignum's when -# needed, so there is no need for an extra module -def factorial(n) - s = 1 - while n > 0 - s *= n - n -= 1 - end - s -end - -puts factorial(500) - -#--------------------------------------------------------- -# Example 4-3. tsc-permute -# tsc_permute: permute each word of input -def permute(items, perms) - unless items.length > 0 - puts perms.join(" ") - else - for i in items - newitems = items.dup - newperms = perms.dup - newperms.unshift(newitems.delete(i)) - permute(newitems, newperms) - end - end -end -# In ruby the main program must be after all definitions it is using -permute(ARGV, []) - -#--------------------------------------------------------- -# mjd_permute: permute each word of input - -def factorial(n) - s = 1 - while n > 0 - s *= n - n -= 1 - end - s -end - -# we use a class with a class variable store the private cache -# for the results of the factorial function. -class Factorial - @@fact = [ 1 ] - def Factorial.compute(n) - if @@fact[n] - @@fact[n] - else - @@fact[n] = n * Factorial.compute(n - 1) - end - end -end - -#--------------------------------------------------------- -# Example 4-4- mjd-permute -# n2pat(n, len): produce the N-th pattern of length len - -# We must use a lower case letter as parameter N, otherwise it is -# handled as constant Length is the length of the resulting -# array, not the index of the last element (length -1) like in -# the perl example. -def n2pat(n, length) - pat = [] - i = 1 - while i <= length - pat.push(n % i) - n /= i - i += 1 - end - pat -end - -# pat2perm(pat): turn pattern returned by n2pat() into -# permutation of integers. -def pat2perm(pat) - source = (0 .. pat.length - 1).to_a - perm = [] - perm.push(source.slice!(pat.pop)) while pat.length > 0 - perm -end - -def n2perm(n, len) - pat2perm(n2pat(n,len)) -end - -# In ruby the main program must be after all definitions -while gets - data = split - # the perl solution has used $#data, which is length-1 - num_permutations = Factorial.compute(data.length()) - 0.upto(num_permutations - 1) do |i| - # in ruby we can not use an array as selector for an array - # but by exchanging the two arrays, we can use the collect method - # which returns an array with the result of all block invocations - permutation = n2perm(i, data.length).collect { - |j| data[j] - } - puts permutation.join(" ") - end -end - - -# @@PLEAC@@_5.0 -age = { "Nat", 24, - "Jules", 25, - "Josh", 17 } - -age["Nat"] = 24 -age["Jules"] = 25 -age["Josh"] = 17 - -food_color = { - "Apple" => "red", - "Banana" => "yellow", - "Lemon" => "yellow", - "Carrot" => "orange" - } - -# In Ruby, you cannot avoid the double or simple quoting -# while manipulatin hashes - - -# @@PLEAC@@_5.1 -hash[key] = value - -food_color["Raspberry"] = "pink" -puts "Known foods:", food_color.keys - - -# @@PLEAC@@_5.2 -# does hash have a value for key ? -if (hash.has_key?(key)) - # it exists -else - # it doesn't -end - -[ "Banana", "Martini" ].each { |name| - print name, " is a ", food_color.has_key?(name) ? "food" : "drink", "\n" -} - -age = {} -age['Toddler'] = 3 -age['Unborn'] = 0 -age['Phantasm'] = nil - -for thing in ['Toddler', 'Unborn', 'Phantasm', 'Relic'] - print "#{thing}: " - print "Has-key " if age.has_key?(thing) - print "True " if age[thing] - print "Nonzero " if age[thing] && age[thing].nonzero? - print "\n" -end - -#=> -# Toddler: Has-key True Nonzero -# Unborn: Has-key True -# Phantasm: Has-key -# Relic: - -# You use Hash#has_key? when you use Perl's exists -> it checks -# for existence of a key in a hash. -# All Numeric are "True" in ruby, so the test doesn't have the -# same semantics as in Perl; you would use Numeric#nonzero? to -# achieve the same semantics (false if 0, true otherwise). - - -# @@PLEAC@@_5.3 -food_color.delete("Banana") - - -# @@PLEAC@@_5.4 -hash.each { |key, value| - # do something with key and value -} - -hash.each_key { |key| - # do something with key -} - -food_color.each { |food, color| - puts "#{food} is #{color}" -} - -food_color.each_key { |food| - puts "#{food} is #{food_color[food]}" -} - -# IMO this demonstrates that OO style is by far more readable -food_color.keys.sort.each { |food| - puts "#{food} is #{food_color[food]}." -} - -#----------------------------- -#!/usr/bin/ruby -# countfrom - count number of messages from each sender - -# Default value is 0 -from = Hash.new(0) -while gets - /^From: (.*)/ and from[$1] += 1 -end - -# More useful to sort by number of received mail by person -from.sort {|a,b| b[1]<=>a[1]}.each { |v| - puts "#{v[1]}: #{v[0]}" -} -#----------------------------- - - -# @@PLEAC@@_5.5 -# You may use the built-in 'inspect' method this way: -p hash - -# Or do it the Cookbook way: -hash.each { |k,v| puts "#{k} => #{v}" } - -# Sorted by keys -hash.sort.each { |e| puts "#{e[0]} => #{e[1]}" } -# Sorted by values -hash.sort{|a,b| a[1]<=>b[1]}.each { |e| puts "#{e[0]} => #{e[1]}" } - - -# @@PLEAC@@_5.7 -ttys = Hash.new -for i in `who` - user, tty = i.split - (ttys[user] ||= []) << tty # see problems_ruby for more infos -end -ttys.keys.sort.each { |k| - puts "#{k}: #{commify_series(ttys[k])}" # from 4.2 -} - - -# @@PLEAC@@_5.8 -surname = { "Mickey" => "Mantle", "Babe" => "Ruth" } -puts surname.index("Mantle") - -# If you really needed to 'invert' the whole hash, use Hash#invert - -#----------------------------- -#!/usr/bin/ruby -w -# foodfind - find match for food or color - -given = ARGV.shift or raise "usage: foodfind food_or_color" - -color = { - "Apple" => "red", - "Banana" => "yellow", - "Lemon" => "yellow", - "Carrot" => "orange", -} - -if (color.has_key?(given)) - puts "#{given} is a food with color #{color[given]}." -end -if (color.has_value?(given)) - puts "#{color.index(given)} is a food with color #{given}." -end -#----------------------------- - - -# @@PLEAC@@_5.9 -# Sorted by keys (Hash#sort gives an Array of pairs made of each key,value) -food_color.sort.each { |f| - puts "#{f[0]} is #{f[1]}." -} - -# Sorted by values -food_color.sort { |a,b| a[1] <=> b[1] }.each { |f| - puts "#{f[0]} is #{f[1]}." -} - -# Sorted by length of values -food_color.sort { |a,b| a[1].length <=> b[1].length }.each { |f| - puts "#{f[0]} is #{f[1]}." -} - - -# @@PLEAC@@_5.10 -merged = a.clone.update(b) # because Hash#update changes object in place - -drink_color = { "Galliano" => "yellow", "Mai Tai" => "blue" } -ingested_color = drink_color.clone.update(food_color) - -substance_color = {} -for i in [ food_color, drink_color ] - i.each_key { |k| - if substance_color.has_key?(k) - puts "Warning: #{k} seen twice. Using the first definition." - next - end - substance_color[k] = 1 - } -end - - -# @@PLEAC@@_5.11 -common = hash1.keys & hash2.keys - -this_not_that = hash1.keys - hash2.keys - - -# @@PLEAC@@_5.12 -# no problem here, Ruby handles any kind of object for key-ing -# (it takes Object#hash, which defaults to Object#id) - - -# @@PLEAC@@_5.13 -# AFAIK, not possible in Ruby - - -# @@PLEAC@@_5.14 -# Be careful, the following is possible only because Fixnum objects are -# special (documentation says: there is effectively only one Fixnum object -# instance for any given integer value). -count = Hash.new(0) -array.each { |e| - count[e] += 1 -} - - -# @@PLEAC@@_5.15 -father = { - "Cain" , "Adam", - "Abel" , "Adam", - "Seth" , "Adam", - "Enoch" , "Cain", - "Irad" , "Enoch", - "Mehujael" , "Irad", - "Methusael" , "Mehujael", - "Lamech" , "Methusael", - "Jabal" , "Lamech", - "Jubal" , "Lamech", - "Tubalcain" , "Lamech", - "Enos" , "Seth", -} - -while gets - chomp - begin - print $_, " " - end while $_ = father[$_] - puts -end - -children = {} -father.each { |k,v| - (children[v] ||= []) << k -} -while gets - chomp - puts "#{$_} begat #{(children[$_] || ['Nobody']).join(', ')}.\n" -end - -includes = {} -files.each { |f| - begin - for l in IO.readlines(f) - next unless l =~ /^\s*#\s*include\s*<([^>]+)>/ - (includes[$1] ||= []) << f - end - rescue SystemCallError - $stderr.puts "#$! (skipping)" - end -} - -include_free = includes.values.flatten.uniq - includes.keys - - -# @@PLEAC@@_5.16 -# dutree - print sorted intented rendition of du output -#% dutree -#% dutree /usr -#% dutree -a -#% dutree -a /bin - -# The DuNode class collects all information about a directory, -# and provides some convenience methods -class DuNode - - attr_reader :name - attr_accessor :size - attr_accessor :kids - - def initialize(name) - @name = name - @kids = [] - @size = 0 - end - - # support for sorting nodes with side - def size_compare(node2) - @size <=> node2.size - end - - def basename - @name.sub(/.*\//, "") - end - - #returns substring before last "/", nil if not there - def parent - p = @name.sub(/\/[^\/]+$/,"") - if p == @name - nil - else - p - end - end - -end - -# The DuTree does the acdtual work of -# getting the input, parsing it, builging up a tree -# and format it for output -class Dutree - - attr_reader :topdir - - def initialize - @nodes = Hash.new - @dirsizes = Hash.new(0) - @kids = Hash.new([]) - end - - # get a node by name, create it if it does not exist yet - def get_create_node(name) - if @nodes.has_key?(name) - @nodes[name] - else - node = DuNode.new(name) - @nodes[name] = node - node - end - end - - # run du, read in input, save sizes and kids - # stores last directory read in instance variable topdir - def input(arguments) - name = "" - cmd = "du " + arguments.join(" ") - IO.popen(cmd) { |pipe| - pipe.each { |line| - size, name = line.chomp.split(/\s+/, 2) - node = get_create_node(name) - node.size = size.to_i - @nodes[name] = node - parent = node.parent - if parent - get_create_node(parent).kids.push(node) - end - } - } - @topdir = @nodes[name] - end - - # figure out how much is taken in each directory - # that isn't stored in the subdirectories. Add a new - # fake kid called "." containing that much. - def get_dots(node) - cursize = node.size - for kid in node.kids - cursize -= kid.size - get_dots(kid) - end - if node.size != cursize - newnode = get_create_node(node.name + "/.") - newnode.size = cursize - node.kids.push(newnode) - end - end - - # recursively output everything - # passing padding and number width as well - # on recursive calls - def output(node, prefix="", width=0) - line = sprintf("%#{width}d %s", node.size, node.basename) - puts(prefix + line) - prefix += line.sub(/\d /, "| ") - prefix.gsub!(/[^|]/, " ") - if node.kids.length > 0 # not a bachelor node - kids = node.kids - kids.sort! { |a,b| - b.size_compare(a) - } - width = kids[0].size.to_s.length - for kid in kids - output(kid, prefix, width) - end - end - end - -end - -tree = Dutree.new -tree.input(ARGV) -tree.get_dots(tree.topdir) -tree.output(tree.topdir) - - -# @@PLEAC@@_6.0 -# The verbose version are match, sub, gsub, sub! and gsub!; -# pattern needs to be a Regexp object; it yields a MatchData -# object. -pattern.match(string) -string.sub(pattern, replacement) -string.gsub(pattern, replacement) -# As usual in Ruby, sub! does the same as sub but also modifies -# the object, the same for gsub!/gsub. - -# Sugared syntax yields the position of the match (or nil if no -# match). Note that the object at the right of the operator needs -# not to be a Regexp object (it can be a String). The "dont -# match" operator yields true or false. -meadow =~ /sheep/ # position of the match, nil if no match -meadow !~ /sheep/ # true if doesn't match, false if it does -# There is no sugared version for the substitution - -meadow =~ /\bovines?\b/i and print "Here be sheep!" - -string = "good food" -string.sub!(/o*/, 'e') - -# % echo ababacaca | ruby -ne 'puts $& if /(a|ba|b)+(a|ac)+/' -# ababa - -# The "global" (or "multiple") match is handled by String#scan -scan (/(\d+)/) { - puts "Found number #{$1}" -} - -# String#scan yields an Array if not used with a block -numbers = scan(/\d+/) - -digits = "123456789" -nonlap = digits.scan(/(\d\d\d)/) -yeslap = digits.scan(/(?=(\d\d\d))/) -puts "Non-overlapping: #{nonlap.join(' ')}" -puts "Overlapping: #{yeslap.join(' ')}"; -# Non-overlapping: 123 456 789 -# Overlapping: 123 234 345 456 567 678 789 - -string = "And little lambs eat ivy" -string =~ /l[^s]*s/ -puts "(#$`) (#$&) (#$')" -# (And ) (little lambs) ( eat ivy) - - -# @@PLEAC@@_6.1 -# Ruby doesn't have the same problem: -dst = src.sub('this', 'that') - -progname = $0.sub('^.*/', '') - -bindirs = %w(/usr/bin /bin /usr/local/bin) -libdirs = bindirs.map { |l| l.sub('bin', 'lib') } - - -# @@PLEAC@@_6.3 -/\S+/ # as many non-whitespace bytes as possible -/[A-Za-z'-]+/ # as many letters, apostrophes, and hyphens - -/\b([A-Za-z]+)\b/ # usually best -/\s([A-Za-z]+)\s/ # fails at ends or w/ punctuation - - -# @@PLEAC@@_6.4 -require 'socket' -str = 'www.ruby-lang.org and www.rubygarden.org' -re = / - ( # capture the hostname in $1 - (?: # these parens for grouping only - (?! [-_] ) # lookahead for neither underscore nor dash - [\w-] + # hostname component - \. # and the domain dot - ) + # now repeat that whole thing a bunch of times - [A-Za-z] # next must be a letter - [\w-] + # now trailing domain part - ) # end of $1 capture - /x # /x for nice formatting - -str.gsub! re do # pass a block to execute replacement - host = TCPsocket.gethostbyname($1) - "#{$1} [#{host[3]}]" -end - -puts str -#----------------------------- -# to match whitespace or #-characters in an extended re you need to escape -# them. - -foo = 42 -str = 'blah #foo# blah' -str.gsub! %r/ # replace - \# # a pound sign - (\w+) # the variable name - \# # another pound sign - /x do - eval $1 # with the value of a local variable - end -puts str # => blah 42 blah - - -# @@PLEAC@@_6.5 -# The 'g' modifier doesn't exist in Ruby, a regexp can't be used -# directly in a while loop; instead, use String#scan { |match| .. } -fish = 'One fish two fish red fish blue fish' -WANT = 3 -count = 0 -fish.scan(/(\w+)\s+fish\b/i) { - if (count += 1) == WANT - puts "The third fish is a #{$1} one." - end -} - -if fish =~ /(?:\w+\s+fish\s+){2}(\w+)\s+fish/i - puts "The third fish is a #{$1} one." -end - -pond = 'One fish two fish red fish blue fish' -# String#scan without a block gives an array of matches, each match -# being an array of all the specified groups -colors = pond.scan(/(\w+)\s+fish\b/i).flatten # get all matches -color = colors[2] # then the one we want -# or without a temporary array -color = pond.scan(/(\w+)\s+fish\b/i).flatten[2] # just grab element 3 -puts "The third fish in the pond is #{color}." - -count = 0 -fishes = 'One fish two fish red fish blue fish' -evens = fishes.scan(/(\w+)\s+fish\b/i).select { (count+=1) % 2 == 0 } -print "Even numbered fish are #{evens.join(' ')}." - -count = 0 -fishes.gsub(/ - \b # makes next \w more efficient - ( \w+ ) # this is what we\'ll be changing - ( - \s+ fish \b - ) - /x) { - if (count += 1) == 4 - 'sushi' + $2 - else - $1 + $2 - end -} - -pond = 'One fish two fish red fish blue fish swim here.' -puts "Last fish is #{pond.scan(/\b(\w+)\s+fish\b/i).flatten[-1]}" - -/ - A # find some pattern A - (?! # mustn\'t be able to find - .* # something - A # and A - ) - $ # through the end of the string -/x - -# The "s" perl modifier is "m" in Ruby (not very nice since there is -# also an "m" in perl..) -pond = "One fish two fish red fish blue fish swim here." -if (pond =~ / - \b ( \w+) \s+ fish \b - (?! .* \b fish \b ) - /mix) - puts "Last fish is #{$1}." -else - puts "Failed!" -end - - -# @@PLEAC@@_6.6 -#----------------------------- -#!/usr/bin/ruby -w -# killtags - very bad html killer -$/ = nil; # each read is whole file -while file = gets() do - file.gsub!(/<.*?>/m,''); # strip tags (terribly) - puts file # print file to STDOUT -end -#----------------------------- -#!/usr/bin/ruby -w -#headerfy - change certain chapter headers to html -$/ = '' -while file = gets() do - pattern = / - \A # start of record - ( # capture in $1 - Chapter # text string - \s+ # mandatory whitespace - \d+ # decimal number - \s* # optional whitespace - : # a real colon - . * # anything not a newline till end of line - ) - /x - puts file.gsub(pattern,'<H1>\1</H1>') -end -#----------------------------- -#% ruby -00pe "gsub!(/\A(Chapter\s+\d+\s*:.*)/,'<H1>\1</H1>')" datafile - -#!/usr/bin/ruby -w -#----------------------------- -for file in ARGV - file = File.open(ARGV.shift) - while file.gets('') do # each read is a paragraph - print "chunk #{$.} in $ARGV has <<#{$1}>>\n" while /^START(.*?)^END/m - end # /m activates the multiline mode -end -#----------------------------- - -# @@PLEAC@@_6.7 -#----------------------------- -$/ = nil; -file = File.open("datafile") -chunks = file.gets.split(/pattern/) -#----------------------------- -# .Ch, .Se and .Ss divide chunks of STDIN -chunks = gets(nil).split(/^\.(Ch|Se|Ss)$/) -print "I read #{chunks.size} chunks.\n" -#----------------------------- - - -# @@PLEAC@@_6.8 -while gets - if ~/BEGIN/ .. ~/END/ - # line falls between BEGIN and END inclusive - end -end - -while gets - if ($. == firstnum) .. ($. == lastnum) - # operate between firstnum and lastnum line number - end -end - -# in ruby versions prior to 1.8, the above two conditional -# expressions could be shortened to: -# if /BEGIN/ .. /END/ -# and -# if firstnum .. lastnum -# but these now only work this way from the command line - -#----------------------------- - -while gets - if ~/BEGIN/ ... ~/END/ - # line falls between BEGIN and END on different lines - end -end - -while gets - if ($. == first) ... ($. == last) - # operate between first and last line number on different lines - end -end - -#----------------------------- -# command-line to print lines 15 through 17 inclusive (see below) -ruby -ne 'print if 15 .. 17' datafile - -# print out all <XMP> .. </XMP> displays from HTML doc -while gets - print if ~%r#<XMP>#i .. ~%r#</XMP>#i; -end - -# same, but as shell command -# ruby -ne 'print if %r#<XMP>#i .. %r#</XMP>#i' document.html -#----------------------------- -# ruby -ne 'BEGIN { $top=3; $bottom=5 }; \ -# print if $top .. $bottom' /etc/passwd # FAILS -# ruby -ne 'BEGIN { $top=3; $bottom=5 }; \ -# print if $. == $top .. $. == $bottom' /etc/passwd # works -# ruby -ne 'print if 3 .. 5' /etc/passwd # also works -#----------------------------- -print if ~/begin/ .. ~/end/; -print if ~/begin/ ... ~/end/; -#----------------------------- -while gets - $in_header = $. == 1 .. ~/^$/ ? true : false - $in_body = ~/^$/ .. ARGF.eof ? true : false -end -#----------------------------- -seen = {} -ARGF.each do |line| - next unless line =~ /^From:?\s/i .. line =~ /^$/; - line.scan(%r/([^<>(),;\s]+\@[^<>(),;\s]+)/).each do |addr| - puts addr unless seen[addr] - seen[addr] ||= 1 - end -end - - -# @@PLEAC@@_6.9 -def glob2pat(globstr) - patmap = { - '*' => '.*', - '?' => '.', - '[' => '[', - ']' => ']', - } - globstr.gsub!(/(.)/) { |c| patmap[c] || Regexp::escape(c) } - '^' + globstr + '$' -end - - -# @@PLEAC@@_6.10 -# avoid interpolating patterns like this if the pattern -# isn't going to change: -pattern = ARGV.shift -ARGF.each do |line| - print line if line =~ /#{pattern}/ -end - -# the above creates a new regex each iteration. Instead, -# use the /o modifier so the regex is compiled only once - -pattern = ARGV.shift -ARGF.each do |line| - print line if line =~ /#{pattern}/o -end - -#----------------------------- - -#!/usr/bin/ruby -# popgrep1 - grep for abbreviations of places that say "pop" -# version 1: slow but obvious way -popstates = %w(CO ON MI WI MN) -ARGF.each do |line| - popstates.each do |state| - if line =~ /\b#{state}\b/ - print line - last - end - end -end - -#----------------------------- -#!/usr/bin/ruby -# popgrep2 - grep for abbreviations of places that say "pop" -# version 2: eval strings; fast but hard to quote -popstates = %w(CO ON MI WI MN) -code = "ARGF.each do |line|\n" -popstates.each do |state| - code += "\tif line =~ /\\b#{state}\\b/; print(line); next; end\n" -end -code += "end\n" -print "CODE IS\n---\n#{code}\n---\n" if false # turn on for debugging -eval code - -# CODE IS -# --- -# ARGF.each do |line| -# if line =~ /\bCO\b/; print(line); next; end -# if line =~ /\bON\b/; print(line); next; end -# if line =~ /\bMI\b/; print(line); next; end -# if line =~ /\bWI\b/; print(line); next; end -# if line =~ /\bMN\b/; print(line); next; end -# end -# -# --- - -## alternatively, the same idea as above but compiling -## to a case statement: (not in perlcookbook) -#!/usr/bin/ruby -w -# popgrep2.5 - grep for abbreviations of places that say "pop" -# version 2.5: eval strings; fast but hard to quote -popstates = %w(CO ON MI WI MN) -code = "ARGF.each do |line|\n case line\n" -popstates.each do |state| - code += " when /\\b#{state}\\b/ : print line\n" -end -code += " end\nend\n" -print "CODE IS\n---\n#{code}\n---\n" if false # turn on for debugging -eval code - -# CODE IS -# --- -# ARGF.each do |line| -# case line -# when /\bCO\b/ : print line -# when /\bON\b/ : print line -# when /\bMI\b/ : print line -# when /\bWI\b/ : print line -# when /\bMN\b/ : print line -# end -# end -# -# --- - -# Note: (above) Ruby 1.8+ allows the 'when EXP : EXPR' on one line -# with the colon separator. - -#----------------------------- -#!/usr/bin/ruby -# popgrep3 - grep for abbreviations of places that say "pop" -# version3: build a match_any function -popstates = %w(CO ON MI WI MN) -expr = popstates.map{|e|"line =~ /\\b#{e}\\b/"}.join('||') -eval "def match_any(line); #{expr};end" -ARGF.each do |line| - print line if match_any(line) -end -#----------------------------- - -## building a match_all function is a trivial -## substitution of && for || -## here is a generalized example: -#!/usr/bin/ruby -w -## grepauth - print lines that mention both foo and bar -class MultiMatch - def initialize(*patterns) - _any = build_match('||',patterns) - _all = build_match('&&',patterns) - eval "def match_any(line);#{_any};end\n" - eval "def match_all(line);#{_all};end\n" - end - def build_match(sym,args) - args.map{|e|"line =~ /#{e}/"}.join(sym) - end -end - -mm = MultiMatch.new('foo','bar') -ARGF.each do |line| - print line if mm.match_all(line) -end -#----------------------------- - -#!/usr/bin/ruby -# popgrep4 - grep for abbreviations of places that say "pop" -# version4: pretty fast, but simple: compile all re's first: -popstates = %w(CO ON MI WI MN) -popstates = popstates.map{|re| %r/\b#{re}\b/} -ARGF.each do |line| - popstates.each do |state_re| - if line =~ state_re - print line - break - end - end -end - -## speeds trials on the jargon file(412): 26006 lines, 1.3MB -## popgrep1 => 7.040s -## popgrep2 => 0.656s -## popgrep2.5 => 0.633s -## popgrep3 => 0.675s -## popgrep4 => 1.027s - -# unless speed is criticial, the technique in popgrep4 is a -# reasonable balance between speed and logical simplicity. - - -# @@PLEAC@@_6.11 -begin - print "Pattern? " - pat = $stdin.gets.chomp - Regexp.new(pat) -rescue - warn "Invalid Pattern" - retry -end - - -# @@PLEAC@@_6.13 -# uses the 'amatch' extension found on: -# http://raa.ruby-lang.org/project/amatch/ -require 'amatch' -matcher = Amatch.new('balast') -#$relative, $distance = 0, 1 -File.open('/usr/share/dict/words').each_line do |line| - print line if matcher.search(line) <= 1 -end -__END__ -#CODE -ballast -ballasts -balustrade -balustrades -blast -blasted -blaster -blasters -blasting -blasts - - -# @@PLEAC@@_6.14 -str.scan(/\G(\d)/).each do |token| - puts "found #{token}" -end -#----------------------------- -n = " 49 here" -n.gsub!(/\G /,'0') -puts n -#----------------------------- -str = "3,4,5,9,120" -str.scan(/\G,?(\d+)/).each do |num| - puts "Found number: #{num}" -end -#----------------------------- -# Ruby doesn't have the String.pos or a /c re modifier like Perl -# But it does have StringScanner in the standard library (strscn) -# which allows similar functionality: - -require 'strscan' -text = 'the year 1752 lost 10 days on the 3rd of September' -sc = StringScanner.new(text) -while sc.scan(/.*?(\d+)/) - print "found: #{sc[1]}\n" -end -if sc.scan(/\S+/) - puts "Found #{sc[0]} after last number" -end -#----------------------------- -# assuming continuing from above: -puts "The position in 'text' is: #{sc.pos}" -sc.pos = 30 -puts "The position in 'text' is: #{sc.pos}" - - -# @@PLEAC@@_6.15 -#----------------------------- -# greedy pattern -str.gsub!(/<.*>/m,'') # not good - -# non-greedy (minimal) pattern -str.gsub!(/<.*?>/m,'') # not great - - -#----------------------------- -#<b><i>this</i> and <i>that</i> are important</b> Oh, <b><i>me too!</i></b> -#----------------------------- -%r{ <b><i>(.*?)</i></b> }mx -#----------------------------- -%r/BEGIN((?:(?!BEGIN).)*)END/ -#----------------------------- -%r{ <b><i>( (?: (?!</b>|</i>). )* ) </i></b> }mx -#----------------------------- -%r{ <b><i>( (?: (?!</[ib]>). )* ) </i></b> }mx -#----------------------------- -%r{ - <b><i> - [^<]* # stuff not possibly bad, and not possibly the end. - (?: - # at this point, we can have '<' if not part of something bad - (?! </?[ib]> ) # what we can't have - < # okay, so match the '<' - [^<]* # and continue with more safe stuff - ) * - </i></b> - }mx - - -# @@PLEAC@@_6.16 -#----------------------------- -$/ = "" -ARGF.each do |para| - para.scan %r/ - \b # start at word boundary - (\S+) # find chunk of non-whitespace - \b # until a word boundary - ( - \s+ # followed by whitespace - \1 # and that same chunk again - \b # and a word boundary - ) + # one or more times - /xi do - puts "dup word '#{$1}' at paragraph #{$.}" - end -end -#----------------------------- -astr = 'nobody' -bstr = 'bodysnatcher' -if "#{astr} #{bstr}" =~ /^(\w+)(\w+) \2(\w+)$/ - print "#{$2} overlaps in #{$1}-#{$2}-#{$3}" -end -#----------------------------- -#!/usr/bin/ruby -w -# prime_pattern -- find prime factors of argument using patterns -ARGV << 180 -cap = 'o' * ARGV.shift -while cap =~ /^(oo+?)\1+$/ - print $1.size, " " - cap.gsub!(/#{$1}/,'o') -end -puts cap.size -#----------------------------- -#diophantine -# solve for 12x + 15y + 16z = 281, maximizing x -if ('o' * 281).match(/^(o*)\1{11}(o*)\2{14}(o*)\3{15}$/) - x, y, z = $1.size, $2.size, $3.size - puts "One solution is: x=#{x}; y=#{y}; z=#{z}" -else - puts "No solution." -end -# => One solution is: x=17; y=3; z=2 - -#----------------------------- -# using different quantifiers: -('o' * 281).match(/^(o+)\1{11}(o+)\2{14}(o+)\3{15}$/) -# => One solution is: x=17; y=3; z=2 - -('o' * 281).match(/^(o*?)\1{11}(o*)\2{14}(o*)\3{15}$/) -# => One solution is: x=0; y=7; z=11 - -('o' * 281).match(/^(o+?)\1{11}(o*)\2{14}(o*)\3{15}$/) -# => One solution is: x=1; y=3; z=14 - - -# @@PLEAC@@_6.17 -# alpha OR beta -%r/alpha|beta/ - -# alpha AND beta -%r/(?=.*alpha)(?=.*beta)/m - -# alpha AND beta, no overlap -%r/alpha.*beta|beta.*alpha/m - -# NOT beta -%r/^(?:(?!beta).)*$/m - -# NOT bad BUT good -%r/(?=(?:(?!BAD).)*$)GOOD/m -#----------------------------- - -if !(string =~ /pattern/) # ugly - something() -end - -if string !~ /pattern/ # preferred - something() -end - - -#----------------------------- -if string =~ /pat1/ && string =~ /pat2/ - something() -end -#----------------------------- -if string =~ /pat1/ || string =~ /pat2/ - something() -end -#----------------------------- -#!/usr/bin/ruby -w -# minigrep - trivial grep -pat = ARGV.shift -ARGF.each do |line| - print line if line =~ /#{pat}/o -end -#----------------------------- - "labelled" =~ /^(?=.*bell)(?=.*lab)/m -#----------------------------- -$string =~ /bell/ && $string =~ /lab/ -#----------------------------- -$murray_hill = "blah bell blah " -if $murray_hill =~ %r{ - ^ # start of string - (?= # zero-width lookahead - .* # any amount of intervening stuff - bell # the desired bell string - ) # rewind, since we were only looking - (?= # and do the same thing - .* # any amount of intervening stuff - lab # and the lab part - ) - }mx # /m means . can match newline - - print "Looks like Bell Labs might be in Murray Hill!\n"; -end -#----------------------------- -"labelled" =~ /(?:^.*bell.*lab)|(?:^.*lab.*bell)/ -#----------------------------- -$brand = "labelled"; -if $brand =~ %r{ - (?: # non-capturing grouper - ^ .*? # any amount of stuff at the front - bell # look for a bell - .*? # followed by any amount of anything - lab # look for a lab - ) # end grouper - | # otherwise, try the other direction - (?: # non-capturing grouper - ^ .*? # any amount of stuff at the front - lab # look for a lab - .*? # followed by any amount of anything - bell # followed by a bell - ) # end grouper - }mx # /m means . can match newline - print "Our brand has bell and lab separate.\n"; -end -#----------------------------- -$map =~ /^(?:(?!waldo).)*$/s -#----------------------------- -$map = "the great baldo" -if $map =~ %r{ - ^ # start of string - (?: # non-capturing grouper - (?! # look ahead negation - waldo # is he ahead of us now? - ) # is so, the negation failed - . # any character (cuzza /s) - ) * # repeat that grouping 0 or more - $ # through the end of the string - }mx # /m means . can match newline - print "There's no waldo here!\n"; -end -=begin - 7:15am up 206 days, 13:30, 4 users, load average: 1.04, 1.07, 1.04 - -USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT - -tchrist tty1 5:16pm 36days 24:43 0.03s xinit - -tchrist tty2 5:19pm 6days 0.43s 0.43s -tcsh - -tchrist ttyp0 chthon 7:58am 3days 23.44s 0.44s -tcsh - -gnat ttyS4 coprolith 2:01pm 13:36m 0.30s 0.30s -tcsh -=end -#% w | minigrep '^(?!.*ttyp).*tchrist' -#----------------------------- -%r{ - ^ # anchored to the start - (?! # zero-width look-ahead assertion - .* # any amount of anything (faster than .*?) - ttyp # the string you don't want to find - ) # end look-ahead negation; rewind to start - .* # any amount of anything (faster than .*?) - tchrist # now try to find Tom -}x -#----------------------------- -#% w | grep tchrist | grep -v ttyp -#----------------------------- -#% grep -i 'pattern' files -#% minigrep '(?i)pattern' files -#----------------------------- - - -# @@PLEAC@@_6.20 -ans = $stdin.gets.chomp -re = %r/^#{Regexp.quote(ans)}/ -case - when "SEND" =~ re : puts "Action is send" - when "STOP" =~ re : puts "Action is stop" - when "ABORT" =~ re : puts "Action is abort" - when "EDIT" =~ re : puts "Action is edit" -end -#----------------------------- -require 'abbrev' -table = Abbrev.abbrev %w-send stop abort edit- -loop do - print "Action: " - ans = $stdin.gets.chomp - puts "Action for #{ans} is #{table[ans.downcase]}" -end - - -#----------------------------- -# dummy values are defined for 'file', 'PAGER', and -# the 'invoke_editor' and 'deliver_message' methods -# do not do anything interesting in this example. -#!/usr/bin/ruby -w -require 'abbrev' - -file = 'pleac_ruby.data' -PAGER = 'less' - -def invoke_editor - puts "invoking editor" -end - -def deliver_message - puts "delivering message" -end - -actions = { - 'edit' => self.method(:invoke_editor), - 'send' => self.method(:deliver_message), - 'list' => proc {system(PAGER, file)}, - 'abort' => proc {puts "See ya!"; exit}, - "" => proc {puts "Unknown Command"} -} - -dtable = Abbrev.abbrev(actions.keys) -loop do - print "Action: " - ans = $stdin.gets.chomp.delete(" \t") - actions[ dtable[ans.downcase] || "" ].call -end - - -# @@PLEAC@@_6.19 -#----------------------------- -# basically, the Perl Cookbook categorizes this as an -# unsolvable problem ... -#----------------------------- -1 while addr.gsub!(/\([^()]*\)/,'') -#----------------------------- -Dear someuser@host.com, - -Please confirm the mail address you gave us Wed May 6 09:38:41 -MDT 1998 by replying to this message. Include the string -"Rumpelstiltskin" in that reply, but spelled in reverse; that is, -start with "Nik...". Once this is done, your confirmed address will -be entered into our records. - - -# @@PLEAC@@_6.21 -#----------------------------- -#% gunzip -c ~/mail/archive.gz | urlify > archive.urlified -#----------------------------- -#% urlify ~/mail/*.inbox > ~/allmail.urlified -#----------------------------- -#!/usr/bin/ruby -w -# urlify - wrap HTML links around URL-like constructs - -urls = '(https?|telnet|gopher|file|wais|ftp)'; -ltrs = '\w'; -gunk = '/#~:.?+=&%@!\-'; -punc = '.:?\-'; -any = "#{ltrs}#{gunk}#{punc}"; - -ARGF.each do |line| - line.gsub! %r/ - \b # start at word boundary - ( # begin $1 { - #{urls} : # need resource and a colon - [#{any}] +? # followed by on or more - # of any valid character, but - # be conservative and take only - # what you need to.... - ) # end $1 } - (?= # look-ahead non-consumptive assertion - [#{punc}]* # either 0 or more punctuation - [^#{any}] # followed by a non-url char - | # or else - $ # then end of the string - ) - /iox do - %Q|<A HREF="#{$1}">#{$1}</A>| - end - print line -end - - -# @@PLEAC@@_6.23 -%r/^m*(d?c{0,3}|c[dm])(l?x{0,3}|x[lc])(v?i{0,3}|i[vx])$/i -#----------------------------- -str.sub!(/(\S+)(\s+)(\S+)/, '\3\2\1') -#----------------------------- -%r/(\w+)\s*=\s*(.*)\s*$/ # keyword is $1, value is $2 -#----------------------------- -%r/.{80,}/ -#----------------------------- -%r|(\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+)| -#----------------------------- -str.gsub!(%r|/usr/bin|,'/usr/local/bin') -#----------------------------- -str.gsub!(/%([0-9A-Fa-f][0-9A-Fa-f])/){ $1.hex.chr } -#----------------------------- -str.gsub!(%r{ - /\* # Match the opening delimiter - .*? # Match a minimal number of characters - \*/ # Match the closing delimiter -}xm,'') -#----------------------------- -str.sub!(/^\s+/, '') -str.sub!(/\s+$/, '') - -# but really, in Ruby we'd just do: -str.strip! -#----------------------------- -str.gsub!(/\\n/,"\n") -#----------------------------- -str.sub!(/^.*::/, '') -#----------------------------- -%r/^([01]?\d\d|2[0-4]\d|25[0-5])\.([01]?\d\d|2[0-4]\d|25[0-5])\. - ([01]?\d\d|2[0-4]\d|25[0-5])\.([01]?\d\d|2[0-4]\d|25[0-5])$/x -#----------------------------- -str.sub!(%r|^.*/|, '') -#----------------------------- -cols = ( (ENV['TERMCAP'] || " ") =~ /:co#(\d+):/ ) ? $1 : 80; -#----------------------------- -name = " #{$0} #{ARGV}".gsub(%r| /\S+/|, ' ') -#----------------------------- -require 'rbconfig' -include Config -raise "This isn't Linux" unless CONFIG['target_os'] =~ /linux/i; -#----------------------------- -str.gsub!(%r/\n\s+/, ' ') -#----------------------------- -nums = str.scan(/(\d+\.?\d*|\.\d+)/) -#----------------------------- -capwords = str.scan(%r/(\b[^\Wa-z0-9_]+\b)/) -#----------------------------- -lowords = str.scan(%r/(\b[^\WA-Z0-9_]+\b)/) -#----------------------------- -icwords = str.scan(%r/(\b[^\Wa-z0-9_][^\WA-Z0-9_]*\b)/) -#----------------------------- -links = str.scan(%r/<A[^>]+?HREF\s*=\s*["']?([^'" >]+?)[ '"]?>/mi) -#----------------------------- -initial = str =~ /^\S+\s+(\S)\S*\s+\S/ ? $1 : "" -#----------------------------- -str.gsub!(%r/"([^"]*)"/, %q-``\1''-) -#----------------------------- - -$/ = "" -sentences = [] -ARGF.each do |para| - para.gsub!(/\n/, ' ') - para.gsub!(/ {3,}/,' ') - sentences << para.scan(/(\S.*?[!?.])(?= |\Z)/) -end - -#----------------------------- -%r/(\d{4})-(\d\d)-(\d\d)/ # YYYY in $1, MM in $2, DD in $3 -#----------------------------- -%r/ ^ - (?: - 1 \s (?: \d\d\d \s)? # 1, or 1 and area code - | # ... or ... - \(\d\d\d\) \s # area code with parens - | # ... or ... - (?: \+\d\d?\d? \s)? # optional +country code - \d\d\d ([\s\-]) # and area code - ) - \d\d\d (\s|\1) # prefix (and area code separator) - \d\d\d\d # exchange - $ - /x -#----------------------------- -%r/\boh\s+my\s+gh?o(d(dess(es)?|s?)|odness|sh)\b/i -#----------------------------- -lines = [] -lines << $1 while input.sub!(/^([^\012\015]*)(\012\015?|\015\012?)/,'') - - -# @@PLEAC@@_7.0 -# An IO object being Enumerable, we can use 'each' directly on it -File.open("/usr/local/widgets/data").each { |line| - puts line if line =~ /blue/ -} - -logfile = File.new("/var/log/rubylog.txt", "w") -mysub($stdin, logfile) - -# The method IO#readline is similar to IO#gets -# but throws an exception when it reaches EOF -f = File.new("bla.txt") -begin - while (line = f.readline) - line.chomp - $stdout.print line if line =~ /blue/ - end -rescue EOFError - f.close -end - -while $stdin.gets # reads from STDIN - unless (/\d/) - $stderr.puts "No digit found." # writes to STDERR - end - puts "Read: #{$_}" # writes to STDOUT -end - -logfile = File.new("/tmp/log", "w") - -logfile.close - -# $defout (or its synonym '$>') is the destination of output -# for Kernel#print, Kernel#puts, and family functions -logfile = File.new("log.txt", "w") -old = $defout -$defout = logfile # switch to logfile for output -puts "Countdown initiated ..." -$defout = old # return to original output -puts "You have 30 seconds to reach minimum safety distance." - - -# @@PLEAC@@_7.1 -source = File.new(path, "r") # open file "path" for reading only -sink = File.new(path, "w") # open file "path" for writing only - -source = File.open(path, File::RDONLY) # open file "path" for reading only -sink = File.open(path, File::WRONLY) # open file "path" for writing only - -file = File.open(path, "r+") # open "path" for reading and writing -file = File.open(path, flags) # open "path" with the flags "flags" (see examples below for flags) - -# open file "path" read only -file = File.open(path, "r") -file = File.open(path, File::RDONLY) - -# open file "path" write only, create it if it does not exist -# truncate it to zero length if it exists -file = File.open(path, "w") -file = File.open(path, File::WRONLY|File::TRUNC|File::CREAT) -file = File.open(path, File::WRONLY|File::TRUNC|File::CREAT, 0666) # with permission 0666 - -# open file "path" write only, fails if file exists -file = File.open(path, File::WRONLY|File::EXCL|File::CREAT) -file = File.open(path, File::WRONLY|File::EXCL|File::CREAT, 0666) - -# open file "path" for appending -file = File.open(path, "a") -file = File.open(path, File::WRONLY|File::APPEND|File::CREAT) -file = File.open(path, File::WRONLY|File::APPEND|File::CREAT, 0666) - -# open file "path" for appending only when file exists -file = File.open(path, File::WRONLY|File::APPEND) - -# open file "path" for reading and writing -file = File.open(path, "r+") -file = File.open(path, File::RDWR) - -# open file for reading and writing, create a new file if it does not exist -file = File.open(path, File::RDWR|File::CREAT) -file = File.open(path, File::RDWR|File::CREAT, 0600) - -# open file "path" reading and writing, fails if file exists -file = File.open(path, File::RDWR|File::EXCL|File::CREAT) -file = File.open(path, File::RDWR|File::EXCL|File::CREAT, 0600) - - -# @@PLEAC@@_7.2 -# No problem with Ruby since the filename doesn't contain characters with -# special meaning; like Perl's sysopen -File.open(filename, 'r') - - -# @@PLEAC@@_7.3 -File.expand_path('~root/tmp') -#=> "/root/tmp" -File.expand_path('~rpcuser') -#=> "/var/lib/nfs" - -# To expand ~/.. it explicitely needs the environment variable HOME -File.expand_path('~/tmp') -#=> "/home/gc/tmp" - - -# @@PLEAC@@_7.4 -# The exception raised in Ruby reports the filename -File.open('afile') - - -# @@PLEAC@@_7.5 -# Standard Ruby distribution provides the following useful extension -require 'tempfile' -# With the Tempfile class, the file is automatically deleted on garbage -# collection, so you won't need to remove it, later on. -tf = Tempfile.new('tmp') # a name is required to create the filename - -# If you need to pass the filename to an external program you can use -# File#path, but don't forget to File#flush in order to flush anything -# living in some buffer somewhere. -tf.flush -system("/usr/bin/dowhatever #{tf.path}") - -fh = Tempfile.new('tmp') -fh.sync = true # autoflushes -10.times { |i| fh.puts i } -fh.rewind -puts 'Tmp file has: ', fh.readlines - - -# @@PLEAC@@_7.6 -while (DATA.gets) do - # process the line -end -__END__ -# your data goes here -# __DATA__ doesn't exist in Ruby - -#CODE -# get info about the script (size, date of last modification) -kilosize = DATA.stat.size / 1024 -last_modif = DATA.stat.mtime -puts "<P>Script size is #{kilosize}" -puts "<P>Last script update: #{last_modif}" -__END__ -# DO NOT REMOVE THE PRECEEDING LINE. -# Everything else in this file will be ignored. -#CODE - - -# @@PLEAC@@_7.7 -while line = gets do - # do something with line. -end - -# or -while gets do - # do something with $_ -end - -# or more rubyish -$stdun.each do |line| - # do stuff with line -end - - -# ARGF may makes this more easy -# this is skipped if ARGV.size==0 -ARGV.each do |filename| - # closing and exception handling are done by the block - open(filename) do |fd| - fd.each do |line| - # do stuff with line - end - end rescue abort("can't open %s" % filename) -end - -# globbing is done in the Dir module -ARGV = Dir["*.[Cch]"] if ARGV.empty? - -# note: optparse is the preferred way to handle this -if (ARGV[0] == '-c') - chop_first += 1 - ARGV.shift -end - - -# processing numerical options -if ARGV[0] =~ /^-(\d+)$/ - columns = $1 - ARGV.shift -end - -# again, better to use optparse: -require 'optparse' -nostdout = 0 -append = 0 -unbuffer = 0 -ignore_ints = 0 -ARGV.options do |opt| - opt.on('-n') { nostdout +=1 } - opt.on('-a') { append +=1 } - opt.on('-u') { unbuffer +=1 } - opt.on('-i') { ignore_ints +=1 } - opt.parse! -end or abort("usage: " + __FILE__ + " [-ainu] [filenames]") - -# no need to do undef $/, we have File.read -str = File.read(ARGV[0]) - -# again we have File.read -str = File.read(ARGV[0]) - -# not sure what this should do: -# I believe open the file, print filename, lineno and line: -ARGF.each_with_index do |line, idx| - print ARGF.filename, ":", idx, ";", line -end - -# print all the lines in every file passed via command line that contains login -ARGF.each do |line| - puts line if line =~ /login/ -end -# -# even this would fit -#%ruby -ne "print if /f/" 2.log -# - -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 - diff --git a/tests/examplefiles/ltmain.sh b/tests/examplefiles/ltmain.sh index 8f7a6ac1..5b5f845f 100644 --- a/tests/examplefiles/ltmain.sh +++ b/tests/examplefiles/ltmain.sh @@ -2847,4125 +2847,3 @@ EOF # We're trying link a shared library against a static one # but the system doesn't support it. - # Just print a warning and add the library to dependency_libs so - # that the program can be linked against the static library. - $echo - $echo "*** Warning: This system can not link to static lib archive $lib." - $echo "*** I have the capability to make that library automatically link in when" - $echo "*** you link to this library. But I can only do this if you have a" - $echo "*** shared version of the library, which you do not appear to have." - if test "$module" = yes; then - $echo "*** But as you try to build a module library, libtool will still create " - $echo "*** a static module, that should work as long as the dlopening application" - $echo "*** is linked with the -dlopen flag to resolve symbols at runtime." - if test -z "$global_symbol_pipe"; then - $echo - $echo "*** However, this would only work if libtool was able to extract symbol" - $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" - $echo "*** not find such a program. So, this module is probably useless." - $echo "*** \`nm' from GNU binutils and a full rebuild may help." - fi - if test "$build_old_libs" = no; then - build_libtool_libs=module - build_old_libs=yes - else - build_libtool_libs=no - fi - fi - else - deplibs="$dir/$old_library $deplibs" - link_static=yes - fi - fi # link shared/static library? - - if test "$linkmode" = lib; then - if test -n "$dependency_libs" && - { test "$hardcode_into_libs" != yes || - test "$build_old_libs" = yes || - test "$link_static" = yes; }; then - # Extract -R from dependency_libs - temp_deplibs= - for libdir in $dependency_libs; do - case $libdir in - -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` - case " $xrpath " in - *" $temp_xrpath "*) ;; - *) xrpath="$xrpath $temp_xrpath";; - esac;; - *) temp_deplibs="$temp_deplibs $libdir";; - esac - done - dependency_libs="$temp_deplibs" - fi - - newlib_search_path="$newlib_search_path $absdir" - # Link against this library - test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" - # ... and its dependency_libs - tmp_libs= - for deplib in $dependency_libs; do - newdependency_libs="$deplib $newdependency_libs" - if test "X$duplicate_deps" = "Xyes" ; then - case "$tmp_libs " in - *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; - esac - fi - tmp_libs="$tmp_libs $deplib" - done - - if test "$link_all_deplibs" != no; then - # Add the search paths of all dependency libraries - for deplib in $dependency_libs; do - case $deplib in - -L*) path="$deplib" ;; - *.la) - dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` - test "X$dir" = "X$deplib" && dir="." - # We need an absolute path. - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; - *) - absdir=`cd "$dir" && pwd` - if test -z "$absdir"; then - $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 - absdir="$dir" - fi - ;; - esac - if grep "^installed=no" $deplib > /dev/null; then - path="$absdir/$objdir" - else - eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` - if test -z "$libdir"; then - $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 - exit $EXIT_FAILURE - fi - if test "$absdir" != "$libdir"; then - $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 - fi - path="$absdir" - fi - depdepl= - case $host in - *-*-darwin*) - # we do not want to link against static libs, - # but need to link against shared - eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` - if test -n "$deplibrary_names" ; then - for tmp in $deplibrary_names ; do - depdepl=$tmp - done - if test -f "$path/$depdepl" ; then - depdepl="$path/$depdepl" - fi - # do not add paths which are already there - case " $newlib_search_path " in - *" $path "*) ;; - *) newlib_search_path="$newlib_search_path $path";; - esac - fi - path="" - ;; - *) - path="-L$path" - ;; - esac - ;; - -l*) - case $host in - *-*-darwin*) - # Again, we only want to link against shared libraries - eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"` - for tmp in $newlib_search_path ; do - if test -f "$tmp/lib$tmp_libs.dylib" ; then - eval depdepl="$tmp/lib$tmp_libs.dylib" - break - fi - done - path="" - ;; - *) continue ;; - esac - ;; - *) continue ;; - esac - case " $deplibs " in - *" $path "*) ;; - *) deplibs="$path $deplibs" ;; - esac - case " $deplibs " in - *" $depdepl "*) ;; - *) deplibs="$depdepl $deplibs" ;; - esac - done - fi # link_all_deplibs != no - fi # linkmode = lib - done # for deplib in $libs - dependency_libs="$newdependency_libs" - if test "$pass" = dlpreopen; then - # Link the dlpreopened libraries before other libraries - for deplib in $save_deplibs; do - deplibs="$deplib $deplibs" - done - fi - if test "$pass" != dlopen; then - if test "$pass" != conv; then - # Make sure lib_search_path contains only unique directories. - lib_search_path= - for dir in $newlib_search_path; do - case "$lib_search_path " in - *" $dir "*) ;; - *) lib_search_path="$lib_search_path $dir" ;; - esac - done - newlib_search_path= - fi - - if test "$linkmode,$pass" != "prog,link"; then - vars="deplibs" - else - vars="compile_deplibs finalize_deplibs" - fi - for var in $vars dependency_libs; do - # Add libraries to $var in reverse order - eval tmp_libs=\"\$$var\" - new_libs= - for deplib in $tmp_libs; do - # FIXME: Pedantically, this is the right thing to do, so - # that some nasty dependency loop isn't accidentally - # broken: - #new_libs="$deplib $new_libs" - # Pragmatically, this seems to cause very few problems in - # practice: - case $deplib in - -L*) new_libs="$deplib $new_libs" ;; - -R*) ;; - *) - # And here is the reason: when a library appears more - # than once as an explicit dependence of a library, or - # is implicitly linked in more than once by the - # compiler, it is considered special, and multiple - # occurrences thereof are not removed. Compare this - # with having the same library being listed as a - # dependency of multiple other libraries: in this case, - # we know (pedantically, we assume) the library does not - # need to be listed more than once, so we keep only the - # last copy. This is not always right, but it is rare - # enough that we require users that really mean to play - # such unportable linking tricks to link the library - # using -Wl,-lname, so that libtool does not consider it - # for duplicate removal. - case " $specialdeplibs " in - *" $deplib "*) new_libs="$deplib $new_libs" ;; - *) - case " $new_libs " in - *" $deplib "*) ;; - *) new_libs="$deplib $new_libs" ;; - esac - ;; - esac - ;; - esac - done - tmp_libs= - for deplib in $new_libs; do - case $deplib in - -L*) - case " $tmp_libs " in - *" $deplib "*) ;; - *) tmp_libs="$tmp_libs $deplib" ;; - esac - ;; - *) tmp_libs="$tmp_libs $deplib" ;; - esac - done - eval $var=\"$tmp_libs\" - done # for var - fi - # Last step: remove runtime libs from dependency_libs - # (they stay in deplibs) - tmp_libs= - for i in $dependency_libs ; do - case " $predeps $postdeps $compiler_lib_search_path " in - *" $i "*) - i="" - ;; - esac - if test -n "$i" ; then - tmp_libs="$tmp_libs $i" - fi - done - dependency_libs=$tmp_libs - done # for pass - if test "$linkmode" = prog; then - dlfiles="$newdlfiles" - dlprefiles="$newdlprefiles" - fi - - case $linkmode in - oldlib) - if test -n "$deplibs"; then - $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 - fi - - if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then - $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 - fi - - if test -n "$rpath"; then - $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 - fi - - if test -n "$xrpath"; then - $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 - fi - - if test -n "$vinfo"; then - $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2 - fi - - if test -n "$release"; then - $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 - fi - - if test -n "$export_symbols" || test -n "$export_symbols_regex"; then - $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 - fi - - # Now set the variables for building old libraries. - build_libtool_libs=no - oldlibs="$output" - objs="$objs$old_deplibs" - ;; - - lib) - # Make sure we only generate libraries of the form `libNAME.la'. - case $outputname in - lib*) - name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` - eval shared_ext=\"$shrext_cmds\" - eval libname=\"$libname_spec\" - ;; - *) - if test "$module" = no; then - $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - if test "$need_lib_prefix" != no; then - # Add the "lib" prefix for modules if required - name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` - eval shared_ext=\"$shrext_cmds\" - eval libname=\"$libname_spec\" - else - libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` - fi - ;; - esac - - if test -n "$objs"; then - if test "$deplibs_check_method" != pass_all; then - $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 - exit $EXIT_FAILURE - else - $echo - $echo "*** Warning: Linking the shared library $output against the non-libtool" - $echo "*** objects $objs is not portable!" - libobjs="$libobjs $objs" - fi - fi - - if test "$dlself" != no; then - $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 - fi - - set dummy $rpath - if test "$#" -gt 2; then - $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 - fi - install_libdir="$2" - - oldlibs= - if test -z "$rpath"; then - if test "$build_libtool_libs" = yes; then - # Building a libtool convenience library. - # Some compilers have problems with a `.al' extension so - # convenience libraries should have the same extension an - # archive normally would. - oldlibs="$output_objdir/$libname.$libext $oldlibs" - build_libtool_libs=convenience - build_old_libs=yes - fi - - if test -n "$vinfo"; then - $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2 - fi - - if test -n "$release"; then - $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 - fi - else - - # Parse the version information argument. - save_ifs="$IFS"; IFS=':' - set dummy $vinfo 0 0 0 - IFS="$save_ifs" - - if test -n "$8"; then - $echo "$modename: too many parameters to \`-version-info'" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - - # convert absolute version numbers to libtool ages - # this retains compatibility with .la files and attempts - # to make the code below a bit more comprehensible - - case $vinfo_number in - yes) - number_major="$2" - number_minor="$3" - number_revision="$4" - # - # There are really only two kinds -- those that - # use the current revision as the major version - # and those that subtract age and use age as - # a minor version. But, then there is irix - # which has an extra 1 added just for fun - # - case $version_type in - darwin|linux|osf|windows) - current=`expr $number_major + $number_minor` - age="$number_minor" - revision="$number_revision" - ;; - freebsd-aout|freebsd-elf|sunos) - current="$number_major" - revision="$number_minor" - age="0" - ;; - irix|nonstopux) - current=`expr $number_major + $number_minor - 1` - age="$number_minor" - revision="$number_minor" - ;; - esac - ;; - no) - current="$2" - revision="$3" - age="$4" - ;; - esac - - # Check that each of the things are valid numbers. - case $current in - 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; - *) - $echo "$modename: CURRENT \`$current' must be a nonnegative integer" 1>&2 - $echo "$modename: \`$vinfo' is not valid version information" 1>&2 - exit $EXIT_FAILURE - ;; - esac - - case $revision in - 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; - *) - $echo "$modename: REVISION \`$revision' must be a nonnegative integer" 1>&2 - $echo "$modename: \`$vinfo' is not valid version information" 1>&2 - exit $EXIT_FAILURE - ;; - esac - - case $age in - 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; - *) - $echo "$modename: AGE \`$age' must be a nonnegative integer" 1>&2 - $echo "$modename: \`$vinfo' is not valid version information" 1>&2 - exit $EXIT_FAILURE - ;; - esac - - if test "$age" -gt "$current"; then - $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 - $echo "$modename: \`$vinfo' is not valid version information" 1>&2 - exit $EXIT_FAILURE - fi - - # Calculate the version variables. - major= - versuffix= - verstring= - case $version_type in - none) ;; - - darwin) - # Like Linux, but with the current version available in - # verstring for coding it into the library header - major=.`expr $current - $age` - versuffix="$major.$age.$revision" - # Darwin ld doesn't like 0 for these options... - minor_current=`expr $current + 1` - verstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" - ;; - - freebsd-aout) - major=".$current" - versuffix=".$current.$revision"; - ;; - - freebsd-elf) - major=".$current" - versuffix=".$current"; - ;; - - irix | nonstopux) - major=`expr $current - $age + 1` - - case $version_type in - nonstopux) verstring_prefix=nonstopux ;; - *) verstring_prefix=sgi ;; - esac - verstring="$verstring_prefix$major.$revision" - - # Add in all the interfaces that we are compatible with. - loop=$revision - while test "$loop" -ne 0; do - iface=`expr $revision - $loop` - loop=`expr $loop - 1` - verstring="$verstring_prefix$major.$iface:$verstring" - done - - # Before this point, $major must not contain `.'. - major=.$major - versuffix="$major.$revision" - ;; - - linux) - major=.`expr $current - $age` - versuffix="$major.$age.$revision" - ;; - - osf) - major=.`expr $current - $age` - versuffix=".$current.$age.$revision" - verstring="$current.$age.$revision" - - # Add in all the interfaces that we are compatible with. - loop=$age - while test "$loop" -ne 0; do - iface=`expr $current - $loop` - loop=`expr $loop - 1` - verstring="$verstring:${iface}.0" - done - - # Make executables depend on our current version. - verstring="$verstring:${current}.0" - ;; - - sunos) - major=".$current" - versuffix=".$current.$revision" - ;; - - windows) - # Use '-' rather than '.', since we only want one - # extension on DOS 8.3 filesystems. - major=`expr $current - $age` - versuffix="-$major" - ;; - - *) - $echo "$modename: unknown library version type \`$version_type'" 1>&2 - $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 - exit $EXIT_FAILURE - ;; - esac - - # Clear the version info if we defaulted, and they specified a release. - if test -z "$vinfo" && test -n "$release"; then - major= - case $version_type in - darwin) - # we can't check for "0.0" in archive_cmds due to quoting - # problems, so we reset it completely - verstring= - ;; - *) - verstring="0.0" - ;; - esac - if test "$need_version" = no; then - versuffix= - else - versuffix=".0.0" - fi - fi - - # Remove version info from name if versioning should be avoided - if test "$avoid_version" = yes && test "$need_version" = no; then - major= - versuffix= - verstring="" - fi - - # Check to see if the archive will have undefined symbols. - if test "$allow_undefined" = yes; then - if test "$allow_undefined_flag" = unsupported; then - $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 - build_libtool_libs=no - build_old_libs=yes - fi - else - # Don't allow undefined symbols. - allow_undefined_flag="$no_undefined_flag" - fi - fi - - if test "$mode" != relink; then - # Remove our outputs, but don't remove object files since they - # may have been created when compiling PIC objects. - removelist= - tempremovelist=`$echo "$output_objdir/*"` - for p in $tempremovelist; do - case $p in - *.$objext) - ;; - $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) - if test "X$precious_files_regex" != "X"; then - if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 - then - continue - fi - fi - removelist="$removelist $p" - ;; - *) ;; - esac - done - if test -n "$removelist"; then - $show "${rm}r $removelist" - $run ${rm}r $removelist - fi - fi - - # Now set the variables for building old libraries. - if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then - oldlibs="$oldlibs $output_objdir/$libname.$libext" - - # Transform .lo files to .o files. - oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` - fi - - # Eliminate all temporary directories. - for path in $notinst_path; do - lib_search_path=`$echo "$lib_search_path " | ${SED} -e "s% $path % %g"` - deplibs=`$echo "$deplibs " | ${SED} -e "s% -L$path % %g"` - dependency_libs=`$echo "$dependency_libs " | ${SED} -e "s% -L$path % %g"` - done - - if test -n "$xrpath"; then - # If the user specified any rpath flags, then add them. - temp_xrpath= - for libdir in $xrpath; do - temp_xrpath="$temp_xrpath -R$libdir" - case "$finalize_rpath " in - *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" ;; - esac - done - if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then - dependency_libs="$temp_xrpath $dependency_libs" - fi - fi - - # Make sure dlfiles contains only unique files that won't be dlpreopened - old_dlfiles="$dlfiles" - dlfiles= - for lib in $old_dlfiles; do - case " $dlprefiles $dlfiles " in - *" $lib "*) ;; - *) dlfiles="$dlfiles $lib" ;; - esac - done - - # Make sure dlprefiles contains only unique files - old_dlprefiles="$dlprefiles" - dlprefiles= - for lib in $old_dlprefiles; do - case "$dlprefiles " in - *" $lib "*) ;; - *) dlprefiles="$dlprefiles $lib" ;; - esac - done - - if test "$build_libtool_libs" = yes; then - if test -n "$rpath"; then - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) - # these systems don't actually have a c library (as such)! - ;; - *-*-rhapsody* | *-*-darwin1.[012]) - # Rhapsody C library is in the System framework - deplibs="$deplibs -framework System" - ;; - *-*-netbsd*) - # Don't link with libc until the a.out ld.so is fixed. - ;; - *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) - # Do not include libc due to us having libc/libc_r. - ;; - *-*-sco3.2v5* | *-*-sco5v6*) - # Causes problems with __ctype - ;; - *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) - # Compiler inserts libc in the correct place for threads to work - ;; - *) - # Add libc to deplibs on all other systems if necessary. - if test "$build_libtool_need_lc" = "yes"; then - deplibs="$deplibs -lc" - fi - ;; - esac - fi - - # Transform deplibs into only deplibs that can be linked in shared. - name_save=$name - libname_save=$libname - release_save=$release - versuffix_save=$versuffix - major_save=$major - # I'm not sure if I'm treating the release correctly. I think - # release should show up in the -l (ie -lgmp5) so we don't want to - # add it in twice. Is that correct? - release="" - versuffix="" - major="" - newdeplibs= - droppeddeps=no - case $deplibs_check_method in - pass_all) - # Don't check for shared/static. Everything works. - # This might be a little naive. We might want to check - # whether the library exists or not. But this is on - # osf3 & osf4 and I'm not really sure... Just - # implementing what was already the behavior. - newdeplibs=$deplibs - ;; - test_compile) - # This code stresses the "libraries are programs" paradigm to its - # limits. Maybe even breaks it. We compile a program, linking it - # against the deplibs as a proxy for the library. Then we can check - # whether they linked in statically or dynamically with ldd. - $rm conftest.c - cat > conftest.c <<EOF - int main() { return 0; } -EOF - $rm conftest - $LTCC $LTCFLAGS -o conftest conftest.c $deplibs - if test "$?" -eq 0 ; then - ldd_output=`ldd conftest` - for i in $deplibs; do - name=`expr $i : '-l\(.*\)'` - # If $name is empty we are operating on a -L argument. - if test "$name" != "" && test "$name" -ne "0"; then - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - case " $predeps $postdeps " in - *" $i "*) - newdeplibs="$newdeplibs $i" - i="" - ;; - esac - fi - if test -n "$i" ; then - libname=`eval \\$echo \"$libname_spec\"` - deplib_matches=`eval \\$echo \"$library_names_spec\"` - set dummy $deplib_matches - deplib_match=$2 - if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then - newdeplibs="$newdeplibs $i" - else - droppeddeps=yes - $echo - $echo "*** Warning: dynamic linker does not accept needed library $i." - $echo "*** I have the capability to make that library automatically link in when" - $echo "*** you link to this library. But I can only do this if you have a" - $echo "*** shared version of the library, which I believe you do not have" - $echo "*** because a test_compile did reveal that the linker did not use it for" - $echo "*** its dynamic dependency list that programs get resolved with at runtime." - fi - fi - else - newdeplibs="$newdeplibs $i" - fi - done - else - # Error occurred in the first compile. Let's try to salvage - # the situation: Compile a separate program for each library. - for i in $deplibs; do - name=`expr $i : '-l\(.*\)'` - # If $name is empty we are operating on a -L argument. - if test "$name" != "" && test "$name" != "0"; then - $rm conftest - $LTCC $LTCFLAGS -o conftest conftest.c $i - # Did it work? - if test "$?" -eq 0 ; then - ldd_output=`ldd conftest` - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - case " $predeps $postdeps " in - *" $i "*) - newdeplibs="$newdeplibs $i" - i="" - ;; - esac - fi - if test -n "$i" ; then - libname=`eval \\$echo \"$libname_spec\"` - deplib_matches=`eval \\$echo \"$library_names_spec\"` - set dummy $deplib_matches - deplib_match=$2 - if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then - newdeplibs="$newdeplibs $i" - else - droppeddeps=yes - $echo - $echo "*** Warning: dynamic linker does not accept needed library $i." - $echo "*** I have the capability to make that library automatically link in when" - $echo "*** you link to this library. But I can only do this if you have a" - $echo "*** shared version of the library, which you do not appear to have" - $echo "*** because a test_compile did reveal that the linker did not use this one" - $echo "*** as a dynamic dependency that programs can get resolved with at runtime." - fi - fi - else - droppeddeps=yes - $echo - $echo "*** Warning! Library $i is needed by this library but I was not able to" - $echo "*** make it link in! You will probably need to install it or some" - $echo "*** library that it depends on before this library will be fully" - $echo "*** functional. Installing it before continuing would be even better." - fi - else - newdeplibs="$newdeplibs $i" - fi - done - fi - ;; - file_magic*) - set dummy $deplibs_check_method - file_magic_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` - for a_deplib in $deplibs; do - name=`expr $a_deplib : '-l\(.*\)'` - # If $name is empty we are operating on a -L argument. - if test "$name" != "" && test "$name" != "0"; then - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - case " $predeps $postdeps " in - *" $a_deplib "*) - newdeplibs="$newdeplibs $a_deplib" - a_deplib="" - ;; - esac - fi - if test -n "$a_deplib" ; then - libname=`eval \\$echo \"$libname_spec\"` - for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do - potential_libs=`ls $i/$libname[.-]* 2>/dev/null` - for potent_lib in $potential_libs; do - # Follow soft links. - if ls -lLd "$potent_lib" 2>/dev/null \ - | grep " -> " >/dev/null; then - continue - fi - # The statement above tries to avoid entering an - # endless loop below, in case of cyclic links. - # We might still enter an endless loop, since a link - # loop can be closed while we follow links, - # but so what? - potlib="$potent_lib" - while test -h "$potlib" 2>/dev/null; do - potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` - case $potliblink in - [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; - *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; - esac - done - # It is ok to link against an archive when - # building a shared library. - if $AR -t $potlib > /dev/null 2>&1; then - newdeplibs="$newdeplibs $a_deplib" - a_deplib="" - break 2 - fi - if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ - | ${SED} 10q \ - | $EGREP "$file_magic_regex" > /dev/null; then - newdeplibs="$newdeplibs $a_deplib" - a_deplib="" - break 2 - fi - done - done - fi - if test -n "$a_deplib" ; then - droppeddeps=yes - $echo - $echo "*** Warning: linker path does not have real file for library $a_deplib." - $echo "*** I have the capability to make that library automatically link in when" - $echo "*** you link to this library. But I can only do this if you have a" - $echo "*** shared version of the library, which you do not appear to have" - $echo "*** because I did check the linker path looking for a file starting" - if test -z "$potlib" ; then - $echo "*** with $libname but no candidates were found. (...for file magic test)" - else - $echo "*** with $libname and none of the candidates passed a file format test" - $echo "*** using a file magic. Last file checked: $potlib" - fi - fi - else - # Add a -L argument. - newdeplibs="$newdeplibs $a_deplib" - fi - done # Gone through all deplibs. - ;; - match_pattern*) - set dummy $deplibs_check_method - match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` - for a_deplib in $deplibs; do - name=`expr $a_deplib : '-l\(.*\)'` - # If $name is empty we are operating on a -L argument. - if test -n "$name" && test "$name" != "0"; then - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - case " $predeps $postdeps " in - *" $a_deplib "*) - newdeplibs="$newdeplibs $a_deplib" - a_deplib="" - ;; - esac - fi - if test -n "$a_deplib" ; then - libname=`eval \\$echo \"$libname_spec\"` - for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do - potential_libs=`ls $i/$libname[.-]* 2>/dev/null` - for potent_lib in $potential_libs; do - potlib="$potent_lib" # see symlink-check above in file_magic test - if eval $echo \"$potent_lib\" 2>/dev/null \ - | ${SED} 10q \ - | $EGREP "$match_pattern_regex" > /dev/null; then - newdeplibs="$newdeplibs $a_deplib" - a_deplib="" - break 2 - fi - done - done - fi - if test -n "$a_deplib" ; then - droppeddeps=yes - $echo - $echo "*** Warning: linker path does not have real file for library $a_deplib." - $echo "*** I have the capability to make that library automatically link in when" - $echo "*** you link to this library. But I can only do this if you have a" - $echo "*** shared version of the library, which you do not appear to have" - $echo "*** because I did check the linker path looking for a file starting" - if test -z "$potlib" ; then - $echo "*** with $libname but no candidates were found. (...for regex pattern test)" - else - $echo "*** with $libname and none of the candidates passed a file format test" - $echo "*** using a regex pattern. Last file checked: $potlib" - fi - fi - else - # Add a -L argument. - newdeplibs="$newdeplibs $a_deplib" - fi - done # Gone through all deplibs. - ;; - none | unknown | *) - newdeplibs="" - tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ - -e 's/ -[LR][^ ]*//g'` - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - for i in $predeps $postdeps ; do - # can't use Xsed below, because $i might contain '/' - tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"` - done - fi - if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \ - | grep . >/dev/null; then - $echo - if test "X$deplibs_check_method" = "Xnone"; then - $echo "*** Warning: inter-library dependencies are not supported in this platform." - else - $echo "*** Warning: inter-library dependencies are not known to be supported." - fi - $echo "*** All declared inter-library dependencies are being dropped." - droppeddeps=yes - fi - ;; - esac - versuffix=$versuffix_save - major=$major_save - release=$release_save - libname=$libname_save - name=$name_save - - case $host in - *-*-rhapsody* | *-*-darwin1.[012]) - # On Rhapsody replace the C library is the System framework - newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` - ;; - esac - - if test "$droppeddeps" = yes; then - if test "$module" = yes; then - $echo - $echo "*** Warning: libtool could not satisfy all declared inter-library" - $echo "*** dependencies of module $libname. Therefore, libtool will create" - $echo "*** a static module, that should work as long as the dlopening" - $echo "*** application is linked with the -dlopen flag." - if test -z "$global_symbol_pipe"; then - $echo - $echo "*** However, this would only work if libtool was able to extract symbol" - $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" - $echo "*** not find such a program. So, this module is probably useless." - $echo "*** \`nm' from GNU binutils and a full rebuild may help." - fi - if test "$build_old_libs" = no; then - oldlibs="$output_objdir/$libname.$libext" - build_libtool_libs=module - build_old_libs=yes - else - build_libtool_libs=no - fi - else - $echo "*** The inter-library dependencies that have been dropped here will be" - $echo "*** automatically added whenever a program is linked with this library" - $echo "*** or is declared to -dlopen it." - - if test "$allow_undefined" = no; then - $echo - $echo "*** Since this library must not contain undefined symbols," - $echo "*** because either the platform does not support them or" - $echo "*** it was explicitly requested with -no-undefined," - $echo "*** libtool will only create a static version of it." - if test "$build_old_libs" = no; then - oldlibs="$output_objdir/$libname.$libext" - build_libtool_libs=module - build_old_libs=yes - else - build_libtool_libs=no - fi - fi - fi - fi - # Done checking deplibs! - deplibs=$newdeplibs - fi - - - # move library search paths that coincide with paths to not yet - # installed libraries to the beginning of the library search list - new_libs= - for path in $notinst_path; do - case " $new_libs " in - *" -L$path/$objdir "*) ;; - *) - case " $deplibs " in - *" -L$path/$objdir "*) - new_libs="$new_libs -L$path/$objdir" ;; - esac - ;; - esac - done - for deplib in $deplibs; do - case $deplib in - -L*) - case " $new_libs " in - *" $deplib "*) ;; - *) new_libs="$new_libs $deplib" ;; - esac - ;; - *) new_libs="$new_libs $deplib" ;; - esac - done - deplibs="$new_libs" - - - # All the library-specific variables (install_libdir is set above). - library_names= - old_library= - dlname= - - # Test again, we may have decided not to build it any more - if test "$build_libtool_libs" = yes; then - if test "$hardcode_into_libs" = yes; then - # Hardcode the library paths - hardcode_libdirs= - dep_rpath= - rpath="$finalize_rpath" - test "$mode" != relink && rpath="$compile_rpath$rpath" - for libdir in $rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - if test -z "$hardcode_libdirs"; then - hardcode_libdirs="$libdir" - else - # Just accumulate the unique libdirs. - case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval flag=\"$hardcode_libdir_flag_spec\" - dep_rpath="$dep_rpath $flag" - fi - elif test -n "$runpath_var"; then - case "$perm_rpath " in - *" $libdir "*) ;; - *) perm_rpath="$perm_rpath $libdir" ;; - esac - fi - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir="$hardcode_libdirs" - if test -n "$hardcode_libdir_flag_spec_ld"; then - eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" - else - eval dep_rpath=\"$hardcode_libdir_flag_spec\" - fi - fi - if test -n "$runpath_var" && test -n "$perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $perm_rpath; do - rpath="$rpath$dir:" - done - eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" - fi - test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" - fi - - shlibpath="$finalize_shlibpath" - test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" - if test -n "$shlibpath"; then - eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" - fi - - # Get the real and link names of the library. - eval shared_ext=\"$shrext_cmds\" - eval library_names=\"$library_names_spec\" - set dummy $library_names - realname="$2" - shift; shift - - if test -n "$soname_spec"; then - eval soname=\"$soname_spec\" - else - soname="$realname" - fi - if test -z "$dlname"; then - dlname=$soname - fi - - lib="$output_objdir/$realname" - linknames= - for link - do - linknames="$linknames $link" - done - - # Use standard objects if they are pic - test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` - - # Prepare the list of exported symbols - if test -z "$export_symbols"; then - if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then - $show "generating symbol list for \`$libname.la'" - export_symbols="$output_objdir/$libname.exp" - $run $rm $export_symbols - cmds=$export_symbols_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - if len=`expr "X$cmd" : ".*"` && - test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then - $show "$cmd" - $run eval "$cmd" || exit $? - skipped_export=false - else - # The command line is too long to execute in one step. - $show "using reloadable object file for export list..." - skipped_export=: - # Break out early, otherwise skipped_export may be - # set to false by a later but shorter cmd. - break - fi - done - IFS="$save_ifs" - if test -n "$export_symbols_regex"; then - $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" - $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' - $show "$mv \"${export_symbols}T\" \"$export_symbols\"" - $run eval '$mv "${export_symbols}T" "$export_symbols"' - fi - fi - fi - - if test -n "$export_symbols" && test -n "$include_expsyms"; then - $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' - fi - - tmp_deplibs= - for test_deplib in $deplibs; do - case " $convenience " in - *" $test_deplib "*) ;; - *) - tmp_deplibs="$tmp_deplibs $test_deplib" - ;; - esac - done - deplibs="$tmp_deplibs" - - if test -n "$convenience"; then - if test -n "$whole_archive_flag_spec"; then - save_libobjs=$libobjs - eval libobjs=\"\$libobjs $whole_archive_flag_spec\" - else - gentop="$output_objdir/${outputname}x" - generated="$generated $gentop" - - func_extract_archives $gentop $convenience - libobjs="$libobjs $func_extract_archives_result" - fi - fi - - if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then - eval flag=\"$thread_safe_flag_spec\" - linker_flags="$linker_flags $flag" - fi - - # Make a backup of the uninstalled library when relinking - if test "$mode" = relink; then - $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? - fi - - # Do each of the archive commands. - if test "$module" = yes && test -n "$module_cmds" ; then - if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then - eval test_cmds=\"$module_expsym_cmds\" - cmds=$module_expsym_cmds - else - eval test_cmds=\"$module_cmds\" - cmds=$module_cmds - fi - else - if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then - eval test_cmds=\"$archive_expsym_cmds\" - cmds=$archive_expsym_cmds - else - eval test_cmds=\"$archive_cmds\" - cmds=$archive_cmds - fi - fi - - if test "X$skipped_export" != "X:" && - len=`expr "X$test_cmds" : ".*" 2>/dev/null` && - test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then - : - else - # The command line is too long to link in one step, link piecewise. - $echo "creating reloadable object files..." - - # Save the value of $output and $libobjs because we want to - # use them later. If we have whole_archive_flag_spec, we - # want to use save_libobjs as it was before - # whole_archive_flag_spec was expanded, because we can't - # assume the linker understands whole_archive_flag_spec. - # This may have to be revisited, in case too many - # convenience libraries get linked in and end up exceeding - # the spec. - if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then - save_libobjs=$libobjs - fi - save_output=$output - output_la=`$echo "X$output" | $Xsed -e "$basename"` - - # Clear the reloadable object creation command queue and - # initialize k to one. - test_cmds= - concat_cmds= - objlist= - delfiles= - last_robj= - k=1 - output=$output_objdir/$output_la-${k}.$objext - # Loop over the list of objects to be linked. - for obj in $save_libobjs - do - eval test_cmds=\"$reload_cmds $objlist $last_robj\" - if test "X$objlist" = X || - { len=`expr "X$test_cmds" : ".*" 2>/dev/null` && - test "$len" -le "$max_cmd_len"; }; then - objlist="$objlist $obj" - else - # The command $test_cmds is almost too long, add a - # command to the queue. - if test "$k" -eq 1 ; then - # The first file doesn't have a previous command to add. - eval concat_cmds=\"$reload_cmds $objlist $last_robj\" - else - # All subsequent reloadable object files will link in - # the last one created. - eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\" - fi - last_robj=$output_objdir/$output_la-${k}.$objext - k=`expr $k + 1` - output=$output_objdir/$output_la-${k}.$objext - objlist=$obj - len=1 - fi - done - # Handle the remaining objects by creating one last - # reloadable object file. All subsequent reloadable object - # files will link in the last one created. - test -z "$concat_cmds" || concat_cmds=$concat_cmds~ - eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" - - if ${skipped_export-false}; then - $show "generating symbol list for \`$libname.la'" - export_symbols="$output_objdir/$libname.exp" - $run $rm $export_symbols - libobjs=$output - # Append the command to create the export file. - eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\" - fi - - # Set up a command to remove the reloadable object files - # after they are used. - i=0 - while test "$i" -lt "$k" - do - i=`expr $i + 1` - delfiles="$delfiles $output_objdir/$output_la-${i}.$objext" - done - - $echo "creating a temporary reloadable object file: $output" - - # Loop through the commands generated above and execute them. - save_ifs="$IFS"; IFS='~' - for cmd in $concat_cmds; do - IFS="$save_ifs" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - - libobjs=$output - # Restore the value of output. - output=$save_output - - if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then - eval libobjs=\"\$libobjs $whole_archive_flag_spec\" - fi - # Expand the library linking commands again to reset the - # value of $libobjs for piecewise linking. - - # Do each of the archive commands. - if test "$module" = yes && test -n "$module_cmds" ; then - if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then - cmds=$module_expsym_cmds - else - cmds=$module_cmds - fi - else - if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then - cmds=$archive_expsym_cmds - else - cmds=$archive_cmds - fi - fi - - # Append the command to remove the reloadable object files - # to the just-reset $cmds. - eval cmds=\"\$cmds~\$rm $delfiles\" - fi - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || { - lt_exit=$? - - # Restore the uninstalled library and exit - if test "$mode" = relink; then - $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' - fi - - exit $lt_exit - } - done - IFS="$save_ifs" - - # Restore the uninstalled library and exit - if test "$mode" = relink; then - $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? - - if test -n "$convenience"; then - if test -z "$whole_archive_flag_spec"; then - $show "${rm}r $gentop" - $run ${rm}r "$gentop" - fi - fi - - exit $EXIT_SUCCESS - fi - - # Create links to the real library. - for linkname in $linknames; do - if test "$realname" != "$linkname"; then - $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" - $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? - fi - done - - # If -module or -export-dynamic was specified, set the dlname. - if test "$module" = yes || test "$export_dynamic" = yes; then - # On all known operating systems, these are identical. - dlname="$soname" - fi - fi - ;; - - obj) - if test -n "$deplibs"; then - $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 - fi - - if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then - $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 - fi - - if test -n "$rpath"; then - $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 - fi - - if test -n "$xrpath"; then - $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 - fi - - if test -n "$vinfo"; then - $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 - fi - - if test -n "$release"; then - $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 - fi - - case $output in - *.lo) - if test -n "$objs$old_deplibs"; then - $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 - exit $EXIT_FAILURE - fi - libobj="$output" - obj=`$echo "X$output" | $Xsed -e "$lo2o"` - ;; - *) - libobj= - obj="$output" - ;; - esac - - # Delete the old objects. - $run $rm $obj $libobj - - # Objects from convenience libraries. This assumes - # single-version convenience libraries. Whenever we create - # different ones for PIC/non-PIC, this we'll have to duplicate - # the extraction. - reload_conv_objs= - gentop= - # reload_cmds runs $LD directly, so let us get rid of - # -Wl from whole_archive_flag_spec - wl= - - if test -n "$convenience"; then - if test -n "$whole_archive_flag_spec"; then - eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" - else - gentop="$output_objdir/${obj}x" - generated="$generated $gentop" - - func_extract_archives $gentop $convenience - reload_conv_objs="$reload_objs $func_extract_archives_result" - fi - fi - - # Create the old-style object. - reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test - - output="$obj" - cmds=$reload_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - - # Exit if we aren't doing a library object file. - if test -z "$libobj"; then - if test -n "$gentop"; then - $show "${rm}r $gentop" - $run ${rm}r $gentop - fi - - exit $EXIT_SUCCESS - fi - - if test "$build_libtool_libs" != yes; then - if test -n "$gentop"; then - $show "${rm}r $gentop" - $run ${rm}r $gentop - fi - - # Create an invalid libtool object if no PIC, so that we don't - # accidentally link it into a program. - # $show "echo timestamp > $libobj" - # $run eval "echo timestamp > $libobj" || exit $? - exit $EXIT_SUCCESS - fi - - if test -n "$pic_flag" || test "$pic_mode" != default; then - # Only do commands if we really have different PIC objects. - reload_objs="$libobjs $reload_conv_objs" - output="$libobj" - cmds=$reload_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - fi - - if test -n "$gentop"; then - $show "${rm}r $gentop" - $run ${rm}r $gentop - fi - - exit $EXIT_SUCCESS - ;; - - prog) - case $host in - *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;; - esac - if test -n "$vinfo"; then - $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 - fi - - if test -n "$release"; then - $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 - fi - - if test "$preload" = yes; then - if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && - test "$dlopen_self_static" = unknown; then - $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." - fi - fi - - case $host in - *-*-rhapsody* | *-*-darwin1.[012]) - # On Rhapsody replace the C library is the System framework - compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` - finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` - ;; - esac - - case $host in - *darwin*) - # Don't allow lazy linking, it breaks C++ global constructors - if test "$tagname" = CXX ; then - compile_command="$compile_command ${wl}-bind_at_load" - finalize_command="$finalize_command ${wl}-bind_at_load" - fi - ;; - esac - - - # move library search paths that coincide with paths to not yet - # installed libraries to the beginning of the library search list - new_libs= - for path in $notinst_path; do - case " $new_libs " in - *" -L$path/$objdir "*) ;; - *) - case " $compile_deplibs " in - *" -L$path/$objdir "*) - new_libs="$new_libs -L$path/$objdir" ;; - esac - ;; - esac - done - for deplib in $compile_deplibs; do - case $deplib in - -L*) - case " $new_libs " in - *" $deplib "*) ;; - *) new_libs="$new_libs $deplib" ;; - esac - ;; - *) new_libs="$new_libs $deplib" ;; - esac - done - compile_deplibs="$new_libs" - - - compile_command="$compile_command $compile_deplibs" - finalize_command="$finalize_command $finalize_deplibs" - - if test -n "$rpath$xrpath"; then - # If the user specified any rpath flags, then add them. - for libdir in $rpath $xrpath; do - # This is the magic to use -rpath. - case "$finalize_rpath " in - *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" ;; - esac - done - fi - - # Now hardcode the library paths - rpath= - hardcode_libdirs= - for libdir in $compile_rpath $finalize_rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - if test -z "$hardcode_libdirs"; then - hardcode_libdirs="$libdir" - else - # Just accumulate the unique libdirs. - case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval flag=\"$hardcode_libdir_flag_spec\" - rpath="$rpath $flag" - fi - elif test -n "$runpath_var"; then - case "$perm_rpath " in - *" $libdir "*) ;; - *) perm_rpath="$perm_rpath $libdir" ;; - esac - fi - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) - testbindir=`$echo "X$libdir" | $Xsed -e 's*/lib$*/bin*'` - case :$dllsearchpath: in - *":$libdir:"*) ;; - *) dllsearchpath="$dllsearchpath:$libdir";; - esac - case :$dllsearchpath: in - *":$testbindir:"*) ;; - *) dllsearchpath="$dllsearchpath:$testbindir";; - esac - ;; - esac - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir="$hardcode_libdirs" - eval rpath=\" $hardcode_libdir_flag_spec\" - fi - compile_rpath="$rpath" - - rpath= - hardcode_libdirs= - for libdir in $finalize_rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - if test -z "$hardcode_libdirs"; then - hardcode_libdirs="$libdir" - else - # Just accumulate the unique libdirs. - case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval flag=\"$hardcode_libdir_flag_spec\" - rpath="$rpath $flag" - fi - elif test -n "$runpath_var"; then - case "$finalize_perm_rpath " in - *" $libdir "*) ;; - *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; - esac - fi - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir="$hardcode_libdirs" - eval rpath=\" $hardcode_libdir_flag_spec\" - fi - finalize_rpath="$rpath" - - if test -n "$libobjs" && test "$build_old_libs" = yes; then - # Transform all the library objects into standard objects. - compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` - finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` - fi - - dlsyms= - if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then - if test -n "$NM" && test -n "$global_symbol_pipe"; then - dlsyms="${outputname}S.c" - else - $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 - fi - fi - - if test -n "$dlsyms"; then - case $dlsyms in - "") ;; - *.c) - # Discover the nlist of each of the dlfiles. - nlist="$output_objdir/${outputname}.nm" - - $show "$rm $nlist ${nlist}S ${nlist}T" - $run $rm "$nlist" "${nlist}S" "${nlist}T" - - # Parse the name list into a source file. - $show "creating $output_objdir/$dlsyms" - - test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ -/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ -/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ - -#ifdef __cplusplus -extern \"C\" { -#endif - -/* Prevent the only kind of declaration conflicts we can make. */ -#define lt_preloaded_symbols some_other_symbol - -/* External symbol declarations for the compiler. */\ -" - - if test "$dlself" = yes; then - $show "generating symbol list for \`$output'" - - test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" - - # Add our own program objects to the symbol list. - progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` - for arg in $progfiles; do - $show "extracting global C symbols from \`$arg'" - $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" - done - - if test -n "$exclude_expsyms"; then - $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' - $run eval '$mv "$nlist"T "$nlist"' - fi - - if test -n "$export_symbols_regex"; then - $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' - $run eval '$mv "$nlist"T "$nlist"' - fi - - # Prepare the list of exported symbols - if test -z "$export_symbols"; then - export_symbols="$output_objdir/$outputname.exp" - $run $rm $export_symbols - $run eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' - case $host in - *cygwin* | *mingw* ) - $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' - $run eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' - ;; - esac - else - $run eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' - $run eval 'grep -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' - $run eval 'mv "$nlist"T "$nlist"' - case $host in - *cygwin* | *mingw* ) - $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' - $run eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' - ;; - esac - fi - fi - - for arg in $dlprefiles; do - $show "extracting global C symbols from \`$arg'" - name=`$echo "$arg" | ${SED} -e 's%^.*/%%'` - $run eval '$echo ": $name " >> "$nlist"' - $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" - done - - if test -z "$run"; then - # Make sure we have at least an empty file. - test -f "$nlist" || : > "$nlist" - - if test -n "$exclude_expsyms"; then - $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T - $mv "$nlist"T "$nlist" - fi - - # Try sorting and uniquifying the output. - if grep -v "^: " < "$nlist" | - if sort -k 3 </dev/null >/dev/null 2>&1; then - sort -k 3 - else - sort +2 - fi | - uniq > "$nlist"S; then - : - else - grep -v "^: " < "$nlist" > "$nlist"S - fi - - if test -f "$nlist"S; then - eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' - else - $echo '/* NONE */' >> "$output_objdir/$dlsyms" - fi - - $echo >> "$output_objdir/$dlsyms" "\ - -#undef lt_preloaded_symbols - -#if defined (__STDC__) && __STDC__ -# define lt_ptr void * -#else -# define lt_ptr char * -# define const -#endif - -/* The mapping between symbol names and symbols. */ -" - - case $host in - *cygwin* | *mingw* ) - $echo >> "$output_objdir/$dlsyms" "\ -/* DATA imports from DLLs on WIN32 can't be const, because - runtime relocations are performed -- see ld's documentation - on pseudo-relocs */ -struct { -" - ;; - * ) - $echo >> "$output_objdir/$dlsyms" "\ -const struct { -" - ;; - esac - - - $echo >> "$output_objdir/$dlsyms" "\ - const char *name; - lt_ptr address; -} -lt_preloaded_symbols[] = -{\ -" - - eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms" - - $echo >> "$output_objdir/$dlsyms" "\ - {0, (lt_ptr) 0} -}; - -/* This works around a problem in FreeBSD linker */ -#ifdef FREEBSD_WORKAROUND -static const void *lt_preloaded_setup() { - return lt_preloaded_symbols; -} -#endif - -#ifdef __cplusplus -} -#endif\ -" - fi - - pic_flag_for_symtable= - case $host in - # compiling the symbol table file with pic_flag works around - # a FreeBSD bug that causes programs to crash when -lm is - # linked before any other PIC object. But we must not use - # pic_flag when linking with -static. The problem exists in - # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. - *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) - case "$compile_command " in - *" -static "*) ;; - *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";; - esac;; - *-*-hpux*) - case "$compile_command " in - *" -static "*) ;; - *) pic_flag_for_symtable=" $pic_flag";; - esac - esac - - # Now compile the dynamic symbol file. - $show "(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" - $run eval '(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? - - # Clean up the generated files. - $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" - $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" - - # Transform the symbol file into the correct name. - case $host in - *cygwin* | *mingw* ) - if test -f "$output_objdir/${outputname}.def" ; then - compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%"` - finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%"` - else - compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` - finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` - fi - ;; - * ) - compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` - finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` - ;; - esac - ;; - *) - $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 - exit $EXIT_FAILURE - ;; - esac - else - # We keep going just in case the user didn't refer to - # lt_preloaded_symbols. The linker will fail if global_symbol_pipe - # really was required. - - # Nullify the symbol file. - compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` - finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` - fi - - if test "$need_relink" = no || test "$build_libtool_libs" != yes; then - # Replace the output file specification. - compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` - link_command="$compile_command$compile_rpath" - - # We have no uninstalled library dependencies, so finalize right now. - $show "$link_command" - $run eval "$link_command" - exit_status=$? - - # Delete the generated files. - if test -n "$dlsyms"; then - $show "$rm $output_objdir/${outputname}S.${objext}" - $run $rm "$output_objdir/${outputname}S.${objext}" - fi - - exit $exit_status - fi - - if test -n "$shlibpath_var"; then - # We should set the shlibpath_var - rpath= - for dir in $temp_rpath; do - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) - # Absolute path. - rpath="$rpath$dir:" - ;; - *) - # Relative path: add a thisdir entry. - rpath="$rpath\$thisdir/$dir:" - ;; - esac - done - temp_rpath="$rpath" - fi - - if test -n "$compile_shlibpath$finalize_shlibpath"; then - compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" - fi - if test -n "$finalize_shlibpath"; then - finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" - fi - - compile_var= - finalize_var= - if test -n "$runpath_var"; then - if test -n "$perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $perm_rpath; do - rpath="$rpath$dir:" - done - compile_var="$runpath_var=\"$rpath\$$runpath_var\" " - fi - if test -n "$finalize_perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $finalize_perm_rpath; do - rpath="$rpath$dir:" - done - finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " - fi - fi - - if test "$no_install" = yes; then - # We don't need to create a wrapper script. - link_command="$compile_var$compile_command$compile_rpath" - # Replace the output file specification. - link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` - # Delete the old output file. - $run $rm $output - # Link the executable and exit - $show "$link_command" - $run eval "$link_command" || exit $? - exit $EXIT_SUCCESS - fi - - if test "$hardcode_action" = relink; then - # Fast installation is not supported - link_command="$compile_var$compile_command$compile_rpath" - relink_command="$finalize_var$finalize_command$finalize_rpath" - - $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 - $echo "$modename: \`$output' will be relinked during installation" 1>&2 - else - if test "$fast_install" != no; then - link_command="$finalize_var$compile_command$finalize_rpath" - if test "$fast_install" = yes; then - relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` - else - # fast_install is set to needless - relink_command= - fi - else - link_command="$compile_var$compile_command$compile_rpath" - relink_command="$finalize_var$finalize_command$finalize_rpath" - fi - fi - - # Replace the output file specification. - link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` - - # Delete the old output files. - $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname - - $show "$link_command" - $run eval "$link_command" || exit $? - - # Now create the wrapper script. - $show "creating $output" - - # Quote the relink command for shipping. - if test -n "$relink_command"; then - # Preserve any variables that may affect compiler behavior - for var in $variables_saved_for_relink; do - if eval test -z \"\${$var+set}\"; then - relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" - elif eval var_value=\$$var; test -z "$var_value"; then - relink_command="$var=; export $var; $relink_command" - else - var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` - relink_command="$var=\"$var_value\"; export $var; $relink_command" - fi - done - relink_command="(cd `pwd`; $relink_command)" - relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` - fi - - # Quote $echo for shipping. - if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then - case $progpath in - [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; - *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; - esac - qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` - else - qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` - fi - - # Only actually do things if our run command is non-null. - if test -z "$run"; then - # win32 will think the script is a binary if it has - # a .exe suffix, so we strip it off here. - case $output in - *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;; - esac - # test for cygwin because mv fails w/o .exe extensions - case $host in - *cygwin*) - exeext=.exe - outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;; - *) exeext= ;; - esac - case $host in - *cygwin* | *mingw* ) - output_name=`basename $output` - output_path=`dirname $output` - cwrappersource="$output_path/$objdir/lt-$output_name.c" - cwrapper="$output_path/$output_name.exe" - $rm $cwrappersource $cwrapper - trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 - - cat > $cwrappersource <<EOF - -/* $cwrappersource - temporary wrapper executable for $objdir/$outputname - Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP - - The $output program cannot be directly executed until all the libtool - libraries that it depends on are installed. - - This wrapper executable should never be moved out of the build directory. - If it is, it will not operate correctly. - - Currently, it simply execs the wrapper *script* "/bin/sh $output", - but could eventually absorb all of the scripts functionality and - exec $objdir/$outputname directly. -*/ -EOF - cat >> $cwrappersource<<"EOF" -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <malloc.h> -#include <stdarg.h> -#include <assert.h> -#include <string.h> -#include <ctype.h> -#include <sys/stat.h> - -#if defined(PATH_MAX) -# define LT_PATHMAX PATH_MAX -#elif defined(MAXPATHLEN) -# define LT_PATHMAX MAXPATHLEN -#else -# define LT_PATHMAX 1024 -#endif - -#ifndef DIR_SEPARATOR -# define DIR_SEPARATOR '/' -# define PATH_SEPARATOR ':' -#endif - -#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ - defined (__OS2__) -# define HAVE_DOS_BASED_FILE_SYSTEM -# ifndef DIR_SEPARATOR_2 -# define DIR_SEPARATOR_2 '\\' -# endif -# ifndef PATH_SEPARATOR_2 -# define PATH_SEPARATOR_2 ';' -# endif -#endif - -#ifndef DIR_SEPARATOR_2 -# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) -#else /* DIR_SEPARATOR_2 */ -# define IS_DIR_SEPARATOR(ch) \ - (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) -#endif /* DIR_SEPARATOR_2 */ - -#ifndef PATH_SEPARATOR_2 -# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) -#else /* PATH_SEPARATOR_2 */ -# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) -#endif /* PATH_SEPARATOR_2 */ - -#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) -#define XFREE(stale) do { \ - if (stale) { free ((void *) stale); stale = 0; } \ -} while (0) - -/* -DDEBUG is fairly common in CFLAGS. */ -#undef DEBUG -#if defined DEBUGWRAPPER -# define DEBUG(format, ...) fprintf(stderr, format, __VA_ARGS__) -#else -# define DEBUG(format, ...) -#endif - -const char *program_name = NULL; - -void * xmalloc (size_t num); -char * xstrdup (const char *string); -const char * base_name (const char *name); -char * find_executable(const char *wrapper); -int check_executable(const char *path); -char * strendzap(char *str, const char *pat); -void lt_fatal (const char *message, ...); - -int -main (int argc, char *argv[]) -{ - char **newargz; - int i; - - program_name = (char *) xstrdup (base_name (argv[0])); - DEBUG("(main) argv[0] : %s\n",argv[0]); - DEBUG("(main) program_name : %s\n",program_name); - newargz = XMALLOC(char *, argc+2); -EOF - - cat >> $cwrappersource <<EOF - newargz[0] = (char *) xstrdup("$SHELL"); -EOF - - cat >> $cwrappersource <<"EOF" - newargz[1] = find_executable(argv[0]); - if (newargz[1] == NULL) - lt_fatal("Couldn't find %s", argv[0]); - DEBUG("(main) found exe at : %s\n",newargz[1]); - /* we know the script has the same name, without the .exe */ - /* so make sure newargz[1] doesn't end in .exe */ - strendzap(newargz[1],".exe"); - for (i = 1; i < argc; i++) - newargz[i+1] = xstrdup(argv[i]); - newargz[argc+1] = NULL; - - for (i=0; i<argc+1; i++) - { - DEBUG("(main) newargz[%d] : %s\n",i,newargz[i]); - ; - } - -EOF - - case $host_os in - mingw*) - cat >> $cwrappersource <<EOF - execv("$SHELL",(char const **)newargz); -EOF - ;; - *) - cat >> $cwrappersource <<EOF - execv("$SHELL",newargz); -EOF - ;; - esac - - cat >> $cwrappersource <<"EOF" - return 127; -} - -void * -xmalloc (size_t num) -{ - void * p = (void *) malloc (num); - if (!p) - lt_fatal ("Memory exhausted"); - - return p; -} - -char * -xstrdup (const char *string) -{ - return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL -; -} - -const char * -base_name (const char *name) -{ - const char *base; - -#if defined (HAVE_DOS_BASED_FILE_SYSTEM) - /* Skip over the disk name in MSDOS pathnames. */ - if (isalpha ((unsigned char)name[0]) && name[1] == ':') - name += 2; -#endif - - for (base = name; *name; name++) - if (IS_DIR_SEPARATOR (*name)) - base = name + 1; - return base; -} - -int -check_executable(const char * path) -{ - struct stat st; - - DEBUG("(check_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!"); - if ((!path) || (!*path)) - return 0; - - if ((stat (path, &st) >= 0) && - ( - /* MinGW & native WIN32 do not support S_IXOTH or S_IXGRP */ -#if defined (S_IXOTH) - ((st.st_mode & S_IXOTH) == S_IXOTH) || -#endif -#if defined (S_IXGRP) - ((st.st_mode & S_IXGRP) == S_IXGRP) || -#endif - ((st.st_mode & S_IXUSR) == S_IXUSR)) - ) - return 1; - else - return 0; -} - -/* Searches for the full path of the wrapper. Returns - newly allocated full path name if found, NULL otherwise */ -char * -find_executable (const char* wrapper) -{ - int has_slash = 0; - const char* p; - const char* p_next; - /* static buffer for getcwd */ - char tmp[LT_PATHMAX + 1]; - int tmp_len; - char* concat_name; - - DEBUG("(find_executable) : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!"); - - if ((wrapper == NULL) || (*wrapper == '\0')) - return NULL; - - /* Absolute path? */ -#if defined (HAVE_DOS_BASED_FILE_SYSTEM) - if (isalpha ((unsigned char)wrapper[0]) && wrapper[1] == ':') - { - concat_name = xstrdup (wrapper); - if (check_executable(concat_name)) - return concat_name; - XFREE(concat_name); - } - else - { -#endif - if (IS_DIR_SEPARATOR (wrapper[0])) - { - concat_name = xstrdup (wrapper); - if (check_executable(concat_name)) - return concat_name; - XFREE(concat_name); - } -#if defined (HAVE_DOS_BASED_FILE_SYSTEM) - } -#endif - - for (p = wrapper; *p; p++) - if (*p == '/') - { - has_slash = 1; - break; - } - if (!has_slash) - { - /* no slashes; search PATH */ - const char* path = getenv ("PATH"); - if (path != NULL) - { - for (p = path; *p; p = p_next) - { - const char* q; - size_t p_len; - for (q = p; *q; q++) - if (IS_PATH_SEPARATOR(*q)) - break; - p_len = q - p; - p_next = (*q == '\0' ? q : q + 1); - if (p_len == 0) - { - /* empty path: current directory */ - if (getcwd (tmp, LT_PATHMAX) == NULL) - lt_fatal ("getcwd failed"); - tmp_len = strlen(tmp); - concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); - memcpy (concat_name, tmp, tmp_len); - concat_name[tmp_len] = '/'; - strcpy (concat_name + tmp_len + 1, wrapper); - } - else - { - concat_name = XMALLOC(char, p_len + 1 + strlen(wrapper) + 1); - memcpy (concat_name, p, p_len); - concat_name[p_len] = '/'; - strcpy (concat_name + p_len + 1, wrapper); - } - if (check_executable(concat_name)) - return concat_name; - XFREE(concat_name); - } - } - /* not found in PATH; assume curdir */ - } - /* Relative path | not found in path: prepend cwd */ - if (getcwd (tmp, LT_PATHMAX) == NULL) - lt_fatal ("getcwd failed"); - tmp_len = strlen(tmp); - concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); - memcpy (concat_name, tmp, tmp_len); - concat_name[tmp_len] = '/'; - strcpy (concat_name + tmp_len + 1, wrapper); - - if (check_executable(concat_name)) - return concat_name; - XFREE(concat_name); - return NULL; -} - -char * -strendzap(char *str, const char *pat) -{ - size_t len, patlen; - - assert(str != NULL); - assert(pat != NULL); - - len = strlen(str); - patlen = strlen(pat); - - if (patlen <= len) - { - str += len - patlen; - if (strcmp(str, pat) == 0) - *str = '\0'; - } - return str; -} - -static void -lt_error_core (int exit_status, const char * mode, - const char * message, va_list ap) -{ - fprintf (stderr, "%s: %s: ", program_name, mode); - vfprintf (stderr, message, ap); - fprintf (stderr, ".\n"); - - if (exit_status >= 0) - exit (exit_status); -} - -void -lt_fatal (const char *message, ...) -{ - va_list ap; - va_start (ap, message); - lt_error_core (EXIT_FAILURE, "FATAL", message, ap); - va_end (ap); -} -EOF - # we should really use a build-platform specific compiler - # here, but OTOH, the wrappers (shell script and this C one) - # are only useful if you want to execute the "real" binary. - # Since the "real" binary is built for $host, then this - # wrapper might as well be built for $host, too. - $run $LTCC $LTCFLAGS -s -o $cwrapper $cwrappersource - ;; - esac - $rm $output - trap "$rm $output; exit $EXIT_FAILURE" 1 2 15 - - $echo > $output "\ -#! $SHELL - -# $output - temporary wrapper script for $objdir/$outputname -# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP -# -# The $output program cannot be directly executed until all the libtool -# libraries that it depends on are installed. -# -# This wrapper script should never be moved out of the build directory. -# If it is, it will not operate correctly. - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -Xsed='${SED} -e 1s/^X//' -sed_quote_subst='$sed_quote_subst' - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -relink_command=\"$relink_command\" - -# This environment variable determines our operation mode. -if test \"\$libtool_install_magic\" = \"$magic\"; then - # install mode needs the following variable: - notinst_deplibs='$notinst_deplibs' -else - # When we are sourced in execute mode, \$file and \$echo are already set. - if test \"\$libtool_execute_magic\" != \"$magic\"; then - echo=\"$qecho\" - file=\"\$0\" - # Make sure echo works. - if test \"X\$1\" = X--no-reexec; then - # Discard the --no-reexec flag, and continue. - shift - elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then - # Yippee, \$echo works! - : - else - # Restart under the correct shell, and then maybe \$echo will work. - exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} - fi - fi\ -" - $echo >> $output "\ - - # Find the directory that this script lives in. - thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` - test \"x\$thisdir\" = \"x\$file\" && thisdir=. - - # Follow symbolic links until we get to the real thisdir. - file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` - while test -n \"\$file\"; do - destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` - - # If there was a directory component, then change thisdir. - if test \"x\$destdir\" != \"x\$file\"; then - case \"\$destdir\" in - [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; - *) thisdir=\"\$thisdir/\$destdir\" ;; - esac - fi - - file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` - file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` - done - - # Try to get the absolute directory name. - absdir=\`cd \"\$thisdir\" && pwd\` - test -n \"\$absdir\" && thisdir=\"\$absdir\" -" - - if test "$fast_install" = yes; then - $echo >> $output "\ - program=lt-'$outputname'$exeext - progdir=\"\$thisdir/$objdir\" - - if test ! -f \"\$progdir/\$program\" || \\ - { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ - test \"X\$file\" != \"X\$progdir/\$program\"; }; then - - file=\"\$\$-\$program\" - - if test ! -d \"\$progdir\"; then - $mkdir \"\$progdir\" - else - $rm \"\$progdir/\$file\" - fi" - - $echo >> $output "\ - - # relink executable if necessary - if test -n \"\$relink_command\"; then - if relink_command_output=\`eval \$relink_command 2>&1\`; then : - else - $echo \"\$relink_command_output\" >&2 - $rm \"\$progdir/\$file\" - exit $EXIT_FAILURE - fi - fi - - $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || - { $rm \"\$progdir/\$program\"; - $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } - $rm \"\$progdir/\$file\" - fi" - else - $echo >> $output "\ - program='$outputname' - progdir=\"\$thisdir/$objdir\" -" - fi - - $echo >> $output "\ - - if test -f \"\$progdir/\$program\"; then" - - # Export our shlibpath_var if we have one. - if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then - $echo >> $output "\ - # Add our own library path to $shlibpath_var - $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" - - # Some systems cannot cope with colon-terminated $shlibpath_var - # The second colon is a workaround for a bug in BeOS R4 sed - $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` - - export $shlibpath_var -" - fi - - # fixup the dll searchpath if we need to. - if test -n "$dllsearchpath"; then - $echo >> $output "\ - # Add the dll search path components to the executable PATH - PATH=$dllsearchpath:\$PATH -" - fi - - $echo >> $output "\ - if test \"\$libtool_execute_magic\" != \"$magic\"; then - # Run the actual program with our arguments. - - # Make sure env LD_LIBRARY_PATH does not mess us up - if test -n \"\${LD_LIBRARY_PATH+set}\"; then - export LD_LIBRARY_PATH=\$progdir:\$LD_LIBRARY_PATH - fi -" - case $host in - # Backslashes separate directories on plain windows - *-*-mingw | *-*-os2*) - $echo >> $output "\ - exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} -" - ;; - - *) - $echo >> $output "\ - exec \"\$progdir/\$program\" \${1+\"\$@\"} -" - ;; - esac - $echo >> $output "\ - \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" - exit $EXIT_FAILURE - fi - else - # The program doesn't exist. - \$echo \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 - \$echo \"This script is just a wrapper for \$program.\" 1>&2 - $echo \"See the $PACKAGE documentation for more information.\" 1>&2 - exit $EXIT_FAILURE - fi -fi\ -" - chmod +x $output - fi - exit $EXIT_SUCCESS - ;; - esac - - # See if we need to build an old-fashioned archive. - for oldlib in $oldlibs; do - - if test "$build_libtool_libs" = convenience; then - oldobjs="$libobjs_save" - addlibs="$convenience" - build_libtool_libs=no - else - if test "$build_libtool_libs" = module; then - oldobjs="$libobjs_save" - build_libtool_libs=no - else - oldobjs="$old_deplibs $non_pic_objects" - fi - addlibs="$old_convenience" - fi - - if test -n "$addlibs"; then - gentop="$output_objdir/${outputname}x" - generated="$generated $gentop" - - func_extract_archives $gentop $addlibs - oldobjs="$oldobjs $func_extract_archives_result" - fi - - # Do each command in the archive commands. - if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then - cmds=$old_archive_from_new_cmds - else - # POSIX demands no paths to be encoded in archives. We have - # to avoid creating archives with duplicate basenames if we - # might have to extract them afterwards, e.g., when creating a - # static archive out of a convenience library, or when linking - # the entirety of a libtool archive into another (currently - # not supported by libtool). - if (for obj in $oldobjs - do - $echo "X$obj" | $Xsed -e 's%^.*/%%' - done | sort | sort -uc >/dev/null 2>&1); then - : - else - $echo "copying selected object files to avoid basename conflicts..." - - if test -z "$gentop"; then - gentop="$output_objdir/${outputname}x" - generated="$generated $gentop" - - $show "${rm}r $gentop" - $run ${rm}r "$gentop" - $show "$mkdir $gentop" - $run $mkdir "$gentop" - exit_status=$? - if test "$exit_status" -ne 0 && test ! -d "$gentop"; then - exit $exit_status - fi - fi - - save_oldobjs=$oldobjs - oldobjs= - counter=1 - for obj in $save_oldobjs - do - objbase=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` - case " $oldobjs " in - " ") oldobjs=$obj ;; - *[\ /]"$objbase "*) - while :; do - # Make sure we don't pick an alternate name that also - # overlaps. - newobj=lt$counter-$objbase - counter=`expr $counter + 1` - case " $oldobjs " in - *[\ /]"$newobj "*) ;; - *) if test ! -f "$gentop/$newobj"; then break; fi ;; - esac - done - $show "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" - $run ln "$obj" "$gentop/$newobj" || - $run cp "$obj" "$gentop/$newobj" - oldobjs="$oldobjs $gentop/$newobj" - ;; - *) oldobjs="$oldobjs $obj" ;; - esac - done - fi - - eval cmds=\"$old_archive_cmds\" - - if len=`expr "X$cmds" : ".*"` && - test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then - cmds=$old_archive_cmds - else - # the command line is too long to link in one step, link in parts - $echo "using piecewise archive linking..." - save_RANLIB=$RANLIB - RANLIB=: - objlist= - concat_cmds= - save_oldobjs=$oldobjs - - # Is there a better way of finding the last object in the list? - for obj in $save_oldobjs - do - last_oldobj=$obj - done - for obj in $save_oldobjs - do - oldobjs="$objlist $obj" - objlist="$objlist $obj" - eval test_cmds=\"$old_archive_cmds\" - if len=`expr "X$test_cmds" : ".*" 2>/dev/null` && - test "$len" -le "$max_cmd_len"; then - : - else - # the above command should be used before it gets too long - oldobjs=$objlist - if test "$obj" = "$last_oldobj" ; then - RANLIB=$save_RANLIB - fi - test -z "$concat_cmds" || concat_cmds=$concat_cmds~ - eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" - objlist= - fi - done - RANLIB=$save_RANLIB - oldobjs=$objlist - if test "X$oldobjs" = "X" ; then - eval cmds=\"\$concat_cmds\" - else - eval cmds=\"\$concat_cmds~\$old_archive_cmds\" - fi - fi - fi - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - eval cmd=\"$cmd\" - IFS="$save_ifs" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - done - - if test -n "$generated"; then - $show "${rm}r$generated" - $run ${rm}r$generated - fi - - # Now create the libtool archive. - case $output in - *.la) - old_library= - test "$build_old_libs" = yes && old_library="$libname.$libext" - $show "creating $output" - - # Preserve any variables that may affect compiler behavior - for var in $variables_saved_for_relink; do - if eval test -z \"\${$var+set}\"; then - relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" - elif eval var_value=\$$var; test -z "$var_value"; then - relink_command="$var=; export $var; $relink_command" - else - var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` - relink_command="$var=\"$var_value\"; export $var; $relink_command" - fi - done - # Quote the link command for shipping. - relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" - relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` - if test "$hardcode_automatic" = yes ; then - relink_command= - fi - - - # Only create the output if not a dry run. - if test -z "$run"; then - for installed in no yes; do - if test "$installed" = yes; then - if test -z "$install_libdir"; then - break - fi - output="$output_objdir/$outputname"i - # Replace all uninstalled libtool libraries with the installed ones - newdependency_libs= - for deplib in $dependency_libs; do - case $deplib in - *.la) - name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` - eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` - if test -z "$libdir"; then - $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 - exit $EXIT_FAILURE - fi - if test "X$EGREP" = X ; then - EGREP=egrep - fi - # We do not want portage's install root ($D) present. Check only for - # this if the .la is being installed. - if test "$installed" = yes && test "$D"; then - eval mynewdependency_lib=`echo "$libdir/$name" |sed -e "s:$D:/:g" -e 's:/\+:/:g'` - else - mynewdependency_lib="$libdir/$name" - fi - # Do not add duplicates - if test "$mynewdependency_lib"; then - my_little_ninja_foo_1=`echo $newdependency_libs |$EGREP -e "$mynewdependency_lib"` - if test -z "$my_little_ninja_foo_1"; then - newdependency_libs="$newdependency_libs $mynewdependency_lib" - fi - fi - ;; - *) - if test "$installed" = yes; then - # Rather use S=WORKDIR if our version of portage supports it. - # This is because some ebuild (gcc) do not use $S as buildroot. - if test "$PWORKDIR"; then - S="$PWORKDIR" - fi - # We do not want portage's build root ($S) present. - my_little_ninja_foo_2=`echo $deplib |$EGREP -e "$S"` - # We do not want portage's install root ($D) present. - my_little_ninja_foo_3=`echo $deplib |$EGREP -e "$D"` - if test -n "$my_little_ninja_foo_2" && test "$S"; then - mynewdependency_lib="" - elif test -n "$my_little_ninja_foo_3" && test "$D"; then - eval mynewdependency_lib=`echo "$deplib" |sed -e "s:$D:/:g" -e 's:/\+:/:g'` - else - mynewdependency_lib="$deplib" - fi - else - mynewdependency_lib="$deplib" - fi - # Do not add duplicates - if test "$mynewdependency_lib"; then - my_little_ninja_foo_4=`echo $newdependency_libs |$EGREP -e "$mynewdependency_lib"` - if test -z "$my_little_ninja_foo_4"; then - newdependency_libs="$newdependency_libs $mynewdependency_lib" - fi - fi - ;; - esac - done - dependency_libs="$newdependency_libs" - newdlfiles= - for lib in $dlfiles; do - name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` - eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` - if test -z "$libdir"; then - $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 - exit $EXIT_FAILURE - fi - newdlfiles="$newdlfiles $libdir/$name" - done - dlfiles="$newdlfiles" - newdlprefiles= - for lib in $dlprefiles; do - name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` - eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` - if test -z "$libdir"; then - $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 - exit $EXIT_FAILURE - fi - newdlprefiles="$newdlprefiles $libdir/$name" - done - dlprefiles="$newdlprefiles" - else - newdlfiles= - for lib in $dlfiles; do - case $lib in - [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; - *) abs=`pwd`"/$lib" ;; - esac - newdlfiles="$newdlfiles $abs" - done - dlfiles="$newdlfiles" - newdlprefiles= - for lib in $dlprefiles; do - case $lib in - [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; - *) abs=`pwd`"/$lib" ;; - esac - newdlprefiles="$newdlprefiles $abs" - done - dlprefiles="$newdlprefiles" - fi - $rm $output - # place dlname in correct position for cygwin - tdlname=$dlname - case $host,$output,$installed,$module,$dlname in - *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; - esac - # Do not add duplicates - if test "$installed" = yes && test "$D"; then - install_libdir=`echo "$install_libdir" |sed -e "s:$D:/:g" -e 's:/\+:/:g'` - fi - $echo > $output "\ -# $outputname - a libtool library file -# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP -# -# Please DO NOT delete this file! -# It is necessary for linking the library. - -# The name that we can dlopen(3). -dlname='$tdlname' - -# Names of this library. -library_names='$library_names' - -# The name of the static archive. -old_library='$old_library' - -# Libraries that this one depends upon. -dependency_libs='$dependency_libs' - -# Version information for $libname. -current=$current -age=$age -revision=$revision - -# Is this an already installed library? -installed=$installed - -# Should we warn about portability when linking against -modules? -shouldnotlink=$module - -# Files to dlopen/dlpreopen -dlopen='$dlfiles' -dlpreopen='$dlprefiles' - -# Directory that this library needs to be installed in: -libdir='$install_libdir'" - if test "$installed" = no && test "$need_relink" = yes; then - $echo >> $output "\ -relink_command=\"$relink_command\"" - fi - done - fi - - # Do a symbolic link so that the libtool archive can be found in - # LD_LIBRARY_PATH before the program is installed. - $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" - $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? - ;; - esac - exit $EXIT_SUCCESS - ;; - - # libtool install mode - install) - modename="$modename: install" - - # There may be an optional sh(1) argument at the beginning of - # install_prog (especially on Windows NT). - if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || - # Allow the use of GNU shtool's install command. - $echo "X$nonopt" | grep shtool > /dev/null; then - # Aesthetically quote it. - arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - arg="\"$arg\"" - ;; - esac - install_prog="$arg " - arg="$1" - shift - else - install_prog= - arg=$nonopt - fi - - # The real first argument should be the name of the installation program. - # Aesthetically quote it. - arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - arg="\"$arg\"" - ;; - esac - install_prog="$install_prog$arg" - - # We need to accept at least all the BSD install flags. - dest= - files= - opts= - prev= - install_type= - isdir=no - stripme= - for arg - do - if test -n "$dest"; then - files="$files $dest" - dest=$arg - continue - fi - - case $arg in - -d) isdir=yes ;; - -f) - case " $install_prog " in - *[\\\ /]cp\ *) ;; - *) prev=$arg ;; - esac - ;; - -g | -m | -o) prev=$arg ;; - -s) - stripme=" -s" - continue - ;; - -*) - ;; - *) - # If the previous option needed an argument, then skip it. - if test -n "$prev"; then - prev= - else - dest=$arg - continue - fi - ;; - esac - - # Aesthetically quote the argument. - arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - arg="\"$arg\"" - ;; - esac - install_prog="$install_prog $arg" - done - - if test -z "$install_prog"; then - $echo "$modename: you must specify an install program" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - - if test -n "$prev"; then - $echo "$modename: the \`$prev' option requires an argument" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - - if test -z "$files"; then - if test -z "$dest"; then - $echo "$modename: no file or destination specified" 1>&2 - else - $echo "$modename: you must specify a destination" 1>&2 - fi - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - - # Strip any trailing slash from the destination. - dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` - - # Check to see that the destination is a directory. - test -d "$dest" && isdir=yes - if test "$isdir" = yes; then - destdir="$dest" - destname= - else - destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` - test "X$destdir" = "X$dest" && destdir=. - destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` - - # Not a directory, so check to see that there is only one file specified. - set dummy $files - if test "$#" -gt 2; then - $echo "$modename: \`$dest' is not a directory" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - fi - case $destdir in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - for file in $files; do - case $file in - *.lo) ;; - *) - $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - ;; - esac - done - ;; - esac - - # This variable tells wrapper scripts just to set variables rather - # than running their programs. - libtool_install_magic="$magic" - - staticlibs= - future_libdirs= - current_libdirs= - for file in $files; do - - # Do each installation. - case $file in - *.$libext) - # Do the static libraries later. - staticlibs="$staticlibs $file" - ;; - - *.la) - # Check to see that this really is a libtool archive. - if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : - else - $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - - library_names= - old_library= - relink_command= - # If there is no directory component, then add one. - case $file in - */* | *\\*) . $file ;; - *) . ./$file ;; - esac - - # Add the libdir to current_libdirs if it is the destination. - if test "X$destdir" = "X$libdir"; then - case "$current_libdirs " in - *" $libdir "*) ;; - *) current_libdirs="$current_libdirs $libdir" ;; - esac - else - # Note the libdir as a future libdir. - case "$future_libdirs " in - *" $libdir "*) ;; - *) future_libdirs="$future_libdirs $libdir" ;; - esac - fi - - dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ - test "X$dir" = "X$file/" && dir= - dir="$dir$objdir" - - if test -n "$relink_command"; then - # Determine the prefix the user has applied to our future dir. - inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"` - - # Don't allow the user to place us outside of our expected - # location b/c this prevents finding dependent libraries that - # are installed to the same prefix. - # At present, this check doesn't affect windows .dll's that - # are installed into $libdir/../bin (currently, that works fine) - # but it's something to keep an eye on. - if test "$inst_prefix_dir" = "$destdir"; then - $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2 - exit $EXIT_FAILURE - fi - - if test -n "$inst_prefix_dir"; then - # Stick the inst_prefix_dir data into the link command. - relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` - else - relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%%"` - fi - - $echo "$modename: warning: relinking \`$file'" 1>&2 - $show "$relink_command" - if $run eval "$relink_command"; then : - else - $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 - exit $EXIT_FAILURE - fi - fi - - # See the names of the shared library. - set dummy $library_names - if test -n "$2"; then - realname="$2" - shift - shift - - srcname="$realname" - test -n "$relink_command" && srcname="$realname"T - - # Install the shared library and build the symlinks. - $show "$install_prog $dir/$srcname $destdir/$realname" - $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? - if test -n "$stripme" && test -n "$striplib"; then - $show "$striplib $destdir/$realname" - $run eval "$striplib $destdir/$realname" || exit $? - fi - - if test "$#" -gt 0; then - # Delete the old symlinks, and create new ones. - # Try `ln -sf' first, because the `ln' binary might depend on - # the symlink we replace! Solaris /bin/ln does not understand -f, - # so we also need to try rm && ln -s. - for linkname - do - if test "$linkname" != "$realname"; then - $show "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" - $run eval "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" - fi - done - fi - - # Do each command in the postinstall commands. - lib="$destdir/$realname" - cmds=$postinstall_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || { - lt_exit=$? - - # Restore the uninstalled library and exit - if test "$mode" = relink; then - $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' - fi - - exit $lt_exit - } - done - IFS="$save_ifs" - fi - - # Install the pseudo-library for information purposes. - name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - instname="$dir/$name"i - $show "$install_prog $instname $destdir/$name" - $run eval "$install_prog $instname $destdir/$name" || exit $? - - # Maybe install the static library, too. - test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" - ;; - - *.lo) - # Install (i.e. copy) a libtool object. - - # Figure out destination file name, if it wasn't already specified. - if test -n "$destname"; then - destfile="$destdir/$destname" - else - destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - destfile="$destdir/$destfile" - fi - - # Deduce the name of the destination old-style object file. - case $destfile in - *.lo) - staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` - ;; - *.$objext) - staticdest="$destfile" - destfile= - ;; - *) - $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - ;; - esac - - # Install the libtool object if requested. - if test -n "$destfile"; then - $show "$install_prog $file $destfile" - $run eval "$install_prog $file $destfile" || exit $? - fi - - # Install the old object if enabled. - if test "$build_old_libs" = yes; then - # Deduce the name of the old-style object file. - staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` - - $show "$install_prog $staticobj $staticdest" - $run eval "$install_prog \$staticobj \$staticdest" || exit $? - fi - exit $EXIT_SUCCESS - ;; - - *) - # Figure out destination file name, if it wasn't already specified. - if test -n "$destname"; then - destfile="$destdir/$destname" - else - destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - destfile="$destdir/$destfile" - fi - - # If the file is missing, and there is a .exe on the end, strip it - # because it is most likely a libtool script we actually want to - # install - stripped_ext="" - case $file in - *.exe) - if test ! -f "$file"; then - file=`$echo $file|${SED} 's,.exe$,,'` - stripped_ext=".exe" - fi - ;; - esac - - # Do a test to see if this is really a libtool program. - case $host in - *cygwin*|*mingw*) - wrapper=`$echo $file | ${SED} -e 's,.exe$,,'` - ;; - *) - wrapper=$file - ;; - esac - if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then - notinst_deplibs= - relink_command= - - # Note that it is not necessary on cygwin/mingw to append a dot to - # foo even if both foo and FILE.exe exist: automatic-append-.exe - # behavior happens only for exec(3), not for open(2)! Also, sourcing - # `FILE.' does not work on cygwin managed mounts. - # - # If there is no directory component, then add one. - case $wrapper in - */* | *\\*) . ${wrapper} ;; - *) . ./${wrapper} ;; - esac - - # Check the variables that should have been set. - if test -z "$notinst_deplibs"; then - $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2 - exit $EXIT_FAILURE - fi - - finalize=yes - for lib in $notinst_deplibs; do - # Check to see that each library is installed. - libdir= - if test -f "$lib"; then - # If there is no directory component, then add one. - case $lib in - */* | *\\*) . $lib ;; - *) . ./$lib ;; - esac - fi - libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test - if test -n "$libdir" && test ! -f "$libfile"; then - $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 - finalize=no - fi - done - - relink_command= - # Note that it is not necessary on cygwin/mingw to append a dot to - # foo even if both foo and FILE.exe exist: automatic-append-.exe - # behavior happens only for exec(3), not for open(2)! Also, sourcing - # `FILE.' does not work on cygwin managed mounts. - # - # If there is no directory component, then add one. - case $wrapper in - */* | *\\*) . ${wrapper} ;; - *) . ./${wrapper} ;; - esac - - outputname= - if test "$fast_install" = no && test -n "$relink_command"; then - if test "$finalize" = yes && test -z "$run"; then - tmpdir=`func_mktempdir` - file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'` - outputname="$tmpdir/$file" - # Replace the output file specification. - relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` - - $show "$relink_command" - if $run eval "$relink_command"; then : - else - $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 - ${rm}r "$tmpdir" - continue - fi - file="$outputname" - else - $echo "$modename: warning: cannot relink \`$file'" 1>&2 - fi - else - # Install the binary that we compiled earlier. - file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` - fi - fi - - # remove .exe since cygwin /usr/bin/install will append another - # one anyway - case $install_prog,$host in - */usr/bin/install*,*cygwin*) - case $file:$destfile in - *.exe:*.exe) - # this is ok - ;; - *.exe:*) - destfile=$destfile.exe - ;; - *:*.exe) - destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'` - ;; - esac - ;; - esac - $show "$install_prog$stripme $file $destfile" - $run eval "$install_prog\$stripme \$file \$destfile" || exit $? - test -n "$outputname" && ${rm}r "$tmpdir" - ;; - esac - done - - for file in $staticlibs; do - name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - - # Set up the ranlib parameters. - oldlib="$destdir/$name" - - $show "$install_prog $file $oldlib" - $run eval "$install_prog \$file \$oldlib" || exit $? - - if test -n "$stripme" && test -n "$old_striplib"; then - $show "$old_striplib $oldlib" - $run eval "$old_striplib $oldlib" || exit $? - fi - - # Do each command in the postinstall commands. - cmds=$old_postinstall_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - done - - if test -n "$future_libdirs"; then - $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 - fi - - if test -n "$current_libdirs"; then - # Maybe just do a dry run. - test -n "$run" && current_libdirs=" -n$current_libdirs" - exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' - else - exit $EXIT_SUCCESS - fi - ;; - - # libtool finish mode - finish) - modename="$modename: finish" - libdirs="$nonopt" - admincmds= - - if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then - for dir - do - libdirs="$libdirs $dir" - done - - for libdir in $libdirs; do - if test -n "$finish_cmds"; then - # Do each command in the finish commands. - cmds=$finish_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || admincmds="$admincmds - $cmd" - done - IFS="$save_ifs" - fi - if test -n "$finish_eval"; then - # Do the single finish_eval. - eval cmds=\"$finish_eval\" - $run eval "$cmds" || admincmds="$admincmds - $cmds" - fi - done - fi - - # Exit here if they wanted silent mode. - test "$show" = : && exit $EXIT_SUCCESS - - $echo "X----------------------------------------------------------------------" | $Xsed - $echo "Libraries have been installed in:" - for libdir in $libdirs; do - $echo " $libdir" - done - $echo - $echo "If you ever happen to want to link against installed libraries" - $echo "in a given directory, LIBDIR, you must either use libtool, and" - $echo "specify the full pathname of the library, or use the \`-LLIBDIR'" - $echo "flag during linking and do at least one of the following:" - if test -n "$shlibpath_var"; then - $echo " - add LIBDIR to the \`$shlibpath_var' environment variable" - $echo " during execution" - fi - if test -n "$runpath_var"; then - $echo " - add LIBDIR to the \`$runpath_var' environment variable" - $echo " during linking" - fi - if test -n "$hardcode_libdir_flag_spec"; then - libdir=LIBDIR - eval flag=\"$hardcode_libdir_flag_spec\" - - $echo " - use the \`$flag' linker flag" - fi - if test -n "$admincmds"; then - $echo " - have your system administrator run these commands:$admincmds" - fi - if test -f /etc/ld.so.conf; then - $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" - fi - $echo - $echo "See any operating system documentation about shared libraries for" - $echo "more information, such as the ld(1) and ld.so(8) manual pages." - $echo "X----------------------------------------------------------------------" | $Xsed - exit $EXIT_SUCCESS - ;; - - # libtool execute mode - execute) - modename="$modename: execute" - - # The first argument is the command name. - cmd="$nonopt" - if test -z "$cmd"; then - $echo "$modename: you must specify a COMMAND" 1>&2 - $echo "$help" - exit $EXIT_FAILURE - fi - - # Handle -dlopen flags immediately. - for file in $execute_dlfiles; do - if test ! -f "$file"; then - $echo "$modename: \`$file' is not a file" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - - dir= - case $file in - *.la) - # Check to see that this really is a libtool archive. - if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : - else - $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - - # Read the libtool library. - dlname= - library_names= - - # If there is no directory component, then add one. - case $file in - */* | *\\*) . $file ;; - *) . ./$file ;; - esac - - # Skip this library if it cannot be dlopened. - if test -z "$dlname"; then - # Warn if it was a shared library. - test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" - continue - fi - - dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` - test "X$dir" = "X$file" && dir=. - - if test -f "$dir/$objdir/$dlname"; then - dir="$dir/$objdir" - else - $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 - exit $EXIT_FAILURE - fi - ;; - - *.lo) - # Just add the directory containing the .lo file. - dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` - test "X$dir" = "X$file" && dir=. - ;; - - *) - $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 - continue - ;; - esac - - # Get the absolute pathname. - absdir=`cd "$dir" && pwd` - test -n "$absdir" && dir="$absdir" - - # Now add the directory to shlibpath_var. - if eval "test -z \"\$$shlibpath_var\""; then - eval "$shlibpath_var=\"\$dir\"" - else - eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" - fi - done - - # This variable tells wrapper scripts just to set shlibpath_var - # rather than running their programs. - libtool_execute_magic="$magic" - - # Check if any of the arguments is a wrapper script. - args= - for file - do - case $file in - -*) ;; - *) - # Do a test to see if this is really a libtool program. - if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - # If there is no directory component, then add one. - case $file in - */* | *\\*) . $file ;; - *) . ./$file ;; - esac - - # Transform arg to wrapped name. - file="$progdir/$program" - fi - ;; - esac - # Quote arguments (to preserve shell metacharacters). - file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` - args="$args \"$file\"" - done - - if test -z "$run"; then - if test -n "$shlibpath_var"; then - # Export the shlibpath_var. - eval "export $shlibpath_var" - fi - - # Restore saved environment variables - if test "${save_LC_ALL+set}" = set; then - LC_ALL="$save_LC_ALL"; export LC_ALL - fi - if test "${save_LANG+set}" = set; then - LANG="$save_LANG"; export LANG - fi - - # Now prepare to actually exec the command. - exec_cmd="\$cmd$args" - else - # Display what would be done. - if test -n "$shlibpath_var"; then - eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" - $echo "export $shlibpath_var" - fi - $echo "$cmd$args" - exit $EXIT_SUCCESS - fi - ;; - - # libtool clean and uninstall mode - clean | uninstall) - modename="$modename: $mode" - rm="$nonopt" - files= - rmforce= - exit_status=0 - - # This variable tells wrapper scripts just to set variables rather - # than running their programs. - libtool_install_magic="$magic" - - for arg - do - case $arg in - -f) rm="$rm $arg"; rmforce=yes ;; - -*) rm="$rm $arg" ;; - *) files="$files $arg" ;; - esac - done - - if test -z "$rm"; then - $echo "$modename: you must specify an RM program" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - - rmdirs= - - origobjdir="$objdir" - for file in $files; do - dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` - if test "X$dir" = "X$file"; then - dir=. - objdir="$origobjdir" - else - objdir="$dir/$origobjdir" - fi - name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - test "$mode" = uninstall && objdir="$dir" - - # Remember objdir for removal later, being careful to avoid duplicates - if test "$mode" = clean; then - case " $rmdirs " in - *" $objdir "*) ;; - *) rmdirs="$rmdirs $objdir" ;; - esac - fi - - # Don't error if the file doesn't exist and rm -f was used. - if (test -L "$file") >/dev/null 2>&1 \ - || (test -h "$file") >/dev/null 2>&1 \ - || test -f "$file"; then - : - elif test -d "$file"; then - exit_status=1 - continue - elif test "$rmforce" = yes; then - continue - fi - - rmfiles="$file" - - case $name in - *.la) - # Possibly a libtool archive, so verify it. - if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - . $dir/$name - - # Delete the libtool libraries and symlinks. - for n in $library_names; do - rmfiles="$rmfiles $objdir/$n" - done - test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" - - case "$mode" in - clean) - case " $library_names " in - # " " in the beginning catches empty $dlname - *" $dlname "*) ;; - *) rmfiles="$rmfiles $objdir/$dlname" ;; - esac - test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" - ;; - uninstall) - if test -n "$library_names"; then - # Do each command in the postuninstall commands. - cmds=$postuninstall_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" - if test "$?" -ne 0 && test "$rmforce" != yes; then - exit_status=1 - fi - done - IFS="$save_ifs" - fi - - if test -n "$old_library"; then - # Do each command in the old_postuninstall commands. - cmds=$old_postuninstall_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" - if test "$?" -ne 0 && test "$rmforce" != yes; then - exit_status=1 - fi - done - IFS="$save_ifs" - fi - # FIXME: should reinstall the best remaining shared library. - ;; - esac - fi - ;; - - *.lo) - # Possibly a libtool object, so verify it. - if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - - # Read the .lo file - . $dir/$name - - # Add PIC object to the list of files to remove. - if test -n "$pic_object" \ - && test "$pic_object" != none; then - rmfiles="$rmfiles $dir/$pic_object" - fi - - # Add non-PIC object to the list of files to remove. - if test -n "$non_pic_object" \ - && test "$non_pic_object" != none; then - rmfiles="$rmfiles $dir/$non_pic_object" - fi - fi - ;; - - *) - if test "$mode" = clean ; then - noexename=$name - case $file in - *.exe) - file=`$echo $file|${SED} 's,.exe$,,'` - noexename=`$echo $name|${SED} 's,.exe$,,'` - # $file with .exe has already been added to rmfiles, - # add $file without .exe - rmfiles="$rmfiles $file" - ;; - esac - # Do a test to see if this is a libtool program. - if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - relink_command= - . $dir/$noexename - - # note $name still contains .exe if it was in $file originally - # as does the version of $file that was added into $rmfiles - rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" - if test "$fast_install" = yes && test -n "$relink_command"; then - rmfiles="$rmfiles $objdir/lt-$name" - fi - if test "X$noexename" != "X$name" ; then - rmfiles="$rmfiles $objdir/lt-${noexename}.c" - fi - fi - fi - ;; - esac - $show "$rm $rmfiles" - $run $rm $rmfiles || exit_status=1 - done - objdir="$origobjdir" - - # Try to remove the ${objdir}s in the directories where we deleted files - for dir in $rmdirs; do - if test -d "$dir"; then - $show "rmdir $dir" - $run rmdir $dir >/dev/null 2>&1 - fi - done - - exit $exit_status - ;; - - "") - $echo "$modename: you must specify a MODE" 1>&2 - $echo "$generic_help" 1>&2 - exit $EXIT_FAILURE - ;; - esac - - if test -z "$exec_cmd"; then - $echo "$modename: invalid operation mode \`$mode'" 1>&2 - $echo "$generic_help" 1>&2 - exit $EXIT_FAILURE - fi -fi # test -z "$show_help" - -if test -n "$exec_cmd"; then - eval exec $exec_cmd - exit $EXIT_FAILURE -fi - -# We need to display help for each of the modes. -case $mode in -"") $echo \ -"Usage: $modename [OPTION]... [MODE-ARG]... - -Provide generalized library-building support services. - - --config show all configuration variables - --debug enable verbose shell tracing --n, --dry-run display commands without modifying any files - --features display basic configuration information and exit - --finish same as \`--mode=finish' - --help display this help message and exit - --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] - --quiet same as \`--silent' - --silent don't print informational messages - --tag=TAG use configuration variables from tag TAG - --version print version information - -MODE must be one of the following: - - clean remove files from the build directory - compile compile a source file into a libtool object - execute automatically set library path, then run a program - finish complete the installation of libtool libraries - install install libraries or executables - link create a library or an executable - uninstall remove libraries from an installed directory - -MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for -a more detailed description of MODE. - -Report bugs to <bug-libtool@gnu.org>." - exit $EXIT_SUCCESS - ;; - -clean) - $echo \ -"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... - -Remove files from the build directory. - -RM is the name of the program to use to delete files associated with each FILE -(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed -to RM. - -If FILE is a libtool library, object or program, all the files associated -with it are deleted. Otherwise, only FILE itself is deleted using RM." - ;; - -compile) - $echo \ -"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE - -Compile a source file into a libtool library object. - -This mode accepts the following additional options: - - -o OUTPUT-FILE set the output file name to OUTPUT-FILE - -prefer-pic try to building PIC objects only - -prefer-non-pic try to building non-PIC objects only - -static always build a \`.o' file suitable for static linking - -COMPILE-COMMAND is a command to be used in creating a \`standard' object file -from the given SOURCEFILE. - -The output file name is determined by removing the directory component from -SOURCEFILE, then substituting the C source code suffix \`.c' with the -library object suffix, \`.lo'." - ;; - -execute) - $echo \ -"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... - -Automatically set library path, then run a program. - -This mode accepts the following additional options: - - -dlopen FILE add the directory containing FILE to the library path - -This mode sets the library path environment variable according to \`-dlopen' -flags. - -If any of the ARGS are libtool executable wrappers, then they are translated -into their corresponding uninstalled binary, and any of their required library -directories are added to the library path. - -Then, COMMAND is executed, with ARGS as arguments." - ;; - -finish) - $echo \ -"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... - -Complete the installation of libtool libraries. - -Each LIBDIR is a directory that contains libtool libraries. - -The commands that this mode executes may require superuser privileges. Use -the \`--dry-run' option if you just want to see what would be executed." - ;; - -install) - $echo \ -"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... - -Install executables or libraries. - -INSTALL-COMMAND is the installation command. The first component should be -either the \`install' or \`cp' program. - -The rest of the components are interpreted as arguments to that command (only -BSD-compatible install options are recognized)." - ;; - -link) - $echo \ -"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... - -Link object files or libraries together to form another library, or to -create an executable program. - -LINK-COMMAND is a command using the C compiler that you would use to create -a program from several object files. - -The following components of LINK-COMMAND are treated specially: - - -all-static do not do any dynamic linking at all - -avoid-version do not add a version suffix if possible - -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime - -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols - -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) - -export-symbols SYMFILE - try to export only the symbols listed in SYMFILE - -export-symbols-regex REGEX - try to export only the symbols matching REGEX - -LLIBDIR search LIBDIR for required installed libraries - -lNAME OUTPUT-FILE requires the installed library libNAME - -module build a library that can dlopened - -no-fast-install disable the fast-install mode - -no-install link a not-installable executable - -no-undefined declare that a library does not refer to external symbols - -o OUTPUT-FILE create OUTPUT-FILE from the specified objects - -objectlist FILE Use a list of object files found in FILE to specify objects - -precious-files-regex REGEX - don't remove output files matching REGEX - -release RELEASE specify package release information - -rpath LIBDIR the created library will eventually be installed in LIBDIR - -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries - -static do not do any dynamic linking of libtool libraries - -version-info CURRENT[:REVISION[:AGE]] - specify library version info [each variable defaults to 0] - -All other options (arguments beginning with \`-') are ignored. - -Every other argument is treated as a filename. Files ending in \`.la' are -treated as uninstalled libtool libraries, other files are standard or library -object files. - -If the OUTPUT-FILE ends in \`.la', then a libtool library is created, -only library objects (\`.lo' files) may be specified, and \`-rpath' is -required, except when creating a convenience library. - -If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created -using \`ar' and \`ranlib', or on Windows using \`lib'. - -If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file -is created, otherwise an executable program is created." - ;; - -uninstall) - $echo \ -"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... - -Remove libraries from an installation directory. - -RM is the name of the program to use to delete files associated with each FILE -(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed -to RM. - -If FILE is a libtool library, all the files associated with it are deleted. -Otherwise, only FILE itself is deleted using RM." - ;; - -*) - $echo "$modename: invalid operation mode \`$mode'" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - ;; -esac - -$echo -$echo "Try \`$modename --help' for more information about other modes." - -exit $? - -# The TAGs below are defined such that we never get into a situation -# in which we disable both kinds of libraries. Given conflicting -# choices, we go for a static library, that is the most portable, -# since we can't tell whether shared libraries were disabled because -# the user asked for that or because the platform doesn't support -# them. This is particularly important on AIX, because we don't -# support having both static and shared libraries enabled at the same -# time on that platform, so we default to a shared-only configuration. -# If a disable-shared tag is given, we'll fallback to a static-only -# configuration. But we'll never go from static-only to shared-only. - -# ### BEGIN LIBTOOL TAG CONFIG: disable-shared -disable_libs=shared -# ### END LIBTOOL TAG CONFIG: disable-shared - -# ### BEGIN LIBTOOL TAG CONFIG: disable-static -disable_libs=static -# ### END LIBTOOL TAG CONFIG: disable-static - -# Local Variables: -# mode:shell-script -# sh-indentation:2 -# End: diff --git a/tests/examplefiles/perlfunc.1 b/tests/examplefiles/perlfunc.1 index 43fcd88b..01413c99 100644 --- a/tests/examplefiles/perlfunc.1 +++ b/tests/examplefiles/perlfunc.1 @@ -3367,4505 +3367,4 @@ conversion assumes base 10.) .IP "open \s-1FILEHANDLE\s0" 8 .IX Item "open FILEHANDLE" .PD -Opens the file whose filename is given by \s-1EXPR\s0, and associates it with -\&\s-1FILEHANDLE\s0. -.Sp -(The following is a comprehensive reference to \fIopen()\fR: for a gentler -introduction you may consider perlopentut.) -.Sp -If \s-1FILEHANDLE\s0 is an undefined scalar variable (or array or hash element) -the variable is assigned a reference to a new anonymous filehandle, -otherwise if \s-1FILEHANDLE\s0 is an expression, its value is used as the name of -the real filehandle wanted. (This is considered a symbolic reference, so -\&\f(CW\*(C`use strict 'refs'\*(C'\fR should \fInot\fR be in effect.) -.Sp -If \s-1EXPR\s0 is omitted, the scalar variable of the same name as the -\&\s-1FILEHANDLE\s0 contains the filename. (Note that lexical variables\*(--those -declared with \f(CW\*(C`my\*(C'\fR\-\-will not work for this purpose; so if you're -using \f(CW\*(C`my\*(C'\fR, specify \s-1EXPR\s0 in your call to open.) -.Sp -If three or more arguments are specified then the mode of opening and -the file name are separate. If \s-1MODE\s0 is \f(CW'<'\fR or nothing, the file -is opened for input. If \s-1MODE\s0 is \f(CW'>'\fR, the file is truncated and -opened for output, being created if necessary. If \s-1MODE\s0 is \f(CW'>>'\fR, -the file is opened for appending, again being created if necessary. -.Sp -You can put a \f(CW'+'\fR in front of the \f(CW'>'\fR or \f(CW'<'\fR to -indicate that you want both read and write access to the file; thus -\&\f(CW'+<'\fR is almost always preferred for read/write updates\*(--the \f(CW'+>'\fR mode would clobber the file first. You can't usually use -either read-write mode for updating textfiles, since they have -variable length records. See the \fB\-i\fR switch in perlrun for a -better approach. The file is created with permissions of \f(CW0666\fR -modified by the process' \f(CW\*(C`umask\*(C'\fR value. -.Sp -These various prefixes correspond to the \fIfopen\fR\|(3) modes of \f(CW'r'\fR, -\&\f(CW'r+'\fR, \f(CW'w'\fR, \f(CW'w+'\fR, \f(CW'a'\fR, and \f(CW'a+'\fR. -.Sp -In the 2\-arguments (and 1\-argument) form of the call the mode and -filename should be concatenated (in this order), possibly separated by -spaces. It is possible to omit the mode in these forms if the mode is -\&\f(CW'<'\fR. -.Sp -If the filename begins with \f(CW'|'\fR, the filename is interpreted as a -command to which output is to be piped, and if the filename ends with a -\&\f(CW'|'\fR, the filename is interpreted as a command which pipes output to -us. See \*(L"Using \fIopen()\fR for \s-1IPC\s0\*(R" in perlipc -for more examples of this. (You are not allowed to \f(CW\*(C`open\*(C'\fR to a command -that pipes both in \fIand\fR out, but see IPC::Open2, IPC::Open3, -and \*(L"Bidirectional Communication with Another Process\*(R" in perlipc -for alternatives.) -.Sp -For three or more arguments if \s-1MODE\s0 is \f(CW'|\-'\fR, the filename is -interpreted as a command to which output is to be piped, and if \s-1MODE\s0 -is \f(CW'\-|'\fR, the filename is interpreted as a command which pipes -output to us. In the 2\-arguments (and 1\-argument) form one should -replace dash (\f(CW'\-'\fR) with the command. -See \*(L"Using \fIopen()\fR for \s-1IPC\s0\*(R" in perlipc for more examples of this. -(You are not allowed to \f(CW\*(C`open\*(C'\fR to a command that pipes both in \fIand\fR -out, but see IPC::Open2, IPC::Open3, and -\&\*(L"Bidirectional Communication\*(R" in perlipc for alternatives.) -.Sp -In the three-or-more argument form of pipe opens, if \s-1LIST\s0 is specified -(extra arguments after the command name) then \s-1LIST\s0 becomes arguments -to the command invoked if the platform supports it. The meaning of -\&\f(CW\*(C`open\*(C'\fR with more than three arguments for non-pipe modes is not yet -specified. Experimental \*(L"layers\*(R" may give extra \s-1LIST\s0 arguments -meaning. -.Sp -In the 2\-arguments (and 1\-argument) form opening \f(CW'\-'\fR opens \s-1STDIN\s0 -and opening \f(CW'>\-'\fR opens \s-1STDOUT\s0. -.Sp -You may use the three-argument form of open to specify \s-1IO\s0 \*(L"layers\*(R" -(sometimes also referred to as \*(L"disciplines\*(R") to be applied to the handle -that affect how the input and output are processed (see open and -PerlIO for more details). For example -.Sp -.Vb 1 -\& open(FH, "<:utf8", "file") -.Ve -.Sp -will open the \s-1UTF\-8\s0 encoded file containing Unicode characters, -see perluniintro. Note that if layers are specified in the -three-arg form then default layers stored in ${^OPEN} (see perlvar; -usually set by the \fBopen\fR pragma or the switch \fB\-CioD\fR) are ignored. -.Sp -Open returns nonzero upon success, the undefined value otherwise. If -the \f(CW\*(C`open\*(C'\fR involved a pipe, the return value happens to be the pid of -the subprocess. -.Sp -If you're running Perl on a system that distinguishes between text -files and binary files, then you should check out \*(L"binmode\*(R" for tips -for dealing with this. The key distinction between systems that need -\&\f(CW\*(C`binmode\*(C'\fR and those that don't is their text file formats. Systems -like Unix, Mac \s-1OS\s0, and Plan 9, which delimit lines with a single -character, and which encode that character in C as \f(CW"\en"\fR, do not -need \f(CW\*(C`binmode\*(C'\fR. The rest need it. -.Sp -When opening a file, it's usually a bad idea to continue normal execution -if the request failed, so \f(CW\*(C`open\*(C'\fR is frequently used in connection with -\&\f(CW\*(C`die\*(C'\fR. Even if \f(CW\*(C`die\*(C'\fR won't do what you want (say, in a \s-1CGI\s0 script, -where you want to make a nicely formatted error message (but there are -modules that can help with that problem)) you should always check -the return value from opening a file. The infrequent exception is when -working with an unopened filehandle is actually what you want to do. -.Sp -As a special case the 3\-arg form with a read/write mode and the third -argument being \f(CW\*(C`undef\*(C'\fR: -.Sp -.Vb 1 -\& open(TMP, "+>", undef) or die ... -.Ve -.Sp -opens a filehandle to an anonymous temporary file. Also using \*(L"+<\*(R" -works for symmetry, but you really should consider writing something -to the temporary file first. You will need to \fIseek()\fR to do the -reading. -.Sp -Since v5.8.0, perl has built using PerlIO by default. Unless you've -changed this (i.e. Configure \-Uuseperlio), you can open file handles to -\&\*(L"in memory\*(R" files held in Perl scalars via: -.Sp -.Vb 1 -\& open($fh, '>', \e$variable) || .. -.Ve -.Sp -Though if you try to re-open \f(CW\*(C`STDOUT\*(C'\fR or \f(CW\*(C`STDERR\*(C'\fR as an \*(L"in memory\*(R" -file, you have to close it first: -.Sp -.Vb 2 -\& close STDOUT; -\& open STDOUT, '>', \e$variable or die "Can't open STDOUT: $!"; -.Ve -.Sp -Examples: -.Sp -.Vb 3 -\& $ARTICLE = 100; -\& open ARTICLE or die "Can't find article $ARTICLE: $!\en"; -\& while (<ARTICLE>) {... -.Ve -.Sp -.Vb 2 -\& open(LOG, '>>/usr/spool/news/twitlog'); # (log is reserved) -\& # if the open fails, output is discarded -.Ve -.Sp -.Vb 2 -\& open(DBASE, '+<', 'dbase.mine') # open for update -\& or die "Can't open 'dbase.mine' for update: $!"; -.Ve -.Sp -.Vb 2 -\& open(DBASE, '+<dbase.mine') # ditto -\& or die "Can't open 'dbase.mine' for update: $!"; -.Ve -.Sp -.Vb 2 -\& open(ARTICLE, '-|', "caesar <$article") # decrypt article -\& or die "Can't start caesar: $!"; -.Ve -.Sp -.Vb 2 -\& open(ARTICLE, "caesar <$article |") # ditto -\& or die "Can't start caesar: $!"; -.Ve -.Sp -.Vb 2 -\& open(EXTRACT, "|sort >Tmp$$") # $$ is our process id -\& or die "Can't start sort: $!"; -.Ve -.Sp -.Vb 4 -\& # in memory files -\& open(MEMORY,'>', \e$var) -\& or die "Can't open memory file: $!"; -\& print MEMORY "foo!\en"; # output will end up in $var -.Ve -.Sp -.Vb 1 -\& # process argument list of files along with any includes -.Ve -.Sp -.Vb 3 -\& foreach $file (@ARGV) { -\& process($file, 'fh00'); -\& } -.Ve -.Sp -.Vb 7 -\& sub process { -\& my($filename, $input) = @_; -\& $input++; # this is a string increment -\& unless (open($input, $filename)) { -\& print STDERR "Can't open $filename: $!\en"; -\& return; -\& } -.Ve -.Sp -.Vb 9 -\& local $_; -\& while (<$input>) { # note use of indirection -\& if (/^#include "(.*)"/) { -\& process($1, $input); -\& next; -\& } -\& #... # whatever -\& } -\& } -.Ve -.Sp -See perliol for detailed info on PerlIO. -.Sp -You may also, in the Bourne shell tradition, specify an \s-1EXPR\s0 beginning -with \f(CW'>&'\fR, in which case the rest of the string is interpreted -as the name of a filehandle (or file descriptor, if numeric) to be -duped (as \fIdup\fR\|(2)) and opened. You may use \f(CW\*(C`&\*(C'\fR after \f(CW\*(C`>\*(C'\fR, -\&\f(CW\*(C`>>\*(C'\fR, \f(CW\*(C`<\*(C'\fR, \f(CW\*(C`+>\*(C'\fR, \f(CW\*(C`+>>\*(C'\fR, and \f(CW\*(C`+<\*(C'\fR. -The mode you specify should match the mode of the original filehandle. -(Duping a filehandle does not take into account any existing contents -of \s-1IO\s0 buffers.) If you use the 3\-arg form then you can pass either a -number, the name of a filehandle or the normal \*(L"reference to a glob\*(R". -.Sp -Here is a script that saves, redirects, and restores \f(CW\*(C`STDOUT\*(C'\fR and -\&\f(CW\*(C`STDERR\*(C'\fR using various methods: -.Sp -.Vb 3 -\& #!/usr/bin/perl -\& open my $oldout, ">&STDOUT" or die "Can't dup STDOUT: $!"; -\& open OLDERR, ">&", \e*STDERR or die "Can't dup STDERR: $!"; -.Ve -.Sp -.Vb 2 -\& open STDOUT, '>', "foo.out" or die "Can't redirect STDOUT: $!"; -\& open STDERR, ">&STDOUT" or die "Can't dup STDOUT: $!"; -.Ve -.Sp -.Vb 2 -\& select STDERR; $| = 1; # make unbuffered -\& select STDOUT; $| = 1; # make unbuffered -.Ve -.Sp -.Vb 2 -\& print STDOUT "stdout 1\en"; # this works for -\& print STDERR "stderr 1\en"; # subprocesses too -.Ve -.Sp -.Vb 2 -\& open STDOUT, ">&", $oldout or die "Can't dup \e$oldout: $!"; -\& open STDERR, ">&OLDERR" or die "Can't dup OLDERR: $!"; -.Ve -.Sp -.Vb 2 -\& print STDOUT "stdout 2\en"; -\& print STDERR "stderr 2\en"; -.Ve -.Sp -If you specify \f(CW'<&=X'\fR, where \f(CW\*(C`X\*(C'\fR is a file descriptor number -or a filehandle, then Perl will do an equivalent of C's \f(CW\*(C`fdopen\*(C'\fR of -that file descriptor (and not call \fIdup\fR\|(2)); this is more -parsimonious of file descriptors. For example: -.Sp -.Vb 2 -\& # open for input, reusing the fileno of $fd -\& open(FILEHANDLE, "<&=$fd") -.Ve -.Sp -or -.Sp -.Vb 1 -\& open(FILEHANDLE, "<&=", $fd) -.Ve -.Sp -or -.Sp -.Vb 2 -\& # open for append, using the fileno of OLDFH -\& open(FH, ">>&=", OLDFH) -.Ve -.Sp -or -.Sp -.Vb 1 -\& open(FH, ">>&=OLDFH") -.Ve -.Sp -Being parsimonious on filehandles is also useful (besides being -parsimonious) for example when something is dependent on file -descriptors, like for example locking using \fIflock()\fR. If you do just -\&\f(CW\*(C`open(A, '>>&B')\*(C'\fR, the filehandle A will not have the same file -descriptor as B, and therefore flock(A) will not flock(B), and vice -versa. But with \f(CW\*(C`open(A, '>>&=B')\*(C'\fR the filehandles will share -the same file descriptor. -.Sp -Note that if you are using Perls older than 5.8.0, Perl will be using -the standard C libraries' \fIfdopen()\fR to implement the \*(L"=\*(R" functionality. -On many \s-1UNIX\s0 systems \fIfdopen()\fR fails when file descriptors exceed a -certain value, typically 255. For Perls 5.8.0 and later, PerlIO is -most often the default. -.Sp -You can see whether Perl has been compiled with PerlIO or not by -running \f(CW\*(C`perl \-V\*(C'\fR and looking for \f(CW\*(C`useperlio=\*(C'\fR line. If \f(CW\*(C`useperlio\*(C'\fR -is \f(CW\*(C`define\*(C'\fR, you have PerlIO, otherwise you don't. -.Sp -If you open a pipe on the command \f(CW'\-'\fR, i.e., either \f(CW'|\-'\fR or \f(CW'\-|'\fR -with 2\-arguments (or 1\-argument) form of \fIopen()\fR, then -there is an implicit fork done, and the return value of open is the pid -of the child within the parent process, and \f(CW0\fR within the child -process. (Use \f(CW\*(C`defined($pid)\*(C'\fR to determine whether the open was successful.) -The filehandle behaves normally for the parent, but i/o to that -filehandle is piped from/to the \s-1STDOUT/STDIN\s0 of the child process. -In the child process the filehandle isn't opened\*(--i/o happens from/to -the new \s-1STDOUT\s0 or \s-1STDIN\s0. Typically this is used like the normal -piped open when you want to exercise more control over just how the -pipe command gets executed, such as when you are running setuid, and -don't want to have to scan shell commands for metacharacters. -The following triples are more or less equivalent: -.Sp -.Vb 4 -\& open(FOO, "|tr '[a-z]' '[A-Z]'"); -\& open(FOO, '|-', "tr '[a-z]' '[A-Z]'"); -\& open(FOO, '|-') || exec 'tr', '[a-z]', '[A-Z]'; -\& open(FOO, '|-', "tr", '[a-z]', '[A-Z]'); -.Ve -.Sp -.Vb 4 -\& open(FOO, "cat -n '$file'|"); -\& open(FOO, '-|', "cat -n '$file'"); -\& open(FOO, '-|') || exec 'cat', '-n', $file; -\& open(FOO, '-|', "cat", '-n', $file); -.Ve -.Sp -The last example in each block shows the pipe as \*(L"list form\*(R", which is -not yet supported on all platforms. A good rule of thumb is that if -your platform has true \f(CW\*(C`fork()\*(C'\fR (in other words, if your platform is -\&\s-1UNIX\s0) you can use the list form. -.Sp -See \*(L"Safe Pipe Opens\*(R" in perlipc for more examples of this. -.Sp -Beginning with v5.6.0, Perl will attempt to flush all files opened for -output before any operation that may do a fork, but this may not be -supported on some platforms (see perlport). To be safe, you may need -to set \f(CW$|\fR ($AUTOFLUSH in English) or call the \f(CW\*(C`autoflush()\*(C'\fR method -of \f(CW\*(C`IO::Handle\*(C'\fR on any open handles. -.Sp -On systems that support a close-on-exec flag on files, the flag will -be set for the newly opened file descriptor as determined by the value -of $^F. See \*(L"$^F\*(R" in perlvar. -.Sp -Closing any piped filehandle causes the parent process to wait for the -child to finish, and returns the status value in \f(CW$?\fR. -.Sp -The filename passed to 2\-argument (or 1\-argument) form of \fIopen()\fR will -have leading and trailing whitespace deleted, and the normal -redirection characters honored. This property, known as \*(L"magic open\*(R", -can often be used to good effect. A user could specify a filename of -\&\fI\*(L"rsh cat file |\*(R"\fR, or you could change certain filenames as needed: -.Sp -.Vb 2 -\& $filename =~ s/(.*\e.gz)\es*$/gzip -dc < $1|/; -\& open(FH, $filename) or die "Can't open $filename: $!"; -.Ve -.Sp -Use 3\-argument form to open a file with arbitrary weird characters in it, -.Sp -.Vb 1 -\& open(FOO, '<', $file); -.Ve -.Sp -otherwise it's necessary to protect any leading and trailing whitespace: -.Sp -.Vb 2 -\& $file =~ s#^(\es)#./$1#; -\& open(FOO, "< $file\e0"); -.Ve -.Sp -(this may not work on some bizarre filesystems). One should -conscientiously choose between the \fImagic\fR and 3\-arguments form -of \fIopen()\fR: -.Sp -.Vb 1 -\& open IN, $ARGV[0]; -.Ve -.Sp -will allow the user to specify an argument of the form \f(CW"rsh cat file |"\fR, -but will not work on a filename which happens to have a trailing space, while -.Sp -.Vb 1 -\& open IN, '<', $ARGV[0]; -.Ve -.Sp -will have exactly the opposite restrictions. -.Sp -If you want a \*(L"real\*(R" C \f(CW\*(C`open\*(C'\fR (see \fIopen\fR\|(2) on your system), then you -should use the \f(CW\*(C`sysopen\*(C'\fR function, which involves no such magic (but -may use subtly different filemodes than Perl \fIopen()\fR, which is mapped -to C \fIfopen()\fR). This is -another way to protect your filenames from interpretation. For example: -.Sp -.Vb 7 -\& use IO::Handle; -\& sysopen(HANDLE, $path, O_RDWR|O_CREAT|O_EXCL) -\& or die "sysopen $path: $!"; -\& $oldfh = select(HANDLE); $| = 1; select($oldfh); -\& print HANDLE "stuff $$\en"; -\& seek(HANDLE, 0, 0); -\& print "File contains: ", <HANDLE>; -.Ve -.Sp -Using the constructor from the \f(CW\*(C`IO::Handle\*(C'\fR package (or one of its -subclasses, such as \f(CW\*(C`IO::File\*(C'\fR or \f(CW\*(C`IO::Socket\*(C'\fR), you can generate anonymous -filehandles that have the scope of whatever variables hold references to -them, and automatically close whenever and however you leave that scope: -.Sp -.Vb 12 -\& use IO::File; -\& #... -\& sub read_myfile_munged { -\& my $ALL = shift; -\& my $handle = new IO::File; -\& open($handle, "myfile") or die "myfile: $!"; -\& $first = <$handle> -\& or return (); # Automatically closed here. -\& mung $first or die "mung failed"; # Or here. -\& return $first, <$handle> if $ALL; # Or here. -\& $first; # Or here. -\& } -.Ve -.Sp -See \*(L"seek\*(R" for some details about mixing reading and writing. -.IP "opendir \s-1DIRHANDLE\s0,EXPR" 8 -.IX Xref "opendir" -.IX Item "opendir DIRHANDLE,EXPR" -Opens a directory named \s-1EXPR\s0 for processing by \f(CW\*(C`readdir\*(C'\fR, \f(CW\*(C`telldir\*(C'\fR, -\&\f(CW\*(C`seekdir\*(C'\fR, \f(CW\*(C`rewinddir\*(C'\fR, and \f(CW\*(C`closedir\*(C'\fR. Returns true if successful. -\&\s-1DIRHANDLE\s0 may be an expression whose value can be used as an indirect -dirhandle, usually the real dirhandle name. If \s-1DIRHANDLE\s0 is an undefined -scalar variable (or array or hash element), the variable is assigned a -reference to a new anonymous dirhandle. -DIRHANDLEs have their own namespace separate from FILEHANDLEs. -.IP "ord \s-1EXPR\s0" 8 -.IX Xref "ord encoding" -.IX Item "ord EXPR" -.PD 0 -.IP "ord" 8 -.IX Item "ord" -.PD -Returns the numeric (the native 8\-bit encoding, like \s-1ASCII\s0 or \s-1EBCDIC\s0, -or Unicode) value of the first character of \s-1EXPR\s0. If \s-1EXPR\s0 is omitted, -uses \f(CW$_\fR. -.Sp -For the reverse, see \*(L"chr\*(R". -See perlunicode and encoding for more about Unicode. -.IP "our \s-1EXPR\s0" 8 -.IX Xref "our global" -.IX Item "our EXPR" -.PD 0 -.IP "our \s-1EXPR\s0 \s-1TYPE\s0" 8 -.IX Item "our EXPR TYPE" -.IP "our \s-1EXPR\s0 : \s-1ATTRS\s0" 8 -.IX Item "our EXPR : ATTRS" -.IP "our \s-1TYPE\s0 \s-1EXPR\s0 : \s-1ATTRS\s0" 8 -.IX Item "our TYPE EXPR : ATTRS" -.PD -\&\f(CW\*(C`our\*(C'\fR associates a simple name with a package variable in the current -package for use within the current scope. When \f(CW\*(C`use strict 'vars'\*(C'\fR is in -effect, \f(CW\*(C`our\*(C'\fR lets you use declared global variables without qualifying -them with package names, within the lexical scope of the \f(CW\*(C`our\*(C'\fR declaration. -In this way \f(CW\*(C`our\*(C'\fR differs from \f(CW\*(C`use vars\*(C'\fR, which is package scoped. -.Sp -Unlike \f(CW\*(C`my\*(C'\fR, which both allocates storage for a variable and associates -a simple name with that storage for use within the current scope, \f(CW\*(C`our\*(C'\fR -associates a simple name with a package variable in the current package, -for use within the current scope. In other words, \f(CW\*(C`our\*(C'\fR has the same -scoping rules as \f(CW\*(C`my\*(C'\fR, but does not necessarily create a -variable. -.Sp -If more than one value is listed, the list must be placed -in parentheses. -.Sp -.Vb 2 -\& our $foo; -\& our($bar, $baz); -.Ve -.Sp -An \f(CW\*(C`our\*(C'\fR declaration declares a global variable that will be visible -across its entire lexical scope, even across package boundaries. The -package in which the variable is entered is determined at the point -of the declaration, not at the point of use. This means the following -behavior holds: -.Sp -.Vb 3 -\& package Foo; -\& our $bar; # declares $Foo::bar for rest of lexical scope -\& $bar = 20; -.Ve -.Sp -.Vb 2 -\& package Bar; -\& print $bar; # prints 20, as it refers to $Foo::bar -.Ve -.Sp -Multiple \f(CW\*(C`our\*(C'\fR declarations with the same name in the same lexical -scope are allowed if they are in different packages. If they happen -to be in the same package, Perl will emit warnings if you have asked -for them, just like multiple \f(CW\*(C`my\*(C'\fR declarations. Unlike a second -\&\f(CW\*(C`my\*(C'\fR declaration, which will bind the name to a fresh variable, a -second \f(CW\*(C`our\*(C'\fR declaration in the same package, in the same scope, is -merely redundant. -.Sp -.Vb 4 -\& use warnings; -\& package Foo; -\& our $bar; # declares $Foo::bar for rest of lexical scope -\& $bar = 20; -.Ve -.Sp -.Vb 3 -\& package Bar; -\& our $bar = 30; # declares $Bar::bar for rest of lexical scope -\& print $bar; # prints 30 -.Ve -.Sp -.Vb 2 -\& our $bar; # emits warning but has no other effect -\& print $bar; # still prints 30 -.Ve -.Sp -An \f(CW\*(C`our\*(C'\fR declaration may also have a list of attributes associated -with it. -.Sp -The exact semantics and interface of \s-1TYPE\s0 and \s-1ATTRS\s0 are still -evolving. \s-1TYPE\s0 is currently bound to the use of \f(CW\*(C`fields\*(C'\fR pragma, -and attributes are handled using the \f(CW\*(C`attributes\*(C'\fR pragma, or starting -from Perl 5.8.0 also via the \f(CW\*(C`Attribute::Handlers\*(C'\fR module. See -\&\*(L"Private Variables via \fImy()\fR\*(R" in perlsub for details, and fields, -attributes, and Attribute::Handlers. -.Sp -The only currently recognized \f(CW\*(C`our()\*(C'\fR attribute is \f(CW\*(C`unique\*(C'\fR which -indicates that a single copy of the global is to be used by all -interpreters should the program happen to be running in a -multi-interpreter environment. (The default behaviour would be for -each interpreter to have its own copy of the global.) Examples: -.Sp -.Vb 3 -\& our @EXPORT : unique = qw(foo); -\& our %EXPORT_TAGS : unique = (bar => [qw(aa bb cc)]); -\& our $VERSION : unique = "1.00"; -.Ve -.Sp -Note that this attribute also has the effect of making the global -readonly when the first new interpreter is cloned (for example, -when the first new thread is created). -.Sp -Multi-interpreter environments can come to being either through the -\&\fIfork()\fR emulation on Windows platforms, or by embedding perl in a -multi-threaded application. The \f(CW\*(C`unique\*(C'\fR attribute does nothing in -all other environments. -.Sp -Warning: the current implementation of this attribute operates on the -typeglob associated with the variable; this means that \f(CW\*(C`our $x : unique\*(C'\fR -also has the effect of \f(CW\*(C`our @x : unique; our %x : unique\*(C'\fR. This may be -subject to change. -.IP "pack \s-1TEMPLATE\s0,LIST" 8 -.IX Xref "pack" -.IX Item "pack TEMPLATE,LIST" -Takes a \s-1LIST\s0 of values and converts it into a string using the rules -given by the \s-1TEMPLATE\s0. The resulting string is the concatenation of -the converted values. Typically, each converted value looks -like its machine-level representation. For example, on 32\-bit machines -a converted integer may be represented by a sequence of 4 bytes. -.Sp -The \s-1TEMPLATE\s0 is a sequence of characters that give the order and type -of values, as follows: -.Sp -.Vb 3 -\& a A string with arbitrary binary data, will be null padded. -\& A A text (ASCII) string, will be space padded. -\& Z A null terminated (ASCIZ) string, will be null padded. -.Ve -.Sp -.Vb 4 -\& b A bit string (ascending bit order inside each byte, like vec()). -\& B A bit string (descending bit order inside each byte). -\& h A hex string (low nybble first). -\& H A hex string (high nybble first). -.Ve -.Sp -.Vb 2 -\& c A signed char value. -\& C An unsigned char value. Only does bytes. See U for Unicode. -.Ve -.Sp -.Vb 5 -\& s A signed short value. -\& S An unsigned short value. -\& (This 'short' is _exactly_ 16 bits, which may differ from -\& what a local C compiler calls 'short'. If you want -\& native-length shorts, use the '!' suffix.) -.Ve -.Sp -.Vb 6 -\& i A signed integer value. -\& I An unsigned integer value. -\& (This 'integer' is _at_least_ 32 bits wide. Its exact -\& size depends on what a local C compiler calls 'int', -\& and may even be larger than the 'long' described in -\& the next item.) -.Ve -.Sp -.Vb 5 -\& l A signed long value. -\& L An unsigned long value. -\& (This 'long' is _exactly_ 32 bits, which may differ from -\& what a local C compiler calls 'long'. If you want -\& native-length longs, use the '!' suffix.) -.Ve -.Sp -.Vb 6 -\& n An unsigned short in "network" (big-endian) order. -\& N An unsigned long in "network" (big-endian) order. -\& v An unsigned short in "VAX" (little-endian) order. -\& V An unsigned long in "VAX" (little-endian) order. -\& (These 'shorts' and 'longs' are _exactly_ 16 bits and -\& _exactly_ 32 bits, respectively.) -.Ve -.Sp -.Vb 5 -\& q A signed quad (64-bit) value. -\& Q An unsigned quad value. -\& (Quads are available only if your system supports 64-bit -\& integer values _and_ if Perl has been compiled to support those. -\& Causes a fatal error otherwise.) -.Ve -.Sp -.Vb 2 -\& j A signed integer value (a Perl internal integer, IV). -\& J An unsigned integer value (a Perl internal unsigned integer, UV). -.Ve -.Sp -.Vb 2 -\& f A single-precision float in the native format. -\& d A double-precision float in the native format. -.Ve -.Sp -.Vb 6 -\& F A floating point value in the native native format -\& (a Perl internal floating point value, NV). -\& D A long double-precision float in the native format. -\& (Long doubles are available only if your system supports long -\& double values _and_ if Perl has been compiled to support those. -\& Causes a fatal error otherwise.) -.Ve -.Sp -.Vb 2 -\& p A pointer to a null-terminated string. -\& P A pointer to a structure (fixed-length string). -.Ve -.Sp -.Vb 3 -\& u A uuencoded string. -\& U A Unicode character number. Encodes to UTF-8 internally -\& (or UTF-EBCDIC in EBCDIC platforms). -.Ve -.Sp -.Vb 4 -\& w A BER compressed integer (not an ASN.1 BER, see perlpacktut for -\& details). Its bytes represent an unsigned integer in base 128, -\& most significant digit first, with as few digits as possible. Bit -\& eight (the high bit) is set on each byte except the last. -.Ve -.Sp -.Vb 5 -\& x A null byte. -\& X Back up a byte. -\& @ Null fill to absolute position, counted from the start of -\& the innermost ()-group. -\& ( Start of a ()-group. -.Ve -.Sp -The following rules apply: -.RS 8 -.IP "*" 8 -Each letter may optionally be followed by a number giving a repeat -count. With all types except \f(CW\*(C`a\*(C'\fR, \f(CW\*(C`A\*(C'\fR, \f(CW\*(C`Z\*(C'\fR, \f(CW\*(C`b\*(C'\fR, \f(CW\*(C`B\*(C'\fR, \f(CW\*(C`h\*(C'\fR, -\&\f(CW\*(C`H\*(C'\fR, \f(CW\*(C`@\*(C'\fR, \f(CW\*(C`x\*(C'\fR, \f(CW\*(C`X\*(C'\fR and \f(CW\*(C`P\*(C'\fR the pack function will gobble up that -many values from the \s-1LIST\s0. A \f(CW\*(C`*\*(C'\fR for the repeat count means to use -however many items are left, except for \f(CW\*(C`@\*(C'\fR, \f(CW\*(C`x\*(C'\fR, \f(CW\*(C`X\*(C'\fR, where it is -equivalent to \f(CW0\fR, and \f(CW\*(C`u\*(C'\fR, where it is equivalent to 1 (or 45, what -is the same). A numeric repeat count may optionally be enclosed in -brackets, as in \f(CW\*(C`pack 'C[80]', @arr\*(C'\fR. -.Sp -One can replace the numeric repeat count by a template enclosed in brackets; -then the packed length of this template in bytes is used as a count. -For example, \f(CW\*(C`x[L]\*(C'\fR skips a long (it skips the number of bytes in a long); -the template \f(CW\*(C`$t X[$t] $t\*(C'\fR \fIunpack()\fRs twice what \f(CW$t\fR unpacks. -If the template in brackets contains alignment commands (such as \f(CW\*(C`x![d]\*(C'\fR), -its packed length is calculated as if the start of the template has the maximal -possible alignment. -.Sp -When used with \f(CW\*(C`Z\*(C'\fR, \f(CW\*(C`*\*(C'\fR results in the addition of a trailing null -byte (so the packed result will be one longer than the byte \f(CW\*(C`length\*(C'\fR -of the item). -.Sp -The repeat count for \f(CW\*(C`u\*(C'\fR is interpreted as the maximal number of bytes -to encode per line of output, with 0 and 1 replaced by 45. -.IP "*" 8 -The \f(CW\*(C`a\*(C'\fR, \f(CW\*(C`A\*(C'\fR, and \f(CW\*(C`Z\*(C'\fR types gobble just one value, but pack it as a -string of length count, padding with nulls or spaces as necessary. When -unpacking, \f(CW\*(C`A\*(C'\fR strips trailing spaces and nulls, \f(CW\*(C`Z\*(C'\fR strips everything -after the first null, and \f(CW\*(C`a\*(C'\fR returns data verbatim. When packing, -\&\f(CW\*(C`a\*(C'\fR, and \f(CW\*(C`Z\*(C'\fR are equivalent. -.Sp -If the value-to-pack is too long, it is truncated. If too long and an -explicit count is provided, \f(CW\*(C`Z\*(C'\fR packs only \f(CW\*(C`$count\-1\*(C'\fR bytes, followed -by a null byte. Thus \f(CW\*(C`Z\*(C'\fR always packs a trailing null byte under -all circumstances. -.IP "*" 8 -Likewise, the \f(CW\*(C`b\*(C'\fR and \f(CW\*(C`B\*(C'\fR fields pack a string that many bits long. -Each byte of the input field of \fIpack()\fR generates 1 bit of the result. -Each result bit is based on the least-significant bit of the corresponding -input byte, i.e., on \f(CW\*(C`ord($byte)%2\*(C'\fR. In particular, bytes \f(CW"0"\fR and -\&\f(CW"1"\fR generate bits 0 and 1, as do bytes \f(CW"\e0"\fR and \f(CW"\e1"\fR. -.Sp -Starting from the beginning of the input string of \fIpack()\fR, each 8\-tuple -of bytes is converted to 1 byte of output. With format \f(CW\*(C`b\*(C'\fR -the first byte of the 8\-tuple determines the least-significant bit of a -byte, and with format \f(CW\*(C`B\*(C'\fR it determines the most-significant bit of -a byte. -.Sp -If the length of the input string is not exactly divisible by 8, the -remainder is packed as if the input string were padded by null bytes -at the end. Similarly, during \fIunpack()\fRing the \*(L"extra\*(R" bits are ignored. -.Sp -If the input string of \fIpack()\fR is longer than needed, extra bytes are ignored. -A \f(CW\*(C`*\*(C'\fR for the repeat count of \fIpack()\fR means to use all the bytes of -the input field. On \fIunpack()\fRing the bits are converted to a string -of \f(CW"0"\fRs and \f(CW"1"\fRs. -.IP "*" 8 -The \f(CW\*(C`h\*(C'\fR and \f(CW\*(C`H\*(C'\fR fields pack a string that many nybbles (4\-bit groups, -representable as hexadecimal digits, 0\-9a\-f) long. -.Sp -Each byte of the input field of \fIpack()\fR generates 4 bits of the result. -For non-alphabetical bytes the result is based on the 4 least-significant -bits of the input byte, i.e., on \f(CW\*(C`ord($byte)%16\*(C'\fR. In particular, -bytes \f(CW"0"\fR and \f(CW"1"\fR generate nybbles 0 and 1, as do bytes -\&\f(CW"\e0"\fR and \f(CW"\e1"\fR. For bytes \f(CW"a".."f"\fR and \f(CW"A".."F"\fR the result -is compatible with the usual hexadecimal digits, so that \f(CW"a"\fR and -\&\f(CW"A"\fR both generate the nybble \f(CW\*(C`0xa==10\*(C'\fR. The result for bytes -\&\f(CW"g".."z"\fR and \f(CW"G".."Z"\fR is not well\-defined. -.Sp -Starting from the beginning of the input string of \fIpack()\fR, each pair -of bytes is converted to 1 byte of output. With format \f(CW\*(C`h\*(C'\fR the -first byte of the pair determines the least-significant nybble of the -output byte, and with format \f(CW\*(C`H\*(C'\fR it determines the most-significant -nybble. -.Sp -If the length of the input string is not even, it behaves as if padded -by a null byte at the end. Similarly, during \fIunpack()\fRing the \*(L"extra\*(R" -nybbles are ignored. -.Sp -If the input string of \fIpack()\fR is longer than needed, extra bytes are ignored. -A \f(CW\*(C`*\*(C'\fR for the repeat count of \fIpack()\fR means to use all the bytes of -the input field. On \fIunpack()\fRing the bits are converted to a string -of hexadecimal digits. -.IP "*" 8 -The \f(CW\*(C`p\*(C'\fR type packs a pointer to a null-terminated string. You are -responsible for ensuring the string is not a temporary value (which can -potentially get deallocated before you get around to using the packed result). -The \f(CW\*(C`P\*(C'\fR type packs a pointer to a structure of the size indicated by the -length. A \s-1NULL\s0 pointer is created if the corresponding value for \f(CW\*(C`p\*(C'\fR or -\&\f(CW\*(C`P\*(C'\fR is \f(CW\*(C`undef\*(C'\fR, similarly for \fIunpack()\fR. -.IP "*" 8 -The \f(CW\*(C`/\*(C'\fR template character allows packing and unpacking of strings where -the packed structure contains a byte count followed by the string itself. -You write \fIlength-item\fR\f(CW\*(C`/\*(C'\fR\fIstring-item\fR. -.Sp -The \fIlength-item\fR can be any \f(CW\*(C`pack\*(C'\fR template letter, and describes -how the length value is packed. The ones likely to be of most use are -integer-packing ones like \f(CW\*(C`n\*(C'\fR (for Java strings), \f(CW\*(C`w\*(C'\fR (for \s-1ASN\s0.1 or -\&\s-1SNMP\s0) and \f(CW\*(C`N\*(C'\fR (for Sun \s-1XDR\s0). -.Sp -For \f(CW\*(C`pack\*(C'\fR, the \fIstring-item\fR must, at present, be \f(CW"A*"\fR, \f(CW"a*"\fR or -\&\f(CW"Z*"\fR. For \f(CW\*(C`unpack\*(C'\fR the length of the string is obtained from the -\&\fIlength-item\fR, but if you put in the '*' it will be ignored. For all other -codes, \f(CW\*(C`unpack\*(C'\fR applies the length value to the next item, which must not -have a repeat count. -.Sp -.Vb 3 -\& unpack 'C/a', "\e04Gurusamy"; gives 'Guru' -\& unpack 'a3/A* A*', '007 Bond J '; gives (' Bond','J') -\& pack 'n/a* w/a*','hello,','world'; gives "\e000\e006hello,\e005world" -.Ve -.Sp -The \fIlength-item\fR is not returned explicitly from \f(CW\*(C`unpack\*(C'\fR. -.Sp -Adding a count to the \fIlength-item\fR letter is unlikely to do anything -useful, unless that letter is \f(CW\*(C`A\*(C'\fR, \f(CW\*(C`a\*(C'\fR or \f(CW\*(C`Z\*(C'\fR. Packing with a -\&\fIlength-item\fR of \f(CW\*(C`a\*(C'\fR or \f(CW\*(C`Z\*(C'\fR may introduce \f(CW"\e000"\fR characters, -which Perl does not regard as legal in numeric strings. -.IP "*" 8 -The integer types \f(CW\*(C`s\*(C'\fR, \f(CW\*(C`S\*(C'\fR, \f(CW\*(C`l\*(C'\fR, and \f(CW\*(C`L\*(C'\fR may be -immediately followed by a \f(CW\*(C`!\*(C'\fR suffix to signify native shorts or -longs\*(--as you can see from above for example a bare \f(CW\*(C`l\*(C'\fR does mean -exactly 32 bits, the native \f(CW\*(C`long\*(C'\fR (as seen by the local C compiler) -may be larger. This is an issue mainly in 64\-bit platforms. You can -see whether using \f(CW\*(C`!\*(C'\fR makes any difference by -.Sp -.Vb 2 -\& print length(pack("s")), " ", length(pack("s!")), "\en"; -\& print length(pack("l")), " ", length(pack("l!")), "\en"; -.Ve -.Sp -\&\f(CW\*(C`i!\*(C'\fR and \f(CW\*(C`I!\*(C'\fR also work but only because of completeness; -they are identical to \f(CW\*(C`i\*(C'\fR and \f(CW\*(C`I\*(C'\fR. -.Sp -The actual sizes (in bytes) of native shorts, ints, longs, and long -longs on the platform where Perl was built are also available via -Config: -.Sp -.Vb 5 -\& use Config; -\& print $Config{shortsize}, "\en"; -\& print $Config{intsize}, "\en"; -\& print $Config{longsize}, "\en"; -\& print $Config{longlongsize}, "\en"; -.Ve -.Sp -(The \f(CW$Config{longlongsize}\fR will be undefined if your system does -not support long longs.) -.IP "*" 8 -The integer formats \f(CW\*(C`s\*(C'\fR, \f(CW\*(C`S\*(C'\fR, \f(CW\*(C`i\*(C'\fR, \f(CW\*(C`I\*(C'\fR, \f(CW\*(C`l\*(C'\fR, \f(CW\*(C`L\*(C'\fR, \f(CW\*(C`j\*(C'\fR, and \f(CW\*(C`J\*(C'\fR -are inherently non-portable between processors and operating systems -because they obey the native byteorder and endianness. For example a -4\-byte integer 0x12345678 (305419896 decimal) would be ordered natively -(arranged in and handled by the \s-1CPU\s0 registers) into bytes as -.Sp -.Vb 2 -\& 0x12 0x34 0x56 0x78 # big-endian -\& 0x78 0x56 0x34 0x12 # little-endian -.Ve -.Sp -Basically, the Intel and \s-1VAX\s0 CPUs are little\-endian, while everybody -else, for example Motorola m68k/88k, \s-1PPC\s0, Sparc, \s-1HP\s0 \s-1PA\s0, Power, and -Cray are big\-endian. Alpha and \s-1MIPS\s0 can be either: Digital/Compaq -used/uses them in little-endian mode; SGI/Cray uses them in big-endian -mode. -.Sp -The names `big\-endian' and `little\-endian' are comic references to -the classic \*(L"Gulliver's Travels\*(R" (via the paper \*(L"On Holy Wars and a -Plea for Peace\*(R" by Danny Cohen, \s-1USC/ISI\s0 \s-1IEN\s0 137, April 1, 1980) and -the egg-eating habits of the Lilliputians. -.Sp -Some systems may have even weirder byte orders such as -.Sp -.Vb 2 -\& 0x56 0x78 0x12 0x34 -\& 0x34 0x12 0x78 0x56 -.Ve -.Sp -You can see your system's preference with -.Sp -.Vb 2 -\& print join(" ", map { sprintf "%#02x", $_ } -\& unpack("C*",pack("L",0x12345678))), "\en"; -.Ve -.Sp -The byteorder on the platform where Perl was built is also available -via Config: -.Sp -.Vb 2 -\& use Config; -\& print $Config{byteorder}, "\en"; -.Ve -.Sp -Byteorders \f(CW'1234'\fR and \f(CW'12345678'\fR are little\-endian, \f(CW'4321'\fR -and \f(CW'87654321'\fR are big\-endian. -.Sp -If you want portable packed integers use the formats \f(CW\*(C`n\*(C'\fR, \f(CW\*(C`N\*(C'\fR, -\&\f(CW\*(C`v\*(C'\fR, and \f(CW\*(C`V\*(C'\fR, their byte endianness and size are known. -See also perlport. -.IP "*" 8 -Real numbers (floats and doubles) are in the native machine format only; -due to the multiplicity of floating formats around, and the lack of a -standard \*(L"network\*(R" representation, no facility for interchange has been -made. This means that packed floating point data written on one machine -may not be readable on another \- even if both use \s-1IEEE\s0 floating point -arithmetic (as the endian-ness of the memory representation is not part -of the \s-1IEEE\s0 spec). See also perlport. -.Sp -Note that Perl uses doubles internally for all numeric calculation, and -converting from double into float and thence back to double again will -lose precision (i.e., \f(CW\*(C`unpack("f", pack("f", $foo)\*(C'\fR) will not in general -equal \f(CW$foo\fR). -.IP "*" 8 -If the pattern begins with a \f(CW\*(C`U\*(C'\fR, the resulting string will be -treated as UTF\-8\-encoded Unicode. You can force \s-1UTF\-8\s0 encoding on in a -string with an initial \f(CW\*(C`U0\*(C'\fR, and the bytes that follow will be -interpreted as Unicode characters. If you don't want this to happen, -you can begin your pattern with \f(CW\*(C`C0\*(C'\fR (or anything else) to force Perl -not to \s-1UTF\-8\s0 encode your string, and then follow this with a \f(CW\*(C`U*\*(C'\fR -somewhere in your pattern. -.IP "*" 8 -You must yourself do any alignment or padding by inserting for example -enough \f(CW'x'\fRes while packing. There is no way to \fIpack()\fR and \fIunpack()\fR -could know where the bytes are going to or coming from. Therefore -\&\f(CW\*(C`pack\*(C'\fR (and \f(CW\*(C`unpack\*(C'\fR) handle their output and input as flat -sequences of bytes. -.IP "*" 8 -A ()\-group is a sub-TEMPLATE enclosed in parentheses. A group may -take a repeat count, both as postfix, and for \fIunpack()\fR also via the \f(CW\*(C`/\*(C'\fR -template character. Within each repetition of a group, positioning with -\&\f(CW\*(C`@\*(C'\fR starts again at 0. Therefore, the result of -.Sp -.Vb 1 -\& pack( '@1A((@2A)@3A)', 'a', 'b', 'c' ) -.Ve -.Sp -is the string \*(L"\e0a\e0\e0bc\*(R". -.IP "*" 8 -\&\f(CW\*(C`x\*(C'\fR and \f(CW\*(C`X\*(C'\fR accept \f(CW\*(C`!\*(C'\fR modifier. In this case they act as -alignment commands: they jump forward/back to the closest position -aligned at a multiple of \f(CW\*(C`count\*(C'\fR bytes. For example, to \fIpack()\fR or -\&\fIunpack()\fR C's \f(CW\*(C`struct {char c; double d; char cc[2]}\*(C'\fR one may need to -use the template \f(CW\*(C`C x![d] d C[2]\*(C'\fR; this assumes that doubles must be -aligned on the double's size. -.Sp -For alignment commands \f(CW\*(C`count\*(C'\fR of 0 is equivalent to \f(CW\*(C`count\*(C'\fR of 1; -both result in no\-ops. -.IP "*" 8 -A comment in a \s-1TEMPLATE\s0 starts with \f(CW\*(C`#\*(C'\fR and goes to the end of line. -White space may be used to separate pack codes from each other, but -a \f(CW\*(C`!\*(C'\fR modifier and a repeat count must follow immediately. -.IP "*" 8 -If \s-1TEMPLATE\s0 requires more arguments to \fIpack()\fR than actually given, \fIpack()\fR -assumes additional \f(CW""\fR arguments. If \s-1TEMPLATE\s0 requires fewer arguments -to \fIpack()\fR than actually given, extra arguments are ignored. -.RE -.RS 8 -.Sp -Examples: -.Sp -.Vb 6 -\& $foo = pack("CCCC",65,66,67,68); -\& # foo eq "ABCD" -\& $foo = pack("C4",65,66,67,68); -\& # same thing -\& $foo = pack("U4",0x24b6,0x24b7,0x24b8,0x24b9); -\& # same thing with Unicode circled letters -.Ve -.Sp -.Vb 2 -\& $foo = pack("ccxxcc",65,66,67,68); -\& # foo eq "AB\e0\e0CD" -.Ve -.Sp -.Vb 4 -\& # note: the above examples featuring "C" and "c" are true -\& # only on ASCII and ASCII-derived systems such as ISO Latin 1 -\& # and UTF-8. In EBCDIC the first example would be -\& # $foo = pack("CCCC",193,194,195,196); -.Ve -.Sp -.Vb 3 -\& $foo = pack("s2",1,2); -\& # "\e1\e0\e2\e0" on little-endian -\& # "\e0\e1\e0\e2" on big-endian -.Ve -.Sp -.Vb 2 -\& $foo = pack("a4","abcd","x","y","z"); -\& # "abcd" -.Ve -.Sp -.Vb 2 -\& $foo = pack("aaaa","abcd","x","y","z"); -\& # "axyz" -.Ve -.Sp -.Vb 2 -\& $foo = pack("a14","abcdefg"); -\& # "abcdefg\e0\e0\e0\e0\e0\e0\e0" -.Ve -.Sp -.Vb 2 -\& $foo = pack("i9pl", gmtime); -\& # a real struct tm (on my system anyway) -.Ve -.Sp -.Vb 3 -\& $utmp_template = "Z8 Z8 Z16 L"; -\& $utmp = pack($utmp_template, @utmp1); -\& # a struct utmp (BSDish) -.Ve -.Sp -.Vb 2 -\& @utmp2 = unpack($utmp_template, $utmp); -\& # "@utmp1" eq "@utmp2" -.Ve -.Sp -.Vb 3 -\& sub bintodec { -\& unpack("N", pack("B32", substr("0" x 32 . shift, -32))); -\& } -.Ve -.Sp -.Vb 5 -\& $foo = pack('sx2l', 12, 34); -\& # short 12, two zero bytes padding, long 34 -\& $bar = pack('s@4l', 12, 34); -\& # short 12, zero fill to position 4, long 34 -\& # $foo eq $bar -.Ve -.Sp -The same template may generally also be used in \fIunpack()\fR. -.RE -.IP "package \s-1NAMESPACE\s0" 8 -.IX Xref "package module namespace" -.IX Item "package NAMESPACE" -.PD 0 -.IP "package" 8 -.IX Item "package" -.PD -Declares the compilation unit as being in the given namespace. The scope -of the package declaration is from the declaration itself through the end -of the enclosing block, file, or eval (the same as the \f(CW\*(C`my\*(C'\fR operator). -All further unqualified dynamic identifiers will be in this namespace. -A package statement affects only dynamic variables\*(--including those -you've used \f(CW\*(C`local\*(C'\fR on\*(--but \fInot\fR lexical variables, which are created -with \f(CW\*(C`my\*(C'\fR. Typically it would be the first declaration in a file to -be included by the \f(CW\*(C`require\*(C'\fR or \f(CW\*(C`use\*(C'\fR operator. You can switch into a -package in more than one place; it merely influences which symbol table -is used by the compiler for the rest of that block. You can refer to -variables and filehandles in other packages by prefixing the identifier -with the package name and a double colon: \f(CW$Package::Variable\fR. -If the package name is null, the \f(CW\*(C`main\*(C'\fR package as assumed. That is, -\&\f(CW$::sail\fR is equivalent to \f(CW$main::sail\fR (as well as to \f(CW$main'sail\fR, -still seen in older code). -.Sp -If \s-1NAMESPACE\s0 is omitted, then there is no current package, and all -identifiers must be fully qualified or lexicals. However, you are -strongly advised not to make use of this feature. Its use can cause -unexpected behaviour, even crashing some versions of Perl. It is -deprecated, and will be removed from a future release. -.Sp -See \*(L"Packages\*(R" in perlmod for more information about packages, modules, -and classes. See perlsub for other scoping issues. -.IP "pipe \s-1READHANDLE\s0,WRITEHANDLE" 8 -.IX Xref "pipe" -.IX Item "pipe READHANDLE,WRITEHANDLE" -Opens a pair of connected pipes like the corresponding system call. -Note that if you set up a loop of piped processes, deadlock can occur -unless you are very careful. In addition, note that Perl's pipes use -\&\s-1IO\s0 buffering, so you may need to set \f(CW$|\fR to flush your \s-1WRITEHANDLE\s0 -after each command, depending on the application. -.Sp -See IPC::Open2, IPC::Open3, and \*(L"Bidirectional Communication\*(R" in perlipc -for examples of such things. -.Sp -On systems that support a close-on-exec flag on files, the flag will be set -for the newly opened file descriptors as determined by the value of $^F. -See \*(L"$^F\*(R" in perlvar. -.IP "pop \s-1ARRAY\s0" 8 -.IX Xref "pop stack" -.IX Item "pop ARRAY" -.PD 0 -.IP "pop" 8 -.IX Item "pop" -.PD -Pops and returns the last value of the array, shortening the array by -one element. Has an effect similar to -.Sp -.Vb 1 -\& $ARRAY[$#ARRAY--] -.Ve -.Sp -If there are no elements in the array, returns the undefined value -(although this may happen at other times as well). If \s-1ARRAY\s0 is -omitted, pops the \f(CW@ARGV\fR array in the main program, and the \f(CW@_\fR -array in subroutines, just like \f(CW\*(C`shift\*(C'\fR. -.IP "pos \s-1SCALAR\s0" 8 -.IX Xref "pos match, position" -.IX Item "pos SCALAR" -.PD 0 -.IP "pos" 8 -.IX Item "pos" -.PD -Returns the offset of where the last \f(CW\*(C`m//g\*(C'\fR search left off for the variable -in question (\f(CW$_\fR is used when the variable is not specified). Note that -0 is a valid match offset. \f(CW\*(C`undef\*(C'\fR indicates that the search position -is reset (usually due to match failure, but can also be because no match has -yet been performed on the scalar). \f(CW\*(C`pos\*(C'\fR directly accesses the location used -by the regexp engine to store the offset, so assigning to \f(CW\*(C`pos\*(C'\fR will change -that offset, and so will also influence the \f(CW\*(C`\eG\*(C'\fR zero-width assertion in -regular expressions. Because a failed \f(CW\*(C`m//gc\*(C'\fR match doesn't reset the offset, -the return from \f(CW\*(C`pos\*(C'\fR won't change either in this case. See perlre and -perlop. -.IP "print \s-1FILEHANDLE\s0 \s-1LIST\s0" 8 -.IX Xref "print" -.IX Item "print FILEHANDLE LIST" -.PD 0 -.IP "print \s-1LIST\s0" 8 -.IX Item "print LIST" -.IP "print" 8 -.IX Item "print" -.PD -Prints a string or a list of strings. Returns true if successful. -\&\s-1FILEHANDLE\s0 may be a scalar variable name, in which case the variable -contains the name of or a reference to the filehandle, thus introducing -one level of indirection. (\s-1NOTE:\s0 If \s-1FILEHANDLE\s0 is a variable and -the next token is a term, it may be misinterpreted as an operator -unless you interpose a \f(CW\*(C`+\*(C'\fR or put parentheses around the arguments.) -If \s-1FILEHANDLE\s0 is omitted, prints by default to standard output (or -to the last selected output channel\*(--see \*(L"select\*(R"). If \s-1LIST\s0 is -also omitted, prints \f(CW$_\fR to the currently selected output channel. -To set the default output channel to something other than \s-1STDOUT\s0 -use the select operation. The current value of \f(CW$,\fR (if any) is -printed between each \s-1LIST\s0 item. The current value of \f(CW\*(C`$\e\*(C'\fR (if -any) is printed after the entire \s-1LIST\s0 has been printed. Because -print takes a \s-1LIST\s0, anything in the \s-1LIST\s0 is evaluated in list -context, and any subroutine that you call will have one or more of -its expressions evaluated in list context. Also be careful not to -follow the print keyword with a left parenthesis unless you want -the corresponding right parenthesis to terminate the arguments to -the print\*(--interpose a \f(CW\*(C`+\*(C'\fR or put parentheses around all the -arguments. -.Sp -Note that if you're storing FILEHANDLEs in an array, or if you're using -any other expression more complex than a scalar variable to retrieve it, -you will have to use a block returning the filehandle value instead: -.Sp -.Vb 2 -\& print { $files[$i] } "stuff\en"; -\& print { $OK ? STDOUT : STDERR } "stuff\en"; -.Ve -.IP "printf \s-1FILEHANDLE\s0 \s-1FORMAT\s0, \s-1LIST\s0" 8 -.IX Xref "printf" -.IX Item "printf FILEHANDLE FORMAT, LIST" -.PD 0 -.IP "printf \s-1FORMAT\s0, \s-1LIST\s0" 8 -.IX Item "printf FORMAT, LIST" -.PD -Equivalent to \f(CW\*(C`print FILEHANDLE sprintf(FORMAT, LIST)\*(C'\fR, except that \f(CW\*(C`$\e\*(C'\fR -(the output record separator) is not appended. The first argument -of the list will be interpreted as the \f(CW\*(C`printf\*(C'\fR format. See \f(CW\*(C`sprintf\*(C'\fR -for an explanation of the format argument. If \f(CW\*(C`use locale\*(C'\fR is in effect, -the character used for the decimal point in formatted real numbers is -affected by the \s-1LC_NUMERIC\s0 locale. See perllocale. -.Sp -Don't fall into the trap of using a \f(CW\*(C`printf\*(C'\fR when a simple -\&\f(CW\*(C`print\*(C'\fR would do. The \f(CW\*(C`print\*(C'\fR is more efficient and less -error prone. -.IP "prototype \s-1FUNCTION\s0" 8 -.IX Xref "prototype" -.IX Item "prototype FUNCTION" -Returns the prototype of a function as a string (or \f(CW\*(C`undef\*(C'\fR if the -function has no prototype). \s-1FUNCTION\s0 is a reference to, or the name of, -the function whose prototype you want to retrieve. -.Sp -If \s-1FUNCTION\s0 is a string starting with \f(CW\*(C`CORE::\*(C'\fR, the rest is taken as a -name for Perl builtin. If the builtin is not \fIoverridable\fR (such as -\&\f(CW\*(C`qw//\*(C'\fR) or its arguments cannot be expressed by a prototype (such as -\&\f(CW\*(C`system\*(C'\fR) returns \f(CW\*(C`undef\*(C'\fR because the builtin does not really behave -like a Perl function. Otherwise, the string describing the equivalent -prototype is returned. -.IP "push \s-1ARRAY\s0,LIST ," 8 -.IX Xref "push stack" -.IX Item "push ARRAY,LIST ," -Treats \s-1ARRAY\s0 as a stack, and pushes the values of \s-1LIST\s0 -onto the end of \s-1ARRAY\s0. The length of \s-1ARRAY\s0 increases by the length of -\&\s-1LIST\s0. Has the same effect as -.Sp -.Vb 3 -\& for $value (LIST) { -\& $ARRAY[++$#ARRAY] = $value; -\& } -.Ve -.Sp -but is more efficient. Returns the number of elements in the array following -the completed \f(CW\*(C`push\*(C'\fR. -.IP "q/STRING/" 8 -.IX Item "q/STRING/" -.PD 0 -.IP "qq/STRING/" 8 -.IX Item "qq/STRING/" -.IP "qr/STRING/" 8 -.IX Item "qr/STRING/" -.IP "qx/STRING/" 8 -.IX Item "qx/STRING/" -.IP "qw/STRING/" 8 -.IX Item "qw/STRING/" -.PD -Generalized quotes. See \*(L"Regexp Quote-Like Operators\*(R" in perlop. -.IP "quotemeta \s-1EXPR\s0" 8 -.IX Xref "quotemeta metacharacter" -.IX Item "quotemeta EXPR" -.PD 0 -.IP "quotemeta" 8 -.IX Item "quotemeta" -.PD -Returns the value of \s-1EXPR\s0 with all non\-\*(L"word\*(R" -characters backslashed. (That is, all characters not matching -\&\f(CW\*(C`/[A\-Za\-z_0\-9]/\*(C'\fR will be preceded by a backslash in the -returned string, regardless of any locale settings.) -This is the internal function implementing -the \f(CW\*(C`\eQ\*(C'\fR escape in double-quoted strings. -.Sp -If \s-1EXPR\s0 is omitted, uses \f(CW$_\fR. -.IP "rand \s-1EXPR\s0" 8 -.IX Xref "rand random" -.IX Item "rand EXPR" -.PD 0 -.IP "rand" 8 -.IX Item "rand" -.PD -Returns a random fractional number greater than or equal to \f(CW0\fR and less -than the value of \s-1EXPR\s0. (\s-1EXPR\s0 should be positive.) If \s-1EXPR\s0 is -omitted, the value \f(CW1\fR is used. Currently \s-1EXPR\s0 with the value \f(CW0\fR is -also special-cased as \f(CW1\fR \- this has not been documented before perl 5.8.0 -and is subject to change in future versions of perl. Automatically calls -\&\f(CW\*(C`srand\*(C'\fR unless \f(CW\*(C`srand\*(C'\fR has already been called. See also \f(CW\*(C`srand\*(C'\fR. -.Sp -Apply \f(CW\*(C`int()\*(C'\fR to the value returned by \f(CW\*(C`rand()\*(C'\fR if you want random -integers instead of random fractional numbers. For example, -.Sp -.Vb 1 -\& int(rand(10)) -.Ve -.Sp -returns a random integer between \f(CW0\fR and \f(CW9\fR, inclusive. -.Sp -(Note: If your rand function consistently returns numbers that are too -large or too small, then your version of Perl was probably compiled -with the wrong number of \s-1RANDBITS\s0.) -.IP "read \s-1FILEHANDLE\s0,SCALAR,LENGTH,OFFSET" 8 -.IX Xref "read" -.IX Item "read FILEHANDLE,SCALAR,LENGTH,OFFSET" -.PD 0 -.IP "read \s-1FILEHANDLE\s0,SCALAR,LENGTH" 8 -.IX Item "read FILEHANDLE,SCALAR,LENGTH" -.PD -Attempts to read \s-1LENGTH\s0 \fIcharacters\fR of data into variable \s-1SCALAR\s0 -from the specified \s-1FILEHANDLE\s0. Returns the number of characters -actually read, \f(CW0\fR at end of file, or undef if there was an error (in -the latter case \f(CW$!\fR is also set). \s-1SCALAR\s0 will be grown or shrunk -so that the last character actually read is the last character of the -scalar after the read. -.Sp -An \s-1OFFSET\s0 may be specified to place the read data at some place in the -string other than the beginning. A negative \s-1OFFSET\s0 specifies -placement at that many characters counting backwards from the end of -the string. A positive \s-1OFFSET\s0 greater than the length of \s-1SCALAR\s0 -results in the string being padded to the required size with \f(CW"\e0"\fR -bytes before the result of the read is appended. -.Sp -The call is actually implemented in terms of either Perl's or system's -\&\fIfread()\fR call. To get a true \fIread\fR\|(2) system call, see \f(CW\*(C`sysread\*(C'\fR. -.Sp -Note the \fIcharacters\fR: depending on the status of the filehandle, -either (8\-bit) bytes or characters are read. By default all -filehandles operate on bytes, but for example if the filehandle has -been opened with the \f(CW\*(C`:utf8\*(C'\fR I/O layer (see \*(L"open\*(R", and the \f(CW\*(C`open\*(C'\fR -pragma, open), the I/O will operate on \s-1UTF\-8\s0 encoded Unicode -characters, not bytes. Similarly for the \f(CW\*(C`:encoding\*(C'\fR pragma: -in that case pretty much any characters can be read. -.IP "readdir \s-1DIRHANDLE\s0" 8 -.IX Xref "readdir" -.IX Item "readdir DIRHANDLE" -Returns the next directory entry for a directory opened by \f(CW\*(C`opendir\*(C'\fR. -If used in list context, returns all the rest of the entries in the -directory. If there are no more entries, returns an undefined value in -scalar context or a null list in list context. -.Sp -If you're planning to filetest the return values out of a \f(CW\*(C`readdir\*(C'\fR, you'd -better prepend the directory in question. Otherwise, because we didn't -\&\f(CW\*(C`chdir\*(C'\fR there, it would have been testing the wrong file. -.Sp -.Vb 3 -\& opendir(DIR, $some_dir) || die "can't opendir $some_dir: $!"; -\& @dots = grep { /^\e./ && -f "$some_dir/$_" } readdir(DIR); -\& closedir DIR; -.Ve -.IP "readline \s-1EXPR\s0" 8 -.IX Xref "readline gets fgets" -.IX Item "readline EXPR" -Reads from the filehandle whose typeglob is contained in \s-1EXPR\s0. In scalar -context, each call reads and returns the next line, until end-of-file is -reached, whereupon the subsequent call returns undef. In list context, -reads until end-of-file is reached and returns a list of lines. Note that -the notion of \*(L"line\*(R" used here is however you may have defined it -with \f(CW$/\fR or \f(CW$INPUT_RECORD_SEPARATOR\fR). See \*(L"$/\*(R" in perlvar. -.Sp -When \f(CW$/\fR is set to \f(CW\*(C`undef\*(C'\fR, when \fIreadline()\fR is in scalar -context (i.e. file slurp mode), and when an empty file is read, it -returns \f(CW''\fR the first time, followed by \f(CW\*(C`undef\*(C'\fR subsequently. -.Sp -This is the internal function implementing the \f(CW\*(C`<EXPR>\*(C'\fR -operator, but you can use it directly. The \f(CW\*(C`<EXPR>\*(C'\fR -operator is discussed in more detail in \*(L"I/O Operators\*(R" in perlop. -.Sp -.Vb 2 -\& $line = <STDIN>; -\& $line = readline(*STDIN); # same thing -.Ve -.Sp -If readline encounters an operating system error, \f(CW$!\fR will be set with the -corresponding error message. It can be helpful to check \f(CW$!\fR when you are -reading from filehandles you don't trust, such as a tty or a socket. The -following example uses the operator form of \f(CW\*(C`readline\*(C'\fR, and takes the necessary -steps to ensure that \f(CW\*(C`readline\*(C'\fR was successful. -.Sp -.Vb 8 -\& for (;;) { -\& undef $!; -\& unless (defined( $line = <> )) { -\& die $! if $!; -\& last; # reached EOF -\& } -\& # ... -\& } -.Ve -.IP "readlink \s-1EXPR\s0" 8 -.IX Xref "readlink" -.IX Item "readlink EXPR" -.PD 0 -.IP "readlink" 8 -.IX Item "readlink" -.PD -Returns the value of a symbolic link, if symbolic links are -implemented. If not, gives a fatal error. If there is some system -error, returns the undefined value and sets \f(CW$!\fR (errno). If \s-1EXPR\s0 is -omitted, uses \f(CW$_\fR. -.IP "readpipe \s-1EXPR\s0" 8 -.IX Xref "readpipe" -.IX Item "readpipe EXPR" -\&\s-1EXPR\s0 is executed as a system command. -The collected standard output of the command is returned. -In scalar context, it comes back as a single (potentially -multi\-line) string. In list context, returns a list of lines -(however you've defined lines with \f(CW$/\fR or \f(CW$INPUT_RECORD_SEPARATOR\fR). -This is the internal function implementing the \f(CW\*(C`qx/EXPR/\*(C'\fR -operator, but you can use it directly. The \f(CW\*(C`qx/EXPR/\*(C'\fR -operator is discussed in more detail in \*(L"I/O Operators\*(R" in perlop. -.IP "recv \s-1SOCKET\s0,SCALAR,LENGTH,FLAGS" 8 -.IX Xref "recv" -.IX Item "recv SOCKET,SCALAR,LENGTH,FLAGS" -Receives a message on a socket. Attempts to receive \s-1LENGTH\s0 characters -of data into variable \s-1SCALAR\s0 from the specified \s-1SOCKET\s0 filehandle. -\&\s-1SCALAR\s0 will be grown or shrunk to the length actually read. Takes the -same flags as the system call of the same name. Returns the address -of the sender if \s-1SOCKET\s0's protocol supports this; returns an empty -string otherwise. If there's an error, returns the undefined value. -This call is actually implemented in terms of \fIrecvfrom\fR\|(2) system call. -See \*(L"\s-1UDP:\s0 Message Passing\*(R" in perlipc for examples. -.Sp -Note the \fIcharacters\fR: depending on the status of the socket, either -(8\-bit) bytes or characters are received. By default all sockets -operate on bytes, but for example if the socket has been changed using -\&\fIbinmode()\fR to operate with the \f(CW\*(C`:utf8\*(C'\fR I/O layer (see the \f(CW\*(C`open\*(C'\fR -pragma, open), the I/O will operate on \s-1UTF\-8\s0 encoded Unicode -characters, not bytes. Similarly for the \f(CW\*(C`:encoding\*(C'\fR pragma: -in that case pretty much any characters can be read. -.IP "redo \s-1LABEL\s0" 8 -.IX Xref "redo" -.IX Item "redo LABEL" -.PD 0 -.IP "redo" 8 -.IX Item "redo" -.PD -The \f(CW\*(C`redo\*(C'\fR command restarts the loop block without evaluating the -conditional again. The \f(CW\*(C`continue\*(C'\fR block, if any, is not executed. If -the \s-1LABEL\s0 is omitted, the command refers to the innermost enclosing -loop. Programs that want to lie to themselves about what was just input -normally use this command: -.Sp -.Vb 16 -\& # a simpleminded Pascal comment stripper -\& # (warning: assumes no { or } in strings) -\& LINE: while (<STDIN>) { -\& while (s|({.*}.*){.*}|$1 |) {} -\& s|{.*}| |; -\& if (s|{.*| |) { -\& $front = $_; -\& while (<STDIN>) { -\& if (/}/) { # end of comment? -\& s|^|$front\e{|; -\& redo LINE; -\& } -\& } -\& } -\& print; -\& } -.Ve -.Sp -\&\f(CW\*(C`redo\*(C'\fR cannot be used to retry a block which returns a value such as -\&\f(CW\*(C`eval {}\*(C'\fR, \f(CW\*(C`sub {}\*(C'\fR or \f(CW\*(C`do {}\*(C'\fR, and should not be used to exit -a \fIgrep()\fR or \fImap()\fR operation. -.Sp -Note that a block by itself is semantically identical to a loop -that executes once. Thus \f(CW\*(C`redo\*(C'\fR inside such a block will effectively -turn it into a looping construct. -.Sp -See also \*(L"continue\*(R" for an illustration of how \f(CW\*(C`last\*(C'\fR, \f(CW\*(C`next\*(C'\fR, and -\&\f(CW\*(C`redo\*(C'\fR work. -.IP "ref \s-1EXPR\s0" 8 -.IX Xref "ref reference" -.IX Item "ref EXPR" -.PD 0 -.IP "ref" 8 -.IX Item "ref" -.PD -Returns a non-empty string if \s-1EXPR\s0 is a reference, the empty -string otherwise. If \s-1EXPR\s0 -is not specified, \f(CW$_\fR will be used. The value returned depends on the -type of thing the reference is a reference to. -Builtin types include: -.Sp -.Vb 7 -\& SCALAR -\& ARRAY -\& HASH -\& CODE -\& REF -\& GLOB -\& LVALUE -.Ve -.Sp -If the referenced object has been blessed into a package, then that package -name is returned instead. You can think of \f(CW\*(C`ref\*(C'\fR as a \f(CW\*(C`typeof\*(C'\fR operator. -.Sp -.Vb 6 -\& if (ref($r) eq "HASH") { -\& print "r is a reference to a hash.\en"; -\& } -\& unless (ref($r)) { -\& print "r is not a reference at all.\en"; -\& } -.Ve -.Sp -See also perlref. -.IP "rename \s-1OLDNAME\s0,NEWNAME" 8 -.IX Xref "rename move mv ren" -.IX Item "rename OLDNAME,NEWNAME" -Changes the name of a file; an existing file \s-1NEWNAME\s0 will be -clobbered. Returns true for success, false otherwise. -.Sp -Behavior of this function varies wildly depending on your system -implementation. For example, it will usually not work across file system -boundaries, even though the system \fImv\fR command sometimes compensates -for this. Other restrictions include whether it works on directories, -open files, or pre-existing files. Check perlport and either the -\&\fIrename\fR\|(2) manpage or equivalent system documentation for details. -.IP "require \s-1VERSION\s0" 8 -.IX Xref "require" -.IX Item "require VERSION" -.PD 0 -.IP "require \s-1EXPR\s0" 8 -.IX Item "require EXPR" -.IP "require" 8 -.IX Item "require" -.PD -Demands a version of Perl specified by \s-1VERSION\s0, or demands some semantics -specified by \s-1EXPR\s0 or by \f(CW$_\fR if \s-1EXPR\s0 is not supplied. -.Sp -\&\s-1VERSION\s0 may be either a numeric argument such as 5.006, which will be -compared to \f(CW$]\fR, or a literal of the form v5.6.1, which will be compared -to \f(CW$^V\fR (aka \f(CW$PERL_VERSION\fR). A fatal error is produced at run time if -\&\s-1VERSION\s0 is greater than the version of the current Perl interpreter. -Compare with \*(L"use\*(R", which can do a similar check at compile time. -.Sp -Specifying \s-1VERSION\s0 as a literal of the form v5.6.1 should generally be -avoided, because it leads to misleading error messages under earlier -versions of Perl that do not support this syntax. The equivalent numeric -version should be used instead. -.Sp -.Vb 3 -\& require v5.6.1; # run time version check -\& require 5.6.1; # ditto -\& require 5.006_001; # ditto; preferred for backwards compatibility -.Ve -.Sp -Otherwise, \f(CW\*(C`require\*(C'\fR demands that a library file be included if it -hasn't already been included. The file is included via the do-FILE -mechanism, which is essentially just a variety of \f(CW\*(C`eval\*(C'\fR. Has -semantics similar to the following subroutine: -.Sp -.Vb 28 -\& sub require { -\& my ($filename) = @_; -\& if (exists $INC{$filename}) { -\& return 1 if $INC{$filename}; -\& die "Compilation failed in require"; -\& } -\& my ($realfilename,$result); -\& ITER: { -\& foreach $prefix (@INC) { -\& $realfilename = "$prefix/$filename"; -\& if (-f $realfilename) { -\& $INC{$filename} = $realfilename; -\& $result = do $realfilename; -\& last ITER; -\& } -\& } -\& die "Can't find $filename in \e@INC"; -\& } -\& if ($@) { -\& $INC{$filename} = undef; -\& die $@; -\& } elsif (!$result) { -\& delete $INC{$filename}; -\& die "$filename did not return true value"; -\& } else { -\& return $result; -\& } -\& } -.Ve -.Sp -Note that the file will not be included twice under the same specified -name. -.Sp -The file must return true as the last statement to indicate -successful execution of any initialization code, so it's customary to -end such a file with \f(CW\*(C`1;\*(C'\fR unless you're sure it'll return true -otherwise. But it's better just to put the \f(CW\*(C`1;\*(C'\fR, in case you add more -statements. -.Sp -If \s-1EXPR\s0 is a bareword, the require assumes a "\fI.pm\fR\*(L" extension and -replaces \*(R"\fI::\fR\*(L" with \*(R"\fI/\fR" in the filename for you, -to make it easy to load standard modules. This form of loading of -modules does not risk altering your namespace. -.Sp -In other words, if you try this: -.Sp -.Vb 1 -\& require Foo::Bar; # a splendid bareword -.Ve -.Sp -The require function will actually look for the "\fIFoo/Bar.pm\fR" file in the -directories specified in the \f(CW@INC\fR array. -.Sp -But if you try this: -.Sp -.Vb 4 -\& $class = 'Foo::Bar'; -\& require $class; # $class is not a bareword -\& #or -\& require "Foo::Bar"; # not a bareword because of the "" -.Ve -.Sp -The require function will look for the "\fIFoo::Bar\fR\*(L" file in the \f(CW@INC\fR array and -will complain about not finding \*(R"\fIFoo::Bar\fR" there. In this case you can do: -.Sp -.Vb 1 -\& eval "require $class"; -.Ve -.Sp -Now that you understand how \f(CW\*(C`require\*(C'\fR looks for files in the case of -a bareword argument, there is a little extra functionality going on -behind the scenes. Before \f(CW\*(C`require\*(C'\fR looks for a "\fI.pm\fR\*(L" extension, -it will first look for a filename with a \*(R"\fI.pmc\fR" extension. A file -with this extension is assumed to be Perl bytecode generated by -B::Bytecode. If this file is found, and its modification -time is newer than a coinciding "\fI.pm\fR\*(L" non-compiled file, it will be -loaded in place of that non-compiled file ending in a \*(R"\fI.pm\fR" extension. -.Sp -You can also insert hooks into the import facility, by putting directly -Perl code into the \f(CW@INC\fR array. There are three forms of hooks: subroutine -references, array references and blessed objects. -.Sp -Subroutine references are the simplest case. When the inclusion system -walks through \f(CW@INC\fR and encounters a subroutine, this subroutine gets -called with two parameters, the first being a reference to itself, and the -second the name of the file to be included (e.g. "\fIFoo/Bar.pm\fR"). The -subroutine should return \f(CW\*(C`undef\*(C'\fR or a filehandle, from which the file to -include will be read. If \f(CW\*(C`undef\*(C'\fR is returned, \f(CW\*(C`require\*(C'\fR will look at -the remaining elements of \f(CW@INC\fR. -.Sp -If the hook is an array reference, its first element must be a subroutine -reference. This subroutine is called as above, but the first parameter is -the array reference. This enables to pass indirectly some arguments to -the subroutine. -.Sp -In other words, you can write: -.Sp -.Vb 5 -\& push @INC, \e&my_sub; -\& sub my_sub { -\& my ($coderef, $filename) = @_; # $coderef is \e&my_sub -\& ... -\& } -.Ve -.Sp -or: -.Sp -.Vb 7 -\& push @INC, [ \e&my_sub, $x, $y, ... ]; -\& sub my_sub { -\& my ($arrayref, $filename) = @_; -\& # Retrieve $x, $y, ... -\& my @parameters = @$arrayref[1..$#$arrayref]; -\& ... -\& } -.Ve -.Sp -If the hook is an object, it must provide an \s-1INC\s0 method that will be -called as above, the first parameter being the object itself. (Note that -you must fully qualify the sub's name, as it is always forced into package -\&\f(CW\*(C`main\*(C'\fR.) Here is a typical code layout: -.Sp -.Vb 7 -\& # In Foo.pm -\& package Foo; -\& sub new { ... } -\& sub Foo::INC { -\& my ($self, $filename) = @_; -\& ... -\& } -.Ve -.Sp -.Vb 2 -\& # In the main program -\& push @INC, new Foo(...); -.Ve -.Sp -Note that these hooks are also permitted to set the \f(CW%INC\fR entry -corresponding to the files they have loaded. See \*(L"%INC\*(R" in perlvar. -.Sp -For a yet-more-powerful import facility, see \*(L"use\*(R" and perlmod. -.IP "reset \s-1EXPR\s0" 8 -.IX Xref "reset" -.IX Item "reset EXPR" -.PD 0 -.IP "reset" 8 -.IX Item "reset" -.PD -Generally used in a \f(CW\*(C`continue\*(C'\fR block at the end of a loop to clear -variables and reset \f(CW\*(C`??\*(C'\fR searches so that they work again. The -expression is interpreted as a list of single characters (hyphens -allowed for ranges). All variables and arrays beginning with one of -those letters are reset to their pristine state. If the expression is -omitted, one-match searches (\f(CW\*(C`?pattern?\*(C'\fR) are reset to match again. Resets -only variables or searches in the current package. Always returns -1. Examples: -.Sp -.Vb 3 -\& reset 'X'; # reset all X variables -\& reset 'a-z'; # reset lower case variables -\& reset; # just reset ?one-time? searches -.Ve -.Sp -Resetting \f(CW"A\-Z"\fR is not recommended because you'll wipe out your -\&\f(CW@ARGV\fR and \f(CW@INC\fR arrays and your \f(CW%ENV\fR hash. Resets only package -variables\*(--lexical variables are unaffected, but they clean themselves -up on scope exit anyway, so you'll probably want to use them instead. -See \*(L"my\*(R". -.IP "return \s-1EXPR\s0" 8 -.IX Xref "return" -.IX Item "return EXPR" -.PD 0 -.IP "return" 8 -.IX Item "return" -.PD -Returns from a subroutine, \f(CW\*(C`eval\*(C'\fR, or \f(CW\*(C`do FILE\*(C'\fR with the value -given in \s-1EXPR\s0. Evaluation of \s-1EXPR\s0 may be in list, scalar, or void -context, depending on how the return value will be used, and the context -may vary from one execution to the next (see \f(CW\*(C`wantarray\*(C'\fR). If no \s-1EXPR\s0 -is given, returns an empty list in list context, the undefined value in -scalar context, and (of course) nothing at all in a void context. -.Sp -(Note that in the absence of an explicit \f(CW\*(C`return\*(C'\fR, a subroutine, eval, -or do \s-1FILE\s0 will automatically return the value of the last expression -evaluated.) -.IP "reverse \s-1LIST\s0" 8 -.IX Xref "reverse rev invert" -.IX Item "reverse LIST" -In list context, returns a list value consisting of the elements -of \s-1LIST\s0 in the opposite order. In scalar context, concatenates the -elements of \s-1LIST\s0 and returns a string value with all characters -in the opposite order. -.Sp -.Vb 1 -\& print reverse <>; # line tac, last line first -.Ve -.Sp -.Vb 2 -\& undef $/; # for efficiency of <> -\& print scalar reverse <>; # character tac, last line tsrif -.Ve -.Sp -Used without arguments in scalar context, \fIreverse()\fR reverses \f(CW$_\fR. -.Sp -This operator is also handy for inverting a hash, although there are some -caveats. If a value is duplicated in the original hash, only one of those -can be represented as a key in the inverted hash. Also, this has to -unwind one hash and build a whole new one, which may take some time -on a large hash, such as from a \s-1DBM\s0 file. -.Sp -.Vb 1 -\& %by_name = reverse %by_address; # Invert the hash -.Ve -.IP "rewinddir \s-1DIRHANDLE\s0" 8 -.IX Xref "rewinddir" -.IX Item "rewinddir DIRHANDLE" -Sets the current position to the beginning of the directory for the -\&\f(CW\*(C`readdir\*(C'\fR routine on \s-1DIRHANDLE\s0. -.IP "rindex \s-1STR\s0,SUBSTR,POSITION" 8 -.IX Xref "rindex" -.IX Item "rindex STR,SUBSTR,POSITION" -.PD 0 -.IP "rindex \s-1STR\s0,SUBSTR" 8 -.IX Item "rindex STR,SUBSTR" -.PD -Works just like \fIindex()\fR except that it returns the position of the \fIlast\fR -occurrence of \s-1SUBSTR\s0 in \s-1STR\s0. If \s-1POSITION\s0 is specified, returns the -last occurrence beginning at or before that position. -.IP "rmdir \s-1FILENAME\s0" 8 -.IX Xref "rmdir rd directory, remove" -.IX Item "rmdir FILENAME" -.PD 0 -.IP "rmdir" 8 -.IX Item "rmdir" -.PD -Deletes the directory specified by \s-1FILENAME\s0 if that directory is -empty. If it succeeds it returns true, otherwise it returns false and -sets \f(CW$!\fR (errno). If \s-1FILENAME\s0 is omitted, uses \f(CW$_\fR. -.IP "s///" 8 -.IX Item "s///" -The substitution operator. See perlop. -.IP "scalar \s-1EXPR\s0" 8 -.IX Xref "scalar context" -.IX Item "scalar EXPR" -Forces \s-1EXPR\s0 to be interpreted in scalar context and returns the value -of \s-1EXPR\s0. -.Sp -.Vb 1 -\& @counts = ( scalar @a, scalar @b, scalar @c ); -.Ve -.Sp -There is no equivalent operator to force an expression to -be interpolated in list context because in practice, this is never -needed. If you really wanted to do so, however, you could use -the construction \f(CW\*(C`@{[ (some expression) ]}\*(C'\fR, but usually a simple -\&\f(CW\*(C`(some expression)\*(C'\fR suffices. -.Sp -Because \f(CW\*(C`scalar\*(C'\fR is unary operator, if you accidentally use for \s-1EXPR\s0 a -parenthesized list, this behaves as a scalar comma expression, evaluating -all but the last element in void context and returning the final element -evaluated in scalar context. This is seldom what you want. -.Sp -The following single statement: -.Sp -.Vb 1 -\& print uc(scalar(&foo,$bar)),$baz; -.Ve -.Sp -is the moral equivalent of these two: -.Sp -.Vb 2 -\& &foo; -\& print(uc($bar),$baz); -.Ve -.Sp -See perlop for more details on unary operators and the comma operator. -.IP "seek \s-1FILEHANDLE\s0,POSITION,WHENCE" 8 -.IX Xref "seek fseek filehandle, position" -.IX Item "seek FILEHANDLE,POSITION,WHENCE" -Sets \s-1FILEHANDLE\s0's position, just like the \f(CW\*(C`fseek\*(C'\fR call of \f(CW\*(C`stdio\*(C'\fR. -\&\s-1FILEHANDLE\s0 may be an expression whose value gives the name of the -filehandle. The values for \s-1WHENCE\s0 are \f(CW0\fR to set the new position -\&\fIin bytes\fR to \s-1POSITION\s0, \f(CW1\fR to set it to the current position plus -\&\s-1POSITION\s0, and \f(CW2\fR to set it to \s-1EOF\s0 plus \s-1POSITION\s0 (typically -negative). For \s-1WHENCE\s0 you may use the constants \f(CW\*(C`SEEK_SET\*(C'\fR, -\&\f(CW\*(C`SEEK_CUR\*(C'\fR, and \f(CW\*(C`SEEK_END\*(C'\fR (start of the file, current position, end -of the file) from the Fcntl module. Returns \f(CW1\fR upon success, \f(CW0\fR -otherwise. -.Sp -Note the \fIin bytes\fR: even if the filehandle has been set to -operate on characters (for example by using the \f(CW\*(C`:utf8\*(C'\fR open -layer), \fItell()\fR will return byte offsets, not character offsets -(because implementing that would render \fIseek()\fR and \fItell()\fR rather slow). -.Sp -If you want to position file for \f(CW\*(C`sysread\*(C'\fR or \f(CW\*(C`syswrite\*(C'\fR, don't use -\&\f(CW\*(C`seek\*(C'\fR\-\-buffering makes its effect on the file's system position -unpredictable and non\-portable. Use \f(CW\*(C`sysseek\*(C'\fR instead. -.Sp -Due to the rules and rigors of \s-1ANSI\s0 C, on some systems you have to do a -seek whenever you switch between reading and writing. Amongst other -things, this may have the effect of calling stdio's \fIclearerr\fR\|(3). -A \s-1WHENCE\s0 of \f(CW1\fR (\f(CW\*(C`SEEK_CUR\*(C'\fR) is useful for not moving the file position: -.Sp -.Vb 1 -\& seek(TEST,0,1); -.Ve -.Sp -This is also useful for applications emulating \f(CW\*(C`tail \-f\*(C'\fR. Once you hit -\&\s-1EOF\s0 on your read, and then sleep for a while, you might have to stick in a -\&\fIseek()\fR to reset things. The \f(CW\*(C`seek\*(C'\fR doesn't change the current position, -but it \fIdoes\fR clear the end-of-file condition on the handle, so that the -next \f(CW\*(C`<FILE>\*(C'\fR makes Perl try again to read something. We hope. -.Sp -If that doesn't work (some \s-1IO\s0 implementations are particularly -cantankerous), then you may need something more like this: -.Sp -.Vb 8 -\& for (;;) { -\& for ($curpos = tell(FILE); $_ = <FILE>; -\& $curpos = tell(FILE)) { -\& # search for some stuff and put it into files -\& } -\& sleep($for_a_while); -\& seek(FILE, $curpos, 0); -\& } -.Ve -.IP "seekdir \s-1DIRHANDLE\s0,POS" 8 -.IX Xref "seekdir" -.IX Item "seekdir DIRHANDLE,POS" -Sets the current position for the \f(CW\*(C`readdir\*(C'\fR routine on \s-1DIRHANDLE\s0. \s-1POS\s0 -must be a value returned by \f(CW\*(C`telldir\*(C'\fR. \f(CW\*(C`seekdir\*(C'\fR also has the same caveats -about possible directory compaction as the corresponding system library -routine. -.IP "select \s-1FILEHANDLE\s0" 8 -.IX Xref "select filehandle, default" -.IX Item "select FILEHANDLE" -.PD 0 -.IP "select" 8 -.IX Item "select" -.PD -Returns the currently selected filehandle. Sets the current default -filehandle for output, if \s-1FILEHANDLE\s0 is supplied. This has two -effects: first, a \f(CW\*(C`write\*(C'\fR or a \f(CW\*(C`print\*(C'\fR without a filehandle will -default to this \s-1FILEHANDLE\s0. Second, references to variables related to -output will refer to this output channel. For example, if you have to -set the top of form format for more than one output channel, you might -do the following: -.Sp -.Vb 4 -\& select(REPORT1); -\& $^ = 'report1_top'; -\& select(REPORT2); -\& $^ = 'report2_top'; -.Ve -.Sp -\&\s-1FILEHANDLE\s0 may be an expression whose value gives the name of the -actual filehandle. Thus: -.Sp -.Vb 1 -\& $oldfh = select(STDERR); $| = 1; select($oldfh); -.Ve -.Sp -Some programmers may prefer to think of filehandles as objects with -methods, preferring to write the last example as: -.Sp -.Vb 2 -\& use IO::Handle; -\& STDERR->autoflush(1); -.Ve -.IP "select \s-1RBITS\s0,WBITS,EBITS,TIMEOUT" 8 -.IX Xref "select" -.IX Item "select RBITS,WBITS,EBITS,TIMEOUT" -This calls the \fIselect\fR\|(2) system call with the bit masks specified, which -can be constructed using \f(CW\*(C`fileno\*(C'\fR and \f(CW\*(C`vec\*(C'\fR, along these lines: -.Sp -.Vb 4 -\& $rin = $win = $ein = ''; -\& vec($rin,fileno(STDIN),1) = 1; -\& vec($win,fileno(STDOUT),1) = 1; -\& $ein = $rin | $win; -.Ve -.Sp -If you want to select on many filehandles you might wish to write a -subroutine: -.Sp -.Vb 9 -\& sub fhbits { -\& my(@fhlist) = split(' ',$_[0]); -\& my($bits); -\& for (@fhlist) { -\& vec($bits,fileno($_),1) = 1; -\& } -\& $bits; -\& } -\& $rin = fhbits('STDIN TTY SOCK'); -.Ve -.Sp -The usual idiom is: -.Sp -.Vb 2 -\& ($nfound,$timeleft) = -\& select($rout=$rin, $wout=$win, $eout=$ein, $timeout); -.Ve -.Sp -or to block until something becomes ready just do this -.Sp -.Vb 1 -\& $nfound = select($rout=$rin, $wout=$win, $eout=$ein, undef); -.Ve -.Sp -Most systems do not bother to return anything useful in \f(CW$timeleft\fR, so -calling \fIselect()\fR in scalar context just returns \f(CW$nfound\fR. -.Sp -Any of the bit masks can also be undef. The timeout, if specified, is -in seconds, which may be fractional. Note: not all implementations are -capable of returning the \f(CW$timeleft\fR. If not, they always return -\&\f(CW$timeleft\fR equal to the supplied \f(CW$timeout\fR. -.Sp -You can effect a sleep of 250 milliseconds this way: -.Sp -.Vb 1 -\& select(undef, undef, undef, 0.25); -.Ve -.Sp -Note that whether \f(CW\*(C`select\*(C'\fR gets restarted after signals (say, \s-1SIGALRM\s0) -is implementation\-dependent. See also perlport for notes on the -portability of \f(CW\*(C`select\*(C'\fR. -.Sp -On error, \f(CW\*(C`select\*(C'\fR behaves like the \fIselect\fR\|(2) system call : it returns -\&\-1 and sets \f(CW$!\fR. -.Sp -Note: on some Unixes, the \fIselect\fR\|(2) system call may report a socket file -descriptor as \*(L"ready for reading\*(R", when actually no data is available, -thus a subsequent read blocks. It can be avoided using always the -O_NONBLOCK flag on the socket. See \fIselect\fR\|(2) and \fIfcntl\fR\|(2) for further -details. -.Sp -\&\fB\s-1WARNING\s0\fR: One should not attempt to mix buffered I/O (like \f(CW\*(C`read\*(C'\fR -or <\s-1FH\s0>) with \f(CW\*(C`select\*(C'\fR, except as permitted by \s-1POSIX\s0, and even -then only on \s-1POSIX\s0 systems. You have to use \f(CW\*(C`sysread\*(C'\fR instead. -.IP "semctl \s-1ID\s0,SEMNUM,CMD,ARG" 8 -.IX Xref "semctl" -.IX Item "semctl ID,SEMNUM,CMD,ARG" -Calls the System V \s-1IPC\s0 function \f(CW\*(C`semctl\*(C'\fR. You'll probably have to say -.Sp -.Vb 1 -\& use IPC::SysV; -.Ve -.Sp -first to get the correct constant definitions. If \s-1CMD\s0 is \s-1IPC_STAT\s0 or -\&\s-1GETALL\s0, then \s-1ARG\s0 must be a variable that will hold the returned -semid_ds structure or semaphore value array. Returns like \f(CW\*(C`ioctl\*(C'\fR: -the undefined value for error, "\f(CW\*(C`0 but true\*(C'\fR" for zero, or the actual -return value otherwise. The \s-1ARG\s0 must consist of a vector of native -short integers, which may be created with \f(CW\*(C`pack("s!",(0)x$nsem)\*(C'\fR. -See also \*(L"SysV \s-1IPC\s0\*(R" in perlipc, \f(CW\*(C`IPC::SysV\*(C'\fR, \f(CW\*(C`IPC::Semaphore\*(C'\fR -documentation. -.IP "semget \s-1KEY\s0,NSEMS,FLAGS" 8 -.IX Xref "semget" -.IX Item "semget KEY,NSEMS,FLAGS" -Calls the System V \s-1IPC\s0 function semget. Returns the semaphore id, or -the undefined value if there is an error. See also -\&\*(L"SysV \s-1IPC\s0\*(R" in perlipc, \f(CW\*(C`IPC::SysV\*(C'\fR, \f(CW\*(C`IPC::SysV::Semaphore\*(C'\fR -documentation. -.IP "semop \s-1KEY\s0,OPSTRING" 8 -.IX Xref "semop" -.IX Item "semop KEY,OPSTRING" -Calls the System V \s-1IPC\s0 function semop to perform semaphore operations -such as signalling and waiting. \s-1OPSTRING\s0 must be a packed array of -semop structures. Each semop structure can be generated with -\&\f(CW\*(C`pack("s!3", $semnum, $semop, $semflag)\*(C'\fR. The length of \s-1OPSTRING\s0 -implies the number of semaphore operations. Returns true if -successful, or false if there is an error. As an example, the -following code waits on semaphore \f(CW$semnum\fR of semaphore id \f(CW$semid:\fR -.Sp -.Vb 2 -\& $semop = pack("s!3", $semnum, -1, 0); -\& die "Semaphore trouble: $!\en" unless semop($semid, $semop); -.Ve -.Sp -To signal the semaphore, replace \f(CW\*(C`\-1\*(C'\fR with \f(CW1\fR. See also -\&\*(L"SysV \s-1IPC\s0\*(R" in perlipc, \f(CW\*(C`IPC::SysV\*(C'\fR, and \f(CW\*(C`IPC::SysV::Semaphore\*(C'\fR -documentation. -.IP "send \s-1SOCKET\s0,MSG,FLAGS,TO" 8 -.IX Xref "send" -.IX Item "send SOCKET,MSG,FLAGS,TO" -.PD 0 -.IP "send \s-1SOCKET\s0,MSG,FLAGS" 8 -.IX Item "send SOCKET,MSG,FLAGS" -.PD -Sends a message on a socket. Attempts to send the scalar \s-1MSG\s0 to the -\&\s-1SOCKET\s0 filehandle. Takes the same flags as the system call of the -same name. On unconnected sockets you must specify a destination to -send \s-1TO\s0, in which case it does a C \f(CW\*(C`sendto\*(C'\fR. Returns the number of -characters sent, or the undefined value if there is an error. The C -system call \fIsendmsg\fR\|(2) is currently unimplemented. See -\&\*(L"\s-1UDP:\s0 Message Passing\*(R" in perlipc for examples. -.Sp -Note the \fIcharacters\fR: depending on the status of the socket, either -(8\-bit) bytes or characters are sent. By default all sockets operate -on bytes, but for example if the socket has been changed using -\&\fIbinmode()\fR to operate with the \f(CW\*(C`:utf8\*(C'\fR I/O layer (see \*(L"open\*(R", or the -\&\f(CW\*(C`open\*(C'\fR pragma, open), the I/O will operate on \s-1UTF\-8\s0 encoded -Unicode characters, not bytes. Similarly for the \f(CW\*(C`:encoding\*(C'\fR pragma: -in that case pretty much any characters can be sent. -.IP "setpgrp \s-1PID\s0,PGRP" 8 -.IX Xref "setpgrp group" -.IX Item "setpgrp PID,PGRP" -Sets the current process group for the specified \s-1PID\s0, \f(CW0\fR for the current -process. Will produce a fatal error if used on a machine that doesn't -implement \s-1POSIX\s0 \fIsetpgid\fR\|(2) or \s-1BSD\s0 \fIsetpgrp\fR\|(2). If the arguments are omitted, -it defaults to \f(CW\*(C`0,0\*(C'\fR. Note that the \s-1BSD\s0 4.2 version of \f(CW\*(C`setpgrp\*(C'\fR does not -accept any arguments, so only \f(CW\*(C`setpgrp(0,0)\*(C'\fR is portable. See also -\&\f(CW\*(C`POSIX::setsid()\*(C'\fR. -.IP "setpriority \s-1WHICH\s0,WHO,PRIORITY" 8 -.IX Xref "setpriority priority nice renice" -.IX Item "setpriority WHICH,WHO,PRIORITY" -Sets the current priority for a process, a process group, or a user. -(See \fIsetpriority\fR\|(2).) Will produce a fatal error if used on a machine -that doesn't implement \fIsetpriority\fR\|(2). -.IP "setsockopt \s-1SOCKET\s0,LEVEL,OPTNAME,OPTVAL" 8 -.IX Xref "setsockopt" -.IX Item "setsockopt SOCKET,LEVEL,OPTNAME,OPTVAL" -Sets the socket option requested. Returns undefined if there is an -error. Use integer constants provided by the \f(CW\*(C`Socket\*(C'\fR module for -\&\s-1LEVEL\s0 and \s-1OPNAME\s0. Values for \s-1LEVEL\s0 can also be obtained from -getprotobyname. \s-1OPTVAL\s0 might either be a packed string or an integer. -An integer \s-1OPTVAL\s0 is shorthand for pack(\*(L"i\*(R", \s-1OPTVAL\s0). -.Sp -An example disabling the Nagle's algorithm for a socket: -.Sp -.Vb 2 -\& use Socket qw(IPPROTO_TCP TCP_NODELAY); -\& setsockopt($socket, IPPROTO_TCP, TCP_NODELAY, 1); -.Ve -.IP "shift \s-1ARRAY\s0" 8 -.IX Xref "shift" -.IX Item "shift ARRAY" -.PD 0 -.IP "shift" 8 -.IX Item "shift" -.PD -Shifts the first value of the array off and returns it, shortening the -array by 1 and moving everything down. If there are no elements in the -array, returns the undefined value. If \s-1ARRAY\s0 is omitted, shifts the -\&\f(CW@_\fR array within the lexical scope of subroutines and formats, and the -\&\f(CW@ARGV\fR array at file scopes or within the lexical scopes established by -the \f(CW\*(C`eval ''\*(C'\fR, \f(CW\*(C`BEGIN {}\*(C'\fR, \f(CW\*(C`INIT {}\*(C'\fR, \f(CW\*(C`CHECK {}\*(C'\fR, and \f(CW\*(C`END {}\*(C'\fR -constructs. -.Sp -See also \f(CW\*(C`unshift\*(C'\fR, \f(CW\*(C`push\*(C'\fR, and \f(CW\*(C`pop\*(C'\fR. \f(CW\*(C`shift\*(C'\fR and \f(CW\*(C`unshift\*(C'\fR do the -same thing to the left end of an array that \f(CW\*(C`pop\*(C'\fR and \f(CW\*(C`push\*(C'\fR do to the -right end. -.IP "shmctl \s-1ID\s0,CMD,ARG" 8 -.IX Xref "shmctl" -.IX Item "shmctl ID,CMD,ARG" -Calls the System V \s-1IPC\s0 function shmctl. You'll probably have to say -.Sp -.Vb 1 -\& use IPC::SysV; -.Ve -.Sp -first to get the correct constant definitions. If \s-1CMD\s0 is \f(CW\*(C`IPC_STAT\*(C'\fR, -then \s-1ARG\s0 must be a variable that will hold the returned \f(CW\*(C`shmid_ds\*(C'\fR -structure. Returns like ioctl: the undefined value for error, "\f(CW0\fR but -true" for zero, or the actual return value otherwise. -See also \*(L"SysV \s-1IPC\s0\*(R" in perlipc and \f(CW\*(C`IPC::SysV\*(C'\fR documentation. -.IP "shmget \s-1KEY\s0,SIZE,FLAGS" 8 -.IX Xref "shmget" -.IX Item "shmget KEY,SIZE,FLAGS" -Calls the System V \s-1IPC\s0 function shmget. Returns the shared memory -segment id, or the undefined value if there is an error. -See also \*(L"SysV \s-1IPC\s0\*(R" in perlipc and \f(CW\*(C`IPC::SysV\*(C'\fR documentation. -.IP "shmread \s-1ID\s0,VAR,POS,SIZE" 8 -.IX Xref "shmread shmwrite" -.IX Item "shmread ID,VAR,POS,SIZE" -.PD 0 -.IP "shmwrite \s-1ID\s0,STRING,POS,SIZE" 8 -.IX Item "shmwrite ID,STRING,POS,SIZE" -.PD -Reads or writes the System V shared memory segment \s-1ID\s0 starting at -position \s-1POS\s0 for size \s-1SIZE\s0 by attaching to it, copying in/out, and -detaching from it. When reading, \s-1VAR\s0 must be a variable that will -hold the data read. When writing, if \s-1STRING\s0 is too long, only \s-1SIZE\s0 -bytes are used; if \s-1STRING\s0 is too short, nulls are written to fill out -\&\s-1SIZE\s0 bytes. Return true if successful, or false if there is an error. -\&\fIshmread()\fR taints the variable. See also \*(L"SysV \s-1IPC\s0\*(R" in perlipc, -\&\f(CW\*(C`IPC::SysV\*(C'\fR documentation, and the \f(CW\*(C`IPC::Shareable\*(C'\fR module from \s-1CPAN\s0. -.IP "shutdown \s-1SOCKET\s0,HOW" 8 -.IX Xref "shutdown" -.IX Item "shutdown SOCKET,HOW" -Shuts down a socket connection in the manner indicated by \s-1HOW\s0, which -has the same interpretation as in the system call of the same name. -.Sp -.Vb 3 -\& shutdown(SOCKET, 0); # I/we have stopped reading data -\& shutdown(SOCKET, 1); # I/we have stopped writing data -\& shutdown(SOCKET, 2); # I/we have stopped using this socket -.Ve -.Sp -This is useful with sockets when you want to tell the other -side you're done writing but not done reading, or vice versa. -It's also a more insistent form of close because it also -disables the file descriptor in any forked copies in other -processes. -.IP "sin \s-1EXPR\s0" 8 -.IX Xref "sin sine asin arcsine" -.IX Item "sin EXPR" -.PD 0 -.IP "sin" 8 -.IX Item "sin" -.PD -Returns the sine of \s-1EXPR\s0 (expressed in radians). If \s-1EXPR\s0 is omitted, -returns sine of \f(CW$_\fR. -.Sp -For the inverse sine operation, you may use the \f(CW\*(C`Math::Trig::asin\*(C'\fR -function, or use this relation: -.Sp -.Vb 1 -\& sub asin { atan2($_[0], sqrt(1 - $_[0] * $_[0])) } -.Ve -.IP "sleep \s-1EXPR\s0" 8 -.IX Xref "sleep pause" -.IX Item "sleep EXPR" -.PD 0 -.IP "sleep" 8 -.IX Item "sleep" -.PD -Causes the script to sleep for \s-1EXPR\s0 seconds, or forever if no \s-1EXPR\s0. -May be interrupted if the process receives a signal such as \f(CW\*(C`SIGALRM\*(C'\fR. -Returns the number of seconds actually slept. You probably cannot -mix \f(CW\*(C`alarm\*(C'\fR and \f(CW\*(C`sleep\*(C'\fR calls, because \f(CW\*(C`sleep\*(C'\fR is often implemented -using \f(CW\*(C`alarm\*(C'\fR. -.Sp -On some older systems, it may sleep up to a full second less than what -you requested, depending on how it counts seconds. Most modern systems -always sleep the full amount. They may appear to sleep longer than that, -however, because your process might not be scheduled right away in a -busy multitasking system. -.Sp -For delays of finer granularity than one second, you may use Perl's -\&\f(CW\*(C`syscall\*(C'\fR interface to access \fIsetitimer\fR\|(2) if your system supports -it, or else see \*(L"select\*(R" above. The Time::HiRes module (from \s-1CPAN\s0, -and starting from Perl 5.8 part of the standard distribution) may also -help. -.Sp -See also the \s-1POSIX\s0 module's \f(CW\*(C`pause\*(C'\fR function. -.IP "socket \s-1SOCKET\s0,DOMAIN,TYPE,PROTOCOL" 8 -.IX Xref "socket" -.IX Item "socket SOCKET,DOMAIN,TYPE,PROTOCOL" -Opens a socket of the specified kind and attaches it to filehandle -\&\s-1SOCKET\s0. \s-1DOMAIN\s0, \s-1TYPE\s0, and \s-1PROTOCOL\s0 are specified the same as for -the system call of the same name. You should \f(CW\*(C`use Socket\*(C'\fR first -to get the proper definitions imported. See the examples in -\&\*(L"Sockets: Client/Server Communication\*(R" in perlipc. -.Sp -On systems that support a close-on-exec flag on files, the flag will -be set for the newly opened file descriptor, as determined by the -value of $^F. See \*(L"$^F\*(R" in perlvar. -.IP "socketpair \s-1SOCKET1\s0,SOCKET2,DOMAIN,TYPE,PROTOCOL" 8 -.IX Xref "socketpair" -.IX Item "socketpair SOCKET1,SOCKET2,DOMAIN,TYPE,PROTOCOL" -Creates an unnamed pair of sockets in the specified domain, of the -specified type. \s-1DOMAIN\s0, \s-1TYPE\s0, and \s-1PROTOCOL\s0 are specified the same as -for the system call of the same name. If unimplemented, yields a fatal -error. Returns true if successful. -.Sp -On systems that support a close-on-exec flag on files, the flag will -be set for the newly opened file descriptors, as determined by the value -of $^F. See \*(L"$^F\*(R" in perlvar. -.Sp -Some systems defined \f(CW\*(C`pipe\*(C'\fR in terms of \f(CW\*(C`socketpair\*(C'\fR, in which a call -to \f(CW\*(C`pipe(Rdr, Wtr)\*(C'\fR is essentially: -.Sp -.Vb 4 -\& use Socket; -\& socketpair(Rdr, Wtr, AF_UNIX, SOCK_STREAM, PF_UNSPEC); -\& shutdown(Rdr, 1); # no more writing for reader -\& shutdown(Wtr, 0); # no more reading for writer -.Ve -.Sp -See perlipc for an example of socketpair use. Perl 5.8 and later will -emulate socketpair using \s-1IP\s0 sockets to localhost if your system implements -sockets but not socketpair. -.IP "sort \s-1SUBNAME\s0 \s-1LIST\s0" 8 -.IX Xref "sort qsort quicksort mergesort" -.IX Item "sort SUBNAME LIST" -.PD 0 -.IP "sort \s-1BLOCK\s0 \s-1LIST\s0" 8 -.IX Item "sort BLOCK LIST" -.IP "sort \s-1LIST\s0" 8 -.IX Item "sort LIST" -.PD -In list context, this sorts the \s-1LIST\s0 and returns the sorted list value. -In scalar context, the behaviour of \f(CW\*(C`sort()\*(C'\fR is undefined. -.Sp -If \s-1SUBNAME\s0 or \s-1BLOCK\s0 is omitted, \f(CW\*(C`sort\*(C'\fRs in standard string comparison -order. If \s-1SUBNAME\s0 is specified, it gives the name of a subroutine -that returns an integer less than, equal to, or greater than \f(CW0\fR, -depending on how the elements of the list are to be ordered. (The \f(CW\*(C`<=>\*(C'\fR and \f(CW\*(C`cmp\*(C'\fR operators are extremely useful in such routines.) -\&\s-1SUBNAME\s0 may be a scalar variable name (unsubscripted), in which case -the value provides the name of (or a reference to) the actual -subroutine to use. In place of a \s-1SUBNAME\s0, you can provide a \s-1BLOCK\s0 as -an anonymous, in-line sort subroutine. -.Sp -If the subroutine's prototype is \f(CW\*(C`($$)\*(C'\fR, the elements to be compared -are passed by reference in \f(CW@_\fR, as for a normal subroutine. This is -slower than unprototyped subroutines, where the elements to be -compared are passed into the subroutine -as the package global variables \f(CW$a\fR and \f(CW$b\fR (see example below). Note that -in the latter case, it is usually counter-productive to declare \f(CW$a\fR and -\&\f(CW$b\fR as lexicals. -.Sp -In either case, the subroutine may not be recursive. The values to be -compared are always passed by reference and should not be modified. -.Sp -You also cannot exit out of the sort block or subroutine using any of the -loop control operators described in perlsyn or with \f(CW\*(C`goto\*(C'\fR. -.Sp -When \f(CW\*(C`use locale\*(C'\fR is in effect, \f(CW\*(C`sort LIST\*(C'\fR sorts \s-1LIST\s0 according to the -current collation locale. See perllocale. -.Sp -\&\fIsort()\fR returns aliases into the original list, much as a for loop's index -variable aliases the list elements. That is, modifying an element of a -list returned by \fIsort()\fR (for example, in a \f(CW\*(C`foreach\*(C'\fR, \f(CW\*(C`map\*(C'\fR or \f(CW\*(C`grep\*(C'\fR) -actually modifies the element in the original list. This is usually -something to be avoided when writing clear code. -.Sp -Perl 5.6 and earlier used a quicksort algorithm to implement sort. -That algorithm was not stable, and \fIcould\fR go quadratic. (A \fIstable\fR sort -preserves the input order of elements that compare equal. Although -quicksort's run time is O(NlogN) when averaged over all arrays of -length N, the time can be O(N**2), \fIquadratic\fR behavior, for some -inputs.) In 5.7, the quicksort implementation was replaced with -a stable mergesort algorithm whose worst-case behavior is O(NlogN). -But benchmarks indicated that for some inputs, on some platforms, -the original quicksort was faster. 5.8 has a sort pragma for -limited control of the sort. Its rather blunt control of the -underlying algorithm may not persist into future Perls, but the -ability to characterize the input or output in implementation -independent ways quite probably will. See sort. -.Sp -Examples: -.Sp -.Vb 2 -\& # sort lexically -\& @articles = sort @files; -.Ve -.Sp -.Vb 2 -\& # same thing, but with explicit sort routine -\& @articles = sort {$a cmp $b} @files; -.Ve -.Sp -.Vb 2 -\& # now case-insensitively -\& @articles = sort {uc($a) cmp uc($b)} @files; -.Ve -.Sp -.Vb 2 -\& # same thing in reversed order -\& @articles = sort {$b cmp $a} @files; -.Ve -.Sp -.Vb 2 -\& # sort numerically ascending -\& @articles = sort {$a <=> $b} @files; -.Ve -.Sp -.Vb 2 -\& # sort numerically descending -\& @articles = sort {$b <=> $a} @files; -.Ve -.Sp -.Vb 3 -\& # this sorts the %age hash by value instead of key -\& # using an in-line function -\& @eldest = sort { $age{$b} <=> $age{$a} } keys %age; -.Ve -.Sp -.Vb 5 -\& # sort using explicit subroutine name -\& sub byage { -\& $age{$a} <=> $age{$b}; # presuming numeric -\& } -\& @sortedclass = sort byage @class; -.Ve -.Sp -.Vb 9 -\& sub backwards { $b cmp $a } -\& @harry = qw(dog cat x Cain Abel); -\& @george = qw(gone chased yz Punished Axed); -\& print sort @harry; -\& # prints AbelCaincatdogx -\& print sort backwards @harry; -\& # prints xdogcatCainAbel -\& print sort @george, 'to', @harry; -\& # prints AbelAxedCainPunishedcatchaseddoggonetoxyz -.Ve -.Sp -.Vb 3 -\& # inefficiently sort by descending numeric compare using -\& # the first integer after the first = sign, or the -\& # whole record case-insensitively otherwise -.Ve -.Sp -.Vb 5 -\& @new = sort { -\& ($b =~ /=(\ed+)/)[0] <=> ($a =~ /=(\ed+)/)[0] -\& || -\& uc($a) cmp uc($b) -\& } @old; -.Ve -.Sp -.Vb 8 -\& # same thing, but much more efficiently; -\& # we'll build auxiliary indices instead -\& # for speed -\& @nums = @caps = (); -\& for (@old) { -\& push @nums, /=(\ed+)/; -\& push @caps, uc($_); -\& } -.Ve -.Sp -.Vb 6 -\& @new = @old[ sort { -\& $nums[$b] <=> $nums[$a] -\& || -\& $caps[$a] cmp $caps[$b] -\& } 0..$#old -\& ]; -.Ve -.Sp -.Vb 6 -\& # same thing, but without any temps -\& @new = map { $_->[0] } -\& sort { $b->[1] <=> $a->[1] -\& || -\& $a->[2] cmp $b->[2] -\& } map { [$_, /=(\ed+)/, uc($_)] } @old; -.Ve -.Sp -.Vb 4 -\& # using a prototype allows you to use any comparison subroutine -\& # as a sort subroutine (including other package's subroutines) -\& package other; -\& sub backwards ($$) { $_[1] cmp $_[0]; } # $a and $b are not set here -.Ve -.Sp -.Vb 2 -\& package main; -\& @new = sort other::backwards @old; -.Ve -.Sp -.Vb 3 -\& # guarantee stability, regardless of algorithm -\& use sort 'stable'; -\& @new = sort { substr($a, 3, 5) cmp substr($b, 3, 5) } @old; -.Ve -.Sp -.Vb 3 -\& # force use of mergesort (not portable outside Perl 5.8) -\& use sort '_mergesort'; # note discouraging _ -\& @new = sort { substr($a, 3, 5) cmp substr($b, 3, 5) } @old; -.Ve -.Sp -If you're using strict, you \fImust not\fR declare \f(CW$a\fR -and \f(CW$b\fR as lexicals. They are package globals. That means -if you're in the \f(CW\*(C`main\*(C'\fR package and type -.Sp -.Vb 1 -\& @articles = sort {$b <=> $a} @files; -.Ve -.Sp -then \f(CW$a\fR and \f(CW$b\fR are \f(CW$main::a\fR and \f(CW$main::b\fR (or \f(CW$::a\fR and \f(CW$::b\fR), -but if you're in the \f(CW\*(C`FooPack\*(C'\fR package, it's the same as typing -.Sp -.Vb 1 -\& @articles = sort {$FooPack::b <=> $FooPack::a} @files; -.Ve -.Sp -The comparison function is required to behave. If it returns -inconsistent results (sometimes saying \f(CW$x[1]\fR is less than \f(CW$x[2]\fR and -sometimes saying the opposite, for example) the results are not -well\-defined. -.Sp -Because \f(CW\*(C`<=>\*(C'\fR returns \f(CW\*(C`undef\*(C'\fR when either operand is \f(CW\*(C`NaN\*(C'\fR -(not\-a\-number), and because \f(CW\*(C`sort\*(C'\fR will trigger a fatal error unless the -result of a comparison is defined, when sorting with a comparison function -like \f(CW\*(C`$a <=> $b\*(C'\fR, be careful about lists that might contain a \f(CW\*(C`NaN\*(C'\fR. -The following example takes advantage of the fact that \f(CW\*(C`NaN != NaN\*(C'\fR to -eliminate any \f(CW\*(C`NaN\*(C'\fRs from the input. -.Sp -.Vb 1 -\& @result = sort { $a <=> $b } grep { $_ == $_ } @input; -.Ve -.IP "splice \s-1ARRAY\s0,OFFSET,LENGTH,LIST" 8 -.IX Xref "splice" -.IX Item "splice ARRAY,OFFSET,LENGTH,LIST" -.PD 0 -.IP "splice \s-1ARRAY\s0,OFFSET,LENGTH" 8 -.IX Item "splice ARRAY,OFFSET,LENGTH" -.IP "splice \s-1ARRAY\s0,OFFSET" 8 -.IX Item "splice ARRAY,OFFSET" -.IP "splice \s-1ARRAY\s0" 8 -.IX Item "splice ARRAY" -.PD -Removes the elements designated by \s-1OFFSET\s0 and \s-1LENGTH\s0 from an array, and -replaces them with the elements of \s-1LIST\s0, if any. In list context, -returns the elements removed from the array. In scalar context, -returns the last element removed, or \f(CW\*(C`undef\*(C'\fR if no elements are -removed. The array grows or shrinks as necessary. -If \s-1OFFSET\s0 is negative then it starts that far from the end of the array. -If \s-1LENGTH\s0 is omitted, removes everything from \s-1OFFSET\s0 onward. -If \s-1LENGTH\s0 is negative, removes the elements from \s-1OFFSET\s0 onward -except for \-LENGTH elements at the end of the array. -If both \s-1OFFSET\s0 and \s-1LENGTH\s0 are omitted, removes everything. If \s-1OFFSET\s0 is -past the end of the array, perl issues a warning, and splices at the -end of the array. -.Sp -The following equivalences hold (assuming \f(CW\*(C`$[ == 0 and $#a >= $i\*(C'\fR ) -.Sp -.Vb 5 -\& push(@a,$x,$y) splice(@a,@a,0,$x,$y) -\& pop(@a) splice(@a,-1) -\& shift(@a) splice(@a,0,1) -\& unshift(@a,$x,$y) splice(@a,0,0,$x,$y) -\& $a[$i] = $y splice(@a,$i,1,$y) -.Ve -.Sp -Example, assuming array lengths are passed before arrays: -.Sp -.Vb 10 -\& sub aeq { # compare two list values -\& my(@a) = splice(@_,0,shift); -\& my(@b) = splice(@_,0,shift); -\& return 0 unless @a == @b; # same len? -\& while (@a) { -\& return 0 if pop(@a) ne pop(@b); -\& } -\& return 1; -\& } -\& if (&aeq($len,@foo[1..$len],0+@bar,@bar)) { ... } -.Ve -.IP "split /PATTERN/,EXPR,LIMIT" 8 -.IX Xref "split" -.IX Item "split /PATTERN/,EXPR,LIMIT" -.PD 0 -.IP "split /PATTERN/,EXPR" 8 -.IX Item "split /PATTERN/,EXPR" -.IP "split /PATTERN/" 8 -.IX Item "split /PATTERN/" -.IP "split" 8 -.IX Item "split" -.PD -Splits the string \s-1EXPR\s0 into a list of strings and returns that list. By -default, empty leading fields are preserved, and empty trailing ones are -deleted. (If all fields are empty, they are considered to be trailing.) -.Sp -In scalar context, returns the number of fields found and splits into -the \f(CW@_\fR array. Use of split in scalar context is deprecated, however, -because it clobbers your subroutine arguments. -.Sp -If \s-1EXPR\s0 is omitted, splits the \f(CW$_\fR string. If \s-1PATTERN\s0 is also omitted, -splits on whitespace (after skipping any leading whitespace). Anything -matching \s-1PATTERN\s0 is taken to be a delimiter separating the fields. (Note -that the delimiter may be longer than one character.) -.Sp -If \s-1LIMIT\s0 is specified and positive, it represents the maximum number -of fields the \s-1EXPR\s0 will be split into, though the actual number of -fields returned depends on the number of times \s-1PATTERN\s0 matches within -\&\s-1EXPR\s0. If \s-1LIMIT\s0 is unspecified or zero, trailing null fields are -stripped (which potential users of \f(CW\*(C`pop\*(C'\fR would do well to remember). -If \s-1LIMIT\s0 is negative, it is treated as if an arbitrarily large \s-1LIMIT\s0 -had been specified. Note that splitting an \s-1EXPR\s0 that evaluates to the -empty string always returns the empty list, regardless of the \s-1LIMIT\s0 -specified. -.Sp -A pattern matching the null string (not to be confused with -a null pattern \f(CW\*(C`//\*(C'\fR, which is just one member of the set of patterns -matching a null string) will split the value of \s-1EXPR\s0 into separate -characters at each point it matches that way. For example: -.Sp -.Vb 1 -\& print join(':', split(/ */, 'hi there')); -.Ve -.Sp -produces the output 'h:i:t:h:e:r:e'. -.Sp -As a special case for \f(CW\*(C`split\*(C'\fR, using the empty pattern \f(CW\*(C`//\*(C'\fR specifically -matches only the null string, and is not be confused with the regular use -of \f(CW\*(C`//\*(C'\fR to mean \*(L"the last successful pattern match\*(R". So, for \f(CW\*(C`split\*(C'\fR, -the following: -.Sp -.Vb 1 -\& print join(':', split(//, 'hi there')); -.Ve -.Sp -produces the output 'h:i: :t:h:e:r:e'. -.Sp -Empty leading (or trailing) fields are produced when there are positive -width matches at the beginning (or end) of the string; a zero-width match -at the beginning (or end) of the string does not produce an empty field. -For example: -.Sp -.Vb 1 -\& print join(':', split(/(?=\ew)/, 'hi there!')); -.Ve -.Sp -produces the output 'h:i :t:h:e:r:e!'. -.Sp -The \s-1LIMIT\s0 parameter can be used to split a line partially -.Sp -.Vb 1 -\& ($login, $passwd, $remainder) = split(/:/, $_, 3); -.Ve -.Sp -When assigning to a list, if \s-1LIMIT\s0 is omitted, or zero, Perl supplies -a \s-1LIMIT\s0 one larger than the number of variables in the list, to avoid -unnecessary work. For the list above \s-1LIMIT\s0 would have been 4 by -default. In time critical applications it behooves you not to split -into more fields than you really need. -.Sp -If the \s-1PATTERN\s0 contains parentheses, additional list elements are -created from each matching substring in the delimiter. -.Sp -.Vb 1 -\& split(/([,-])/, "1-10,20", 3); -.Ve -.Sp -produces the list value -.Sp -.Vb 1 -\& (1, '-', 10, ',', 20) -.Ve -.Sp -If you had the entire header of a normal Unix email message in \f(CW$header\fR, -you could split it up into fields and their values this way: -.Sp -.Vb 2 -\& $header =~ s/\en\es+/ /g; # fix continuation lines -\& %hdrs = (UNIX_FROM => split /^(\eS*?):\es*/m, $header); -.Ve -.Sp -The pattern \f(CW\*(C`/PATTERN/\*(C'\fR may be replaced with an expression to specify -patterns that vary at runtime. (To do runtime compilation only once, -use \f(CW\*(C`/$variable/o\*(C'\fR.) -.Sp -As a special case, specifying a \s-1PATTERN\s0 of space (\f(CW'\ '\fR) will split on -white space just as \f(CW\*(C`split\*(C'\fR with no arguments does. Thus, \f(CW\*(C`split('\ ')\*(C'\fR can -be used to emulate \fBawk\fR's default behavior, whereas \f(CW\*(C`split(/\ /)\*(C'\fR -will give you as many null initial fields as there are leading spaces. -A \f(CW\*(C`split\*(C'\fR on \f(CW\*(C`/\es+/\*(C'\fR is like a \f(CW\*(C`split('\ ')\*(C'\fR except that any leading -whitespace produces a null first field. A \f(CW\*(C`split\*(C'\fR with no arguments -really does a \f(CW\*(C`split('\ ',\ $_)\*(C'\fR internally. -.Sp -A \s-1PATTERN\s0 of \f(CW\*(C`/^/\*(C'\fR is treated as if it were \f(CW\*(C`/^/m\*(C'\fR, since it isn't -much use otherwise. -.Sp -Example: -.Sp -.Vb 7 -\& open(PASSWD, '/etc/passwd'); -\& while (<PASSWD>) { -\& chomp; -\& ($login, $passwd, $uid, $gid, -\& $gcos, $home, $shell) = split(/:/); -\& #... -\& } -.Ve -.Sp -As with regular pattern matching, any capturing parentheses that are not -matched in a \f(CW\*(C`split()\*(C'\fR will be set to \f(CW\*(C`undef\*(C'\fR when returned: -.Sp -.Vb 2 -\& @fields = split /(A)|B/, "1A2B3"; -\& # @fields is (1, 'A', 2, undef, 3) -.Ve -.IP "sprintf \s-1FORMAT\s0, \s-1LIST\s0" 8 -.IX Xref "sprintf" -.IX Item "sprintf FORMAT, LIST" -Returns a string formatted by the usual \f(CW\*(C`printf\*(C'\fR conventions of the C -library function \f(CW\*(C`sprintf\*(C'\fR. See below for more details -and see \fIsprintf\fR\|(3) or \fIprintf\fR\|(3) on your system for an explanation of -the general principles. -.Sp -For example: -.Sp -.Vb 2 -\& # Format number with up to 8 leading zeroes -\& $result = sprintf("%08d", $number); -.Ve -.Sp -.Vb 2 -\& # Round number to 3 digits after decimal point -\& $rounded = sprintf("%.3f", $number); -.Ve -.Sp -Perl does its own \f(CW\*(C`sprintf\*(C'\fR formatting\*(--it emulates the C -function \f(CW\*(C`sprintf\*(C'\fR, but it doesn't use it (except for floating-point -numbers, and even then only the standard modifiers are allowed). As a -result, any non-standard extensions in your local \f(CW\*(C`sprintf\*(C'\fR are not -available from Perl. -.Sp -Unlike \f(CW\*(C`printf\*(C'\fR, \f(CW\*(C`sprintf\*(C'\fR does not do what you probably mean when you -pass it an array as your first argument. The array is given scalar context, -and instead of using the 0th element of the array as the format, Perl will -use the count of elements in the array as the format, which is almost never -useful. -.Sp -Perl's \f(CW\*(C`sprintf\*(C'\fR permits the following universally-known conversions: -.Sp -.Vb 10 -\& %% a percent sign -\& %c a character with the given number -\& %s a string -\& %d a signed integer, in decimal -\& %u an unsigned integer, in decimal -\& %o an unsigned integer, in octal -\& %x an unsigned integer, in hexadecimal -\& %e a floating-point number, in scientific notation -\& %f a floating-point number, in fixed decimal notation -\& %g a floating-point number, in %e or %f notation -.Ve -.Sp -In addition, Perl permits the following widely-supported conversions: -.Sp -.Vb 7 -\& %X like %x, but using upper-case letters -\& %E like %e, but using an upper-case "E" -\& %G like %g, but with an upper-case "E" (if applicable) -\& %b an unsigned integer, in binary -\& %p a pointer (outputs the Perl value's address in hexadecimal) -\& %n special: *stores* the number of characters output so far -\& into the next variable in the parameter list -.Ve -.Sp -Finally, for backward (and we do mean \*(L"backward\*(R") compatibility, Perl -permits these unnecessary but widely-supported conversions: -.Sp -.Vb 5 -\& %i a synonym for %d -\& %D a synonym for %ld -\& %U a synonym for %lu -\& %O a synonym for %lo -\& %F a synonym for %f -.Ve -.Sp -Note that the number of exponent digits in the scientific notation produced -by \f(CW%e\fR, \f(CW%E\fR, \f(CW%g\fR and \f(CW%G\fR for numbers with the modulus of the -exponent less than 100 is system\-dependent: it may be three or less -(zero\-padded as necessary). In other words, 1.23 times ten to the -99th may be either \*(L"1.23e99\*(R" or \*(L"1.23e099\*(R". -.Sp -Between the \f(CW\*(C`%\*(C'\fR and the format letter, you may specify a number of -additional attributes controlling the interpretation of the format. -In order, these are: -.RS 8 -.IP "format parameter index" 4 -.IX Item "format parameter index" -An explicit format parameter index, such as \f(CW\*(C`2$\*(C'\fR. By default sprintf -will format the next unused argument in the list, but this allows you -to take the arguments out of order, e.g.: -.Sp -.Vb 2 -\& printf '%2$d %1$d', 12, 34; # prints "34 12" -\& printf '%3$d %d %1$d', 1, 2, 3; # prints "3 1 1" -.Ve -.IP "flags" 4 -.IX Item "flags" -one or more of: - space prefix positive number with a space - + prefix positive number with a plus sign - \- left-justify within the field - 0 use zeros, not spaces, to right-justify - # prefix non-zero octal with \*(L"0\*(R", non-zero hex with \*(L"0x\*(R", - non-zero binary with \*(L"0b\*(R" -.Sp -For example: -.Sp -.Vb 6 -\& printf '<% d>', 12; # prints "< 12>" -\& printf '<%+d>', 12; # prints "<+12>" -\& printf '<%6s>', 12; # prints "< 12>" -\& printf '<%-6s>', 12; # prints "<12 >" -\& printf '<%06s>', 12; # prints "<000012>" -\& printf '<%#x>', 12; # prints "<0xc>" -.Ve -.IP "vector flag" 4 -.IX Item "vector flag" -This flag tells perl to interpret the supplied string as a vector of -integers, one for each character in the string. Perl applies the format to -each integer in turn, then joins the resulting strings with a separator (a -dot \f(CW\*(C`.\*(C'\fR by default). This can be useful for displaying ordinal values of -characters in arbitrary strings: -.Sp -.Vb 2 -\& printf "%vd", "AB\ex{100}"; # prints "65.66.256" -\& printf "version is v%vd\en", $^V; # Perl's version -.Ve -.Sp -Put an asterisk \f(CW\*(C`*\*(C'\fR before the \f(CW\*(C`v\*(C'\fR to override the string to -use to separate the numbers: -.Sp -.Vb 2 -\& printf "address is %*vX\en", ":", $addr; # IPv6 address -\& printf "bits are %0*v8b\en", " ", $bits; # random bitstring -.Ve -.Sp -You can also explicitly specify the argument number to use for -the join string using e.g. \f(CW\*(C`*2$v\*(C'\fR: -.Sp -.Vb 1 -\& printf '%*4$vX %*4$vX %*4$vX', @addr[1..3], ":"; # 3 IPv6 addresses -.Ve -.IP "(minimum) width" 4 -.IX Item "(minimum) width" -Arguments are usually formatted to be only as wide as required to -display the given value. You can override the width by putting -a number here, or get the width from the next argument (with \f(CW\*(C`*\*(C'\fR) -or from a specified argument (with e.g. \f(CW\*(C`*2$\*(C'\fR): -.Sp -.Vb 5 -\& printf '<%s>', "a"; # prints "<a>" -\& printf '<%6s>', "a"; # prints "< a>" -\& printf '<%*s>', 6, "a"; # prints "< a>" -\& printf '<%*2$s>', "a", 6; # prints "< a>" -\& printf '<%2s>', "long"; # prints "<long>" (does not truncate) -.Ve -.Sp -If a field width obtained through \f(CW\*(C`*\*(C'\fR is negative, it has the same -effect as the \f(CW\*(C`\-\*(C'\fR flag: left\-justification. -.IP "precision, or maximum width" 4 -.IX Xref "precision" -.IX Item "precision, or maximum width" -You can specify a precision (for numeric conversions) or a maximum -width (for string conversions) by specifying a \f(CW\*(C`.\*(C'\fR followed by a number. -For floating point formats, with the exception of 'g' and 'G', this specifies -the number of decimal places to show (the default being 6), e.g.: -.Sp -.Vb 6 -\& # these examples are subject to system-specific variation -\& printf '<%f>', 1; # prints "<1.000000>" -\& printf '<%.1f>', 1; # prints "<1.0>" -\& printf '<%.0f>', 1; # prints "<1>" -\& printf '<%e>', 10; # prints "<1.000000e+01>" -\& printf '<%.1e>', 10; # prints "<1.0e+01>" -.Ve -.Sp -For 'g' and 'G', this specifies the maximum number of digits to show, -including prior to the decimal point as well as after it, e.g.: -.Sp -.Vb 8 -\& # these examples are subject to system-specific variation -\& printf '<%g>', 1; # prints "<1>" -\& printf '<%.10g>', 1; # prints "<1>" -\& printf '<%g>', 100; # prints "<100>" -\& printf '<%.1g>', 100; # prints "<1e+02>" -\& printf '<%.2g>', 100.01; # prints "<1e+02>" -\& printf '<%.5g>', 100.01; # prints "<100.01>" -\& printf '<%.4g>', 100.01; # prints "<100>" -.Ve -.Sp -For integer conversions, specifying a precision implies that the -output of the number itself should be zero-padded to this width: -.Sp -.Vb 3 -\& printf '<%.6x>', 1; # prints "<000001>" -\& printf '<%#.6x>', 1; # prints "<0x000001>" -\& printf '<%-10.6x>', 1; # prints "<000001 >" -.Ve -.Sp -For string conversions, specifying a precision truncates the string -to fit in the specified width: -.Sp -.Vb 2 -\& printf '<%.5s>', "truncated"; # prints "<trunc>" -\& printf '<%10.5s>', "truncated"; # prints "< trunc>" -.Ve -.Sp -You can also get the precision from the next argument using \f(CW\*(C`.*\*(C'\fR: -.Sp -.Vb 2 -\& printf '<%.6x>', 1; # prints "<000001>" -\& printf '<%.*x>', 6, 1; # prints "<000001>" -.Ve -.Sp -You cannot currently get the precision from a specified number, -but it is intended that this will be possible in the future using -e.g. \f(CW\*(C`.*2$\*(C'\fR: -.Sp -.Vb 1 -\& printf '<%.*2$x>', 1, 6; # INVALID, but in future will print "<000001>" -.Ve -.IP "size" 4 -.IX Item "size" -For numeric conversions, you can specify the size to interpret the -number as using \f(CW\*(C`l\*(C'\fR, \f(CW\*(C`h\*(C'\fR, \f(CW\*(C`V\*(C'\fR, \f(CW\*(C`q\*(C'\fR, \f(CW\*(C`L\*(C'\fR, or \f(CW\*(C`ll\*(C'\fR. For integer -conversions (\f(CW\*(C`d u o x X b i D U O\*(C'\fR), numbers are usually assumed to be -whatever the default integer size is on your platform (usually 32 or 64 -bits), but you can override this to use instead one of the standard C types, -as supported by the compiler used to build Perl: -.Sp -.Vb 4 -\& l interpret integer as C type "long" or "unsigned long" -\& h interpret integer as C type "short" or "unsigned short" -\& q, L or ll interpret integer as C type "long long", "unsigned long long". -\& or "quads" (typically 64-bit integers) -.Ve -.Sp -The last will produce errors if Perl does not understand \*(L"quads\*(R" in your -installation. (This requires that either the platform natively supports quads -or Perl was specifically compiled to support quads.) You can find out -whether your Perl supports quads via Config: -.Sp -.Vb 3 -\& use Config; -\& ($Config{use64bitint} eq 'define' || $Config{longsize} >= 8) && -\& print "quads\en"; -.Ve -.Sp -For floating point conversions (\f(CW\*(C`e f g E F G\*(C'\fR), numbers are usually assumed -to be the default floating point size on your platform (double or long double), -but you can force 'long double' with \f(CW\*(C`q\*(C'\fR, \f(CW\*(C`L\*(C'\fR, or \f(CW\*(C`ll\*(C'\fR if your -platform supports them. You can find out whether your Perl supports long -doubles via Config: -.Sp -.Vb 2 -\& use Config; -\& $Config{d_longdbl} eq 'define' && print "long doubles\en"; -.Ve -.Sp -You can find out whether Perl considers 'long double' to be the default -floating point size to use on your platform via Config: -.Sp -.Vb 3 -\& use Config; -\& ($Config{uselongdouble} eq 'define') && -\& print "long doubles by default\en"; -.Ve -.Sp -It can also be the case that long doubles and doubles are the same thing: -.Sp -.Vb 3 -\& use Config; -\& ($Config{doublesize} == $Config{longdblsize}) && -\& print "doubles are long doubles\en"; -.Ve -.Sp -The size specifier \f(CW\*(C`V\*(C'\fR has no effect for Perl code, but it is supported -for compatibility with \s-1XS\s0 code; it means 'use the standard size for -a Perl integer (or floating-point number)', which is already the -default for Perl code. -.IP "order of arguments" 4 -.IX Item "order of arguments" -Normally, sprintf takes the next unused argument as the value to -format for each format specification. If the format specification -uses \f(CW\*(C`*\*(C'\fR to require additional arguments, these are consumed from -the argument list in the order in which they appear in the format -specification \fIbefore\fR the value to format. Where an argument is -specified using an explicit index, this does not affect the normal -order for the arguments (even when the explicitly specified index -would have been the next argument in any case). -.Sp -So: -.Sp -.Vb 1 -\& printf '<%*.*s>', $a, $b, $c; -.Ve -.Sp -would use \f(CW$a\fR for the width, \f(CW$b\fR for the precision and \f(CW$c\fR -as the value to format, while: -.Sp -.Vb 1 -\& print '<%*1$.*s>', $a, $b; -.Ve -.Sp -would use \f(CW$a\fR for the width and the precision, and \f(CW$b\fR as the -value to format. -.Sp -Here are some more examples \- beware that when using an explicit -index, the \f(CW\*(C`$\*(C'\fR may need to be escaped: -.Sp -.Vb 4 -\& printf "%2\e$d %d\en", 12, 34; # will print "34 12\en" -\& printf "%2\e$d %d %d\en", 12, 34; # will print "34 12 34\en" -\& printf "%3\e$d %d %d\en", 12, 34, 56; # will print "56 12 34\en" -\& printf "%2\e$*3\e$d %d\en", 12, 34, 3; # will print " 34 12\en" -.Ve -.RE -.RS 8 -.Sp -If \f(CW\*(C`use locale\*(C'\fR is in effect, the character used for the decimal -point in formatted real numbers is affected by the \s-1LC_NUMERIC\s0 locale. -See perllocale. -.RE -.IP "sqrt \s-1EXPR\s0" 8 -.IX Xref "sqrt root square root" -.IX Item "sqrt EXPR" -.PD 0 -.IP "sqrt" 8 -.IX Item "sqrt" -.PD -Return the square root of \s-1EXPR\s0. If \s-1EXPR\s0 is omitted, returns square -root of \f(CW$_\fR. Only works on non-negative operands, unless you've -loaded the standard Math::Complex module. -.Sp -.Vb 2 -\& use Math::Complex; -\& print sqrt(-2); # prints 1.4142135623731i -.Ve -.IP "srand \s-1EXPR\s0" 8 -.IX Xref "srand seed randseed" -.IX Item "srand EXPR" -.PD 0 -.IP "srand" 8 -.IX Item "srand" -.PD -Sets the random number seed for the \f(CW\*(C`rand\*(C'\fR operator. -.Sp -The point of the function is to \*(L"seed\*(R" the \f(CW\*(C`rand\*(C'\fR function so that -\&\f(CW\*(C`rand\*(C'\fR can produce a different sequence each time you run your -program. -.Sp -If \fIsrand()\fR is not called explicitly, it is called implicitly at the -first use of the \f(CW\*(C`rand\*(C'\fR operator. However, this was not the case in -versions of Perl before 5.004, so if your script will run under older -Perl versions, it should call \f(CW\*(C`srand\*(C'\fR. -.Sp -Most programs won't even call \fIsrand()\fR at all, except those that -need a cryptographically-strong starting point rather than the -generally acceptable default, which is based on time of day, -process \s-1ID\s0, and memory allocation, or the \fI/dev/urandom\fR device, -if available. -.Sp -You can call srand($seed) with the same \f(CW$seed\fR to reproduce the -\&\fIsame\fR sequence from \fIrand()\fR, but this is usually reserved for -generating predictable results for testing or debugging. -Otherwise, don't call \fIsrand()\fR more than once in your program. -.Sp -Do \fBnot\fR call \fIsrand()\fR (i.e. without an argument) more than once in -a script. The internal state of the random number generator should -contain more entropy than can be provided by any seed, so calling -\&\fIsrand()\fR again actually \fIloses\fR randomness. -.Sp -Most implementations of \f(CW\*(C`srand\*(C'\fR take an integer and will silently -truncate decimal numbers. This means \f(CW\*(C`srand(42)\*(C'\fR will usually -produce the same results as \f(CW\*(C`srand(42.1)\*(C'\fR. To be safe, always pass -\&\f(CW\*(C`srand\*(C'\fR an integer. -.Sp -In versions of Perl prior to 5.004 the default seed was just the -current \f(CW\*(C`time\*(C'\fR. This isn't a particularly good seed, so many old -programs supply their own seed value (often \f(CW\*(C`time ^ $$\*(C'\fR or \f(CW\*(C`time ^ -($$ + ($$ << 15))\*(C'\fR), but that isn't necessary any more. -.Sp -For cryptographic purposes, however, you need something much more random -than the default seed. Checksumming the compressed output of one or more -rapidly changing operating system status programs is the usual method. For -example: -.Sp -.Vb 1 -\& srand (time ^ $$ ^ unpack "%L*", `ps axww | gzip`); -.Ve -.Sp -If you're particularly concerned with this, see the \f(CW\*(C`Math::TrulyRandom\*(C'\fR -module in \s-1CPAN\s0. -.Sp -Frequently called programs (like \s-1CGI\s0 scripts) that simply use -.Sp -.Vb 1 -\& time ^ $$ -.Ve -.Sp -for a seed can fall prey to the mathematical property that -.Sp -.Vb 1 -\& a^b == (a+1)^(b+1) -.Ve -.Sp -one-third of the time. So don't do that. -.IP "stat \s-1FILEHANDLE\s0" 8 -.IX Xref "stat file, status" -.IX Item "stat FILEHANDLE" -.PD 0 -.IP "stat \s-1EXPR\s0" 8 -.IX Item "stat EXPR" -.IP "stat" 8 -.IX Item "stat" -.PD -Returns a 13\-element list giving the status info for a file, either -the file opened via \s-1FILEHANDLE\s0, or named by \s-1EXPR\s0. If \s-1EXPR\s0 is omitted, -it stats \f(CW$_\fR. Returns a null list if the stat fails. Typically used -as follows: -.Sp -.Vb 3 -\& ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, -\& $atime,$mtime,$ctime,$blksize,$blocks) -\& = stat($filename); -.Ve -.Sp -Not all fields are supported on all filesystem types. Here are the -meanings of the fields: -.Sp -.Vb 13 -\& 0 dev device number of filesystem -\& 1 ino inode number -\& 2 mode file mode (type and permissions) -\& 3 nlink number of (hard) links to the file -\& 4 uid numeric user ID of file's owner -\& 5 gid numeric group ID of file's owner -\& 6 rdev the device identifier (special files only) -\& 7 size total size of file, in bytes -\& 8 atime last access time in seconds since the epoch -\& 9 mtime last modify time in seconds since the epoch -\& 10 ctime inode change time in seconds since the epoch (*) -\& 11 blksize preferred block size for file system I/O -\& 12 blocks actual number of blocks allocated -.Ve -.Sp -(The epoch was at 00:00 January 1, 1970 \s-1GMT\s0.) -.Sp -(*) Not all fields are supported on all filesystem types. Notably, the -ctime field is non\-portable. In particular, you cannot expect it to be a -\&\*(L"creation time\*(R", see \*(L"Files and Filesystems\*(R" in perlport for details. -.Sp -If \f(CW\*(C`stat\*(C'\fR is passed the special filehandle consisting of an underline, no -stat is done, but the current contents of the stat structure from the -last \f(CW\*(C`stat\*(C'\fR, \f(CW\*(C`lstat\*(C'\fR, or filetest are returned. Example: -.Sp -.Vb 3 -\& if (-x $file && (($d) = stat(_)) && $d < 0) { -\& print "$file is executable NFS file\en"; -\& } -.Ve -.Sp -(This works on machines only for which the device number is negative -under \s-1NFS\s0.) -.Sp -Because the mode contains both the file type and its permissions, you -should mask off the file type portion and (s)printf using a \f(CW"%o"\fR -if you want to see the real permissions. -.Sp -.Vb 2 -\& $mode = (stat($filename))[2]; -\& printf "Permissions are %04o\en", $mode & 07777; -.Ve -.Sp -In scalar context, \f(CW\*(C`stat\*(C'\fR returns a boolean value indicating success -or failure, and, if successful, sets the information associated with -the special filehandle \f(CW\*(C`_\*(C'\fR. -.Sp -The File::stat module provides a convenient, by-name access mechanism: -.Sp -.Vb 5 -\& use File::stat; -\& $sb = stat($filename); -\& printf "File is %s, size is %s, perm %04o, mtime %s\en", -\& $filename, $sb->size, $sb->mode & 07777, -\& scalar localtime $sb->mtime; -.Ve -.Sp -You can import symbolic mode constants (\f(CW\*(C`S_IF*\*(C'\fR) and functions -(\f(CW\*(C`S_IS*\*(C'\fR) from the Fcntl module: -.Sp -.Vb 1 -\& use Fcntl ':mode'; -.Ve -.Sp -.Vb 1 -\& $mode = (stat($filename))[2]; -.Ve -.Sp -.Vb 3 -\& $user_rwx = ($mode & S_IRWXU) >> 6; -\& $group_read = ($mode & S_IRGRP) >> 3; -\& $other_execute = $mode & S_IXOTH; -.Ve -.Sp -.Vb 1 -\& printf "Permissions are %04o\en", S_IMODE($mode), "\en"; -.Ve -.Sp -.Vb 2 -\& $is_setuid = $mode & S_ISUID; -\& $is_setgid = S_ISDIR($mode); -.Ve -.Sp -You could write the last two using the \f(CW\*(C`\-u\*(C'\fR and \f(CW\*(C`\-d\*(C'\fR operators. -The commonly available \f(CW\*(C`S_IF*\*(C'\fR constants are -.Sp -.Vb 1 -\& # Permissions: read, write, execute, for user, group, others. -.Ve -.Sp -.Vb 3 -\& S_IRWXU S_IRUSR S_IWUSR S_IXUSR -\& S_IRWXG S_IRGRP S_IWGRP S_IXGRP -\& S_IRWXO S_IROTH S_IWOTH S_IXOTH -.Ve -.Sp -.Vb 2 -\& # Setuid/Setgid/Stickiness/SaveText. -\& # Note that the exact meaning of these is system dependent. -.Ve -.Sp -.Vb 1 -\& S_ISUID S_ISGID S_ISVTX S_ISTXT -.Ve -.Sp -.Vb 1 -\& # File types. Not necessarily all are available on your system. -.Ve -.Sp -.Vb 1 -\& S_IFREG S_IFDIR S_IFLNK S_IFBLK S_IFCHR S_IFIFO S_IFSOCK S_IFWHT S_ENFMT -.Ve -.Sp -.Vb 1 -\& # The following are compatibility aliases for S_IRUSR, S_IWUSR, S_IXUSR. -.Ve -.Sp -.Vb 1 -\& S_IREAD S_IWRITE S_IEXEC -.Ve -.Sp -and the \f(CW\*(C`S_IF*\*(C'\fR functions are -.Sp -.Vb 2 -\& S_IMODE($mode) the part of $mode containing the permission bits -\& and the setuid/setgid/sticky bits -.Ve -.Sp -.Vb 3 -\& S_IFMT($mode) the part of $mode containing the file type -\& which can be bit-anded with e.g. S_IFREG -\& or with the following functions -.Ve -.Sp -.Vb 1 -\& # The operators -f, -d, -l, -b, -c, -p, and -S. -.Ve -.Sp -.Vb 2 -\& S_ISREG($mode) S_ISDIR($mode) S_ISLNK($mode) -\& S_ISBLK($mode) S_ISCHR($mode) S_ISFIFO($mode) S_ISSOCK($mode) -.Ve -.Sp -.Vb 3 -\& # No direct -X operator counterpart, but for the first one -\& # the -g operator is often equivalent. The ENFMT stands for -\& # record flocking enforcement, a platform-dependent feature. -.Ve -.Sp -.Vb 1 -\& S_ISENFMT($mode) S_ISWHT($mode) -.Ve -.Sp -See your native \fIchmod\fR\|(2) and \fIstat\fR\|(2) documentation for more details -about the \f(CW\*(C`S_*\*(C'\fR constants. To get status info for a symbolic link -instead of the target file behind the link, use the \f(CW\*(C`lstat\*(C'\fR function. -.IP "study \s-1SCALAR\s0" 8 -.IX Xref "study" -.IX Item "study SCALAR" -.PD 0 -.IP "study" 8 -.IX Item "study" -.PD -Takes extra time to study \s-1SCALAR\s0 (\f(CW$_\fR if unspecified) in anticipation of -doing many pattern matches on the string before it is next modified. -This may or may not save time, depending on the nature and number of -patterns you are searching on, and on the distribution of character -frequencies in the string to be searched\*(--you probably want to compare -run times with and without it to see which runs faster. Those loops -that scan for many short constant strings (including the constant -parts of more complex patterns) will benefit most. You may have only -one \f(CW\*(C`study\*(C'\fR active at a time\*(--if you study a different scalar the first -is \*(L"unstudied\*(R". (The way \f(CW\*(C`study\*(C'\fR works is this: a linked list of every -character in the string to be searched is made, so we know, for -example, where all the \f(CW'k'\fR characters are. From each search string, -the rarest character is selected, based on some static frequency tables -constructed from some C programs and English text. Only those places -that contain this \*(L"rarest\*(R" character are examined.) -.Sp -For example, here is a loop that inserts index producing entries -before any line containing a certain pattern: -.Sp -.Vb 8 -\& while (<>) { -\& study; -\& print ".IX foo\en" if /\ebfoo\eb/; -\& print ".IX bar\en" if /\ebbar\eb/; -\& print ".IX blurfl\en" if /\ebblurfl\eb/; -\& # ... -\& print; -\& } -.Ve -.Sp -In searching for \f(CW\*(C`/\ebfoo\eb/\*(C'\fR, only those locations in \f(CW$_\fR that contain \f(CW\*(C`f\*(C'\fR -will be looked at, because \f(CW\*(C`f\*(C'\fR is rarer than \f(CW\*(C`o\*(C'\fR. In general, this is -a big win except in pathological cases. The only question is whether -it saves you more time than it took to build the linked list in the -first place. -.Sp -Note that if you have to look for strings that you don't know till -runtime, you can build an entire loop as a string and \f(CW\*(C`eval\*(C'\fR that to -avoid recompiling all your patterns all the time. Together with -undefining \f(CW$/\fR to input entire files as one record, this can be very -fast, often faster than specialized programs like \fIfgrep\fR\|(1). The following -scans a list of files (\f(CW@files\fR) for a list of words (\f(CW@words\fR), and prints -out the names of those files that contain a match: -.Sp -.Vb 12 -\& $search = 'while (<>) { study;'; -\& foreach $word (@words) { -\& $search .= "++\e$seen{\e$ARGV} if /\e\eb$word\e\eb/;\en"; -\& } -\& $search .= "}"; -\& @ARGV = @files; -\& undef $/; -\& eval $search; # this screams -\& $/ = "\en"; # put back to normal input delimiter -\& foreach $file (sort keys(%seen)) { -\& print $file, "\en"; -\& } -.Ve -.IP "sub \s-1NAME\s0 \s-1BLOCK\s0" 8 -.IX Xref "sub" -.IX Item "sub NAME BLOCK" -.PD 0 -.IP "sub \s-1NAME\s0 (\s-1PROTO\s0) \s-1BLOCK\s0" 8 -.IX Item "sub NAME (PROTO) BLOCK" -.IP "sub \s-1NAME\s0 : \s-1ATTRS\s0 \s-1BLOCK\s0" 8 -.IX Item "sub NAME : ATTRS BLOCK" -.IP "sub \s-1NAME\s0 (\s-1PROTO\s0) : \s-1ATTRS\s0 \s-1BLOCK\s0" 8 -.IX Item "sub NAME (PROTO) : ATTRS BLOCK" -.PD -This is subroutine definition, not a real function \fIper se\fR. -Without a \s-1BLOCK\s0 it's just a forward declaration. Without a \s-1NAME\s0, -it's an anonymous function declaration, and does actually return -a value: the \s-1CODE\s0 ref of the closure you just created. -.Sp -See perlsub and perlref for details about subroutines and -references, and attributes and Attribute::Handlers for more -information about attributes. -.IP "substr \s-1EXPR\s0,OFFSET,LENGTH,REPLACEMENT" 8 -.IX Xref "substr substring mid left right" -.IX Item "substr EXPR,OFFSET,LENGTH,REPLACEMENT" -.PD 0 -.IP "substr \s-1EXPR\s0,OFFSET,LENGTH" 8 -.IX Item "substr EXPR,OFFSET,LENGTH" -.IP "substr \s-1EXPR\s0,OFFSET" 8 -.IX Item "substr EXPR,OFFSET" -.PD -Extracts a substring out of \s-1EXPR\s0 and returns it. First character is at -offset \f(CW0\fR, or whatever you've set \f(CW$[\fR to (but don't do that). -If \s-1OFFSET\s0 is negative (or more precisely, less than \f(CW$[\fR), starts -that far from the end of the string. If \s-1LENGTH\s0 is omitted, returns -everything to the end of the string. If \s-1LENGTH\s0 is negative, leaves that -many characters off the end of the string. -.Sp -You can use the \fIsubstr()\fR function as an lvalue, in which case \s-1EXPR\s0 -must itself be an lvalue. If you assign something shorter than \s-1LENGTH\s0, -the string will shrink, and if you assign something longer than \s-1LENGTH\s0, -the string will grow to accommodate it. To keep the string the same -length you may need to pad or chop your value using \f(CW\*(C`sprintf\*(C'\fR. -.Sp -If \s-1OFFSET\s0 and \s-1LENGTH\s0 specify a substring that is partly outside the -string, only the part within the string is returned. If the substring -is beyond either end of the string, \fIsubstr()\fR returns the undefined -value and produces a warning. When used as an lvalue, specifying a -substring that is entirely outside the string is a fatal error. -Here's an example showing the behavior for boundary cases: -.Sp -.Vb 5 -\& my $name = 'fred'; -\& substr($name, 4) = 'dy'; # $name is now 'freddy' -\& my $null = substr $name, 6, 2; # returns '' (no warning) -\& my $oops = substr $name, 7; # returns undef, with warning -\& substr($name, 7) = 'gap'; # fatal error -.Ve -.Sp -An alternative to using \fIsubstr()\fR as an lvalue is to specify the -replacement string as the 4th argument. This allows you to replace -parts of the \s-1EXPR\s0 and return what was there before in one operation, -just as you can with \fIsplice()\fR. -.IP "symlink \s-1OLDFILE\s0,NEWFILE" 8 -.IX Xref "symlink link symbolic link link, symbolic" -.IX Item "symlink OLDFILE,NEWFILE" -Creates a new filename symbolically linked to the old filename. -Returns \f(CW1\fR for success, \f(CW0\fR otherwise. On systems that don't support -symbolic links, produces a fatal error at run time. To check for that, -use eval: -.Sp -.Vb 1 -\& $symlink_exists = eval { symlink("",""); 1 }; -.Ve -.IP "syscall \s-1NUMBER\s0, \s-1LIST\s0" 8 -.IX Xref "syscall system call" -.IX Item "syscall NUMBER, LIST" -Calls the system call specified as the first element of the list, -passing the remaining elements as arguments to the system call. If -unimplemented, produces a fatal error. The arguments are interpreted -as follows: if a given argument is numeric, the argument is passed as -an int. If not, the pointer to the string value is passed. You are -responsible to make sure a string is pre-extended long enough to -receive any result that might be written into a string. You can't use a -string literal (or other read-only string) as an argument to \f(CW\*(C`syscall\*(C'\fR -because Perl has to assume that any string pointer might be written -through. If your -integer arguments are not literals and have never been interpreted in a -numeric context, you may need to add \f(CW0\fR to them to force them to look -like numbers. This emulates the \f(CW\*(C`syswrite\*(C'\fR function (or vice versa): -.Sp -.Vb 3 -\& require 'syscall.ph'; # may need to run h2ph -\& $s = "hi there\en"; -\& syscall(&SYS_write, fileno(STDOUT), $s, length $s); -.Ve -.Sp -Note that Perl supports passing of up to only 14 arguments to your system call, -which in practice should usually suffice. -.Sp -Syscall returns whatever value returned by the system call it calls. -If the system call fails, \f(CW\*(C`syscall\*(C'\fR returns \f(CW\*(C`\-1\*(C'\fR and sets \f(CW$!\fR (errno). -Note that some system calls can legitimately return \f(CW\*(C`\-1\*(C'\fR. The proper -way to handle such calls is to assign \f(CW\*(C`$!=0;\*(C'\fR before the call and -check the value of \f(CW$!\fR if syscall returns \f(CW\*(C`\-1\*(C'\fR. -.Sp -There's a problem with \f(CW\*(C`syscall(&SYS_pipe)\*(C'\fR: it returns the file -number of the read end of the pipe it creates. There is no way -to retrieve the file number of the other end. You can avoid this -problem by using \f(CW\*(C`pipe\*(C'\fR instead. -.IP "sysopen \s-1FILEHANDLE\s0,FILENAME,MODE" 8 -.IX Xref "sysopen" -.IX Item "sysopen FILEHANDLE,FILENAME,MODE" -.PD 0 -.IP "sysopen \s-1FILEHANDLE\s0,FILENAME,MODE,PERMS" 8 -.IX Item "sysopen FILEHANDLE,FILENAME,MODE,PERMS" -.PD -Opens the file whose filename is given by \s-1FILENAME\s0, and associates it -with \s-1FILEHANDLE\s0. If \s-1FILEHANDLE\s0 is an expression, its value is used as -the name of the real filehandle wanted. This function calls the -underlying operating system's \f(CW\*(C`open\*(C'\fR function with the parameters -\&\s-1FILENAME\s0, \s-1MODE\s0, \s-1PERMS\s0. -.Sp -The possible values and flag bits of the \s-1MODE\s0 parameter are -system\-dependent; they are available via the standard module \f(CW\*(C`Fcntl\*(C'\fR. -See the documentation of your operating system's \f(CW\*(C`open\*(C'\fR to see which -values and flag bits are available. You may combine several flags -using the \f(CW\*(C`|\*(C'\fR\-operator. -.Sp -Some of the most common values are \f(CW\*(C`O_RDONLY\*(C'\fR for opening the file in -read-only mode, \f(CW\*(C`O_WRONLY\*(C'\fR for opening the file in write-only mode, -and \f(CW\*(C`O_RDWR\*(C'\fR for opening the file in read-write mode. -.IX Xref "O_RDONLY O_RDWR O_WRONLY" -.Sp -For historical reasons, some values work on almost every system -supported by perl: zero means read\-only, one means write\-only, and two -means read/write. We know that these values do \fInot\fR work under -\&\s-1OS/390\s0 & \s-1VM/ESA\s0 Unix and on the Macintosh; you probably don't want to -use them in new code. -.Sp -If the file named by \s-1FILENAME\s0 does not exist and the \f(CW\*(C`open\*(C'\fR call creates -it (typically because \s-1MODE\s0 includes the \f(CW\*(C`O_CREAT\*(C'\fR flag), then the value of -\&\s-1PERMS\s0 specifies the permissions of the newly created file. If you omit -the \s-1PERMS\s0 argument to \f(CW\*(C`sysopen\*(C'\fR, Perl uses the octal value \f(CW0666\fR. -These permission values need to be in octal, and are modified by your -process's current \f(CW\*(C`umask\*(C'\fR. -.IX Xref "O_CREAT" -.Sp -In many systems the \f(CW\*(C`O_EXCL\*(C'\fR flag is available for opening files in -exclusive mode. This is \fBnot\fR locking: exclusiveness means here that -if the file already exists, \fIsysopen()\fR fails. \f(CW\*(C`O_EXCL\*(C'\fR may not work -on network filesystems, and has no effect unless the \f(CW\*(C`O_CREAT\*(C'\fR flag -is set as well. Setting \f(CW\*(C`O_CREAT|O_EXCL\*(C'\fR prevents the file from -being opened if it is a symbolic link. It does not protect against -symbolic links in the file's path. -.IX Xref "O_EXCL" -.Sp -Sometimes you may want to truncate an already-existing file. This -can be done using the \f(CW\*(C`O_TRUNC\*(C'\fR flag. The behavior of -\&\f(CW\*(C`O_TRUNC\*(C'\fR with \f(CW\*(C`O_RDONLY\*(C'\fR is undefined. -.IX Xref "O_TRUNC" -.Sp -You should seldom if ever use \f(CW0644\fR as argument to \f(CW\*(C`sysopen\*(C'\fR, because -that takes away the user's option to have a more permissive umask. -Better to omit it. See the \fIperlfunc\fR\|(1) entry on \f(CW\*(C`umask\*(C'\fR for more -on this. -.Sp -Note that \f(CW\*(C`sysopen\*(C'\fR depends on the \fIfdopen()\fR C library function. -On many \s-1UNIX\s0 systems, \fIfdopen()\fR is known to fail when file descriptors -exceed a certain value, typically 255. If you need more file -descriptors than that, consider rebuilding Perl to use the \f(CW\*(C`sfio\*(C'\fR -library, or perhaps using the \fIPOSIX::open()\fR function. -.Sp -See perlopentut for a kinder, gentler explanation of opening files. -.IP "sysread \s-1FILEHANDLE\s0,SCALAR,LENGTH,OFFSET" 8 -.IX Xref "sysread" -.IX Item "sysread FILEHANDLE,SCALAR,LENGTH,OFFSET" -.PD 0 -.IP "sysread \s-1FILEHANDLE\s0,SCALAR,LENGTH" 8 -.IX Item "sysread FILEHANDLE,SCALAR,LENGTH" -.PD -Attempts to read \s-1LENGTH\s0 bytes of data into variable \s-1SCALAR\s0 from the -specified \s-1FILEHANDLE\s0, using the system call \fIread\fR\|(2). It bypasses -buffered \s-1IO\s0, so mixing this with other kinds of reads, \f(CW\*(C`print\*(C'\fR, -\&\f(CW\*(C`write\*(C'\fR, \f(CW\*(C`seek\*(C'\fR, \f(CW\*(C`tell\*(C'\fR, or \f(CW\*(C`eof\*(C'\fR can cause confusion because the -perlio or stdio layers usually buffers data. Returns the number of -bytes actually read, \f(CW0\fR at end of file, or undef if there was an -error (in the latter case \f(CW$!\fR is also set). \s-1SCALAR\s0 will be grown or -shrunk so that the last byte actually read is the last byte of the -scalar after the read. -.Sp -An \s-1OFFSET\s0 may be specified to place the read data at some place in the -string other than the beginning. A negative \s-1OFFSET\s0 specifies -placement at that many characters counting backwards from the end of -the string. A positive \s-1OFFSET\s0 greater than the length of \s-1SCALAR\s0 -results in the string being padded to the required size with \f(CW"\e0"\fR -bytes before the result of the read is appended. -.Sp -There is no \fIsyseof()\fR function, which is ok, since \fIeof()\fR doesn't work -very well on device files (like ttys) anyway. Use \fIsysread()\fR and check -for a return value for 0 to decide whether you're done. -.Sp -Note that if the filehandle has been marked as \f(CW\*(C`:utf8\*(C'\fR Unicode -characters are read instead of bytes (the \s-1LENGTH\s0, \s-1OFFSET\s0, and the -return value of \fIsysread()\fR are in Unicode characters). -The \f(CW\*(C`:encoding(...)\*(C'\fR layer implicitly introduces the \f(CW\*(C`:utf8\*(C'\fR layer. -See \*(L"binmode\*(R", \*(L"open\*(R", and the \f(CW\*(C`open\*(C'\fR pragma, open. -.IP "sysseek \s-1FILEHANDLE\s0,POSITION,WHENCE" 8 -.IX Xref "sysseek lseek" -.IX Item "sysseek FILEHANDLE,POSITION,WHENCE" -Sets \s-1FILEHANDLE\s0's system position in bytes using the system call -\&\fIlseek\fR\|(2). \s-1FILEHANDLE\s0 may be an expression whose value gives the name -of the filehandle. The values for \s-1WHENCE\s0 are \f(CW0\fR to set the new -position to \s-1POSITION\s0, \f(CW1\fR to set the it to the current position plus -\&\s-1POSITION\s0, and \f(CW2\fR to set it to \s-1EOF\s0 plus \s-1POSITION\s0 (typically -negative). -.Sp -Note the \fIin bytes\fR: even if the filehandle has been set to operate -on characters (for example by using the \f(CW\*(C`:utf8\*(C'\fR I/O layer), \fItell()\fR -will return byte offsets, not character offsets (because implementing -that would render \fIsysseek()\fR very slow). -.Sp -\&\fIsysseek()\fR bypasses normal buffered \s-1IO\s0, so mixing this with reads (other -than \f(CW\*(C`sysread\*(C'\fR, for example \f(CW\*(C`<>\*(C'\fR or \fIread()\fR) \f(CW\*(C`print\*(C'\fR, \f(CW\*(C`write\*(C'\fR, -\&\f(CW\*(C`seek\*(C'\fR, \f(CW\*(C`tell\*(C'\fR, or \f(CW\*(C`eof\*(C'\fR may cause confusion. -.Sp -For \s-1WHENCE\s0, you may also use the constants \f(CW\*(C`SEEK_SET\*(C'\fR, \f(CW\*(C`SEEK_CUR\*(C'\fR, -and \f(CW\*(C`SEEK_END\*(C'\fR (start of the file, current position, end of the file) -from the Fcntl module. Use of the constants is also more portable -than relying on 0, 1, and 2. For example to define a \*(L"systell\*(R" function: -.Sp -.Vb 2 -\& use Fcntl 'SEEK_CUR'; -\& sub systell { sysseek($_[0], 0, SEEK_CUR) } -.Ve -.Sp -Returns the new position, or the undefined value on failure. A position -of zero is returned as the string \f(CW"0 but true"\fR; thus \f(CW\*(C`sysseek\*(C'\fR returns -true on success and false on failure, yet you can still easily determine -the new position. -.IP "system \s-1LIST\s0" 8 -.IX Xref "system shell" -.IX Item "system LIST" -.PD 0 -.IP "system \s-1PROGRAM\s0 \s-1LIST\s0" 8 -.IX Item "system PROGRAM LIST" -.PD -Does exactly the same thing as \f(CW\*(C`exec LIST\*(C'\fR, except that a fork is -done first, and the parent process waits for the child process to -complete. Note that argument processing varies depending on the -number of arguments. If there is more than one argument in \s-1LIST\s0, -or if \s-1LIST\s0 is an array with more than one value, starts the program -given by the first element of the list with arguments given by the -rest of the list. If there is only one scalar argument, the argument -is checked for shell metacharacters, and if there are any, the -entire argument is passed to the system's command shell for parsing -(this is \f(CW\*(C`/bin/sh \-c\*(C'\fR on Unix platforms, but varies on other -platforms). If there are no shell metacharacters in the argument, -it is split into words and passed directly to \f(CW\*(C`execvp\*(C'\fR, which is -more efficient. -.Sp -Beginning with v5.6.0, Perl will attempt to flush all files opened for -output before any operation that may do a fork, but this may not be -supported on some platforms (see perlport). To be safe, you may need -to set \f(CW$|\fR ($AUTOFLUSH in English) or call the \f(CW\*(C`autoflush()\*(C'\fR method -of \f(CW\*(C`IO::Handle\*(C'\fR on any open handles. -.Sp -The return value is the exit status of the program as returned by the -\&\f(CW\*(C`wait\*(C'\fR call. To get the actual exit value, shift right by eight (see -below). See also \*(L"exec\*(R". This is \fInot\fR what you want to use to capture -the output from a command, for that you should use merely backticks or -\&\f(CW\*(C`qx//\*(C'\fR, as described in \*(L"`STRING`\*(R" in perlop. Return value of \-1 -indicates a failure to start the program or an error of the \fIwait\fR\|(2) system -call (inspect $! for the reason). -.Sp -Like \f(CW\*(C`exec\*(C'\fR, \f(CW\*(C`system\*(C'\fR allows you to lie to a program about its name if -you use the \f(CW\*(C`system PROGRAM LIST\*(C'\fR syntax. Again, see \*(L"exec\*(R". -.Sp -Since \f(CW\*(C`SIGINT\*(C'\fR and \f(CW\*(C`SIGQUIT\*(C'\fR are ignored during the execution of -\&\f(CW\*(C`system\*(C'\fR, if you expect your program to terminate on receipt of these -signals you will need to arrange to do so yourself based on the return -value. -.Sp -.Vb 3 -\& @args = ("command", "arg1", "arg2"); -\& system(@args) == 0 -\& or die "system @args failed: $?" -.Ve -.Sp -You can check all the failure possibilities by inspecting -\&\f(CW$?\fR like this: -.Sp -.Vb 10 -\& if ($? == -1) { -\& print "failed to execute: $!\en"; -\& } -\& elsif ($? & 127) { -\& printf "child died with signal %d, %s coredump\en", -\& ($? & 127), ($? & 128) ? 'with' : 'without'; -\& } -\& else { -\& printf "child exited with value %d\en", $? >> 8; -\& } -.Ve -.Sp -or more portably by using the W*() calls of the \s-1POSIX\s0 extension; -see perlport for more information. -.Sp -When the arguments get executed via the system shell, results -and return codes will be subject to its quirks and capabilities. -See \*(L"`STRING`\*(R" in perlop and \*(L"exec\*(R" for details. -.IP "syswrite \s-1FILEHANDLE\s0,SCALAR,LENGTH,OFFSET" 8 -.IX Xref "syswrite" -.IX Item "syswrite FILEHANDLE,SCALAR,LENGTH,OFFSET" -.PD 0 -.IP "syswrite \s-1FILEHANDLE\s0,SCALAR,LENGTH" 8 -.IX Item "syswrite FILEHANDLE,SCALAR,LENGTH" -.IP "syswrite \s-1FILEHANDLE\s0,SCALAR" 8 -.IX Item "syswrite FILEHANDLE,SCALAR" -.PD -Attempts to write \s-1LENGTH\s0 bytes of data from variable \s-1SCALAR\s0 to the -specified \s-1FILEHANDLE\s0, using the system call \fIwrite\fR\|(2). If \s-1LENGTH\s0 is -not specified, writes whole \s-1SCALAR\s0. It bypasses buffered \s-1IO\s0, so -mixing this with reads (other than \f(CWsysread())\fR, \f(CW\*(C`print\*(C'\fR, \f(CW\*(C`write\*(C'\fR, -\&\f(CW\*(C`seek\*(C'\fR, \f(CW\*(C`tell\*(C'\fR, or \f(CW\*(C`eof\*(C'\fR may cause confusion because the perlio and -stdio layers usually buffers data. Returns the number of bytes -actually written, or \f(CW\*(C`undef\*(C'\fR if there was an error (in this case the -errno variable \f(CW$!\fR is also set). If the \s-1LENGTH\s0 is greater than the -available data in the \s-1SCALAR\s0 after the \s-1OFFSET\s0, only as much data as is -available will be written. -.Sp -An \s-1OFFSET\s0 may be specified to write the data from some part of the -string other than the beginning. A negative \s-1OFFSET\s0 specifies writing -that many characters counting backwards from the end of the string. -In the case the \s-1SCALAR\s0 is empty you can use \s-1OFFSET\s0 but only zero offset. -.Sp -Note that if the filehandle has been marked as \f(CW\*(C`:utf8\*(C'\fR, Unicode -characters are written instead of bytes (the \s-1LENGTH\s0, \s-1OFFSET\s0, and the -return value of \fIsyswrite()\fR are in \s-1UTF\-8\s0 encoded Unicode characters). -The \f(CW\*(C`:encoding(...)\*(C'\fR layer implicitly introduces the \f(CW\*(C`:utf8\*(C'\fR layer. -See \*(L"binmode\*(R", \*(L"open\*(R", and the \f(CW\*(C`open\*(C'\fR pragma, open. -.IP "tell \s-1FILEHANDLE\s0" 8 -.IX Xref "tell" -.IX Item "tell FILEHANDLE" -.PD 0 -.IP "tell" 8 -.IX Item "tell" -.PD -Returns the current position \fIin bytes\fR for \s-1FILEHANDLE\s0, or \-1 on -error. \s-1FILEHANDLE\s0 may be an expression whose value gives the name of -the actual filehandle. If \s-1FILEHANDLE\s0 is omitted, assumes the file -last read. -.Sp -Note the \fIin bytes\fR: even if the filehandle has been set to -operate on characters (for example by using the \f(CW\*(C`:utf8\*(C'\fR open -layer), \fItell()\fR will return byte offsets, not character offsets -(because that would render \fIseek()\fR and \fItell()\fR rather slow). -.Sp -The return value of \fItell()\fR for the standard streams like the \s-1STDIN\s0 -depends on the operating system: it may return \-1 or something else. -\&\fItell()\fR on pipes, fifos, and sockets usually returns \-1. -.Sp -There is no \f(CW\*(C`systell\*(C'\fR function. Use \f(CW\*(C`sysseek(FH, 0, 1)\*(C'\fR for that. -.Sp -Do not use \fItell()\fR (or other buffered I/O operations) on a file handle -that has been manipulated by \fIsysread()\fR, \fIsyswrite()\fR or \fIsysseek()\fR. -Those functions ignore the buffering, while \fItell()\fR does not. -.IP "telldir \s-1DIRHANDLE\s0" 8 -.IX Xref "telldir" -.IX Item "telldir DIRHANDLE" -Returns the current position of the \f(CW\*(C`readdir\*(C'\fR routines on \s-1DIRHANDLE\s0. -Value may be given to \f(CW\*(C`seekdir\*(C'\fR to access a particular location in a -directory. \f(CW\*(C`telldir\*(C'\fR has the same caveats about possible directory -compaction as the corresponding system library routine. -.IP "tie \s-1VARIABLE\s0,CLASSNAME,LIST" 8 -.IX Xref "tie" -.IX Item "tie VARIABLE,CLASSNAME,LIST" -This function binds a variable to a package class that will provide the -implementation for the variable. \s-1VARIABLE\s0 is the name of the variable -to be enchanted. \s-1CLASSNAME\s0 is the name of a class implementing objects -of correct type. Any additional arguments are passed to the \f(CW\*(C`new\*(C'\fR -method of the class (meaning \f(CW\*(C`TIESCALAR\*(C'\fR, \f(CW\*(C`TIEHANDLE\*(C'\fR, \f(CW\*(C`TIEARRAY\*(C'\fR, -or \f(CW\*(C`TIEHASH\*(C'\fR). Typically these are arguments such as might be passed -to the \f(CW\*(C`dbm_open()\*(C'\fR function of C. The object returned by the \f(CW\*(C`new\*(C'\fR -method is also returned by the \f(CW\*(C`tie\*(C'\fR function, which would be useful -if you want to access other methods in \s-1CLASSNAME\s0. -.Sp -Note that functions such as \f(CW\*(C`keys\*(C'\fR and \f(CW\*(C`values\*(C'\fR may return huge lists -when used on large objects, like \s-1DBM\s0 files. You may prefer to use the -\&\f(CW\*(C`each\*(C'\fR function to iterate over such. Example: -.Sp -.Vb 7 -\& # print out history file offsets -\& use NDBM_File; -\& tie(%HIST, 'NDBM_File', '/usr/lib/news/history', 1, 0); -\& while (($key,$val) = each %HIST) { -\& print $key, ' = ', unpack('L',$val), "\en"; -\& } -\& untie(%HIST); -.Ve -.Sp -A class implementing a hash should have the following methods: -.Sp -.Vb 11 -\& TIEHASH classname, LIST -\& FETCH this, key -\& STORE this, key, value -\& DELETE this, key -\& CLEAR this -\& EXISTS this, key -\& FIRSTKEY this -\& NEXTKEY this, lastkey -\& SCALAR this -\& DESTROY this -\& UNTIE this -.Ve -.Sp -A class implementing an ordinary array should have the following methods: -.Sp -.Vb 14 -\& TIEARRAY classname, LIST -\& FETCH this, key -\& STORE this, key, value -\& FETCHSIZE this -\& STORESIZE this, count -\& CLEAR this -\& PUSH this, LIST -\& POP this -\& SHIFT this -\& UNSHIFT this, LIST -\& SPLICE this, offset, length, LIST -\& EXTEND this, count -\& DESTROY this -\& UNTIE this -.Ve -.Sp -A class implementing a file handle should have the following methods: -.Sp -.Vb 16 -\& TIEHANDLE classname, LIST -\& READ this, scalar, length, offset -\& READLINE this -\& GETC this -\& WRITE this, scalar, length, offset -\& PRINT this, LIST -\& PRINTF this, format, LIST -\& BINMODE this -\& EOF this -\& FILENO this -\& SEEK this, position, whence -\& TELL this -\& OPEN this, mode, LIST -\& CLOSE this -\& DESTROY this -\& UNTIE this -.Ve -.Sp -A class implementing a scalar should have the following methods: -.Sp -.Vb 5 -\& TIESCALAR classname, LIST -\& FETCH this, -\& STORE this, value -\& DESTROY this -\& UNTIE this -.Ve -.Sp -Not all methods indicated above need be implemented. See perltie, -Tie::Hash, Tie::Array, Tie::Scalar, and Tie::Handle. -.Sp -Unlike \f(CW\*(C`dbmopen\*(C'\fR, the \f(CW\*(C`tie\*(C'\fR function will not use or require a module -for you\*(--you need to do that explicitly yourself. See DB_File -or the \fIConfig\fR module for interesting \f(CW\*(C`tie\*(C'\fR implementations. -.Sp -For further details see perltie, \*(L"tied \s-1VARIABLE\s0\*(R". -.IP "tied \s-1VARIABLE\s0" 8 -.IX Xref "tied" -.IX Item "tied VARIABLE" -Returns a reference to the object underlying \s-1VARIABLE\s0 (the same value -that was originally returned by the \f(CW\*(C`tie\*(C'\fR call that bound the variable -to a package.) Returns the undefined value if \s-1VARIABLE\s0 isn't tied to a -package. -.IP "time" 8 -.IX Xref "time epoch" -.IX Item "time" -Returns the number of non-leap seconds since whatever time the system -considers to be the epoch, suitable for feeding to \f(CW\*(C`gmtime\*(C'\fR and -\&\f(CW\*(C`localtime\*(C'\fR. On most systems the epoch is 00:00:00 \s-1UTC\s0, January 1, 1970; -a prominent exception being Mac \s-1OS\s0 Classic which uses 00:00:00, January 1, -1904 in the current local time zone for its epoch. -.Sp -For measuring time in better granularity than one second, -you may use either the Time::HiRes module (from \s-1CPAN\s0, and starting from -Perl 5.8 part of the standard distribution), or if you have -\&\fIgettimeofday\fR\|(2), you may be able to use the \f(CW\*(C`syscall\*(C'\fR interface of Perl. -See perlfaq8 for details. -.IP "times" 8 -.IX Xref "times" -.IX Item "times" -Returns a four-element list giving the user and system times, in -seconds, for this process and the children of this process. -.Sp -.Vb 1 -\& ($user,$system,$cuser,$csystem) = times; -.Ve -.Sp -In scalar context, \f(CW\*(C`times\*(C'\fR returns \f(CW$user\fR. -.IP "tr///" 8 -.IX Item "tr///" -The transliteration operator. Same as \f(CW\*(C`y///\*(C'\fR. See perlop. -.IP "truncate \s-1FILEHANDLE\s0,LENGTH" 8 -.IX Xref "truncate" -.IX Item "truncate FILEHANDLE,LENGTH" -.PD 0 -.IP "truncate \s-1EXPR\s0,LENGTH" 8 -.IX Item "truncate EXPR,LENGTH" -.PD -Truncates the file opened on \s-1FILEHANDLE\s0, or named by \s-1EXPR\s0, to the -specified length. Produces a fatal error if truncate isn't implemented -on your system. Returns true if successful, the undefined value -otherwise. -.Sp -The behavior is undefined if \s-1LENGTH\s0 is greater than the length of the -file. -.IP "uc \s-1EXPR\s0" 8 -.IX Xref "uc uppercase toupper" -.IX Item "uc EXPR" -.PD 0 -.IP "uc" 8 -.IX Item "uc" -.PD -Returns an uppercased version of \s-1EXPR\s0. This is the internal function -implementing the \f(CW\*(C`\eU\*(C'\fR escape in double-quoted strings. Respects -current \s-1LC_CTYPE\s0 locale if \f(CW\*(C`use locale\*(C'\fR in force. See perllocale -and perlunicode for more details about locale and Unicode support. -It does not attempt to do titlecase mapping on initial letters. See -\&\f(CW\*(C`ucfirst\*(C'\fR for that. -.Sp -If \s-1EXPR\s0 is omitted, uses \f(CW$_\fR. -.IP "ucfirst \s-1EXPR\s0" 8 -.IX Xref "ucfirst uppercase" -.IX Item "ucfirst EXPR" -.PD 0 -.IP "ucfirst" 8 -.IX Item "ucfirst" -.PD -Returns the value of \s-1EXPR\s0 with the first character in uppercase -(titlecase in Unicode). This is the internal function implementing -the \f(CW\*(C`\eu\*(C'\fR escape in double-quoted strings. Respects current \s-1LC_CTYPE\s0 -locale if \f(CW\*(C`use locale\*(C'\fR in force. See perllocale and perlunicode -for more details about locale and Unicode support. -.Sp -If \s-1EXPR\s0 is omitted, uses \f(CW$_\fR. -.IP "umask \s-1EXPR\s0" 8 -.IX Xref "umask" -.IX Item "umask EXPR" -.PD 0 -.IP "umask" 8 -.IX Item "umask" -.PD -Sets the umask for the process to \s-1EXPR\s0 and returns the previous value. -If \s-1EXPR\s0 is omitted, merely returns the current umask. -.Sp -The Unix permission \f(CW\*(C`rwxr\-x\-\-\-\*(C'\fR is represented as three sets of three -bits, or three octal digits: \f(CW0750\fR (the leading 0 indicates octal -and isn't one of the digits). The \f(CW\*(C`umask\*(C'\fR value is such a number -representing disabled permissions bits. The permission (or \*(L"mode\*(R") -values you pass \f(CW\*(C`mkdir\*(C'\fR or \f(CW\*(C`sysopen\*(C'\fR are modified by your umask, so -even if you tell \f(CW\*(C`sysopen\*(C'\fR to create a file with permissions \f(CW0777\fR, -if your umask is \f(CW0022\fR then the file will actually be created with -permissions \f(CW0755\fR. If your \f(CW\*(C`umask\*(C'\fR were \f(CW0027\fR (group can't -write; others can't read, write, or execute), then passing -\&\f(CW\*(C`sysopen\*(C'\fR \f(CW0666\fR would create a file with mode \f(CW0640\fR (\f(CW\*(C`0666 &~ -027\*(C'\fR is \f(CW0640\fR). -.Sp -Here's some advice: supply a creation mode of \f(CW0666\fR for regular -files (in \f(CW\*(C`sysopen\*(C'\fR) and one of \f(CW0777\fR for directories (in -\&\f(CW\*(C`mkdir\*(C'\fR) and executable files. This gives users the freedom of -choice: if they want protected files, they might choose process umasks -of \f(CW022\fR, \f(CW027\fR, or even the particularly antisocial mask of \f(CW077\fR. -Programs should rarely if ever make policy decisions better left to -the user. The exception to this is when writing files that should be -kept private: mail files, web browser cookies, \fI.rhosts\fR files, and -so on. -.Sp -If \fIumask\fR\|(2) is not implemented on your system and you are trying to -restrict access for \fIyourself\fR (i.e., (\s-1EXPR\s0 & 0700) > 0), produces a -fatal error at run time. If \fIumask\fR\|(2) is not implemented and you are -not trying to restrict access for yourself, returns \f(CW\*(C`undef\*(C'\fR. -.Sp -Remember that a umask is a number, usually given in octal; it is \fInot\fR a -string of octal digits. See also \*(L"oct\*(R", if all you have is a string. -.IP "undef \s-1EXPR\s0" 8 -.IX Xref "undef undefine" -.IX Item "undef EXPR" -.PD 0 -.IP "undef" 8 -.IX Item "undef" -.PD -Undefines the value of \s-1EXPR\s0, which must be an lvalue. Use only on a -scalar value, an array (using \f(CW\*(C`@\*(C'\fR), a hash (using \f(CW\*(C`%\*(C'\fR), a subroutine -(using \f(CW\*(C`&\*(C'\fR), or a typeglob (using \f(CW\*(C`*\*(C'\fR). (Saying \f(CW\*(C`undef $hash{$key}\*(C'\fR -will probably not do what you expect on most predefined variables or -\&\s-1DBM\s0 list values, so don't do that; see delete.) Always returns the -undefined value. You can omit the \s-1EXPR\s0, in which case nothing is -undefined, but you still get an undefined value that you could, for -instance, return from a subroutine, assign to a variable or pass as a -parameter. Examples: -.Sp -.Vb 9 -\& undef $foo; -\& undef $bar{'blurfl'}; # Compare to: delete $bar{'blurfl'}; -\& undef @ary; -\& undef %hash; -\& undef &mysub; -\& undef *xyz; # destroys $xyz, @xyz, %xyz, &xyz, etc. -\& return (wantarray ? (undef, $errmsg) : undef) if $they_blew_it; -\& select undef, undef, undef, 0.25; -\& ($a, $b, undef, $c) = &foo; # Ignore third value returned -.Ve -.Sp -Note that this is a unary operator, not a list operator. -.IP "unlink \s-1LIST\s0" 8 -.IX Xref "unlink delete remove rm" -.IX Item "unlink LIST" -.PD 0 -.IP "unlink" 8 -.IX Item "unlink" -.PD -Deletes a list of files. Returns the number of files successfully -deleted. -.Sp -.Vb 3 -\& $cnt = unlink 'a', 'b', 'c'; -\& unlink @goners; -\& unlink <*.bak>; -.Ve -.Sp -Note: \f(CW\*(C`unlink\*(C'\fR will not attempt to delete directories unless you are superuser -and the \fB\-U\fR flag is supplied to Perl. Even if these conditions are -met, be warned that unlinking a directory can inflict damage on your -filesystem. Finally, using \f(CW\*(C`unlink\*(C'\fR on directories is not supported on -many operating systems. Use \f(CW\*(C`rmdir\*(C'\fR instead. -.Sp -If \s-1LIST\s0 is omitted, uses \f(CW$_\fR. -.IP "unpack \s-1TEMPLATE\s0,EXPR" 8 -.IX Xref "unpack" -.IX Item "unpack TEMPLATE,EXPR" -\&\f(CW\*(C`unpack\*(C'\fR does the reverse of \f(CW\*(C`pack\*(C'\fR: it takes a string -and expands it out into a list of values. -(In scalar context, it returns merely the first value produced.) -.Sp -The string is broken into chunks described by the \s-1TEMPLATE\s0. Each chunk -is converted separately to a value. Typically, either the string is a result -of \f(CW\*(C`pack\*(C'\fR, or the bytes of the string represent a C structure of some -kind. -.Sp -The \s-1TEMPLATE\s0 has the same format as in the \f(CW\*(C`pack\*(C'\fR function. -Here's a subroutine that does substring: -.Sp -.Vb 4 -\& sub substr { -\& my($what,$where,$howmuch) = @_; -\& unpack("x$where a$howmuch", $what); -\& } -.Ve -.Sp -and then there's -.Sp -.Vb 1 -\& sub ordinal { unpack("c",$_[0]); } # same as ord() -.Ve -.Sp -In addition to fields allowed in \fIpack()\fR, you may prefix a field with -a %<number> to indicate that -you want a <number>\-bit checksum of the items instead of the items -themselves. Default is a 16\-bit checksum. Checksum is calculated by -summing numeric values of expanded values (for string fields the sum of -\&\f(CW\*(C`ord($char)\*(C'\fR is taken, for bit fields the sum of zeroes and ones). -.Sp -For example, the following -computes the same number as the System V sum program: -.Sp -.Vb 4 -\& $checksum = do { -\& local $/; # slurp! -\& unpack("%32C*",<>) % 65535; -\& }; -.Ve -.Sp -The following efficiently counts the number of set bits in a bit vector: -.Sp -.Vb 1 -\& $setbits = unpack("%32b*", $selectmask); -.Ve -.Sp -The \f(CW\*(C`p\*(C'\fR and \f(CW\*(C`P\*(C'\fR formats should be used with care. Since Perl -has no way of checking whether the value passed to \f(CW\*(C`unpack()\*(C'\fR -corresponds to a valid memory location, passing a pointer value that's -not known to be valid is likely to have disastrous consequences. -.Sp -If there are more pack codes or if the repeat count of a field or a group -is larger than what the remainder of the input string allows, the result -is not well defined: in some cases, the repeat count is decreased, or -\&\f(CW\*(C`unpack()\*(C'\fR will produce null strings or zeroes, or terminate with an -error. If the input string is longer than one described by the \s-1TEMPLATE\s0, -the rest is ignored. -.Sp -See \*(L"pack\*(R" for more examples and notes. -.IP "untie \s-1VARIABLE\s0" 8 -.IX Xref "untie" -.IX Item "untie VARIABLE" -Breaks the binding between a variable and a package. (See \f(CW\*(C`tie\*(C'\fR.) -Has no effect if the variable is not tied. -.IP "unshift \s-1ARRAY\s0,LIST" 8 -.IX Xref "unshift" -.IX Item "unshift ARRAY,LIST" -Does the opposite of a \f(CW\*(C`shift\*(C'\fR. Or the opposite of a \f(CW\*(C`push\*(C'\fR, -depending on how you look at it. Prepends list to the front of the -array, and returns the new number of elements in the array. -.Sp -.Vb 1 -\& unshift(@ARGV, '-e') unless $ARGV[0] =~ /^-/; -.Ve -.Sp -Note the \s-1LIST\s0 is prepended whole, not one element at a time, so the -prepended elements stay in the same order. Use \f(CW\*(C`reverse\*(C'\fR to do the -reverse. -.IP "use Module \s-1VERSION\s0 \s-1LIST\s0" 8 -.IX Xref "use module import" -.IX Item "use Module VERSION LIST" -.PD 0 -.IP "use Module \s-1VERSION\s0" 8 -.IX Item "use Module VERSION" -.IP "use Module \s-1LIST\s0" 8 -.IX Item "use Module LIST" -.IP "use Module" 8 -.IX Item "use Module" -.IP "use \s-1VERSION\s0" 8 -.IX Item "use VERSION" -.PD -Imports some semantics into the current package from the named module, -generally by aliasing certain subroutine or variable names into your -package. It is exactly equivalent to -.Sp -.Vb 1 -\& BEGIN { require Module; import Module LIST; } -.Ve -.Sp -except that Module \fImust\fR be a bareword. -.Sp -\&\s-1VERSION\s0 may be either a numeric argument such as 5.006, which will be -compared to \f(CW$]\fR, or a literal of the form v5.6.1, which will be compared -to \f(CW$^V\fR (aka \f(CW$PERL_VERSION\fR. A fatal error is produced if \s-1VERSION\s0 is -greater than the version of the current Perl interpreter; Perl will not -attempt to parse the rest of the file. Compare with \*(L"require\*(R", which can -do a similar check at run time. -.Sp -Specifying \s-1VERSION\s0 as a literal of the form v5.6.1 should generally be -avoided, because it leads to misleading error messages under earlier -versions of Perl that do not support this syntax. The equivalent numeric -version should be used instead. -.Sp -.Vb 3 -\& use v5.6.1; # compile time version check -\& use 5.6.1; # ditto -\& use 5.006_001; # ditto; preferred for backwards compatibility -.Ve -.Sp -This is often useful if you need to check the current Perl version before -\&\f(CW\*(C`use\*(C'\fRing library modules that have changed in incompatible ways from -older versions of Perl. (We try not to do this more than we have to.) -.Sp -The \f(CW\*(C`BEGIN\*(C'\fR forces the \f(CW\*(C`require\*(C'\fR and \f(CW\*(C`import\*(C'\fR to happen at compile time. The -\&\f(CW\*(C`require\*(C'\fR makes sure the module is loaded into memory if it hasn't been -yet. The \f(CW\*(C`import\*(C'\fR is not a builtin\*(--it's just an ordinary static method -call into the \f(CW\*(C`Module\*(C'\fR package to tell the module to import the list of -features back into the current package. The module can implement its -\&\f(CW\*(C`import\*(C'\fR method any way it likes, though most modules just choose to -derive their \f(CW\*(C`import\*(C'\fR method via inheritance from the \f(CW\*(C`Exporter\*(C'\fR class that -is defined in the \f(CW\*(C`Exporter\*(C'\fR module. See Exporter. If no \f(CW\*(C`import\*(C'\fR -method can be found then the call is skipped. -.Sp -If you do not want to call the package's \f(CW\*(C`import\*(C'\fR method (for instance, -to stop your namespace from being altered), explicitly supply the empty list: -.Sp -.Vb 1 -\& use Module (); -.Ve -.Sp -That is exactly equivalent to -.Sp -.Vb 1 -\& BEGIN { require Module } -.Ve -.Sp -If the \s-1VERSION\s0 argument is present between Module and \s-1LIST\s0, then the -\&\f(CW\*(C`use\*(C'\fR will call the \s-1VERSION\s0 method in class Module with the given -version as an argument. The default \s-1VERSION\s0 method, inherited from -the \s-1UNIVERSAL\s0 class, croaks if the given version is larger than the -value of the variable \f(CW$Module::VERSION\fR. -.Sp -Again, there is a distinction between omitting \s-1LIST\s0 (\f(CW\*(C`import\*(C'\fR called -with no arguments) and an explicit empty \s-1LIST\s0 \f(CW\*(C`()\*(C'\fR (\f(CW\*(C`import\*(C'\fR not -called). Note that there is no comma after \s-1VERSION\s0! -.Sp -Because this is a wide-open interface, pragmas (compiler directives) -are also implemented this way. Currently implemented pragmas are: -.Sp -.Vb 8 -\& use constant; -\& use diagnostics; -\& use integer; -\& use sigtrap qw(SEGV BUS); -\& use strict qw(subs vars refs); -\& use subs qw(afunc blurfl); -\& use warnings qw(all); -\& use sort qw(stable _quicksort _mergesort); -.Ve -.Sp -Some of these pseudo-modules import semantics into the current -block scope (like \f(CW\*(C`strict\*(C'\fR or \f(CW\*(C`integer\*(C'\fR, unlike ordinary modules, -which import symbols into the current package (which are effective -through the end of the file). -.Sp -There's a corresponding \f(CW\*(C`no\*(C'\fR command that unimports meanings imported -by \f(CW\*(C`use\*(C'\fR, i.e., it calls \f(CW\*(C`unimport Module LIST\*(C'\fR instead of \f(CW\*(C`import\*(C'\fR. -.Sp -.Vb 3 -\& no integer; -\& no strict 'refs'; -\& no warnings; -.Ve -.Sp -See perlmodlib for a list of standard modules and pragmas. See perlrun -for the \f(CW\*(C`\-M\*(C'\fR and \f(CW\*(C`\-m\*(C'\fR command-line options to perl that give \f(CW\*(C`use\*(C'\fR -functionality from the command\-line. -.IP "utime \s-1LIST\s0" 8 -.IX Xref "utime" -.IX Item "utime LIST" -Changes the access and modification times on each file of a list of -files. The first two elements of the list must be the \s-1NUMERICAL\s0 access -and modification times, in that order. Returns the number of files -successfully changed. The inode change time of each file is set -to the current time. For example, this code has the same effect as the -Unix \fItouch\fR\|(1) command when the files \fIalready exist\fR and belong to -the user running the program: -.Sp -.Vb 3 -\& #!/usr/bin/perl -\& $atime = $mtime = time; -\& utime $atime, $mtime, @ARGV; -.Ve -.Sp -Since perl 5.7.2, if the first two elements of the list are \f(CW\*(C`undef\*(C'\fR, then -the \fIutime\fR\|(2) function in the C library will be called with a null second -argument. On most systems, this will set the file's access and -modification times to the current time (i.e. equivalent to the example -above) and will even work on other users' files where you have write -permission: -.Sp -.Vb 1 -\& utime undef, undef, @ARGV; -.Ve -.Sp -Under \s-1NFS\s0 this will use the time of the \s-1NFS\s0 server, not the time of -the local machine. If there is a time synchronization problem, the -\&\s-1NFS\s0 server and local machine will have different times. The Unix -\&\fItouch\fR\|(1) command will in fact normally use this form instead of the -one shown in the first example. -.Sp -Note that only passing one of the first two elements as \f(CW\*(C`undef\*(C'\fR will -be equivalent of passing it as 0 and will not have the same effect as -described when they are both \f(CW\*(C`undef\*(C'\fR. This case will also trigger an -uninitialized warning. -.IP "values \s-1HASH\s0" 8 -.IX Xref "values" -.IX Item "values HASH" -Returns a list consisting of all the values of the named hash. -(In a scalar context, returns the number of values.) -.Sp -The values are returned in an apparently random order. The actual -random order is subject to change in future versions of perl, but it -is guaranteed to be the same order as either the \f(CW\*(C`keys\*(C'\fR or \f(CW\*(C`each\*(C'\fR -function would produce on the same (unmodified) hash. Since Perl -5.8.1 the ordering is different even between different runs of Perl -for security reasons (see \*(L"Algorithmic Complexity Attacks\*(R" in perlsec). -.Sp -As a side effect, calling \fIvalues()\fR resets the \s-1HASH\s0's internal iterator, -see \*(L"each\*(R". (In particular, calling \fIvalues()\fR in void context resets -the iterator with no other overhead.) -.Sp -Note that the values are not copied, which means modifying them will -modify the contents of the hash: -.Sp -.Vb 2 -\& for (values %hash) { s/foo/bar/g } # modifies %hash values -\& for (@hash{keys %hash}) { s/foo/bar/g } # same -.Ve -.Sp -See also \f(CW\*(C`keys\*(C'\fR, \f(CW\*(C`each\*(C'\fR, and \f(CW\*(C`sort\*(C'\fR. -.IP "vec \s-1EXPR\s0,OFFSET,BITS" 8 -.IX Xref "vec bit bit vector" -.IX Item "vec EXPR,OFFSET,BITS" -Treats the string in \s-1EXPR\s0 as a bit vector made up of elements of -width \s-1BITS\s0, and returns the value of the element specified by \s-1OFFSET\s0 -as an unsigned integer. \s-1BITS\s0 therefore specifies the number of bits -that are reserved for each element in the bit vector. This must -be a power of two from 1 to 32 (or 64, if your platform supports -that). -.Sp -If \s-1BITS\s0 is 8, \*(L"elements\*(R" coincide with bytes of the input string. -.Sp -If \s-1BITS\s0 is 16 or more, bytes of the input string are grouped into chunks -of size \s-1BITS/8\s0, and each group is converted to a number as with -\&\fIpack()\fR/\fIunpack()\fR with big-endian formats \f(CW\*(C`n\*(C'\fR/\f(CW\*(C`N\*(C'\fR (and analogously -for BITS==64). See \*(L"pack\*(R" for details. -.Sp -If bits is 4 or less, the string is broken into bytes, then the bits -of each byte are broken into 8/BITS groups. Bits of a byte are -numbered in a little-endian-ish way, as in \f(CW0x01\fR, \f(CW0x02\fR, -\&\f(CW0x04\fR, \f(CW0x08\fR, \f(CW0x10\fR, \f(CW0x20\fR, \f(CW0x40\fR, \f(CW0x80\fR. For example, -breaking the single input byte \f(CW\*(C`chr(0x36)\*(C'\fR into two groups gives a list -\&\f(CW\*(C`(0x6, 0x3)\*(C'\fR; breaking it into 4 groups gives \f(CW\*(C`(0x2, 0x1, 0x3, 0x0)\*(C'\fR. -.Sp -\&\f(CW\*(C`vec\*(C'\fR may also be assigned to, in which case parentheses are needed -to give the expression the correct precedence as in -.Sp -.Vb 1 -\& vec($image, $max_x * $x + $y, 8) = 3; -.Ve -.Sp -If the selected element is outside the string, the value 0 is returned. -If an element off the end of the string is written to, Perl will first -extend the string with sufficiently many zero bytes. It is an error -to try to write off the beginning of the string (i.e. negative \s-1OFFSET\s0). -.Sp -The string should not contain any character with the value > 255 (which -can only happen if you're using \s-1UTF\-8\s0 encoding). If it does, it will be -treated as something that is not \s-1UTF\-8\s0 encoded. When the \f(CW\*(C`vec\*(C'\fR was -assigned to, other parts of your program will also no longer consider the -string to be \s-1UTF\-8\s0 encoded. In other words, if you do have such characters -in your string, \fIvec()\fR will operate on the actual byte string, and not the -conceptual character string. -.Sp -Strings created with \f(CW\*(C`vec\*(C'\fR can also be manipulated with the logical -operators \f(CW\*(C`|\*(C'\fR, \f(CW\*(C`&\*(C'\fR, \f(CW\*(C`^\*(C'\fR, and \f(CW\*(C`~\*(C'\fR. These operators will assume a bit -vector operation is desired when both operands are strings. -See \*(L"Bitwise String Operators\*(R" in perlop. -.Sp -The following code will build up an \s-1ASCII\s0 string saying \f(CW'PerlPerlPerl'\fR. -The comments show the string after each step. Note that this code works -in the same way on big-endian or little-endian machines. -.Sp -.Vb 2 -\& my $foo = ''; -\& vec($foo, 0, 32) = 0x5065726C; # 'Perl' -.Ve -.Sp -.Vb 2 -\& # $foo eq "Perl" eq "\ex50\ex65\ex72\ex6C", 32 bits -\& print vec($foo, 0, 8); # prints 80 == 0x50 == ord('P') -.Ve -.Sp -.Vb 11 -\& vec($foo, 2, 16) = 0x5065; # 'PerlPe' -\& vec($foo, 3, 16) = 0x726C; # 'PerlPerl' -\& vec($foo, 8, 8) = 0x50; # 'PerlPerlP' -\& vec($foo, 9, 8) = 0x65; # 'PerlPerlPe' -\& vec($foo, 20, 4) = 2; # 'PerlPerlPe' . "\ex02" -\& vec($foo, 21, 4) = 7; # 'PerlPerlPer' -\& # 'r' is "\ex72" -\& vec($foo, 45, 2) = 3; # 'PerlPerlPer' . "\ex0c" -\& vec($foo, 93, 1) = 1; # 'PerlPerlPer' . "\ex2c" -\& vec($foo, 94, 1) = 1; # 'PerlPerlPerl' -\& # 'l' is "\ex6c" -.Ve -.Sp -To transform a bit vector into a string or list of 0's and 1's, use these: -.Sp -.Vb 2 -\& $bits = unpack("b*", $vector); -\& @bits = split(//, unpack("b*", $vector)); -.Ve -.Sp -If you know the exact length in bits, it can be used in place of the \f(CW\*(C`*\*(C'\fR. -.Sp -Here is an example to illustrate how the bits actually fall in place: -.Sp -.Vb 1 -\& #!/usr/bin/perl -wl -.Ve -.Sp -.Vb 5 -\& print <<'EOT'; -\& 0 1 2 3 -\& unpack("V",$_) 01234567890123456789012345678901 -\& ------------------------------------------------------------------ -\& EOT -.Ve -.Sp -.Vb 13 -\& for $w (0..3) { -\& $width = 2**$w; -\& for ($shift=0; $shift < $width; ++$shift) { -\& for ($off=0; $off < 32/$width; ++$off) { -\& $str = pack("B*", "0"x32); -\& $bits = (1<<$shift); -\& vec($str, $off, $width) = $bits; -\& $res = unpack("b*",$str); -\& $val = unpack("V", $str); -\& write; -\& } -\& } -\& } -.Ve -.Sp -.Vb 5 -\& format STDOUT = -\& vec($_,@#,@#) = @<< == @######### @>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -\& $off, $width, $bits, $val, $res -\& . -\& __END__ -.Ve -.Sp -Regardless of the machine architecture on which it is run, the above -example should print the following table: -.Sp -.Vb 131 -\& 0 1 2 3 -\& unpack("V",$_) 01234567890123456789012345678901 -\& ------------------------------------------------------------------ -\& vec($_, 0, 1) = 1 == 1 10000000000000000000000000000000 -\& vec($_, 1, 1) = 1 == 2 01000000000000000000000000000000 -\& vec($_, 2, 1) = 1 == 4 00100000000000000000000000000000 -\& vec($_, 3, 1) = 1 == 8 00010000000000000000000000000000 -\& vec($_, 4, 1) = 1 == 16 00001000000000000000000000000000 -\& vec($_, 5, 1) = 1 == 32 00000100000000000000000000000000 -\& vec($_, 6, 1) = 1 == 64 00000010000000000000000000000000 -\& vec($_, 7, 1) = 1 == 128 00000001000000000000000000000000 -\& vec($_, 8, 1) = 1 == 256 00000000100000000000000000000000 -\& vec($_, 9, 1) = 1 == 512 00000000010000000000000000000000 -\& vec($_,10, 1) = 1 == 1024 00000000001000000000000000000000 -\& vec($_,11, 1) = 1 == 2048 00000000000100000000000000000000 -\& vec($_,12, 1) = 1 == 4096 00000000000010000000000000000000 -\& vec($_,13, 1) = 1 == 8192 00000000000001000000000000000000 -\& vec($_,14, 1) = 1 == 16384 00000000000000100000000000000000 -\& vec($_,15, 1) = 1 == 32768 00000000000000010000000000000000 -\& vec($_,16, 1) = 1 == 65536 00000000000000001000000000000000 -\& vec($_,17, 1) = 1 == 131072 00000000000000000100000000000000 -\& vec($_,18, 1) = 1 == 262144 00000000000000000010000000000000 -\& vec($_,19, 1) = 1 == 524288 00000000000000000001000000000000 -\& vec($_,20, 1) = 1 == 1048576 00000000000000000000100000000000 -\& vec($_,21, 1) = 1 == 2097152 00000000000000000000010000000000 -\& vec($_,22, 1) = 1 == 4194304 00000000000000000000001000000000 -\& vec($_,23, 1) = 1 == 8388608 00000000000000000000000100000000 -\& vec($_,24, 1) = 1 == 16777216 00000000000000000000000010000000 -\& vec($_,25, 1) = 1 == 33554432 00000000000000000000000001000000 -\& vec($_,26, 1) = 1 == 67108864 00000000000000000000000000100000 -\& vec($_,27, 1) = 1 == 134217728 00000000000000000000000000010000 -\& vec($_,28, 1) = 1 == 268435456 00000000000000000000000000001000 -\& vec($_,29, 1) = 1 == 536870912 00000000000000000000000000000100 -\& vec($_,30, 1) = 1 == 1073741824 00000000000000000000000000000010 -\& vec($_,31, 1) = 1 == 2147483648 00000000000000000000000000000001 -\& vec($_, 0, 2) = 1 == 1 10000000000000000000000000000000 -\& vec($_, 1, 2) = 1 == 4 00100000000000000000000000000000 -\& vec($_, 2, 2) = 1 == 16 00001000000000000000000000000000 -\& vec($_, 3, 2) = 1 == 64 00000010000000000000000000000000 -\& vec($_, 4, 2) = 1 == 256 00000000100000000000000000000000 -\& vec($_, 5, 2) = 1 == 1024 00000000001000000000000000000000 -\& vec($_, 6, 2) = 1 == 4096 00000000000010000000000000000000 -\& vec($_, 7, 2) = 1 == 16384 00000000000000100000000000000000 -\& vec($_, 8, 2) = 1 == 65536 00000000000000001000000000000000 -\& vec($_, 9, 2) = 1 == 262144 00000000000000000010000000000000 -\& vec($_,10, 2) = 1 == 1048576 00000000000000000000100000000000 -\& vec($_,11, 2) = 1 == 4194304 00000000000000000000001000000000 -\& vec($_,12, 2) = 1 == 16777216 00000000000000000000000010000000 -\& vec($_,13, 2) = 1 == 67108864 00000000000000000000000000100000 -\& vec($_,14, 2) = 1 == 268435456 00000000000000000000000000001000 -\& vec($_,15, 2) = 1 == 1073741824 00000000000000000000000000000010 -\& vec($_, 0, 2) = 2 == 2 01000000000000000000000000000000 -\& vec($_, 1, 2) = 2 == 8 00010000000000000000000000000000 -\& vec($_, 2, 2) = 2 == 32 00000100000000000000000000000000 -\& vec($_, 3, 2) = 2 == 128 00000001000000000000000000000000 -\& vec($_, 4, 2) = 2 == 512 00000000010000000000000000000000 -\& vec($_, 5, 2) = 2 == 2048 00000000000100000000000000000000 -\& vec($_, 6, 2) = 2 == 8192 00000000000001000000000000000000 -\& vec($_, 7, 2) = 2 == 32768 00000000000000010000000000000000 -\& vec($_, 8, 2) = 2 == 131072 00000000000000000100000000000000 -\& vec($_, 9, 2) = 2 == 524288 00000000000000000001000000000000 -\& vec($_,10, 2) = 2 == 2097152 00000000000000000000010000000000 -\& vec($_,11, 2) = 2 == 8388608 00000000000000000000000100000000 -\& vec($_,12, 2) = 2 == 33554432 00000000000000000000000001000000 -\& vec($_,13, 2) = 2 == 134217728 00000000000000000000000000010000 -\& vec($_,14, 2) = 2 == 536870912 00000000000000000000000000000100 -\& vec($_,15, 2) = 2 == 2147483648 00000000000000000000000000000001 -\& vec($_, 0, 4) = 1 == 1 10000000000000000000000000000000 -\& vec($_, 1, 4) = 1 == 16 00001000000000000000000000000000 -\& vec($_, 2, 4) = 1 == 256 00000000100000000000000000000000 -\& vec($_, 3, 4) = 1 == 4096 00000000000010000000000000000000 -\& vec($_, 4, 4) = 1 == 65536 00000000000000001000000000000000 -\& vec($_, 5, 4) = 1 == 1048576 00000000000000000000100000000000 -\& vec($_, 6, 4) = 1 == 16777216 00000000000000000000000010000000 -\& vec($_, 7, 4) = 1 == 268435456 00000000000000000000000000001000 -\& vec($_, 0, 4) = 2 == 2 01000000000000000000000000000000 -\& vec($_, 1, 4) = 2 == 32 00000100000000000000000000000000 -\& vec($_, 2, 4) = 2 == 512 00000000010000000000000000000000 -\& vec($_, 3, 4) = 2 == 8192 00000000000001000000000000000000 -\& vec($_, 4, 4) = 2 == 131072 00000000000000000100000000000000 -\& vec($_, 5, 4) = 2 == 2097152 00000000000000000000010000000000 -\& vec($_, 6, 4) = 2 == 33554432 00000000000000000000000001000000 -\& vec($_, 7, 4) = 2 == 536870912 00000000000000000000000000000100 -\& vec($_, 0, 4) = 4 == 4 00100000000000000000000000000000 -\& vec($_, 1, 4) = 4 == 64 00000010000000000000000000000000 -\& vec($_, 2, 4) = 4 == 1024 00000000001000000000000000000000 -\& vec($_, 3, 4) = 4 == 16384 00000000000000100000000000000000 -\& vec($_, 4, 4) = 4 == 262144 00000000000000000010000000000000 -\& vec($_, 5, 4) = 4 == 4194304 00000000000000000000001000000000 -\& vec($_, 6, 4) = 4 == 67108864 00000000000000000000000000100000 -\& vec($_, 7, 4) = 4 == 1073741824 00000000000000000000000000000010 -\& vec($_, 0, 4) = 8 == 8 00010000000000000000000000000000 -\& vec($_, 1, 4) = 8 == 128 00000001000000000000000000000000 -\& vec($_, 2, 4) = 8 == 2048 00000000000100000000000000000000 -\& vec($_, 3, 4) = 8 == 32768 00000000000000010000000000000000 -\& vec($_, 4, 4) = 8 == 524288 00000000000000000001000000000000 -\& vec($_, 5, 4) = 8 == 8388608 00000000000000000000000100000000 -\& vec($_, 6, 4) = 8 == 134217728 00000000000000000000000000010000 -\& vec($_, 7, 4) = 8 == 2147483648 00000000000000000000000000000001 -\& vec($_, 0, 8) = 1 == 1 10000000000000000000000000000000 -\& vec($_, 1, 8) = 1 == 256 00000000100000000000000000000000 -\& vec($_, 2, 8) = 1 == 65536 00000000000000001000000000000000 -\& vec($_, 3, 8) = 1 == 16777216 00000000000000000000000010000000 -\& vec($_, 0, 8) = 2 == 2 01000000000000000000000000000000 -\& vec($_, 1, 8) = 2 == 512 00000000010000000000000000000000 -\& vec($_, 2, 8) = 2 == 131072 00000000000000000100000000000000 -\& vec($_, 3, 8) = 2 == 33554432 00000000000000000000000001000000 -\& vec($_, 0, 8) = 4 == 4 00100000000000000000000000000000 -\& vec($_, 1, 8) = 4 == 1024 00000000001000000000000000000000 -\& vec($_, 2, 8) = 4 == 262144 00000000000000000010000000000000 -\& vec($_, 3, 8) = 4 == 67108864 00000000000000000000000000100000 -\& vec($_, 0, 8) = 8 == 8 00010000000000000000000000000000 -\& vec($_, 1, 8) = 8 == 2048 00000000000100000000000000000000 -\& vec($_, 2, 8) = 8 == 524288 00000000000000000001000000000000 -\& vec($_, 3, 8) = 8 == 134217728 00000000000000000000000000010000 -\& vec($_, 0, 8) = 16 == 16 00001000000000000000000000000000 -\& vec($_, 1, 8) = 16 == 4096 00000000000010000000000000000000 -\& vec($_, 2, 8) = 16 == 1048576 00000000000000000000100000000000 -\& vec($_, 3, 8) = 16 == 268435456 00000000000000000000000000001000 -\& vec($_, 0, 8) = 32 == 32 00000100000000000000000000000000 -\& vec($_, 1, 8) = 32 == 8192 00000000000001000000000000000000 -\& vec($_, 2, 8) = 32 == 2097152 00000000000000000000010000000000 -\& vec($_, 3, 8) = 32 == 536870912 00000000000000000000000000000100 -\& vec($_, 0, 8) = 64 == 64 00000010000000000000000000000000 -\& vec($_, 1, 8) = 64 == 16384 00000000000000100000000000000000 -\& vec($_, 2, 8) = 64 == 4194304 00000000000000000000001000000000 -\& vec($_, 3, 8) = 64 == 1073741824 00000000000000000000000000000010 -\& vec($_, 0, 8) = 128 == 128 00000001000000000000000000000000 -\& vec($_, 1, 8) = 128 == 32768 00000000000000010000000000000000 -\& vec($_, 2, 8) = 128 == 8388608 00000000000000000000000100000000 -\& vec($_, 3, 8) = 128 == 2147483648 00000000000000000000000000000001 -.Ve -.IP "wait" 8 -.IX Xref "wait" -.IX Item "wait" -Behaves like the \fIwait\fR\|(2) system call on your system: it waits for a child -process to terminate and returns the pid of the deceased process, or -\&\f(CW\*(C`\-1\*(C'\fR if there are no child processes. The status is returned in \f(CW$?\fR. -Note that a return value of \f(CW\*(C`\-1\*(C'\fR could mean that child processes are -being automatically reaped, as described in perlipc. -.IP "waitpid \s-1PID\s0,FLAGS" 8 -.IX Xref "waitpid" -.IX Item "waitpid PID,FLAGS" -Waits for a particular child process to terminate and returns the pid of -the deceased process, or \f(CW\*(C`\-1\*(C'\fR if there is no such child process. On some -systems, a value of 0 indicates that there are processes still running. -The status is returned in \f(CW$?\fR. If you say -.Sp -.Vb 5 -\& use POSIX ":sys_wait_h"; -\& #... -\& do { -\& $kid = waitpid(-1, WNOHANG); -\& } until $kid > 0; -.Ve -.Sp -then you can do a non-blocking wait for all pending zombie processes. -Non-blocking wait is available on machines supporting either the -\&\fIwaitpid\fR\|(2) or \fIwait4\fR\|(2) system calls. However, waiting for a particular -pid with \s-1FLAGS\s0 of \f(CW0\fR is implemented everywhere. (Perl emulates the -system call by remembering the status values of processes that have -exited but have not been harvested by the Perl script yet.) -.Sp -Note that on some systems, a return value of \f(CW\*(C`\-1\*(C'\fR could mean that child -processes are being automatically reaped. See perlipc for details, -and for other examples. -.IP "wantarray" 8 -.IX Xref "wantarray context" -.IX Item "wantarray" -Returns true if the context of the currently executing subroutine or -\&\f(CW\*(C`eval\*(C'\fR is looking for a list value. Returns false if the context is -looking for a scalar. Returns the undefined value if the context is -looking for no value (void context). -.Sp -.Vb 3 -\& return unless defined wantarray; # don't bother doing more -\& my @a = complex_calculation(); -\& return wantarray ? @a : "@a"; -.Ve -.Sp -\&\f(CW\*(C`wantarray()\*(C'\fR's result is unspecified in the top level of a file, -in a \f(CW\*(C`BEGIN\*(C'\fR, \f(CW\*(C`CHECK\*(C'\fR, \f(CW\*(C`INIT\*(C'\fR or \f(CW\*(C`END\*(C'\fR block, or in a \f(CW\*(C`DESTROY\*(C'\fR -method. -.Sp -This function should have been named \fIwantlist()\fR instead. -.IP "warn \s-1LIST\s0" 8 -.IX Xref "warn warning STDERR" -.IX Item "warn LIST" -Produces a message on \s-1STDERR\s0 just like \f(CW\*(C`die\*(C'\fR, but doesn't exit or throw -an exception. -.Sp -If \s-1LIST\s0 is empty and \f(CW$@\fR already contains a value (typically from a -previous eval) that value is used after appending \f(CW"\et...caught"\fR -to \f(CW$@\fR. This is useful for staying almost, but not entirely similar to -\&\f(CW\*(C`die\*(C'\fR. -.Sp -If \f(CW$@\fR is empty then the string \f(CW"Warning: Something's wrong"\fR is used. -.Sp -No message is printed if there is a \f(CW$SIG{_\|_WARN_\|_}\fR handler -installed. It is the handler's responsibility to deal with the message -as it sees fit (like, for instance, converting it into a \f(CW\*(C`die\*(C'\fR). Most -handlers must therefore make arrangements to actually display the -warnings that they are not prepared to deal with, by calling \f(CW\*(C`warn\*(C'\fR -again in the handler. Note that this is quite safe and will not -produce an endless loop, since \f(CW\*(C`_\|_WARN_\|_\*(C'\fR hooks are not called from -inside one. -.Sp -You will find this behavior is slightly different from that of -\&\f(CW$SIG{_\|_DIE_\|_}\fR handlers (which don't suppress the error text, but can -instead call \f(CW\*(C`die\*(C'\fR again to change it). -.Sp -Using a \f(CW\*(C`_\|_WARN_\|_\*(C'\fR handler provides a powerful way to silence all -warnings (even the so-called mandatory ones). An example: -.Sp -.Vb 7 -\& # wipe out *all* compile-time warnings -\& BEGIN { $SIG{'__WARN__'} = sub { warn $_[0] if $DOWARN } } -\& my $foo = 10; -\& my $foo = 20; # no warning about duplicate my $foo, -\& # but hey, you asked for it! -\& # no compile-time or run-time warnings before here -\& $DOWARN = 1; -.Ve -.Sp -.Vb 2 -\& # run-time warnings enabled after here -\& warn "\e$foo is alive and $foo!"; # does show up -.Ve -.Sp -See perlvar for details on setting \f(CW%SIG\fR entries, and for more -examples. See the Carp module for other kinds of warnings using its -\&\fIcarp()\fR and \fIcluck()\fR functions. -.IP "write \s-1FILEHANDLE\s0" 8 -.IX Xref "write" -.IX Item "write FILEHANDLE" -.PD 0 -.IP "write \s-1EXPR\s0" 8 -.IX Item "write EXPR" -.IP "write" 8 -.IX Item "write" -.PD -Writes a formatted record (possibly multi\-line) to the specified \s-1FILEHANDLE\s0, -using the format associated with that file. By default the format for -a file is the one having the same name as the filehandle, but the -format for the current output channel (see the \f(CW\*(C`select\*(C'\fR function) may be set -explicitly by assigning the name of the format to the \f(CW$~\fR variable. -.Sp -Top of form processing is handled automatically: if there is -insufficient room on the current page for the formatted record, the -page is advanced by writing a form feed, a special top-of-page format -is used to format the new page header, and then the record is written. -By default the top-of-page format is the name of the filehandle with -\&\*(L"_TOP\*(R" appended, but it may be dynamically set to the format of your -choice by assigning the name to the \f(CW$^\fR variable while the filehandle is -selected. The number of lines remaining on the current page is in -variable \f(CW\*(C`$\-\*(C'\fR, which can be set to \f(CW0\fR to force a new page. -.Sp -If \s-1FILEHANDLE\s0 is unspecified, output goes to the current default output -channel, which starts out as \s-1STDOUT\s0 but may be changed by the -\&\f(CW\*(C`select\*(C'\fR operator. If the \s-1FILEHANDLE\s0 is an \s-1EXPR\s0, then the expression -is evaluated and the resulting string is used to look up the name of -the \s-1FILEHANDLE\s0 at run time. For more on formats, see perlform. -.Sp -Note that write is \fInot\fR the opposite of \f(CW\*(C`read\*(C'\fR. Unfortunately. -.IP "y///" 8 -.IX Item "y///" -The transliteration operator. Same as \f(CW\*(C`tr///\*(C'\fR. See perlop. + diff --git a/tests/examplefiles/pleac.in.rb b/tests/examplefiles/pleac.in.rb index d74944ad..d1dea9f4 100644 --- a/tests/examplefiles/pleac.in.rb +++ b/tests/examplefiles/pleac.in.rb @@ -1221,1739 +1221,3 @@ def naive_shuffle(a) end -# @@PLEAC@@_4.18 -#!/usr/bin/env ruby -# example 4-2 words -# words - gather lines, present in colums - -# class to encapsulate the word formatting from the input -class WordFormatter - def initialize(cols) - @cols = cols - end - - # helper to return the length of the longest word in the wordlist - def maxlen(wordlist) - max = 1 - for word in wordlist - if word.length > max - max = word.length - end - end - max - end - - # process the wordlist and print it formmated into columns - def output(wordlist) - collen = maxlen(wordlist) + 1 - columns = @cols / collen - columns = 1 if columns == 0 - rows = (wordlist.length + columns - 1) / columns - # now process each item, picking out proper piece for this position - 0.upto(rows * columns - 1) { |item| - target = (item % columns) * rows + (item / columns) - eol = ((item+1) % columns == 0) - piece = wordlist[target] || "" - piece = piece.ljust(collen) unless eol - print piece - puts if eol - } - # no need to finish it up, because eol is always true for the last element - end -end - -# get nr of chars that fit in window or console, see PLEAC 15.4 -# not portable -- linux only (?) -def getWinCharWidth() - buf = "\0" * 8 - $stdout.ioctl(0x5413, buf) - ws_row, ws_col, ws_xpixel, ws_ypixel = buf.unpack("$4") - ws_col || 80 -rescue - 80 -end - -# main program -cols = getWinCharWidth() -formatter = WordFormatter.new(cols) -words = readlines() -words.collect! { |line| - line.chomp -} -formatter.output(words) - - -# @@PLEAC@@_4.19 -# In ruby, Fixnum's are automatically converted to Bignum's when -# needed, so there is no need for an extra module -def factorial(n) - s = 1 - while n > 0 - s *= n - n -= 1 - end - s -end - -puts factorial(500) - -#--------------------------------------------------------- -# Example 4-3. tsc-permute -# tsc_permute: permute each word of input -def permute(items, perms) - unless items.length > 0 - puts perms.join(" ") - else - for i in items - newitems = items.dup - newperms = perms.dup - newperms.unshift(newitems.delete(i)) - permute(newitems, newperms) - end - end -end -# In ruby the main program must be after all definitions it is using -permute(ARGV, []) - -#--------------------------------------------------------- -# mjd_permute: permute each word of input - -def factorial(n) - s = 1 - while n > 0 - s *= n - n -= 1 - end - s -end - -# we use a class with a class variable store the private cache -# for the results of the factorial function. -class Factorial - @@fact = [ 1 ] - def Factorial.compute(n) - if @@fact[n] - @@fact[n] - else - @@fact[n] = n * Factorial.compute(n - 1) - end - end -end - -#--------------------------------------------------------- -# Example 4-4- mjd-permute -# n2pat(n, len): produce the N-th pattern of length len - -# We must use a lower case letter as parameter N, otherwise it is -# handled as constant Length is the length of the resulting -# array, not the index of the last element (length -1) like in -# the perl example. -def n2pat(n, length) - pat = [] - i = 1 - while i <= length - pat.push(n % i) - n /= i - i += 1 - end - pat -end - -# pat2perm(pat): turn pattern returned by n2pat() into -# permutation of integers. -def pat2perm(pat) - source = (0 .. pat.length - 1).to_a - perm = [] - perm.push(source.slice!(pat.pop)) while pat.length > 0 - perm -end - -def n2perm(n, len) - pat2perm(n2pat(n,len)) -end - -# In ruby the main program must be after all definitions -while gets - data = split - # the perl solution has used $#data, which is length-1 - num_permutations = Factorial.compute(data.length()) - 0.upto(num_permutations - 1) do |i| - # in ruby we can not use an array as selector for an array - # but by exchanging the two arrays, we can use the collect method - # which returns an array with the result of all block invocations - permutation = n2perm(i, data.length).collect { - |j| data[j] - } - puts permutation.join(" ") - end -end - - -# @@PLEAC@@_5.0 -age = { "Nat", 24, - "Jules", 25, - "Josh", 17 } - -age["Nat"] = 24 -age["Jules"] = 25 -age["Josh"] = 17 - -food_color = { - "Apple" => "red", - "Banana" => "yellow", - "Lemon" => "yellow", - "Carrot" => "orange" - } - -# In Ruby, you cannot avoid the double or simple quoting -# while manipulatin hashes - - -# @@PLEAC@@_5.1 -hash[key] = value - -food_color["Raspberry"] = "pink" -puts "Known foods:", food_color.keys - - -# @@PLEAC@@_5.2 -# does hash have a value for key ? -if (hash.has_key?(key)) - # it exists -else - # it doesn't -end - -[ "Banana", "Martini" ].each { |name| - print name, " is a ", food_color.has_key?(name) ? "food" : "drink", "\n" -} - -age = {} -age['Toddler'] = 3 -age['Unborn'] = 0 -age['Phantasm'] = nil - -for thing in ['Toddler', 'Unborn', 'Phantasm', 'Relic'] - print "#{thing}: " - print "Has-key " if age.has_key?(thing) - print "True " if age[thing] - print "Nonzero " if age[thing] && age[thing].nonzero? - print "\n" -end - -#=> -# Toddler: Has-key True Nonzero -# Unborn: Has-key True -# Phantasm: Has-key -# Relic: - -# You use Hash#has_key? when you use Perl's exists -> it checks -# for existence of a key in a hash. -# All Numeric are "True" in ruby, so the test doesn't have the -# same semantics as in Perl; you would use Numeric#nonzero? to -# achieve the same semantics (false if 0, true otherwise). - - -# @@PLEAC@@_5.3 -food_color.delete("Banana") - - -# @@PLEAC@@_5.4 -hash.each { |key, value| - # do something with key and value -} - -hash.each_key { |key| - # do something with key -} - -food_color.each { |food, color| - puts "#{food} is #{color}" -} - -food_color.each_key { |food| - puts "#{food} is #{food_color[food]}" -} - -# IMO this demonstrates that OO style is by far more readable -food_color.keys.sort.each { |food| - puts "#{food} is #{food_color[food]}." -} - -#----------------------------- -#!/usr/bin/ruby -# countfrom - count number of messages from each sender - -# Default value is 0 -from = Hash.new(0) -while gets - /^From: (.*)/ and from[$1] += 1 -end - -# More useful to sort by number of received mail by person -from.sort {|a,b| b[1]<=>a[1]}.each { |v| - puts "#{v[1]}: #{v[0]}" -} -#----------------------------- - - -# @@PLEAC@@_5.5 -# You may use the built-in 'inspect' method this way: -p hash - -# Or do it the Cookbook way: -hash.each { |k,v| puts "#{k} => #{v}" } - -# Sorted by keys -hash.sort.each { |e| puts "#{e[0]} => #{e[1]}" } -# Sorted by values -hash.sort{|a,b| a[1]<=>b[1]}.each { |e| puts "#{e[0]} => #{e[1]}" } - - -# @@PLEAC@@_5.7 -ttys = Hash.new -for i in `who` - user, tty = i.split - (ttys[user] ||= []) << tty # see problems_ruby for more infos -end -ttys.keys.sort.each { |k| - puts "#{k}: #{commify_series(ttys[k])}" # from 4.2 -} - - -# @@PLEAC@@_5.8 -surname = { "Mickey" => "Mantle", "Babe" => "Ruth" } -puts surname.index("Mantle") - -# If you really needed to 'invert' the whole hash, use Hash#invert - -#----------------------------- -#!/usr/bin/ruby -w -# foodfind - find match for food or color - -given = ARGV.shift or raise "usage: foodfind food_or_color" - -color = { - "Apple" => "red", - "Banana" => "yellow", - "Lemon" => "yellow", - "Carrot" => "orange", -} - -if (color.has_key?(given)) - puts "#{given} is a food with color #{color[given]}." -end -if (color.has_value?(given)) - puts "#{color.index(given)} is a food with color #{given}." -end -#----------------------------- - - -# @@PLEAC@@_5.9 -# Sorted by keys (Hash#sort gives an Array of pairs made of each key,value) -food_color.sort.each { |f| - puts "#{f[0]} is #{f[1]}." -} - -# Sorted by values -food_color.sort { |a,b| a[1] <=> b[1] }.each { |f| - puts "#{f[0]} is #{f[1]}." -} - -# Sorted by length of values -food_color.sort { |a,b| a[1].length <=> b[1].length }.each { |f| - puts "#{f[0]} is #{f[1]}." -} - - -# @@PLEAC@@_5.10 -merged = a.clone.update(b) # because Hash#update changes object in place - -drink_color = { "Galliano" => "yellow", "Mai Tai" => "blue" } -ingested_color = drink_color.clone.update(food_color) - -substance_color = {} -for i in [ food_color, drink_color ] - i.each_key { |k| - if substance_color.has_key?(k) - puts "Warning: #{k} seen twice. Using the first definition." - next - end - substance_color[k] = 1 - } -end - - -# @@PLEAC@@_5.11 -common = hash1.keys & hash2.keys - -this_not_that = hash1.keys - hash2.keys - - -# @@PLEAC@@_5.12 -# no problem here, Ruby handles any kind of object for key-ing -# (it takes Object#hash, which defaults to Object#id) - - -# @@PLEAC@@_5.13 -# AFAIK, not possible in Ruby - - -# @@PLEAC@@_5.14 -# Be careful, the following is possible only because Fixnum objects are -# special (documentation says: there is effectively only one Fixnum object -# instance for any given integer value). -count = Hash.new(0) -array.each { |e| - count[e] += 1 -} - - -# @@PLEAC@@_5.15 -father = { - "Cain" , "Adam", - "Abel" , "Adam", - "Seth" , "Adam", - "Enoch" , "Cain", - "Irad" , "Enoch", - "Mehujael" , "Irad", - "Methusael" , "Mehujael", - "Lamech" , "Methusael", - "Jabal" , "Lamech", - "Jubal" , "Lamech", - "Tubalcain" , "Lamech", - "Enos" , "Seth", -} - -while gets - chomp - begin - print $_, " " - end while $_ = father[$_] - puts -end - -children = {} -father.each { |k,v| - (children[v] ||= []) << k -} -while gets - chomp - puts "#{$_} begat #{(children[$_] || ['Nobody']).join(', ')}.\n" -end - -includes = {} -files.each { |f| - begin - for l in IO.readlines(f) - next unless l =~ /^\s*#\s*include\s*<([^>]+)>/ - (includes[$1] ||= []) << f - end - rescue SystemCallError - $stderr.puts "#$! (skipping)" - end -} - -include_free = includes.values.flatten.uniq - includes.keys - - -# @@PLEAC@@_5.16 -# dutree - print sorted intented rendition of du output -#% dutree -#% dutree /usr -#% dutree -a -#% dutree -a /bin - -# The DuNode class collects all information about a directory, -# and provides some convenience methods -class DuNode - - attr_reader :name - attr_accessor :size - attr_accessor :kids - - def initialize(name) - @name = name - @kids = [] - @size = 0 - end - - # support for sorting nodes with side - def size_compare(node2) - @size <=> node2.size - end - - def basename - @name.sub(/.*\//, "") - end - - #returns substring before last "/", nil if not there - def parent - p = @name.sub(/\/[^\/]+$/,"") - if p == @name - nil - else - p - end - end - -end - -# The DuTree does the acdtual work of -# getting the input, parsing it, builging up a tree -# and format it for output -class Dutree - - attr_reader :topdir - - def initialize - @nodes = Hash.new - @dirsizes = Hash.new(0) - @kids = Hash.new([]) - end - - # get a node by name, create it if it does not exist yet - def get_create_node(name) - if @nodes.has_key?(name) - @nodes[name] - else - node = DuNode.new(name) - @nodes[name] = node - node - end - end - - # run du, read in input, save sizes and kids - # stores last directory read in instance variable topdir - def input(arguments) - name = "" - cmd = "du " + arguments.join(" ") - IO.popen(cmd) { |pipe| - pipe.each { |line| - size, name = line.chomp.split(/\s+/, 2) - node = get_create_node(name) - node.size = size.to_i - @nodes[name] = node - parent = node.parent - if parent - get_create_node(parent).kids.push(node) - end - } - } - @topdir = @nodes[name] - end - - # figure out how much is taken in each directory - # that isn't stored in the subdirectories. Add a new - # fake kid called "." containing that much. - def get_dots(node) - cursize = node.size - for kid in node.kids - cursize -= kid.size - get_dots(kid) - end - if node.size != cursize - newnode = get_create_node(node.name + "/.") - newnode.size = cursize - node.kids.push(newnode) - end - end - - # recursively output everything - # passing padding and number width as well - # on recursive calls - def output(node, prefix="", width=0) - line = sprintf("%#{width}d %s", node.size, node.basename) - puts(prefix + line) - prefix += line.sub(/\d /, "| ") - prefix.gsub!(/[^|]/, " ") - if node.kids.length > 0 # not a bachelor node - kids = node.kids - kids.sort! { |a,b| - b.size_compare(a) - } - width = kids[0].size.to_s.length - for kid in kids - output(kid, prefix, width) - end - end - end - -end - -tree = Dutree.new -tree.input(ARGV) -tree.get_dots(tree.topdir) -tree.output(tree.topdir) - - -# @@PLEAC@@_6.0 -# The verbose version are match, sub, gsub, sub! and gsub!; -# pattern needs to be a Regexp object; it yields a MatchData -# object. -pattern.match(string) -string.sub(pattern, replacement) -string.gsub(pattern, replacement) -# As usual in Ruby, sub! does the same as sub but also modifies -# the object, the same for gsub!/gsub. - -# Sugared syntax yields the position of the match (or nil if no -# match). Note that the object at the right of the operator needs -# not to be a Regexp object (it can be a String). The "dont -# match" operator yields true or false. -meadow =~ /sheep/ # position of the match, nil if no match -meadow !~ /sheep/ # true if doesn't match, false if it does -# There is no sugared version for the substitution - -meadow =~ /\bovines?\b/i and print "Here be sheep!" - -string = "good food" -string.sub!(/o*/, 'e') - -# % echo ababacaca | ruby -ne 'puts $& if /(a|ba|b)+(a|ac)+/' -# ababa - -# The "global" (or "multiple") match is handled by String#scan -scan (/(\d+)/) { - puts "Found number #{$1}" -} - -# String#scan yields an Array if not used with a block -numbers = scan(/\d+/) - -digits = "123456789" -nonlap = digits.scan(/(\d\d\d)/) -yeslap = digits.scan(/(?=(\d\d\d))/) -puts "Non-overlapping: #{nonlap.join(' ')}" -puts "Overlapping: #{yeslap.join(' ')}"; -# Non-overlapping: 123 456 789 -# Overlapping: 123 234 345 456 567 678 789 - -string = "And little lambs eat ivy" -string =~ /l[^s]*s/ -puts "(#$`) (#$&) (#$')" -# (And ) (little lambs) ( eat ivy) - - -# @@PLEAC@@_6.1 -# Ruby doesn't have the same problem: -dst = src.sub('this', 'that') - -progname = $0.sub('^.*/', '') - -bindirs = %w(/usr/bin /bin /usr/local/bin) -libdirs = bindirs.map { |l| l.sub('bin', 'lib') } - - -# @@PLEAC@@_6.3 -/\S+/ # as many non-whitespace bytes as possible -/[A-Za-z'-]+/ # as many letters, apostrophes, and hyphens - -/\b([A-Za-z]+)\b/ # usually best -/\s([A-Za-z]+)\s/ # fails at ends or w/ punctuation - - -# @@PLEAC@@_6.4 -require 'socket' -str = 'www.ruby-lang.org and www.rubygarden.org' -re = / - ( # capture the hostname in $1 - (?: # these parens for grouping only - (?! [-_] ) # lookahead for neither underscore nor dash - [\w-] + # hostname component - \. # and the domain dot - ) + # now repeat that whole thing a bunch of times - [A-Za-z] # next must be a letter - [\w-] + # now trailing domain part - ) # end of $1 capture - /x # /x for nice formatting - -str.gsub! re do # pass a block to execute replacement - host = TCPsocket.gethostbyname($1) - "#{$1} [#{host[3]}]" -end - -puts str -#----------------------------- -# to match whitespace or #-characters in an extended re you need to escape -# them. - -foo = 42 -str = 'blah #foo# blah' -str.gsub! %r/ # replace - \# # a pound sign - (\w+) # the variable name - \# # another pound sign - /x do - eval $1 # with the value of a local variable - end -puts str # => blah 42 blah - - -# @@PLEAC@@_6.5 -# The 'g' modifier doesn't exist in Ruby, a regexp can't be used -# directly in a while loop; instead, use String#scan { |match| .. } -fish = 'One fish two fish red fish blue fish' -WANT = 3 -count = 0 -fish.scan(/(\w+)\s+fish\b/i) { - if (count += 1) == WANT - puts "The third fish is a #{$1} one." - end -} - -if fish =~ /(?:\w+\s+fish\s+){2}(\w+)\s+fish/i - puts "The third fish is a #{$1} one." -end - -pond = 'One fish two fish red fish blue fish' -# String#scan without a block gives an array of matches, each match -# being an array of all the specified groups -colors = pond.scan(/(\w+)\s+fish\b/i).flatten # get all matches -color = colors[2] # then the one we want -# or without a temporary array -color = pond.scan(/(\w+)\s+fish\b/i).flatten[2] # just grab element 3 -puts "The third fish in the pond is #{color}." - -count = 0 -fishes = 'One fish two fish red fish blue fish' -evens = fishes.scan(/(\w+)\s+fish\b/i).select { (count+=1) % 2 == 0 } -print "Even numbered fish are #{evens.join(' ')}." - -count = 0 -fishes.gsub(/ - \b # makes next \w more efficient - ( \w+ ) # this is what we\'ll be changing - ( - \s+ fish \b - ) - /x) { - if (count += 1) == 4 - 'sushi' + $2 - else - $1 + $2 - end -} - -pond = 'One fish two fish red fish blue fish swim here.' -puts "Last fish is #{pond.scan(/\b(\w+)\s+fish\b/i).flatten[-1]}" - -/ - A # find some pattern A - (?! # mustn\'t be able to find - .* # something - A # and A - ) - $ # through the end of the string -/x - -# The "s" perl modifier is "m" in Ruby (not very nice since there is -# also an "m" in perl..) -pond = "One fish two fish red fish blue fish swim here." -if (pond =~ / - \b ( \w+) \s+ fish \b - (?! .* \b fish \b ) - /mix) - puts "Last fish is #{$1}." -else - puts "Failed!" -end - - -# @@PLEAC@@_6.6 -#----------------------------- -#!/usr/bin/ruby -w -# killtags - very bad html killer -$/ = nil; # each read is whole file -while file = gets() do - file.gsub!(/<.*?>/m,''); # strip tags (terribly) - puts file # print file to STDOUT -end -#----------------------------- -#!/usr/bin/ruby -w -#headerfy - change certain chapter headers to html -$/ = '' -while file = gets() do - pattern = / - \A # start of record - ( # capture in $1 - Chapter # text string - \s+ # mandatory whitespace - \d+ # decimal number - \s* # optional whitespace - : # a real colon - . * # anything not a newline till end of line - ) - /x - puts file.gsub(pattern,'<H1>\1</H1>') -end -#----------------------------- -#% ruby -00pe "gsub!(/\A(Chapter\s+\d+\s*:.*)/,'<H1>\1</H1>')" datafile - -#!/usr/bin/ruby -w -#----------------------------- -for file in ARGV - file = File.open(ARGV.shift) - while file.gets('') do # each read is a paragraph - print "chunk #{$.} in $ARGV has <<#{$1}>>\n" while /^START(.*?)^END/m - end # /m activates the multiline mode -end -#----------------------------- - -# @@PLEAC@@_6.7 -#----------------------------- -$/ = nil; -file = File.open("datafile") -chunks = file.gets.split(/pattern/) -#----------------------------- -# .Ch, .Se and .Ss divide chunks of STDIN -chunks = gets(nil).split(/^\.(Ch|Se|Ss)$/) -print "I read #{chunks.size} chunks.\n" -#----------------------------- - - -# @@PLEAC@@_6.8 -while gets - if ~/BEGIN/ .. ~/END/ - # line falls between BEGIN and END inclusive - end -end - -while gets - if ($. == firstnum) .. ($. == lastnum) - # operate between firstnum and lastnum line number - end -end - -# in ruby versions prior to 1.8, the above two conditional -# expressions could be shortened to: -# if /BEGIN/ .. /END/ -# and -# if firstnum .. lastnum -# but these now only work this way from the command line - -#----------------------------- - -while gets - if ~/BEGIN/ ... ~/END/ - # line falls between BEGIN and END on different lines - end -end - -while gets - if ($. == first) ... ($. == last) - # operate between first and last line number on different lines - end -end - -#----------------------------- -# command-line to print lines 15 through 17 inclusive (see below) -ruby -ne 'print if 15 .. 17' datafile - -# print out all <XMP> .. </XMP> displays from HTML doc -while gets - print if ~%r#<XMP>#i .. ~%r#</XMP>#i; -end - -# same, but as shell command -# ruby -ne 'print if %r#<XMP>#i .. %r#</XMP>#i' document.html -#----------------------------- -# ruby -ne 'BEGIN { $top=3; $bottom=5 }; \ -# print if $top .. $bottom' /etc/passwd # FAILS -# ruby -ne 'BEGIN { $top=3; $bottom=5 }; \ -# print if $. == $top .. $. == $bottom' /etc/passwd # works -# ruby -ne 'print if 3 .. 5' /etc/passwd # also works -#----------------------------- -print if ~/begin/ .. ~/end/; -print if ~/begin/ ... ~/end/; -#----------------------------- -while gets - $in_header = $. == 1 .. ~/^$/ ? true : false - $in_body = ~/^$/ .. ARGF.eof ? true : false -end -#----------------------------- -seen = {} -ARGF.each do |line| - next unless line =~ /^From:?\s/i .. line =~ /^$/; - line.scan(%r/([^<>(),;\s]+\@[^<>(),;\s]+)/).each do |addr| - puts addr unless seen[addr] - seen[addr] ||= 1 - end -end - - -# @@PLEAC@@_6.9 -def glob2pat(globstr) - patmap = { - '*' => '.*', - '?' => '.', - '[' => '[', - ']' => ']', - } - globstr.gsub!(/(.)/) { |c| patmap[c] || Regexp::escape(c) } - '^' + globstr + '$' -end - - -# @@PLEAC@@_6.10 -# avoid interpolating patterns like this if the pattern -# isn't going to change: -pattern = ARGV.shift -ARGF.each do |line| - print line if line =~ /#{pattern}/ -end - -# the above creates a new regex each iteration. Instead, -# use the /o modifier so the regex is compiled only once - -pattern = ARGV.shift -ARGF.each do |line| - print line if line =~ /#{pattern}/o -end - -#----------------------------- - -#!/usr/bin/ruby -# popgrep1 - grep for abbreviations of places that say "pop" -# version 1: slow but obvious way -popstates = %w(CO ON MI WI MN) -ARGF.each do |line| - popstates.each do |state| - if line =~ /\b#{state}\b/ - print line - last - end - end -end - -#----------------------------- -#!/usr/bin/ruby -# popgrep2 - grep for abbreviations of places that say "pop" -# version 2: eval strings; fast but hard to quote -popstates = %w(CO ON MI WI MN) -code = "ARGF.each do |line|\n" -popstates.each do |state| - code += "\tif line =~ /\\b#{state}\\b/; print(line); next; end\n" -end -code += "end\n" -print "CODE IS\n---\n#{code}\n---\n" if false # turn on for debugging -eval code - -# CODE IS -# --- -# ARGF.each do |line| -# if line =~ /\bCO\b/; print(line); next; end -# if line =~ /\bON\b/; print(line); next; end -# if line =~ /\bMI\b/; print(line); next; end -# if line =~ /\bWI\b/; print(line); next; end -# if line =~ /\bMN\b/; print(line); next; end -# end -# -# --- - -## alternatively, the same idea as above but compiling -## to a case statement: (not in perlcookbook) -#!/usr/bin/ruby -w -# popgrep2.5 - grep for abbreviations of places that say "pop" -# version 2.5: eval strings; fast but hard to quote -popstates = %w(CO ON MI WI MN) -code = "ARGF.each do |line|\n case line\n" -popstates.each do |state| - code += " when /\\b#{state}\\b/ : print line\n" -end -code += " end\nend\n" -print "CODE IS\n---\n#{code}\n---\n" if false # turn on for debugging -eval code - -# CODE IS -# --- -# ARGF.each do |line| -# case line -# when /\bCO\b/ : print line -# when /\bON\b/ : print line -# when /\bMI\b/ : print line -# when /\bWI\b/ : print line -# when /\bMN\b/ : print line -# end -# end -# -# --- - -# Note: (above) Ruby 1.8+ allows the 'when EXP : EXPR' on one line -# with the colon separator. - -#----------------------------- -#!/usr/bin/ruby -# popgrep3 - grep for abbreviations of places that say "pop" -# version3: build a match_any function -popstates = %w(CO ON MI WI MN) -expr = popstates.map{|e|"line =~ /\\b#{e}\\b/"}.join('||') -eval "def match_any(line); #{expr};end" -ARGF.each do |line| - print line if match_any(line) -end -#----------------------------- - -## building a match_all function is a trivial -## substitution of && for || -## here is a generalized example: -#!/usr/bin/ruby -w -## grepauth - print lines that mention both foo and bar -class MultiMatch - def initialize(*patterns) - _any = build_match('||',patterns) - _all = build_match('&&',patterns) - eval "def match_any(line);#{_any};end\n" - eval "def match_all(line);#{_all};end\n" - end - def build_match(sym,args) - args.map{|e|"line =~ /#{e}/"}.join(sym) - end -end - -mm = MultiMatch.new('foo','bar') -ARGF.each do |line| - print line if mm.match_all(line) -end -#----------------------------- - -#!/usr/bin/ruby -# popgrep4 - grep for abbreviations of places that say "pop" -# version4: pretty fast, but simple: compile all re's first: -popstates = %w(CO ON MI WI MN) -popstates = popstates.map{|re| %r/\b#{re}\b/} -ARGF.each do |line| - popstates.each do |state_re| - if line =~ state_re - print line - break - end - end -end - -## speeds trials on the jargon file(412): 26006 lines, 1.3MB -## popgrep1 => 7.040s -## popgrep2 => 0.656s -## popgrep2.5 => 0.633s -## popgrep3 => 0.675s -## popgrep4 => 1.027s - -# unless speed is criticial, the technique in popgrep4 is a -# reasonable balance between speed and logical simplicity. - - -# @@PLEAC@@_6.11 -begin - print "Pattern? " - pat = $stdin.gets.chomp - Regexp.new(pat) -rescue - warn "Invalid Pattern" - retry -end - - -# @@PLEAC@@_6.13 -# uses the 'amatch' extension found on: -# http://raa.ruby-lang.org/project/amatch/ -require 'amatch' -matcher = Amatch.new('balast') -#$relative, $distance = 0, 1 -File.open('/usr/share/dict/words').each_line do |line| - print line if matcher.search(line) <= 1 -end -__END__ -#CODE -ballast -ballasts -balustrade -balustrades -blast -blasted -blaster -blasters -blasting -blasts - - -# @@PLEAC@@_6.14 -str.scan(/\G(\d)/).each do |token| - puts "found #{token}" -end -#----------------------------- -n = " 49 here" -n.gsub!(/\G /,'0') -puts n -#----------------------------- -str = "3,4,5,9,120" -str.scan(/\G,?(\d+)/).each do |num| - puts "Found number: #{num}" -end -#----------------------------- -# Ruby doesn't have the String.pos or a /c re modifier like Perl -# But it does have StringScanner in the standard library (strscn) -# which allows similar functionality: - -require 'strscan' -text = 'the year 1752 lost 10 days on the 3rd of September' -sc = StringScanner.new(text) -while sc.scan(/.*?(\d+)/) - print "found: #{sc[1]}\n" -end -if sc.scan(/\S+/) - puts "Found #{sc[0]} after last number" -end -#----------------------------- -# assuming continuing from above: -puts "The position in 'text' is: #{sc.pos}" -sc.pos = 30 -puts "The position in 'text' is: #{sc.pos}" - - -# @@PLEAC@@_6.15 -#----------------------------- -# greedy pattern -str.gsub!(/<.*>/m,'') # not good - -# non-greedy (minimal) pattern -str.gsub!(/<.*?>/m,'') # not great - - -#----------------------------- -#<b><i>this</i> and <i>that</i> are important</b> Oh, <b><i>me too!</i></b> -#----------------------------- -%r{ <b><i>(.*?)</i></b> }mx -#----------------------------- -%r/BEGIN((?:(?!BEGIN).)*)END/ -#----------------------------- -%r{ <b><i>( (?: (?!</b>|</i>). )* ) </i></b> }mx -#----------------------------- -%r{ <b><i>( (?: (?!</[ib]>). )* ) </i></b> }mx -#----------------------------- -%r{ - <b><i> - [^<]* # stuff not possibly bad, and not possibly the end. - (?: - # at this point, we can have '<' if not part of something bad - (?! </?[ib]> ) # what we can't have - < # okay, so match the '<' - [^<]* # and continue with more safe stuff - ) * - </i></b> - }mx - - -# @@PLEAC@@_6.16 -#----------------------------- -$/ = "" -ARGF.each do |para| - para.scan %r/ - \b # start at word boundary - (\S+) # find chunk of non-whitespace - \b # until a word boundary - ( - \s+ # followed by whitespace - \1 # and that same chunk again - \b # and a word boundary - ) + # one or more times - /xi do - puts "dup word '#{$1}' at paragraph #{$.}" - end -end -#----------------------------- -astr = 'nobody' -bstr = 'bodysnatcher' -if "#{astr} #{bstr}" =~ /^(\w+)(\w+) \2(\w+)$/ - print "#{$2} overlaps in #{$1}-#{$2}-#{$3}" -end -#----------------------------- -#!/usr/bin/ruby -w -# prime_pattern -- find prime factors of argument using patterns -ARGV << 180 -cap = 'o' * ARGV.shift -while cap =~ /^(oo+?)\1+$/ - print $1.size, " " - cap.gsub!(/#{$1}/,'o') -end -puts cap.size -#----------------------------- -#diophantine -# solve for 12x + 15y + 16z = 281, maximizing x -if ('o' * 281).match(/^(o*)\1{11}(o*)\2{14}(o*)\3{15}$/) - x, y, z = $1.size, $2.size, $3.size - puts "One solution is: x=#{x}; y=#{y}; z=#{z}" -else - puts "No solution." -end -# => One solution is: x=17; y=3; z=2 - -#----------------------------- -# using different quantifiers: -('o' * 281).match(/^(o+)\1{11}(o+)\2{14}(o+)\3{15}$/) -# => One solution is: x=17; y=3; z=2 - -('o' * 281).match(/^(o*?)\1{11}(o*)\2{14}(o*)\3{15}$/) -# => One solution is: x=0; y=7; z=11 - -('o' * 281).match(/^(o+?)\1{11}(o*)\2{14}(o*)\3{15}$/) -# => One solution is: x=1; y=3; z=14 - - -# @@PLEAC@@_6.17 -# alpha OR beta -%r/alpha|beta/ - -# alpha AND beta -%r/(?=.*alpha)(?=.*beta)/m - -# alpha AND beta, no overlap -%r/alpha.*beta|beta.*alpha/m - -# NOT beta -%r/^(?:(?!beta).)*$/m - -# NOT bad BUT good -%r/(?=(?:(?!BAD).)*$)GOOD/m -#----------------------------- - -if !(string =~ /pattern/) # ugly - something() -end - -if string !~ /pattern/ # preferred - something() -end - - -#----------------------------- -if string =~ /pat1/ && string =~ /pat2/ - something() -end -#----------------------------- -if string =~ /pat1/ || string =~ /pat2/ - something() -end -#----------------------------- -#!/usr/bin/ruby -w -# minigrep - trivial grep -pat = ARGV.shift -ARGF.each do |line| - print line if line =~ /#{pat}/o -end -#----------------------------- - "labelled" =~ /^(?=.*bell)(?=.*lab)/m -#----------------------------- -$string =~ /bell/ && $string =~ /lab/ -#----------------------------- -$murray_hill = "blah bell blah " -if $murray_hill =~ %r{ - ^ # start of string - (?= # zero-width lookahead - .* # any amount of intervening stuff - bell # the desired bell string - ) # rewind, since we were only looking - (?= # and do the same thing - .* # any amount of intervening stuff - lab # and the lab part - ) - }mx # /m means . can match newline - - print "Looks like Bell Labs might be in Murray Hill!\n"; -end -#----------------------------- -"labelled" =~ /(?:^.*bell.*lab)|(?:^.*lab.*bell)/ -#----------------------------- -$brand = "labelled"; -if $brand =~ %r{ - (?: # non-capturing grouper - ^ .*? # any amount of stuff at the front - bell # look for a bell - .*? # followed by any amount of anything - lab # look for a lab - ) # end grouper - | # otherwise, try the other direction - (?: # non-capturing grouper - ^ .*? # any amount of stuff at the front - lab # look for a lab - .*? # followed by any amount of anything - bell # followed by a bell - ) # end grouper - }mx # /m means . can match newline - print "Our brand has bell and lab separate.\n"; -end -#----------------------------- -$map =~ /^(?:(?!waldo).)*$/s -#----------------------------- -$map = "the great baldo" -if $map =~ %r{ - ^ # start of string - (?: # non-capturing grouper - (?! # look ahead negation - waldo # is he ahead of us now? - ) # is so, the negation failed - . # any character (cuzza /s) - ) * # repeat that grouping 0 or more - $ # through the end of the string - }mx # /m means . can match newline - print "There's no waldo here!\n"; -end -=begin - 7:15am up 206 days, 13:30, 4 users, load average: 1.04, 1.07, 1.04 - -USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT - -tchrist tty1 5:16pm 36days 24:43 0.03s xinit - -tchrist tty2 5:19pm 6days 0.43s 0.43s -tcsh - -tchrist ttyp0 chthon 7:58am 3days 23.44s 0.44s -tcsh - -gnat ttyS4 coprolith 2:01pm 13:36m 0.30s 0.30s -tcsh -=end -#% w | minigrep '^(?!.*ttyp).*tchrist' -#----------------------------- -%r{ - ^ # anchored to the start - (?! # zero-width look-ahead assertion - .* # any amount of anything (faster than .*?) - ttyp # the string you don't want to find - ) # end look-ahead negation; rewind to start - .* # any amount of anything (faster than .*?) - tchrist # now try to find Tom -}x -#----------------------------- -#% w | grep tchrist | grep -v ttyp -#----------------------------- -#% grep -i 'pattern' files -#% minigrep '(?i)pattern' files -#----------------------------- - - -# @@PLEAC@@_6.20 -ans = $stdin.gets.chomp -re = %r/^#{Regexp.quote(ans)}/ -case - when "SEND" =~ re : puts "Action is send" - when "STOP" =~ re : puts "Action is stop" - when "ABORT" =~ re : puts "Action is abort" - when "EDIT" =~ re : puts "Action is edit" -end -#----------------------------- -require 'abbrev' -table = Abbrev.abbrev %w-send stop abort edit- -loop do - print "Action: " - ans = $stdin.gets.chomp - puts "Action for #{ans} is #{table[ans.downcase]}" -end - - -#----------------------------- -# dummy values are defined for 'file', 'PAGER', and -# the 'invoke_editor' and 'deliver_message' methods -# do not do anything interesting in this example. -#!/usr/bin/ruby -w -require 'abbrev' - -file = 'pleac_ruby.data' -PAGER = 'less' - -def invoke_editor - puts "invoking editor" -end - -def deliver_message - puts "delivering message" -end - -actions = { - 'edit' => self.method(:invoke_editor), - 'send' => self.method(:deliver_message), - 'list' => proc {system(PAGER, file)}, - 'abort' => proc {puts "See ya!"; exit}, - "" => proc {puts "Unknown Command"} -} - -dtable = Abbrev.abbrev(actions.keys) -loop do - print "Action: " - ans = $stdin.gets.chomp.delete(" \t") - actions[ dtable[ans.downcase] || "" ].call -end - - -# @@PLEAC@@_6.19 -#----------------------------- -# basically, the Perl Cookbook categorizes this as an -# unsolvable problem ... -#----------------------------- -1 while addr.gsub!(/\([^()]*\)/,'') -#----------------------------- -Dear someuser@host.com, - -Please confirm the mail address you gave us Wed May 6 09:38:41 -MDT 1998 by replying to this message. Include the string -"Rumpelstiltskin" in that reply, but spelled in reverse; that is, -start with "Nik...". Once this is done, your confirmed address will -be entered into our records. - - -# @@PLEAC@@_6.21 -#----------------------------- -#% gunzip -c ~/mail/archive.gz | urlify > archive.urlified -#----------------------------- -#% urlify ~/mail/*.inbox > ~/allmail.urlified -#----------------------------- -#!/usr/bin/ruby -w -# urlify - wrap HTML links around URL-like constructs - -urls = '(https?|telnet|gopher|file|wais|ftp)'; -ltrs = '\w'; -gunk = '/#~:.?+=&%@!\-'; -punc = '.:?\-'; -any = "#{ltrs}#{gunk}#{punc}"; - -ARGF.each do |line| - line.gsub! %r/ - \b # start at word boundary - ( # begin $1 { - #{urls} : # need resource and a colon - [#{any}] +? # followed by on or more - # of any valid character, but - # be conservative and take only - # what you need to.... - ) # end $1 } - (?= # look-ahead non-consumptive assertion - [#{punc}]* # either 0 or more punctuation - [^#{any}] # followed by a non-url char - | # or else - $ # then end of the string - ) - /iox do - %Q|<A HREF="#{$1}">#{$1}</A>| - end - print line -end - - -# @@PLEAC@@_6.23 -%r/^m*(d?c{0,3}|c[dm])(l?x{0,3}|x[lc])(v?i{0,3}|i[vx])$/i -#----------------------------- -str.sub!(/(\S+)(\s+)(\S+)/, '\3\2\1') -#----------------------------- -%r/(\w+)\s*=\s*(.*)\s*$/ # keyword is $1, value is $2 -#----------------------------- -%r/.{80,}/ -#----------------------------- -%r|(\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+)| -#----------------------------- -str.gsub!(%r|/usr/bin|,'/usr/local/bin') -#----------------------------- -str.gsub!(/%([0-9A-Fa-f][0-9A-Fa-f])/){ $1.hex.chr } -#----------------------------- -str.gsub!(%r{ - /\* # Match the opening delimiter - .*? # Match a minimal number of characters - \*/ # Match the closing delimiter -}xm,'') -#----------------------------- -str.sub!(/^\s+/, '') -str.sub!(/\s+$/, '') - -# but really, in Ruby we'd just do: -str.strip! -#----------------------------- -str.gsub!(/\\n/,"\n") -#----------------------------- -str.sub!(/^.*::/, '') -#----------------------------- -%r/^([01]?\d\d|2[0-4]\d|25[0-5])\.([01]?\d\d|2[0-4]\d|25[0-5])\. - ([01]?\d\d|2[0-4]\d|25[0-5])\.([01]?\d\d|2[0-4]\d|25[0-5])$/x -#----------------------------- -str.sub!(%r|^.*/|, '') -#----------------------------- -cols = ( (ENV['TERMCAP'] || " ") =~ /:co#(\d+):/ ) ? $1 : 80; -#----------------------------- -name = " #{$0} #{ARGV}".gsub(%r| /\S+/|, ' ') -#----------------------------- -require 'rbconfig' -include Config -raise "This isn't Linux" unless CONFIG['target_os'] =~ /linux/i; -#----------------------------- -str.gsub!(%r/\n\s+/, ' ') -#----------------------------- -nums = str.scan(/(\d+\.?\d*|\.\d+)/) -#----------------------------- -capwords = str.scan(%r/(\b[^\Wa-z0-9_]+\b)/) -#----------------------------- -lowords = str.scan(%r/(\b[^\WA-Z0-9_]+\b)/) -#----------------------------- -icwords = str.scan(%r/(\b[^\Wa-z0-9_][^\WA-Z0-9_]*\b)/) -#----------------------------- -links = str.scan(%r/<A[^>]+?HREF\s*=\s*["']?([^'" >]+?)[ '"]?>/mi) -#----------------------------- -initial = str =~ /^\S+\s+(\S)\S*\s+\S/ ? $1 : "" -#----------------------------- -str.gsub!(%r/"([^"]*)"/, %q-``\1''-) -#----------------------------- - -$/ = "" -sentences = [] -ARGF.each do |para| - para.gsub!(/\n/, ' ') - para.gsub!(/ {3,}/,' ') - sentences << para.scan(/(\S.*?[!?.])(?= |\Z)/) -end - -#----------------------------- -%r/(\d{4})-(\d\d)-(\d\d)/ # YYYY in $1, MM in $2, DD in $3 -#----------------------------- -%r/ ^ - (?: - 1 \s (?: \d\d\d \s)? # 1, or 1 and area code - | # ... or ... - \(\d\d\d\) \s # area code with parens - | # ... or ... - (?: \+\d\d?\d? \s)? # optional +country code - \d\d\d ([\s\-]) # and area code - ) - \d\d\d (\s|\1) # prefix (and area code separator) - \d\d\d\d # exchange - $ - /x -#----------------------------- -%r/\boh\s+my\s+gh?o(d(dess(es)?|s?)|odness|sh)\b/i -#----------------------------- -lines = [] -lines << $1 while input.sub!(/^([^\012\015]*)(\012\015?|\015\012?)/,'') - - -# @@PLEAC@@_7.0 -# An IO object being Enumerable, we can use 'each' directly on it -File.open("/usr/local/widgets/data").each { |line| - puts line if line =~ /blue/ -} - -logfile = File.new("/var/log/rubylog.txt", "w") -mysub($stdin, logfile) - -# The method IO#readline is similar to IO#gets -# but throws an exception when it reaches EOF -f = File.new("bla.txt") -begin - while (line = f.readline) - line.chomp - $stdout.print line if line =~ /blue/ - end -rescue EOFError - f.close -end - -while $stdin.gets # reads from STDIN - unless (/\d/) - $stderr.puts "No digit found." # writes to STDERR - end - puts "Read: #{$_}" # writes to STDOUT -end - -logfile = File.new("/tmp/log", "w") - -logfile.close - -# $defout (or its synonym '$>') is the destination of output -# for Kernel#print, Kernel#puts, and family functions -logfile = File.new("log.txt", "w") -old = $defout -$defout = logfile # switch to logfile for output -puts "Countdown initiated ..." -$defout = old # return to original output -puts "You have 30 seconds to reach minimum safety distance." - - -# @@PLEAC@@_7.1 -source = File.new(path, "r") # open file "path" for reading only -sink = File.new(path, "w") # open file "path" for writing only - -source = File.open(path, File::RDONLY) # open file "path" for reading only -sink = File.open(path, File::WRONLY) # open file "path" for writing only - -file = File.open(path, "r+") # open "path" for reading and writing -file = File.open(path, flags) # open "path" with the flags "flags" (see examples below for flags) - -# open file "path" read only -file = File.open(path, "r") -file = File.open(path, File::RDONLY) - -# open file "path" write only, create it if it does not exist -# truncate it to zero length if it exists -file = File.open(path, "w") -file = File.open(path, File::WRONLY|File::TRUNC|File::CREAT) -file = File.open(path, File::WRONLY|File::TRUNC|File::CREAT, 0666) # with permission 0666 - -# open file "path" write only, fails if file exists -file = File.open(path, File::WRONLY|File::EXCL|File::CREAT) -file = File.open(path, File::WRONLY|File::EXCL|File::CREAT, 0666) - -# open file "path" for appending -file = File.open(path, "a") -file = File.open(path, File::WRONLY|File::APPEND|File::CREAT) -file = File.open(path, File::WRONLY|File::APPEND|File::CREAT, 0666) - -# open file "path" for appending only when file exists -file = File.open(path, File::WRONLY|File::APPEND) - -# open file "path" for reading and writing -file = File.open(path, "r+") -file = File.open(path, File::RDWR) - -# open file for reading and writing, create a new file if it does not exist -file = File.open(path, File::RDWR|File::CREAT) -file = File.open(path, File::RDWR|File::CREAT, 0600) - -# open file "path" reading and writing, fails if file exists -file = File.open(path, File::RDWR|File::EXCL|File::CREAT) -file = File.open(path, File::RDWR|File::EXCL|File::CREAT, 0600) - - -# @@PLEAC@@_7.2 -# No problem with Ruby since the filename doesn't contain characters with -# special meaning; like Perl's sysopen -File.open(filename, 'r') - - -# @@PLEAC@@_7.3 -File.expand_path('~root/tmp') -#=> "/root/tmp" -File.expand_path('~rpcuser') -#=> "/var/lib/nfs" - -# To expand ~/.. it explicitely needs the environment variable HOME -File.expand_path('~/tmp') -#=> "/home/gc/tmp" - - -# @@PLEAC@@_7.4 -# The exception raised in Ruby reports the filename -File.open('afile') - - -# @@PLEAC@@_7.5 -# Standard Ruby distribution provides the following useful extension -require 'tempfile' -# With the Tempfile class, the file is automatically deleted on garbage -# collection, so you won't need to remove it, later on. -tf = Tempfile.new('tmp') # a name is required to create the filename - -# If you need to pass the filename to an external program you can use -# File#path, but don't forget to File#flush in order to flush anything -# living in some buffer somewhere. -tf.flush -system("/usr/bin/dowhatever #{tf.path}") - -fh = Tempfile.new('tmp') -fh.sync = true # autoflushes -10.times { |i| fh.puts i } -fh.rewind -puts 'Tmp file has: ', fh.readlines - - -# @@PLEAC@@_7.6 -while (DATA.gets) do - # process the line -end -__END__ -# your data goes here -# __DATA__ doesn't exist in Ruby - -#CODE -# get info about the script (size, date of last modification) -kilosize = DATA.stat.size / 1024 -last_modif = DATA.stat.mtime -puts "<P>Script size is #{kilosize}" -puts "<P>Last script update: #{last_modif}" -__END__ -# DO NOT REMOVE THE PRECEEDING LINE. -# Everything else in this file will be ignored. -#CODE - - -# @@PLEAC@@_7.7 -while line = gets do - # do something with line. -end - -# or -while gets do - # do something with $_ -end - -# or more rubyish -$stdin.each do |line| - # do stuff with line -end - - -# ARGF may makes this more easy -# this is skipped if ARGV.size==0 -ARGV.each do |filename| - # closing and exception handling are done by the block - open(filename) do |fd| - fd.each do |line| - # do stuff with line - end - end rescue abort("can't open %s" % filename) -end - -# globbing is done in the Dir module -ARGV = Dir["*.[Cch]"] if ARGV.empty? - -# note: optparse is the preferred way to handle this -if (ARGV[0] == '-c') - chop_first += 1 - ARGV.shift -end - - -# processing numerical options -if ARGV[0] =~ /^-(\d+)$/ - columns = $1 - ARGV.shift -end - -# again, better to use optparse: -require 'optparse' -nostdout = 0 -append = 0 -unbuffer = 0 -ignore_ints = 0 -ARGV.options do |opt| - opt.on('-n') { nostdout +=1 } - opt.on('-a') { append +=1 } - opt.on('-u') { unbuffer +=1 } - opt.on('-i') { ignore_ints +=1 } - opt.parse! -end or abort("usage: " + __FILE__ + " [-ainu] [filenames]") - -# no need to do undef $/, we have File.read -str = File.read(ARGV[0]) - -# again we have File.read -str = File.read(ARGV[0]) - -# not sure what this should do: -# I believe open the file, print filename, lineno and line: -ARGF.each_with_index do |line, idx| - print ARGF.filename, ":", idx, ";", line -end - -# print all the lines in every file passed via command line that contains login -ARGF.each do |line| - puts line if line =~ /login/ -end -# -# even this would fit -#%ruby -ne "print if /f/" 2.log -# - -ARGF.each { |l| puts l.downcase! } - diff --git a/tests/examplefiles/test.html b/tests/examplefiles/test.html index 72cba437..ea723232 100644 --- a/tests/examplefiles/test.html +++ b/tests/examplefiles/test.html @@ -1119,1671 +1119,3 @@ pre.syntax { padding: 5px; margin-top: 0px; } <span class="kw">else</span>: <span class="kw">raise</span> <span class="name">PocooRuntimeError</span>(<span class="st st-sg">'</span><span class="st">req.cache_control invalid</span><span class="st st-sg">'</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.captcha - ~~~~~~~~~~~~~~~~~~~~~~ - - Captcha URL Handler. - - Displays a random captcha picture (debugging only). - - :copyright: 2006-2007 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.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">class </span><span class="cls">CaptchaImage</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">!captcha$</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">from </span><span class="cls">pocoo.utils.captcha</span><span class="kw"> import</span> <span class="name">Captcha</span> - - <span class="name">c</span> <span class="op">=</span> <span class="name">Captcha</span>() - <span class="name">response</span> <span class="op">=</span> <span class="name">Response</span>(<span class="name">c</span>.<span class="name">generate_image</span>()) - <span class="name">response</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">response</span> -<span class="cm"># -*- coding: utf-8 -*-</span> -<span class="st st-db">"""</span><span class="st"> - pocoo.pkg.core.cobalt - ~~~~~~~~~~~~~~~~~~~~~ - - Provides static content serving like mozilla's chrome:// scheme. - - :copyright: 2006-2007 by Armin Ronacher, Georg Brandl. - :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">import </span><span class="cls">time</span> - -<span class="kw">from </span><span class="cls">mimetypes</span><span class="kw"> import</span> <span class="name">guess_type</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">CobaltMiddleware</span>(<span class="bn">object</span>): - <span class="st st-db">"""</span><span class="st"> - - The Cobalt middleware serves static files. - </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">app</span>, <span class="name">ctx</span>): - <span class="bn bn-pseudo">self</span>.<span class="name">app</span> <span class="op">=</span> <span class="name">app</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">cache_enabled</span> <span class="op">=</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">cache</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">static_cache</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">if</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">self</span>.<span class="name">cache_enabled</span> <span class="op op-word">or</span> <span class="st st-sg">'</span><span class="st">cobalt/stylesheet_imports</span><span class="st st-sg">'</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">ctx</span>.<span class="name">_cache</span>: - <span class="name">handled</span> <span class="op">=</span> <span class="name">set</span>() - <span class="name">lines</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">FileRequirements</span>): - <span class="kw">for</span> <span class="name">name</span> <span class="op op-word">in</span> <span class="name">comp</span>.<span class="name">get_stylesheet_imports</span>(): - <span class="name">item</span> <span class="op">=</span> (<span class="name">comp</span>.<span class="name">package</span>, <span class="name">name</span>) - <span class="kw">if</span> <span class="name">item</span> <span class="op op-word">in</span> <span class="name">handled</span>: - <span class="kw">continue</span> - - <span class="name">handled</span>.<span class="name">add</span>(<span class="name">item</span>) - <span class="name">url</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">!cobalt/</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">item</span> - - <span class="name">lines</span>.<span class="name">append</span>(<span class="st st-sg">'</span><span class="st">@import url(</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">str</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">make_url</span>(<span class="name">url</span>))) - <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">_cache</span>[<span class="st st-sg">'</span><span class="st">cobalt/stylesheet_imports</span><span class="st st-sg">'</span>] <span class="op">=</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">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">_cache</span>[<span class="st st-sg">'</span><span class="st">cobalt/stylesheet_imports</span><span class="st st-sg">'</span>] - - <span class="kw">def </span><span class="fun">get_javascript_imports</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">if</span> <span class="op op-word">not</span> <span class="bn bn-pseudo">self</span>.<span class="name">cache_enabled</span> <span class="op op-word">or</span> <span class="st st-sg">'</span><span class="st">cobalt/javascript_imports</span><span class="st st-sg">'</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">ctx</span>.<span class="name">_cache</span>: - <span class="name">handled</span> <span class="op">=</span> <span class="name">set</span>() - <span class="name">lines</span> <span class="op">=</span> [] - <span class="name">onload</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">FileRequirements</span>): - <span class="kw">for</span> <span class="name">name</span> <span class="op op-word">in</span> <span class="name">comp</span>.<span class="name">get_javascript_imports</span>(): - <span class="name">item</span> <span class="op">=</span> (<span class="name">comp</span>.<span class="name">package</span>, <span class="name">name</span>) - <span class="kw">if</span> <span class="name">item</span> <span class="op op-word">in</span> <span class="name">handled</span>: - <span class="kw">continue</span> - - <span class="name">handled</span>.<span class="name">add</span>(<span class="name">item</span>) - <span class="name">imp</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">pkgmanager</span>.<span class="name">importers</span>[<span class="name">comp</span>.<span class="name">package</span>] - <span class="name">lines</span>.<span class="name">append</span>(<span class="name">imp</span>.<span class="name">get_data</span>(<span class="name">os</span>.<span class="name">path</span>.<span class="name">join</span>(<span class="st st-sg">'</span><span class="st">static</span><span class="st st-sg">'</span>, <span class="name">name</span>))) - <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">_cache</span>[<span class="st st-sg">'</span><span class="st">cobalt/javascript_imports</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="st st-sg">'</span><span class="st st-esc">\n\n</span><span class="st st-sg">'</span>.<span class="name">join</span>(<span class="name">lines</span>) - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">_cache</span>[<span class="st st-sg">'</span><span class="st">cobalt/javascript_imports</span><span class="st st-sg">'</span>] - - <span class="kw">def </span><span class="fun">__call__</span>(<span class="bn bn-pseudo">self</span>, <span class="name">environ</span>, <span class="name">start_response</span>): - <span class="name">path</span> <span class="op">=</span> <span class="name">environ</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">PATH_INFO</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="kw">if</span> <span class="name">path</span>.<span class="name">startswith</span>(<span class="st st-sg">'</span><span class="st">/!cobalt/</span><span class="st st-sg">'</span>): - <span class="name">mime_type</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="kw">try</span>: - <span class="name">pkgname</span>, <span class="name">fname</span> <span class="op">=</span> <span class="name">path</span>[<span class="nb nb-int">9</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="kw">if</span> <span class="name">pkgname</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">_import_</span><span class="st st-sg">'</span>: - <span class="kw">if</span> <span class="name">fname</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">styles.css</span><span class="st st-sg">'</span>: - <span class="name">mime_type</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">text/css</span><span class="st st-sg">'</span> - - <span class="name">content</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">get_stylesheet_imports</span>() - <span class="kw">elif</span> <span class="name">fname</span> <span class="op">==</span> <span class="st st-sg">'</span><span class="st">script.js</span><span class="st st-sg">'</span>: - <span class="name">mime_type</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">application/x-javascript</span><span class="st st-sg">'</span> - - <span class="name">content</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">get_javascript_imports</span>() - <span class="kw">else</span>: - <span class="name">guessed_type</span> <span class="op">=</span> <span class="name">guess_type</span>(<span class="name">fname</span>) - <span class="name">mime_type</span> <span class="op">=</span> <span class="name">guessed_type</span>[<span class="nb nb-int">0</span>] <span class="op op-word">or</span> <span class="st st-sg">'</span><span class="st">text/plain</span><span class="st st-sg">'</span> - - <span class="name">imp</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>.<span class="name">pkgmanager</span>.<span class="name">importers</span>[<span class="name">pkgname</span>] - <span class="name">content</span> <span class="op">=</span> <span class="name">imp</span>.<span class="name">get_data</span>(<span class="name">os</span>.<span class="name">path</span>.<span class="name">join</span>(<span class="st st-sg">'</span><span class="st">static</span><span class="st st-sg">'</span>, <span class="name">fname</span>)) - <span class="kw">if</span> <span class="name">mime_type</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">expiry</span> <span class="op">=</span> <span class="name">time</span>.<span class="name">time</span>() <span class="op">+</span> <span class="nb nb-int">3600</span> <span class="cm"># cache for one hour</span> - - <span class="name">expiry</span> <span class="op">=</span> <span class="name">time</span>.<span class="name">asctime</span>(<span class="name">time</span>.<span class="name">gmtime</span>(<span class="name">expiry</span>)) - <span class="name">headers</span> <span class="op">=</span> [(<span class="st st-sg">'</span><span class="st">Content-Type</span><span class="st st-sg">'</span>, <span class="name">mime_type</span>), - (<span class="st st-sg">'</span><span class="st">Cache-Control</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">public</span><span class="st st-sg">'</span>), - (<span class="st st-sg">'</span><span class="st">Expires</span><span class="st st-sg">'</span>, <span class="name">expiry</span>)] - <span class="name">start_response</span>(<span class="st st-sg">'</span><span class="st">200 OK</span><span class="st st-sg">'</span>, <span class="name">headers</span>) - <span class="kw">if</span> <span class="name">environ</span>.<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">REQUEST_METHOD</span><span class="st st-sg">'</span>, <span class="st st-sg">'</span><span class="st">GET</span><span class="st st-sg">'</span>) <span class="op">==</span> <span class="st st-sg">'</span><span class="st">HEAD</span><span class="st st-sg">'</span>: - <span class="kw">return</span> [] - <span class="kw">else</span>: - <span class="kw">return</span> [<span class="name">content</span>] - <span class="kw">except</span> (<span class="exc">ValueError</span>, <span class="exc">KeyError</span>, <span class="exc">IOError</span>): - <span class="cm"># XXX: output custom error message?</span> - - <span class="kw">pass</span> - <span class="kw">return</span> <span class="bn bn-pseudo">self</span>.<span class="name">app</span>(<span class="name">environ</span>, <span class="name">start_response</span>) -<span class="cm"># -*- coding: utf-8 -*-</span> -<span class="st st-db">"""</span><span class="st"> - - pocoo.pkg.core.db - ~~~~~~~~~~~~~~~~~ - - Pocoo core database definition. - - :copyright: 2006-2007 by Armin Ronacher, 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.db</span><span class="kw"> import</span> <span class="name">meta</span>, <span class="name">DatabaseObserver</span> - - -<span class="name">ANONYMOUS_USER_ID</span> <span class="op">=</span> <span class="op">-</span><span class="nb nb-int">1</span> - -<span class="name">DEFAULT_USER_ID</span> <span class="op">=</span> <span class="nb nb-int">0</span> - - -<span class="name">sessions</span> <span class="op">=</span> <span class="name">meta</span>.<span class="name">Table</span>(<span class="st st-sg">'</span><span class="st">core_sessions</span><span class="st st-sg">'</span>, - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">session_key</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Unicode</span>(<span class="nb nb-int">40</span>), <span class="name">primary_key</span><span class="op">=</span><span class="bn bn-pseudo">True</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">ip_addr</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Unicode</span>(<span class="nb nb-int">15</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">expires</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">DateTime</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">last_reload</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">DateTime</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">data</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Pickled</span>(<span class="bn">dict</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">action</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Unicode</span>), -) - - -<span class="name">users</span> <span class="op">=</span> <span class="name">meta</span>.<span class="name">Table</span>(<span class="st st-sg">'</span><span class="st">core_users</span><span class="st st-sg">'</span>, - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">user_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, <span class="name">primary_key</span><span class="op">=</span><span class="bn bn-pseudo">True</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">subject_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, - <span class="name">meta</span>.<span class="name">ForeignKey</span>(<span class="st st-sg">'</span><span class="st">core_acl_subjects.subject_id</span><span class="st st-sg">'</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Unicode</span>(<span class="nb nb-int">40</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">email</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Unicode</span>(<span class="nb nb-int">250</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">pwhash</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Unicode</span>(<span class="nb nb-int">60</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">act_key</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Unicode</span>(<span class="nb nb-int">8</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">language</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Unicode</span>(<span class="nb nb-int">2</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">profile</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Pickled</span>(<span class="bn">dict</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">settings</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Pickled</span>(<span class="bn">dict</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">last_login</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">DateTime</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">register_date</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">DateTime</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">post_count</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">read_threads</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Binary</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">read_posts</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Binary</span>), -) - - -<span class="name">groups</span> <span class="op">=</span> <span class="name">meta</span>.<span class="name">Table</span>(<span class="st st-sg">'</span><span class="st">core_groups</span><span class="st st-sg">'</span>, - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">group_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, <span class="name">primary_key</span><span class="op">=</span><span class="bn bn-pseudo">True</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">subject_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, - <span class="name">meta</span>.<span class="name">ForeignKey</span>(<span class="st st-sg">'</span><span class="st">core_acl_subjects.subject_id</span><span class="st st-sg">'</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">name</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Unicode</span>(<span class="nb nb-int">40</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">public</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Boolean</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">hidden</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Boolean</span>) -) - - -<span class="name">group_members</span> <span class="op">=</span> <span class="name">meta</span>.<span class="name">Table</span>(<span class="st st-sg">'</span><span class="st">core_group_members</span><span class="st st-sg">'</span>, - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">user_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, - <span class="name">meta</span>.<span class="name">ForeignKey</span>(<span class="st st-sg">'</span><span class="st">core_users.user_id</span><span class="st st-sg">'</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">group_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, - <span class="name">meta</span>.<span class="name">ForeignKey</span>(<span class="st st-sg">'</span><span class="st">core_groups.group_id</span><span class="st st-sg">'</span>)) -) - - -<span class="name">forums</span> <span class="op">=</span> <span class="name">meta</span>.<span class="name">Table</span>(<span class="st st-sg">'</span><span class="st">core_forums</span><span class="st st-sg">'</span>, - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, <span class="name">primary_key</span><span class="op">=</span><span class="bn bn-pseudo">True</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">parent_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, - <span class="name">meta</span>.<span class="name">ForeignKey</span>(<span class="st st-sg">'</span><span class="st">core_forums.forum_id</span><span class="st st-sg">'</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">object_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, - <span class="name">meta</span>.<span class="name">ForeignKey</span>(<span class="st st-sg">'</span><span class="st">core_acl_objects.object_id</span><span class="st st-sg">'</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">name</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Unicode</span>(<span class="nb nb-int">100</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">description</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Unicode</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">position</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">link</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Unicode</span>(<span class="nb nb-int">100</span>)), - <span class="cm">#XXX: foreign key doesn't work</span> - - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">last_post_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">post_count</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">thread_count</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>) -) - - -<span class="name">posts</span> <span class="op">=</span> <span class="name">meta</span>.<span class="name">Table</span>(<span class="st st-sg">'</span><span class="st">core_posts</span><span class="st st-sg">'</span>, - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, <span class="name">primary_key</span><span class="op">=</span><span class="bn bn-pseudo">True</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, - <span class="name">meta</span>.<span class="name">ForeignKey</span>(<span class="st st-sg">'</span><span class="st">core_forums.forum_id</span><span class="st st-sg">'</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">parent_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, - <span class="name">meta</span>.<span class="name">ForeignKey</span>(<span class="st st-sg">'</span><span class="st">core_posts.post_id</span><span class="st st-sg">'</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">root_post_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, - <span class="name">meta</span>.<span class="name">ForeignKey</span>(<span class="st st-sg">'</span><span class="st">core_posts.post_id</span><span class="st st-sg">'</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">object_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, - <span class="name">meta</span>.<span class="name">ForeignKey</span>(<span class="st st-sg">'</span><span class="st">core_acl_objects.object_id</span><span class="st st-sg">'</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">post_count</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">view_count</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">author_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, - <span class="name">meta</span>.<span class="name">ForeignKey</span>(<span class="st st-sg">'</span><span class="st">core_users.user_id</span><span class="st st-sg">'</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Unicode</span>(<span class="nb nb-int">200</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Unicode</span>(<span class="nb nb-int">200</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">text</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Unicode</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">timestamp</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">DateTime</span>) -) - - -<span class="name">privileges</span> <span class="op">=</span> <span class="name">meta</span>.<span class="name">Table</span>(<span class="st st-sg">'</span><span class="st">core_privileges</span><span class="st st-sg">'</span>, - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">priv_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, <span class="name">primary_key</span><span class="op">=</span><span class="bn bn-pseudo">True</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">name</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Unicode</span>(<span class="nb nb-int">100</span>)) -) - - -<span class="name">acl_mapping</span> <span class="op">=</span> <span class="name">meta</span>.<span class="name">Table</span>(<span class="st st-sg">'</span><span class="st">core_acl_mapping</span><span class="st st-sg">'</span>, - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">priv_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, - <span class="name">meta</span>.<span class="name">ForeignKey</span>(<span class="st st-sg">'</span><span class="st">core_privileges.priv_id</span><span class="st st-sg">'</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">subject_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, - <span class="name">meta</span>.<span class="name">ForeignKey</span>(<span class="st st-sg">'</span><span class="st">core_acl_subjects.subject_id</span><span class="st st-sg">'</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">object_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, - <span class="name">meta</span>.<span class="name">ForeignKey</span>(<span class="st st-sg">'</span><span class="st">core_acl_objects.object_id</span><span class="st st-sg">'</span>)), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">state</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>) -) - - -<span class="name">acl_subjects</span> <span class="op">=</span> <span class="name">meta</span>.<span class="name">Table</span>(<span class="st st-sg">'</span><span class="st">core_acl_subjects</span><span class="st st-sg">'</span>, - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">subject_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, <span class="name">primary_key</span><span class="op">=</span><span class="bn bn-pseudo">True</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">subject_type</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">String</span>(<span class="nb nb-int">10</span>)) -) - - -<span class="name">acl_objects</span> <span class="op">=</span> <span class="name">meta</span>.<span class="name">Table</span>(<span class="st st-sg">'</span><span class="st">core_acl_objects</span><span class="st st-sg">'</span>, - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">object_id</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">Integer</span>, <span class="name">primary_key</span><span class="op">=</span><span class="bn bn-pseudo">True</span>), - <span class="name">meta</span>.<span class="name">Column</span>(<span class="st st-sg">'</span><span class="st">object_type</span><span class="st st-sg">'</span>, <span class="name">meta</span>.<span class="name">String</span>(<span class="nb nb-int">10</span>)) -) - - -<span class="name">acl_subject_join</span> <span class="op">=</span> <span class="name">meta</span>.<span class="name">polymorphic_union</span>({ - <span class="st st-sg">'</span><span class="st">user</span><span class="st st-sg">'</span>: <span class="name">users</span>, - <span class="st st-sg">'</span><span class="st">group</span><span class="st st-sg">'</span>: <span class="name">groups</span> -}, <span class="st st-sg">'</span><span class="st">subject_type</span><span class="st st-sg">'</span>) - - -<span class="name">acl_object_join</span> <span class="op">=</span> <span class="name">meta</span>.<span class="name">polymorphic_union</span>({ - <span class="st st-sg">'</span><span class="st">forum</span><span class="st st-sg">'</span>: <span class="name">forums</span>, - <span class="st st-sg">'</span><span class="st">post</span><span class="st st-sg">'</span>: <span class="name">posts</span> -}, <span class="st st-sg">'</span><span class="st">object_type</span><span class="st st-sg">'</span>) - - -<span class="kw">class </span><span class="cls">CoreTableObserver</span>(<span class="name">DatabaseObserver</span>): - - <span class="kw">def </span><span class="fun">after_table_creation</span>(<span class="bn bn-pseudo">self</span>, <span class="name">table</span>): - <span class="kw">if</span> <span class="name">table</span> <span class="op op-word">is</span> <span class="name">users</span>: - <span class="name">e</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">e</span>(<span class="name">users</span>.<span class="name">insert</span>(), <span class="name">user_id</span><span class="op">=</span><span class="name">ANONYMOUS_USER_ID</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="name">e</span>(<span class="name">users</span>.<span class="name">insert</span>(), <span class="name">user_id</span><span class="op">=</span><span class="name">DEFAULT_USER_ID</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="cm"># -*- coding: utf-8 -*-</span> -<span class="st st-db">"""</span><span class="st"> - pocoo.pkg.core.feeds - ~~~~~~~~~~~~~~~~~~~~ - - Provides RSS Feeds. - - :copyright: 2006-2007 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.http</span><span class="kw"> import</span> <span class="name">PageNotFound</span>, <span class="name">Response</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.db</span><span class="kw"> import</span> <span class="name">meta</span> -<span class="kw">from </span><span class="cls">pocoo.utils.feed</span><span class="kw"> import</span> <span class="name">Feed</span> - -<span class="kw">from </span><span class="cls">pocoo.pkg.core.db</span><span class="kw"> import</span> <span class="name">forums</span>, <span class="name">posts</span>, <span class="name">users</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="kw">class </span><span class="cls">FeedProvider</span>(<span class="name">Component</span>): - <span class="cm">#: identifier for this feed. must be lowercase</span> - <span class="name">identifier</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">unknown</span><span class="st st-sg">'</span> - - <span class="kw">def </span><span class="fun">get_feed</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">parameter</span>): - <span class="st st-db">"""</span><span class="st"> - Return a dict in the following form:: - - {'title': 'Title of this feed', - 'description': 'Description of this feed', - 'items': [{ - 'title': 'title of this item', - 'link': 'relative link of this item', - 'author': 'author of this item', - 'description': 'description of this item', - 'pub_date': 'date of this item' - - }]} - - Can raise a `FeedNotFound` exception. - </span><span class="st st-db">"""</span> - - <span class="deco">@property</span> - <span class="kw">def </span><span class="fun">url</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</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/</span><span class="st st-int">%s</span><span class="st">.xml</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="bn bn-pseudo">self</span>.<span class="name">identifier</span>) - - - -<span class="kw">class </span><span class="cls">FeedNotFound</span>(<span class="exc">Exception</span>): - <span class="kw">pass</span> - - -<span class="kw">class </span><span class="cls">ThreadFeed</span>(<span class="name">FeedProvider</span>): - <span class="name">identifier</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">thread</span><span class="st st-sg">'</span> - - <span class="kw">def </span><span class="fun">get_feed</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">post_id</span>): - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - - <span class="kw">try</span>: - <span class="name">post_id</span> <span class="op">=</span> <span class="bn">int</span>(<span class="name">post_id</span>) - <span class="kw">except</span>: - <span class="kw">raise</span> <span class="name">FeedNotFound</span>() - <span class="name">row</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">posts</span>.<span class="name">c</span>.<span class="name">root_post_id</span>], - (<span class="name">posts</span>.<span class="name">c</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="name">post_id</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">raise</span> <span class="name">FeedNotFound</span>() - <span class="name">root_post_id</span> <span class="op">=</span> <span class="name">row</span>[<span class="nb nb-int">0</span>] - <span class="cm"># select data</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">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">title</span>, <span class="name">posts</span>.<span class="name">c</span>.<span class="name">text</span>, - <span class="name">posts</span>.<span class="name">c</span>.<span class="name">timestamp</span>, <span class="name">users</span>.<span class="name">c</span>.<span class="name">username</span>], - (<span class="name">posts</span>.<span class="name">c</span>.<span class="name">root_post_id</span> <span class="op">==</span> <span class="name">root_post_id</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">posts</span>.<span class="name">c</span>.<span class="name">author_id</span>), - <span class="name">order_by</span><span class="op">=</span>[<span class="name">meta</span>.<span class="name">desc</span>(<span class="name">posts</span>.<span class="name">c</span>.<span class="name">post_id</span>)], - <span class="name">limit</span><span class="op">=</span><span class="nb nb-int">10</span> - - )) - <span class="kw">return</span> { - <span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span>: <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Last Posts in Thread </span><span class="st st-int">%d</span><span class="st st-sg">'</span>) <span class="op">%</span> <span class="name">root_post_id</span>, - <span class="st st-sg">'</span><span class="st">description</span><span class="st st-sg">'</span>: <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">The last 10 posts in Thread </span><span class="st st-int">%d</span><span class="st st-sg">'</span>) <span class="op">%</span> <span class="name">root_post_id</span>, - <span class="st st-sg">'</span><span class="st">items</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">post</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">link</span><span class="st st-sg">'</span>: <span class="st st-sg">'</span><span class="st">post/</span><span class="st st-int">%d</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">post</span>[<span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>], - <span class="st st-sg">'</span><span class="st">description</span><span class="st st-sg">'</span>: <span class="name">parse_and_render</span>(<span class="name">req</span>, <span class="name">post</span>[<span class="st st-sg">'</span><span class="st">text</span><span class="st st-sg">'</span>]), - <span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</span>: <span class="name">post</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">pub_date</span><span class="st st-sg">'</span>: <span class="name">post</span>[<span class="st st-sg">'</span><span class="st">timestamp</span><span class="st st-sg">'</span>] - } <span class="kw">for</span> <span class="name">post</span> <span class="op op-word">in</span> <span class="name">result</span>] - } - - - -<span class="kw">class </span><span class="cls">ForumFeed</span>(<span class="name">FeedProvider</span>): - <span class="name">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_feed</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">forum_id</span>): - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</span> - - <span class="kw">try</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">except</span>: - <span class="kw">raise</span> <span class="name">FeedNotFound</span>() - <span class="kw">if</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">forums</span>.<span class="name">c</span>.<span class="name">forum_id</span>], - (<span class="name">forums</span>.<span class="name">c</span>.<span class="name">forum_id</span> <span class="op">==</span> <span class="name">forum_id</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="name">FeedNotFound</span>() - <span class="cm"># select data</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">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">title</span>, <span class="name">posts</span>.<span class="name">c</span>.<span class="name">text</span>, - <span class="name">posts</span>.<span class="name">c</span>.<span class="name">timestamp</span>, <span class="name">users</span>.<span class="name">c</span>.<span class="name">username</span>], - (<span class="name">posts</span>.<span class="name">c</span>.<span class="name">forum_id</span> <span class="op">==</span> <span class="name">forum_id</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">posts</span>.<span class="name">c</span>.<span class="name">author_id</span>), - <span class="name">order_by</span><span class="op">=</span>[<span class="name">meta</span>.<span class="name">desc</span>(<span class="name">posts</span>.<span class="name">c</span>.<span class="name">post_id</span>)], - <span class="name">limit</span><span class="op">=</span><span class="nb nb-int">10</span> - - )) - <span class="kw">return</span> { - <span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span>: <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Last Posts in Forum </span><span class="st st-int">%d</span><span class="st st-sg">'</span>) <span class="op">%</span> <span class="name">forum_id</span>, - <span class="st st-sg">'</span><span class="st">description</span><span class="st st-sg">'</span>: <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">The last 10 posts of forum </span><span class="st st-int">%d</span><span class="st st-sg">'</span>) <span class="op">%</span> <span class="name">forum_id</span>, - <span class="st st-sg">'</span><span class="st">items</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">post</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">link</span><span class="st st-sg">'</span>: <span class="st st-sg">'</span><span class="st">post/</span><span class="st st-int">%d</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">post</span>[<span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>], - <span class="st st-sg">'</span><span class="st">description</span><span class="st st-sg">'</span>: <span class="name">parse_and_render</span>(<span class="name">req</span>, <span class="name">post</span>[<span class="st st-sg">'</span><span class="st">text</span><span class="st st-sg">'</span>]), - <span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</span>: <span class="name">post</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">pub_date</span><span class="st st-sg">'</span>: <span class="name">post</span>[<span class="st st-sg">'</span><span class="st">timestamp</span><span class="st st-sg">'</span>] - } <span class="kw">for</span> <span class="name">post</span> <span class="op op-word">in</span> <span class="name">result</span>] - } - - - -<span class="kw">class </span><span class="cls">RecentChangesFeed</span>(<span class="name">FeedProvider</span>): - <span class="name">identifier</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">recent</span><span class="st st-sg">'</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="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">Recent Changes</span><span class="st st-sg">'</span>) - - <span class="kw">def </span><span class="fun">get_description</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">The recent posts</span><span class="st st-sg">'</span>) - - <span class="kw">def </span><span class="fun">get_feed</span>(<span class="bn bn-pseudo">self</span>, <span class="name">req</span>, <span class="name">parameter</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">parameter</span>: - <span class="kw">raise</span> <span class="name">FeedNotFound</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">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">title</span>, <span class="name">posts</span>.<span class="name">c</span>.<span class="name">text</span>, - <span class="name">posts</span>.<span class="name">c</span>.<span class="name">timestamp</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">posts</span>.<span class="name">c</span>.<span class="name">author_id</span>), - <span class="name">order_by</span><span class="op">=</span>[<span class="name">meta</span>.<span class="name">desc</span>(<span class="name">posts</span>.<span class="name">c</span>.<span class="name">post_id</span>)], - <span class="name">limit</span><span class="op">=</span><span class="nb nb-int">10</span> - - )) - <span class="kw">return</span> { - <span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span>: <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Recent Changes</span><span class="st st-sg">'</span>), - <span class="st st-sg">'</span><span class="st">description</span><span class="st st-sg">'</span>: <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">The most recent posts</span><span class="st st-sg">'</span>), - <span class="st st-sg">'</span><span class="st">items</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">post</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">link</span><span class="st st-sg">'</span>: <span class="st st-sg">'</span><span class="st">post/</span><span class="st st-int">%d</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">post</span>[<span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>], - <span class="st st-sg">'</span><span class="st">description</span><span class="st st-sg">'</span>: <span class="name">parse_and_render</span>(<span class="name">req</span>, <span class="name">post</span>[<span class="st st-sg">'</span><span class="st">text</span><span class="st st-sg">'</span>]), - <span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</span>: <span class="name">post</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">pub_date</span><span class="st st-sg">'</span>: <span class="name">post</span>[<span class="st st-sg">'</span><span class="st">timestamp</span><span class="st st-sg">'</span>] - } <span class="kw">for</span> <span class="name">post</span> <span class="op op-word">in</span> <span class="name">result</span>] - } - - - -<span class="kw">class </span><span class="cls">FeedDisplay</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">^feeds/(?P<feed>[a-z0-9_-]+)\.xml$</span><span class="st st-sg">'</span>, - <span class="st st-sg">r'</span><span class="st">^feeds/(?P<feed>[a-z0-9_-]+)/(?P<parameter>.+)\.xml$</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">feed</span>, <span class="name">parameter</span><span class="op">=</span><span class="bn bn-pseudo">None</span>): - <span class="kw">for</span> <span class="name">feed_provider</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">FeedProvider</span>): - <span class="kw">if</span> <span class="name">feed_provider</span>.<span class="name">identifier</span> <span class="op">==</span> <span class="name">feed</span>: - <span class="name">data</span> <span class="op">=</span> <span class="name">feed_provider</span>.<span class="name">get_feed</span>(<span class="name">req</span>, <span class="name">parameter</span>) - <span class="name">feed</span> <span class="op">=</span> <span class="name">Feed</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, <span class="name">data</span>[<span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span>], - <span class="name">data</span>[<span class="st st-sg">'</span><span class="st">description</span><span class="st st-sg">'</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="kw">try</span>: - <span class="kw">for</span> <span class="name">item</span> <span class="op op-word">in</span> <span class="name">data</span>[<span class="st st-sg">'</span><span class="st">items</span><span class="st st-sg">'</span>]: - <span class="name">feed</span>.<span class="name">add_item</span>(<span class="op">**</span><span class="name">item</span>) - <span class="kw">except</span> <span class="name">FeedNotFound</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">feed</span>.<span class="name">generate</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">text/xml</span><span class="st st-sg">'</span> - - <span class="kw">return</span> <span class="name">resp</span> - <span class="kw">return</span> <span class="name">PageNotFound</span>() -<span class="cm"># -*- coding: utf-8 -*-</span> -<span class="st st-db">"""</span><span class="st"> - pocoo.pkg.core.forum - ~~~~~~~~~~~~~~~~~~~~ - - Forum Utilities. - - :copyright: 2006-2007 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">datetime</span><span class="kw"> import</span> <span class="name">datetime</span> - -<span class="kw">from </span><span class="cls">math</span><span class="kw"> import</span> <span class="name">ceil</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.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.pkg.core.user</span><span class="kw"> import</span> <span class="name">User</span> -<span class="kw">from </span><span class="cls">pocoo.pkg.core.db</span><span class="kw"> import</span> <span class="name">forums</span>, <span class="name">posts</span>, <span class="name">users</span>, <span class="name">ANONYMOUS_USER_ID</span> - -<span class="kw">from </span><span class="cls">pocoo.pkg.core.template</span><span class="kw"> import</span> <span class="name">Pagination</span>, <span class="name">LazyPagination</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">quote_text</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.iterators</span><span class="kw"> import</span> <span class="name">inciter</span> - -<span class="cm"># for default arguments in Thread</span> - -<span class="name">_missing</span> <span class="op">=</span> <span class="bn">object</span>() - - -<span class="kw">class </span><span class="cls">PostProcessor</span>(<span class="name">Component</span>): - <span class="st st-db">"""</span><span class="st"> - Process a posting before it is stored in the database. - </span><span class="st st-db">"""</span> - - <span class="kw">def </span><span class="fun">process_post</span>(<span class="bn bn-pseudo">self</span>, <span class="name">text</span>, <span class="name">title</span>, <span class="name">reason</span>): - <span class="st st-db">"""</span><span class="st"> - - Process a posting. - - :param text: Text of the posting, possibly changed by - another PostProcessor. - :param title: The subject of the posting - :param reason: Can be ``'new'`` or ``'edit'``. - - :returns: - * ``True``: store the posting as-is, or - * ``False``: refuse to store the posting, or - * a string: use as the new posting text, or - * a tuple: (text, title) for the posting - </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">apply_post_processors</span>(<span class="name">ctx</span>, <span class="name">text</span>, <span class="name">title</span>, <span class="name">reason</span>): - <span class="st st-db">"""</span><span class="st"> - - Apply all `PostProcessor` components to the posting. - - Return (``text``, ``title``) tuple. - </span><span class="st st-db">"""</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">PostProcessor</span>): - <span class="name">rv</span> <span class="op">=</span> <span class="name">comp</span>.<span class="name">process_post</span>(<span class="name">text</span>, <span class="name">title</span>, <span class="st st-sg">'</span><span class="st">new</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">rv</span>: - <span class="kw">raise</span> <span class="exc">ValueError</span>(<span class="st st-sg">'</span><span class="st">creation of posting denied</span><span class="st st-sg">'</span>) - <span class="kw">elif</span> <span class="bn">isinstance</span>(<span class="name">rv</span>, <span class="bn">basestring</span>): - <span class="name">text</span> <span class="op">=</span> <span class="bn">unicode</span>(<span class="name">rv</span>) - <span class="kw">elif</span> <span class="bn">isinstance</span>(<span class="name">rv</span>, <span class="bn">tuple</span>): - <span class="name">text</span> <span class="op">=</span> <span class="bn">unicode</span>(<span class="name">rv</span>[<span class="nb nb-int">0</span>]) - <span class="name">title</span> <span class="op">=</span> <span class="bn">unicode</span>(<span class="name">rv</span>[<span class="nb nb-int">1</span>]) - <span class="kw">return</span> <span class="name">text</span>, <span class="name">title</span> - - -<span class="kw">def </span><span class="fun">get_forum_index</span>(<span class="name">req</span>): - <span class="st st-db">"""</span><span class="st"> - Return a list of dicts with forum information so that - the template can use it. - - If the request object has an identified user object attached - the returned dict will include status information. (read, - unread) - </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">f</span> <span class="op">=</span> <span class="name">forums</span>.<span class="name">c</span> - <span class="name">p</span> <span class="op">=</span> <span class="name">posts</span>.<span class="name">c</span> - - <span class="name">u</span> <span class="op">=</span> <span class="name">users</span>.<span class="name">c</span> - <span class="name">columns</span> <span class="op">=</span> [<span class="name">f</span>.<span class="name">forum_id</span>, <span class="name">f</span>.<span class="name">description</span>, <span class="name">f</span>.<span class="name">name</span>, <span class="name">f</span>.<span class="name">link</span>, <span class="name">f</span>.<span class="name">post_count</span>, - <span class="name">f</span>.<span class="name">thread_count</span>] - - <span class="name">categories</span> <span class="op">=</span> [] - <span class="kw">def </span><span class="fun">do</span>(<span class="name">con</span>): - <span class="kw">for</span> <span class="name">category</span> <span class="op op-word">in</span> <span class="name">con</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>(<span class="name">columns</span>, - <span class="name">f</span>.<span class="name">parent_id</span> <span class="op">==</span> <span class="bn bn-pseudo">None</span>)): - <span class="name">category</span> <span class="op">=</span> <span class="bn">dict</span>(<span class="name">category</span>) - <span class="name">category</span>[<span class="st st-sg">'</span><span class="st">is_external_link</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="bn">bool</span>(<span class="name">category</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">link</span><span class="st st-sg">'</span>)) - <span class="name">category</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">forum</span><span class="st st-sg">'</span>, <span class="name">category</span>[<span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>]) - <span class="name">forums</span> <span class="op">=</span> [] - <span class="kw">for</span> <span class="name">forum</span> <span class="op op-word">in</span> <span class="name">con</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>(<span class="name">columns</span> <span class="op">+</span> [<span class="name">f</span>.<span class="name">last_post_id</span>], - <span class="name">f</span>.<span class="name">parent_id</span> <span class="op">==</span> <span class="name">category</span>[<span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>])): - <span class="name">forum</span> <span class="op">=</span> <span class="bn">dict</span>(<span class="name">forum</span>) - <span class="name">forum</span>[<span class="st st-sg">'</span><span class="st">is_external_link</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="bn">bool</span>(<span class="name">forum</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">link</span><span class="st st-sg">'</span>)) - <span class="name">forum</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">forum</span><span class="st st-sg">'</span>, <span class="name">forum</span>[<span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>]) - <span class="cm"># get last post</span> - - <span class="name">last_post_id</span> <span class="op">=</span> <span class="name">forum</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">last_post_id</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="name">last_post_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">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">u</span>.<span class="name">user_id</span>, <span class="name">u</span>.<span class="name">username</span>, - <span class="name">p</span>.<span class="name">post_id</span>, <span class="name">p</span>.<span class="name">title</span>, - <span class="name">p</span>.<span class="name">timestamp</span>, - <span class="name">p</span>.<span class="name">username</span>.<span class="name">label</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>)], - (<span class="name">p</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="name">last_post_id</span>) <span class="op">&</span> - - (<span class="name">p</span>.<span class="name">post_id</span> <span class="op">!=</span> <span class="bn bn-pseudo">None</span>) <span class="op">&</span> - (<span class="name">u</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">p</span>.<span class="name">author_id</span>) - )) - <span class="name">last_post</span> <span class="op">=</span> <span class="bn">dict</span>(<span class="name">result</span>.<span class="name">fetchone</span>()) - <span class="name">username</span> <span class="op">=</span> <span class="name">urlencode</span>(<span class="name">last_post</span>[<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>]) - <span class="name">last_post</span>[<span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</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">last_post</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">registered</span><span class="st st-sg">'</span>: <span class="name">last_post</span>.<span class="name">pop</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">0</span>, - <span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>: <span class="name">last_post</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>) <span class="op op-word">or</span>\ - <span class="name">last_post</span>.<span class="name">pop</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">username</span>) - } - <span class="name">last_post</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">post</span><span class="st st-sg">'</span>, <span class="name">last_post</span>[<span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>]) - <span class="kw">else</span>: - <span class="name">last_post</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="name">forum</span>[<span class="st st-sg">'</span><span class="st">last_post</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">last_post</span> - <span class="name">subforums</span> <span class="op">=</span> [] - <span class="kw">for</span> <span class="name">sf</span> <span class="op op-word">in</span> <span class="name">con</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>([<span class="name">f</span>.<span class="name">forum_id</span>, <span class="name">f</span>.<span class="name">name</span>, <span class="name">f</span>.<span class="name">link</span>], - <span class="name">f</span>.<span class="name">parent_id</span> <span class="op">==</span> <span class="name">forum</span>[<span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>])): - <span class="name">sf</span> <span class="op">=</span> <span class="bn">dict</span>(<span class="name">sf</span>) - <span class="name">sf</span>[<span class="st st-sg">'</span><span class="st">is_external_url</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="bn">bool</span>(<span class="name">sf</span>[<span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>]) - <span class="name">sf</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">forum</span><span class="st st-sg">'</span>, <span class="name">sf</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>)) - <span class="name">subforums</span>.<span class="name">append</span>(<span class="name">sf</span>) - <span class="name">forum</span>[<span class="st st-sg">'</span><span class="st">subforums</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">subforums</span> - - <span class="name">forums</span>.<span class="name">append</span>(<span class="name">forum</span>) - <span class="name">category</span>[<span class="st st-sg">'</span><span class="st">forums</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">forums</span> - <span class="name">categories</span>.<span class="name">append</span>(<span class="name">category</span>) - <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">transaction</span>(<span class="name">do</span>) - <span class="kw">return</span> <span class="name">categories</span> - - -<span class="kw">def </span><span class="fun">get_forum</span>(<span class="name">req</span>, <span class="name">forum_id</span>, <span class="name">page</span><span class="op">=</span><span class="nb nb-int">1</span>): - <span class="st st-db">"""</span><span class="st"> - Return a list of dicts so that the template can use it. - - Return ``None`` if the forum does not exist. - </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">f</span> <span class="op">=</span> <span class="name">forums</span>.<span class="name">c</span> - - <span class="name">p</span> <span class="op">=</span> <span class="name">posts</span>.<span class="name">c</span> - <span class="name">u</span> <span class="op">=</span> <span class="name">users</span>.<span class="name">c</span> - - <span class="name">columns</span> <span class="op">=</span> [<span class="name">f</span>.<span class="name">forum_id</span>, <span class="name">f</span>.<span class="name">description</span>, <span class="name">f</span>.<span class="name">name</span>, <span class="name">f</span>.<span class="name">link</span>, <span class="name">f</span>.<span class="name">post_count</span>, - <span class="name">f</span>.<span class="name">thread_count</span>] - <span class="name">forum_columns</span> <span class="op">=</span> [<span class="name">f</span>.<span class="name">forum_id</span>, <span class="name">f</span>.<span class="name">name</span>, <span class="name">f</span>.<span class="name">description</span>, <span class="name">f</span>.<span class="name">link</span>, - <span class="name">f</span>.<span class="name">post_count</span>, <span class="name">f</span>.<span class="name">thread_count</span>, <span class="name">f</span>.<span class="name">last_post_id</span>] - <span class="name">sf_columns</span> <span class="op">=</span> [<span class="name">f</span>.<span class="name">forum_id</span>, <span class="name">f</span>.<span class="name">name</span>, <span class="name">f</span>.<span class="name">link</span>] - <span class="name">thread_columns</span> <span class="op">=</span> [<span class="name">p</span>.<span class="name">post_id</span>, <span class="name">p</span>.<span class="name">title</span>, <span class="name">p</span>.<span class="name">timestamp</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">p</span>.<span class="name">post_count</span>, <span class="name">p</span>.<span class="name">view_count</span>, <span class="name">p</span>.<span class="name">username</span>.<span class="name">label</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>)] - <span class="kw">def </span><span class="fun">do</span>(<span class="name">con</span>): - <span class="name">category</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">columns</span>, - <span class="name">f</span>.<span class="name">forum_id</span> <span class="op">==</span> <span class="name">forum_id</span> - - )).<span class="name">fetchone</span>() - <span class="kw">if</span> <span class="name">category</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="kw">return</span> - <span class="name">category</span> <span class="op">=</span> <span class="bn">dict</span>(<span class="name">category</span>) - <span class="name">category</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">forum</span><span class="st st-sg">'</span>, <span class="name">category</span>[<span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>]) - <span class="cm"># wo don't pop link here so that the ForumPage request handler</span> - - <span class="cm"># can use the link key for redirecting. That means we don't</span> - <span class="cm"># need a second query. But template designers shouldn't</span> - <span class="cm"># ever access {{ forum.link }}</span> - <span class="name">category</span>[<span class="st st-sg">'</span><span class="st">is_external_url</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="bn">bool</span>(<span class="name">category</span>[<span class="st st-sg">'</span><span class="st">link</span><span class="st st-sg">'</span>]) - <span class="name">forums</span> <span class="op">=</span> [] - <span class="kw">for</span> <span class="name">forum</span> <span class="op op-word">in</span> <span class="name">con</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>(<span class="name">forum_columns</span>, - <span class="name">f</span>.<span class="name">parent_id</span> <span class="op">==</span> <span class="name">category</span>[<span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>])): - <span class="name">forum</span> <span class="op">=</span> <span class="bn">dict</span>(<span class="name">forum</span>) - <span class="name">forum</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">forum</span><span class="st st-sg">'</span>, <span class="name">forum</span>[<span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>]) - <span class="cm"># wo don't pop that here so that the ForumPage request handler</span> - - <span class="cm"># can use the link key for redirecting. That means we don't</span> - <span class="cm"># need a second query. But template designers shouldn't</span> - <span class="cm"># ever access {{ forum.link }}</span> - <span class="name">forum</span>[<span class="st st-sg">'</span><span class="st">is_external_link</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="bn">bool</span>(<span class="name">forum</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">link</span><span class="st st-sg">'</span>)) - <span class="name">subforums</span> <span class="op">=</span> [] - <span class="kw">for</span> <span class="name">sf</span> <span class="op op-word">in</span> <span class="name">con</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>(<span class="name">sf_columns</span>, - <span class="name">f</span>.<span class="name">parent_id</span> <span class="op">==</span> <span class="name">forum</span>[<span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>])): - <span class="name">sf</span> <span class="op">=</span> <span class="bn">dict</span>(<span class="name">sf</span>) - <span class="name">sf</span>[<span class="st st-sg">'</span><span class="st">is_external_link</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="bn">bool</span>(<span class="name">sf</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">link</span><span class="st st-sg">'</span>)) - <span class="name">sf</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">forum</span><span class="st st-sg">'</span>, <span class="name">sf</span>[<span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>]) - <span class="name">subforums</span>.<span class="name">append</span>(<span class="name">sf</span>) - <span class="name">forum</span>[<span class="st st-sg">'</span><span class="st">subforums</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">subforums</span> - - <span class="cm"># get last post</span> - <span class="name">last_post_id</span> <span class="op">=</span> <span class="name">forum</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">last_post_id</span><span class="st st-sg">'</span>) - <span class="kw">if</span> <span class="name">last_post_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">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">u</span>.<span class="name">user_id</span>, <span class="name">u</span>.<span class="name">username</span>, - <span class="name">p</span>.<span class="name">post_id</span>, <span class="name">p</span>.<span class="name">title</span>, - <span class="name">p</span>.<span class="name">username</span>.<span class="name">label</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>), - <span class="name">p</span>.<span class="name">timestamp</span>], - (<span class="name">p</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="name">last_post_id</span>) <span class="op">&</span> - - (<span class="name">p</span>.<span class="name">post_id</span> <span class="op">!=</span> <span class="bn bn-pseudo">None</span>) <span class="op">&</span> - (<span class="name">u</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">p</span>.<span class="name">author_id</span>) - )) - <span class="name">last_post</span> <span class="op">=</span> <span class="name">result</span>.<span class="name">fetchone</span>() - <span class="name">last_post</span> <span class="op">=</span> <span class="bn">dict</span>(<span class="name">last_post</span>) - <span class="name">username</span> <span class="op">=</span> <span class="name">urlencode</span>(<span class="name">last_post</span>[<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>]) - <span class="name">last_post</span>[<span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</span>] <span class="op">=</span> { - <span class="st st-sg">'</span><span class="st">registered</span><span class="st st-sg">'</span>: <span class="name">last_post</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">0</span>, - <span class="st st-sg">'</span><span class="st">user_id</span><span class="st st-sg">'</span>: <span class="name">last_post</span>.<span class="name">pop</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">last_post</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>) <span class="op op-word">or</span>\ - <span class="name">last_post</span>.<span class="name">pop</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">username</span>), - } - <span class="name">last_post</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">post</span><span class="st st-sg">'</span>, <span class="name">last_post</span>[<span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>]) - <span class="kw">else</span>: - <span class="name">last_post</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="name">forum</span>[<span class="st st-sg">'</span><span class="st">last_post</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">last_post</span> - <span class="name">forums</span>.<span class="name">append</span>(<span class="name">forum</span>) - <span class="name">category</span>[<span class="st st-sg">'</span><span class="st">forums</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">forums</span> - - <span class="cm"># pagination</span> - <span class="kw">def </span><span class="fun">get_page_link</span>(<span class="name">number</span>): - <span class="name">link</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">forum/</span><span class="st st-int">%d</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">forum_id</span> - - <span class="kw">if</span> <span class="name">number</span> <span class="op">></span> <span class="nb nb-int">1</span>: - <span class="name">link</span> <span class="op">+=</span> <span class="st st-sg">'</span><span class="st">?page=</span><span class="st st-int">%d</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">number</span> - - <span class="kw">return</span> <span class="name">link</span> - <span class="name">threads_per_page</span> <span class="op">=</span> <span class="name">get_threads_per_page</span>(<span class="name">req</span>) - <span class="name">page_count</span> <span class="op">=</span> <span class="bn">int</span>(<span class="name">ceil</span>(<span class="name">category</span>[<span class="st st-sg">'</span><span class="st">thread_count</span><span class="st st-sg">'</span>] <span class="op">/</span> (<span class="name">threads_per_page</span> <span class="op">*</span> <span class="nb nb-flt">1.0</span>))) - <span class="name">pagination</span> <span class="op">=</span> <span class="name">LazyPagination</span>(<span class="name">req</span>, <span class="name">page</span>, <span class="name">threads_per_page</span>, <span class="name">page_count</span>, - <span class="name">get_page_link</span>) - - <span class="name">threads</span> <span class="op">=</span> [] - <span class="kw">for</span> <span class="name">thread</span> <span class="op op-word">in</span> <span class="name">con</span>.<span class="name">execute</span>(<span class="name">meta</span>.<span class="name">select</span>(<span class="name">thread_columns</span>, - (<span class="name">p</span>.<span class="name">forum_id</span> <span class="op">==</span> <span class="name">category</span>[<span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>]) <span class="op">&</span> - - (<span class="name">p</span>.<span class="name">parent_id</span> <span class="op">==</span> <span class="bn bn-pseudo">None</span>) <span class="op">&</span> - (<span class="name">u</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">p</span>.<span class="name">author_id</span>), - <span class="name">order_by</span><span class="op">=</span>[<span class="name">meta</span>.<span class="name">desc</span>(<span class="name">p</span>.<span class="name">post_id</span>)], - <span class="name">limit</span><span class="op">=</span><span class="name">threads_per_page</span>, - <span class="name">offset</span><span class="op">=</span><span class="name">threads_per_page</span> <span class="op">*</span> (<span class="name">page</span> <span class="op">-</span> <span class="nb nb-int">1</span>) - )): - <span class="name">thread</span> <span class="op">=</span> <span class="bn">dict</span>(<span class="name">thread</span>) - <span class="name">thread</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">post</span><span class="st st-sg">'</span>, <span class="name">thread</span>[<span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>]) - <span class="name">thread</span>[<span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</span>] <span class="op">=</span> { - <span class="st st-sg">'</span><span class="st">registered</span><span class="st st-sg">'</span>: <span class="name">thread</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">0</span>, - <span class="st st-sg">'</span><span class="st">user_id</span><span class="st st-sg">'</span>: <span class="name">thread</span>.<span class="name">pop</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">thread</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>) <span class="op op-word">or</span> <span class="name">thread</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">thread</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>))) - } - <span class="cm"># get last post</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">u</span>.<span class="name">user_id</span>, <span class="name">u</span>.<span class="name">username</span>, <span class="name">p</span>.<span class="name">post_id</span>, - <span class="name">p</span>.<span class="name">title</span>, <span class="name">p</span>.<span class="name">timestamp</span>, - <span class="name">p</span>.<span class="name">username</span>.<span class="name">label</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>)], - (<span class="name">p</span>.<span class="name">root_post_id</span> <span class="op">==</span> <span class="name">thread</span>[<span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>]) <span class="op">&</span> - - (<span class="name">u</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">p</span>.<span class="name">author_id</span>), - <span class="name">order_by</span><span class="op">=</span>[<span class="name">meta</span>.<span class="name">desc</span>(<span class="name">p</span>.<span class="name">post_id</span>)], - <span class="name">limit</span><span class="op">=</span><span class="nb nb-int">1</span> - - )) - <span class="name">last_post</span> <span class="op">=</span> <span class="name">result</span>.<span class="name">fetchone</span>() - <span class="kw">if</span> <span class="name">last_post</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">last_post</span> <span class="op">=</span> <span class="bn">dict</span>(<span class="name">last_post</span>) - <span class="name">username</span> <span class="op">=</span> <span class="name">last_post</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>) - <span class="name">last_post</span>[<span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</span>] <span class="op">=</span> { - <span class="st st-sg">'</span><span class="st">registered</span><span class="st st-sg">'</span>: <span class="name">last_post</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">0</span>, - <span class="st st-sg">'</span><span class="st">user_id</span><span class="st st-sg">'</span>: <span class="name">last_post</span>.<span class="name">pop</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">last_post</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>) <span class="op op-word">or</span> <span class="name">username</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">username</span>)), - } - <span class="name">last_post</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">post</span><span class="st st-sg">'</span>, <span class="name">last_post</span>[<span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>]) - <span class="name">thread</span>[<span class="st st-sg">'</span><span class="st">last_post</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">last_post</span> - - <span class="name">threads</span>.<span class="name">append</span>(<span class="name">thread</span>) - <span class="name">category</span>[<span class="st st-sg">'</span><span class="st">threads</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">threads</span> - <span class="name">category</span>[<span class="st st-sg">'</span><span class="st">pagination</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">pagination</span> - - <span class="kw">return</span> <span class="name">category</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_forum_pathbar</span>(<span class="name">ctx</span>, <span class="name">forum_id</span>): - <span class="st st-db">"""</span><span class="st">Return the pathbar for a given forum.</span><span class="st st-db">"""</span> - - <span class="name">f</span> <span class="op">=</span> <span class="name">forums</span>.<span class="name">c</span> - <span class="name">pathbar</span> <span class="op">=</span> [] - <span class="kw">def </span><span class="fun">do</span>(<span class="name">con</span>, <span class="name">fid</span><span class="op">=</span><span class="bn bn-pseudo">None</span>): - <span class="kw">if</span> <span class="name">fid</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="name">fid</span> <span class="op">=</span> <span class="name">forum_id</span> - - <span class="name">row</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">f</span>.<span class="name">parent_id</span>, <span class="name">f</span>.<span class="name">name</span>], - <span class="name">forums</span>.<span class="name">c</span>.<span class="name">forum_id</span> <span class="op">==</span> <span class="name">fid</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">l</span> <span class="op">=</span> <span class="st st-sg">'</span><span class="st">forum/</span><span class="st st-int">%d</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">fid</span> - - <span class="name">pathbar</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">ctx</span>.<span class="name">make_url</span>(<span class="name">l</span>), - <span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>: <span class="name">fid</span>, - <span class="st st-sg">'</span><span class="st">name</span><span class="st st-sg">'</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">if</span> <span class="name">row</span>[<span class="st st-sg">'</span><span class="st">parent_id</span><span class="st st-sg">'</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">do</span>(<span class="name">con</span>, <span class="name">row</span>[<span class="st st-sg">'</span><span class="st">parent_id</span><span class="st st-sg">'</span>]) - <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">transaction</span>(<span class="name">do</span>) - <span class="name">pathbar</span>.<span class="name">reverse</span>() - <span class="kw">return</span> <span class="name">pathbar</span> - - -<span class="kw">def </span><span class="fun">get_post_pathbar</span>(<span class="name">ctx</span>, <span class="name">post_id</span>): - <span class="st st-db">"""</span><span class="st">Returns the pathbar for a given post including all forums and subforums</span><span class="st st-db">"""</span> - <span class="name">thread</span> <span class="op">=</span> <span class="name">Thread</span>.<span class="name">by_child</span>(<span class="name">ctx</span>, <span class="name">post_id</span>) - <span class="name">pathbar</span> <span class="op">=</span> <span class="name">get_forum_pathbar</span>(<span class="name">ctx</span>, <span class="name">thread</span>.<span class="name">forum_id</span>) - <span class="name">post_list</span> <span class="op">=</span> [ <span class="name">thread</span>.<span class="name">root_post_id</span> ] - <span class="name">p</span> <span class="op">=</span> <span class="name">posts</span>.<span class="name">c</span> - - <span class="kw">if</span> <span class="name">thread</span>.<span class="name">root_post_id</span> <span class="op">!=</span> <span class="bn">int</span>(<span class="name">post_id</span>): - <span class="name">post_list</span>.<span class="name">append</span>(<span class="name">post_id</span>) - - <span class="kw">def </span><span class="fun">do</span>(<span class="name">con</span>): - <span class="kw">for</span> <span class="bn">id</span> <span class="op op-word">in</span> <span class="name">post_list</span>: - <span class="name">row</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">p</span>.<span class="name">title</span>], - <span class="name">p</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="bn">id</span> - - )).<span class="name">fetchone</span>() - <span class="name">pathbar</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">ctx</span>.<span class="name">make_url</span>(<span class="st st-sg">'</span><span class="st">post/</span><span class="st st-int">%s</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="bn">id</span>), - <span class="st st-sg">'</span><span class="st">name</span><span class="st st-sg">'</span>: <span class="name">row</span>[<span class="st st-db">"</span><span class="st">title</span><span class="st st-db">"</span>] - }) - <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">transaction</span>(<span class="name">do</span>) - <span class="kw">return</span> <span class="name">pathbar</span> - - -<span class="kw">def </span><span class="fun">get_post_tree</span>(<span class="name">req</span>, <span class="name">post_id</span>, <span class="name">inc_view_count</span><span class="op">=</span><span class="bn bn-pseudo">True</span>): - <span class="st st-db">"""</span><span class="st"> - Return a dict with the thread information and a tree of posts. - - Per default it will increment the view counter of the - thread requested. If you don't want that set ``inc_view_count`` - to ``False``. - </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">p</span> <span class="op">=</span> <span class="name">posts</span>.<span class="name">c</span> - - <span class="name">u</span> <span class="op">=</span> <span class="name">users</span>.<span class="name">c</span> - <span class="name">f</span> <span class="op">=</span> <span class="name">forums</span>.<span class="name">c</span> - - <span class="cm"># load the post requested and lookup root_post_id</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">p</span>.<span class="name">root_post_id</span>, <span class="name">p</span>.<span class="name">post_id</span>, <span class="name">p</span>.<span class="name">title</span>, - <span class="name">p</span>.<span class="name">text</span>, <span class="name">p</span>.<span class="name">timestamp</span>, <span class="name">u</span>.<span class="name">user_id</span>, - <span class="name">u</span>.<span class="name">register_date</span>, - <span class="name">u</span>.<span class="name">username</span>, <span class="name">u</span>.<span class="name">profile</span>, <span class="name">u</span>.<span class="name">post_count</span>, - <span class="name">p</span>.<span class="name">username</span>.<span class="name">label</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>)], - (<span class="name">p</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="name">post_id</span>) <span class="op">&</span> - - (<span class="name">u</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">p</span>.<span class="name">author_id</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: need error return here</span> - - <span class="kw">return</span> - <span class="name">post</span> <span class="op">=</span> <span class="bn">dict</span>(<span class="name">row</span>) - <span class="name">post</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">post</span><span class="st st-sg">'</span>, <span class="name">row</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-sg">'</span><span class="st">author</span><span class="st st-sg">'</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">post</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">post</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>) <span class="op op-word">or</span> <span class="name">post</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">self</span><span class="st st-sg">'</span>: <span class="name">req</span>.<span class="name">user</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">post</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">registered</span><span class="st st-sg">'</span>: <span class="name">post</span>.<span class="name">pop</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">0</span>, - <span class="st st-sg">'</span><span class="st">register_date</span><span class="st st-sg">'</span>: <span class="name">post</span>.<span class="name">pop</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">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">post</span>.<span class="name">pop</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">profile</span><span class="st st-sg">'</span>: <span class="name">post</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">profile</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">post</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">post_count</span><span class="st st-sg">'</span>), - } - <span class="name">signature</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="kw">if</span> <span class="name">post</span>[<span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</span>][<span class="st st-sg">'</span><span class="st">profile</span><span class="st st-sg">'</span>].<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">signature</span><span class="st st-sg">'</span>): - <span class="name">signature</span> <span class="op">=</span> <span class="name">parse_and_render</span>(<span class="name">req</span>, <span class="name">post</span>[<span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</span>][<span class="st st-sg">'</span><span class="st">profile</span><span class="st st-sg">'</span>][<span class="st st-sg">'</span><span class="st">signature</span><span class="st st-sg">'</span>], - <span class="name">signature</span><span class="op">=</span><span class="bn bn-pseudo">True</span>) - <span class="name">post</span>[<span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</span>][<span class="st st-sg">'</span><span class="st">signature</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">signature</span> - - <span class="cm">#XXX: cache here</span> - <span class="name">post</span>[<span class="st st-sg">'</span><span class="st">parsed_text</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">parse_and_render</span>(<span class="name">req</span>, <span class="name">post</span>[<span class="st st-sg">'</span><span class="st">text</span><span class="st st-sg">'</span>]) - <span class="name">root_post_id</span> <span class="op">=</span> <span class="name">post</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">root_post_id</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">p</span>.<span class="name">post_id</span>, <span class="name">p</span>.<span class="name">root_post_id</span>, <span class="name">p</span>.<span class="name">title</span>, - <span class="name">p</span>.<span class="name">parent_id</span>, <span class="name">p</span>.<span class="name">timestamp</span>, <span class="name">u</span>.<span class="name">username</span>, - <span class="name">u</span>.<span class="name">user_id</span>, <span class="name">p</span>.<span class="name">username</span>.<span class="name">label</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>)], - (<span class="name">p</span>.<span class="name">root_post_id</span> <span class="op">==</span> <span class="name">root_post_id</span>) <span class="op">&</span> - - (<span class="name">u</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">p</span>.<span class="name">author_id</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">author</span><span class="st st-sg">'</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">d</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">d</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>) <span class="op op-word">or</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">self</span><span class="st st-sg">'</span>: <span class="name">req</span>.<span class="name">user</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">d</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">registered</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">user_id</span><span class="st st-sg">'</span>) <span class="op">></span> <span class="nb nb-int">0</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">d</span>.<span class="name">pop</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">active</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>] <span class="op">==</span> <span class="name">post_id</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">post</span><span class="st st-sg">'</span>, <span class="name">row</span>[<span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>]) - <span class="kw">return</span> <span class="name">d</span> - - <span class="cm"># map threads by their parents and prepare the context</span> - <span class="name">mapping</span> <span class="op">=</span> {} - <span class="name">flat_posts</span> <span class="op">=</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="name">tmp</span> <span class="op">=</span> <span class="name">prepare</span>(<span class="name">row</span>) - <span class="name">mapping</span>.<span class="name">setdefault</span>(<span class="name">row</span>[<span class="st st-sg">'</span><span class="st">parent_id</span><span class="st st-sg">'</span>], []).<span class="name">append</span>(<span class="name">tmp</span>) - <span class="name">flat_posts</span>.<span class="name">append</span>(<span class="name">tmp</span>) - <span class="name">root</span> <span class="op">=</span> <span class="name">mapping</span>.<span class="name">pop</span>(<span class="bn bn-pseudo">None</span>, <span class="bn bn-pseudo">None</span>) - <span class="kw">if</span> <span class="name">root</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="kw">return</span> - - <span class="kw">assert</span> <span class="bn">len</span>(<span class="name">root</span>) <span class="op">==</span> <span class="nb nb-int">1</span>, <span class="st st-sg">'</span><span class="st">something went seriously wrong</span><span class="st st-sg">'</span> - - <span class="cm"># reassamble thread</span> - - <span class="kw">def </span><span class="fun">reassamble</span>(<span class="name">nodes</span>): - <span class="kw">for</span> <span class="name">node</span> <span class="op op-word">in</span> <span class="name">nodes</span>: - <span class="name">node</span>[<span class="st st-sg">'</span><span class="st">children</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">n</span> <span class="op">=</span> <span class="name">mapping</span>.<span class="name">pop</span>(<span class="name">node</span>[<span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>], []) - <span class="name">reassamble</span>(<span class="name">n</span>) - <span class="name">reassamble</span>(<span class="name">root</span>) - - <span class="cm"># increment view_count</span> - - <span class="kw">if</span> <span class="name">inc_view_count</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">p</span>.<span class="name">view_count</span>], - <span class="name">p</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="name">root_post_id</span>)) - <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">posts</span>.<span class="name">update</span>(<span class="name">p</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="name">root_post_id</span>), - <span class="name">view_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="op">+</span> <span class="nb nb-int">1</span> - - ) - - - <span class="cm"># fetch overall information for whole thread</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">p</span>.<span class="name">post_id</span>, <span class="name">p</span>.<span class="name">title</span>, <span class="name">p</span>.<span class="name">forum_id</span>, - <span class="name">p</span>.<span class="name">timestamp</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">f</span>.<span class="name">name</span>, <span class="name">p</span>.<span class="name">username</span>.<span class="name">label</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>)], - (<span class="name">p</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="name">root_post_id</span>) <span class="op">&</span> - - (<span class="name">u</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">p</span>.<span class="name">author_id</span>) <span class="op">&</span> - (<span class="name">f</span>.<span class="name">forum_id</span> <span class="op">==</span> <span class="name">p</span>.<span class="name">forum_id</span>) - )) - <span class="name">row</span> <span class="op">=</span> <span class="name">result</span>.<span class="name">fetchone</span>() - <span class="kw">return</span> { - <span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>: <span class="name">row</span>[<span class="st st-sg">'</span><span class="st">post_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">post</span><span class="st st-sg">'</span>, <span class="name">row</span>[<span class="st st-sg">'</span><span class="st">post_id</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">row</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">timestamp</span><span class="st st-sg">'</span>: <span class="name">row</span>[<span class="st st-sg">'</span><span class="st">timestamp</span><span class="st st-sg">'</span>], - <span class="st st-sg">'</span><span class="st">forum</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">row</span>[<span class="st st-sg">'</span><span class="st">forum_id</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="name">row</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">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">forum</span><span class="st st-sg">'</span>, <span class="name">row</span>[<span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>]), - }, - <span class="st st-sg">'</span><span class="st">author</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">row</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">registered</span><span class="st st-sg">'</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="op">></span> <span class="nb nb-int">0</span>, - <span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>: <span class="name">row</span>[<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>] <span class="op op-word">or</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="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">row</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">posts</span><span class="st st-sg">'</span>: <span class="name">root</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="kw">def </span><span class="fun">get_post</span>(<span class="name">req</span>, <span class="name">post_id</span>): - <span class="st st-db">"""</span><span class="st"> - Return exactly one post. If the post does not exist the result - will be ``None``. - </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">p</span> <span class="op">=</span> <span class="name">posts</span>.<span class="name">c</span> - <span class="name">u</span> <span class="op">=</span> <span class="name">users</span>.<span class="name">c</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">meta</span>.<span class="name">select</span>([<span class="name">p</span>.<span class="name">post_id</span>, <span class="name">p</span>.<span class="name">title</span>, <span class="name">p</span>.<span class="name">text</span>, <span class="name">p</span>.<span class="name">timestamp</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">profile</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">p</span>.<span class="name">username</span>.<span class="name">label</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>)], - (<span class="name">p</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="name">post_id</span>) <span class="op">&</span> - - (<span class="name">u</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">p</span>.<span class="name">author_id</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">return</span> - - <span class="name">post</span> <span class="op">=</span> <span class="bn">dict</span>(<span class="name">row</span>) - <span class="name">post</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">post</span><span class="st st-sg">'</span>, <span class="name">post</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-sg">'</span><span class="st">author</span><span class="st st-sg">'</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">post</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">post</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>) <span class="op op-word">or</span> <span class="name">post</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">self</span><span class="st st-sg">'</span>: <span class="name">req</span>.<span class="name">user</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">post</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">registered</span><span class="st st-sg">'</span>: <span class="name">post</span>.<span class="name">pop</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">0</span>, - <span class="st st-sg">'</span><span class="st">register_date</span><span class="st st-sg">'</span>: <span class="name">post</span>.<span class="name">pop</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">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">post</span>.<span class="name">pop</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">profile</span><span class="st st-sg">'</span>: <span class="name">post</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">profile</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">post</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">post_count</span><span class="st st-sg">'</span>) - } - <span class="name">signature</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="kw">if</span> <span class="name">post</span>[<span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</span>][<span class="st st-sg">'</span><span class="st">profile</span><span class="st st-sg">'</span>].<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">signature</span><span class="st st-sg">'</span>): - <span class="name">signature</span> <span class="op">=</span> <span class="name">parse_and_render</span>(<span class="name">req</span>, <span class="name">post</span>[<span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</span>][<span class="st st-sg">'</span><span class="st">profile</span><span class="st st-sg">'</span>][<span class="st st-sg">'</span><span class="st">signature</span><span class="st st-sg">'</span>]) - <span class="name">post</span>[<span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</span>][<span class="st st-sg">'</span><span class="st">signature</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">signature</span> - - <span class="cm">#XXX: cache here</span> - <span class="name">post</span>[<span class="st st-sg">'</span><span class="st">parsed_text</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">parse_and_render</span>(<span class="name">req</span>, <span class="name">post</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">post</span> - - -<span class="kw">def </span><span class="fun">get_last_posts</span>(<span class="name">req</span>, <span class="name">root_post_id</span>, <span class="name">n</span><span class="op">=</span><span class="nb nb-int">1</span>, <span class="name">offset</span><span class="op">=</span><span class="nb nb-int">0</span>): - <span class="st st-db">"""</span><span class="st"> - - Returns a flat view of the n latest posts that are - children of root_post_id. - </span><span class="st st-db">"""</span> - <span class="name">p</span> <span class="op">=</span> <span class="name">posts</span>.<span class="name">c</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">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">p</span>.<span class="name">post_id</span>, <span class="name">p</span>.<span class="name">title</span>, <span class="name">p</span>.<span class="name">text</span>, - <span class="name">p</span>.<span class="name">timestamp</span>, <span class="name">u</span>.<span class="name">username</span>, - <span class="name">u</span>.<span class="name">user_id</span>, <span class="name">u</span>.<span class="name">profile</span>, - <span class="name">u</span>.<span class="name">post_count</span>, <span class="name">u</span>.<span class="name">register_date</span>, - <span class="name">p</span>.<span class="name">username</span>.<span class="name">label</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>)], - (<span class="name">p</span>.<span class="name">root_post_id</span> <span class="op">==</span> <span class="name">root_post_id</span>) <span class="op">&</span> - - (<span class="name">u</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">p</span>.<span class="name">author_id</span>), - <span class="name">order_by</span><span class="op">=</span>[<span class="name">meta</span>.<span class="name">desc</span>(<span class="name">p</span>.<span class="name">post_id</span>)], - <span class="name">limit</span><span class="op">=</span><span class="name">n</span>, - <span class="name">offset</span><span class="op">=</span><span class="name">offset</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">user_id</span> <span class="op">=</span> <span class="name">d</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">user_id</span><span class="st st-sg">'</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">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">row</span>[<span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>]) - <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</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">user_id</span>, - <span class="st st-sg">'</span><span class="st">registered</span><span class="st st-sg">'</span>: <span class="name">user_id</span> <span class="op">></span> <span class="nb nb-int">0</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="name">pop</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>) <span class="op op-word">or</span> <span class="name">d</span>.<span class="name">pop</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">self</span><span class="st st-sg">'</span>: <span class="name">req</span>.<span class="name">user</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">user_id</span>, - <span class="st st-sg">'</span><span class="st">profile</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">profile</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">d</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">post_count</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">d</span>.<span class="name">pop</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">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">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="name">signature</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="kw">if</span> <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</span>][<span class="st st-sg">'</span><span class="st">profile</span><span class="st st-sg">'</span>].<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">signature</span><span class="st st-sg">'</span>): - <span class="name">signature</span> <span class="op">=</span> <span class="name">parse_and_render</span>(<span class="name">req</span>, <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</span>][<span class="st st-sg">'</span><span class="st">profile</span><span class="st st-sg">'</span>][<span class="st st-sg">'</span><span class="st">signature</span><span class="st st-sg">'</span>], - <span class="name">signature</span><span class="op">=</span><span class="bn bn-pseudo">True</span>) - <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</span>][<span class="st st-sg">'</span><span class="st">signature</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">signature</span> - - <span class="cm">#XXX: this doesn't cache by now</span> - <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">parsed_text</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">parse_and_render</span>(<span class="name">req</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">d</span> - - <span class="name">post_list</span> <span class="op">=</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">return</span> <span class="name">post_list</span> - - -<span class="kw">def </span><span class="fun">get_flat_view</span>(<span class="name">req</span>, <span class="name">post_id</span>, <span class="name">inc_view_count</span><span class="op">=</span><span class="bn bn-pseudo">True</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="st st-db">"""</span><span class="st"> - - Returns the flat view of an post and the next n posts so - that the template can render a page. n is the number of - posts per page defined in either the user settings or the - global forum configuration. - - Per default it will increment the view counter of the - thread requested. If you don't want that set ``inc_view_count`` - to ``False``. - - If you want to get the latest post first, set ``order`` - to ``'desc'``. - </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">p</span> <span class="op">=</span> <span class="name">posts</span>.<span class="name">c</span> - - <span class="name">f</span> <span class="op">=</span> <span class="name">forums</span>.<span class="name">c</span> - <span class="name">u</span> <span class="op">=</span> <span class="name">users</span>.<span class="name">c</span> - - <span class="cm"># find root_post_id</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">p</span>.<span class="name">root_post_id</span>], - <span class="name">p</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="name">post_id</span> - - )) - <span class="cm"># XXX: This raises TypeError on failure.</span> - <span class="name">root_post_id</span> <span class="op">=</span> <span class="name">result</span>.<span class="name">fetchone</span>()[<span class="nb nb-int">0</span>] - - <span class="cm"># select all post ids to calculate the position of the post on a page</span> - - <span class="cm"># the purpose of this calculation is to find the first and last post</span> - <span class="cm"># on the page if the post_id given the function</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">p</span>.<span class="name">post_id</span>], - <span class="name">p</span>.<span class="name">root_post_id</span> <span class="op">==</span> <span class="name">root_post_id</span> - - )) - <span class="name">posts_per_page</span> <span class="op">=</span> <span class="name">get_posts_per_page</span>(<span class="name">req</span>) - <span class="name">postlist</span> <span class="op">=</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="name">post_index</span> <span class="op">=</span> <span class="name">postlist</span>.<span class="name">index</span>(<span class="name">post_id</span>) - <span class="name">page</span> <span class="op">=</span> <span class="name">post_index</span> <span class="op">//</span> <span class="name">posts_per_page</span> - - <span class="name">page_start</span> <span class="op">=</span> <span class="name">page</span> <span class="op">*</span> <span class="name">posts_per_page</span> - <span class="name">post_range_low</span> <span class="op">=</span> <span class="name">postlist</span>[<span class="name">page_start</span>] - <span class="name">post_range_high</span> <span class="op">=</span> <span class="name">postlist</span>[<span class="name">page_start</span>:<span class="name">page_start</span> <span class="op">+</span> <span class="name">posts_per_page</span>][<span class="op">-</span><span class="nb nb-int">1</span>] - - <span class="name">pagination</span> <span class="op">=</span> <span class="name">Pagination</span>(<span class="name">req</span>, <span class="name">postlist</span>, <span class="name">page_start</span>, <span class="name">posts_per_page</span>, - <span class="kw">lambda</span> <span class="name">x</span>: <span class="st st-sg">'</span><span class="st">post/</span><span class="st st-int">%d</span><span class="st st-sg">'</span> <span class="op">%</span> <span class="name">x</span>) - - <span class="name">orderfunc</span> <span class="op">=</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="op op-word">and</span> <span class="name">meta</span>.<span class="name">desc</span> <span class="op op-word">or</span> <span class="name">meta</span>.<span class="name">asc</span>) - <span class="cm"># select matching posts</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">p</span>.<span class="name">post_id</span>, <span class="name">p</span>.<span class="name">root_post_id</span>, <span class="name">p</span>.<span class="name">title</span>, - <span class="name">p</span>.<span class="name">forum_id</span>, <span class="name">p</span>.<span class="name">parent_id</span>, <span class="name">p</span>.<span class="name">text</span>, - <span class="name">p</span>.<span class="name">timestamp</span>, <span class="name">u</span>.<span class="name">username</span>, <span class="name">u</span>.<span class="name">user_id</span>, - <span class="name">u</span>.<span class="name">profile</span>, <span class="name">u</span>.<span class="name">post_count</span>, <span class="name">u</span>.<span class="name">register_date</span>, - <span class="name">p</span>.<span class="name">username</span>.<span class="name">label</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>)], - (<span class="name">p</span>.<span class="name">root_post_id</span> <span class="op">==</span> <span class="name">root_post_id</span>) <span class="op">&</span> - - (<span class="name">p</span>.<span class="name">post_id</span> <span class="op">>=</span> <span class="name">post_range_low</span>) <span class="op">&</span> - (<span class="name">p</span>.<span class="name">post_id</span> <span class="op"><=</span> <span class="name">post_range_high</span>) <span class="op">&</span> - - (<span class="name">u</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">p</span>.<span class="name">author_id</span>), - <span class="name">order_by</span><span class="op">=</span>[<span class="name">orderfunc</span>(<span class="name">p</span>.<span class="name">post_id</span>)] - )) - - <span class="kw">def </span><span class="fun">prepare</span>(<span class="name">number</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">user_id</span> <span class="op">=</span> <span class="name">d</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">user_id</span><span class="st st-sg">'</span>) - <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">post_number</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">number</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">post</span><span class="st st-sg">'</span>, <span class="name">row</span>[<span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>]) - <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</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">user_id</span>, - <span class="st st-sg">'</span><span class="st">registered</span><span class="st st-sg">'</span>: <span class="name">user_id</span> <span class="op">></span> <span class="nb nb-int">0</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="name">pop</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>) <span class="op op-word">or</span> <span class="name">d</span>.<span class="name">pop</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">self</span><span class="st st-sg">'</span>: <span class="name">req</span>.<span class="name">user</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">user_id</span>, - <span class="st st-sg">'</span><span class="st">profile</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">profile</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">d</span>.<span class="name">pop</span>(<span class="st st-sg">'</span><span class="st">post_count</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">d</span>.<span class="name">pop</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">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">row</span>[<span class="st st-sg">'</span><span class="st">username</span><span class="st st-sg">'</span>])), - } - <span class="name">signature</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="kw">if</span> <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</span>][<span class="st st-sg">'</span><span class="st">profile</span><span class="st st-sg">'</span>].<span class="name">get</span>(<span class="st st-sg">'</span><span class="st">signature</span><span class="st st-sg">'</span>): - <span class="name">signature</span> <span class="op">=</span> <span class="name">parse_and_render</span>(<span class="name">req</span>, <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</span>][<span class="st st-sg">'</span><span class="st">profile</span><span class="st st-sg">'</span>][<span class="st st-sg">'</span><span class="st">signature</span><span class="st st-sg">'</span>], - <span class="name">signature</span><span class="op">=</span><span class="bn bn-pseudo">True</span>) - <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">author</span><span class="st st-sg">'</span>][<span class="st st-sg">'</span><span class="st">signature</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">signature</span> - - <span class="cm">#XXX: this doesn't cache by now</span> - <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">parsed_text</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">parse_and_render</span>(<span class="name">req</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">d</span> - - <span class="name">real_posts</span> <span class="op">=</span> [<span class="name">prepare</span>(<span class="name">num</span>, <span class="name">row</span>) <span class="kw">for</span> <span class="name">num</span>, <span class="name">row</span> <span class="op op-word">in</span> <span class="name">inciter</span>(<span class="name">result</span>, <span class="name">page_start</span>)] - - <span class="cm"># increment view_count</span> - - <span class="kw">if</span> <span class="name">inc_view_count</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">p</span>.<span class="name">view_count</span>], - <span class="name">p</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="name">root_post_id</span>)) - <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">execute</span>(<span class="name">posts</span>.<span class="name">update</span>(<span class="name">p</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="name">root_post_id</span>), - <span class="name">view_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="op">+</span> <span class="nb nb-int">1</span> - - ) - - <span class="cm"># and another query for the overview page</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">p</span>.<span class="name">post_id</span>, <span class="name">p</span>.<span class="name">title</span>, <span class="name">p</span>.<span class="name">forum_id</span>, - <span class="name">p</span>.<span class="name">timestamp</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">f</span>.<span class="name">name</span>, <span class="name">p</span>.<span class="name">username</span>.<span class="name">label</span>(<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>)], - (<span class="name">p</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="name">root_post_id</span>) <span class="op">&</span> - - (<span class="name">u</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">p</span>.<span class="name">author_id</span>) <span class="op">&</span> - (<span class="name">f</span>.<span class="name">forum_id</span> <span class="op">==</span> <span class="name">p</span>.<span class="name">forum_id</span>) - )) - <span class="name">row</span> <span class="op">=</span> <span class="name">result</span>.<span class="name">fetchone</span>() - <span class="kw">return</span> { - <span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>: <span class="name">row</span>[<span class="st st-sg">'</span><span class="st">post_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">post</span><span class="st st-sg">'</span>, <span class="name">row</span>[<span class="st st-sg">'</span><span class="st">post_id</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">row</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">timestamp</span><span class="st st-sg">'</span>: <span class="name">row</span>[<span class="st st-sg">'</span><span class="st">timestamp</span><span class="st st-sg">'</span>], - <span class="st st-sg">'</span><span class="st">forum</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">row</span>[<span class="st st-sg">'</span><span class="st">forum_id</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="name">row</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">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">forum</span><span class="st st-sg">'</span>, <span class="name">row</span>[<span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>]), - }, - <span class="st st-sg">'</span><span class="st">author</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">row</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">row</span>[<span class="st st-sg">'</span><span class="st">guestname</span><span class="st st-sg">'</span>] <span class="op op-word">or</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="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">row</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">pagination</span><span class="st st-sg">'</span>: <span class="name">pagination</span>, - <span class="st st-sg">'</span><span class="st">posts</span><span class="st st-sg">'</span>: <span class="name">real_posts</span> - - } - - -<span class="kw">def </span><span class="fun">get_last_thread_change</span>(<span class="name">req</span>, <span class="name">post_id</span>): - <span class="st st-db">"""</span><span class="st"> - Return the timestamp of the last change in the thread. - ``post_id`` must be the root_post_id, there is no further - check done. - - Return ``None`` if something in the query went wrong (eg. - no thread with the requested root_post_id exists) - </span><span class="st st-db">"""</span> - <span class="cm">#XXX: doesn't cover edits</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">posts</span>.<span class="name">c</span>.<span class="name">timestamp</span>], - (<span class="name">posts</span>.<span class="name">c</span>.<span class="name">root_post_id</span> <span class="op">==</span> <span class="name">post_id</span>), - <span class="name">order_by</span><span class="op">=</span>[<span class="name">meta</span>.<span class="name">desc</span>(<span class="name">posts</span>.<span class="name">c</span>.<span class="name">post_id</span>)], - <span class="name">limit</span><span class="op">=</span><span class="nb nb-int">1</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="kw">return</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">get_posts_per_page</span>(<span class="name">req</span>): - <span class="st st-db">"""</span><span class="st"> - Return the number of posts a user wishes to display on the - flat view page. - </span><span class="st st-db">"""</span> - <span class="kw">try</span>: - <span class="name">posts_per_page</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">settings</span>[<span class="st st-sg">'</span><span class="st">posts_per_page</span><span class="st st-sg">'</span>] - <span class="kw">if</span> <span class="name">posts_per_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">posts_per_page</span> - - <span class="kw">except</span> <span class="exc">KeyError</span>: - <span class="kw">pass</span> - <span class="kw">return</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">posts_per_page</span><span class="st st-sg">'</span>, <span class="nb nb-int">15</span>) - - - -<span class="kw">def </span><span class="fun">get_threads_per_page</span>(<span class="name">req</span>): - <span class="st st-db">"""</span><span class="st"> - Return the number of posts a users whishes to display on the - viewforum page. - </span><span class="st st-db">"""</span> - <span class="kw">try</span>: - <span class="name">threads_per_page</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">user</span>.<span class="name">settings</span>[<span class="st st-sg">'</span><span class="st">threads_per_page</span><span class="st st-sg">'</span>] - <span class="kw">if</span> <span class="name">threads_per_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">threads_per_page</span> - - <span class="kw">except</span> <span class="exc">KeyError</span>: - <span class="kw">pass</span> - <span class="kw">return</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">threads_per_page</span><span class="st st-sg">'</span>, <span class="nb nb-int">20</span>) - - - -<span class="kw">def </span><span class="fun">get_view_mode</span>(<span class="name">req</span>): - <span class="st st-db">"""</span><span class="st"> - Return the display mode a user has defined in the user settings - or fall back to the default mode from the pocoo.conf. - - :return: either ``'flat'`` or ``'threaded'``. - </span><span class="st st-db">"""</span> - <span class="name">val</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="kw">if</span> <span class="name">val</span> <span class="op op-word">in</span> (<span class="st st-sg">'</span><span class="st">flat</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="kw">return</span> <span class="name">val</span> - - <span class="name">val</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">default_view</span><span class="st st-sg">'</span>, <span class="bn bn-pseudo">None</span>) - <span class="kw">return</span> (<span class="name">val</span> <span class="op op-word">in</span> (<span class="st st-sg">'</span><span class="st">flat</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="op op-word">and</span> <span class="name">val</span> <span class="op op-word">or</span> <span class="st st-sg">'</span><span class="st">threaded</span><span class="st st-sg">'</span> - - -<span class="kw">def </span><span class="fun">quote_post</span>(<span class="name">req</span>, <span class="name">post_id</span>): - <span class="st st-db">"""</span><span class="st"> - Return a tuple in the form ``(text, title)`` which is useful - for replying and quoting existing posts. The title is - prefixed with a local representation of 'Re:' and the text - is quoted with the selected markup. - </span><span class="st st-db">"""</span> - <span class="name">p</span> <span class="op">=</span> <span class="name">posts</span>.<span class="name">c</span> - - <span class="name">u</span> <span class="op">=</span> <span class="name">users</span>.<span class="name">c</span> - <span class="name">_</span> <span class="op">=</span> <span class="name">req</span>.<span class="name">gettext</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">p</span>.<span class="name">title</span>, <span class="name">p</span>.<span class="name">text</span>, <span class="name">u</span>.<span class="name">username</span>], - (<span class="name">p</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="name">post_id</span>) <span class="op">&</span> - - (<span class="name">u</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">p</span>.<span class="name">author_id</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: ValueError?</span> - - <span class="kw">raise</span> <span class="exc">ValueError</span>(<span class="st st-sg">'</span><span class="st">post </span><span class="st st-int">%s</span><span class="st"> does not exist</span><span class="st st-sg">'</span>) - - <span class="name">suffix</span> <span class="op">=</span> <span class="name">_</span>(<span class="st st-sg">'</span><span class="st">Re:</span><span class="st st-sg">'</span>) - <span class="name">title</span> <span class="op">=</span> <span class="name">row</span>[<span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span>] - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">title</span>.<span class="name">startswith</span>(<span class="name">suffix</span>): - <span class="name">title</span> <span class="op">=</span> <span class="name">u</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">suffix</span>, <span class="name">title</span>) - <span class="name">text</span> <span class="op">=</span> <span class="name">quote_text</span>(<span class="name">req</span>, <span class="name">row</span>[<span class="st st-sg">'</span><span class="st">text</span><span class="st st-sg">'</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">text</span>, <span class="name">title</span> - - -<span class="kw">def </span><span class="fun">edit_post</span>(<span class="name">req</span>, <span class="name">post_id</span>): - <span class="st st-db">"""</span><span class="st"> - Return a tuple in the form (``text``, ``title``, ``username``) - for the edit view. - - :see: `quote_post` - </span><span class="st st-db">"""</span> - <span class="name">p</span> <span class="op">=</span> <span class="name">posts</span>.<span class="name">c</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">p</span>.<span class="name">text</span>, <span class="name">p</span>.<span class="name">title</span>, <span class="name">p</span>.<span class="name">username</span>], - (<span class="name">p</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="name">post_id</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: ValueError?</span> - - <span class="kw">raise</span> <span class="exc">ValueError</span>(<span class="st st-sg">'</span><span class="st">post </span><span class="st st-int">%s</span><span class="st"> does not exist</span><span class="st st-sg">'</span>) - <span class="kw">return</span> <span class="bn">tuple</span>(<span class="name">row</span>) - - -<span class="kw">class </span><span class="cls">_Site</span>(<span class="bn">object</span>): - <span class="st st-db">"""</span><span class="st">A special singleton representing a whole site.</span><span class="st st-db">"""</span> - - <span class="name">object_id</span> <span class="op">=</span> <span class="nb nb-int">0</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="name">Site</span> <span class="op">=</span> <span class="name">_Site</span>() - - -<span class="kw">class </span><span class="cls">Forum</span>(<span class="name">DatabaseModel</span>): - <span class="st st-db">"""</span><span class="st"> - This class represents one forum. Don't pass instances of this - class to templates, therefore there are some other functions - in this module. - - The main purpose of this class is the creation and management - of forums. You can also use this class for the ACL functions. - </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">forum_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">forum_id</span> <span class="op">=</span> <span class="name">forum_id</span> - <span class="bn">super</span>(<span class="name">Forum</span>, <span class="bn bn-pseudo">self</span>).<span class="name">__init__</span>(<span class="name">ctx</span>, <span class="name">forums</span>, <span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>) - - <span class="name">parent_id</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">parent_id</span><span class="st st-sg">'</span>) - <span class="name">object_id</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">object_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">description</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">description</span><span class="st st-sg">'</span>) - <span class="name">position</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">position</span><span class="st st-sg">'</span>) - <span class="name">link</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">link</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">description</span><span class="op">=</span><span class="st st-db">""</span>, <span class="name">parent</span><span class="op">=</span><span class="bn bn-pseudo">None</span>, <span class="name">position</span><span class="op">=</span><span class="bn bn-pseudo">None</span>, - <span class="name">link</span><span class="op">=</span><span class="bn bn-pseudo">None</span>): - <span class="st st-db">"""</span><span class="st">Create a new forum.</span><span class="st st-db">"""</span> - - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="name">parent</span>, <span class="name">Forum</span>): - <span class="name">parent</span> <span class="op">=</span> <span class="name">parent</span>.<span class="name">forum_id</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">forums</span>.<span class="name">insert</span>(), - <span class="name">parent_id</span><span class="op">=</span><span class="name">parent</span>, - <span class="name">name</span><span class="op">=</span><span class="name">name</span>, - <span class="name">description</span><span class="op">=</span><span class="name">description</span>, - <span class="name">position</span><span class="op">=</span><span class="name">position</span>, - <span class="name">link</span><span class="op">=</span><span class="name">link</span>, - <span class="name">post_count</span><span class="op">=</span><span class="nb nb-int">0</span>, - <span class="name">thread_count</span><span class="op">=</span><span class="nb nb-int">0</span> - - ) - <span class="kw">return</span> <span class="name">Forum</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">parent_get</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">return</span> <span class="name">Forum</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, <span class="bn bn-pseudo">self</span>.<span class="name">parent_id</span>) - <span class="kw">def </span><span class="fun">parent_set</span>(<span class="bn bn-pseudo">self</span>, <span class="name">value</span>): - <span class="kw">if</span> <span class="name">value</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">parent_id</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="name">value</span>, <span class="name">Forum</span>): - <span class="bn bn-pseudo">self</span>.<span class="name">parent_id</span> <span class="op">=</span> <span class="name">value</span>.<span class="name">forum_id</span> - - <span class="name">parent</span> <span class="op">=</span> <span class="bn">property</span>(<span class="name">parent_get</span>, <span class="name">parent_set</span>) - <span class="kw">del</span> <span class="name">parent_get</span>, <span class="name">parent_set</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">forum_id</span>, - <span class="bn bn-pseudo">self</span>.<span class="name">name</span> - - ) - - -<span class="kw">class </span><span class="cls">Thread</span>(<span class="name">DatabaseModel</span>): - <span class="st st-db">"""</span><span class="st"> - This class represents a root post with all of its children. - You can use this class to manage a thread, add a new reply - or edit one of its children. - </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">root_post_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">post_id</span> <span class="op">=</span> <span class="name">root_post_id</span> - <span class="bn">super</span>(<span class="name">Thread</span>, <span class="bn bn-pseudo">self</span>).<span class="name">__init__</span>(<span class="name">ctx</span>, <span class="name">posts</span>, <span class="st st-sg">'</span><span class="st">post_id</span><span class="st st-sg">'</span>, - <span class="name">posts</span>.<span class="name">c</span>.<span class="name">parent_id</span> <span class="op">==</span> <span class="bn bn-pseudo">None</span> - - ) - - <span class="name">forum_id</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">forum_id</span><span class="st st-sg">'</span>) - <span class="name">parent_id</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">parent_id</span><span class="st st-sg">'</span>) - <span class="name">root_post_id</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">root_post_id</span><span class="st st-sg">'</span>) - <span class="name">object_id</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">object_id</span><span class="st st-sg">'</span>) - <span class="name">author_id</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">author_id</span><span class="st st-sg">'</span>) - <span class="name">title</span> <span class="op">=</span> <span class="name">lazy_column</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">lazy_column</span>(<span class="st st-sg">'</span><span class="st">text</span><span class="st st-sg">'</span>) - <span class="name">timestamp</span> <span class="op">=</span> <span class="name">lazy_column</span>(<span class="st st-sg">'</span><span class="st">timestamp</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">forum</span>, <span class="name">author</span>, <span class="name">title</span>, <span class="name">text</span>, <span class="name">timestamp</span><span class="op">=</span><span class="bn bn-pseudo">None</span>): - <span class="st st-db">"""</span><span class="st">Create a new thread. - If author is a string it will be an anonymous posting.</span><span class="st st-db">"""</span> - - <span class="name">username</span> <span class="op">=</span> <span class="bn bn-pseudo">None</span> - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="name">forum</span>, <span class="name">Forum</span>): - <span class="name">forum</span> <span class="op">=</span> <span class="name">forum</span>.<span class="name">forum_id</span> - - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="name">author</span>, <span class="name">User</span>): - <span class="name">author</span> <span class="op">=</span> <span class="name">author</span>.<span class="name">user_id</span> - - <span class="kw">elif</span> <span class="bn">isinstance</span>(<span class="name">author</span>, <span class="bn">basestring</span>): - <span class="name">username</span> <span class="op">=</span> <span class="name">author</span> - <span class="name">author</span> <span class="op">=</span> <span class="name">ANONYMOUS_USER_ID</span> - - <span class="kw">if</span> <span class="name">timestamp</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="name">timestamp</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">result</span> <span class="op">=</span> <span class="name">con</span>.<span class="name">execute</span>(<span class="name">posts</span>.<span class="name">insert</span>(), - <span class="name">forum_id</span> <span class="op">=</span> <span class="name">forum</span>, - <span class="name">author_id</span> <span class="op">=</span> <span class="name">author</span>, - <span class="name">username</span> <span class="op">=</span> <span class="name">username</span>, - <span class="name">title</span> <span class="op">=</span> <span class="name">title</span>, - <span class="name">text</span> <span class="op">=</span> <span class="name">text</span>, - <span class="name">timestamp</span> <span class="op">=</span> <span class="name">timestamp</span>, - <span class="name">post_count</span> <span class="op">=</span> <span class="nb nb-int">1</span>, - <span class="name">view_count</span> <span class="op">=</span> <span class="nb nb-int">0</span> - - ) - <span class="name">thread_id</span> <span class="op">=</span> <span class="name">result</span>.<span class="name">last_inserted_ids</span>()[<span class="op">-</span><span class="nb nb-int">1</span>] - <span class="cm"># increment author post count</span> - <span class="kw">if</span> <span class="name">author</span> <span class="op">></span> <span class="op">-</span><span class="nb nb-int">1</span>: - <span class="name">old</span> <span class="op">=</span> <span class="name">meta</span>.<span class="name">select</span>([<span class="name">users</span>.<span class="name">c</span>.<span class="name">post_count</span>], <span class="name">users</span>.<span class="name">c</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">author</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">author</span>), - <span class="name">post_count</span> <span class="op">=</span> <span class="name">con</span>.<span class="name">execute</span>(<span class="name">old</span>).<span class="name">fetchone</span>()[<span class="nb nb-int">0</span>] <span class="op">+</span> <span class="nb nb-int">1</span> - - ) - <span class="cm"># increment forum post and thread count</span> - <span class="name">old</span> <span class="op">=</span> <span class="name">meta</span>.<span class="name">select</span>([<span class="name">forums</span>.<span class="name">c</span>.<span class="name">post_count</span>, <span class="name">forums</span>.<span class="name">c</span>.<span class="name">thread_count</span>], - <span class="name">forums</span>.<span class="name">c</span>.<span class="name">forum_id</span> <span class="op">==</span> <span class="name">forum</span>) - <span class="name">row</span> <span class="op">=</span> <span class="name">con</span>.<span class="name">execute</span>(<span class="name">old</span>).<span class="name">fetchone</span>() - <span class="name">con</span>.<span class="name">execute</span>(<span class="name">forums</span>.<span class="name">update</span>(<span class="name">forums</span>.<span class="name">c</span>.<span class="name">forum_id</span> <span class="op">==</span> <span class="name">forum</span>), - <span class="name">post_count</span> <span class="op">=</span> <span class="name">row</span>[<span class="nb nb-int">0</span>] <span class="op">+</span> <span class="nb nb-int">1</span>, - <span class="name">thread_count</span> <span class="op">=</span> <span class="name">row</span>[<span class="nb nb-int">1</span>] <span class="op">+</span> <span class="nb nb-int">1</span>, - <span class="name">last_post_id</span> <span class="op">=</span> <span class="name">thread_id</span> - - ) - <span class="kw">return</span> <span class="name">thread_id</span> - <span class="name">thread_id</span> <span class="op">=</span> <span class="name">ctx</span>.<span class="name">engine</span>.<span class="name">transaction</span>(<span class="name">do</span>) - <span class="cm"># XXX: this feels a bit strange</span> - - <span class="name">t</span> <span class="op">=</span> <span class="name">Thread</span>(<span class="name">ctx</span>, <span class="name">thread_id</span>) - <span class="name">t</span>.<span class="name">root_post_id</span> <span class="op">=</span> <span class="name">t</span>.<span class="name">post_id</span> - - <span class="name">t</span>.<span class="name">save</span>() - <span class="kw">return</span> <span class="name">t</span> - - <span class="deco">@staticmethod</span> - <span class="kw">def </span><span class="fun">by_child</span>(<span class="name">ctx</span>, <span class="name">post_id</span>): - <span class="st st-db">"""</span><span class="st"> - - Return the thread of a given ``post_id``. - </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">posts</span>.<span class="name">c</span>.<span class="name">root_post_id</span>], - (<span class="name">posts</span>.<span class="name">c</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="name">post_id</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: ValueError?</span> - - <span class="kw">raise</span> <span class="exc">ValueError</span>(<span class="st st-sg">'</span><span class="st">post </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">post_id</span>) - <span class="kw">return</span> <span class="name">Thread</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">reply</span>(<span class="bn bn-pseudo">self</span>, <span class="name">post_id</span>, <span class="name">author</span>, <span class="name">title</span>, <span class="name">text</span>, <span class="name">timestamp</span><span class="op">=</span><span class="bn bn-pseudo">None</span>, - <span class="name">no_processor</span><span class="op">=</span><span class="bn bn-pseudo">False</span>): - <span class="st st-db">"""</span><span class="st"> - - Reply to post ``post_id`` which is a child of the thread. - Return the id of the new post. - - If ``author`` is a string it will be an anonymous posting. - </span><span class="st st-db">"""</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">post_id</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="name">post_id</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">post_id</span> - - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="name">author</span>, <span class="name">User</span>): - <span class="name">author</span> <span class="op">=</span> <span class="name">author</span>.<span class="name">user_id</span> - - <span class="kw">elif</span> <span class="bn">isinstance</span>(<span class="name">author</span>, <span class="bn">basestring</span>): - <span class="name">username</span> <span class="op">=</span> <span class="name">author</span> - <span class="name">author</span> <span class="op">=</span> <span class="name">ANONYMOUS_USER_ID</span> - - <span class="kw">if</span> <span class="name">timestamp</span> <span class="op op-word">is</span> <span class="bn bn-pseudo">None</span>: - <span class="name">timestamp</span> <span class="op">=</span> <span class="name">datetime</span>.<span class="name">utcnow</span>() - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">no_processor</span>: - <span class="name">text</span>, <span class="name">title</span> <span class="op">=</span> <span class="name">apply_post_processors</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, <span class="name">text</span>, - <span class="name">title</span>, <span class="st st-sg">'</span><span class="st">new</span><span class="st st-sg">'</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">posts</span>.<span class="name">c</span>.<span class="name">root_post_id</span>], - <span class="name">posts</span>.<span class="name">c</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="name">post_id</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="op op-word">or</span> <span class="name">row</span>[<span class="nb nb-int">0</span>] <span class="op">!=</span> <span class="bn">int</span>(<span class="bn bn-pseudo">self</span>.<span class="name">post_id</span>): - <span class="cm"># XXX: ValueError?</span> - - <span class="kw">raise</span> <span class="exc">ValueError</span>(<span class="st st-sg">'</span><span class="st">The post either does not exist or does not </span><span class="st st-sg">'</span> - <span class="st st-sg">'</span><span class="st">belong to this thread</span><span class="st st-sg">'</span>) - <span class="name">new_post_id</span> <span class="op">=</span> <span class="name">con</span>.<span class="name">execute</span>(<span class="name">posts</span>.<span class="name">insert</span>(), - <span class="name">forum_id</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">forum_id</span>, - <span class="name">parent_id</span> <span class="op">=</span> <span class="name">post_id</span>, - <span class="name">root_post_id</span> <span class="op">=</span> <span class="bn bn-pseudo">self</span>.<span class="name">post_id</span>, - <span class="name">author_id</span> <span class="op">=</span> <span class="name">author</span>, - <span class="name">username</span> <span class="op">=</span> <span class="name">username</span>, - <span class="name">title</span> <span class="op">=</span> <span class="name">title</span>, - <span class="name">text</span> <span class="op">=</span> <span class="name">text</span>, - <span class="name">timestamp</span> <span class="op">=</span> <span class="name">timestamp</span> - - ).<span class="name">last_inserted_ids</span>()[<span class="nb nb-int">0</span>] - - <span class="cm"># increment author post count</span> - <span class="kw">if</span> <span class="name">author</span> <span class="op">></span> <span class="op">-</span><span class="nb nb-int">1</span>: - <span class="name">old</span> <span class="op">=</span> <span class="name">meta</span>.<span class="name">select</span>([<span class="name">users</span>.<span class="name">c</span>.<span class="name">post_count</span>], <span class="name">users</span>.<span class="name">c</span>.<span class="name">user_id</span> <span class="op">==</span> <span class="name">author</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">author</span>), - <span class="name">post_count</span> <span class="op">=</span> <span class="name">con</span>.<span class="name">execute</span>(<span class="name">old</span>).<span class="name">fetchone</span>()[<span class="nb nb-int">0</span>] <span class="op">+</span> <span class="nb nb-int">1</span> - - ) - <span class="cm"># increment forum post count and update last_post_id</span> - <span class="name">old</span> <span class="op">=</span> <span class="name">meta</span>.<span class="name">select</span>([<span class="name">forums</span>.<span class="name">c</span>.<span class="name">post_count</span>], - <span class="name">forums</span>.<span class="name">c</span>.<span class="name">forum_id</span> <span class="op">==</span> <span class="bn bn-pseudo">self</span>.<span class="name">forum_id</span>) - <span class="name">con</span>.<span class="name">execute</span>(<span class="name">forums</span>.<span class="name">update</span>(<span class="name">forums</span>.<span class="name">c</span>.<span class="name">forum_id</span> <span class="op">==</span> <span class="bn bn-pseudo">self</span>.<span class="name">forum_id</span>), - <span class="name">post_count</span> <span class="op">=</span> <span class="name">con</span>.<span class="name">execute</span>(<span class="name">old</span>).<span class="name">fetchone</span>()[<span class="nb nb-int">0</span>] <span class="op">+</span> <span class="nb nb-int">1</span>, - <span class="name">last_post_id</span> <span class="op">=</span> <span class="name">new_post_id</span> - - ) - <span class="cm"># increment thread post count</span> - <span class="name">old</span> <span class="op">=</span> <span class="name">meta</span>.<span class="name">select</span>([<span class="name">posts</span>.<span class="name">c</span>.<span class="name">post_count</span>], - <span class="name">posts</span>.<span class="name">c</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="bn bn-pseudo">self</span>.<span class="name">post_id</span>) - <span class="name">con</span>.<span class="name">execute</span>(<span class="name">posts</span>.<span class="name">update</span>(<span class="name">posts</span>.<span class="name">c</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="bn bn-pseudo">self</span>.<span class="name">post_id</span>), - <span class="name">post_count</span> <span class="op">=</span> <span class="name">con</span>.<span class="name">execute</span>(<span class="name">old</span>).<span class="name">fetchone</span>()[<span class="nb nb-int">0</span>] <span class="op">+</span> <span class="nb nb-int">1</span> - - ) - <span class="kw">return</span> <span class="name">new_post_id</span> - <span class="kw">return</span> <span class="bn bn-pseudo">self</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">edit_reply</span>(<span class="bn bn-pseudo">self</span>, <span class="name">post_id</span>, <span class="name">author</span><span class="op">=</span><span class="name">_missing</span>, <span class="name">title</span><span class="op">=</span><span class="name">_missing</span>, - <span class="name">text</span><span class="op">=</span><span class="name">_missing</span>, <span class="name">timestamp</span><span class="op">=</span><span class="name">_missing</span>, - <span class="name">no_processor</span><span class="op">=</span><span class="bn bn-pseudo">False</span>): - <span class="st st-db">"""</span><span class="st">Edit a reply.</span><span class="st st-db">"""</span> - - <span class="name">d</span> <span class="op">=</span> {} - <span class="kw">if</span> <span class="name">author</span> <span class="op op-word">is</span> <span class="op op-word">not</span> <span class="name">_missing</span>: - <span class="kw">if</span> <span class="bn">isinstance</span>(<span class="name">author</span>, <span class="name">User</span>): - <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">author_id</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">author</span>.<span class="name">user_id</span> <span class="cm"># pylint: disable-msg=E1101</span> - - <span class="kw">else</span>: - <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">author_id</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">author</span> - <span class="kw">if</span> <span class="name">title</span> <span class="op op-word">is</span> <span class="op op-word">not</span> <span class="name">_missing</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="op">=</span> <span class="name">title</span> - - <span class="kw">if</span> <span class="name">text</span> <span class="op op-word">is</span> <span class="op op-word">not</span> <span class="name">_missing</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="op">=</span> <span class="name">text</span> - - <span class="kw">if</span> <span class="name">timestamp</span> <span class="op op-word">is</span> <span class="op op-word">not</span> <span class="name">_missing</span>: - <span class="name">d</span>[<span class="st st-sg">'</span><span class="st">timestamp</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">timestamp</span> - - <span class="kw">if</span> <span class="op op-word">not</span> <span class="name">no_processor</span> <span class="op op-word">and</span> <span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span> <span class="op op-word">in</span> <span class="name">d</span> <span class="op op-word">and</span> <span class="st st-sg">'</span><span class="st">text</span><span class="st st-sg">'</span> <span class="op op-word">in</span> <span class="name">d</span>: - <span class="name">rv</span> <span class="op">=</span> <span class="name">apply_post_processors</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</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="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">edit</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="name">d</span>[<span class="st st-sg">'</span><span class="st">title</span><span class="st st-sg">'</span>] <span class="op">=</span> <span class="name">rv</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">posts</span>.<span class="name">update</span>(<span class="name">posts</span>.<span class="name">c</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="name">post_id</span>), <span class="op">**</span><span class="name">d</span>) - - <span class="kw">def </span><span class="fun">has_child</span>(<span class="bn bn-pseudo">self</span>, <span class="name">post_id</span>): - <span class="st st-db">"""</span><span class="st">Check if a post_id is a child of this thread.</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">posts</span>.<span class="name">c</span>.<span class="name">root_post_id</span>], - <span class="name">posts</span>.<span class="name">c</span>.<span class="name">post_id</span> <span class="op">==</span> <span class="name">post_id</span> - - )) - <span class="name">row</span> <span class="op">=</span> <span class="name">result</span>.<span class="name">fetchone</span>() - <span class="kw">return</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="name">row</span>[<span class="st st-sg">'</span><span class="st">root_post_id</span><span class="st st-sg">'</span>] <span class="op">==</span> <span class="bn bn-pseudo">self</span>.<span class="name">post_id</span> - - <span class="kw">def </span><span class="fun">get_post_list</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st"> - Return a flat list of all posts in this thread sorted by their post_id. - </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">posts</span>.<span class="name">select</span>( - <span class="name">posts</span>.<span class="name">c</span>.<span class="name">root_post_id</span> <span class="op">==</span> <span class="bn bn-pseudo">self</span>.<span class="name">post_id</span> - - )) - <span class="kw">return</span> <span class="bn">map</span>(<span class="bn">dict</span>, <span class="name">result</span>) - - <span class="kw">def </span><span class="fun">count_children</span>(<span class="bn bn-pseudo">self</span>): - <span class="st st-db">"""</span><span class="st"> - Return the number of direct or indirect children of this thread. - </span><span class="st st-db">"""</span> - - <span class="name">p</span> <span class="op">=</span> <span class="name">posts</span>.<span class="name">c</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">meta</span>.<span class="name">func</span>.<span class="name">count</span>(<span class="name">p</span>.<span class="name">post_id</span>)], - <span class="name">p</span>.<span class="name">root_post_id</span> <span class="op">==</span> <span class="bn bn-pseudo">self</span>.<span class="name">post_id</span> - - )) - <span class="kw">return</span> <span class="name">result</span>.<span class="name">fetchone</span>()[<span class="nb nb-int">0</span>] - - <span class="name">__len__</span> <span class="op">=</span> <span class="name">count_children</span> - - <span class="kw">def </span><span class="fun">forum_get</span>(<span class="bn bn-pseudo">self</span>): - <span class="kw">if</span> <span class="bn bn-pseudo">self</span>.<span class="name">forum_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="kw">return</span> <span class="name">Forum</span>(<span class="bn bn-pseudo">self</span>.<span class="name">ctx</span>, <span class="bn bn-pseudo">self</span>.<span class="name">forum_id</span>) - <span class="kw">def </span><span class="fun">forum_set</span>(<span class="bn bn-pseudo">self</span>, <span class="name">value</span>): - <span class="kw">if</span> <span class="op op-word">not</span> <span class="bn">isinstance</span>(<span class="name">value</span>, <span class="name">Forum</span>): - <span class="kw">raise</span> <span class="exc">TypeError</span>(<span class="st st-sg">'</span><span class="st">Can only set Forum instances</span><span class="st st-sg">'</span>) - <span class="bn bn-pseudo">self</span>.<span class="name">forum_id</span> <span class="op">=</span> <span class="name">value</span>.<span class="name">forum_id</span> - - <span class="name">forum</span> <span class="op">=</span> <span class="bn">property</span>(<span class="name">forum_get</span>, <span class="name">forum_set</span>) - <span class="kw">del</span> <span class="name">forum_get</span>, <span class="name">forum_set</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">post_id</span> <span class="op">==</span> <span class="name">other</span>.<span class="name">post_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">post_id</span>, - <span class="bn bn-pseudo">self</span>.<span class="name">title</span> - - ) -<span class="cm"># -*- coding: utf-8 -*-</span> -</pre> -<script type="text/javascript">initCodeBlock('code-block')</script> -</body> -</html> diff --git a/tests/test_examplefiles.py b/tests/test_examplefiles.py index 93bbab16..ee9c78af 100644 --- a/tests/test_examplefiles.py +++ b/tests/test_examplefiles.py @@ -7,8 +7,8 @@ :license: BSD, see LICENSE for more details. """ -import unittest import os +import unittest from pygments import highlight from pygments.lexers import get_lexer_for_filename, get_lexer_by_name diff --git a/tests/test_latex_formatter.py b/tests/test_latex_formatter.py new file mode 100644 index 00000000..376abb81 --- /dev/null +++ b/tests/test_latex_formatter.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +""" + Pygments LaTeX formatter tests + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + :copyright: 2006-2007 by Georg Brandl. + :license: BSD, see LICENSE for more details. +""" + +import os +import unittest +import StringIO +import tempfile + +from pygments import lexers, formatters +from pygments.token import _TokenType +from pygments.formatters import LatexFormatter +from pygments.lexers import PythonLexer + + +class LatexFormatterTest(unittest.TestCase): + + def test_valid_output(self): + tokensource = list(PythonLexer().get_tokens(file(os.path.join(testdir, testfile)).read())) + fmt = LatexFormatter(full=True) + + handle, pathname = tempfile.mkstemp('.tex') + # place all output files in /tmp too + old_wd = os.getcwd() + os.chdir(os.path.dirname(pathname)) + tfile = os.fdopen(handle, 'w+b') + fmt.format(tokensource, tfile) + tfile.close() + try: + try: + import subprocess + ret = subprocess.Popen(['latex', '-interaction=nonstopmode', pathname], + stdout=subprocess.PIPE).wait() + except ImportError: + # Python 2.3 - no subprocess module + ret = os.popen('latex -interaction=nonstopmode "%s"' % pathname).close() + if ret == 32512: raise OSError # not found + except OSError: + # latex not available + pass + else: + self.failIf(ret, 'latex run reported errors') + + os.unlink(pathname) + os.chdir(old_wd) |