/* This module provides the suite of standard class-based exceptions for * Python's builtin module. This is a complete C implementation of what, * in Python 1.5.2, was contained in the exceptions.py module. The problem * there was that if exceptions.py could not be imported for some reason, * the entire interpreter would abort. * * By moving the exceptions into C and statically linking, we can guarantee * that the standard exceptions will always be available. * * history: * 98-08-19 fl created (for pyexe) * 00-02-08 fl updated for 1.5.2 * 26-May-2000 baw vetted for Python 1.6 * * written by Fredrik Lundh * modifications, additions, cleanups, and proofreading by Barry Warsaw * * Copyright (c) 1998-2000 by Secret Labs AB. All rights reserved. */ #include "Python.h" #include "osdefs.h" /* Caution: MS Visual C++ 6 errors if a single string literal exceeds * 2Kb. So the module docstring has been broken roughly in half, using * compile-time literal concatenation. */ /* NOTE: If the exception class hierarchy changes, don't forget to update * Doc/lib/libexcs.tex! */ PyDoc_STRVAR(module__doc__, "Python's standard exception class hierarchy.\n\ \n\ Before Python 1.5, the standard exceptions were all simple string objects.\n\ In Python 1.5, the standard exceptions were converted to classes organized\n\ into a relatively flat hierarchy. String-based standard exceptions were\n\ optional, or used as a fallback if some problem occurred while importing\n\ the exception module. With Python 1.6, optional string-based standard\n\ exceptions were removed (along with the -X command line flag).\n\ \n\ The class exceptions were implemented in such a way as to be almost\n\ completely backward compatible. Some tricky uses of IOError could\n\ potentially have broken, but by Python 1.6, all of these should have\n\ been fixed. As of Python 1.6, the class-based standard exceptions are\n\ now implemented in C, and are guaranteed to exist in the Python\n\ interpreter.\n\ \n\ Here is a rundown of the class hierarchy. The classes found here are\n\ inserted into both the exceptions module and the `built-in' module. It is\n\ recommended that user defined class based exceptions be derived from the\n\ `Exception' class, although this is currently not enforced.\n" /* keep string pieces "small" */ "\n\ Exception\n\ |\n\ +-- SystemExit\n\ +-- StopIteration\n\ +-- StandardError\n\ | |\n\ | +-- KeyboardInterrupt\n\ | +-- ImportError\n\ | +-- EnvironmentError\n\ | | |\n\ | | +-- IOError\n\ | | +-- OSError\n\ | | |\n\ | | +-- WindowsError\n\ | | +-- VMSError\n\ | |\n\ | +-- EOFError\n\ | +-- RuntimeError\n\ | | |\n\ | | +-- NotImplementedError\n\ | |\n\ | +-- NameError\n\ | | |\n\ | | +-- UnboundLocalError\n\ | |\n\ | +-- AttributeError\n\ | +-- SyntaxError\n\ | | |\n\ | | +-- IndentationError\n\ | | |\n\ | | +-- TabError\n\ | |\n\ | +-- TypeError\n\ | +-- AssertionError\n\ | +-- LookupError\n\ | | |\n\ | | +-- IndexError\n\ | | +-- KeyError\n\ | |\n\ | +-- ArithmeticError\n\ | | |\n\ | | +-- OverflowError\n\ | | +-- ZeroDivisionError\n\ | | +-- FloatingPointError\n\ | |\n\ | +-- ValueError\n\ | | |\n\ | | +-- UnicodeError\n\ | | |\n\ | | +-- UnicodeEncodeError\n\ | | +-- UnicodeDecodeError\n\ | | +-- UnicodeTranslateError\n\ | |\n\ | +-- ReferenceError\n\ | +-- SystemError\n\ | +-- MemoryError\n\ |\n\ +---Warning\n\ |\n\ +-- UserWarning\n\ +-- DeprecationWarning\n\ +-- PendingDeprecationWarning\n\ +-- SyntaxWarning\n\ +-- OverflowWarning\n\ +-- RuntimeWarning\n\ +-- FutureWarning" ); /* Helper function for populating a dictionary with method wrappers. */ static int populate_methods(PyObject *klass, PyObject *dict, PyMethodDef *methods) { if (!methods) return 0; while (methods->ml_name) { /* get a wrapper for the built-in function */ PyObject *func = PyCFunction_New(methods, NULL); PyObject *meth; int status; if (!func) return -1; /* turn the function into an unbound method */ if (!(meth = PyMethod_New(func, NULL, klass))) { Py_DECREF(func); return -1; } /* add method to dictionary */ status = PyDict_SetItemString(dict, methods->ml_name, meth); Py_DECREF(meth); Py_DECREF(func); /* stop now if an error occurred, otherwise do the next method */ if (status) return status; methods++; } return 0; } /* This function is used to create all subsequent exception classes. */ static int make_class(PyObject **klass, PyObject *base, char *name, PyMethodDef *methods, char *docstr) { PyObject *dict = PyDict_New(); PyObject *str = NULL; int status = -1; if (!dict) return -1; /* If an error occurs from here on, goto finally instead of explicitly * returning NULL. */ if (docstr) { if (!(str = PyString_FromString(docstr))) goto finally; if (PyDict_SetItemString(dict, "__doc__", str)) goto finally; } if (!(*klass = PyErr_NewException(name, base, dict))) goto finally; if (populate_methods(*klass, dict, methods)) { Py_DECREF(*klass); *klass = NULL; goto finally; } status = 0; finally: Py_XDECREF(dict); Py_XDECREF(str); return status; } /* Use this for *args signatures, otherwise just use PyArg_ParseTuple() */ static PyObject * get_self(PyObject *args) { PyObject *self = PyTuple_GetItem(args, 0); if (!self) { /* Watch out for being called to early in the bootstrapping process */ if (PyExc_TypeError) { PyErr_SetString(PyExc_TypeError, "unbound method must be called with instance as first argument"); } return NULL; } return self; } /* Notes on bootstrapping the exception classes. * * First thing we create is the base class for all exceptions, called * appropriately enough: Exception. Creation of this class makes no * assumptions about the existence of any other exception class -- except * for TypeError, which can conditionally exist. * * Next, StandardError is created (which is quite simple) followed by * TypeError, because the instantiation of other exceptions can potentially * throw a TypeError. Once these exceptions are created, all the others * can be created in any order. See the static exctable below for the * explicit bootstrap order. * * All classes after Exception can be created using PyErr_NewException(). */ PyDoc_STRVAR(Exception__doc__, "Common base class for all exceptions."); static PyObject * Exception__init__(PyObject *self, PyObject *args) { int status; if (!(self = get_self(args))) return NULL; /* set args attribute */ /* XXX size is only a hint */ args = PySequence_GetSlice(args, 1, PySequence_Size(args)); if (!args) return NULL; status = PyObject_SetAttrString(self, "args", args); Py_DECREF(args); if (status < 0) return NULL; Py_INCREF(Py_None); return Py_None; } static PyObject * Exception__str__(PyObject *self, PyObject *args) { PyObject *out; if (!PyArg_ParseTuple(args, "O:__str__", &self)) return NULL; args = PyObject_GetAttrString(self, "args"); if (!args) return NULL; switch (PySequence_Size(args)) { case 0: out = PyString_FromString(""); break; case 1: { PyObject *tmp = PySequence_GetItem(args, 0); if (tmp) { out = PyObject_Str(tmp); Py_DECREF(tmp); } else out = NULL; break; } case -1: PyErr_Clear(); /* Fall through */ default: out = PyObject_Str(args); break; } Py_DECREF(args); return out; } static PyObject * Exception__getitem__(PyObject *self, PyObject *args) { PyObject *out; PyObject *index; if (!PyArg_ParseTuple(args, "OO:__getitem__", &self, &index)) return NULL; args = PyObject_GetAttrString(self, "args"); if (!args) return NULL; out = PyObject_GetItem(args, index); Py_DECREF(args); return out; } static PyMethodDef Exception_methods[] = { /* methods for the Exception class */ { "__getitem__", Exception__getitem__, METH_VARARGS}, { "__str__", Exception__str__, METH_VARARGS}, { "__init__", Exception__init__, METH_VARARGS}, { NULL, NULL } }; static int make_Exception(char *modulename) { PyObject *dict = PyDict_New(); PyObject *str = NULL; PyObject *name = NULL; int status = -1; if (!dict) return -1; /* If an error occurs from here on, goto finally instead of explicitly * returning NULL. */ if (!(str = PyString_FromString(modulename))) goto finally; if (PyDict_SetItemString(dict, "__module__", str)) goto finally; Py_DECREF(str); if (!(str = PyString_FromString(Exception__doc__))) goto finally; if (PyDict_SetItemString(dict, "__doc__", str)) goto finally; if (!(name = PyString_FromString("Exception"))) goto finally; if (!(PyExc_Exception = PyClass_New(NULL, dict, name))) goto finally; /* Now populate the dictionary with the method suite */ if (populate_methods(PyExc_Exception, dict, Exception_methods)) /* Don't need to reclaim PyExc_Exception here because that'll * happen during interpreter shutdown. */ goto finally; status = 0; finally: Py_XDECREF(dict); Py_XDECREF(str); Py_XDECREF(name); return status; } PyDoc_STRVAR(StandardError__doc__, "Base class for all standard Python exceptions."); PyDoc_STRVAR(TypeError__doc__, "Inappropriate argument type."); PyDoc_STRVAR(StopIteration__doc__, "Signal the end from iterator.next()."); PyDoc_STRVAR(SystemExit__doc__, "Request to exit from the interpreter."); static PyObject * SystemExit__init__(PyObject *self, PyObject *args) { PyObject *code; int status; if (!(self = get_self(args))) return NULL; /* Set args attribute. */ if (!(args = PySequence_GetSlice(args, 1, PySequence_Size(args)))) return NULL; status = PyObject_SetAttrString(self, "args", args); if (status < 0) { Py_DECREF(args); return NULL; } /* set code attribute */ switch (PySequence_Size(args)) { case 0: Py_INCREF(Py_None); code = Py_None; break; case 1: code = PySequence_GetItem(args, 0); break; case -1: PyErr_Clear(); /* Fall through */ default: Py_INCREF(args); code = args; break; } status = PyObject_SetAttrString(self, "code", code); Py_DECREF(code); Py_DECREF(args); if (status < 0) return NULL; Py_INCREF(Py_None); return Py_None; } static PyMethodDef SystemExit_methods[] = { { "__init__", SystemExit__init__, METH_VARARGS}, {NULL, NULL} }; PyDoc_STRVAR(KeyboardInterrupt__doc__, "Program interrupted by user."); PyDoc_STRVAR(ImportError__doc__, "Import can't find module, or can't find name in module."); PyDoc_STRVAR(EnvironmentError__doc__, "Base class for I/O related errors."); static PyObject * EnvironmentError__init__(PyObject *self, PyObject *args) { PyObject *item0 = NULL; PyObject *item1 = NULL; PyObject *item2 = NULL; PyObject *subslice = NULL; PyObject *rtnval = NULL; if (!(self = get_self(args))) return NULL; if (!(args = PySequence_GetSlice(args, 1, PySequence_Size(args)))) return NULL; if (PyObject_SetAttrString(self, "args", args) || PyObject_SetAttrString(self, "errno", Py_None) || PyObject_SetAttrString(self, "strerror", Py_None) || PyObject_SetAttrString(self, "filename", Py_None)) { goto finally; } switch (PySequence_Size(args)) { case 3: /* Where a function has a single filename, such as open() or some * of the os module functions, PyErr_SetFromErrnoWithFilename() is * called, giving a third argument which is the filename. But, so * that old code using in-place unpacking doesn't break, e.g.: * * except IOError, (errno, strerror): * * we hack args so that it only contains two items. This also * means we need our own __str__() which prints out the filename * when it was supplied. */ item0 = PySequence_GetItem(args, 0); item1 = PySequence_GetItem(args, 1); item2 = PySequence_GetItem(args, 2); if (!item0 || !item1 || !item2) goto finally; if (PyObject_SetAttrString(self, "errno", item0) || PyObject_SetAttrString(self, "strerror", item1) || PyObject_SetAttrString(self, "filename", item2)) { goto finally; } subslice = PySequence_GetSlice(args, 0, 2); if (!subslice || PyObject_SetAttrString(self, "args", subslice)) goto finally; break; case 2: /* Used when PyErr_SetFromErrno() is called and no filename * argument is given. */ item0 = PySequence_GetItem(args, 0); item1 = PySequence_GetItem(args, 1); if (!item0 || !item1) goto finally; if (PyObject_SetAttrString(self, "errno", item0) || PyObject_SetAttrString(self, "strerror", item1)) { goto finally; } break; case -1: PyErr_Clear(); break; } Py_INCREF(Py_None); rtnval = Py_None; finally: Py_DECREF(args); Py_XDECREF(item0); Py_XDECREF(item1); Py_XDECREF(item2); Py_XDECREF(subslice); return rtnval; } static PyObject * EnvironmentError__str__(PyObject *self, PyObject *args) { PyObject *originalself = self; PyObject *filename; PyObject *serrno; PyObject *strerror; PyObject *rtnval = NULL; if (!PyArg_ParseTuple(args, "O:__str__", &self)) return NULL; filename = PyObject_GetAttrString(self, "filename"); serrno = PyObject_GetAttrString(self, "errno"); str#! /usr/bin/env python3 # Perform massive identifier substitution on C source files. # This actually tokenizes the files (to some extent) so it can # avoid making substitutions inside strings or comments. # Inside strings, substitutions are never made; inside comments, # it is a user option (off by default). # # The substitutions are read from one or more files whose lines, # when not empty, after stripping comments starting with #, # must contain exactly two words separated by whitespace: the # old identifier and its replacement. # # The option -r reverses the sense of the substitutions (this may be # useful to undo a particular substitution). # # If the old identifier is prefixed with a '*' (with no intervening # whitespace), then it will not be substituted inside comments. # # Command line arguments are files or directories to be processed. # Directories are searched recursively for files whose name looks # like a C file (ends in .h or .c). The special filename '-' means # operate in filter mode: read stdin, write stdout. # # Symbolic links are always ignored (except as explicit directory # arguments). # # The original files are kept as back-up with a "~" suffix. # # Changes made are reported to stdout in a diff-like format. # # NB: by changing only the function fixline() you can turn this # into a program for different changes to C source files; by # changing the function wanted() you can make a different selection of # files. import sys import re import os from stat import * import getopt err = sys.stderr.write dbg = err rep = sys.stdout.write def usage(): progname = sys.argv[0] err('Usage: ' + progname + ' [-c] [-r] [-s file] ... file-or-directory ...\n') err('\n') err('-c : substitute inside comments\n') err('-r : reverse direction for following -s options\n') err('-s substfile : add a file of substitutions\n') err('\n') err('Each non-empty non-comment line in a substitution file must\n') err('contain exactly two words: an identifier and its replacement.\n') err('Comments start with a # character and end at end of line.\n') err('If an identifier is preceded with a *, it is not substituted\n') err('inside a comment even when -c is specified.\n') def main(): try: opts, args = getopt.getopt(sys.argv[1:], 'crs:') except getopt.error as msg: err('Options error: ' + str(msg) + '\n') usage() sys.exit(2) bad = 0 if not args: # No arguments usage() sys.exit(2) for opt, arg in opts: if opt == '-c': setdocomments() if opt == '-r': setreverse() if opt == '-s': addsubst(arg) for arg in args: if os.path.isdir(arg): if recursedown(arg): bad = 1 elif os.path.islink(arg): err(arg + ': will not process symbolic links\n') bad = 1 else: if fix(arg): bad = 1 sys.exit(bad) # Change this regular expression to select a different set of files Wanted = '^[a-zA-Z0-9_]+\.[ch]$' def wanted(name): return re.match(Wanted, name) >= 0 def recursedown(dirname): dbg('recursedown(%r)\n' % (dirname,)) bad = 0 try: names = os.listdir(dirname) except os.error as msg: err(dirname + ': cannot list directory: ' + str(msg) + '\n') return 1 names.sort() subdirs = [] for name in names: if name in (os.curdir, os.pardir): continue fullname = os.path.join(dirname, name) if os.path.islink(fullname): pass elif os.path.isdir(fullname): subdirs.append(fullname) elif wanted(name): if fix(fullname): bad = 1 for fullname in subdirs: if recursedown(fullname): bad = 1 return bad def fix(filename): ## dbg('fix(%r)\n' % (filename,)) if filename == '-': # Filter mode f = sys.stdin g = sys.stdout else: # File replacement mode try: f = open(filename, 'r') except IOError as msg: err(filename + ': cannot open: ' + str(msg) + '\n') return 1 head, tail = os.path.split(filename) tempname = os.path.join(head, '@' + tail) g = None # If we find a match, we rewind the file and start over but # now copy everything to a temp file. lineno = 0 initfixline() while 1: line = f.readline() if not line: break lineno = lineno + 1 while line[-2:] == '\\\n': nextline = f.readline() if not nextline: break line = line + nextline lineno = lineno + 1 newline = fixline(line) if newline != line: if g is None: try: g = open(tempname, 'w') except IOError as msg: f.close() err(tempname+': cannot create: '+ str(msg)+'\n') return 1 f.seek(0) lineno = 0 initfixline() rep(filename + ':\n') continue # restart from the beginning rep(repr(lineno) + '\n') rep('< ' + line) rep('> ' + newline) if g is not None: g.write(newline) # End of file if filename == '-': return 0 # Done in filter mode f.close() if not g: return 0 # No changes # Finishing touch -- move files # First copy the file's mode to the temp file try: statbuf = os.stat(filename) os.chmod(tempname, statbuf[ST_MODE] & 0o7777) except os.error as msg: err(tempname + ': warning: chmod failed (' + str(msg) + ')\n') # Then make a backup of the original file as filename~ try: os.rename(filename, filename + '~') except os.error as msg: err(filename + ': warning: backup failed (' + str(msg) + ')\n') # Now move the temp file to the original file try: os.rename(tempname, filename) except os.error as msg: err(filename + ': rename failed (' + str(msg) + ')\n') return 1 # Return success return 0 # Tokenizing ANSI C (partly) Identifier = '\(struct \)?[a-zA-Z_][a-zA-Z0-9_]+' String = '"\([^\n\\"]\|\\\\.\)*"' Char = '\'\([^\n\\\']\|\\\\.\)*\'' CommentStart = '/\*' CommentEnd = '\*/' Hexnumber = '0[xX][0-9a-fA-F]*[uUlL]*' Octnumber = '0[0-7]*[uUlL]*' Decnumber = '[1-9][0-9]*[uUlL]*' Intnumber = Hexnumber + '\|' + Octnumber + '\|' + Decnumber Exponent = '[eE][-+]?[0-9]+' Pointfloat = '\([0-9]+\.[0-9]*\|\.[0-9]+\)\(' + Exponent + '\)?' Expfloat = '[0-9]+' + Exponent Floatnumber = Pointfloat + '\|' + Expfloat Number = Floatnumber + '\|' + Intnumber # Anything else is an operator -- don't list this explicitly because of '/*' OutsideComment = (Identifier, Number, String, Char, CommentStart) OutsideCommentPattern = '(' + '|'.join(OutsideComment) + ')' OutsideCommentProgram = re.compile(OutsideCommentPattern) InsideComment = (Identifier, Number, CommentEnd) InsideCommentPattern = '(' + '|'.join(InsideComment) + ')' InsideCommentProgram = re.compile(InsideCommentPattern) def initfixline(): global Program Program = OutsideCommentProgram def fixline(line): global Program ## print '-->', repr(line) i = 0 while i < len(line): i = Program.search(line, i) if i < 0: break found = Program.group(0) ## if Program is InsideCommentProgram: print '...', ## else: print ' ', ## print found if len(found) == 2: if found == '/*': Program = InsideCommentProgram elif found == '*/': Program = OutsideCommentProgram n = len(found) if found in Dict: subst = Dict[found] if Program is InsideCommentProgram: if not Docomments: print('Found in comment:', found) i = i + n continue if NotInComment.has_key(found): ## print 'Ignored in comment:', ## print found, '-->', subst ## print 'Line:', line, subst = found ## else: ## print 'Substituting in comment:', ## print found, '-->', subst ## print 'Line:', line, line = line[:i] + subst + line[i+n:] n = len(subst) i = i + n return line Docomments = 0 def setdocomments(): global