summaryrefslogtreecommitdiffstats
path: root/Python/Python-ast.c
Commit message (Collapse)AuthorAgeFilesLines
...
* closes bpo-38648: Remove double tp_free slot in Python-ast.c. (GH-17002)Max Bernstein2019-10-311-1/+0
| | | This looks like a typo due to copy-paste.
* bpo-38425: Fix ‘res’ may be used uninitialized warning (GH-16688)Dong-hee Na2019-10-101-1/+2
|
* bpo-38140: Make dict and weakref offsets opaque for C heap types (#16076)Eddie Elizondo2019-09-191-2/+7
| | | | | | * Make dict and weakref offsets opaque for C heap types * Add news
* Fix leaks in Python-ast.c (#16127)Eddie Elizondo2019-09-141-1/+5
|
* bpo-38113: Update the Python-ast.c generator to PEP384 (gh-15957)Dino Viehland2019-09-111-1388/+2462
| | | Summary: This mostly migrates Python-ast.c to PEP384 and removes all statics from the whole file. This modifies the generator itself that generates the Python-ast.c. It leaves in the usage of _PyObject_LookupAttr even though it's not fully PEP384 compatible (this could always be shimmed in by anyone who needs it).
* bpo-38083: Minor improvements in asdl_c.py and Python-ast.c. (GH-15824)Serhiy Storchaka2019-09-101-131/+307
| | | | | * Use the const qualifier for constant C strings. * Intern field and attribute names. * Temporary incref a borrowed reference to a list item.
* bpo-37593: Swap the positions of posonlyargs and args in the constructor of ↵Pablo Galindo2019-07-141-23/+23
| | | | | ast.parameters nodes (GH-14778) https://bugs.python.org/issue37593
* bpo-37253: Remove PyAST_obj2mod_ex() function (GH-14020)Victor Stinner2019-06-131-5/+0
| | | | PyAST_obj2mod_ex() is similar to PyAST_obj2mod() with an additional 'feature_version' parameter which is unused.
* bpo-36974: tp_print -> tp_vectorcall_offset and tp_reserved -> tp_as_async ↵Jeroen Demeyer2019-05-311-2/+2
| | | | | | | | | (GH-13464) Automatically replace tp_print -> tp_vectorcall_offset tp_compare -> tp_as_async tp_reserved -> tp_as_async
* bpo-37050: Remove expr_text from FormattedValue ast node, use Constant node ↵Eric V. Smith2019-05-271-29/+6
| | | | | instead (GH-13597) When using the "=" debug functionality of f-strings, use another Constant node (or a merged constant node) instead of adding expr_text to the FormattedValue node.
* bpo-36842: Implement PEP 578 (GH-12613)Steve Dower2019-05-231-0/+4
| | | Adds sys.audit, sys.addaudithook, io.open_code, and associated C APIs.
* bpo-36878: Track extra text added to 'type: ignore' in the AST (GH-13479)Michael J. Sullivan2019-05-221-3/+30
| | | | | GH-13238 made extra text after a # type: ignore accepted by the parser. This finishes the job and actually plumbs the extra text through the parser and makes it available in the AST.
* bpo-34616: Add PyCF_ALLOW_TOP_LEVEL_AWAIT to allow top-level await (GH-13148)Matthias Bussonnier2019-05-211-0/+2
| | | Co-Authored-By: Yury Selivanov <yury@magic.io>
* bpo-36817: Add f-string debugging using '='. (GH-13123)Eric V. Smith2019-05-081-6/+29
| | | If a "=" is specified a the end of an f-string expression, the f-string will evaluate to the text of the expression, followed by '=', followed by the repr of the value of the expression.
* bpo-36540: PEP 570 -- Implementation (GH-12701)Pablo Galindo2019-04-291-5/+45
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This commit contains the implementation of PEP570: Python positional-only parameters. * Update Grammar/Grammar with new typedarglist and varargslist * Regenerate grammar files * Update and regenerate AST related files * Update code object * Update marshal.c * Update compiler and symtable * Regenerate importlib files * Update callable objects * Implement positional-only args logic in ceval.c * Regenerate frozen data * Update standard library to account for positional-only args * Add test file for positional-only args * Update other test files to account for positional-only args * Add News entry * Update inspect module and related tests
* bpo-36280: Add Constant.kind field (GH-12295)Guido van Rossum2019-03-131-5/+27
| | | | | | | | | | | | | | The value is a string for string and byte literals, None otherwise. It is 'u' for u"..." literals, 'b' for b"..." literals, '' for "..." literals. The 'r' (raw) prefix is ignored. Does not apply to f-strings. This appears sufficient to make mypy capable of using the stdlib ast module instead of typed_ast (assuming a mypy patch I'm working on). WIP: I need to make the tests pass. @ilevkivskyi @serhiy-storchaka https://bugs.python.org/issue36280
* bpo-35975: Support parsing earlier minor versions of Python 3 (GH-12086)Guido van Rossum2019-03-071-0/+5
| | | | | | | This adds a `feature_version` flag to `ast.parse()` (documented) and `compile()` (hidden) that allow tweaking the parser to support older versions of the grammar. In particular if `feature_version` is 5 or 6, the hacks for the `async` and `await` keyword from PEP 492 are reinstated. (For 7 or higher, these are unconditionally treated as keywords, but they are still special tokens rather than `NAME` tokens that the parser driver recognizes.) https://bugs.python.org/issue35975
* bpo-36187: Remove NamedStore. (GH-12167)Serhiy Storchaka2019-03-051-20/+1
| | | | | NamedStore has been replaced with Store. The difference between NamedStore and Store is handled when precess the NamedExpr node one level upper.
* bpo-35766 follow-up: Kill half-support for FunctionType in PyAST_obj2mod ↵Guido van Rossum2019-02-011-3/+2
| | | | | | | (#11714) See https://github.com/python/cpython/pull/11645/files/229874c612df868e7ae3e997e159915f49d16542#r252631862 https://bugs.python.org/issue35766
* bpo-35766: Merge typed_ast back into CPython (GH-11645)Guido van Rossum2019-01-311-46/+466
|
* bpo-35224: PEP 572 Implementation (#10497)Emily Morehouse2019-01-241-1/+110
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * Add tokenization of := - Add token to Include/token.h. Add token to documentation in Doc/library/token.rst. - Run `./python Lib/token.py` to regenerate Lib/token.py. - Update Parser/tokenizer.c: add case to handle `:=`. * Add initial usage of := in grammar. * Update Python.asdl to match the grammar updates. Regenerated Include/Python-ast.h and Python/Python-ast.c * Update AST and compiler files in Python/ast.c and Python/compile.c. Basic functionality, this isn't scoped properly * Regenerate Lib/symbol.py using `./python Lib/symbol.py` * Tests - Fix failing tests in test_parser.py due to changes in token numbers for internal representation * Tests - Add simple test for := token * Tests - Add simple tests for named expressions using expr and suite * Tests - Update number of levels for nested expressions to prevent stack overflow * Update symbol table to handle NamedExpr * Update Grammar to allow assignment expressions in if statements. Regenerate Python/graminit.c accordingly using `make regen-grammar` * Tests - Add additional tests for named expressions in RoundtripLegalSyntaxTestCase, based on examples and information directly from PEP 572 Note: failing tests are currently commented out (4 out of 24 tests currently fail) * Tests - Add temporary syntax test failure tests in test_parser.py Note: There is an outstanding TODO for this -- syntax tests need to be moved to a different file (presumably test_syntax.py), but this is covering what needs to be tested at the moment, and it's more convenient to run a single test for the time being * Add support for allowing assignment expressions as function argument annotations. Uncomment tests for these cases because they all pass now! * Tests - Move existing syntax tests out of test_parser.py and into test_named_expressions.py. Refactor syntax tests to use unittest * Add TargetScopeError exception to extend SyntaxError Note: This simply creates the TargetScopeError exception, it is not yet used anywhere * Tests - Update tests per PEP 572 Continue refactoring test suite: The named expression test suite now checks for any invalid cases that throw exceptions (no longer limited to SyntaxErrors), assignment tests to ensure that variables are properly assigned, and scope tests to ensure that variable availability and values are correct Note: - There are still tests that are marked to skip, as they are not yet implemented - There are approximately 300 lines of the PEP that have not yet been addressed, though these may be deferred * Documentation - Small updates to XXX/todo comments - Remove XXX from child description in ast.c - Add comment with number of previously supported nested expressions for 3.7.X in test_parser.py * Fix assert in seq_for_testlist() * Cleanup - Denote "Not implemented -- No keyword args" on failing test case. Fix PEP8 error for blank lines at beginning of test classes in test_parser.py * Tests - Wrap all file opens in `with...as` to ensure files are closed * WIP: handle f(a := 1) * Tests and Cleanup - No longer skips keyword arg test. Keyword arg test now uses a simpler test case and does not rely on an external file. Remove print statements from ast.c * Tests - Refactor last remaining test case that relied on on external file to use a simpler test case without the dependency * Tests - Add better description of remaning skipped tests. Add test checking scope when using assignment expression in a function argument * Tests - Add test for nested comprehension, testing value and scope. Fix variable name in skipped comprehension scope test * Handle restriction of LHS for named expressions - can only assign to LHS of type NAME. Specifically, restrict assignment to tuples This adds an alternative set_context specifically for named expressions, set_namedexpr_context. Thus, context is now set differently for standard assignment versus assignment for named expressions in order to handle restrictions. * Tests - Update negative test case for assigning to lambda to match new error message. Add negative test case for assigning to tuple * Tests - Reorder test cases to group invalid syntax cases and named assignment target errors * Tests - Update test case for named expression in function argument - check that result and variable are set correctly * Todo - Add todo for TargetScopeError based on Guido's comment (https://github.com/python/cpython/commit/2b3acd37bdfc2d35e5094228c6684050d2aa8b0a#r30472562) * Tests - Add named expression tests for assignment operator in function arguments Note: One of two tests are skipped, as function arguments are currently treating an assignment expression inside of parenthesis as one child, which does not properly catch the named expression, nor does it count arguments properly * Add NamedStore to expr_context. Regenerate related code with `make regen-ast` * Add usage of NamedStore to ast_for_named_expr in ast.c. Update occurances of checking for Store to also handle NamedStore where appropriate * Add ste_comprehension to _symtable_entry to track if the namespace is a comprehension. Initialize ste_comprehension to 0. Set set_comprehension to 1 in symtable_handle_comprehension * s/symtable_add_def/symtable_add_def_helper. Add symtable_add_def to handle grabbing st->st_cur and passing it to symtable_add_def_helper. This now allows us to call the original code from symtable_add_def by instead calling symtable_add_def_helper with a different ste. * Refactor symtable_record_directive to take lineno and col_offset as arguments instead of stmt_ty. This allows symtable_record_directive to be used for stmt_ty and expr_ty * Handle elevating scope for named expressions in comprehensions. * Handle error for usage of named expression inside a class block * Tests - No longer skip scope tests. Add additional scope tests * Cleanup - Update error message for named expression within a comprehension within a class. Update comments. Add assert for symtable_extend_namedexpr_scope to validate that we always find at least a ModuleScope if we don't find a Class or FunctionScope * Cleanup - Add missing case for NamedStore in expr_context_name. Remove unused var in set_namedexpr_content * Refactor - Consolidate set_context and set_namedexpr_context to reduce duplicated code. Special cases for named expressions are handled by checking if ctx is NamedStore * Cleanup - Add additional use cases for ast_for_namedexpr in usage comment. Fix multiple blank lines in test_named_expressions * Tests - Remove unnecessary test case. Renumber test case function names * Remove TargetScopeError for now. Will add back if needed * Cleanup - Small comment nit for consistency * Handle positional argument check with named expression * Add TargetScopeError exception definition. Add documentation for TargetScopeError in c-api docs. Throw TargetScopeError instead of SyntaxError when using a named expression in a comprehension within a class scope * Increase stack size for parser by 200. This is a minimal change (approx. 5kb) and should not have an impact on any systems. Update parser test to allow 99 nested levels again * Add TargetScopeError to exception_hierarchy.txt for test_baseexception.py_ * Tests - Major update for named expression tests, both in test_named_expressions and test_parser - Add test for TargetScopeError - Add tests for named expressions in comprehension scope and edge cases - Add tests for named expressions in function arguments (declarations and call sites) - Reorganize tests to group them more logically * Cleanup - Remove unnecessary comment * Cleanup - Comment nitpicks * Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0) - Add check for LHS types to detect a parenthesis then a name (see note) - Add test for this scenario - Update tests for changed error message for named assignment to a tuple (also, see note) Note: This caused issues with the previous error handling for named assignment to a LHS that contained an expression, such as a tuple. Thus, the check for the LHS of a named expression must be changed to be more specific if we wish to maintain the previous error messages * Cleanup - Wrap lines more strictly in test file * Revert "Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0)" This reverts commit f1531400ca7d7a2d148830c8ac703f041740896d. * Add NEWS.d entry * Tests - Fix error in test_pickle.test_exceptions by adding TargetScopeError to list of exceptions * Tests - Update error message tests to reflect improved messaging convention (s/can't/cannot) * Remove cases that cannot be reached in compile.c. Small linting update. * Update Grammar/Tokens to add COLONEQUAL. Regenerate all files * Update TargetScopeError PRE_INIT and POST_INIT, as this was purposefully left out when fixing rebase conflicts * Add NamedStore back and regenerate files * Pass along line number and end col info for named expression * Simplify News entry * Fix compiler warning and explicity mark fallthrough
* bpo-33416: Add end positions to Python AST (GH-11605)Ivan Levkivskyi2019-01-221-124/+454
| | | | | | | | | | | | | | | | | | The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
* bpo-32892: Use ast.Constant instead of specific constant AST types. (GH-9445)Serhiy Storchaka2018-09-271-308/+4
|
* bpo-33677: Fix signatures of tp_clear handlers for AST and deque. (GH-7196)Serhiy Storchaka2018-05-311-1/+2
|
* bpo-32911: Revert bpo-29463. (GH-7121) (GH-7197)Serhiy Storchaka2018-05-291-102/+17
| | | | | | Remove the docstring attribute of AST types and restore docstring expression as a first stmt in their body. Co-authored-by: INADA Naoki <methane@users.noreply.github.com>
* bpo-32571: Avoid raising unneeded AttributeError and silencing it in C code ↵Serhiy Storchaka2018-01-251-1016/+1174
| | | | | (GH-5222) Add two new private APIs: _PyObject_LookupAttr() and _PyObject_LookupAttrId()
* bpo-31572: Get rid of _PyObject_HasAttrId() in the ASDL parser. (#3725)Serhiy Storchaka2017-11-111-610/+774
| | | Silence only expected AttributeError.
* bpo-31095: fix potential crash during GC (GH-2974)INADA Naoki2017-08-241-0/+2
|
* Fix a shadow-compatible-local warning (#2180)Yuan Chao Chou2017-08-041-165/+165
| | | | Change the shadowing naming, 'value' (Python-ast.c:4652), to 'val' to prevent the variables from being misused.
* bpo-29622: Make AST constructor to accept less than enough number of ↵INADA Naoki2017-02-231-19/+17
| | | | | | | | | | | positional arguments (GH-249) bpo-29463 added optional "docstring" field to 4 AST types. While it is optional, it breaks backward compatibility because AST constructor requires number of positional argument is same to number of fields. AST types accepts empty arguments, and incomplete keyword arguments. But it's not big problem because field can be filled after creation, and checked when compiling. So stop requiring complete set of fields for positional arguments too.
* bpo-29463: Add docstring field to some AST nodes. (#46)INADA Naoki2017-02-221-17/+90
| | | | | | | | | | | * bpo-29463: Add docstring field to some AST nodes. ClassDef, ModuleDef, FunctionDef, and AsyncFunctionDef has docstring field for now. It was first statement of there body. * fix document. thanks travis! * doc fixes
* Issue #29369: Use Py_IDENTIFIER in Python-ast.cINADA Naoki2017-01-251-6/+12
|
* Issue #28999: Use Py_RETURN_NONE, Py_RETURN_TRUE and Py_RETURN_FALSE whereverSerhiy Storchaka2017-01-231-22/+11
| | | | possible. Patch is writen with Coccinelle.
* Issue #24098: Fixed possible crash when AST is changed in process ofSerhiy Storchaka2016-10-071-0/+220
|\ | | | | | | compiling it.
| * Issue #24098: Fixed possible crash when AST is changed in process ofSerhiy Storchaka2016-10-071-0/+216
| | | | | | | | compiling it.
| * Issue #25555: Fix parser and AST: fill lineno and col_offset of "arg" node whenVictor Stinner2015-11-061-2/+29
| | | | | | | | compiling AST from Python objects.
* | Issue #28008: Implement PEP 530 -- asynchronous comprehensions.Yury Selivanov2016-09-091-3/+24
| |
* | Issue #27985: Implement PEP 526 -- Syntax for Variable Annotations.Yury Selivanov2016-09-091-1/+123
| | | | | | | | Patch by Ivan Levkivskyi.
* | Issue #26146: remove useless codeVictor Stinner2016-01-261-7/+0
| | | | | | | | | | | | | | | | obj2ast_constant() code is baesd on obj2ast_object() which has a special case for Py_None. But in practice, we don't need to have a special case for constants. Issue noticed by Joseph Jevnik on a review.
* | Add ast.ConstantVictor Stinner2016-01-251-0/+79
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Issue #26146: Add a new kind of AST node: ast.Constant. It can be used by external AST optimizers, but the compiler does not emit directly such node. An optimizer can replace the following AST nodes with ast.Constant: * ast.NameConstant: None, False, True * ast.Num: int, float, complex * ast.Str: str * ast.Bytes: bytes * ast.Tuple if items are constants too: tuple * frozenset Update code to accept ast.Constant instead of ast.Num and/or ast.Str: * compiler * docstrings * ast.literal_eval() * Tools/parser/unparse.py
* | Issue #25555: Fix parser and AST: fill lineno and col_offset of "arg" node whenVictor Stinner2015-11-061-2/+29
| | | | | | | | compiling AST from Python objects.
* | Issue #24965: Implement PEP 498 "Literal String Interpolation". ↵Eric V. Smith2015-09-191-0/+165
| | | | | | | | Documentation is still needed, I'll open an issue for that.
* | Issue #15989: Fixed some scarcely probable integer overflows.Serhiy Storchaka2015-09-061-1/+1
|/ | | | It is very unlikely that they can occur in real code for now.
* PEP 0492 -- Coroutines with async and await syntax. Issue #24017.Yury Selivanov2015-05-121-0/+473
|
* PEP 448: additional unpacking generalizations (closes #2292)Benjamin Peterson2015-05-061-93/+12
| | | | Patch by Neil Girdhar.
* PEP 465: a dedicated infix operator for matrix multiplication (closes #21176)Benjamin Peterson2014-04-101-3/+21
|
* merge 3.3 (#20588)Benjamin Peterson2014-02-111-2/+6
|\
| * don't put runtime values in array initializer for C89 compliance (closes #20588)Benjamin Peterson2014-02-111-2/+6
| |
* | Issue #4555: All exported C symbols are now prefixed with either "Py" or "_Py".Antoine Pitrou2013-10-121-48/+48
| | | | | | | | ("make smelly" now clean)
* | Issue #18552: Check return value of PyArena_AddPyObject() in obj2ast_object().Christian Heimes2013-07-261-3/+7
|\ \ | |/
> 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908

/* New getargs implementation */

#include "Python.h"

#include <ctype.h>


#ifdef __cplusplus
extern "C" {
#endif
int PyArg_Parse(PyObject *, const char *, ...);
int PyArg_ParseTuple(PyObject *, const char *, ...);
int PyArg_VaParse(PyObject *, const char *, va_list);

int PyArg_ParseTupleAndKeywords(PyObject *, PyObject *,
                                const char *, char **, ...);
int PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *,
                                const char *, char **, va_list);

#ifdef HAVE_DECLSPEC_DLL
/* Export functions */
PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *, char *, ...);
PyAPI_FUNC(int) _PyArg_ParseTuple_SizeT(PyObject *, char *, ...);
PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywords_SizeT(PyObject *, PyObject *,
                                                  const char *, char **, ...);
PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...);
PyAPI_FUNC(int) _PyArg_VaParse_SizeT(PyObject *, char *, va_list);
PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *, PyObject *,
                                              const char *, char **, va_list);
#endif

#define FLAG_COMPAT 1
#define FLAG_SIZE_T 2


/* Forward */
static int vgetargs1(PyObject *, const char *, va_list *, int);
static void seterror(int, const char *, int *, const char *, const char *);
static char *convertitem(PyObject *, const char **, va_list *, int, int *,
                         char *, size_t, PyObject **);
static char *converttuple(PyObject *, const char **, va_list *, int,
                          int *, char *, size_t, int, PyObject **);
static char *convertsimple(PyObject *, const char **, va_list *, int, char *,
                           size_t, PyObject **);
static Py_ssize_t convertbuffer(PyObject *, void **p, char **);
static int getbuffer(PyObject *, Py_buffer *, char**);

static int vgetargskeywords(PyObject *, PyObject *,
                            const char *, char **, va_list *, int);
static char *skipitem(const char **, va_list *, int);

int
PyArg_Parse(PyObject *args, const char *format, ...)
{
    int retval;
    va_list va;

    va_start(va, format);
    retval = vgetargs1(args, format, &va, FLAG_COMPAT);
    va_end(va);
    return retval;
}

int
_PyArg_Parse_SizeT(PyObject *args, char *format, ...)
{
    int retval;
    va_list va;

    va_start(va, format);
    retval = vgetargs1(args, format, &va, FLAG_COMPAT|FLAG_SIZE_T);
    va_end(va);
    return retval;
}


int
PyArg_ParseTuple(PyObject *args, const char *format, ...)
{
    int retval;
    va_list va;

    va_start(va, format);
    retval = vgetargs1(args, format, &va, 0);
    va_end(va);
    return retval;
}

int
_PyArg_ParseTuple_SizeT(PyObject *args, char *format, ...)
{
    int retval;
    va_list va;

    va_start(va, format);
    retval = vgetargs1(args, format, &va, FLAG_SIZE_T);
    va_end(va);
    return retval;
}


int
PyArg_VaParse(PyObject *args, const char *format, va_list va)
{
    va_list lva;

#ifdef VA_LIST_IS_ARRAY
    memcpy(lva, va, sizeof(va_list));
#else
#ifdef __va_copy
    __va_copy(lva, va);
#else
    lva = va;
#endif
#endif

    return vgetargs1(args, format, &lva, 0);
}

int
_PyArg_VaParse_SizeT(PyObject *args, char *format, va_list va)
{
    va_list lva;

#ifdef VA_LIST_IS_ARRAY
    memcpy(lva, va, sizeof(va_list));
#else
#ifdef __va_copy
    __va_copy(lva, va);
#else
    lva = va;
#endif
#endif

    return vgetargs1(args, format, &lva, FLAG_SIZE_T);
}


/* Handle cleanup of allocated memory in case of exception */

#define GETARGS_CAPSULE_NAME_CLEANUP_PTR "getargs.cleanup_ptr"
#define GETARGS_CAPSULE_NAME_CLEANUP_BUFFER "getargs.cleanup_buffer"

static void
cleanup_ptr(PyObject *self)
{
    void *ptr = PyCapsule_GetPointer(self, GETARGS_CAPSULE_NAME_CLEANUP_PTR);
    if (ptr) {
      PyMem_FREE(ptr);
    }
}

static void
cleanup_buffer(PyObject *self)
{
    Py_buffer *ptr = (Py_buffer *)PyCapsule_GetPointer(self, GETARGS_CAPSULE_NAME_CLEANUP_BUFFER);
    if (ptr) {
        PyBuffer_Release(ptr);
    }
}

static int
addcleanup(void *ptr, PyObject **freelist, PyCapsule_Destructor destr)
{
    PyObject *cobj;
    const char *name;

    if (!*freelist) {
        *freelist = PyList_New(0);
        if (!*freelist) {
            destr(ptr);
            return -1;
        }
    }

    if (destr == cleanup_ptr) {
        name = GETARGS_CAPSULE_NAME_CLEANUP_PTR;
    } else if (destr == cleanup_buffer) {
        name = GETARGS_CAPSULE_NAME_CLEANUP_BUFFER;
    } else {
        return -1;
    }
    cobj = PyCapsule_New(ptr, name, destr);
    if (!cobj) {
        destr(ptr);
        return -1;
    }
    if (PyList_Append(*freelist, cobj)) {
        Py_DECREF(cobj);
        return -1;
    }
    Py_DECREF(cobj);
    return 0;
}

static int
cleanreturn(int retval, PyObject *freelist)
{
    if (freelist && retval != 0) {
        /* We were successful, reset the destructors so that they
           don't get called. */
        Py_ssize_t len = PyList_GET_SIZE(freelist), i;
        for (i = 0; i < len; i++)
            PyCapsule_SetDestructor(PyList_GET_ITEM(freelist, i), NULL);
    }
    Py_XDECREF(freelist);
    return retval;
}


static int
vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
{
    char msgbuf[256];
    int levels[32];
    const char *fname = NULL;
    const char *message = NULL;
    int min = -1;
    int max = 0;
    int level = 0;
    int endfmt = 0;
    const char *formatsave = format;
    Py_ssize_t i, len;
    char *msg;
    PyObject *freelist = NULL;
    int compat = flags & FLAG_COMPAT;

    assert(compat || (args != (PyObject*)NULL));
    flags = flags & ~FLAG_COMPAT;

    while (endfmt == 0) {
        int c = *format++;
        switch (c) {
        case '(':
            if (level == 0)
                max++;
            level++;
            if (level >= 30)
                Py_FatalError("too many tuple nesting levels "
                              "in argument format string");
            break;
        case ')':
            if (level == 0)
                Py_FatalError("excess ')' in getargs format");
            else
                level--;
            break;
        case '\0':
            endfmt = 1;
            break;
        case ':':
            fname = format;
            endfmt = 1;
            break;
        case ';':
            message = format;
            endfmt = 1;
            break;
        default:
            if (level == 0) {
                if (c == 'O')
                    max++;
                else if (isalpha(Py_CHARMASK(c))) {
                    if (c != 'e') /* skip encoded */
                        max++;
                } else if (c == '|')
                    min = max;
            }
            break;
        }
    }

    if (level != 0)
        Py_FatalError(/* '(' */ "missing ')' in getargs format");

    if (min < 0)
        min = max;

    format = formatsave;

    if (compat) {
        if (max == 0) {
            if (args == NULL)
                return 1;
            PyOS_snprintf(msgbuf, sizeof(msgbuf),
                          "%.200s%s takes no arguments",
                          fname==NULL ? "function" : fname,
                          fname==NULL ? "" : "()");
            PyErr_SetString(PyExc_TypeError, msgbuf);
            return 0;
        }
        else if (min == 1 && max == 1) {
            if (args == NULL) {
                PyOS_snprintf(msgbuf, sizeof(msgbuf),
                      "%.200s%s takes at least one argument",
                          fname==NULL ? "function" : fname,
                          fname==NULL ? "" : "()");
                PyErr_SetString(PyExc_TypeError, msgbuf);
                return 0;
            }
            msg = convertitem(args, &format, p_va, flags, levels,
                              msgbuf, sizeof(msgbuf), &freelist);
            if (msg == NULL)
                return cleanreturn(1, freelist);
            seterror(levels[0], msg, levels+1, fname, message);
            return cleanreturn(0, freelist);
        }
        else {
            PyErr_SetString(PyExc_SystemError,
                "old style getargs format uses new features");
            return 0;
        }
    }

    if (!PyTuple_Check(args)) {
        PyErr_SetString(PyExc_SystemError,
            "new style getargs format but argument is not a tuple");
        return 0;
    }

    len = PyTuple_GET_SIZE(args);

    if (len < min || max < len) {
        if (message == NULL) {
            PyOS_snprintf(msgbuf, sizeof(msgbuf),
                          "%.150s%s takes %s %d argument%s "
                          "(%ld given)",
                          fname==NULL ? "function" : fname,
                          fname==NULL ? "" : "()",
                          min==max ? "exactly"
                          : len < min ? "at least" : "at most",
                          len < min ? min : max,
                          (len < min ? min : max) == 1 ? "" : "s",
                          Py_SAFE_DOWNCAST(len, Py_ssize_t, long));
            message = msgbuf;
        }
        PyErr_SetString(PyExc_TypeError, message);
        return 0;
    }

    for (i = 0; i < len; i++) {
        if (*format == '|')
            format++;
        msg = convertitem(PyTuple_GET_ITEM(args, i), &format, p_va,
                          flags, levels, msgbuf,
                          sizeof(msgbuf), &freelist);
        if (msg) {
            seterror(i+1, msg, levels, fname, msg);
            return cleanreturn(0, freelist);
        }
    }

    if (*format != '\0' && !isalpha(Py_CHARMASK(*format)) &&
        *format != '(' &&
        *format != '|' && *format != ':' && *format != ';') {
        PyErr_Format(PyExc_SystemError,
                     "bad format string: %.200s", formatsave);
        return cleanreturn(0, freelist);
    }

    return cleanreturn(1, freelist);
}



static void
seterror(int iarg, const char *msg, int *levels, const char *fname,
         const char *message)
{
    char buf[512];
    int i;
    char *p = buf;

    if (PyErr_Occurred())
        return;
    else if (message == NULL) {
        if (fname != NULL) {
            PyOS_snprintf(p, sizeof(buf), "%.200s() ", fname);
            p += strlen(p);
        }
        if (iarg != 0) {
            PyOS_snprintf(p, sizeof(buf) - (p - buf),
                          "argument %d", iarg);
            i = 0;
            p += strlen(p);
            while (levels[i] > 0 && i < 32 && (int)(p-buf) < 220) {
                PyOS_snprintf(p, sizeof(buf) - (p - buf),
                              ", item %d", levels[i]-1);
                p += strlen(p);
                i++;
            }
        }
        else {
            PyOS_snprintf(p, sizeof(buf) - (p - buf), "argument");
            p += strlen(p);
        }
        PyOS_snprintf(p, sizeof(buf) - (p - buf), " %.256s", msg);
        message = buf;
    }
    PyErr_SetString(PyExc_TypeError, message);
}


/* Convert a tuple argument.
   On entry, *p_format points to the character _after_ the opening '('.
   On successful exit, *p_format points to the closing ')'.
   If successful:
      *p_format and *p_va are updated,
      *levels and *msgbuf are untouched,
      and NULL is returned.
   If the argument is invalid:
      *p_format is unchanged,
      *p_va is undefined,
      *levels is a 0-terminated list of item numbers,
      *msgbuf contains an error message, whose format is:
     "must be <typename1>, not <typename2>", where:
        <typename1> is the name of the expected type, and
        <typename2> is the name of the actual type,
      and msgbuf is returned.
*/

static char *
converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
             int *levels, char *msgbuf, size_t bufsize, int toplevel,
             PyObject **freelist)
{
    int level = 0;
    int n = 0;
    const char *format = *p_format;
    int i;

    for (;;) {
        int c = *format++;
        if (c == '(') {
            if (level == 0)
                n++;
            level++;
        }
        else if (c == ')') {
            if (level == 0)
                break;
            level--;
        }
        else if (c == ':' || c == ';' || c == '\0')
            break;
        else if (level == 0 && isalpha(Py_CHARMASK(c)))
            n++;
    }

    if (!PySequence_Check(arg) || PyString_Check(arg)) {
        levels[0] = 0;
        PyOS_snprintf(msgbuf, bufsize,
                      toplevel ? "expected %d arguments, not %.50s" :
                      "must be %d-item sequence, not %.50s",
                  n,
                  arg == Py_None ? "None" : arg->ob_type->tp_name);
        return msgbuf;
    }

    if ((i = PySequence_Size(arg)) != n) {
        levels[0] = 0;
        PyOS_snprintf(msgbuf, bufsize,
                      toplevel ? "expected %d arguments, not %d" :
                     "must be sequence of length %d, not %d",
                  n, i);
        return msgbuf;
    }

    format = *p_format;
    for (i = 0; i < n; i++) {
        char *msg;
        PyObject *item;
        item = PySequence_GetItem(arg, i);
        if (item == NULL) {
            PyErr_Clear();
            levels[0] = i+1;
            levels[1] = 0;
            strncpy(msgbuf, "is not retrievable", bufsize);
            return msgbuf;
        }
        msg = convertitem(item, &format, p_va, flags, levels+1,
                          msgbuf, bufsize, freelist);
        /* PySequence_GetItem calls tp->sq_item, which INCREFs */
        Py_XDECREF(item);
        if (msg != NULL) {
            levels[0] = i+1;
            return msg;
        }
    }

    *p_format = format;
    return NULL;
}


/* Convert a single item. */

static char *
convertitem(PyObject *arg, const char **p_format, va_list *p_va, int flags,
            int *levels, char *msgbuf, size_t bufsize, PyObject **freelist)
{
    char *msg;
    const char *format = *p_format;

    if (*format == '(' /* ')' */) {
        format++;
        msg = converttuple(arg, &format, p_va, flags, levels, msgbuf,
                           bufsize, 0, freelist);
        if (msg == NULL)
            format++;
    }
    else {
        msg = convertsimple(arg, &format, p_va, flags,
                            msgbuf, bufsize, freelist);
        if (msg != NULL)
            levels[0] = 0;
    }
    if (msg == NULL)
        *p_format = format;
    return msg;
}



#define UNICODE_DEFAULT_ENCODING(arg) \
    _PyUnicode_AsDefaultEncodedString(arg, NULL)

/* Format an error message generated by convertsimple(). */

static char *
converterr(const char *expected, PyObject *arg, char *msgbuf, size_t bufsize)
{
    assert(expected != NULL);
    assert(arg != NULL);
    PyOS_snprintf(msgbuf, bufsize,
                  "must be %.50s, not %.50s", expected,
                  arg == Py_None ? "None" : arg->ob_type->tp_name);
    return msgbuf;
}

#define CONV_UNICODE "(unicode conversion error)"

/* explicitly check for float arguments when integers are expected.  For now
 * signal a warning.  Returns true if an exception was raised. */
static int
float_argument_warning(PyObject *arg)
{
    if (PyFloat_Check(arg) &&
        PyErr_Warn(PyExc_DeprecationWarning,
                   "integer argument expected, got float" ))
        return 1;
    else
        return 0;
}

/* explicitly check for float arguments when integers are expected.  Raises
   TypeError and returns true for float arguments. */
static int
float_argument_error(PyObject *arg)
{
    if (PyFloat_Check(arg)) {
        PyErr_SetString(PyExc_TypeError,
                        "integer argument expected, got float");
        return 1;
    }
    else
        return 0;
}

/* Convert a non-tuple argument.  Return NULL if conversion went OK,
   or a string with a message describing the failure.  The message is
   formatted as "must be <desired type>, not <actual type>".
   When failing, an exception may or may not have been raised.
   Don't call if a tuple is expected.

   When you add new format codes, please don't forget poor skipitem() below.
*/

static char *
convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
              char *msgbuf, size_t bufsize, PyObject **freelist)
{
    /* For # codes */
#define FETCH_SIZE      int *q=NULL;Py_ssize_t *q2=NULL;\
    if (flags & FLAG_SIZE_T) q2=va_arg(*p_va, Py_ssize_t*); \
    else q=va_arg(*p_va, int*);
#define STORE_SIZE(s)   \
    if (flags & FLAG_SIZE_T) \
        *q2=s; \
    else { \
        if (INT_MAX < s) { \
            PyErr_SetString(PyExc_OverflowError, \
                "size does not fit in an int"); \
            return converterr("", arg, msgbuf, bufsize); \
        } \
        *q=s; \
    }
#define BUFFER_LEN      ((flags & FLAG_SIZE_T) ? *q2:*q)

    const char *format = *p_format;
    char c = *format++;
#ifdef Py_USING_UNICODE
    PyObject *uarg;
#endif

    switch (c) {

    case 'b': { /* unsigned byte -- very short int */
        char *p = va_arg(*p_va, char *);
        long ival;
        if (float_argument_error(arg))
            return converterr("integer<b>", arg, msgbuf, bufsize);
        ival = PyInt_AsLong(arg);
        if (ival == -1 && PyErr_Occurred())
            return converterr("integer<b>", arg, msgbuf, bufsize);
        else if (ival < 0) {
            PyErr_SetString(PyExc_OverflowError,
            "unsigned byte integer is less than minimum");
            return converterr("integer<b>", arg, msgbuf, bufsize);
        }
        else if (ival > UCHAR_MAX) {
            PyErr_SetString(PyExc_OverflowError,
            "unsigned byte integer is greater than maximum");
            return converterr("integer<b>", arg, msgbuf, bufsize);
        }
        else
            *p = (unsigned char) ival;
        break;
    }

    case 'B': {/* byte sized bitfield - both signed and unsigned
                  values allowed */
        char *p = va_arg(*p_va, char *);
        long ival;
        if (float_argument_error(arg))
            return converterr("integer<B>", arg, msgbuf, bufsize);
        ival = PyInt_AsUnsignedLongMask(arg);
        if (ival == -1 && PyErr_Occurred())
            return converterr("integer<B>", arg, msgbuf, bufsize);
        else
            *p = (unsigned char) ival;
        break;
    }

    case 'h': {/* signed short int */
        short *p = va_arg(*p_va, short *);
        long ival;
        if (float_argument_error(arg))
            return converterr("integer<h>", arg, msgbuf, bufsize);
        ival = PyInt_AsLong(arg);
        if (ival == -1 && PyErr_Occurred())
            return converterr("integer<h>", arg, msgbuf, bufsize);
        else if (ival < SHRT_MIN) {
            PyErr_SetString(PyExc_OverflowError,
            "signed short integer is less than minimum");
            return converterr("integer<h>", arg, msgbuf, bufsize);
        }
        else if (ival > SHRT_MAX) {
            PyErr_SetString(PyExc_OverflowError,
            "signed short integer is greater than maximum");
            return converterr("integer<h>", arg, msgbuf, bufsize);
        }
        else
            *p = (short) ival;
        break;
    }

    case 'H': { /* short int sized bitfield, both signed and
                   unsigned allowed */
        unsigned short *p = va_arg(*p_va, unsigned short *);
        long ival;
        if (float_argument_error(arg))
            return converterr("integer<H>", arg, msgbuf, bufsize);
        ival = PyInt_AsUnsignedLongMask(arg);
        if (ival == -1 && PyErr_Occurred())
            return converterr("integer<H>", arg, msgbuf, bufsize);
        else
            *p = (unsigned short) ival;
        break;
    }

    case 'i': {/* signed int */
        int *p = va_arg(*p_va, int *);
        long ival;
        if (float_argument_error(arg))
            return converterr("integer<i>", arg, msgbuf, bufsize);
        ival = PyInt_AsLong(arg);
        if (ival == -1 && PyErr_Occurred())
            return converterr("integer<i>", arg, msgbuf, bufsize);
        else if (ival > INT_MAX) {
            PyErr_SetString(PyExc_OverflowError,
                "signed integer is greater than maximum");
            return converterr("integer<i>", arg, msgbuf, bufsize);
        }
        else if (ival < INT_MIN) {
            PyErr_SetString(PyExc_OverflowError,
                "signed integer is less than minimum");
            return converterr("integer<i>", arg, msgbuf, bufsize);
        }
        else
            *p = ival;
        break;
    }

    case 'I': { /* int sized bitfield, both signed and
                   unsigned allowed */
        unsigned int *p = va_arg(*p_va, unsigned int *);
        unsigned int ival;
        if (float_argument_error(arg))
            return converterr("integer<I>", arg, msgbuf, bufsize);
        ival = (unsigned int)PyInt_AsUnsignedLongMask(arg);
        if (ival == (unsigned int)-1 && PyErr_Occurred())
            return converterr("integer<I>", arg, msgbuf, bufsize);
        else
            *p = ival;
        break;
    }

    case 'n': /* Py_ssize_t */
#if SIZEOF_SIZE_T != SIZEOF_LONG
    {
        Py_ssize_t *p = va_arg(*p_va, Py_ssize_t *);
        Py_ssize_t ival;
        if (float_argument_error(arg))
            return converterr("integer<n>", arg, msgbuf, bufsize);
        ival = PyInt_AsSsize_t(arg);
        if (ival == -1 && PyErr_Occurred())
            return converterr("integer<n>", arg, msgbuf, bufsize);
        *p = ival;
        break;
    }
#endif
    /* Fall through from 'n' to 'l' if Py_ssize_t is int */
    case 'l': {/* long int */
        long *p = va_arg(*p_va, long *);
        long ival;
        if (float_argument_error(arg))
            return converterr("integer<l>", arg, msgbuf, bufsize);
        ival = PyInt_AsLong(arg);
        if (ival == -1 && PyErr_Occurred())
            return converterr("integer<l>", arg, msgbuf, bufsize);
        else
            *p = ival;
        break;
    }

    case 'k': { /* long sized bitfield */
        unsigned long *p = va_arg(*p_va, unsigned long *);
        unsigned long ival;
        if (PyInt_Check(arg))
            ival = PyInt_AsUnsignedLongMask(arg);
        else if (PyLong_Check(arg))
            ival = PyLong_AsUnsignedLongMask(arg);
        else
            return converterr("integer<k>", arg, msgbuf, bufsize);
        *p = ival;
        break;
    }

#ifdef HAVE_LONG_LONG
    case 'L': {/* PY_LONG_LONG */
        PY_LONG_LONG *p = va_arg( *p_va, PY_LONG_LONG * );
        PY_LONG_LONG ival;
        if (float_argument_warning(arg))
            return converterr("long<L>", arg, msgbuf, bufsize);
        ival = PyLong_AsLongLong(arg);
        if (ival == (PY_LONG_LONG)-1 && PyErr_Occurred() ) {
            return converterr("long<L>", arg, msgbuf, bufsize);
        } else {
            *p = ival;
        }
        break;
    }

    case 'K': { /* long long sized bitfield */
        unsigned PY_LONG_LONG *p = va_arg(*p_va, unsigned PY_LONG_LONG *);
        unsigned PY_LONG_LONG ival;
        if (PyInt_Check(arg))
            ival = PyInt_AsUnsignedLongMask(arg);
        else if (PyLong_Check(arg))
            ival = PyLong_AsUnsignedLongLongMask(arg);
        else
            return converterr("integer<K>", arg, msgbuf, bufsize);
        *p = ival;
        break;
    }
#endif

    case 'f': {/* float */
        float *p = va_arg(*p_va, float *);
        double dval = PyFloat_AsDouble(arg);
        if (PyErr_Occurred())
            return converterr("float<f>", arg, msgbuf, bufsize);
        else
            *p = (float) dval;
        break;
    }

    case 'd': {/* double */
        double *p = va_arg(*p_va, double *);
        double dval = PyFloat_AsDouble(arg);
        if (PyErr_Occurred())
            return converterr("float<d>", arg, msgbuf, bufsize);
        else
            *p = dval;
        break;
    }

#ifndef WITHOUT_COMPLEX
    case 'D': {/* complex double */
        Py_complex *p = va_arg(*p_va, Py_complex *);
        Py_complex cval;
        cval = PyComplex_AsCComplex(arg);
        if (PyErr_Occurred())
            return converterr("complex<D>", arg, msgbuf, bufsize);
        else
            *p = cval;
        break;
    }
#endif /* WITHOUT_COMPLEX */

    case 'c': {/* char */
        char *p = va_arg(*p_va, char *);
        if (PyString_Check(arg) && PyString_Size(arg) == 1)
            *p = PyString_AS_STRING(arg)[0];
        else
            return converterr("char", arg, msgbuf, bufsize);
        break;
    }

    case 's': {/* string */
        if (*format == '*') {
            Py_buffer *p = (Py_buffer *)va_arg(*p_va, Py_buffer *);

            if (PyString_Check(arg)) {
                PyBuffer_FillInfo(p, arg,
                                  PyString_AS_STRING(arg), PyString_GET_SIZE(arg),
                                  1, 0);
            }
#ifdef Py_USING_UNICODE
            else if (PyUnicode_Check(arg)) {
                uarg = UNICODE_DEFAULT_ENCODING(arg);
                if (uarg == NULL)
                    return converterr(CONV_UNICODE,
                                      arg, msgbuf, bufsize);
                PyBuffer_FillInfo(p, arg,
                                  PyString_AS_STRING(uarg), PyString_GET_SIZE(uarg),
                                  1, 0);
            }
#endif
            else { /* any buffer-like object */
                char *buf;
                if (getbuffer(arg, p, &buf) < 0)
                    return converterr(buf, arg, msgbuf, bufsize);
            }
            if (addcleanup(p, freelist, cleanup_buffer)) {
                return converterr(
                    "(cleanup problem)",
                    arg, msgbuf, bufsize);
            }
            format++;
        } else if (*format == '#') {
            void **p = (void **)va_arg(*p_va, char **);
            FETCH_SIZE;

            if (PyString_Check(arg)) {
                *p = PyString_AS_STRING(arg);
                STORE_SIZE(PyString_GET_SIZE(arg));
            }
#ifdef Py_USING_UNICODE
            else if (PyUnicode_Check(arg)) {
                uarg = UNICODE_DEFAULT_ENCODING(arg);
                if (uarg == NULL)
                    return converterr(CONV_UNICODE,
                                      arg, msgbuf, bufsize);
                *p = PyString_AS_STRING(uarg);
                STORE_SIZE(PyString_GET_SIZE(uarg));
            }
#endif
            else { /* any buffer-like object */
                char *buf;
                Py_ssize_t count = convertbuffer(arg, p, &buf);
                if (count < 0)
                    return converterr(buf, arg, msgbuf, bufsize);
                STORE_SIZE(count);
            }
            format++;
        } else {
            char **p = va_arg(*p_va, char **);

            if (PyString_Check(arg))
                *p = PyString_AS_STRING(arg);
#ifdef Py_USING_UNICODE
            else if (PyUnicode_Check(arg)) {
                uarg = UNICODE_DEFAULT_ENCODING(arg);
                if (uarg == NULL)
                    return converterr(CONV_UNICODE,
                                      arg, msgbuf, bufsize);
                *p = PyString_AS_STRING(uarg);
            }
#endif
            else
                return converterr("string", arg, msgbuf, bufsize);
            if ((Py_ssize_t)strlen(*p) != PyString_Size(arg))
                return converterr("string without null bytes",
                                  arg, msgbuf, bufsize);
        }
        break;
    }

    case 'z': {/* string, may be NULL (None) */
        if (*format == '*') {
            Py_buffer *p = (Py_buffer *)va_arg(*p_va, Py_buffer *);

            if (arg == Py_None)
                PyBuffer_FillInfo(p, NULL, NULL, 0, 1, 0);
            else if (PyString_Check(arg)) {
                PyBuffer_FillInfo(p, arg,
                                  PyString_AS_STRING(arg), PyString_GET_SIZE(arg),
                                  1, 0);
            }
#ifdef Py_USING_UNICODE
            else if (PyUnicode_Check(arg)) {
                uarg = UNICODE_DEFAULT_ENCODING(arg);
                if (uarg == NULL)
                    return converterr(CONV_UNICODE,
                                      arg, msgbuf, bufsize);
                PyBuffer_FillInfo(p, arg,
                                  PyString_AS_STRING(uarg), PyString_GET_SIZE(uarg),
                                  1, 0);
            }
#endif
            else { /* any buffer-like object */
                char *buf;
                if (getbuffer(arg, p, &buf) < 0)
                    return converterr(buf, arg, msgbuf, bufsize);
            }
            if (addcleanup(p, freelist, cleanup_buffer)) {
                return converterr(
                    "(cleanup problem)",
                    arg, msgbuf, bufsize);
            }
            format++;
        } else if (*format == '#') { /* any buffer-like object */
            void **p = (void **)va_arg(*p_va, char **);
            FETCH_SIZE;

            if (arg == Py_None) {
                *p = 0;
                STORE_SIZE(0);
            }
            else if (PyString_Check(arg)) {
                *p = PyString_AS_STRING(arg);
                STORE_SIZE(PyString_GET_SIZE(arg));
            }
#ifdef Py_USING_UNICODE
            else if (PyUnicode_Check(arg)) {
                uarg = UNICODE_DEFAULT_ENCODING(arg);
                if (uarg == NULL)
                    return converterr(CONV_UNICODE,
                                      arg, msgbuf, bufsize);
                *p = PyString_AS_STRING(uarg);
                STORE_SIZE(PyString_GET_SIZE(uarg));
            }
#endif
            else { /* any buffer-like object */
                char *buf;
                Py_ssize_t count = convertbuffer(arg, p, &buf);
                if (count < 0)
                    return converterr(buf, arg, msgbuf, bufsize);
                STORE_SIZE(count);
            }
            format++;
        } else {
            char **p = va_arg(*p_va, char **);

            if (arg == Py_None)
                *p = 0;
            else if (PyString_Check(arg))
                *p = PyString_AS_STRING(arg);
#ifdef Py_USING_UNICODE
            else if (PyUnicode_Check(arg)) {
                uarg = UNICODE_DEFAULT_ENCODING(arg);
                if (uarg == NULL)
                    return converterr(CONV_UNICODE,
                                      arg, msgbuf, bufsize);
                *p = PyString_AS_STRING(uarg);
            }
#endif
            else
                return converterr("string or None",
                                  arg, msgbuf, bufsize);
            if (*format == '#') {
                FETCH_SIZE;
                assert(0); /* XXX redundant with if-case */
                if (arg == Py_None) {
                    STORE_SIZE(0);
                } else {
                    STORE_SIZE(PyString_Size(arg));
                }
                format++;
            }
            else if (*p != NULL &&
                     (Py_ssize_t)strlen(*p) != PyString_Size(arg))
                return converterr(
                    "string without null bytes or None",
                    arg, msgbuf, bufsize);
        }
        break;
    }

    case 'e': {/* encoded string */
        char **buffer;
        const char *encoding;
        PyObject *s;
        Py_ssize_t size;
        int recode_strings;

        /* Get 'e' parameter: the encoding name */
        encoding = (const char *)va_arg(*p_va, const char *);
#ifdef Py_USING_UNICODE
        if (encoding == NULL)
            encoding = PyUnicode_GetDefaultEncoding();
#endif

        /* Get output buffer parameter:
           's' (recode all objects via Unicode) or
           't' (only recode non-string objects)
        */
        if (*format == 's')
            recode_strings = 1;
        else if (*format == 't')
            recode_strings = 0;
        else
            return converterr(
                "(unknown parser marker combination)",
                arg, msgbuf, bufsize);
        buffer = (char **)va_arg(*p_va, char **);
        format++;
        if (buffer == NULL)
            return converterr("(buffer is NULL)",
                              arg, msgbuf, bufsize);

        /* Encode object */
        if (!recode_strings && PyString_Check(arg)) {
            s = arg;
            Py_INCREF(s);
        }
        else {
#ifdef Py_USING_UNICODE
            PyObject *u;

            /* Convert object to Unicode */
            u = PyUnicode_FromObject(arg);
            if (u == NULL)
                return converterr(
                    "string or unicode or text buffer",
                    arg, msgbuf, bufsize);

            /* Encode object; use default error handling */
            s = PyUnicode_AsEncodedString(u,
                                          encoding,
                                          NULL);
            Py_DECREF(u);
            if (s == NULL)
                return converterr("(encoding failed)",
                                  arg, msgbuf, bufsize);
            if (!PyString_Check(s)) {
                Py_DECREF(s);
                return converterr(
                    "(encoder failed to return a string)",
                    arg, msgbuf, bufsize);
            }
#else
            return converterr("string<e>", arg, msgbuf, bufsize);
#endif
        }
        size = PyString_GET_SIZE(s);

        /* Write output; output is guaranteed to be 0-terminated */
        if (*format == '#') {
            /* Using buffer length parameter '#':

               - if *buffer is NULL, a new buffer of the
               needed size is allocated and the data
               copied into it; *buffer is updated to point
               to the new buffer; the caller is
               responsible for PyMem_Free()ing it after
               usage

               - if *buffer is not NULL, the data is
               copied to *buffer; *buffer_len has to be
               set to the size of the buffer on input;
               buffer overflow is signalled with an error;
               buffer has to provide enough room for the
               encoded string plus the trailing 0-byte

               - in both cases, *buffer_len is updated to
               the size of the buffer /excluding/ the
               trailing 0-byte

            */
            FETCH_SIZE;

            format++;
            if (q == NULL && q2 == NULL) {
                Py_DECREF(s);
                return converterr(
                    "(buffer_len is NULL)",
                    arg, msgbuf, bufsize);
            }
            if (*buffer == NULL) {
                *buffer = PyMem_NEW(char, size + 1);
                if (*buffer == NULL) {
                    Py_DECREF(s);
                    return converterr(
                        "(memory error)",
                        arg, msgbuf, bufsize);
                }
                if (addcleanup(*buffer, freelist, cleanup_ptr)) {
                    Py_DECREF(s);
                    return converterr(
                        "(cleanup problem)",
                        arg, msgbuf, bufsize);
                }
            } else {
                if (size + 1 > BUFFER_LEN) {
                    Py_DECREF(s);
                    return converterr(
                        "(buffer overflow)",
                        arg, msgbuf, bufsize);
                }
            }
            memcpy(*buffer,
                   PyString_AS_STRING(s),
                   size + 1);
            STORE_SIZE(size);
        } else {
            /* Using a 0-terminated buffer:

               - the encoded string has to be 0-terminated
               for this variant to work; if it is not, an
               error raised

               - a new buffer of the needed size is
               allocated and the data copied into it;
               *buffer is updated to point to the new
               buffer; the caller is responsible for
               PyMem_Free()ing it after usage

            */
            if ((Py_ssize_t)strlen(PyString_AS_STRING(s))
                                                    != size) {
                Py_DECREF(s);
                return converterr(
                    "encoded string without NULL bytes",
                    arg, msgbuf, bufsize);
            }
            *buffer = PyMem_NEW(char, size + 1);
            if (*buffer == NULL) {
                Py_DECREF(s);
                return converterr("(memory error)",
                                  arg, msgbuf, bufsize);
            }
            if (addcleanup(*buffer, freelist, cleanup_ptr)) {
                Py_DECREF(s);
                return converterr("(cleanup problem)",
                                arg, msgbuf, bufsize);
            }
            memcpy(*buffer,
                   PyString_AS_STRING(s),
                   size + 1);
        }
        Py_DECREF(s);
        break;
    }

#ifdef Py_USING_UNICODE
    case 'u': {/* raw unicode buffer (Py_UNICODE *) */
        if (*format == '#') { /* any buffer-like object */
            void **p = (void **)va_arg(*p_va, char **);
            FETCH_SIZE;
            if (PyUnicode_Check(arg)) {
                *p = PyUnicode_AS_UNICODE(arg);
                STORE_SIZE(PyUnicode_GET_SIZE(arg));
            }
            else {
                return converterr("cannot convert raw buffers",
                                  arg, msgbuf, bufsize);
            }
            format++;
        } else {
            Py_UNICODE **p = va_arg(*p_va, Py_UNICODE **);
            if (PyUnicode_Check(arg))
                *p = PyUnicode_AS_UNICODE(arg);
            else
                return converterr("unicode", arg, msgbuf, bufsize);
        }
        break;
    }
#endif

    case 'S': { /* string object */
        PyObject **p = va_arg(*p_va, PyObject **);
        if (PyString_Check(arg))
            *p = arg;
        else
            return converterr("string", arg, msgbuf, bufsize);
        break;
    }

#ifdef Py_USING_UNICODE
    case 'U': { /* Unicode object */
        PyObject **p = va_arg(*p_va, PyObject **);
        if (PyUnicode_Check(arg))
            *p = arg;
        else
            return converterr("unicode", arg, msgbuf, bufsize);
        break;
    }
#endif

    case 'O': { /* object */
        PyTypeObject *type;
        PyObject **p;
        if (*format == '!') {
            type = va_arg(*p_va, PyTypeObject*);
            p = va_arg(*p_va, PyObject **);
            format++;
            if (PyType_IsSubtype(arg->ob_type, type))
                *p = arg;
            else
                return converterr(type->tp_name, arg, msgbuf, bufsize);

        }
        else if (*format == '?') {
            inquiry pred = va_arg(*p_va, inquiry);
            p = va_arg(*p_va, PyObject **);
            format++;
            if ((*pred)(arg))
                *p = arg;
            else
                return converterr("(unspecified)",
                                  arg, msgbuf, bufsize);

        }
        else if (*format == '&') {
            typedef int (*converter)(PyObject *, void *);
            converter convert = va_arg(*p_va, converter);
            void *addr = va_arg(*p_va, void *);
            format++;
            if (! (*convert)(arg, addr))
                return converterr("(unspecified)",
                                  arg, msgbuf, bufsize);
        }
        else {
            p = va_arg(*p_va, PyObject **);
            *p = arg;
        }
        break;
    }


    case 'w': { /* memory buffer, read-write access */
        void **p = va_arg(*p_va, void **);
        void *res;
        PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
        Py_ssize_t count;

        if (pb && pb->bf_releasebuffer && *format != '*')
            /* Buffer must be released, yet caller does not use
               the Py_buffer protocol. */
            return converterr("pinned buffer", arg, msgbuf, bufsize);

        if (pb && pb->bf_getbuffer && *format == '*') {
            /* Caller is interested in Py_buffer, and the object
               supports it directly. */
            format++;
            if (pb->bf_getbuffer(arg, (Py_buffer*)p, PyBUF_WRITABLE) < 0) {
                PyErr_Clear();
                return converterr("read-write buffer", arg, msgbuf, bufsize);
            }
            if (addcleanup(p, freelist, cleanup_buffer)) {
                return converterr(
                    "(cleanup problem)",
                    arg, msgbuf, bufsize);
            }
            if (!PyBuffer_IsContiguous((Py_buffer*)p, 'C'))
                return converterr("contiguous buffer", arg, msgbuf, bufsize);
            break;
        }

        if (pb == NULL ||
            pb->bf_getwritebuffer == NULL ||
            pb->bf_getsegcount == NULL)
            return converterr("read-write buffer", arg, msgbuf, bufsize);
        if ((*pb->bf_getsegcount)(arg, NULL) != 1)
            return converterr("single-segment read-write buffer",
                              arg, msgbuf, bufsize);
        if ((count = pb->bf_getwritebuffer(arg, 0, &res)) < 0)
            return converterr("(unspecified)", arg, msgbuf, bufsize);
        if (*format == '*') {
            PyBuffer_FillInfo((Py_buffer*)p, arg, res, count, 1, 0);
            format++;
        }
        else {
            *p = res;
            if (*format == '#') {
                FETCH_SIZE;
                STORE_SIZE(count);
                format++;
            }
        }
        break;
    }

    case 't': { /* 8-bit character buffer, read-only access */
        char **p = va_arg(*p_va, char **);
        PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
        Py_ssize_t count;

        if (*format++ != '#')
            return converterr(
                "invalid use of 't' format character",
                arg, msgbuf, bufsize);
        if (!PyType_HasFeature(arg->ob_type,
                               Py_TPFLAGS_HAVE_GETCHARBUFFER) ||
            pb == NULL || pb->bf_getcharbuffer == NULL ||
            pb->bf_getsegcount == NULL)
            return converterr(
                "string or read-only character buffer",
                arg, msgbuf, bufsize);

        if (pb->bf_getsegcount(arg, NULL) != 1)
            return converterr(
                "string or single-segment read-only buffer",
                arg, msgbuf, bufsize);

        if (pb->bf_releasebuffer)
            return converterr(
                "string or pinned buffer",
                arg, msgbuf, bufsize);

        count = pb->bf_getcharbuffer(arg, 0, p);
        if (count < 0)
            return converterr("(unspecified)", arg, msgbuf, bufsize);
        {
            FETCH_SIZE;
            STORE_SIZE(count);
        }
        break;
    }

    default:
        return converterr("impossible<bad format char>", arg, msgbuf, bufsize);

    }

    *p_format = format;
    return NULL;
}

static Py_ssize_t
convertbuffer(PyObject *arg, void **p, char **errmsg)
{
    PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
    Py_ssize_t count;
    if (pb == NULL ||
        pb->bf_getreadbuffer == NULL ||
        pb->bf_getsegcount == NULL ||
        pb->bf_releasebuffer != NULL) {
        *errmsg = "string or read-only buffer";
        return -1;
    }
    if ((*pb->bf_getsegcount)(arg, NULL) != 1) {
        *errmsg = "string or single-segment read-only buffer";
        return -1;
    }
    if ((count = (*pb->bf_getreadbuffer)(arg, 0, p)) < 0) {
        *errmsg = "(unspecified)";
    }
    return count;
}

static int
getbuffer(PyObject *arg, Py_buffer *view, char **errmsg)
{
    void *buf;
    Py_ssize_t count;
    PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
    if (pb == NULL) {
        *errmsg = "string or buffer";
        return -1;
    }
    if (pb->bf_getbuffer) {
        if (pb->bf_getbuffer(arg, view, 0) < 0) {
            *errmsg = "convertible to a buffer";
            return -1;
        }
        if (!PyBuffer_IsContiguous(view, 'C')) {
            *errmsg = "contiguous buffer";
            return -1;
        }
        return 0;
    }

    count = convertbuffer(arg, &buf, errmsg);
    if (count < 0) {
        *errmsg = "convertible to a buffer";
        return count;
    }
    PyBuffer_FillInfo(view, arg, buf, count, 1, 0);
    return 0;
}

/* Support for keyword arguments donated by
   Geoff Philbrick <philbric@delphi.hks.com> */

/* Return false (0) for error, else true. */
int
PyArg_ParseTupleAndKeywords(PyObject *args,
                            PyObject *keywords,
                            const char *format,
                            char **kwlist, ...)
{
    int retval;
    va_list va;

    if ((args == NULL || !PyTuple_Check(args)) ||
        (keywords != NULL && !PyDict_Check(keywords)) ||
        format == NULL ||
        kwlist == NULL)
    {
        PyErr_BadInternalCall();
        return 0;
    }

    va_start(va, kwlist);
    retval = vgetargskeywords(args, keywords, format, kwlist, &va, 0);
    va_end(va);
    return retval;
}

int
_PyArg_ParseTupleAndKeywords_SizeT(PyObject *args,
                                  PyObject *keywords,
                                  const char *format,
                                  char **kwlist, ...)
{
    int retval;
    va_list va;

    if ((args == NULL || !PyTuple_Check(args)) ||
        (keywords != NULL && !PyDict_Check(keywords)) ||
        format == NULL ||
        kwlist == NULL)
    {
        PyErr_BadInternalCall();
        return 0;
    }

    va_start(va, kwlist);
    retval = vgetargskeywords(args, keywords, format,
                              kwlist, &va, FLAG_SIZE_T);
    va_end(va);
    return retval;
}


int
PyArg_VaParseTupleAndKeywords(PyObject *args,
                              PyObject *keywords,
                              const char *format,
                              char **kwlist, va_list va)
{
    int retval;
    va_list lva;

    if ((args == NULL || !PyTuple_Check(args)) ||
        (keywords != NULL && !PyDict_Check(keywords)) ||
        format == NULL ||
        kwlist == NULL)
    {
        PyErr_BadInternalCall();
        return 0;
    }

#ifdef VA_LIST_IS_ARRAY
    memcpy(lva, va, sizeof(va_list));
#else
#ifdef __va_copy
    __va_copy(lva, va);
#else
    lva = va;
#endif
#endif

    retval = vgetargskeywords(args, keywords, format, kwlist, &lva, 0);
    return retval;
}

int
_PyArg_VaParseTupleAndKeywords_SizeT(PyObject *args,
                                    PyObject *keywords,
                                    const char *format,
                                    char **kwlist, va_list va)
{
    int retval;
    va_list lva;

    if ((args == NULL || !PyTuple_Check(args)) ||
        (keywords != NULL && !PyDict_Check(keywords)) ||
        format == NULL ||
        kwlist == NULL)
    {
        PyErr_BadInternalCall();
        return 0;
    }

#ifdef VA_LIST_IS_ARRAY
    memcpy(lva, va, sizeof(va_list));
#else
#ifdef __va_copy
    __va_copy(lva, va);
#else
    lva = va;
#endif
#endif

    retval = vgetargskeywords(args, keywords, format,
                              kwlist, &lva, FLAG_SIZE_T);
    return retval;
}

#define IS_END_OF_FORMAT(c) (c == '\0' || c == ';' || c == ':')

static int
vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
                 char **kwlist, va_list *p_va, int flags)
{
    char msgbuf[512];
    int levels[32];
    const char *fname, *msg, *custom_msg, *keyword;
    int min = INT_MAX;
    int i, len, nargs, nkeywords;
    PyObject *freelist = NULL, *current_arg;

    assert(args != NULL && PyTuple_Check(args));
    assert(keywords == NULL || PyDict_Check(keywords));
    assert(format != NULL);
    assert(kwlist != NULL);
    assert(p_va != NULL);

    /* grab the function name or custom error msg first (mutually exclusive) */
    fname = strchr(format, ':');
    if (fname) {
        fname++;
        custom_msg = NULL;
    }
    else {
        custom_msg = strchr(format,';');
        if (custom_msg)
            custom_msg++;
    }

    /* scan kwlist and get greatest possible nbr of args */
    for (len=0; kwlist[len]; len++)
        continue;

    nargs = PyTuple_GET_SIZE(args);
    nkeywords = (keywords == NULL) ? 0 : PyDict_Size(keywords);
    if (nargs + nkeywords > len) {
        PyErr_Format(PyExc_TypeError, "%s%s takes at most %d "
                     "argument%s (%d given)",
                     (fname == NULL) ? "function" : fname,
                     (fname == NULL) ? "" : "()",
                     len,
                     (len == 1) ? "" : "s",
                     nargs + nkeywords);
        return 0;
    }

    /* convert tuple args and keyword args in same loop, using kwlist to drive process */
    for (i = 0; i < len; i++) {
        keyword = kwlist[i];
        if (*format == '|') {
            min = i;
            format++;
        }
        if (IS_END_OF_FORMAT(*format)) {
            PyErr_Format(PyExc_RuntimeError,
                         "More keyword list entries (%d) than "
                         "format specifiers (%d)", len, i);
            return cleanreturn(0, freelist);
        }
        current_arg = NULL;
        if (nkeywords) {
            current_arg = PyDict_GetItemString(keywords, keyword);
        }
        if (current_arg) {
            --nkeywords;
            if (i < nargs) {
                /* arg present in tuple and in dict */
                PyErr_Format(PyExc_TypeError,
                             "Argument given by name ('%s') "
                             "and position (%d)",
                             keyword, i+1);
                return cleanreturn(0, freelist);
            }
        }
        else if (nkeywords && PyErr_Occurred())
            return cleanreturn(0, freelist);
        else if (i < nargs)
            current_arg = PyTuple_GET_ITEM(args, i);

        if (current_arg) {
            msg = convertitem(current_arg, &format, p_va, flags,
                levels, msgbuf, sizeof(msgbuf), &freelist);
            if (msg) {
                seterror(i+1, msg, levels, fname, custom_msg);
                return cleanreturn(0, freelist);
            }
            continue;
        }

        if (i < min) {
            PyErr_Format(PyExc_TypeError, "Required argument "
                         "'%s' (pos %d) not found",
                         keyword, i+1);
            return cleanreturn(0, freelist);
        }
        /* current code reports success when all required args
         * fulfilled and no keyword args left, with no further
         * validation. XXX Maybe skip this in debug build ?
         */
        if (!nkeywords)
            return cleanreturn(1, freelist);

        /* We are into optional args, skip thru to any remaining
         * keyword args */
        msg = skipitem(&format, p_va, flags);
        if (msg) {
            PyErr_Format(PyExc_RuntimeError, "%s: '%s'", msg,
                         format);
            return cleanreturn(0, freelist);
        }
    }

    if (!IS_END_OF_FORMAT(*format) && *format != '|') {
        PyErr_Format(PyExc_RuntimeError,
            "more argument specifiers than keyword list entries "
            "(remaining format:'%s')", format);
        return cleanreturn(0, freelist);
    }

    /* make sure there are no extraneous keyword arguments */
    if (nkeywords > 0) {
        PyObject *key, *value;
        Py_ssize_t pos = 0;
        while (PyDict_Next(keywords, &pos, &key, &value)) {
            int match = 0;
            char *ks;
            if (!PyString_Check(key)) {
                PyErr_SetString(PyExc_TypeError,
                                "keywords must be strings");
                return cleanreturn(0, freelist);
            }
            ks = PyString_AsString(key);
            for (i = 0; i < len; i++) {
                if (!strcmp(ks, kwlist[i])) {
                    match = 1;
                    break;
                }
            }
            if (!match) {
                PyErr_Format(PyExc_TypeError,
                             "'%s' is an invalid keyword "
                             "argument for this function",
                             ks);
                return cleanreturn(0, freelist);
            }
        }
    }

    return cleanreturn(1, freelist);
}


static char *
skipitem(const char **p_format, va_list *p_va, int flags)
{
    const char *format = *p_format;
    char c = *format++;

    switch (c) {

    /* simple codes
     * The individual types (second arg of va_arg) are irrelevant */

    case 'b': /* byte -- very short int */
    case 'B': /* byte as bitfield */
    case 'h': /* short int */
    case 'H': /* short int as bitfield */
    case 'i': /* int */
    case 'I': /* int sized bitfield */
    case 'l': /* long int */
    case 'k': /* long int sized bitfield */
#ifdef HAVE_LONG_LONG
    case 'L': /* PY_LONG_LONG */
    case 'K': /* PY_LONG_LONG sized bitfield */
#endif
    case 'f': /* float */
    case 'd': /* double */
#ifndef WITHOUT_COMPLEX
    case 'D': /* complex double */
#endif
    case 'c': /* char */
        {
            (void) va_arg(*p_va, void *);
            break;
        }

    case 'n': /* Py_ssize_t */
        {
            (void) va_arg(*p_va, Py_ssize_t *);
            break;
        }

    /* string codes */

    case 'e': /* string with encoding */
        {
            (void) va_arg(*p_va, const char *);
            if (!(*format == 's' || *format == 't'))
                /* after 'e', only 's' and 't' is allowed */
                goto err;
            format++;
            /* explicit fallthrough to string cases */
        }

    case 's': /* string */
    case 'z': /* string or None */
#ifdef Py_USING_UNICODE
    case 'u': /* unicode string */
#endif
    case 't': /* buffer, read-only */
    case 'w': /* buffer, read-write */
        {
            (void) va_arg(*p_va, char **);
            if (*format == '#') {
                if (flags & FLAG_SIZE_T)
                    (void) va_arg(*p_va, Py_ssize_t *);
                else
                    (void) va_arg(*p_va, int *);
                format++;
            } else if ((c == 's' || c == 'z') && *format == '*') {
                format++;
            }
            break;
        }

    /* object codes */

    case 'S': /* string object */
#ifdef Py_USING_UNICODE
    case 'U': /* unicode string object */
#endif
        {
            (void) va_arg(*p_va, PyObject **);
            break;
        }

    case 'O': /* object */
        {
            if (*format == '!') {
                format++;
                (void) va_arg(*p_va, PyTypeObject*);
                (void) va_arg(*p_va, PyObject **);
            }
            else if (*format == '&') {
                typedef int (*converter)(PyObject *, void *);
                (void) va_arg(*p_va, converter);
                (void) va_arg(*p_va, void *);
                format++;
            }
            else {
                (void) va_arg(*p_va, PyObject **);
            }
            break;
        }

    case '(':           /* bypass tuple, not handled at all previously */
        {
            char *msg;
            for (;;) {
                if (*format==')')
                    break;
                if (IS_END_OF_FORMAT(*format))
                    return "Unmatched left paren in format "
                           "string";
                msg = skipitem(&format, p_va, flags);
                if (msg)
                    return msg;
            }
            format++;
            break;
        }

    case ')':
        return "Unmatched right paren in format string";

    default:
err:
        return "impossible<bad format char>";

    }

    *p_format = format;
    return NULL;
}


int
PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, ...)
{
    Py_ssize_t i, l;
    PyObject **o;
    va_list vargs;

#ifdef HAVE_STDARG_PROTOTYPES
    va_start(vargs, max);
#else
    va_start(vargs);
#endif

    assert(min >= 0);
    assert(min <= max);
    if (!PyTuple_Check(args)) {
        va_end(vargs);
        PyErr_SetString(PyExc_SystemError,
            "PyArg_UnpackTuple() argument list is not a tuple");
        return 0;
    }
    l = PyTuple_GET_SIZE(args);
    if (l < min) {
        if (name != NULL)
            PyErr_Format(
                PyExc_TypeError,
                "%s expected %s%zd arguments, got %zd",
                name, (min == max ? "" : "at least "), min, l);
        else
            PyErr_Format(
                PyExc_TypeError,
                "unpacked tuple should have %s%zd elements,"
                " but has %zd",
                (min == max ? "" : "at least "), min, l);
        va_end(vargs);
        return 0;
    }
    if (l > max) {
        if (name != NULL)
            PyErr_Format(
                PyExc_TypeError,
                "%s expected %s%zd arguments, got %zd",
                name, (min == max ? "" : "at most "), max, l);
        else
            PyErr_Format(
                PyExc_TypeError,
                "unpacked tuple should have %s%zd elements,"
                " but has %zd",
                (min == max ? "" : "at most "), max, l);
        va_end(vargs);
        return 0;
    }
    for (i = 0; i < l; i++) {
        o = va_arg(vargs, PyObject **);
        *o = PyTuple_GET_ITEM(args, i);
    }
    va_end(vargs);
    return 1;
}


/* For type constructors that don't take keyword args
 *
 * Sets a TypeError and returns 0 if the kwds dict is
 * not empty, returns 1 otherwise
 */
int
_PyArg_NoKeywords(const char *funcname, PyObject *kw)
{
    if (kw == NULL)
        return 1;
    if (!PyDict_CheckExact(kw)) {
        PyErr_BadInternalCall();
        return 0;
    }
    if (PyDict_Size(kw) == 0)
        return 1;

    PyErr_Format(PyExc_TypeError, "%s does not take keyword arguments",
                    funcname);
    return 0;
}
#ifdef __cplusplus
};
#endif