diff options
author | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-03-04 22:59:56 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-03-04 22:59:56 +0000 |
commit | 1db43e412f57c4f6ab03525569cbd398b234476f (patch) | |
tree | 030266749a2fdbc631a02bc77a53f6182973d942 | |
parent | 62a6e52515045ad51fc4764d36f72e4a602f0fc0 (diff) | |
parent | 2d9dbc9f306462644b502c8e1f4d564659bf0a9c (diff) | |
download | pycparser-1db43e412f57c4f6ab03525569cbd398b234476f.tar.gz |
Merge "Upgrade python/pycparser to release_v2.20" am: 2d9dbc9f30
Change-Id: I89e58ce156bae722cc2db9b389b53e2922e93923
30 files changed, 26490 insertions, 84 deletions
diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..91c326c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.ppout linguist-vendored=true + @@ -14,4 +14,4 @@ parser.out .tox utils/z.c *.egg-info - +*.swp diff --git a/.travis.yml b/.travis.yml index 25c9df6..d71276e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: python python: - "2.7" - - "3.4" - - "3.5" - "3.6" + - "3.7" + - "3.8" script: python tests/all_tests.py @@ -0,0 +1,8 @@ +" Force indentation styles for this directory +autocmd FileType python set shiftwidth=4 +autocmd FileType python set tabstop=4 +autocmd FileType python set softtabstop=4 + +autocmd FileType c set shiftwidth=2 +autocmd FileType c set tabstop=2 +autocmd FileType c set softtabstop=2 @@ -1,9 +1,26 @@ ++ Version 2.20 (2020.03.04) + + - #61: Fix slow backtracking when parsing strings. + - #99: Parser for FuncDecl incorrectly sets declname attribute on return type. + - #310: Fix crash when file starts with a semicolon. + - #313: Fix array type generation. + - #314: Fix failed parsing of unnamed function parameters with array dim + qualifiers. + - #315: Fix pointer type generation. + - #324: Fixes for u/l constant integer suffix. + - #346: Fix error transforming an empty switch. + - #350: Recognize integer multicharacter constants like 'ABCD'. + - #363: Fix incorrect AST when parsing offsetof. + + Version 2.19 (2018.09.19) - PR #277: Fix parsing of floating point literals - PR #254: Add support for parsing empty structs - PR #240: Fix enum formatting in generated C code (also #216) - PR #222: Add support for #pragma in struct declarations + - There are reports that this release doesn't work with Python 2.6 (#281). + Please note that the minimal supported version is 2.7; the required versions + are listed in the README file. + Version 2.18 (2017.07.04) @@ -149,11 +166,11 @@ + Version 2.05 (2011.10.16) - Added support for the C99 ``_Bool`` type and ``stdbool.h`` header file - - Expanded ``examples/explore_ast.py`` with more details on working with the + - Expanded ``examples/explore_ast.py`` with more details on working with the AST - Relaxed the rules on parsing unnamed struct members (helps parse ``windows.h``) - Bug fixes: - + * Fixed spacing issue for some type declarations * Issue 47: display empty statements (lone ';') correctly after parsing @@ -161,34 +178,34 @@ - License changed from LGPL to BSD - Bug fixes: - + * Issue 31: constraining the scope of typedef definitions * Issues 33, 35: fixes for the c-to-c.py example - + - Added C99 integer types to fake headers - Added unit tests for the c-to-c.py example + Version 2.03 (2011.03.06) - Bug fixes: - + * Issue 17: empty file-level declarations * Issue 18: empty statements and declarations in functions * Issue 19: anonymous structs & union fields * Issue 23: fix coordinates of Cast nodes - + - New example added (``examples/c-to-c.py``) for translating ASTs generated by ``pycparser`` back into C code. - ``pycparser`` is now on PyPI (Python Package Index) - Created `FAQ <http://code.google.com/p/pycparser/wiki/FAQ>`_ on - the ``pycparser`` project page + the ``pycparser`` project page - Removed support for Python 2.5. ``pycparser`` supports Python 2 from 2.6 and on, and Python 3. + Version 2.02 (2010.12.10) - * The name of a ``NamedInitializer`` node was turned into a sequence of nodes - instead of an attribute, to make it discoverable by the AST node visitor. + * The name of a ``NamedInitializer`` node was turned into a sequence of nodes + instead of an attribute, to make it discoverable by the AST node visitor. * Documentation updates + Version 2.01 (04.12.2010) @@ -218,7 +235,7 @@ + Version 1.06 (2010.04.10) - * Bug fixes: + * Bug fixes: + coord not propagated to FuncCall nodes + lexing of the ^= token (XOREQUALS) @@ -246,7 +263,7 @@ + Version 1.02 (2009.01.16) * Fixed problem of parsing struct/enum/union names that were named similarly - to previously defined ``typedef`` types. + to previously defined ``typedef`` types. + Version 1.01 (2009.01.09) @@ -9,11 +9,11 @@ third_party { type: GIT value: "https://github.com/eliben/pycparser" } - version: "release_v2.19" + version: "release_v2.20" license_type: NOTICE last_upgrade_date { - year: 2019 - month: 5 - day: 2 + year: 2020 + month: 3 + day: 4 } } @@ -1,9 +1,15 @@ =============== -pycparser v2.19 +pycparser v2.20 =============== -:Author: `Eli Bendersky <https://eli.thegreenplace.net/>`_ +.. image:: https://travis-ci.org/eliben/pycparser.png?branch=master + :align: center + :target: https://travis-ci.org/eliben/pycparser + +.. image:: https://ci.appveyor.com/api/projects/status/wrup68o5y8nuk1i9?svg=true + :align: center + :target: https://ci.appveyor.com/project/eliben/pycparser/ .. contents:: :backlinks: none @@ -161,6 +167,9 @@ See `this blog post <https://eli.thegreenplace.net/2015/on-parsing-c-type-declarations-and-fake-headers>`_ for more details. +Note that the fake headers are not included in the ``pip`` package nor installed +via ``setup.py`` (`#224 <https://github.com/eliben/pycparser/issues/224>`_). + Basic usage ----------- @@ -240,18 +249,3 @@ updating this list because Github does a much better job at tracking contributions. -CI Status -========= - -**pycparser** has automatic testing enabled through the convenient -`Travis CI project <https://travis-ci.org>`_. Here is the latest build status: - -.. image:: https://travis-ci.org/eliben/pycparser.png?branch=master - :align: center - :target: https://travis-ci.org/eliben/pycparser - -AppVeyor also helps run tests on Windows: - -.. image:: https://ci.appveyor.com/api/projects/status/wrup68o5y8nuk1i9?svg=true - :align: center - :target: https://ci.appveyor.com/project/eliben/pycparser/ @@ -19,7 +19,7 @@ Now create a new virtualenv and in it install the tarball with `pip install <tarballname>`. See that pycparser is importable in the Python interpreter of this virtualenv; run pycparser tests from this virtualenv. -After this it's OK to rerun `python3.6 setup.py sdist upload` to push to PyPI +After this it's OK to rerun `python3.6 -m twine upload dist/*` to push to PyPI (older Pythons use a deprecated API for PyPI uploading). - Tag in git. When pushing to GitHub, git push --tags diff --git a/appveyor.yml b/appveyor.yml index 05c1c7e..900df8f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,9 +2,9 @@ environment: matrix: - PYTHON: "C:\\Python27" - - PYTHON: "C:\\Python34" - PYTHON: "C:\\Python35" - PYTHON: "C:\\Python36" + - PYTHON: "C:\\Python37" build: off diff --git a/examples/dump_ast.py b/examples/dump_ast.py index 2cff874..63f5e2d 100644 --- a/examples/dump_ast.py +++ b/examples/dump_ast.py @@ -19,7 +19,9 @@ from pycparser import c_parser, c_ast, parse_file if __name__ == "__main__": argparser = argparse.ArgumentParser('Dump AST') argparser.add_argument('filename', help='name of file to parse') + argparser.add_argument('--coord', help='show coordinates in the dump', + action='store_true') args = argparser.parse_args() ast = parse_file(args.filename, use_cpp=False) - ast.show() + ast.show(showcoord=args.coord) diff --git a/examples/func_calls.py b/examples/func_calls.py index ec31fe5..97a7271 100644 --- a/examples/func_calls.py +++ b/examples/func_calls.py @@ -17,9 +17,7 @@ sys.path.extend(['.', '..']) from pycparser import c_parser, c_ast, parse_file -# A visitor with some state information (the funcname it's -# looking for) -# +# A visitor with some state information (the funcname it's looking for) class FuncCallVisitor(c_ast.NodeVisitor): def __init__(self, funcname): self.funcname = funcname @@ -27,6 +25,9 @@ class FuncCallVisitor(c_ast.NodeVisitor): def visit_FuncCall(self, node): if node.name.name == self.funcname: print('%s called at %s' % (self.funcname, node.name.coord)) + # Visit args in case they contain more func calls. + if node.args: + self.visit(node.args) def show_func_calls(filename, funcname): diff --git a/pycparser/__init__.py b/pycparser/__init__.py index b67389f..6e86e9f 100644 --- a/pycparser/__init__.py +++ b/pycparser/__init__.py @@ -8,7 +8,7 @@ # License: BSD #----------------------------------------------------------------- __all__ = ['c_lexer', 'c_parser', 'c_ast'] -__version__ = '2.19' +__version__ = '2.20' import io from subprocess import check_output diff --git a/pycparser/_build_tables.py b/pycparser/_build_tables.py index 94a3891..958381a 100644 --- a/pycparser/_build_tables.py +++ b/pycparser/_build_tables.py @@ -10,13 +10,17 @@ # License: BSD #----------------------------------------------------------------- +# Insert '.' and '..' as first entries to the search path for modules. +# Restricted environments like embeddable python do not include the +# current working directory on startup. +import sys +sys.path[0:0] = ['.', '..'] + # Generate c_ast.py from _ast_gen import ASTCodeGenerator ast_gen = ASTCodeGenerator('_c_ast.cfg') ast_gen.generate(open('c_ast.py', 'w')) -import sys -sys.path[0:0] = ['.', '..'] from pycparser import c_parser # Generates the tables diff --git a/pycparser/ast_transforms.py b/pycparser/ast_transforms.py index ba50966..0aeb88f 100644 --- a/pycparser/ast_transforms.py +++ b/pycparser/ast_transforms.py @@ -74,7 +74,8 @@ def fix_switch_cases(switch_node): # Goes over the children of the Compound below the Switch, adding them # either directly below new_compound or below the last Case as appropriate - for child in switch_node.stmt.block_items: + # (for `switch(cond) {}`, block_items would have been None) + for child in (switch_node.stmt.block_items or []): if isinstance(child, (c_ast.Case, c_ast.Default)): # If it's a Case/Default: # 1. Add it to the Compound and mark as "last case" diff --git a/pycparser/c_generator.py b/pycparser/c_generator.py index f789742..973d24a 100644 --- a/pycparser/c_generator.py +++ b/pycparser/c_generator.py @@ -119,7 +119,7 @@ class CGenerator(object): return s def visit_Cast(self, n): - s = '(' + self._generate_type(n.to_type) + ')' + s = '(' + self._generate_type(n.to_type, emit_declname=False) + ')' return s + ' ' + self._parenthesize_unless_simple(n.expr) def visit_ExprList(self, n): @@ -291,6 +291,15 @@ class CGenerator(object): def visit_FuncDecl(self, n): return self._generate_type(n) + def visit_ArrayDecl(self, n): + return self._generate_type(n, emit_declname=False) + + def visit_TypeDecl(self, n): + return self._generate_type(n, emit_declname=False) + + def visit_PtrDecl(self, n): + return self._generate_type(n, emit_declname=False) + def _generate_struct_union_enum(self, n, name): """ Generates code for structs, unions, and enums. name should be 'struct', 'union', or 'enum'. @@ -359,7 +368,7 @@ class CGenerator(object): s += self._generate_type(n.type) return s - def _generate_type(self, n, modifiers=[]): + def _generate_type(self, n, modifiers=[], emit_declname = True): """ Recursive generation from a type node. n is the type node. modifiers collects the PtrDecl, ArrayDecl and FuncDecl modifiers encountered on the way down to a TypeDecl, to allow proper @@ -373,23 +382,29 @@ class CGenerator(object): if n.quals: s += ' '.join(n.quals) + ' ' s += self.visit(n.type) - nstr = n.declname if n.declname else '' + nstr = n.declname if n.declname and emit_declname else '' # Resolve modifiers. # Wrap in parens to distinguish pointer to array and pointer to # function syntax. # for i, modifier in enumerate(modifiers): if isinstance(modifier, c_ast.ArrayDecl): - if (i != 0 and isinstance(modifiers[i - 1], c_ast.PtrDecl)): - nstr = '(' + nstr + ')' - nstr += '[' + self.visit(modifier.dim) + ']' + if (i != 0 and + isinstance(modifiers[i - 1], c_ast.PtrDecl)): + nstr = '(' + nstr + ')' + nstr += '[' + if modifier.dim_quals: + nstr += ' '.join(modifier.dim_quals) + ' ' + nstr += self.visit(modifier.dim) + ']' elif isinstance(modifier, c_ast.FuncDecl): - if (i != 0 and isinstance(modifiers[i - 1], c_ast.PtrDecl)): - nstr = '(' + nstr + ')' + if (i != 0 and + isinstance(modifiers[i - 1], c_ast.PtrDecl)): + nstr = '(' + nstr + ')' nstr += '(' + self.visit(modifier.args) + ')' elif isinstance(modifier, c_ast.PtrDecl): if modifier.quals: - nstr = '* %s %s' % (' '.join(modifier.quals), nstr) + nstr = '* %s%s' % (' '.join(modifier.quals), + ' ' + nstr if nstr else '') else: nstr = '*' + nstr if nstr: s += ' ' + nstr @@ -397,11 +412,12 @@ class CGenerator(object): elif typ == c_ast.Decl: return self._generate_decl(n.type) elif typ == c_ast.Typename: - return self._generate_type(n.type) + return self._generate_type(n.type, emit_declname = emit_declname) elif typ == c_ast.IdentifierType: return ' '.join(n.names) + ' ' elif typ in (c_ast.ArrayDecl, c_ast.PtrDecl, c_ast.FuncDecl): - return self._generate_type(n.type, modifiers + [n]) + return self._generate_type(n.type, modifiers + [n], + emit_declname = emit_declname) else: return self.visit(n) diff --git a/pycparser/c_lexer.py b/pycparser/c_lexer.py index de8445e..045d24e 100644 --- a/pycparser/c_lexer.py +++ b/pycparser/c_lexer.py @@ -19,7 +19,7 @@ class CLexer(object): tokens. The public attribute filename can be set to an initial - filaneme, but the lexer will update it upon #line + filename, but the lexer will update it upon #line directives. """ def __init__(self, error_func, on_lbrace_func, on_rbrace_func, @@ -130,7 +130,7 @@ class CLexer(object): 'TYPEID', # constants - 'INT_CONST_DEC', 'INT_CONST_OCT', 'INT_CONST_HEX', 'INT_CONST_BIN', + 'INT_CONST_DEC', 'INT_CONST_OCT', 'INT_CONST_HEX', 'INT_CONST_BIN', 'INT_CONST_CHAR', 'FLOAT_CONST', 'HEX_FLOAT_CONST', 'CHAR_CONST', 'WCHAR_CONST', @@ -205,23 +205,49 @@ class CLexer(object): # parse all correct code, even if it means to sometimes parse incorrect # code. # - simple_escape = r"""([a-zA-Z._~!=&\^\-\\?'"])""" - decimal_escape = r"""(\d+)""" - hex_escape = r"""(x[0-9a-fA-F]+)""" - bad_escape = r"""([\\][^a-zA-Z._~^!=&\^\-\\?'"x0-7])""" + # The original regexes were taken verbatim from the C syntax definition, + # and were later modified to avoid worst-case exponential running time. + # + # simple_escape = r"""([a-zA-Z._~!=&\^\-\\?'"])""" + # decimal_escape = r"""(\d+)""" + # hex_escape = r"""(x[0-9a-fA-F]+)""" + # bad_escape = r"""([\\][^a-zA-Z._~^!=&\^\-\\?'"x0-7])""" + # + # The following modifications were made to avoid the ambiguity that allowed backtracking: + # (https://github.com/eliben/pycparser/issues/61) + # + # - \x was removed from simple_escape, unless it was not followed by a hex digit, to avoid ambiguity with hex_escape. + # - hex_escape allows one or more hex characters, but requires that the next character(if any) is not hex + # - decimal_escape allows one or more decimal characters, but requires that the next character(if any) is not a decimal + # - bad_escape does not allow any decimals (8-9), to avoid conflicting with the permissive decimal_escape. + # + # Without this change, python's `re` module would recursively try parsing each ambiguous escape sequence in multiple ways. + # e.g. `\123` could be parsed as `\1`+`23`, `\12`+`3`, and `\123`. + + simple_escape = r"""([a-wyzA-Z._~!=&\^\-\\?'"]|x(?![0-9a-fA-F]))""" + decimal_escape = r"""(\d+)(?!\d)""" + hex_escape = r"""(x[0-9a-fA-F]+)(?![0-9a-fA-F])""" + bad_escape = r"""([\\][^a-zA-Z._~^!=&\^\-\\?'"x0-9])""" escape_sequence = r"""(\\("""+simple_escape+'|'+decimal_escape+'|'+hex_escape+'))' + + # This complicated regex with lookahead might be slow for strings, so because all of the valid escapes (including \x) allowed + # 0 or more non-escaped characters after the first character, simple_escape+decimal_escape+hex_escape got simplified to + + escape_sequence_start_in_string = r"""(\\[0-9a-zA-Z._~!=&\^\-\\?'"])""" + cconst_char = r"""([^'\\\n]|"""+escape_sequence+')' char_const = "'"+cconst_char+"'" wchar_const = 'L'+char_const + multicharacter_constant = "'"+cconst_char+"{2,4}'" unmatched_quote = "('"+cconst_char+"*\\n)|('"+cconst_char+"*$)" bad_char_const = r"""('"""+cconst_char+"""[^'\n]+')|('')|('"""+bad_escape+r"""[^'\n]*')""" # string literals (K&R2: A.2.6) - string_char = r"""([^"\\\n]|"""+escape_sequence+')' + string_char = r"""([^"\\\n]|"""+escape_sequence_start_in_string+')' string_literal = '"'+string_char+'*"' wstring_literal = 'L'+string_literal - bad_string_literal = '"'+string_char+'*?'+bad_escape+string_char+'*"' + bad_string_literal = '"'+string_char+'*'+bad_escape+string_char+'*"' # floating constants (K&R2: A.2.5.3) exponent_part = r"""([eE][-+]?[0-9]+)""" @@ -443,6 +469,10 @@ class CLexer(object): # Must come before bad_char_const, to prevent it from # catching valid char constants as invalid # + @TOKEN(multicharacter_constant) + def t_INT_CONST_CHAR(self, t): + return t + @TOKEN(char_const) def t_CHAR_CONST(self, t): return t diff --git a/pycparser/c_parser.py b/pycparser/c_parser.py index 0e6e755..744ede8 100644 --- a/pycparser/c_parser.py +++ b/pycparser/c_parser.py @@ -529,8 +529,7 @@ class CParser(PLYParser): def p_translation_unit_2(self, p): """ translation_unit : translation_unit external_declaration """ - if p[2] is not None: - p[1].extend(p[2]) + p[1].extend(p[2]) p[0] = p[1] # Declarations always come as lists (because they can be @@ -557,7 +556,7 @@ class CParser(PLYParser): def p_external_declaration_4(self, p): """ external_declaration : SEMI """ - p[0] = None + p[0] = [] def p_pp_directive(self, p): """ pp_directive : PPHASH @@ -1411,12 +1410,13 @@ class CParser(PLYParser): p[0] = self._type_modify_decl(decl=p[1], modifier=arr) def p_direct_abstract_declarator_3(self, p): - """ direct_abstract_declarator : LBRACKET assignment_expression_opt RBRACKET + """ direct_abstract_declarator : LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET """ + quals = (p[2] if len(p) > 4 else []) or [] p[0] = c_ast.ArrayDecl( type=c_ast.TypeDecl(None, None, None), - dim=p[2], - dim_quals=[], + dim=p[3] if len(p) > 4 else p[2], + dim_quals=quals, coord=self._token_coord(p, 1)) def p_direct_abstract_declarator_4(self, p): @@ -1740,8 +1740,7 @@ class CParser(PLYParser): if len(p) == 2: p[0] = p[1] elif len(p) == 4: - field = c_ast.ID(p[3], self._token_coord(p, 3)) - p[0] = c_ast.StructRef(p[1], p[2], field, p[1].coord) + p[0] = c_ast.StructRef(p[1], p[2], p[3], p[1].coord) elif len(p) == 5: p[0] = c_ast.ArrayRef(p[1], p[3], p[1].coord) else: @@ -1766,9 +1765,23 @@ class CParser(PLYParser): | INT_CONST_OCT | INT_CONST_HEX | INT_CONST_BIN - """ + | INT_CONST_CHAR + """ + uCount = 0 + lCount = 0 + for x in p[1][-3:]: + if x in ('l', 'L'): + lCount += 1 + elif x in ('u', 'U'): + uCount += 1 + t = '' + if uCount > 1: + raise ValueError('Constant cannot have more than one u/U suffix.') + elif lCount > 2: + raise ValueError('Constant cannot have more than two l/L suffix.') + prefix = 'unsigned ' * uCount + 'long ' * lCount p[0] = c_ast.Constant( - 'int', p[1], self._token_coord(p, 1)) + prefix + 'int', p[1], self._token_coord(p, 1)) def p_constant_2(self, p): """ constant : FLOAT_CONST @@ -43,7 +43,7 @@ setup( C compilers or analysis tools. """, license='BSD', - version='2.19', + version='2.20', author='Eli Bendersky', maintainer='Eli Bendersky', author_email='eliben@gmail.com', diff --git a/tests/test_c_generator.py b/tests/test_c_generator.py index 3727f91..dd19a11 100644 --- a/tests/test_c_generator.py +++ b/tests/test_c_generator.py @@ -1,11 +1,12 @@ +import os +import platform import sys -import textwrap import unittest # Run from the root dir sys.path.insert(0, '.') -from pycparser import c_parser, c_generator, c_ast +from pycparser import c_parser, c_generator, c_ast, parse_file _c_parser = c_parser.CParser( lex_optimize=False, @@ -332,6 +333,62 @@ class TestCtoC(unittest.TestCase): name='', ) + def test_array_decl(self): + self._assert_ctoc_correct('int g(const int a[const 20]){}') + ast = parse_to_ast('const int a[const 20];') + generator = c_generator.CGenerator() + self.assertEqual(generator.visit(ast.ext[0].type), + 'const int [const 20]') + self.assertEqual(generator.visit(ast.ext[0].type.type), + 'const int') + + def test_ptr_decl(self): + src = 'const int ** const x;' + self._assert_ctoc_correct(src) + ast = parse_to_ast(src) + generator = c_generator.CGenerator() + self.assertEqual(generator.visit(ast.ext[0].type), + 'const int ** const') + self.assertEqual(generator.visit(ast.ext[0].type.type), + 'const int *') + self.assertEqual(generator.visit(ast.ext[0].type.type.type), + 'const int') + + +class TestCasttoC(unittest.TestCase): + def _find_file(self, name): + test_dir = os.path.dirname(__file__) + name = os.path.join(test_dir, 'c_files', name) + assert os.path.exists(name) + return name + + def test_to_type(self): + src = 'int *x;' + generator = c_generator.CGenerator() + test_fun = c_ast.FuncCall(c_ast.ID('test_fun'), c_ast.ExprList([])) + + ast1 = parse_to_ast(src) + int_ptr_type = ast1.ext[0].type + int_type = int_ptr_type.type + self.assertEqual(generator.visit(c_ast.Cast(int_ptr_type, test_fun)), + '(int *) test_fun()') + self.assertEqual(generator.visit(c_ast.Cast(int_type, test_fun)), + '(int) test_fun()') + + @unittest.skipUnless(platform.system() == 'Linux', + 'cpp only works on Linux') + def test_to_type_with_cpp(self): + generator = c_generator.CGenerator() + test_fun = c_ast.FuncCall(c_ast.ID('test_fun'), c_ast.ExprList([])) + memmgr_path = self._find_file('memmgr.h') + + ast2 = parse_file(memmgr_path, use_cpp=True) + void_ptr_type = ast2.ext[-3].type.type + void_type = void_ptr_type.type + self.assertEqual(generator.visit(c_ast.Cast(void_ptr_type, test_fun)), + '(void *) test_fun()') + self.assertEqual(generator.visit(c_ast.Cast(void_type, test_fun)), + '(void) test_fun()') if __name__ == "__main__": unittest.main() diff --git a/tests/test_c_lexer.py b/tests/test_c_lexer.py index 11c7b26..d63d6fd 100644 --- a/tests/test_c_lexer.py +++ b/tests/test_c_lexer.py @@ -77,6 +77,10 @@ class TestCLexerNoErrors(unittest.TestCase): self.assertTokensTypes('0xf7', ['INT_CONST_HEX']) self.assertTokensTypes('0b110', ['INT_CONST_BIN']) self.assertTokensTypes('0x01202AAbbf7Ul', ['INT_CONST_HEX']) + self.assertTokensTypes("'12'", ['INT_CONST_CHAR']) + self.assertTokensTypes("'123'", ['INT_CONST_CHAR']) + self.assertTokensTypes("'1AB4'", ['INT_CONST_CHAR']) + self.assertTokensTypes(r"'1A\n4'", ['INT_CONST_CHAR']) # no 0 before x, so ID catches it self.assertTokensTypes('xf7', ['ID']) @@ -116,6 +120,7 @@ class TestCLexerNoErrors(unittest.TestCase): self.assertTokensTypes(r"""'\t'""", ['CHAR_CONST']) self.assertTokensTypes(r"""'\''""", ['CHAR_CONST']) self.assertTokensTypes(r"""'\?'""", ['CHAR_CONST']) + self.assertTokensTypes(r"""'\0'""", ['CHAR_CONST']) self.assertTokensTypes(r"""'\012'""", ['CHAR_CONST']) self.assertTokensTypes(r"""'\x2f'""", ['CHAR_CONST']) self.assertTokensTypes(r"""'\x2f12'""", ['CHAR_CONST']) @@ -149,6 +154,24 @@ class TestCLexerNoErrors(unittest.TestCase): self.assertTokensTypes( '"\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123"', ['STRING_LITERAL']) + # Note: a-zA-Z and '.-~^_!=&;,' are allowed as escape chars to support #line + # directives with Windows paths as filenames (..\..\dir\file) + self.assertTokensTypes( + r'"\x"', + ['STRING_LITERAL']) + self.assertTokensTypes( + r'"\a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z\A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z"', + ['STRING_LITERAL']) + self.assertTokensTypes( + r'"C:\x\fa\x1e\xited"', + ['STRING_LITERAL']) + # The lexer is permissive and allows decimal escapes (not just octal) + self.assertTokensTypes( + '"jx\9"', + ['STRING_LITERAL']) + self.assertTokensTypes( + '"fo\9999999"', + ['STRING_LITERAL']) def test_mess(self): self.assertTokensTypes( @@ -428,14 +451,24 @@ class TestCLexerErrors(unittest.TestCase): def test_char_constants(self): self.assertLexerError("'", ERR_UNMATCHED_QUOTE) self.assertLexerError("'b\n", ERR_UNMATCHED_QUOTE) - - self.assertLexerError("'jx'", ERR_INVALID_CCONST) + self.assertLexerError("'\\xaa\n'", ERR_UNMATCHED_QUOTE) + + self.assertLexerError(r"'123\12a'", ERR_INVALID_CCONST) + self.assertLexerError(r"'123\xabg'", ERR_INVALID_CCONST) + self.assertLexerError("''", ERR_INVALID_CCONST) + self.assertLexerError("'abcjx'", ERR_INVALID_CCONST) self.assertLexerError(r"'\*'", ERR_INVALID_CCONST) def test_string_literals(self): - self.assertLexerError(r'"jx\9"', ERR_STRING_ESCAPE) + self.assertLexerError(r'"jx\`"', ERR_STRING_ESCAPE) self.assertLexerError(r'"hekllo\* on ix"', ERR_STRING_ESCAPE) self.assertLexerError(r'L"hekllo\* on ix"', ERR_STRING_ESCAPE) + # Should not suffer from slow backtracking + self.assertLexerError(r'"\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\`\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123"', ERR_STRING_ESCAPE) + self.assertLexerError(r'"\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\x23\`\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23"', ERR_STRING_ESCAPE) + # Should not suffer from slow backtracking when there's no end quote + self.assertLexerError(r'"\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\`\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\12\123456', ERR_ILLEGAL_CHAR) + self.assertLexerError(r'"\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\`\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x2\x23456', ERR_ILLEGAL_CHAR) def test_preprocessor(self): self.assertLexerError('#line "ka"', ERR_FILENAME_BEFORE_LINE) diff --git a/tests/test_c_parser.py b/tests/test_c_parser.py index a48f1c6..b6ecdd5 100755 --- a/tests/test_c_parser.py +++ b/tests/test_c_parser.py @@ -136,6 +136,15 @@ class TestCParser_fundamentals(TestCParser_base): ['Decl', 'foo', ['TypeDecl', ['IdentifierType', ['int']]]]) + def test_initial_semi(self): + t = self.parse(';') + self.assertEqual(len(t.ext), 0) + t = self.parse(';int foo;') + self.assertEqual(len(t.ext), 1) + self.assertEqual(expand_decl(t.ext[0]), + ['Decl', 'foo', + ['TypeDecl', ['IdentifierType', ['int']]]]) + def test_coords(self): """ Tests the "coordinates" of parsed elements - file name, line and column numbers, with modification @@ -413,6 +422,7 @@ class TestCParser_fundamentals(TestCParser_base): ['TypeDecl', ['IdentifierType', ['int']]]]]]) def test_func_decls_with_array_dim_qualifiers(self): + # named function parameter self.assertEqual(self.get_decl('int zz(int p[static 10]);'), ['Decl', 'zz', ['FuncDecl', @@ -443,6 +453,30 @@ class TestCParser_fundamentals(TestCParser_base): ['TypeDecl', ['IdentifierType', ['int']]]]]]], ['TypeDecl', ['IdentifierType', ['int']]]]]) + # unnamed function parameter + self.assertEqual(self.get_decl('int zz(int [const 10]);'), + ['Decl', 'zz', + ['FuncDecl', + [['Typename', ['ArrayDecl', '10', ['const'], + ['TypeDecl', ['IdentifierType', ['int']]]]]], + ['TypeDecl', ['IdentifierType', ['int']]]]]) + + self.assertEqual(self.get_decl('int zz(int [restrict][5]);'), + ['Decl', 'zz', + ['FuncDecl', + [['Typename', ['ArrayDecl', '', ['restrict'], + ['ArrayDecl', '5', [], + ['TypeDecl', ['IdentifierType', ['int']]]]]]], + ['TypeDecl', ['IdentifierType', ['int']]]]]) + + self.assertEqual(self.get_decl('int zz(int [const restrict volatile 10][5]);'), + ['Decl', 'zz', + ['FuncDecl', + [['Typename', ['ArrayDecl', '10', ['const', 'restrict', 'volatile'], + ['ArrayDecl', '5', [], + ['TypeDecl', ['IdentifierType', ['int']]]]]]], + ['TypeDecl', ['IdentifierType', ['int']]]]]) + def test_qualifiers_storage_specifiers(self): def assert_qs(txt, index, quals, storage): d = self.parse(txt).ext[index] @@ -495,6 +529,18 @@ class TestCParser_fundamentals(TestCParser_base): ['IdentifierType', ['int']]]]]]) def test_offsetof(self): + def expand_ref(n): + if isinstance(n, StructRef): + return ['StructRef', expand_ref(n.name), expand_ref(n.field)] + elif isinstance(n, ArrayRef): + return ['ArrayRef', expand_ref(n.name), expand_ref(n.subscript)] + elif isinstance(n, ID): + return ['ID', n.name] + elif isinstance(n, Constant): + return ['Constant', n.type, n.value] + else: + raise TypeError("Unexpected type " + n.__class__.__name__) + e = """ void foo() { int a = offsetof(struct S, p); @@ -512,8 +558,20 @@ class TestCParser_fundamentals(TestCParser_base): self.assertIsInstance(s1.args.exprs[1], ID) s3 = compound.block_items[2].init self.assertIsInstance(s3.args.exprs[1], StructRef) + self.assertEqual(expand_ref(s3.args.exprs[1]), + ['StructRef', + ['StructRef', ['ID', 'p'], ['ID', 'q']], + ['ID', 'r']]) s4 = compound.block_items[3].init self.assertIsInstance(s4.args.exprs[1], ArrayRef) + self.assertEqual(expand_ref(s4.args.exprs[1]), + ['ArrayRef', + ['ArrayRef', + ['StructRef', + ['ArrayRef', ['ID', 'p'], ['Constant', 'int', '5']], + ['ID', 'q']], + ['Constant', 'int', '4']], + ['Constant', 'int', '5']]) def test_compound_statement(self): e = """ @@ -828,6 +886,19 @@ class TestCParser_fundamentals(TestCParser_base): ['Decl', 'd', ['TypeDecl', ['IdentifierType', ['char']]]]]]]]) + def test_struct_with_initial_semi(self): + s1 = """ + struct { + ;int a; + } foo; + """ + s1_ast = self.parse(s1) + self.assertEqual(expand_decl(s1_ast.ext[0]), + ['Decl', 'foo', + ['TypeDecl', ['Struct', None, + [['Decl', 'a', + ['TypeDecl', ['IdentifierType', ['int']]]]]]]]) + def test_anonymous_struct_union(self): s1 = """ union @@ -1240,6 +1311,22 @@ class TestCParser_fundamentals(TestCParser_base): self.assertEqual(self.get_decl_init(d55), ['Constant', 'float', '0xDE.38p0']) + d6 = 'int i = 1;' + self.assertEqual(self.get_decl_init(d6), + ['Constant', 'int', '1']) + + d61 = 'long int li = 1l;' + self.assertEqual(self.get_decl_init(d61), + ['Constant', 'long int', '1l']) + + d62 = 'unsigned int ui = 1u;' + self.assertEqual(self.get_decl_init(d62), + ['Constant', 'unsigned int', '1u']) + + d63 = 'unsigned long long int ulli = 1LLU;' + self.assertEqual(self.get_decl_init(d63), + ['Constant', 'unsigned long long int', '1LLU']) + def test_decl_named_inits(self): d1 = 'int a = {.k = 16};' self.assertEqual(self.get_decl_init(d1), @@ -1407,6 +1494,10 @@ class TestCParser_fundamentals(TestCParser_base): void main() { #pragma foo for(;;) {} + #pragma baz + { + int i = 0; + } #pragma } struct s { @@ -1423,12 +1514,16 @@ class TestCParser_fundamentals(TestCParser_base): self.assertEqual(s1_ast.ext[1].body.block_items[0].coord.line, 4) self.assertIsInstance(s1_ast.ext[1].body.block_items[2], Pragma) - self.assertEqual(s1_ast.ext[1].body.block_items[2].string, '') + self.assertEqual(s1_ast.ext[1].body.block_items[2].string, 'baz') self.assertEqual(s1_ast.ext[1].body.block_items[2].coord.line, 6) + self.assertIsInstance(s1_ast.ext[1].body.block_items[4], Pragma) + self.assertEqual(s1_ast.ext[1].body.block_items[4].string, '') + self.assertEqual(s1_ast.ext[1].body.block_items[4].coord.line, 10) + self.assertIsInstance(s1_ast.ext[2].type.type.decls[0], Pragma) self.assertEqual(s1_ast.ext[2].type.type.decls[0].string, 'baz') - self.assertEqual(s1_ast.ext[2].type.type.decls[0].coord.line, 9) + self.assertEqual(s1_ast.ext[2].type.type.decls[0].coord.line, 13) def test_pragmacomp_or_statement(self): s1 = r''' @@ -1475,8 +1570,10 @@ class TestCParser_fundamentals(TestCParser_base): self.assertIsInstance(s1_ast.ext[0].body.block_items[4].iftrue.block_items[1], Assignment) self.assertIsInstance(s1_ast.ext[0].body.block_items[5], Switch) self.assertIsInstance(s1_ast.ext[0].body.block_items[5].stmt.stmts[0], Compound) - self.assertIsInstance(s1_ast.ext[0].body.block_items[5].stmt.stmts[0].block_items[0], Pragma) - self.assertIsInstance(s1_ast.ext[0].body.block_items[5].stmt.stmts[0].block_items[1], Assignment) + self.assertIsInstance(s1_ast.ext[0].body.block_items[5].stmt.stmts[0].block_items[0], + Pragma) + self.assertIsInstance(s1_ast.ext[0].body.block_items[5].stmt.stmts[0].block_items[1], + Assignment) class TestCParser_whole_code(TestCParser_base): @@ -1719,6 +1816,7 @@ class TestCParser_whole_code(TestCParser_base): switch = ps1.ext[0].body.block_items[0] block = switch.stmt.block_items + self.assertEqual(len(block), 4) assert_case_node(block[0], '10') self.assertEqual(len(block[0].stmts), 3) assert_case_node(block[1], '20') @@ -1746,6 +1844,7 @@ class TestCParser_whole_code(TestCParser_base): switch = ps2.ext[0].body.block_items[0] block = switch.stmt.block_items + self.assertEqual(len(block), 5) assert_default_node(block[0]) self.assertEqual(len(block[0].stmts), 2) assert_case_node(block[1], '10') @@ -1757,6 +1856,18 @@ class TestCParser_whole_code(TestCParser_base): assert_case_node(block[4], '40') self.assertEqual(len(block[4].stmts), 1) + s3 = r''' + int foo(void) { + switch (myvar) { + } + return 0; + } + ''' + ps3 = self.parse(s3) + switch = ps3.ext[0].body.block_items[0] + + self.assertEqual(switch.stmt.block_items, []) + def test_for_statement(self): s2 = r''' void x(void) diff --git a/utils/benchmark/README.rst b/utils/benchmark/README.rst new file mode 100644 index 0000000..652b274 --- /dev/null +++ b/utils/benchmark/README.rst @@ -0,0 +1,22 @@ +Basic benchmarking of parsing speed with pycparser. + +The ``inputs`` directory contains preprocessed files taken from open source +projects. + +``redis.c.pp`` taken from Redis. Generated with: + +.. sourcecode:: + + gcc -nostdinc -D'__attribute__(x)=' -E -Isrc/ -Ideps/hiredis -Ideps/linenoise -I$HOME/eli/pycparser/utils/fake_libc_include src/redis-cli.c + +``tccgen.c.pp`` taken from TCC. Generated with: + +.. sourcecode:: + + gcc -nostdinc -D'__attribute__(x)=' -E -I. -I$HOME/eli/pycparser/utils/fake_libc_include tccgen.c + +``sqlite-btree.c.pp`` taken from SQLite. Generated with: + +.. sourcecode:: + + gcc -nostdinc -D'__attribute__(x)=' -E -I. -Isrc/ -I$HOME/eli/pycparser/utils/fake_libc_include src/btree.c diff --git a/utils/benchmark/benchmark-parse.py b/utils/benchmark/benchmark-parse.py new file mode 100644 index 0000000..003acda --- /dev/null +++ b/utils/benchmark/benchmark-parse.py @@ -0,0 +1,58 @@ +#----------------------------------------------------------------- +# Benchmarking utility for internal use. +# +# Use with Python 3.6+ +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +#----------------------------------------------------------------- +import os +import statistics +import sys +import time + +sys.path.extend(['.', '..']) + +from pycparser import c_parser, c_ast + + +def measure_parse(text, n, progress_cb): + """Measure the parsing of text with pycparser. + + text should represent a full file. n is the number of iterations to measure. + progress_cb will be called with the iteration number each time one is done. + + Returns a list of elapsed times, one per iteration. + """ + times = [] + for i in range(n): + parser = c_parser.CParser() + t1 = time.time() + ast = parser.parse(text, '') + elapsed = time.time() - t1 + assert isinstance(ast, c_ast.FileAST) + times.append(elapsed) + progress_cb(i) + return times + + +def measure_file(filename, n): + progress_cb = lambda i: print('.', sep='', end='', flush=True) + with open(filename) as f: + print('%-25s' % os.path.basename(filename), end='', flush=True) + text = f.read() + times = measure_parse(text, n, progress_cb) + print(' Mean: %.3f Stddev: %.3f' % (statistics.mean(times), + statistics.stdev(times))) + + +NUM_RUNS = 5 + + +if __name__ == '__main__': + if len(sys.argv) < 2: + print("Usage: %s <dir with input files>") + sys.exit(1) + for filename in os.listdir(sys.argv[1]): + filename = os.path.join(sys.argv[1], filename) + measure_file(filename, NUM_RUNS) diff --git a/utils/benchmark/inputs/redis.c.ppout b/utils/benchmark/inputs/redis.c.ppout new file mode 100644 index 0000000..b1fa222 --- /dev/null +++ b/utils/benchmark/inputs/redis.c.ppout @@ -0,0 +1,4621 @@ +# 1 "src/redis-cli.c" +# 1 "<built-in>" +# 1 "<command-line>" +# 1 "src/redis-cli.c" +# 31 "src/redis-cli.c" +# 1 "src/fmacros.h" 1 +# 32 "src/redis-cli.c" 2 +# 1 "src/version.h" 1 +# 33 "src/redis-cli.c" 2 + +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_typedefs.h" 1 + + + +typedef int size_t; +typedef int __builtin_va_list; +typedef int __gnuc_va_list; +typedef int va_list; +typedef int __int8_t; +typedef int __uint8_t; +typedef int __int16_t; +typedef int __uint16_t; +typedef int __int_least16_t; +typedef int __uint_least16_t; +typedef int __int32_t; +typedef int __uint32_t; +typedef int __int64_t; +typedef int __uint64_t; +typedef int __int_least32_t; +typedef int __uint_least32_t; +typedef int __s8; +typedef int __u8; +typedef int __s16; +typedef int __u16; +typedef int __s32; +typedef int __u32; +typedef int __s64; +typedef int __u64; +typedef int _LOCK_T; +typedef int _LOCK_RECURSIVE_T; +typedef int _off_t; +typedef int __dev_t; +typedef int __uid_t; +typedef int __gid_t; +typedef int _off64_t; +typedef int _fpos_t; +typedef int _ssize_t; +typedef int wint_t; +typedef int _mbstate_t; +typedef int _flock_t; +typedef int _iconv_t; +typedef int __ULong; +typedef int __FILE; +typedef int ptrdiff_t; +typedef int wchar_t; +typedef int __off_t; +typedef int __pid_t; +typedef int __loff_t; +typedef int u_char; +typedef int u_short; +typedef int u_int; +typedef int u_long; +typedef int ushort; +typedef int uint; +typedef int clock_t; +typedef int time_t; +typedef int daddr_t; +typedef int caddr_t; +typedef int ino_t; +typedef int off_t; +typedef int dev_t; +typedef int uid_t; +typedef int gid_t; +typedef int pid_t; +typedef int key_t; +typedef int ssize_t; +typedef int mode_t; +typedef int nlink_t; +typedef int fd_mask; +typedef int _types_fd_set; +typedef int clockid_t; +typedef int timer_t; +typedef int useconds_t; +typedef int suseconds_t; +typedef int FILE; +typedef int fpos_t; +typedef int cookie_read_function_t; +typedef int cookie_write_function_t; +typedef int cookie_seek_function_t; +typedef int cookie_close_function_t; +typedef int cookie_io_functions_t; +typedef int div_t; +typedef int ldiv_t; +typedef int lldiv_t; +typedef int sigset_t; +typedef int __sigset_t; +typedef int _sig_func_ptr; +typedef int sig_atomic_t; +typedef int __tzrule_type; +typedef int __tzinfo_type; +typedef int mbstate_t; +typedef int sem_t; +typedef int pthread_t; +typedef int pthread_attr_t; +typedef int pthread_mutex_t; +typedef int pthread_mutexattr_t; +typedef int pthread_cond_t; +typedef int pthread_condattr_t; +typedef int pthread_key_t; +typedef int pthread_once_t; +typedef int pthread_rwlock_t; +typedef int pthread_rwlockattr_t; +typedef int pthread_spinlock_t; +typedef int pthread_barrier_t; +typedef int pthread_barrierattr_t; +typedef int jmp_buf; +typedef int rlim_t; +typedef int sa_family_t; +typedef int sigjmp_buf; +typedef int stack_t; +typedef int siginfo_t; +typedef int z_stream; + + +typedef int int8_t; +typedef int uint8_t; +typedef int int16_t; +typedef int uint16_t; +typedef int int32_t; +typedef int uint32_t; +typedef int int64_t; +typedef int uint64_t; + + +typedef int int_least8_t; +typedef int uint_least8_t; +typedef int int_least16_t; +typedef int uint_least16_t; +typedef int int_least32_t; +typedef int uint_least32_t; +typedef int int_least64_t; +typedef int uint_least64_t; + + +typedef int int_fast8_t; +typedef int uint_fast8_t; +typedef int int_fast16_t; +typedef int uint_fast16_t; +typedef int int_fast32_t; +typedef int uint_fast32_t; +typedef int int_fast64_t; +typedef int uint_fast64_t; + + +typedef int intptr_t; +typedef int uintptr_t; + + +typedef int intmax_t; +typedef int uintmax_t; + + +typedef _Bool bool; + + +typedef void* MirEGLNativeWindowType; +typedef void* MirEGLNativeDisplayType; +typedef struct MirConnection MirConnection; +typedef struct MirSurface MirSurface; +typedef struct MirSurfaceSpec MirSurfaceSpec; +typedef struct MirScreencast MirScreencast; +typedef struct MirPromptSession MirPromptSession; +typedef struct MirBufferStream MirBufferStream; +typedef struct MirPersistentId MirPersistentId; +typedef struct MirBlob MirBlob; +typedef struct MirDisplayConfig MirDisplayConfig; + + +typedef struct xcb_connection_t xcb_connection_t; +typedef uint32_t xcb_window_t; +typedef uint32_t xcb_visualid_t; +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 2 +# 35 "src/redis-cli.c" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/string.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/string.h" 2 +# 36 "src/redis-cli.c" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdlib.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdlib.h" 2 +# 37 "src/redis-cli.c" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/signal.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/signal.h" 2 +# 38 "src/redis-cli.c" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/unistd.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/unistd.h" 2 +# 39 "src/redis-cli.c" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 2 +# 40 "src/redis-cli.c" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/ctype.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/ctype.h" 2 +# 41 "src/redis-cli.c" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/errno.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/errno.h" 2 +# 42 "src/redis-cli.c" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/stat.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/stat.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_typedefs.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/stat.h" 2 +# 43 "src/redis-cli.c" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 2 +# 44 "src/redis-cli.c" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/assert.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/assert.h" 2 +# 45 "src/redis-cli.c" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/fcntl.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/fcntl.h" 2 +# 46 "src/redis-cli.c" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/limits.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/limits.h" 2 +# 47 "src/redis-cli.c" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/math.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/math.h" 2 +# 48 "src/redis-cli.c" 2 + +# 1 "deps/hiredis/hiredis.h" 1 +# 36 "deps/hiredis/hiredis.h" +# 1 "deps/hiredis/read.h" 1 +# 35 "deps/hiredis/read.h" +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 2 +# 36 "deps/hiredis/read.h" 2 +# 63 "deps/hiredis/read.h" +typedef struct redisReadTask { + int type; + int elements; + int idx; + void *obj; + struct redisReadTask *parent; + void *privdata; +} redisReadTask; + +typedef struct redisReplyObjectFunctions { + void *(*createString)(const redisReadTask*, char*, size_t); + void *(*createArray)(const redisReadTask*, int); + void *(*createInteger)(const redisReadTask*, long long); + void *(*createNil)(const redisReadTask*); + void (*freeObject)(void*); +} redisReplyObjectFunctions; + +typedef struct redisReader { + int err; + char errstr[128]; + + char *buf; + size_t pos; + size_t len; + size_t maxbuf; + + redisReadTask rstack[9]; + int ridx; + void *reply; + + redisReplyObjectFunctions *fn; + void *privdata; +} redisReader; + + +redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn); +void redisReaderFree(redisReader *r); +int redisReaderFeed(redisReader *r, const char *buf, size_t len); +int redisReaderGetReply(redisReader *r, void **reply); +# 37 "deps/hiredis/hiredis.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 2 +# 38 "deps/hiredis/hiredis.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 2 +# 39 "deps/hiredis/hiredis.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdint.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdint.h" 2 +# 40 "deps/hiredis/hiredis.h" 2 +# 1 "deps/hiredis/sds.h" 1 +# 38 "deps/hiredis/sds.h" +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/types.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/types.h" 2 +# 39 "deps/hiredis/sds.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 2 +# 40 "deps/hiredis/sds.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdint.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdint.h" 2 +# 41 "deps/hiredis/sds.h" 2 + +typedef char *sds; + + + +struct sdshdr5 { + unsigned char flags; + char buf[]; +}; +struct sdshdr8 { + uint8_t len; + uint8_t alloc; + unsigned char flags; + char buf[]; +}; +struct sdshdr16 { + uint16_t len; + uint16_t alloc; + unsigned char flags; + char buf[]; +}; +struct sdshdr32 { + uint32_t len; + uint32_t alloc; + unsigned char flags; + char buf[]; +}; +struct sdshdr64 { + uint64_t len; + uint64_t alloc; + unsigned char flags; + char buf[]; +}; +# 86 "deps/hiredis/sds.h" +static inline size_t sdslen(const sds s) { + unsigned char flags = s[-1]; + switch(flags&7) { + case 0: + return ((flags)>>3); + case 1: + return ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->len; + case 2: + return ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->len; + case 3: + return ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->len; + case 4: + return ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->len; + } + return 0; +} + +static inline size_t sdsavail(const sds s) { + unsigned char flags = s[-1]; + switch(flags&7) { + case 0: { + return 0; + } + case 1: { + struct sdshdr8 *sh = (struct sdshdr8 *)((s)-(sizeof(struct sdshdr8)));; + return sh->alloc - sh->len; + } + case 2: { + struct sdshdr16 *sh = (struct sdshdr16 *)((s)-(sizeof(struct sdshdr16)));; + return sh->alloc - sh->len; + } + case 3: { + struct sdshdr32 *sh = (struct sdshdr32 *)((s)-(sizeof(struct sdshdr32)));; + return sh->alloc - sh->len; + } + case 4: { + struct sdshdr64 *sh = (struct sdshdr64 *)((s)-(sizeof(struct sdshdr64)));; + return sh->alloc - sh->len; + } + } + return 0; +} + +static inline void sdssetlen(sds s, size_t newlen) { + unsigned char flags = s[-1]; + switch(flags&7) { + case 0: + { + unsigned char *fp = ((unsigned char*)s)-1; + *fp = 0 | (newlen << 3); + } + break; + case 1: + ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->len = newlen; + break; + case 2: + ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->len = newlen; + break; + case 3: + ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->len = newlen; + break; + case 4: + ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->len = newlen; + break; + } +} + +static inline void sdsinclen(sds s, size_t inc) { + unsigned char flags = s[-1]; + switch(flags&7) { + case 0: + { + unsigned char *fp = ((unsigned char*)s)-1; + unsigned char newlen = ((flags)>>3)+inc; + *fp = 0 | (newlen << 3); + } + break; + case 1: + ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->len += inc; + break; + case 2: + ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->len += inc; + break; + case 3: + ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->len += inc; + break; + case 4: + ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->len += inc; + break; + } +} + + +static inline size_t sdsalloc(const sds s) { + unsigned char flags = s[-1]; + switch(flags&7) { + case 0: + return ((flags)>>3); + case 1: + return ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->alloc; + case 2: + return ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->alloc; + case 3: + return ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->alloc; + case 4: + return ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->alloc; + } + return 0; +} + +static inline void sdssetalloc(sds s, size_t newlen) { + unsigned char flags = s[-1]; + switch(flags&7) { + case 0: + + break; + case 1: + ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->alloc = newlen; + break; + case 2: + ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->alloc = newlen; + break; + case 3: + ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->alloc = newlen; + break; + case 4: + ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->alloc = newlen; + break; + } +} + +sds sdsnewlen(const void *init, size_t initlen); +sds sdsnew(const char *init); +sds sdsempty(void); +sds sdsdup(const sds s); +void sdsfree(sds s); +sds sdsgrowzero(sds s, size_t len); +sds sdscatlen(sds s, const void *t, size_t len); +sds sdscat(sds s, const char *t); +sds sdscatsds(sds s, const sds t); +sds sdscpylen(sds s, const char *t, size_t len); +sds sdscpy(sds s, const char *t); + +sds sdscatvprintf(sds s, const char *fmt, va_list ap); + +sds sdscatprintf(sds s, const char *fmt, ...) + ; + + + + +sds sdscatfmt(sds s, char const *fmt, ...); +sds sdstrim(sds s, const char *cset); +void sdsrange(sds s, int start, int end); +void sdsupdatelen(sds s); +void sdsclear(sds s); +int sdscmp(const sds s1, const sds s2); +sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count); +void sdsfreesplitres(sds *tokens, int count); +void sdstolower(sds s); +void sdstoupper(sds s); +sds sdsfromlonglong(long long value); +sds sdscatrepr(sds s, const char *p, size_t len); +sds *sdssplitargs(const char *line, int *argc); +sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen); +sds sdsjoin(char **argv, int argc, char *sep); +sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen); + + +sds sdsMakeRoomFor(sds s, size_t addlen); +void sdsIncrLen(sds s, int incr); +sds sdsRemoveFreeSpace(sds s); +size_t sdsAllocSize(sds s); +void *sdsAllocPtr(sds s); + + + + + +void *sds_malloc(size_t size); +void *sds_realloc(void *ptr, size_t size); +void sds_free(void *ptr); +# 41 "deps/hiredis/hiredis.h" 2 +# 112 "deps/hiredis/hiredis.h" +typedef struct redisReply { + int type; + long long integer; + size_t len; + char *str; + size_t elements; + struct redisReply **element; +} redisReply; + +redisReader *redisReaderCreate(void); + + +void freeReplyObject(void *reply); + + +int redisvFormatCommand(char **target, const char *format, va_list ap); +int redisFormatCommand(char **target, const char *format, ...); +int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen); +int redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const size_t *argvlen); +void redisFreeCommand(char *cmd); +void redisFreeSdsCommand(sds cmd); + +enum redisConnectionType { + REDIS_CONN_TCP, + REDIS_CONN_UNIX +}; + + +typedef struct redisContext { + int err; + char errstr[128]; + int fd; + int flags; + char *obuf; + redisReader *reader; + + enum redisConnectionType connection_type; + struct timeval *timeout; + + struct { + char *host; + char *source_addr; + int port; + } tcp; + + struct { + char *path; + } unix_sock; + +} redisContext; + +redisContext *redisConnect(const char *ip, int port); +redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv); +redisContext *redisConnectNonBlock(const char *ip, int port); +redisContext *redisConnectBindNonBlock(const char *ip, int port, + const char *source_addr); +redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port, + const char *source_addr); +redisContext *redisConnectUnix(const char *path); +redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv); +redisContext *redisConnectUnixNonBlock(const char *path); +redisContext *redisConnectFd(int fd); +# 184 "deps/hiredis/hiredis.h" +int redisReconnect(redisContext *c); + +int redisSetTimeout(redisContext *c, const struct timeval tv); +int redisEnableKeepAlive(redisContext *c); +void redisFree(redisContext *c); +int redisFreeKeepFd(redisContext *c); +int redisBufferRead(redisContext *c); +int redisBufferWrite(redisContext *c, int *done); + + + + + +int redisGetReply(redisContext *c, void **reply); +int redisGetReplyFromReader(redisContext *c, void **reply); + + + +int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len); + + + +int redisvAppendCommand(redisContext *c, const char *format, va_list ap); +int redisAppendCommand(redisContext *c, const char *format, ...); +int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); + + + + + + +void *redisvCommand(redisContext *c, const char *format, va_list ap); +void *redisCommand(redisContext *c, const char *format, ...); +void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); +# 50 "src/redis-cli.c" 2 +# 1 "src/sds.h" 1 +# 51 "src/redis-cli.c" 2 +# 1 "src/zmalloc.h" 1 +# 75 "src/zmalloc.h" +void *zmalloc(size_t size); +void *zcalloc(size_t size); +void *zrealloc(void *ptr, size_t size); +void zfree(void *ptr); +char *zstrdup(const char *s); +size_t zmalloc_used_memory(void); +void zmalloc_set_oom_handler(void (*oom_handler)(size_t)); +float zmalloc_get_fragmentation_ratio(size_t rss); +size_t zmalloc_get_rss(void); +size_t zmalloc_get_private_dirty(long pid); +size_t zmalloc_get_smap_bytes_by_field(char *field, long pid); +size_t zmalloc_get_memory_size(void); +void zlibc_free(void *ptr); + + + + + + + +size_t zmalloc_size(void *ptr); +# 52 "src/redis-cli.c" 2 +# 1 "deps/linenoise/linenoise.h" 1 +# 46 "deps/linenoise/linenoise.h" +typedef struct linenoiseCompletions { + size_t len; + char **cvec; +} linenoiseCompletions; + +typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *); +typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold); +typedef void(linenoiseFreeHintsCallback)(void *); +void linenoiseSetCompletionCallback(linenoiseCompletionCallback *); +void linenoiseSetHintsCallback(linenoiseHintsCallback *); +void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *); +void linenoiseAddCompletion(linenoiseCompletions *, const char *); + +char *linenoise(const char *prompt); +void linenoiseFree(void *ptr); +int linenoiseHistoryAdd(const char *line); +int linenoiseHistorySetMaxLen(int len); +int linenoiseHistorySave(const char *filename); +int linenoiseHistoryLoad(const char *filename); +void linenoiseClearScreen(void); +void linenoiseSetMultiLine(int ml); +void linenoisePrintKeyCodes(void); +# 53 "src/redis-cli.c" 2 +# 1 "src/help.h" 1 + + + + + +static char *commandGroups[] = { + "generic", + "string", + "list", + "set", + "sorted_set", + "hash", + "pubsub", + "transactions", + "connection", + "server", + "scripting", + "hyperloglog", + "cluster", + "geo" +}; + +struct commandHelp { + char *name; + char *params; + char *summary; + int group; + char *since; +} commandHelp[] = { + { "APPEND", + "key value", + "Append a value to a key", + 1, + "2.0.0" }, + { "AUTH", + "password", + "Authenticate to the server", + 8, + "1.0.0" }, + { "BGREWRITEAOF", + "-", + "Asynchronously rewrite the append-only file", + 9, + "1.0.0" }, + { "BGSAVE", + "-", + "Asynchronously save the dataset to disk", + 9, + "1.0.0" }, + { "BITCOUNT", + "key [start end]", + "Count set bits in a string", + 1, + "2.6.0" }, + { "BITFIELD", + "key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]", + "Perform arbitrary bitfield integer operations on strings", + 1, + "3.2.0" }, + { "BITOP", + "operation destkey key [key ...]", + "Perform bitwise operations between strings", + 1, + "2.6.0" }, + { "BITPOS", + "key bit [start] [end]", + "Find first bit set or clear in a string", + 1, + "2.8.7" }, + { "BLPOP", + "key [key ...] timeout", + "Remove and get the first element in a list, or block until one is available", + 2, + "2.0.0" }, + { "BRPOP", + "key [key ...] timeout", + "Remove and get the last element in a list, or block until one is available", + 2, + "2.0.0" }, + { "BRPOPLPUSH", + "source destination timeout", + "Pop a value from a list, push it to another list and return it; or block until one is available", + 2, + "2.2.0" }, + { "CLIENT GETNAME", + "-", + "Get the current connection name", + 9, + "2.6.9" }, + { "CLIENT KILL", + "[ip:port] [ID client-id] [TYPE normal|master|slave|pubsub] [ADDR ip:port] [SKIPME yes/no]", + "Kill the connection of a client", + 9, + "2.4.0" }, + { "CLIENT LIST", + "-", + "Get the list of client connections", + 9, + "2.4.0" }, + { "CLIENT PAUSE", + "timeout", + "Stop processing commands from clients for some time", + 9, + "2.9.50" }, + { "CLIENT REPLY", + "ON|OFF|SKIP", + "Instruct the server whether to reply to commands", + 9, + "3.2" }, + { "CLIENT SETNAME", + "connection-name", + "Set the current connection name", + 9, + "2.6.9" }, + { "CLUSTER ADDSLOTS", + "slot [slot ...]", + "Assign new hash slots to receiving node", + 12, + "3.0.0" }, + { "CLUSTER COUNT-FAILURE-REPORTS", + "node-id", + "Return the number of failure reports active for a given node", + 12, + "3.0.0" }, + { "CLUSTER COUNTKEYSINSLOT", + "slot", + "Return the number of local keys in the specified hash slot", + 12, + "3.0.0" }, + { "CLUSTER DELSLOTS", + "slot [slot ...]", + "Set hash slots as unbound in receiving node", + 12, + "3.0.0" }, + { "CLUSTER FAILOVER", + "[FORCE|TAKEOVER]", + "Forces a slave to perform a manual failover of its master.", + 12, + "3.0.0" }, + { "CLUSTER FORGET", + "node-id", + "Remove a node from the nodes table", + 12, + "3.0.0" }, + { "CLUSTER GETKEYSINSLOT", + "slot count", + "Return local key names in the specified hash slot", + 12, + "3.0.0" }, + { "CLUSTER INFO", + "-", + "Provides info about Redis Cluster node state", + 12, + "3.0.0" }, + { "CLUSTER KEYSLOT", + "key", + "Returns the hash slot of the specified key", + 12, + "3.0.0" }, + { "CLUSTER MEET", + "ip port", + "Force a node cluster to handshake with another node", + 12, + "3.0.0" }, + { "CLUSTER NODES", + "-", + "Get Cluster config for the node", + 12, + "3.0.0" }, + { "CLUSTER REPLICATE", + "node-id", + "Reconfigure a node as a slave of the specified master node", + 12, + "3.0.0" }, + { "CLUSTER RESET", + "[HARD|SOFT]", + "Reset a Redis Cluster node", + 12, + "3.0.0" }, + { "CLUSTER SAVECONFIG", + "-", + "Forces the node to save cluster state on disk", + 12, + "3.0.0" }, + { "CLUSTER SET-CONFIG-EPOCH", + "config-epoch", + "Set the configuration epoch in a new node", + 12, + "3.0.0" }, + { "CLUSTER SETSLOT", + "slot IMPORTING|MIGRATING|STABLE|NODE [node-id]", + "Bind a hash slot to a specific node", + 12, + "3.0.0" }, + { "CLUSTER SLAVES", + "node-id", + "List slave nodes of the specified master node", + 12, + "3.0.0" }, + { "CLUSTER SLOTS", + "-", + "Get array of Cluster slot to node mappings", + 12, + "3.0.0" }, + { "COMMAND", + "-", + "Get array of Redis command details", + 9, + "2.8.13" }, + { "COMMAND COUNT", + "-", + "Get total number of Redis commands", + 9, + "2.8.13" }, + { "COMMAND GETKEYS", + "-", + "Extract keys given a full Redis command", + 9, + "2.8.13" }, + { "COMMAND INFO", + "command-name [command-name ...]", + "Get array of specific Redis command details", + 9, + "2.8.13" }, + { "CONFIG GET", + "parameter", + "Get the value of a configuration parameter", + 9, + "2.0.0" }, + { "CONFIG RESETSTAT", + "-", + "Reset the stats returned by INFO", + 9, + "2.0.0" }, + { "CONFIG REWRITE", + "-", + "Rewrite the configuration file with the in memory configuration", + 9, + "2.8.0" }, + { "CONFIG SET", + "parameter value", + "Set a configuration parameter to the given value", + 9, + "2.0.0" }, + { "DBSIZE", + "-", + "Return the number of keys in the selected database", + 9, + "1.0.0" }, + { "DEBUG OBJECT", + "key", + "Get debugging information about a key", + 9, + "1.0.0" }, + { "DEBUG SEGFAULT", + "-", + "Make the server crash", + 9, + "1.0.0" }, + { "DECR", + "key", + "Decrement the integer value of a key by one", + 1, + "1.0.0" }, + { "DECRBY", + "key decrement", + "Decrement the integer value of a key by the given number", + 1, + "1.0.0" }, + { "DEL", + "key [key ...]", + "Delete a key", + 0, + "1.0.0" }, + { "DISCARD", + "-", + "Discard all commands issued after MULTI", + 7, + "2.0.0" }, + { "DUMP", + "key", + "Return a serialized version of the value stored at the specified key.", + 0, + "2.6.0" }, + { "ECHO", + "message", + "Echo the given string", + 8, + "1.0.0" }, + { "EVAL", + "script numkeys key [key ...] arg [arg ...]", + "Execute a Lua script server side", + 10, + "2.6.0" }, + { "EVALSHA", + "sha1 numkeys key [key ...] arg [arg ...]", + "Execute a Lua script server side", + 10, + "2.6.0" }, + { "EXEC", + "-", + "Execute all commands issued after MULTI", + 7, + "1.2.0" }, + { "EXISTS", + "key [key ...]", + "Determine if a key exists", + 0, + "1.0.0" }, + { "EXPIRE", + "key seconds", + "Set a key's time to live in seconds", + 0, + "1.0.0" }, + { "EXPIREAT", + "key timestamp", + "Set the expiration for a key as a UNIX timestamp", + 0, + "1.2.0" }, + { "FLUSHALL", + "-", + "Remove all keys from all databases", + 9, + "1.0.0" }, + { "FLUSHDB", + "-", + "Remove all keys from the current database", + 9, + "1.0.0" }, + { "GEOADD", + "key longitude latitude member [longitude latitude member ...]", + "Add one or more geospatial items in the geospatial index represented using a sorted set", + 13, + "3.2.0" }, + { "GEODIST", + "key member1 member2 [unit]", + "Returns the distance between two members of a geospatial index", + 13, + "3.2.0" }, + { "GEOHASH", + "key member [member ...]", + "Returns members of a geospatial index as standard geohash strings", + 13, + "3.2.0" }, + { "GEOPOS", + "key member [member ...]", + "Returns longitude and latitude of members of a geospatial index", + 13, + "3.2.0" }, + { "GEORADIUS", + "key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]", + "Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a point", + 13, + "3.2.0" }, + { "GEORADIUSBYMEMBER", + "key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]", + "Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a member", + 13, + "3.2.0" }, + { "GET", + "key", + "Get the value of a key", + 1, + "1.0.0" }, + { "GETBIT", + "key offset", + "Returns the bit value at offset in the string value stored at key", + 1, + "2.2.0" }, + { "GETRANGE", + "key start end", + "Get a substring of the string stored at a key", + 1, + "2.4.0" }, + { "GETSET", + "key value", + "Set the string value of a key and return its old value", + 1, + "1.0.0" }, + { "HDEL", + "key field [field ...]", + "Delete one or more hash fields", + 5, + "2.0.0" }, + { "HEXISTS", + "key field", + "Determine if a hash field exists", + 5, + "2.0.0" }, + { "HGET", + "key field", + "Get the value of a hash field", + 5, + "2.0.0" }, + { "HGETALL", + "key", + "Get all the fields and values in a hash", + 5, + "2.0.0" }, + { "HINCRBY", + "key field increment", + "Increment the integer value of a hash field by the given number", + 5, + "2.0.0" }, + { "HINCRBYFLOAT", + "key field increment", + "Increment the float value of a hash field by the given amount", + 5, + "2.6.0" }, + { "HKEYS", + "key", + "Get all the fields in a hash", + 5, + "2.0.0" }, + { "HLEN", + "key", + "Get the number of fields in a hash", + 5, + "2.0.0" }, + { "HMGET", + "key field [field ...]", + "Get the values of all the given hash fields", + 5, + "2.0.0" }, + { "HMSET", + "key field value [field value ...]", + "Set multiple hash fields to multiple values", + 5, + "2.0.0" }, + { "HSCAN", + "key cursor [MATCH pattern] [COUNT count]", + "Incrementally iterate hash fields and associated values", + 5, + "2.8.0" }, + { "HSET", + "key field value", + "Set the string value of a hash field", + 5, + "2.0.0" }, + { "HSETNX", + "key field value", + "Set the value of a hash field, only if the field does not exist", + 5, + "2.0.0" }, + { "HSTRLEN", + "key field", + "Get the length of the value of a hash field", + 5, + "3.2.0" }, + { "HVALS", + "key", + "Get all the values in a hash", + 5, + "2.0.0" }, + { "INCR", + "key", + "Increment the integer value of a key by one", + 1, + "1.0.0" }, + { "INCRBY", + "key increment", + "Increment the integer value of a key by the given amount", + 1, + "1.0.0" }, + { "INCRBYFLOAT", + "key increment", + "Increment the float value of a key by the given amount", + 1, + "2.6.0" }, + { "INFO", + "[section]", + "Get information and statistics about the server", + 9, + "1.0.0" }, + { "KEYS", + "pattern", + "Find all keys matching the given pattern", + 0, + "1.0.0" }, + { "LASTSAVE", + "-", + "Get the UNIX time stamp of the last successful save to disk", + 9, + "1.0.0" }, + { "LINDEX", + "key index", + "Get an element from a list by its index", + 2, + "1.0.0" }, + { "LINSERT", + "key BEFORE|AFTER pivot value", + "Insert an element before or after another element in a list", + 2, + "2.2.0" }, + { "LLEN", + "key", + "Get the length of a list", + 2, + "1.0.0" }, + { "LPOP", + "key", + "Remove and get the first element in a list", + 2, + "1.0.0" }, + { "LPUSH", + "key value [value ...]", + "Prepend one or multiple values to a list", + 2, + "1.0.0" }, + { "LPUSHX", + "key value", + "Prepend a value to a list, only if the list exists", + 2, + "2.2.0" }, + { "LRANGE", + "key start stop", + "Get a range of elements from a list", + 2, + "1.0.0" }, + { "LREM", + "key count value", + "Remove elements from a list", + 2, + "1.0.0" }, + { "LSET", + "key index value", + "Set the value of an element in a list by its index", + 2, + "1.0.0" }, + { "LTRIM", + "key start stop", + "Trim a list to the specified range", + 2, + "1.0.0" }, + { "MGET", + "key [key ...]", + "Get the values of all the given keys", + 1, + "1.0.0" }, + { "MIGRATE", + "host port key|"" destination-db timeout [COPY] [REPLACE] [KEYS key]", + "Atomically transfer a key from a Redis instance to another one.", + 0, + "2.6.0" }, + { "MONITOR", + "-", + "Listen for all requests received by the server in real time", + 9, + "1.0.0" }, + { "MOVE", + "key db", + "Move a key to another database", + 0, + "1.0.0" }, + { "MSET", + "key value [key value ...]", + "Set multiple keys to multiple values", + 1, + "1.0.1" }, + { "MSETNX", + "key value [key value ...]", + "Set multiple keys to multiple values, only if none of the keys exist", + 1, + "1.0.1" }, + { "MULTI", + "-", + "Mark the start of a transaction block", + 7, + "1.2.0" }, + { "OBJECT", + "subcommand [arguments [arguments ...]]", + "Inspect the internals of Redis objects", + 0, + "2.2.3" }, + { "PERSIST", + "key", + "Remove the expiration from a key", + 0, + "2.2.0" }, + { "PEXPIRE", + "key milliseconds", + "Set a key's time to live in milliseconds", + 0, + "2.6.0" }, + { "PEXPIREAT", + "key milliseconds-timestamp", + "Set the expiration for a key as a UNIX timestamp specified in milliseconds", + 0, + "2.6.0" }, + { "PFADD", + "key element [element ...]", + "Adds the specified elements to the specified HyperLogLog.", + 11, + "2.8.9" }, + { "PFCOUNT", + "key [key ...]", + "Return the approximated cardinality of the set(s) observed by the HyperLogLog at key(s).", + 11, + "2.8.9" }, + { "PFMERGE", + "destkey sourcekey [sourcekey ...]", + "Merge N different HyperLogLogs into a single one.", + 11, + "2.8.9" }, + { "PING", + "[message]", + "Ping the server", + 8, + "1.0.0" }, + { "PSETEX", + "key milliseconds value", + "Set the value and expiration in milliseconds of a key", + 1, + "2.6.0" }, + { "PSUBSCRIBE", + "pattern [pattern ...]", + "Listen for messages published to channels matching the given patterns", + 6, + "2.0.0" }, + { "PTTL", + "key", + "Get the time to live for a key in milliseconds", + 0, + "2.6.0" }, + { "PUBLISH", + "channel message", + "Post a message to a channel", + 6, + "2.0.0" }, + { "PUBSUB", + "subcommand [argument [argument ...]]", + "Inspect the state of the Pub/Sub subsystem", + 6, + "2.8.0" }, + { "PUNSUBSCRIBE", + "[pattern [pattern ...]]", + "Stop listening for messages posted to channels matching the given patterns", + 6, + "2.0.0" }, + { "QUIT", + "-", + "Close the connection", + 8, + "1.0.0" }, + { "RANDOMKEY", + "-", + "Return a random key from the keyspace", + 0, + "1.0.0" }, + { "READONLY", + "-", + "Enables read queries for a connection to a cluster slave node", + 12, + "3.0.0" }, + { "READWRITE", + "-", + "Disables read queries for a connection to a cluster slave node", + 12, + "3.0.0" }, + { "RENAME", + "key newkey", + "Rename a key", + 0, + "1.0.0" }, + { "RENAMENX", + "key newkey", + "Rename a key, only if the new key does not exist", + 0, + "1.0.0" }, + { "RESTORE", + "key ttl serialized-value [REPLACE]", + "Create a key using the provided serialized value, previously obtained using DUMP.", + 0, + "2.6.0" }, + { "ROLE", + "-", + "Return the role of the instance in the context of replication", + 9, + "2.8.12" }, + { "RPOP", + "key", + "Remove and get the last element in a list", + 2, + "1.0.0" }, + { "RPOPLPUSH", + "source destination", + "Remove the last element in a list, prepend it to another list and return it", + 2, + "1.2.0" }, + { "RPUSH", + "key value [value ...]", + "Append one or multiple values to a list", + 2, + "1.0.0" }, + { "RPUSHX", + "key value", + "Append a value to a list, only if the list exists", + 2, + "2.2.0" }, + { "SADD", + "key member [member ...]", + "Add one or more members to a set", + 3, + "1.0.0" }, + { "SAVE", + "-", + "Synchronously save the dataset to disk", + 9, + "1.0.0" }, + { "SCAN", + "cursor [MATCH pattern] [COUNT count]", + "Incrementally iterate the keys space", + 0, + "2.8.0" }, + { "SCARD", + "key", + "Get the number of members in a set", + 3, + "1.0.0" }, + { "SCRIPT DEBUG", + "YES|SYNC|NO", + "Set the debug mode for executed scripts.", + 10, + "3.2.0" }, + { "SCRIPT EXISTS", + "script [script ...]", + "Check existence of scripts in the script cache.", + 10, + "2.6.0" }, + { "SCRIPT FLUSH", + "-", + "Remove all the scripts from the script cache.", + 10, + "2.6.0" }, + { "SCRIPT KILL", + "-", + "Kill the script currently in execution.", + 10, + "2.6.0" }, + { "SCRIPT LOAD", + "script", + "Load the specified Lua script into the script cache.", + 10, + "2.6.0" }, + { "SDIFF", + "key [key ...]", + "Subtract multiple sets", + 3, + "1.0.0" }, + { "SDIFFSTORE", + "destination key [key ...]", + "Subtract multiple sets and store the resulting set in a key", + 3, + "1.0.0" }, + { "SELECT", + "index", + "Change the selected database for the current connection", + 8, + "1.0.0" }, + { "SET", + "key value [EX seconds] [PX milliseconds] [NX|XX]", + "Set the string value of a key", + 1, + "1.0.0" }, + { "SETBIT", + "key offset value", + "Sets or clears the bit at offset in the string value stored at key", + 1, + "2.2.0" }, + { "SETEX", + "key seconds value", + "Set the value and expiration of a key", + 1, + "2.0.0" }, + { "SETNX", + "key value", + "Set the value of a key, only if the key does not exist", + 1, + "1.0.0" }, + { "SETRANGE", + "key offset value", + "Overwrite part of a string at key starting at the specified offset", + 1, + "2.2.0" }, + { "SHUTDOWN", + "[NOSAVE|SAVE]", + "Synchronously save the dataset to disk and then shut down the server", + 9, + "1.0.0" }, + { "SINTER", + "key [key ...]", + "Intersect multiple sets", + 3, + "1.0.0" }, + { "SINTERSTORE", + "destination key [key ...]", + "Intersect multiple sets and store the resulting set in a key", + 3, + "1.0.0" }, + { "SISMEMBER", + "key member", + "Determine if a given value is a member of a set", + 3, + "1.0.0" }, + { "SLAVEOF", + "host port", + "Make the server a slave of another instance, or promote it as master", + 9, + "1.0.0" }, + { "SLOWLOG", + "subcommand [argument]", + "Manages the Redis slow queries log", + 9, + "2.2.12" }, + { "SMEMBERS", + "key", + "Get all the members in a set", + 3, + "1.0.0" }, + { "SMOVE", + "source destination member", + "Move a member from one set to another", + 3, + "1.0.0" }, + { "SORT", + "key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]", + "Sort the elements in a list, set or sorted set", + 0, + "1.0.0" }, + { "SPOP", + "key [count]", + "Remove and return one or multiple random members from a set", + 3, + "1.0.0" }, + { "SRANDMEMBER", + "key [count]", + "Get one or multiple random members from a set", + 3, + "1.0.0" }, + { "SREM", + "key member [member ...]", + "Remove one or more members from a set", + 3, + "1.0.0" }, + { "SSCAN", + "key cursor [MATCH pattern] [COUNT count]", + "Incrementally iterate Set elements", + 3, + "2.8.0" }, + { "STRLEN", + "key", + "Get the length of the value stored in a key", + 1, + "2.2.0" }, + { "SUBSCRIBE", + "channel [channel ...]", + "Listen for messages published to the given channels", + 6, + "2.0.0" }, + { "SUNION", + "key [key ...]", + "Add multiple sets", + 3, + "1.0.0" }, + { "SUNIONSTORE", + "destination key [key ...]", + "Add multiple sets and store the resulting set in a key", + 3, + "1.0.0" }, + { "SYNC", + "-", + "Internal command used for replication", + 9, + "1.0.0" }, + { "TIME", + "-", + "Return the current server time", + 9, + "2.6.0" }, + { "TTL", + "key", + "Get the time to live for a key", + 0, + "1.0.0" }, + { "TYPE", + "key", + "Determine the type stored at key", + 0, + "1.0.0" }, + { "UNSUBSCRIBE", + "[channel [channel ...]]", + "Stop listening for messages posted to the given channels", + 6, + "2.0.0" }, + { "UNWATCH", + "-", + "Forget about all watched keys", + 7, + "2.2.0" }, + { "WAIT", + "numslaves timeout", + "Wait for the synchronous replication of all the write commands sent in the context of the current connection", + 0, + "3.0.0" }, + { "WATCH", + "key [key ...]", + "Watch the given keys to determine execution of the MULTI/EXEC block", + 7, + "2.2.0" }, + { "ZADD", + "key [NX|XX] [CH] [INCR] score member [score member ...]", + "Add one or more members to a sorted set, or update its score if it already exists", + 4, + "1.2.0" }, + { "ZCARD", + "key", + "Get the number of members in a sorted set", + 4, + "1.2.0" }, + { "ZCOUNT", + "key min max", + "Count the members in a sorted set with scores within the given values", + 4, + "2.0.0" }, + { "ZINCRBY", + "key increment member", + "Increment the score of a member in a sorted set", + 4, + "1.2.0" }, + { "ZINTERSTORE", + "destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]", + "Intersect multiple sorted sets and store the resulting sorted set in a new key", + 4, + "2.0.0" }, + { "ZLEXCOUNT", + "key min max", + "Count the number of members in a sorted set between a given lexicographical range", + 4, + "2.8.9" }, + { "ZRANGE", + "key start stop [WITHSCORES]", + "Return a range of members in a sorted set, by index", + 4, + "1.2.0" }, + { "ZRANGEBYLEX", + "key min max [LIMIT offset count]", + "Return a range of members in a sorted set, by lexicographical range", + 4, + "2.8.9" }, + { "ZRANGEBYSCORE", + "key min max [WITHSCORES] [LIMIT offset count]", + "Return a range of members in a sorted set, by score", + 4, + "1.0.5" }, + { "ZRANK", + "key member", + "Determine the index of a member in a sorted set", + 4, + "2.0.0" }, + { "ZREM", + "key member [member ...]", + "Remove one or more members from a sorted set", + 4, + "1.2.0" }, + { "ZREMRANGEBYLEX", + "key min max", + "Remove all members in a sorted set between the given lexicographical range", + 4, + "2.8.9" }, + { "ZREMRANGEBYRANK", + "key start stop", + "Remove all members in a sorted set within the given indexes", + 4, + "2.0.0" }, + { "ZREMRANGEBYSCORE", + "key min max", + "Remove all members in a sorted set within the given scores", + 4, + "1.2.0" }, + { "ZREVRANGE", + "key start stop [WITHSCORES]", + "Return a range of members in a sorted set, by index, with scores ordered from high to low", + 4, + "1.2.0" }, + { "ZREVRANGEBYLEX", + "key max min [LIMIT offset count]", + "Return a range of members in a sorted set, by lexicographical range, ordered from higher to lower strings.", + 4, + "2.8.9" }, + { "ZREVRANGEBYSCORE", + "key max min [WITHSCORES] [LIMIT offset count]", + "Return a range of members in a sorted set, by score, with scores ordered from high to low", + 4, + "2.2.0" }, + { "ZREVRANK", + "key member", + "Determine the index of a member in a sorted set, with scores ordered from high to low", + 4, + "2.0.0" }, + { "ZSCAN", + "key cursor [MATCH pattern] [COUNT count]", + "Incrementally iterate sorted sets elements and associated scores", + 4, + "2.8.0" }, + { "ZSCORE", + "key member", + "Get the score associated with the given member in a sorted set", + 4, + "1.2.0" }, + { "ZUNIONSTORE", + "destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]", + "Add multiple sorted sets and store the resulting sorted set in a new key", + 4, + "2.0.0" } +}; +# 54 "src/redis-cli.c" 2 +# 1 "src/anet.h" 1 +# 34 "src/anet.h" +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/types.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/types.h" 2 +# 35 "src/anet.h" 2 +# 52 "src/anet.h" +int anetTcpConnect(char *err, char *addr, int port); +int anetTcpNonBlockConnect(char *err, char *addr, int port); +int anetTcpNonBlockBindConnect(char *err, char *addr, int port, char *source_addr); +int anetTcpNonBlockBestEffortBindConnect(char *err, char *addr, int port, char *source_addr); +int anetUnixConnect(char *err, char *path); +int anetUnixNonBlockConnect(char *err, char *path); +int anetRead(int fd, char *buf, int count); +int anetResolve(char *err, char *host, char *ipbuf, size_t ipbuf_len); +int anetResolveIP(char *err, char *host, char *ipbuf, size_t ipbuf_len); +int anetTcpServer(char *err, int port, char *bindaddr, int backlog); +int anetTcp6Server(char *err, int port, char *bindaddr, int backlog); +int anetUnixServer(char *err, char *path, mode_t perm, int backlog); +int anetTcpAccept(char *err, int serversock, char *ip, size_t ip_len, int *port); +int anetUnixAccept(char *err, int serversock); +int anetWrite(int fd, char *buf, int count); +int anetNonBlock(char *err, int fd); +int anetBlock(char *err, int fd); +int anetEnableTcpNoDelay(char *err, int fd); +int anetDisableTcpNoDelay(char *err, int fd); +int anetTcpKeepAlive(char *err, int fd); +int anetSendTimeout(char *err, int fd, long long ms); +int anetPeerToString(int fd, char *ip, size_t ip_len, int *port); +int anetKeepAlive(char *err, int fd, int interval); +int anetSockName(int fd, char *ip, size_t ip_len, int *port); +int anetFormatAddr(char *fmt, size_t fmt_len, char *ip, int port); +int anetFormatPeer(int fd, char *fmt, size_t fmt_len); +int anetFormatSock(int fd, char *fmt, size_t fmt_len); +# 55 "src/redis-cli.c" 2 +# 1 "src/ae.h" 1 +# 36 "src/ae.h" +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 2 +# 37 "src/ae.h" 2 +# 57 "src/ae.h" +struct aeEventLoop; + + +typedef void aeFileProc(struct aeEventLoop *eventLoop, int fd, void *clientData, int mask); +typedef int aeTimeProc(struct aeEventLoop *eventLoop, long long id, void *clientData); +typedef void aeEventFinalizerProc(struct aeEventLoop *eventLoop, void *clientData); +typedef void aeBeforeSleepProc(struct aeEventLoop *eventLoop); + + +typedef struct aeFileEvent { + int mask; + aeFileProc *rfileProc; + aeFileProc *wfileProc; + void *clientData; +} aeFileEvent; + + +typedef struct aeTimeEvent { + long long id; + long when_sec; + long when_ms; + aeTimeProc *timeProc; + aeEventFinalizerProc *finalizerProc; + void *clientData; + struct aeTimeEvent *next; +} aeTimeEvent; + + +typedef struct aeFiredEvent { + int fd; + int mask; +} aeFiredEvent; + + +typedef struct aeEventLoop { + int maxfd; + int setsize; + long long timeEventNextId; + time_t lastTime; + aeFileEvent *events; + aeFiredEvent *fired; + aeTimeEvent *timeEventHead; + int stop; + void *apidata; + aeBeforeSleepProc *beforesleep; + aeBeforeSleepProc *aftersleep; +} aeEventLoop; + + +aeEventLoop *aeCreateEventLoop(int setsize); +void aeDeleteEventLoop(aeEventLoop *eventLoop); +void aeStop(aeEventLoop *eventLoop); +int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask, + aeFileProc *proc, void *clientData); +void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask); +int aeGetFileEvents(aeEventLoop *eventLoop, int fd); +long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds, + aeTimeProc *proc, void *clientData, + aeEventFinalizerProc *finalizerProc); +int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id); +int aeProcessEvents(aeEventLoop *eventLoop, int flags); +int aeWait(int fd, int mask, long long milliseconds); +void aeMain(aeEventLoop *eventLoop); +char *aeGetApiName(void); +void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep); +void aeSetAfterSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *aftersleep); +int aeGetSetSize(aeEventLoop *eventLoop); +int aeResizeSetSize(aeEventLoop *eventLoop, int setsize); +# 56 "src/redis-cli.c" 2 +# 70 "src/redis-cli.c" +int spectrum_palette_color_size = 19; +int spectrum_palette_color[] = {0,233,234,235,237,239,241,243,245,247,144,143,142,184,226,214,208,202,196}; + +int spectrum_palette_mono_size = 13; +int spectrum_palette_mono[] = {0,233,234,235,237,239,241,243,245,247,249,251,253}; + + +int *spectrum_palette; +int spectrum_palette_size; + +static redisContext *context; +static struct config { + char *hostip; + int hostport; + char *hostsocket; + long repeat; + long interval; + int dbnum; + int interactive; + int shutdown; + int monitor_mode; + int pubsub_mode; + int latency_mode; + int latency_dist_mode; + int latency_history; + int lru_test_mode; + long long lru_test_sample_size; + int cluster_mode; + int cluster_reissue_command; + int slave_mode; + int pipe_mode; + int pipe_timeout; + int getrdb_mode; + int stat_mode; + int scan_mode; + int intrinsic_latency_mode; + int intrinsic_latency_duration; + char *pattern; + char *rdb_filename; + int bigkeys; + int hotkeys; + int stdinarg; + char *auth; + int output; + sds mb_delim; + char prompt[128]; + char *eval; + int eval_ldb; + int eval_ldb_sync; + int eval_ldb_end; + int enable_ldb_on_eval; + int last_cmd_type; +} config; + + +static struct pref { + int hints; +} pref; + +static volatile sig_atomic_t force_cancel_loop = 0; +static void usage(void); +static void slaveMode(void); +char *redisGitSHA1(void); +char *redisGitDirty(void); +static int cliConnect(int force); + + + + + +static long long ustime(void) { + struct timeval tv; + long long ust; + + gettimeofday(&tv, 0); + ust = ((long long)tv.tv_sec)*1000000; + ust += tv.tv_usec; + return ust; +} + +static long long mstime(void) { + return ustime()/1000; +} + +static void cliRefreshPrompt(void) { + int len; + + if (config.eval_ldb) return; + if (config.hostsocket != 0) + len = snprintf(config.prompt,sizeof(config.prompt),"redis %s", + config.hostsocket); + else + len = anetFormatAddr(config.prompt, sizeof(config.prompt), + config.hostip, config.hostport); + + if (config.dbnum != 0) + len += snprintf(config.prompt+len,sizeof(config.prompt)-len,"[%d]", + config.dbnum); + snprintf(config.prompt+len,sizeof(config.prompt)-len,"> "); +} +# 179 "src/redis-cli.c" +static sds getDotfilePath(char *envoverride, char *dotfilename) { + char *path = 0; + sds dotPath = 0; + + + path = getenv(envoverride); + if (path != 0 && *path != '\0') { + if (!strcmp("/dev/null", path)) { + return 0; + } + + + dotPath = sdsnew(path); + } else { + char *home = getenv("HOME"); + if (home != 0 && *home != '\0') { + + dotPath = sdscatprintf(sdsempty(), "%s/%s", home, dotfilename); + } + } + return dotPath; +} + + + + + + +static sds percentDecode(const char *pe, size_t len) { + const char *end = pe + len; + sds ret = sdsempty(); + const char *curr = pe; + + while (curr < end) { + if (*curr == '%') { + if ((end - curr) < 2) { + fprintf(stderr, "Incomplete URI encoding\n"); + exit(1); + } + + char h = tolower(*(++curr)); + char l = tolower(*(++curr)); + if (!(isdigit(h) || (h >= 'a' && h <= 'f')) || !(isdigit(l) || (l >= 'a' && l <= 'f'))) { + fprintf(stderr, "Illegal character in URI encoding\n"); + exit(1); + } + char c = (((isdigit(h) ? h - '0' : h - 'a' + 10) << 4) + (isdigit(l) ? l - '0' : l - 'a' + 10)); + ret = sdscatlen(ret, &c, 1); + curr++; + } else { + ret = sdscatlen(ret, curr++, 1); + } + } + + return ret; +} +# 244 "src/redis-cli.c" +static void parseRedisUri(const char *uri) { + + const char *scheme = "redis://"; + const char *curr = uri; + const char *end = uri + strlen(uri); + const char *userinfo, *username, *port, *host, *path; + + + if (strncasecmp(scheme, curr, strlen(scheme))) { + fprintf(stderr,"Invalid URI scheme\n"); + exit(1); + } + curr += strlen(scheme); + if (curr == end) return; + + + if ((userinfo = strchr(curr,'@'))) { + if ((username = strchr(curr, ':')) && username < userinfo) { + + curr = username + 1; + } + + config.auth = percentDecode(curr, userinfo - curr); + curr = userinfo + 1; + } + if (curr == end) return; + + + path = strchr(curr, '/'); + if (*curr != '/') { + host = path ? path - 1 : end; + if ((port = strchr(curr, ':'))) { + config.hostport = atoi(port + 1); + host = port - 1; + } + config.hostip = sdsnewlen(curr, host - curr + 1); + } + curr = path ? path + 1 : end; + if (curr == end) return; + + + config.dbnum = atoi(curr); +} +# 295 "src/redis-cli.c" +typedef struct { + int type; + int argc; + sds *argv; + sds full; + + + struct commandHelp *org; +} helpEntry; + +static helpEntry *helpEntries; +static int helpEntriesLen; + +static sds cliVersion(void) { + sds version; + version = sdscatprintf(sdsempty(), "%s", "4.0.8"); + + + if (strtoll(redisGitSHA1(),0,16)) { + version = sdscatprintf(version, " (git:%s", redisGitSHA1()); + if (strtoll(redisGitDirty(),0,10)) + version = sdscatprintf(version, "-dirty"); + version = sdscat(version, ")"); + } + return version; +} + +static void cliInitHelp(void) { + int commandslen = sizeof(commandHelp)/sizeof(struct commandHelp); + int groupslen = sizeof(commandGroups)/sizeof(char*); + int i, len, pos = 0; + helpEntry tmp; + + helpEntriesLen = len = commandslen+groupslen; + helpEntries = zmalloc(sizeof(helpEntry)*len); + + for (i = 0; i < groupslen; i++) { + tmp.argc = 1; + tmp.argv = zmalloc(sizeof(sds)); + tmp.argv[0] = sdscatprintf(sdsempty(),"@%s",commandGroups[i]); + tmp.full = tmp.argv[0]; + tmp.type = 2; + tmp.org = 0; + helpEntries[pos++] = tmp; + } + + for (i = 0; i < commandslen; i++) { + tmp.argv = sdssplitargs(commandHelp[i].name,&tmp.argc); + tmp.full = sdsnew(commandHelp[i].name); + tmp.type = 1; + tmp.org = &commandHelp[i]; + helpEntries[pos++] = tmp; + } +} + + + + + + +static void cliIntegrateHelp(void) { + if (cliConnect(0) == -1) return; + + redisReply *reply = redisCommand(context, "COMMAND"); + if(reply == 0 || reply->type != 2) return; + + + + for (size_t j = 0; j < reply->elements; j++) { + redisReply *entry = reply->element[j]; + if (entry->type != 2 || entry->elements < 4 || + entry->element[0]->type != 1 || + entry->element[1]->type != 3 || + entry->element[3]->type != 3) return; + char *cmdname = entry->element[0]->str; + int i; + + for (i = 0; i < helpEntriesLen; i++) { + helpEntry *he = helpEntries+i; + if (!strcasecmp(he->argv[0],cmdname)) + break; + } + if (i != helpEntriesLen) continue; + + helpEntriesLen++; + helpEntries = zrealloc(helpEntries,sizeof(helpEntry)*helpEntriesLen); + helpEntry *new = helpEntries+(helpEntriesLen-1); + + new->argc = 1; + new->argv = zmalloc(sizeof(sds)); + new->argv[0] = sdsnew(cmdname); + new->full = new->argv[0]; + new->type = 1; + sdstoupper(new->argv[0]); + + struct commandHelp *ch = zmalloc(sizeof(*ch)); + ch->name = new->argv[0]; + ch->params = sdsempty(); + int args = llabs(entry->element[1]->integer); + if (entry->element[3]->integer == 1) { + ch->params = sdscat(ch->params,"key "); + args--; + } + while(args--) ch->params = sdscat(ch->params,"arg "); + if (entry->element[1]->integer < 0) + ch->params = sdscat(ch->params,"...options..."); + ch->summary = "Help not available"; + ch->group = 0; + ch->since = "not known"; + new->org = ch; + } + freeReplyObject(reply); +} + + +static void cliOutputCommandHelp(struct commandHelp *help, int group) { + printf("\r\n \x1b[1m%s\x1b[0m \x1b[90m%s\x1b[0m\r\n", help->name, help->params); + printf(" \x1b[33msummary:\x1b[0m %s\r\n", help->summary); + printf(" \x1b[33msince:\x1b[0m %s\r\n", help->since); + if (group) { + printf(" \x1b[33mgroup:\x1b[0m %s\r\n", commandGroups[help->group]); + } +} + + +static void cliOutputGenericHelp(void) { + sds version = cliVersion(); + printf( + "redis-cli %s\n" + "To get help about Redis commands type:\n" + " \"help @<group>\" to get a list of commands in <group>\n" + " \"help <command>\" for help on <command>\n" + " \"help <tab>\" to get a list of possible help topics\n" + " \"quit\" to exit\n" + "\n" + "To set redis-cli preferences:\n" + " \":set hints\" enable online hints\n" + " \":set nohints\" disable online hints\n" + "Set your preferences in ~/.redisclirc\n", + version + ); + sdsfree(version); +} + + +static void cliOutputHelp(int argc, char **argv) { + int i, j, len; + int group = -1; + helpEntry *entry; + struct commandHelp *help; + + if (argc == 0) { + cliOutputGenericHelp(); + return; + } else if (argc > 0 && argv[0][0] == '@') { + len = sizeof(commandGroups)/sizeof(char*); + for (i = 0; i < len; i++) { + if (strcasecmp(argv[0]+1,commandGroups[i]) == 0) { + group = i; + break; + } + } + } + + assert(argc > 0); + for (i = 0; i < helpEntriesLen; i++) { + entry = &helpEntries[i]; + if (entry->type != 1) continue; + + help = entry->org; + if (group == -1) { + + if (argc == entry->argc) { + for (j = 0; j < argc; j++) { + if (strcasecmp(argv[j],entry->argv[j]) != 0) break; + } + if (j == argc) { + cliOutputCommandHelp(help,1); + } + } + } else { + if (group == help->group) { + cliOutputCommandHelp(help,0); + } + } + } + printf("\r\n"); +} + + +static void completionCallback(const char *buf, linenoiseCompletions *lc) { + size_t startpos = 0; + int mask; + int i; + size_t matchlen; + sds tmp; + + if (strncasecmp(buf,"help ",5) == 0) { + startpos = 5; + while (isspace(buf[startpos])) startpos++; + mask = 1 | 2; + } else { + mask = 1; + } + + for (i = 0; i < helpEntriesLen; i++) { + if (!(helpEntries[i].type & mask)) continue; + + matchlen = strlen(buf+startpos); + if (strncasecmp(buf+startpos,helpEntries[i].full,matchlen) == 0) { + tmp = sdsnewlen(buf,startpos); + tmp = sdscat(tmp,helpEntries[i].full); + linenoiseAddCompletion(lc,tmp); + sdsfree(tmp); + } + } +} + + +static char *hintsCallback(const char *buf, int *color, int *bold) { + if (!pref.hints) return 0; + + int i, argc, buflen = strlen(buf); + sds *argv = sdssplitargs(buf,&argc); + int endspace = buflen && isspace(buf[buflen-1]); + + + if (argc == 0) { + sdsfreesplitres(argv,argc); + return 0; + } + + for (i = 0; i < helpEntriesLen; i++) { + if (!(helpEntries[i].type & 1)) continue; + + if (strcasecmp(argv[0],helpEntries[i].full) == 0) + { + *color = 90; + *bold = 0; + sds hint = sdsnew(helpEntries[i].org->params); + + + + int toremove = argc-1; + while(toremove > 0 && sdslen(hint)) { + if (hint[0] == '[') break; + if (hint[0] == ' ') toremove--; + sdsrange(hint,1,-1); + } + + + if (!endspace) { + sds newhint = sdsnewlen(" ",1); + newhint = sdscatsds(newhint,hint); + sdsfree(hint); + hint = newhint; + } + + sdsfreesplitres(argv,argc); + return hint; + } + } + sdsfreesplitres(argv,argc); + return 0; +} + +static void freeHintsCallback(void *ptr) { + sdsfree(ptr); +} + + + + + + +static int cliAuth(void) { + redisReply *reply; + if (config.auth == 0) return 0; + + reply = redisCommand(context,"AUTH %s",config.auth); + if (reply != 0) { + freeReplyObject(reply); + return 0; + } + return -1; +} + + +static int cliSelect(void) { + redisReply *reply; + if (config.dbnum == 0) return 0; + + reply = redisCommand(context,"SELECT %d",config.dbnum); + if (reply != 0) { + int result = 0; + if (reply->type == 6) result = -1; + freeReplyObject(reply); + return result; + } + return -1; +} + + + +static int cliConnect(int force) { + if (context == 0 || force) { + if (context != 0) { + redisFree(context); + } + + if (config.hostsocket == 0) { + context = redisConnect(config.hostip,config.hostport); + } else { + context = redisConnectUnix(config.hostsocket); + } + + if (context->err) { + fprintf(stderr,"Could not connect to Redis at "); + if (config.hostsocket == 0) + fprintf(stderr,"%s:%d: %s\n",config.hostip,config.hostport,context->errstr); + else + fprintf(stderr,"%s: %s\n",config.hostsocket,context->errstr); + redisFree(context); + context = 0; + return -1; + } + + + + + + anetKeepAlive(0, context->fd, 15); + + + if (cliAuth() != 0) + return -1; + if (cliSelect() != 0) + return -1; + } + return 0; +} + +static void cliPrintContextError(void) { + if (context == 0) return; + fprintf(stderr,"Error: %s\n",context->errstr); +} + +static sds cliFormatReplyTTY(redisReply *r, char *prefix) { + sds out = sdsempty(); + switch (r->type) { + case 6: + out = sdscatprintf(out,"(error) %s\n", r->str); + break; + case 5: + out = sdscat(out,r->str); + out = sdscat(out,"\n"); + break; + case 3: + out = sdscatprintf(out,"(integer) %lld\n",r->integer); + break; + case 1: + + + out = sdscatrepr(out,r->str,r->len); + out = sdscat(out,"\n"); + break; + case 4: + out = sdscat(out,"(nil)\n"); + break; + case 2: + if (r->elements == 0) { + out = sdscat(out,"(empty list or set)\n"); + } else { + unsigned int i, idxlen = 0; + char _prefixlen[16]; + char _prefixfmt[16]; + sds _prefix; + sds tmp; + + + i = r->elements; + do { + idxlen++; + i /= 10; + } while(i); + + + memset(_prefixlen,' ',idxlen+2); + _prefixlen[idxlen+2] = '\0'; + _prefix = sdscat(sdsnew(prefix),_prefixlen); + + + snprintf(_prefixfmt,sizeof(_prefixfmt),"%%s%%%ud) ",idxlen); + + for (i = 0; i < r->elements; i++) { + + + out = sdscatprintf(out,_prefixfmt,i == 0 ? "" : prefix,i+1); + + + tmp = cliFormatReplyTTY(r->element[i],_prefix); + out = sdscatlen(out,tmp,sdslen(tmp)); + sdsfree(tmp); + } + sdsfree(_prefix); + } + break; + default: + fprintf(stderr,"Unknown reply type: %d\n", r->type); + exit(1); + } + return out; +} + +int isColorTerm(void) { + char *t = getenv("TERM"); + return t != 0 && strstr(t,"xterm") != 0; +} + + + +sds sdscatcolor(sds o, char *s, size_t len, char *color) { + if (!isColorTerm()) return sdscatlen(o,s,len); + + int bold = strstr(color,"bold") != 0; + int ccode = 37; + if (strstr(color,"red")) ccode = 31; + else if (strstr(color,"green")) ccode = 32; + else if (strstr(color,"yellow")) ccode = 33; + else if (strstr(color,"blue")) ccode = 34; + else if (strstr(color,"magenta")) ccode = 35; + else if (strstr(color,"cyan")) ccode = 36; + else if (strstr(color,"white")) ccode = 37; + + o = sdscatfmt(o,"\033[%i;%i;49m",bold,ccode); + o = sdscatlen(o,s,len); + o = sdscat(o,"\033[0m"); + return o; +} + + + +sds sdsCatColorizedLdbReply(sds o, char *s, size_t len) { + char *color = "white"; + + if (strstr(s,"<debug>")) color = "bold"; + if (strstr(s,"<redis>")) color = "green"; + if (strstr(s,"<reply>")) color = "cyan"; + if (strstr(s,"<error>")) color = "red"; + if (strstr(s,"<hint>")) color = "bold"; + if (strstr(s,"<value>") || strstr(s,"<retval>")) color = "magenta"; + if (len > 4 && isdigit(s[3])) { + if (s[1] == '>') color = "yellow"; + else if (s[2] == '#') color = "bold"; + } + return sdscatcolor(o,s,len,color); +} + +static sds cliFormatReplyRaw(redisReply *r) { + sds out = sdsempty(), tmp; + size_t i; + + switch (r->type) { + case 4: + + break; + case 6: + out = sdscatlen(out,r->str,r->len); + out = sdscatlen(out,"\n",1); + break; + case 5: + case 1: + if (r->type == 5 && config.eval_ldb) { + + + + + + if (strstr(r->str,"<endsession>") == r->str) { + config.enable_ldb_on_eval = 0; + config.eval_ldb = 0; + config.eval_ldb_end = 1; + config.output = 0; + cliRefreshPrompt(); + } else { + out = sdsCatColorizedLdbReply(out,r->str,r->len); + } + } else { + out = sdscatlen(out,r->str,r->len); + } + break; + case 3: + out = sdscatprintf(out,"%lld",r->integer); + break; + case 2: + for (i = 0; i < r->elements; i++) { + if (i > 0) out = sdscat(out,config.mb_delim); + tmp = cliFormatReplyRaw(r->element[i]); + out = sdscatlen(out,tmp,sdslen(tmp)); + sdsfree(tmp); + } + break; + default: + fprintf(stderr,"Unknown reply type: %d\n", r->type); + exit(1); + } + return out; +} + +static sds cliFormatReplyCSV(redisReply *r) { + unsigned int i; + + sds out = sdsempty(); + switch (r->type) { + case 6: + out = sdscat(out,"ERROR,"); + out = sdscatrepr(out,r->str,strlen(r->str)); + break; + case 5: + out = sdscatrepr(out,r->str,r->len); + break; + case 3: + out = sdscatprintf(out,"%lld",r->integer); + break; + case 1: + out = sdscatrepr(out,r->str,r->len); + break; + case 4: + out = sdscat(out,"NIL"); + break; + case 2: + for (i = 0; i < r->elements; i++) { + sds tmp = cliFormatReplyCSV(r->element[i]); + out = sdscatlen(out,tmp,sdslen(tmp)); + if (i != r->elements-1) out = sdscat(out,","); + sdsfree(tmp); + } + break; + default: + fprintf(stderr,"Unknown reply type: %d\n", r->type); + exit(1); + } + return out; +} + +static int cliReadReply(int output_raw_strings) { + void *_reply; + redisReply *reply; + sds out = 0; + int output = 1; + + if (redisGetReply(context,&_reply) != 0) { + if (config.shutdown) { + redisFree(context); + context = 0; + return 0; + } + if (config.interactive) { + + if (context->err == 1 && + (errno == ECONNRESET || errno == EPIPE)) + return -1; + if (context->err == 3) + return -1; + } + cliPrintContextError(); + exit(1); + return -1; + } + + reply = (redisReply*)_reply; + + config.last_cmd_type = reply->type; + + + + if (config.cluster_mode && reply->type == 6 && + (!strncmp(reply->str,"MOVED",5) || !strcmp(reply->str,"ASK"))) + { + char *p = reply->str, *s; + int slot; + + output = 0; + + + + + + s = strchr(p,' '); + p = strchr(s+1,' '); + *p = '\0'; + slot = atoi(s+1); + s = strrchr(p+1,':'); + *s = '\0'; + sdsfree(config.hostip); + config.hostip = sdsnew(p+1); + config.hostport = atoi(s+1); + if (config.interactive) + printf("-> Redirected to slot [%d] located at %s:%d\n", + slot, config.hostip, config.hostport); + config.cluster_reissue_command = 1; + cliRefreshPrompt(); + } + + if (output) { + if (output_raw_strings) { + out = cliFormatReplyRaw(reply); + } else { + if (config.output == 1) { + out = cliFormatReplyRaw(reply); + out = sdscat(out,"\n"); + } else if (config.output == 0) { + out = cliFormatReplyTTY(reply,""); + } else if (config.output == 2) { + out = cliFormatReplyCSV(reply); + out = sdscat(out,"\n"); + } + } + fwrite(out,sdslen(out),1,stdout); + sdsfree(out); + } + freeReplyObject(reply); + return 0; +} + +static int cliSendCommand(int argc, char **argv, int repeat) { + char *command = argv[0]; + size_t *argvlen; + int j, output_raw; + + if (!config.eval_ldb && + (!strcasecmp(command,"help") || !strcasecmp(command,"?"))) { + cliOutputHelp(--argc, ++argv); + return 0; + } + + if (context == 0) return -1; + + output_raw = 0; + if (!strcasecmp(command,"info") || + (argc >= 2 && !strcasecmp(command,"debug") && + !strcasecmp(argv[1],"htstats")) || + (argc >= 2 && !strcasecmp(command,"memory") && + (!strcasecmp(argv[1],"malloc-stats") || + !strcasecmp(argv[1],"doctor"))) || + (argc == 2 && !strcasecmp(command,"cluster") && + (!strcasecmp(argv[1],"nodes") || + !strcasecmp(argv[1],"info"))) || + (argc == 2 && !strcasecmp(command,"client") && + !strcasecmp(argv[1],"list")) || + (argc == 3 && !strcasecmp(command,"latency") && + !strcasecmp(argv[1],"graph")) || + (argc == 2 && !strcasecmp(command,"latency") && + !strcasecmp(argv[1],"doctor"))) + { + output_raw = 1; + } + + if (!strcasecmp(command,"shutdown")) config.shutdown = 1; + if (!strcasecmp(command,"monitor")) config.monitor_mode = 1; + if (!strcasecmp(command,"subscribe") || + !strcasecmp(command,"psubscribe")) config.pubsub_mode = 1; + if (!strcasecmp(command,"sync") || + !strcasecmp(command,"psync")) config.slave_mode = 1; + + + + if (argc == 3 && !strcasecmp(argv[0],"script") && + !strcasecmp(argv[1],"debug")) + { + if (!strcasecmp(argv[2],"yes") || !strcasecmp(argv[2],"sync")) { + config.enable_ldb_on_eval = 1; + } else { + config.enable_ldb_on_eval = 0; + } + } + + + if (!strcasecmp(command,"eval") && config.enable_ldb_on_eval) { + config.eval_ldb = 1; + config.output = 1; + } + + + argvlen = zmalloc(argc*sizeof(size_t)); + for (j = 0; j < argc; j++) + argvlen[j] = sdslen(argv[j]); + + while(repeat--) { + redisAppendCommandArgv(context,argc,(const char**)argv,argvlen); + while (config.monitor_mode) { + if (cliReadReply(output_raw) != 0) exit(1); + fflush(stdout); + } + + if (config.pubsub_mode) { + if (config.output != 1) + printf("Reading messages... (press Ctrl-C to quit)\n"); + while (1) { + if (cliReadReply(output_raw) != 0) exit(1); + } + } + + if (config.slave_mode) { + printf("Entering slave output mode... (press Ctrl-C to quit)\n"); + slaveMode(); + config.slave_mode = 0; + zfree(argvlen); + return -1; + } + + if (cliReadReply(output_raw) != 0) { + zfree(argvlen); + return -1; + } else { + + if (!strcasecmp(command,"select") && argc == 2 && config.last_cmd_type != 6) { + config.dbnum = atoi(argv[1]); + cliRefreshPrompt(); + } else if (!strcasecmp(command,"auth") && argc == 2) { + cliSelect(); + } + } + if (config.interval) usleep(config.interval); + fflush(stdout); + } + + zfree(argvlen); + return 0; +} + + +static redisReply *reconnectingRedisCommand(redisContext *c, const char *fmt, ...) { + redisReply *reply = 0; + int tries = 0; + va_list ap; + + assert(!c->err); + while(reply == 0) { + while (c->err & (1 | 3)) { + printf("\r\x1b[0K"); + printf("Reconnecting... %d\r", ++tries); + fflush(stdout); + + redisFree(c); + c = redisConnect(config.hostip,config.hostport); + usleep(1000000); + } + + __builtin_va_start((ap)); + reply = redisvCommand(c,fmt,ap); + ; + + if (c->err && !(c->err & (1 | 3))) { + fprintf(stderr, "Error: %s\n", c->errstr); + exit(1); + } else if (tries > 0) { + printf("\r\x1b[0K"); + } + } + + context = c; + return reply; +} + + + + + +static int parseOptions(int argc, char **argv) { + int i; + + for (i = 1; i < argc; i++) { + int lastarg = i==argc-1; + + if (!strcmp(argv[i],"-h") && !lastarg) { + sdsfree(config.hostip); + config.hostip = sdsnew(argv[++i]); + } else if (!strcmp(argv[i],"-h") && lastarg) { + usage(); + } else if (!strcmp(argv[i],"--help")) { + usage(); + } else if (!strcmp(argv[i],"-x")) { + config.stdinarg = 1; + } else if (!strcmp(argv[i],"-p") && !lastarg) { + config.hostport = atoi(argv[++i]); + } else if (!strcmp(argv[i],"-s") && !lastarg) { + config.hostsocket = argv[++i]; + } else if (!strcmp(argv[i],"-r") && !lastarg) { + config.repeat = strtoll(argv[++i],0,10); + } else if (!strcmp(argv[i],"-i") && !lastarg) { + double seconds = atof(argv[++i]); + config.interval = seconds*1000000; + } else if (!strcmp(argv[i],"-n") && !lastarg) { + config.dbnum = atoi(argv[++i]); + } else if (!strcmp(argv[i],"-a") && !lastarg) { + config.auth = argv[++i]; + } else if (!strcmp(argv[i],"-u") && !lastarg) { + parseRedisUri(argv[++i]); + } else if (!strcmp(argv[i],"--raw")) { + config.output = 1; + } else if (!strcmp(argv[i],"--no-raw")) { + config.output = 0; + } else if (!strcmp(argv[i],"--csv")) { + config.output = 2; + } else if (!strcmp(argv[i],"--latency")) { + config.latency_mode = 1; + } else if (!strcmp(argv[i],"--latency-dist")) { + config.latency_dist_mode = 1; + } else if (!strcmp(argv[i],"--mono")) { + spectrum_palette = spectrum_palette_mono; + spectrum_palette_size = spectrum_palette_mono_size; + } else if (!strcmp(argv[i],"--latency-history")) { + config.latency_mode = 1; + config.latency_history = 1; + } else if (!strcmp(argv[i],"--lru-test") && !lastarg) { + config.lru_test_mode = 1; + config.lru_test_sample_size = strtoll(argv[++i],0,10); + } else if (!strcmp(argv[i],"--slave")) { + config.slave_mode = 1; + } else if (!strcmp(argv[i],"--stat")) { + config.stat_mode = 1; + } else if (!strcmp(argv[i],"--scan")) { + config.scan_mode = 1; + } else if (!strcmp(argv[i],"--pattern") && !lastarg) { + config.pattern = argv[++i]; + } else if (!strcmp(argv[i],"--intrinsic-latency") && !lastarg) { + config.intrinsic_latency_mode = 1; + config.intrinsic_latency_duration = atoi(argv[++i]); + } else if (!strcmp(argv[i],"--rdb") && !lastarg) { + config.getrdb_mode = 1; + config.rdb_filename = argv[++i]; + } else if (!strcmp(argv[i],"--pipe")) { + config.pipe_mode = 1; + } else if (!strcmp(argv[i],"--pipe-timeout") && !lastarg) { + config.pipe_timeout = atoi(argv[++i]); + } else if (!strcmp(argv[i],"--bigkeys")) { + config.bigkeys = 1; + } else if (!strcmp(argv[i],"--hotkeys")) { + config.hotkeys = 1; + } else if (!strcmp(argv[i],"--eval") && !lastarg) { + config.eval = argv[++i]; + } else if (!strcmp(argv[i],"--ldb")) { + config.eval_ldb = 1; + config.output = 1; + } else if (!strcmp(argv[i],"--ldb-sync-mode")) { + config.eval_ldb = 1; + config.eval_ldb_sync = 1; + config.output = 1; + } else if (!strcmp(argv[i],"-c")) { + config.cluster_mode = 1; + } else if (!strcmp(argv[i],"-d") && !lastarg) { + sdsfree(config.mb_delim); + config.mb_delim = sdsnew(argv[++i]); + } else if (!strcmp(argv[i],"-v") || !strcmp(argv[i], "--version")) { + sds version = cliVersion(); + printf("redis-cli %s\n", version); + sdsfree(version); + exit(0); + } else { + if (argv[i][0] == '-') { + fprintf(stderr, + "Unrecognized option or bad number of args for: '%s'\n", + argv[i]); + exit(1); + } else { + + break; + } + } + } + + + if (config.eval_ldb && config.eval == 0) { + fprintf(stderr,"Options --ldb and --ldb-sync-mode require --eval.\n"); + fprintf(stderr,"Try %s --help for more information.\n", argv[0]); + exit(1); + } + return i; +} + +static sds readArgFromStdin(void) { + char buf[1024]; + sds arg = sdsempty(); + + while(1) { + int nread = read(fileno(stdin),buf,1024); + + if (nread == 0) break; + else if (nread == -1) { + perror("Reading from standard input"); + exit(1); + } + arg = sdscatlen(arg,buf,nread); + } + return arg; +} + +static void usage(void) { + sds version = cliVersion(); + fprintf(stderr, +"redis-cli %s\n" +"\n" +"Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]\n" +" -h <hostname> Server hostname (default: 127.0.0.1).\n" +" -p <port> Server port (default: 6379).\n" +" -s <socket> Server socket (overrides hostname and port).\n" +" -a <password> Password to use when connecting to the server.\n" +" -u <uri> Server URI.\n" +" -r <repeat> Execute specified command N times.\n" +" -i <interval> When -r is used, waits <interval> seconds per command.\n" +" It is possible to specify sub-second times like -i 0.1.\n" +" -n <db> Database number.\n" +" -x Read last argument from STDIN.\n" +" -d <delimiter> Multi-bulk delimiter in for raw formatting (default: \\n).\n" +" -c Enable cluster mode (follow -ASK and -MOVED redirections).\n" +" --raw Use raw formatting for replies (default when STDOUT is\n" +" not a tty).\n" +" --no-raw Force formatted output even when STDOUT is not a tty.\n" +" --csv Output in CSV format.\n" +" --stat Print rolling stats about server: mem, clients, ...\n" +" --latency Enter a special mode continuously sampling latency.\n" +" If you use this mode in an interactive session it runs\n" +" forever displaying real-time stats. Otherwise if --raw or\n" +" --csv is specified, or if you redirect the output to a non\n" +" TTY, it samples the latency for 1 second (you can use\n" +" -i to change the interval), then produces a single output\n" +" and exits.\n" +" --latency-history Like --latency but tracking latency changes over time.\n" +" Default time interval is 15 sec. Change it using -i.\n" +" --latency-dist Shows latency as a spectrum, requires xterm 256 colors.\n" +" Default time interval is 1 sec. Change it using -i.\n" +" --lru-test <keys> Simulate a cache workload with an 80-20 distribution.\n" +" --slave Simulate a slave showing commands received from the master.\n" +" --rdb <filename> Transfer an RDB dump from remote server to local file.\n" +" --pipe Transfer raw Redis protocol from stdin to server.\n" +" --pipe-timeout <n> In --pipe mode, abort with error if after sending all data.\n" +" no reply is received within <n> seconds.\n" +" Default timeout: %d. Use 0 to wait forever.\n" +" --bigkeys Sample Redis keys looking for big keys.\n" +" --hotkeys Sample Redis keys looking for hot keys.\n" +" only works when maxmemory-policy is *lfu.\n" +" --scan List all keys using the SCAN command.\n" +" --pattern <pat> Useful with --scan to specify a SCAN pattern.\n" +" --intrinsic-latency <sec> Run a test to measure intrinsic system latency.\n" +" The test will run for the specified amount of seconds.\n" +" --eval <file> Send an EVAL command using the Lua script at <file>.\n" +" --ldb Used with --eval enable the Redis Lua debugger.\n" +" --ldb-sync-mode Like --ldb but uses the synchronous Lua debugger, in\n" +" this mode the server is blocked and script changes are\n" +" are not rolled back from the server memory.\n" +" --help Output this help and exit.\n" +" --version Output version and exit.\n" +"\n" +"Examples:\n" +" cat /etc/passwd | redis-cli -x set mypasswd\n" +" redis-cli get mypasswd\n" +" redis-cli -r 100 lpush mylist x\n" +" redis-cli -r 100 -i 1 info | grep used_memory_human:\n" +" redis-cli --eval myscript.lua key1 key2 , arg1 arg2 arg3\n" +" redis-cli --scan --pattern '*:12345*'\n" +"\n" +" (Note: when using --eval the comma separates KEYS[] from ARGV[] items)\n" +"\n" +"When no command is given, redis-cli starts in interactive mode.\n" +"Type \"help\" in interactive mode for information on available commands\n" +"and settings.\n" +"\n", + version, 30); + sdsfree(version); + exit(1); +} + + +static char **convertToSds(int count, char** args) { + int j; + char **sds = zmalloc(sizeof(char*)*count); + + for(j = 0; j < count; j++) + sds[j] = sdsnew(args[j]); + + return sds; +} + +static int issueCommandRepeat(int argc, char **argv, long repeat) { + while (1) { + config.cluster_reissue_command = 0; + if (cliSendCommand(argc,argv,repeat) != 0) { + cliConnect(1); + + + + if (cliSendCommand(argc,argv,repeat) != 0) { + cliPrintContextError(); + return -1; + } + } + + if (config.cluster_mode && config.cluster_reissue_command) { + cliConnect(1); + } else { + break; + } + } + return 0; +} + +static int issueCommand(int argc, char **argv) { + return issueCommandRepeat(argc, argv, config.repeat); +} + + + + + + + +static sds *cliSplitArgs(char *line, int *argc) { + if (config.eval_ldb && (strstr(line,"eval ") == line || + strstr(line,"e ") == line)) + { + sds *argv = sds_malloc(sizeof(sds)*2); + *argc = 2; + int len = strlen(line); + int elen = line[1] == ' ' ? 2 : 5; + argv[0] = sdsnewlen(line,elen-1); + argv[1] = sdsnewlen(line+elen,len-elen); + return argv; + } else { + return sdssplitargs(line,argc); + } +} + + + + +void cliSetPreferences(char **argv, int argc, int interactive) { + if (!strcasecmp(argv[0],":set") && argc >= 2) { + if (!strcasecmp(argv[1],"hints")) pref.hints = 1; + else if (!strcasecmp(argv[1],"nohints")) pref.hints = 0; + else { + printf("%sunknown redis-cli preference '%s'\n", + interactive ? "" : ".redisclirc: ", + argv[1]); + } + } else { + printf("%sunknown redis-cli internal command '%s'\n", + interactive ? "" : ".redisclirc: ", + argv[0]); + } +} + + +void cliLoadPreferences(void) { + sds rcfile = getDotfilePath("REDISCLI_RCFILE",".redisclirc"); + if (rcfile == 0) return; + FILE *fp = fopen(rcfile,"r"); + char buf[1024]; + + if (fp) { + while(fgets(buf,sizeof(buf),fp) != 0) { + sds *argv; + int argc; + + argv = sdssplitargs(buf,&argc); + if (argc > 0) cliSetPreferences(argv,argc,0); + sdsfreesplitres(argv,argc); + } + fclose(fp); + } + sdsfree(rcfile); +} + +static void repl(void) { + sds historyfile = 0; + int history = 0; + char *line; + int argc; + sds *argv; + + + + cliInitHelp(); + cliIntegrateHelp(); + + config.interactive = 1; + linenoiseSetMultiLine(1); + linenoiseSetCompletionCallback(completionCallback); + linenoiseSetHintsCallback(hintsCallback); + linenoiseSetFreeHintsCallback(freeHintsCallback); + + + if (isatty(fileno(stdin))) { + historyfile = getDotfilePath("REDISCLI_HISTFILE",".rediscli_history"); + + history = 1; + if (historyfile != 0) { + linenoiseHistoryLoad(historyfile); + } + cliLoadPreferences(); + } + + cliRefreshPrompt(); + while((line = linenoise(context ? config.prompt : "not connected> ")) != 0) { + if (line[0] != '\0') { + argv = cliSplitArgs(line,&argc); + if (history) linenoiseHistoryAdd(line); + if (historyfile) linenoiseHistorySave(historyfile); + + if (argv == 0) { + printf("Invalid argument(s)\n"); + linenoiseFree(line); + continue; + } else if (argc > 0) { + if (strcasecmp(argv[0],"quit") == 0 || + strcasecmp(argv[0],"exit") == 0) + { + exit(0); + } else if (argv[0][0] == ':') { + cliSetPreferences(argv,argc,1); + continue; + } else if (strcasecmp(argv[0],"restart") == 0) { + if (config.eval) { + config.eval_ldb = 1; + config.output = 1; + return; + } else { + printf("Use 'restart' only in Lua debugging mode."); + } + } else if (argc == 3 && !strcasecmp(argv[0],"connect")) { + sdsfree(config.hostip); + config.hostip = sdsnew(argv[1]); + config.hostport = atoi(argv[2]); + cliRefreshPrompt(); + cliConnect(1); + } else if (argc == 1 && !strcasecmp(argv[0],"clear")) { + linenoiseClearScreen(); + } else { + long long start_time = mstime(), elapsed; + int repeat, skipargs = 0; + char *endptr; + + repeat = strtol(argv[0], &endptr, 10); + if (argc > 1 && *endptr == '\0' && repeat) { + skipargs = 1; + } else { + repeat = 1; + } + + issueCommandRepeat(argc-skipargs, argv+skipargs, repeat); + + + + if (config.eval_ldb_end) { + config.eval_ldb_end = 0; + cliReadReply(0); + printf("\n(Lua debugging session ended%s)\n\n", + config.eval_ldb_sync ? "" : + " -- dataset changes rolled back"); + } + + elapsed = mstime()-start_time; + if (elapsed >= 500 && + config.output == 0) + { + printf("(%.2fs)\n",(double)elapsed/1000); + } + } + } + + sdsfreesplitres(argv,argc); + } + + linenoiseFree(line); + } + exit(0); +} + +static int noninteractive(int argc, char **argv) { + int retval = 0; + if (config.stdinarg) { + argv = zrealloc(argv, (argc+1)*sizeof(char*)); + argv[argc] = readArgFromStdin(); + retval = issueCommand(argc+1, argv); + } else { + retval = issueCommand(argc, argv); + } + return retval; +} + + + + + +static int evalMode(int argc, char **argv) { + sds script = 0; + FILE *fp; + char buf[1024]; + size_t nread; + char **argv2; + int j, got_comma, keys; + int retval = 0; + + while(1) { + if (config.eval_ldb) { + printf( + "Lua debugging session started, please use:\n" + "quit -- End the session.\n" + "restart -- Restart the script in debug mode again.\n" + "help -- Show Lua script debugging commands.\n\n" + ); + } + + sdsfree(script); + script = sdsempty(); + got_comma = 0; + keys = 0; + + + fp = fopen(config.eval,"r"); + if (!fp) { + fprintf(stderr, + "Can't open file '%s': %s\n", config.eval, strerror(errno)); + exit(1); + } + while((nread = fread(buf,1,sizeof(buf),fp)) != 0) { + script = sdscatlen(script,buf,nread); + } + fclose(fp); + + + if (config.eval_ldb) { + redisReply *reply = redisCommand(context, + config.eval_ldb_sync ? + "SCRIPT DEBUG sync": "SCRIPT DEBUG yes"); + if (reply) freeReplyObject(reply); + } + + + argv2 = zmalloc(sizeof(sds)*(argc+3)); + argv2[0] = sdsnew("EVAL"); + argv2[1] = script; + for (j = 0; j < argc; j++) { + if (!got_comma && argv[j][0] == ',' && argv[j][1] == 0) { + got_comma = 1; + continue; + } + argv2[j+3-got_comma] = sdsnew(argv[j]); + if (!got_comma) keys++; + } + argv2[2] = sdscatprintf(sdsempty(),"%d",keys); + + + int eval_ldb = config.eval_ldb; + retval = issueCommand(argc+3-got_comma, argv2); + if (eval_ldb) { + if (!config.eval_ldb) { + + + + printf("Eval debugging session can't start:\n"); + cliReadReply(0); + break; + } else { + strncpy(config.prompt,"lua debugger> ",sizeof(config.prompt)); + repl(); + + cliConnect(1); + printf("\n"); + } + } else { + break; + } + } + return retval; +} + + + + + +static void latencyModePrint(long long min, long long max, double avg, long long count) { + if (config.output == 0) { + printf("min: %lld, max: %lld, avg: %.2f (%lld samples)", + min, max, avg, count); + fflush(stdout); + } else if (config.output == 2) { + printf("%lld,%lld,%.2f,%lld\n", min, max, avg, count); + } else if (config.output == 1) { + printf("%lld %lld %.2f %lld\n", min, max, avg, count); + } +} + + + +static void latencyMode(void) { + redisReply *reply; + long long start, latency, min = 0, max = 0, tot = 0, count = 0; + long long history_interval = + config.interval ? config.interval/1000 : + 15000; + double avg; + long long history_start = mstime(); + + + + if (config.interval == 0) { + config.interval = 1000; + } else { + config.interval /= 1000; + } + + if (!context) exit(1); + while(1) { + start = mstime(); + reply = reconnectingRedisCommand(context,"PING"); + if (reply == 0) { + fprintf(stderr,"\nI/O error\n"); + exit(1); + } + latency = mstime()-start; + freeReplyObject(reply); + count++; + if (count == 1) { + min = max = tot = latency; + avg = (double) latency; + } else { + if (latency < min) min = latency; + if (latency > max) max = latency; + tot += latency; + avg = (double) tot/count; + } + + if (config.output == 0) { + printf("\x1b[0G\x1b[2K"); + latencyModePrint(min,max,avg,count); + } else { + if (config.latency_history) { + latencyModePrint(min,max,avg,count); + } else if (mstime()-history_start > config.interval) { + latencyModePrint(min,max,avg,count); + exit(0); + } + } + + if (config.latency_history && mstime()-history_start > history_interval) + { + printf(" -- %.2f seconds range\n", (float)(mstime()-history_start)/1000); + history_start = mstime(); + min = max = tot = count = 0; + } + usleep(10 * 1000); + } +} +# 1657 "src/redis-cli.c" +struct distsamples { + long long max; + long long count; + int character; +}; +# 1674 "src/redis-cli.c" +void showLatencyDistSamples(struct distsamples *samples, long long tot) { + int j; + + + + + + + printf("\033[38;5;0m"); + for (j = 0; ; j++) { + int coloridx = + ceil((float) samples[j].count / tot * (spectrum_palette_size-1)); + int color = spectrum_palette[coloridx]; + printf("\033[48;5;%dm%c", (int)color, samples[j].character); + samples[j].count = 0; + if (samples[j].max == 0) break; + } + printf("\033[0m\n"); + fflush(stdout); +} + + + +void showLatencyDistLegend(void) { + int j; + + printf("---------------------------------------------\n"); + printf(". - * # .01 .125 .25 .5 milliseconds\n"); + printf("1,2,3,...,9 from 1 to 9 milliseconds\n"); + printf("A,B,C,D,E 10,20,30,40,50 milliseconds\n"); + printf("F,G,H,I,J .1,.2,.3,.4,.5 seconds\n"); + printf("K,L,M,N,O,P,Q,? 1,2,4,8,16,30,60,>60 seconds\n"); + printf("From 0 to 100%%: "); + for (j = 0; j < spectrum_palette_size; j++) { + printf("\033[48;5;%dm ", spectrum_palette[j]); + } + printf("\033[0m\n"); + printf("---------------------------------------------\n"); +} + +static void latencyDistMode(void) { + redisReply *reply; + long long start, latency, count = 0; + long long history_interval = + config.interval ? config.interval/1000 : + 1000; + long long history_start = ustime(); + int j, outputs = 0; + + struct distsamples samples[] = { + + + + {10,0,'.'}, + {125,0,'-'}, + {250,0,'*'}, + {500,0,'#'}, + {1000,0,'1'}, + {2000,0,'2'}, + {3000,0,'3'}, + {4000,0,'4'}, + {5000,0,'5'}, + {6000,0,'6'}, + {7000,0,'7'}, + {8000,0,'8'}, + {9000,0,'9'}, + {10000,0,'A'}, + {20000,0,'B'}, + {30000,0,'C'}, + {40000,0,'D'}, + {50000,0,'E'}, + {100000,0,'F'}, + {200000,0,'G'}, + {300000,0,'H'}, + {400000,0,'I'}, + {500000,0,'J'}, + {1000000,0,'K'}, + {2000000,0,'L'}, + {4000000,0,'M'}, + {8000000,0,'N'}, + {16000000,0,'O'}, + {30000000,0,'P'}, + {60000000,0,'Q'}, + {0,0,'?'}, + }; + + if (!context) exit(1); + while(1) { + start = ustime(); + reply = reconnectingRedisCommand(context,"PING"); + if (reply == 0) { + fprintf(stderr,"\nI/O error\n"); + exit(1); + } + latency = ustime()-start; + freeReplyObject(reply); + count++; + + + for (j = 0; ; j++) { + if (samples[j].max == 0 || latency <= samples[j].max) { + samples[j].count++; + break; + } + } + + + if (count && (ustime()-history_start)/1000 > history_interval) { + if ((outputs++ % 20) == 0) + showLatencyDistLegend(); + showLatencyDistSamples(samples,count); + history_start = ustime(); + count = 0; + } + usleep(10 * 1000); + } +} + + + + + + + +unsigned long long sendSync(int fd) { + + + + + char buf[4096], *p; + ssize_t nread; + + + if (write(fd,"SYNC\r\n",6) != 6) { + fprintf(stderr,"Error writing to master\n"); + exit(1); + } + + + p = buf; + while(1) { + nread = read(fd,p,1); + if (nread <= 0) { + fprintf(stderr,"Error reading bulk length while SYNCing\n"); + exit(1); + } + if (*p == '\n' && p != buf) break; + if (*p != '\n') p++; + } + *p = '\0'; + if (buf[0] == '-') { + printf("SYNC with master failed: %s\n", buf); + exit(1); + } + return strtoull(buf+1,0,10); +} + +static void slaveMode(void) { + int fd = context->fd; + unsigned long long payload = sendSync(fd); + char buf[1024]; + int original_output = config.output; + + fprintf(stderr,"SYNC with master, discarding %llu " + "bytes of bulk transfer...\n", payload); + + + while(payload) { + ssize_t nread; + + nread = read(fd,buf,(payload > sizeof(buf)) ? sizeof(buf) : payload); + if (nread <= 0) { + fprintf(stderr,"Error reading RDB payload while SYNCing\n"); + exit(1); + } + payload -= nread; + } + fprintf(stderr,"SYNC done. Logging commands from master.\n"); + + + config.output = 2; + while (cliReadReply(0) == 0); + config.output = original_output; +} + + + + + + + +static void getRDB(void) { + int s = context->fd; + int fd; + unsigned long long payload = sendSync(s); + char buf[4096]; + + fprintf(stderr,"SYNC sent to master, writing %llu bytes to '%s'\n", + payload, config.rdb_filename); + + + if (!strcmp(config.rdb_filename,"-")) { + fd = STDOUT_FILENO; + } else { + fd = open(config.rdb_filename, O_CREAT|O_WRONLY, 0644); + if (fd == -1) { + fprintf(stderr, "Error opening '%s': %s\n", config.rdb_filename, + strerror(errno)); + exit(1); + } + } + + while(payload) { + ssize_t nread, nwritten; + + nread = read(s,buf,(payload > sizeof(buf)) ? sizeof(buf) : payload); + if (nread <= 0) { + fprintf(stderr,"I/O Error reading RDB payload from socket\n"); + exit(1); + } + nwritten = write(fd, buf, nread); + if (nwritten != nread) { + fprintf(stderr,"Error writing data to file: %s\n", + strerror(errno)); + exit(1); + } + payload -= nread; + } + close(s); + fsync(fd); + fprintf(stderr,"Transfer finished with success.\n"); + exit(0); +} + + + + + + +static void pipeMode(void) { + int fd = context->fd; + long long errors = 0, replies = 0, obuf_len = 0, obuf_pos = 0; + char ibuf[1024*16], obuf[1024*16]; + char aneterr[256]; + redisReader *reader = redisReaderCreate(); + redisReply *reply; + int eof = 0; + int done = 0; + char magic[20]; + time_t last_read_time = time(0); + + srand(time(0)); + + + if (anetNonBlock(aneterr,fd) == -1) { + fprintf(stderr, "Can't set the socket in non blocking mode: %s\n", + aneterr); + exit(1); + } + + + + while(!done) { + int mask = 1; + + if (!eof || obuf_len != 0) mask |= 2; + mask = aeWait(fd,mask,1000); + + + if (mask & 1) { + ssize_t nread; + + + do { + nread = read(fd,ibuf,sizeof(ibuf)); + if (nread == -1 && errno != EAGAIN && errno != EINTR) { + fprintf(stderr, "Error reading from the server: %s\n", + strerror(errno)); + exit(1); + } + if (nread > 0) { + redisReaderFeed(reader,ibuf,nread); + last_read_time = time(0); + } + } while(nread > 0); + + + do { + if (redisReaderGetReply(reader,(void**)&reply) == -1) { + fprintf(stderr, "Error reading replies from server\n"); + exit(1); + } + if (reply) { + if (reply->type == 6) { + fprintf(stderr,"%s\n", reply->str); + errors++; + } else if (eof && reply->type == 1 && + reply->len == 20) { + + + + if (memcmp(reply->str,magic,20) == 0) { + printf("Last reply received from server.\n"); + done = 1; + replies--; + } + } + replies++; + freeReplyObject(reply); + } + } while(reply); + } + + + if (mask & 2) { + ssize_t loop_nwritten = 0; + + while(1) { + + if (obuf_len != 0) { + ssize_t nwritten = write(fd,obuf+obuf_pos,obuf_len); + + if (nwritten == -1) { + if (errno != EAGAIN && errno != EINTR) { + fprintf(stderr, "Error writing to the server: %s\n", + strerror(errno)); + exit(1); + } else { + nwritten = 0; + } + } + obuf_len -= nwritten; + obuf_pos += nwritten; + loop_nwritten += nwritten; + if (obuf_len != 0) break; + } + + if (obuf_len == 0 && !eof) { + ssize_t nread = read(STDIN_FILENO,obuf,sizeof(obuf)); + + if (nread == 0) { + + + + + char echo[] = + "\r\n*2\r\n$4\r\nECHO\r\n$20\r\n01234567890123456789\r\n"; + int j; + + eof = 1; + + + + for (j = 0; j < 20; j++) + magic[j] = rand() & 0xff; + memcpy(echo+21,magic,20); + memcpy(obuf,echo,sizeof(echo)-1); + obuf_len = sizeof(echo)-1; + obuf_pos = 0; + printf("All data transferred. Waiting for the last reply...\n"); + } else if (nread == -1) { + fprintf(stderr, "Error reading from stdin: %s\n", + strerror(errno)); + exit(1); + } else { + obuf_len = nread; + obuf_pos = 0; + } + } + if ((obuf_len == 0 && eof) || + loop_nwritten > (128*1024)) break; + } + } + + + + + if (eof && config.pipe_timeout > 0 && + time(0)-last_read_time > config.pipe_timeout) + { + fprintf(stderr,"No replies for %d seconds: exiting.\n", + config.pipe_timeout); + errors++; + break; + } + } + redisReaderFree(reader); + printf("errors: %lld, replies: %lld\n", errors, replies); + if (errors) + exit(1); + else + exit(0); +} +# 2079 "src/redis-cli.c" +static redisReply *sendScan(unsigned long long *it) { + redisReply *reply = redisCommand(context, "SCAN %llu", *it); + + + if(reply == 0) { + fprintf(stderr, "\nI/O error\n"); + exit(1); + } else if(reply->type == 6) { + fprintf(stderr, "SCAN error: %s\n", reply->str); + exit(1); + } else if(reply->type != 2) { + fprintf(stderr, "Non ARRAY response from SCAN!\n"); + exit(1); + } else if(reply->elements != 2) { + fprintf(stderr, "Invalid element count from SCAN!\n"); + exit(1); + } + + + assert(reply->element[0]->type == 1); + assert(reply->element[1]->type == 2); + + + *it = strtoull(reply->element[0]->str, 0, 10); + + return reply; +} + +static int getDbSize(void) { + redisReply *reply; + int size; + + reply = redisCommand(context, "DBSIZE"); + + if(reply == 0 || reply->type != 3) { + fprintf(stderr, "Couldn't determine DBSIZE!\n"); + exit(1); + } + + + size = reply->integer; + freeReplyObject(reply); + + return size; +} + +static int toIntType(char *key, char *type) { + if(!strcmp(type, "string")) { + return 0; + } else if(!strcmp(type, "list")) { + return 1; + } else if(!strcmp(type, "set")) { + return 2; + } else if(!strcmp(type, "hash")) { + return 3; + } else if(!strcmp(type, "zset")) { + return 4; + } else if(!strcmp(type, "none")) { + return 5; + } else { + fprintf(stderr, "Unknown type '%s' for key '%s'\n", type, key); + exit(1); + } +} + +static void getKeyTypes(redisReply *keys, int *types) { + redisReply *reply; + unsigned int i; + + + for(i=0;i<keys->elements;i++) { + redisAppendCommand(context, "TYPE %s", keys->element[i]->str); + } + + + for(i=0;i<keys->elements;i++) { + if(redisGetReply(context, (void**)&reply)!=0) { + fprintf(stderr, "Error getting type for key '%s' (%d: %s)\n", + keys->element[i]->str, context->err, context->errstr); + exit(1); + } else if(reply->type != 5) { + if(reply->type == 6) { + fprintf(stderr, "TYPE returned an error: %s\n", reply->str); + } else { + fprintf(stderr, + "Invalid reply type (%d) for TYPE on key '%s'!\n", + reply->type, keys->element[i]->str); + } + exit(1); + } + + types[i] = toIntType(keys->element[i]->str, reply->str); + freeReplyObject(reply); + } +} + +static void getKeySizes(redisReply *keys, int *types, + unsigned long long *sizes) +{ + redisReply *reply; + char *sizecmds[] = {"STRLEN","LLEN","SCARD","HLEN","ZCARD"}; + unsigned int i; + + + for(i=0;i<keys->elements;i++) { + + if(types[i]==5) + continue; + + redisAppendCommand(context, "%s %s", sizecmds[types[i]], + keys->element[i]->str); + } + + + for(i=0;i<keys->elements;i++) { + + if(types[i] == 5) { + sizes[i] = 0; + continue; + } + + + if(redisGetReply(context, (void**)&reply)!=0) { + fprintf(stderr, "Error getting size for key '%s' (%d: %s)\n", + keys->element[i]->str, context->err, context->errstr); + exit(1); + } else if(reply->type != 3) { + + + fprintf(stderr, + "Warning: %s on '%s' failed (may have changed type)\n", + sizecmds[types[i]], keys->element[i]->str); + sizes[i] = 0; + } else { + sizes[i] = reply->integer; + } + + freeReplyObject(reply); + } +} + +static void findBigKeys(void) { + unsigned long long biggest[5] = {0}, counts[5] = {0}, totalsize[5] = {0}; + unsigned long long sampled = 0, total_keys, totlen=0, *sizes=0, it=0; + sds maxkeys[5] = {0}; + char *typename[] = {"string","list","set","hash","zset"}; + char *typeunit[] = {"bytes","items","members","fields","members"}; + redisReply *reply, *keys; + unsigned int arrsize=0, i; + int type, *types=0; + double pct; + + + total_keys = getDbSize(); + + + printf("\n# Scanning the entire keyspace to find biggest keys as well as\n"); + printf("# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec\n"); + printf("# per 100 SCAN commands (not usually needed).\n\n"); + + + for(i=0;i<5; i++) { + maxkeys[i] = sdsempty(); + if(!maxkeys[i]) { + fprintf(stderr, "Failed to allocate memory for largest key names!\n"); + exit(1); + } + } + + + do { + + pct = 100 * (double)sampled/total_keys; + + + reply = sendScan(&it); + keys = reply->element[1]; + + + if(keys->elements > arrsize) { + types = zrealloc(types, sizeof(int)*keys->elements); + sizes = zrealloc(sizes, sizeof(unsigned long long)*keys->elements); + + if(!types || !sizes) { + fprintf(stderr, "Failed to allocate storage for keys!\n"); + exit(1); + } + + arrsize = keys->elements; + } + + + getKeyTypes(keys, types); + getKeySizes(keys, types, sizes); + + + for(i=0;i<keys->elements;i++) { + if((type = types[i]) == 5) + continue; + + totalsize[type] += sizes[i]; + counts[type]++; + totlen += keys->element[i]->len; + sampled++; + + if(biggest[type]<sizes[i]) { + printf( + "[%05.2f%%] Biggest %-6s found so far '%s' with %llu %s\n", + pct, typename[type], keys->element[i]->str, sizes[i], + typeunit[type]); + + + maxkeys[type] = sdscpy(maxkeys[type], keys->element[i]->str); + if(!maxkeys[type]) { + fprintf(stderr, "Failed to allocate memory for key!\n"); + exit(1); + } + + + biggest[type] = sizes[i]; + } + + + if(sampled % 1000000 == 0) { + printf("[%05.2f%%] Sampled %llu keys so far\n", pct, sampled); + } + } + + + if(sampled && (sampled %100) == 0 && config.interval) { + usleep(config.interval); + } + + freeReplyObject(reply); + } while(it != 0); + + if(types) zfree(types); + if(sizes) zfree(sizes); + + + printf("\n-------- summary -------\n\n"); + + printf("Sampled %llu keys in the keyspace!\n", sampled); + printf("Total key length in bytes is %llu (avg len %.2f)\n\n", + totlen, totlen ? (double)totlen/sampled : 0); + + + for(i=0;i<5;i++) { + if(sdslen(maxkeys[i])>0) { + printf("Biggest %6s found '%s' has %llu %s\n", typename[i], maxkeys[i], + biggest[i], typeunit[i]); + } + } + + printf("\n"); + + for(i=0;i<5;i++) { + printf("%llu %ss with %llu %s (%05.2f%% of keys, avg size %.2f)\n", + counts[i], typename[i], totalsize[i], typeunit[i], + sampled ? 100 * (double)counts[i]/sampled : 0, + counts[i] ? (double)totalsize[i]/counts[i] : 0); + } + + + for(i=0;i<5;i++) { + sdsfree(maxkeys[i]); + } + + + exit(0); +} + +static void getKeyFreqs(redisReply *keys, unsigned long long *freqs) { + redisReply *reply; + unsigned int i; + + + for(i=0;i<keys->elements;i++) { + redisAppendCommand(context, "OBJECT freq %s", keys->element[i]->str); + } + + + for(i=0;i<keys->elements;i++) { + if(redisGetReply(context, (void**)&reply)!=0) { + fprintf(stderr, "Error getting freq for key '%s' (%d: %s)\n", + keys->element[i]->str, context->err, context->errstr); + exit(1); + } else if(reply->type != 3) { + if(reply->type == 6) { + fprintf(stderr, "Error: %s\n", reply->str); + exit(1); + } else { + fprintf(stderr, "Warning: OBJECT freq on '%s' failed (may have been deleted)\n", keys->element[i]->str); + freqs[i] = 0; + } + } else { + freqs[i] = reply->integer; + } + freeReplyObject(reply); + } +} + + +static void findHotKeys(void) { + redisReply *keys, *reply; + unsigned long long counters[16] = {0}; + sds hotkeys[16] = {0}; + unsigned long long sampled = 0, total_keys, *freqs = 0, it = 0; + unsigned int arrsize = 0, i, k; + double pct; + + + total_keys = getDbSize(); + + + printf("\n# Scanning the entire keyspace to find hot keys as well as\n"); + printf("# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec\n"); + printf("# per 100 SCAN commands (not usually needed).\n\n"); + + + do { + + pct = 100 * (double)sampled/total_keys; + + + reply = sendScan(&it); + keys = reply->element[1]; + + + if(keys->elements > arrsize) { + freqs = zrealloc(freqs, sizeof(unsigned long long)*keys->elements); + + if(!freqs) { + fprintf(stderr, "Failed to allocate storage for keys!\n"); + exit(1); + } + + arrsize = keys->elements; + } + + getKeyFreqs(keys, freqs); + + + for(i=0;i<keys->elements;i++) { + sampled++; + + if(sampled % 1000000 == 0) { + printf("[%05.2f%%] Sampled %llu keys so far\n", pct, sampled); + } + + + k = 0; + while (k < 16 && freqs[i] > counters[k]) k++; + if (k == 0) continue; + k--; + if (k == 0 || counters[k] == 0) { + sdsfree(hotkeys[k]); + } else { + sdsfree(hotkeys[0]); + memmove(counters,counters+1,sizeof(counters[0])*k); + memmove(hotkeys,hotkeys+1,sizeof(hotkeys[0])*k); + } + counters[k] = freqs[i]; + hotkeys[k] = sdsnew(keys->element[i]->str); + printf( + "[%05.2f%%] Hot key '%s' found so far with counter %llu\n", + pct, keys->element[i]->str, freqs[i]); + } + + + if(sampled && (sampled %100) == 0 && config.interval) { + usleep(config.interval); + } + + freeReplyObject(reply); + } while(it != 0); + + if (freqs) zfree(freqs); + + + printf("\n-------- summary -------\n\n"); + + printf("Sampled %llu keys in the keyspace!\n", sampled); + + for (i=1; i<= 16; i++) { + k = 16 - i; + if(counters[k]>0) { + printf("hot key found with counter: %llu\tkeyname: %s\n", counters[k], hotkeys[k]); + sdsfree(hotkeys[k]); + } + } + + exit(0); +} +# 2481 "src/redis-cli.c" +static char *getInfoField(char *info, char *field) { + char *p = strstr(info,field); + char *n1, *n2; + char *result; + + if (!p) return 0; + p += strlen(field)+1; + n1 = strchr(p,'\r'); + n2 = strchr(p,','); + if (n2 && n2 < n1) n1 = n2; + result = zmalloc(sizeof(char)*(n1-p)+1); + memcpy(result,p,(n1-p)); + result[n1-p] = '\0'; + return result; +} + + + +static long getLongInfoField(char *info, char *field) { + char *value = getInfoField(info,field); + long l; + + if (!value) return LONG_MIN; + l = strtol(value,0,10); + zfree(value); + return l; +} + + + +void bytesToHuman(char *s, long long n) { + double d; + + if (n < 0) { + *s = '-'; + s++; + n = -n; + } + if (n < 1024) { + + sprintf(s,"%lldB",n); + return; + } else if (n < (1024*1024)) { + d = (double)n/(1024); + sprintf(s,"%.2fK",d); + } else if (n < (1024LL*1024*1024)) { + d = (double)n/(1024*1024); + sprintf(s,"%.2fM",d); + } else if (n < (1024LL*1024*1024*1024)) { + d = (double)n/(1024LL*1024*1024); + sprintf(s,"%.2fG",d); + } +} + +static void statMode(void) { + redisReply *reply; + long aux, requests = 0; + int i = 0; + + while(1) { + char buf[64]; + int j; + + reply = reconnectingRedisCommand(context,"INFO"); + if (reply->type == 6) { + printf("ERROR: %s\n", reply->str); + exit(1); + } + + if ((i++ % 20) == 0) { + printf( +"------- data ------ --------------------- load -------------------- - child -\n" +"keys mem clients blocked requests connections \n"); + } + + + aux = 0; + for (j = 0; j < 20; j++) { + long k; + + sprintf(buf,"db%d:keys",j); + k = getLongInfoField(reply->str,buf); + if (k == LONG_MIN) continue; + aux += k; + } + sprintf(buf,"%ld",aux); + printf("%-11s",buf); + + + aux = getLongInfoField(reply->str,"used_memory"); + bytesToHuman(buf,aux); + printf("%-8s",buf); + + + aux = getLongInfoField(reply->str,"connected_clients"); + sprintf(buf,"%ld",aux); + printf(" %-8s",buf); + + + aux = getLongInfoField(reply->str,"blocked_clients"); + sprintf(buf,"%ld",aux); + printf("%-8s",buf); + + + aux = getLongInfoField(reply->str,"total_commands_processed"); + sprintf(buf,"%ld (+%ld)",aux,requests == 0 ? 0 : aux-requests); + printf("%-19s",buf); + requests = aux; + + + aux = getLongInfoField(reply->str,"total_connections_received"); + sprintf(buf,"%ld",aux); + printf(" %-12s",buf); + + + aux = getLongInfoField(reply->str,"bgsave_in_progress"); + aux |= getLongInfoField(reply->str,"aof_rewrite_in_progress") << 1; + aux |= getLongInfoField(reply->str,"loading") << 2; + switch(aux) { + case 0: break; + case 1: + printf("SAVE"); + break; + case 2: + printf("AOF"); + break; + case 3: + printf("SAVE+AOF"); + break; + case 4: + printf("LOAD"); + break; + } + + printf("\n"); + freeReplyObject(reply); + usleep(config.interval); + } +} + + + + + +static void scanMode(void) { + redisReply *reply; + unsigned long long cur = 0; + + do { + if (config.pattern) + reply = redisCommand(context,"SCAN %llu MATCH %s", + cur,config.pattern); + else + reply = redisCommand(context,"SCAN %llu",cur); + if (reply == 0) { + printf("I/O error\n"); + exit(1); + } else if (reply->type == 6) { + printf("ERROR: %s\n", reply->str); + exit(1); + } else { + unsigned int j; + + cur = strtoull(reply->element[0]->str,0,10); + for (j = 0; j < reply->element[1]->elements; j++) + printf("%s\n", reply->element[1]->element[j]->str); + } + freeReplyObject(reply); + } while(cur != 0); + + exit(0); +} +# 2664 "src/redis-cli.c" +long long powerLawRand(long long min, long long max, double alpha) { + double pl, r; + + max += 1; + r = ((double)rand()) / 32767; + pl = pow( + ((pow(max,alpha+1) - pow(min,alpha+1))*r + pow(min,alpha+1)), + (1.0/(alpha+1))); + return (max-1-(long long)pl)+min; +} + + + +void LRUTestGenKey(char *buf, size_t buflen) { + snprintf(buf, buflen, "lru:%lld", + powerLawRand(1, config.lru_test_sample_size, 6.2)); +} + + + +static void LRUTestMode(void) { + redisReply *reply; + char key[128]; + long long start_cycle; + int j; + + srand(time(0)^getpid()); + while(1) { + + + + start_cycle = mstime(); + long long hits = 0, misses = 0; + while(mstime() - start_cycle < 1000) { + + for (j = 0; j < 250; j++) { + char val[6]; + val[5] = '\0'; + for (int i = 0; i < 5; i++) val[i] = 'A'+rand()%('z'-'A'); + LRUTestGenKey(key,sizeof(key)); + redisAppendCommand(context, "SET %s %s",key,val); + } + for (j = 0; j < 250; j++) + redisGetReply(context, (void**)&reply); + + + for (j = 0; j < 250; j++) { + LRUTestGenKey(key,sizeof(key)); + redisAppendCommand(context, "GET %s",key); + } + for (j = 0; j < 250; j++) { + if (redisGetReply(context, (void**)&reply) == 0) { + switch(reply->type) { + case 6: + printf("%s\n", reply->str); + break; + case 4: + misses++; + break; + default: + hits++; + break; + } + } + } + + if (context->err) { + fprintf(stderr,"I/O error during LRU test\n"); + exit(1); + } + } + + printf( + "%lld Gets/sec | Hits: %lld (%.2f%%) | Misses: %lld (%.2f%%)\n", + hits+misses, + hits, (double)hits/(hits+misses)*100, + misses, (double)misses/(hits+misses)*100); + } + exit(0); +} +# 2756 "src/redis-cli.c" +unsigned long compute_something_fast(void) { + unsigned char s[256], i, j, t; + int count = 1000, k; + unsigned long output = 0; + + for (k = 0; k < 256; k++) s[k] = k; + + i = 0; + j = 0; + while(count--) { + i++; + j = j + s[i]; + t = s[i]; + s[i] = s[j]; + s[j] = t; + output += s[(s[i]+s[j])&255]; + } + return output; +} + +static void intrinsicLatencyModeStop(int s) { + ((void) s); + force_cancel_loop = 1; +} + +static void intrinsicLatencyMode(void) { + long long test_end, run_time, max_latency = 0, runs = 0; + + run_time = config.intrinsic_latency_duration*1000000; + test_end = ustime() + run_time; + signal(SIGINT, intrinsicLatencyModeStop); + + while(1) { + long long start, end, latency; + + start = ustime(); + compute_something_fast(); + end = ustime(); + latency = end-start; + runs++; + if (latency <= 0) continue; + + + if (latency > max_latency) { + max_latency = latency; + printf("Max latency so far: %lld microseconds.\n", max_latency); + } + + double avg_us = (double)run_time/runs; + double avg_ns = avg_us * 1e3; + if (force_cancel_loop || end > test_end) { + printf("\n%lld total runs " + "(avg latency: " + "%.4f microseconds / %.2f nanoseconds per run).\n", + runs, avg_us, avg_ns); + printf("Worst run took %.0fx longer than the average latency.\n", + max_latency / avg_us); + exit(0); + } + } +} + + + + + +int main(int argc, char **argv) { + int firstarg; + + config.hostip = sdsnew("127.0.0.1"); + config.hostport = 6379; + config.hostsocket = 0; + config.repeat = 1; + config.interval = 0; + config.dbnum = 0; + config.interactive = 0; + config.shutdown = 0; + config.monitor_mode = 0; + config.pubsub_mode = 0; + config.latency_mode = 0; + config.latency_dist_mode = 0; + config.latency_history = 0; + config.lru_test_mode = 0; + config.lru_test_sample_size = 0; + config.cluster_mode = 0; + config.slave_mode = 0; + config.getrdb_mode = 0; + config.stat_mode = 0; + config.scan_mode = 0; + config.intrinsic_latency_mode = 0; + config.pattern = 0; + config.rdb_filename = 0; + config.pipe_mode = 0; + config.pipe_timeout = 30; + config.bigkeys = 0; + config.hotkeys = 0; + config.stdinarg = 0; + config.auth = 0; + config.eval = 0; + config.eval_ldb = 0; + config.eval_ldb_end = 0; + config.eval_ldb_sync = 0; + config.enable_ldb_on_eval = 0; + config.last_cmd_type = -1; + + pref.hints = 1; + + spectrum_palette = spectrum_palette_color; + spectrum_palette_size = spectrum_palette_color_size; + + if (!isatty(fileno(stdout)) && (getenv("FAKETTY") == 0)) + config.output = 1; + else + config.output = 0; + config.mb_delim = sdsnew("\n"); + + firstarg = parseOptions(argc,argv); + argc -= firstarg; + argv += firstarg; + + + if (config.latency_mode) { + if (cliConnect(0) == -1) exit(1); + latencyMode(); + } + + + if (config.latency_dist_mode) { + if (cliConnect(0) == -1) exit(1); + latencyDistMode(); + } + + + if (config.slave_mode) { + if (cliConnect(0) == -1) exit(1); + slaveMode(); + } + + + if (config.getrdb_mode) { + if (cliConnect(0) == -1) exit(1); + getRDB(); + } + + + if (config.pipe_mode) { + if (cliConnect(0) == -1) exit(1); + pipeMode(); + } + + + if (config.bigkeys) { + if (cliConnect(0) == -1) exit(1); + findBigKeys(); + } + + + if (config.hotkeys) { + if (cliConnect(0) == -1) exit(1); + findHotKeys(); + } + + + if (config.stat_mode) { + if (cliConnect(0) == -1) exit(1); + if (config.interval == 0) config.interval = 1000000; + statMode(); + } + + + if (config.scan_mode) { + if (cliConnect(0) == -1) exit(1); + scanMode(); + } + + + if (config.lru_test_mode) { + if (cliConnect(0) == -1) exit(1); + LRUTestMode(); + } + + + if (config.intrinsic_latency_mode) intrinsicLatencyMode(); + + + if (argc == 0 && !config.eval) { + + signal(SIGPIPE, SIG_IGN); + + + + cliConnect(0); + repl(); + } + + + if (cliConnect(0) != 0) exit(1); + if (config.eval) { + return evalMode(argc,argv); + } else { + return noninteractive(argc,convertToSds(argc,argv)); + } +} diff --git a/utils/benchmark/inputs/sqlite-btree.c.ppout b/utils/benchmark/inputs/sqlite-btree.c.ppout new file mode 100644 index 0000000..e73a0fa --- /dev/null +++ b/utils/benchmark/inputs/sqlite-btree.c.ppout @@ -0,0 +1,11397 @@ +# 1 "src/btree.c" +# 1 "<built-in>" +# 1 "<command-line>" +# 1 "src/btree.c" +# 16 "src/btree.c" +# 1 "src/btreeInt.h" 1 +# 216 "src/btreeInt.h" +# 1 "src/sqliteInt.h" 1 +# 59 "src/sqliteInt.h" +# 1 "src/msvc.h" 1 +# 60 "src/sqliteInt.h" 2 + + + + +# 1 "src/vxworks.h" 1 +# 65 "src/sqliteInt.h" 2 +# 167 "src/sqliteInt.h" +# 1 "./sqlite3.h" 1 +# 35 "./sqlite3.h" +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_typedefs.h" 1 + + + +typedef int size_t; +typedef int __builtin_va_list; +typedef int __gnuc_va_list; +typedef int va_list; +typedef int __int8_t; +typedef int __uint8_t; +typedef int __int16_t; +typedef int __uint16_t; +typedef int __int_least16_t; +typedef int __uint_least16_t; +typedef int __int32_t; +typedef int __uint32_t; +typedef int __int64_t; +typedef int __uint64_t; +typedef int __int_least32_t; +typedef int __uint_least32_t; +typedef int __s8; +typedef int __u8; +typedef int __s16; +typedef int __u16; +typedef int __s32; +typedef int __u32; +typedef int __s64; +typedef int __u64; +typedef int _LOCK_T; +typedef int _LOCK_RECURSIVE_T; +typedef int _off_t; +typedef int __dev_t; +typedef int __uid_t; +typedef int __gid_t; +typedef int _off64_t; +typedef int _fpos_t; +typedef int _ssize_t; +typedef int wint_t; +typedef int _mbstate_t; +typedef int _flock_t; +typedef int _iconv_t; +typedef int __ULong; +typedef int __FILE; +typedef int ptrdiff_t; +typedef int wchar_t; +typedef int __off_t; +typedef int __pid_t; +typedef int __loff_t; +typedef int u_char; +typedef int u_short; +typedef int u_int; +typedef int u_long; +typedef int ushort; +typedef int uint; +typedef int clock_t; +typedef int time_t; +typedef int daddr_t; +typedef int caddr_t; +typedef int ino_t; +typedef int off_t; +typedef int dev_t; +typedef int uid_t; +typedef int gid_t; +typedef int pid_t; +typedef int key_t; +typedef int ssize_t; +typedef int mode_t; +typedef int nlink_t; +typedef int fd_mask; +typedef int _types_fd_set; +typedef int clockid_t; +typedef int timer_t; +typedef int useconds_t; +typedef int suseconds_t; +typedef int FILE; +typedef int fpos_t; +typedef int cookie_read_function_t; +typedef int cookie_write_function_t; +typedef int cookie_seek_function_t; +typedef int cookie_close_function_t; +typedef int cookie_io_functions_t; +typedef int div_t; +typedef int ldiv_t; +typedef int lldiv_t; +typedef int sigset_t; +typedef int __sigset_t; +typedef int _sig_func_ptr; +typedef int sig_atomic_t; +typedef int __tzrule_type; +typedef int __tzinfo_type; +typedef int mbstate_t; +typedef int sem_t; +typedef int pthread_t; +typedef int pthread_attr_t; +typedef int pthread_mutex_t; +typedef int pthread_mutexattr_t; +typedef int pthread_cond_t; +typedef int pthread_condattr_t; +typedef int pthread_key_t; +typedef int pthread_once_t; +typedef int pthread_rwlock_t; +typedef int pthread_rwlockattr_t; +typedef int pthread_spinlock_t; +typedef int pthread_barrier_t; +typedef int pthread_barrierattr_t; +typedef int jmp_buf; +typedef int rlim_t; +typedef int sa_family_t; +typedef int sigjmp_buf; +typedef int stack_t; +typedef int siginfo_t; +typedef int z_stream; + + +typedef int int8_t; +typedef int uint8_t; +typedef int int16_t; +typedef int uint16_t; +typedef int int32_t; +typedef int uint32_t; +typedef int int64_t; +typedef int uint64_t; + + +typedef int int_least8_t; +typedef int uint_least8_t; +typedef int int_least16_t; +typedef int uint_least16_t; +typedef int int_least32_t; +typedef int uint_least32_t; +typedef int int_least64_t; +typedef int uint_least64_t; + + +typedef int int_fast8_t; +typedef int uint_fast8_t; +typedef int int_fast16_t; +typedef int uint_fast16_t; +typedef int int_fast32_t; +typedef int uint_fast32_t; +typedef int int_fast64_t; +typedef int uint_fast64_t; + + +typedef int intptr_t; +typedef int uintptr_t; + + +typedef int intmax_t; +typedef int uintmax_t; + + +typedef _Bool bool; + + +typedef void* MirEGLNativeWindowType; +typedef void* MirEGLNativeDisplayType; +typedef struct MirConnection MirConnection; +typedef struct MirSurface MirSurface; +typedef struct MirSurfaceSpec MirSurfaceSpec; +typedef struct MirScreencast MirScreencast; +typedef struct MirPromptSession MirPromptSession; +typedef struct MirBufferStream MirBufferStream; +typedef struct MirPersistentId MirPersistentId; +typedef struct MirBlob MirBlob; +typedef struct MirDisplayConfig MirDisplayConfig; + + +typedef struct xcb_connection_t xcb_connection_t; +typedef uint32_t xcb_window_t; +typedef uint32_t xcb_visualid_t; +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 2 +# 36 "./sqlite3.h" 2 +# 162 "./sqlite3.h" + extern const char sqlite3_version[]; + const char *sqlite3_libversion(void); + const char *sqlite3_sourceid(void); + int sqlite3_libversion_number(void); +# 190 "./sqlite3.h" + int sqlite3_compileoption_used(const char *zOptName); + const char *sqlite3_compileoption_get(int N); +# 233 "./sqlite3.h" + int sqlite3_threadsafe(void); +# 249 "./sqlite3.h" +typedef struct sqlite3 sqlite3; +# 278 "./sqlite3.h" + typedef long long int sqlite_int64; + typedef unsigned long long int sqlite_uint64; + +typedef sqlite_int64 sqlite3_int64; +typedef sqlite_uint64 sqlite3_uint64; +# 334 "./sqlite3.h" + int sqlite3_close(sqlite3*); + int sqlite3_close_v2(sqlite3*); + + + + + + +typedef int (*sqlite3_callback)(void*,int,char**, char**); +# 406 "./sqlite3.h" + int sqlite3_exec( + sqlite3*, + const char *sql, + int (*callback)(void*,int,char**,char**), + void *, + char **errmsg +); +# 677 "./sqlite3.h" +typedef struct sqlite3_file sqlite3_file; +struct sqlite3_file { + const struct sqlite3_io_methods *pMethods; +}; +# 776 "./sqlite3.h" +typedef struct sqlite3_io_methods sqlite3_io_methods; +struct sqlite3_io_methods { + int iVersion; + int (*xClose)(sqlite3_file*); + int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); + int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst); + int (*xTruncate)(sqlite3_file*, sqlite3_int64 size); + int (*xSync)(sqlite3_file*, int flags); + int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize); + int (*xLock)(sqlite3_file*, int); + int (*xUnlock)(sqlite3_file*, int); + int (*xCheckReservedLock)(sqlite3_file*, int *pResOut); + int (*xFileControl)(sqlite3_file*, int op, void *pArg); + int (*xSectorSize)(sqlite3_file*); + int (*xDeviceCharacteristics)(sqlite3_file*); + + int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**); + int (*xShmLock)(sqlite3_file*, int offset, int n, int flags); + void (*xShmBarrier)(sqlite3_file*); + int (*xShmUnmap)(sqlite3_file*, int deleteFlag); + + int (*xFetch)(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); + int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p); + + +}; +# 1164 "./sqlite3.h" +typedef struct sqlite3_mutex sqlite3_mutex; +# 1174 "./sqlite3.h" +typedef struct sqlite3_api_routines sqlite3_api_routines; +# 1345 "./sqlite3.h" +typedef struct sqlite3_vfs sqlite3_vfs; +typedef void (*sqlite3_syscall_ptr)(void); +struct sqlite3_vfs { + int iVersion; + int szOsFile; + int mxPathname; + sqlite3_vfs *pNext; + const char *zName; + void *pAppData; + int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*, + int flags, int *pOutFlags); + int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir); + int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut); + int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut); + void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename); + void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg); + void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void); + void (*xDlClose)(sqlite3_vfs*, void*); + int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut); + int (*xSleep)(sqlite3_vfs*, int microseconds); + int (*xCurrentTime)(sqlite3_vfs*, double*); + int (*xGetLastError)(sqlite3_vfs*, int, char *); + + + + + int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*); + + + + + int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr); + sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName); + const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName); + + + + + +}; +# 1523 "./sqlite3.h" + int sqlite3_initialize(void); + int sqlite3_shutdown(void); + int sqlite3_os_init(void); + int sqlite3_os_end(void); +# 1559 "./sqlite3.h" + int sqlite3_config(int, ...); +# 1578 "./sqlite3.h" + int sqlite3_db_config(sqlite3*, int op, ...); +# 1643 "./sqlite3.h" +typedef struct sqlite3_mem_methods sqlite3_mem_methods; +struct sqlite3_mem_methods { + void *(*xMalloc)(int); + void (*xFree)(void*); + void *(*xRealloc)(void*,int); + int (*xSize)(void*); + int (*xRoundup)(int); + int (*xInit)(void*); + void (*xShutdown)(void*); + void *pAppData; +}; +# 2278 "./sqlite3.h" + int sqlite3_extended_result_codes(sqlite3*, int onoff); +# 2340 "./sqlite3.h" + sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); +# 2350 "./sqlite3.h" + void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); +# 2408 "./sqlite3.h" + int sqlite3_changes(sqlite3*); +# 2445 "./sqlite3.h" + int sqlite3_total_changes(sqlite3*); +# 2482 "./sqlite3.h" + void sqlite3_interrupt(sqlite3*); +# 2517 "./sqlite3.h" + int sqlite3_complete(const char *sql); + int sqlite3_complete16(const void *sql); +# 2579 "./sqlite3.h" + int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*); +# 2602 "./sqlite3.h" + int sqlite3_busy_timeout(sqlite3*, int ms); +# 2677 "./sqlite3.h" + int sqlite3_get_table( + sqlite3 *db, + const char *zSql, + char ***pazResult, + int *pnRow, + int *pnColumn, + char **pzErrmsg +); + void sqlite3_free_table(char **result); +# 2727 "./sqlite3.h" + char *sqlite3_mprintf(const char*,...); + char *sqlite3_vmprintf(const char*, va_list); + char *sqlite3_snprintf(int,char*,const char*, ...); + char *sqlite3_vsnprintf(int,char*,const char*, va_list); +# 2820 "./sqlite3.h" + void *sqlite3_malloc(int); + void *sqlite3_malloc64(sqlite3_uint64); + void *sqlite3_realloc(void*, int); + void *sqlite3_realloc64(void*, sqlite3_uint64); + void sqlite3_free(void*); + sqlite3_uint64 sqlite3_msize(void*); +# 2850 "./sqlite3.h" + sqlite3_int64 sqlite3_memory_used(void); + sqlite3_int64 sqlite3_memory_highwater(int resetFlag); +# 2874 "./sqlite3.h" + void sqlite3_randomness(int N, void *P); +# 2965 "./sqlite3.h" + int sqlite3_set_authorizer( + sqlite3*, + int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), + void *pUserData +); +# 3073 "./sqlite3.h" + void *sqlite3_trace(sqlite3*, + void(*xTrace)(void*,const char*), void*); + void *sqlite3_profile(sqlite3*, + void(*xProfile)(void*,const char*,sqlite3_uint64), void*); +# 3164 "./sqlite3.h" + int sqlite3_trace_v2( + sqlite3*, + unsigned uMask, + int(*xCallback)(unsigned,void*,void*,void*), + void *pCtx +); +# 3203 "./sqlite3.h" + void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); +# 3432 "./sqlite3.h" + int sqlite3_open( + const char *filename, + sqlite3 **ppDb +); + int sqlite3_open16( + const void *filename, + sqlite3 **ppDb +); + int sqlite3_open_v2( + const char *filename, + sqlite3 **ppDb, + int flags, + const char *zVfs +); +# 3488 "./sqlite3.h" + const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); + int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault); + sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64); +# 3545 "./sqlite3.h" + int sqlite3_errcode(sqlite3 *db); + int sqlite3_extended_errcode(sqlite3 *db); + const char *sqlite3_errmsg(sqlite3*); + const void *sqlite3_errmsg16(sqlite3*); + const char *sqlite3_errstr(int); +# 3575 "./sqlite3.h" +typedef struct sqlite3_stmt sqlite3_stmt; +# 3617 "./sqlite3.h" + int sqlite3_limit(sqlite3*, int id, int newVal); +# 3827 "./sqlite3.h" + int sqlite3_prepare( + sqlite3 *db, + const char *zSql, + int nByte, + sqlite3_stmt **ppStmt, + const char **pzTail +); + int sqlite3_prepare_v2( + sqlite3 *db, + const char *zSql, + int nByte, + sqlite3_stmt **ppStmt, + const char **pzTail +); + int sqlite3_prepare_v3( + sqlite3 *db, + const char *zSql, + int nByte, + unsigned int prepFlags, + sqlite3_stmt **ppStmt, + const char **pzTail +); + int sqlite3_prepare16( + sqlite3 *db, + const void *zSql, + int nByte, + sqlite3_stmt **ppStmt, + const void **pzTail +); + int sqlite3_prepare16_v2( + sqlite3 *db, + const void *zSql, + int nByte, + sqlite3_stmt **ppStmt, + const void **pzTail +); + int sqlite3_prepare16_v3( + sqlite3 *db, + const void *zSql, + int nByte, + unsigned int prepFlags, + sqlite3_stmt **ppStmt, + const void **pzTail +); +# 3910 "./sqlite3.h" + const char *sqlite3_sql(sqlite3_stmt *pStmt); + char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); + const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt); +# 3948 "./sqlite3.h" + int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); +# 3960 "./sqlite3.h" + int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt); +# 3981 "./sqlite3.h" + int sqlite3_stmt_busy(sqlite3_stmt*); +# 4023 "./sqlite3.h" +typedef struct sqlite3_value sqlite3_value; +# 4037 "./sqlite3.h" +typedef struct sqlite3_context sqlite3_context; +# 4157 "./sqlite3.h" + int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); + int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64, + void(*)(void*)); + int sqlite3_bind_double(sqlite3_stmt*, int, double); + int sqlite3_bind_int(sqlite3_stmt*, int, int); + int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); + int sqlite3_bind_null(sqlite3_stmt*, int); + int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*)); + int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); + int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, + void(*)(void*), unsigned char encoding); + int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); + int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*)); + int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); + int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64); +# 4192 "./sqlite3.h" + int sqlite3_bind_parameter_count(sqlite3_stmt*); +# 4220 "./sqlite3.h" + const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int); +# 4238 "./sqlite3.h" + int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName); +# 4248 "./sqlite3.h" + int sqlite3_clear_bindings(sqlite3_stmt*); +# 4264 "./sqlite3.h" + int sqlite3_column_count(sqlite3_stmt *pStmt); +# 4293 "./sqlite3.h" + const char *sqlite3_column_name(sqlite3_stmt*, int N); + const void *sqlite3_column_name16(sqlite3_stmt*, int N); +# 4342 "./sqlite3.h" + const char *sqlite3_column_database_name(sqlite3_stmt*,int); + const void *sqlite3_column_database_name16(sqlite3_stmt*,int); + const char *sqlite3_column_table_name(sqlite3_stmt*,int); + const void *sqlite3_column_table_name16(sqlite3_stmt*,int); + const char *sqlite3_column_origin_name(sqlite3_stmt*,int); + const void *sqlite3_column_origin_name16(sqlite3_stmt*,int); +# 4379 "./sqlite3.h" + const char *sqlite3_column_decltype(sqlite3_stmt*,int); + const void *sqlite3_column_decltype16(sqlite3_stmt*,int); +# 4464 "./sqlite3.h" + int sqlite3_step(sqlite3_stmt*); +# 4485 "./sqlite3.h" + int sqlite3_data_count(sqlite3_stmt *pStmt); +# 4728 "./sqlite3.h" + const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); + double sqlite3_column_double(sqlite3_stmt*, int iCol); + int sqlite3_column_int(sqlite3_stmt*, int iCol); + sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); + const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); + const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); + sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol); + int sqlite3_column_bytes(sqlite3_stmt*, int iCol); + int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); + int sqlite3_column_type(sqlite3_stmt*, int iCol); +# 4765 "./sqlite3.h" + int sqlite3_finalize(sqlite3_stmt *pStmt); +# 4792 "./sqlite3.h" + int sqlite3_reset(sqlite3_stmt *pStmt); +# 4904 "./sqlite3.h" + int sqlite3_create_function( + sqlite3 *db, + const char *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*) +); + int sqlite3_create_function16( + sqlite3 *db, + const void *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*) +); + int sqlite3_create_function_v2( + sqlite3 *db, + const char *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void(*xDestroy)(void*) +); + int sqlite3_create_window_function( + sqlite3 *db, + const char *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void (*xValue)(sqlite3_context*), + void (*xInverse)(sqlite3_context*,int,sqlite3_value**), + void(*xDestroy)(void*) +); +# 4982 "./sqlite3.h" + int sqlite3_aggregate_count(sqlite3_context*); + int sqlite3_expired(sqlite3_stmt*); + int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); + int sqlite3_global_recover(void); + void sqlite3_thread_cleanup(void); + int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int), + void*,sqlite3_int64); +# 5119 "./sqlite3.h" + const void *sqlite3_value_blob(sqlite3_value*); + double sqlite3_value_double(sqlite3_value*); + int sqlite3_value_int(sqlite3_value*); + sqlite3_int64 sqlite3_value_int64(sqlite3_value*); + void *sqlite3_value_pointer(sqlite3_value*, const char*); + const unsigned char *sqlite3_value_text(sqlite3_value*); + const void *sqlite3_value_text16(sqlite3_value*); + const void *sqlite3_value_text16le(sqlite3_value*); + const void *sqlite3_value_text16be(sqlite3_value*); + int sqlite3_value_bytes(sqlite3_value*); + int sqlite3_value_bytes16(sqlite3_value*); + int sqlite3_value_type(sqlite3_value*); + int sqlite3_value_numeric_type(sqlite3_value*); + int sqlite3_value_nochange(sqlite3_value*); + int sqlite3_value_frombind(sqlite3_value*); +# 5145 "./sqlite3.h" + unsigned int sqlite3_value_subtype(sqlite3_value*); +# 5161 "./sqlite3.h" + sqlite3_value *sqlite3_value_dup(const sqlite3_value*); + void sqlite3_value_free(sqlite3_value*); +# 5207 "./sqlite3.h" + void *sqlite3_aggregate_context(sqlite3_context*, int nBytes); +# 5222 "./sqlite3.h" + void *sqlite3_user_data(sqlite3_context*); +# 5234 "./sqlite3.h" + sqlite3 *sqlite3_context_db_handle(sqlite3_context*); +# 5293 "./sqlite3.h" + void *sqlite3_get_auxdata(sqlite3_context*, int N); + void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); +# 5311 "./sqlite3.h" +typedef void (*sqlite3_destructor_type)(void*); +# 5441 "./sqlite3.h" + void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); + void sqlite3_result_blob64(sqlite3_context*,const void*, + sqlite3_uint64,void(*)(void*)); + void sqlite3_result_double(sqlite3_context*, double); + void sqlite3_result_error(sqlite3_context*, const char*, int); + void sqlite3_result_error16(sqlite3_context*, const void*, int); + void sqlite3_result_error_toobig(sqlite3_context*); + void sqlite3_result_error_nomem(sqlite3_context*); + void sqlite3_result_error_code(sqlite3_context*, int); + void sqlite3_result_int(sqlite3_context*, int); + void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); + void sqlite3_result_null(sqlite3_context*); + void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); + void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64, + void(*)(void*), unsigned char encoding); + void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); + void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); + void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); + void sqlite3_result_value(sqlite3_context*, sqlite3_value*); + void sqlite3_result_pointer(sqlite3_context*, void*,const char*,void(*)(void*)); + void sqlite3_result_zeroblob(sqlite3_context*, int n); + int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); +# 5477 "./sqlite3.h" + void sqlite3_result_subtype(sqlite3_context*,unsigned int); +# 5559 "./sqlite3.h" + int sqlite3_create_collation( + sqlite3*, + const char *zName, + int eTextRep, + void *pArg, + int(*xCompare)(void*,int,const void*,int,const void*) +); + int sqlite3_create_collation_v2( + sqlite3*, + const char *zName, + int eTextRep, + void *pArg, + int(*xCompare)(void*,int,const void*,int,const void*), + void(*xDestroy)(void*) +); + int sqlite3_create_collation16( + sqlite3*, + const void *zName, + int eTextRep, + void *pArg, + int(*xCompare)(void*,int,const void*,int,const void*) +); +# 5609 "./sqlite3.h" + int sqlite3_collation_needed( + sqlite3*, + void*, + void(*)(void*,sqlite3*,int eTextRep,const char*) +); + int sqlite3_collation_needed16( + sqlite3*, + void*, + void(*)(void*,sqlite3*,int eTextRep,const void*) +); +# 5692 "./sqlite3.h" + int sqlite3_sleep(int); +# 5750 "./sqlite3.h" + extern char *sqlite3_temp_directory; +# 5787 "./sqlite3.h" + extern char *sqlite3_data_directory; +# 5808 "./sqlite3.h" + int sqlite3_win32_set_directory( + unsigned long type, + void *zValue +); + int sqlite3_win32_set_directory8(unsigned long type, const char *zValue); + int sqlite3_win32_set_directory16(unsigned long type, const void *zValue); +# 5846 "./sqlite3.h" + int sqlite3_get_autocommit(sqlite3*); +# 5859 "./sqlite3.h" + sqlite3 *sqlite3_db_handle(sqlite3_stmt*); +# 5876 "./sqlite3.h" + const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); +# 5886 "./sqlite3.h" + int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); +# 5902 "./sqlite3.h" + sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt); +# 5951 "./sqlite3.h" + void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*); + void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); +# 6003 "./sqlite3.h" + void *sqlite3_update_hook( + sqlite3*, + void(*)(void *,int ,char const *,char const *,sqlite3_int64), + void* +); +# 6044 "./sqlite3.h" + int sqlite3_enable_shared_cache(int); +# 6060 "./sqlite3.h" + int sqlite3_release_memory(int); +# 6074 "./sqlite3.h" + int sqlite3_db_release_memory(sqlite3*); +# 6127 "./sqlite3.h" + sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N); +# 6138 "./sqlite3.h" + void sqlite3_soft_heap_limit(int N); +# 6210 "./sqlite3.h" + int sqlite3_table_column_metadata( + sqlite3 *db, + const char *zDbName, + const char *zTableName, + const char *zColumnName, + char const **pzDataType, + char const **pzCollSeq, + int *pNotNull, + int *pPrimaryKey, + int *pAutoinc +); +# 6266 "./sqlite3.h" + int sqlite3_load_extension( + sqlite3 *db, + const char *zFile, + const char *zProc, + char **pzErrMsg +); +# 6298 "./sqlite3.h" + int sqlite3_enable_load_extension(sqlite3 *db, int onoff); +# 6336 "./sqlite3.h" + int sqlite3_auto_extension(void(*xEntryPoint)(void)); +# 6348 "./sqlite3.h" + int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void)); + + + + + + + + void sqlite3_reset_auto_extension(void); +# 6370 "./sqlite3.h" +typedef struct sqlite3_vtab sqlite3_vtab; +typedef struct sqlite3_index_info sqlite3_index_info; +typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor; +typedef struct sqlite3_module sqlite3_module; +# 6391 "./sqlite3.h" +struct sqlite3_module { + int iVersion; + int (*xCreate)(sqlite3*, void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVTab, char**); + int (*xConnect)(sqlite3*, void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVTab, char**); + int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*); + int (*xDisconnect)(sqlite3_vtab *pVTab); + int (*xDestroy)(sqlite3_vtab *pVTab); + int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor); + int (*xClose)(sqlite3_vtab_cursor*); + int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, + int argc, sqlite3_value **argv); + int (*xNext)(sqlite3_vtab_cursor*); + int (*xEof)(sqlite3_vtab_cursor*); + int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int); + int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid); + int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *); + int (*xBegin)(sqlite3_vtab *pVTab); + int (*xSync)(sqlite3_vtab *pVTab); + int (*xCommit)(sqlite3_vtab *pVTab); + int (*xRollback)(sqlite3_vtab *pVTab); + int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, + void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), + void **ppArg); + int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); + + + int (*xSavepoint)(sqlite3_vtab *pVTab, int); + int (*xRelease)(sqlite3_vtab *pVTab, int); + int (*xRollbackTo)(sqlite3_vtab *pVTab, int); + + + int (*xShadowName)(const char*); +}; +# 6525 "./sqlite3.h" +struct sqlite3_index_info { + + int nConstraint; + struct sqlite3_index_constraint { + int iColumn; + unsigned char op; + unsigned char usable; + int iTermOffset; + } *aConstraint; + int nOrderBy; + struct sqlite3_index_orderby { + int iColumn; + unsigned char desc; + } *aOrderBy; + + struct sqlite3_index_constraint_usage { + int argvIndex; + unsigned char omit; + } *aConstraintUsage; + int idxNum; + char *idxStr; + int needToFreeIdxStr; + int orderByConsumed; + double estimatedCost; + + sqlite3_int64 estimatedRows; + + int idxFlags; + + sqlite3_uint64 colUsed; +}; +# 6616 "./sqlite3.h" + int sqlite3_create_module( + sqlite3 *db, + const char *zName, + const sqlite3_module *p, + void *pClientData +); + int sqlite3_create_module_v2( + sqlite3 *db, + const char *zName, + const sqlite3_module *p, + void *pClientData, + void(*xDestroy)(void*) +); +# 6648 "./sqlite3.h" +struct sqlite3_vtab { + const sqlite3_module *pModule; + int nRef; + char *zErrMsg; + +}; +# 6672 "./sqlite3.h" +struct sqlite3_vtab_cursor { + sqlite3_vtab *pVtab; + +}; +# 6685 "./sqlite3.h" + int sqlite3_declare_vtab(sqlite3*, const char *zSQL); +# 6704 "./sqlite3.h" + int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg); +# 6728 "./sqlite3.h" +typedef struct sqlite3_blob sqlite3_blob; +# 6813 "./sqlite3.h" + int sqlite3_blob_open( + sqlite3*, + const char *zDb, + const char *zTable, + const char *zColumn, + sqlite3_int64 iRow, + int flags, + sqlite3_blob **ppBlob +); +# 6846 "./sqlite3.h" + int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); +# 6869 "./sqlite3.h" + int sqlite3_blob_close(sqlite3_blob *); +# 6885 "./sqlite3.h" + int sqlite3_blob_bytes(sqlite3_blob *); +# 6914 "./sqlite3.h" + int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset); +# 6956 "./sqlite3.h" + int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset); +# 6987 "./sqlite3.h" + sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName); + int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt); + int sqlite3_vfs_unregister(sqlite3_vfs*); +# 7105 "./sqlite3.h" + sqlite3_mutex *sqlite3_mutex_alloc(int); + void sqlite3_mutex_free(sqlite3_mutex*); + void sqlite3_mutex_enter(sqlite3_mutex*); + int sqlite3_mutex_try(sqlite3_mutex*); + void sqlite3_mutex_leave(sqlite3_mutex*); +# 7176 "./sqlite3.h" +typedef struct sqlite3_mutex_methods sqlite3_mutex_methods; +struct sqlite3_mutex_methods { + int (*xMutexInit)(void); + int (*xMutexEnd)(void); + sqlite3_mutex *(*xMutexAlloc)(int); + void (*xMutexFree)(sqlite3_mutex *); + void (*xMutexEnter)(sqlite3_mutex *); + int (*xMutexTry)(sqlite3_mutex *); + void (*xMutexLeave)(sqlite3_mutex *); + int (*xMutexHeld)(sqlite3_mutex *); + int (*xMutexNotheld)(sqlite3_mutex *); +}; +# 7219 "./sqlite3.h" + int sqlite3_mutex_held(sqlite3_mutex*); + int sqlite3_mutex_notheld(sqlite3_mutex*); +# 7260 "./sqlite3.h" + sqlite3_mutex *sqlite3_db_mutex(sqlite3*); +# 7303 "./sqlite3.h" + int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*); +# 7322 "./sqlite3.h" + int sqlite3_test_control(int op, ...); +# 7410 "./sqlite3.h" + int sqlite3_keyword_count(void); + int sqlite3_keyword_name(int,const char**,int*); + int sqlite3_keyword_check(const char*,int); +# 7430 "./sqlite3.h" +typedef struct sqlite3_str sqlite3_str; +# 7457 "./sqlite3.h" + sqlite3_str *sqlite3_str_new(sqlite3*); +# 7472 "./sqlite3.h" + char *sqlite3_str_finish(sqlite3_str*); +# 7506 "./sqlite3.h" + void sqlite3_str_appendf(sqlite3_str*, const char *zFormat, ...); + void sqlite3_str_vappendf(sqlite3_str*, const char *zFormat, va_list); + void sqlite3_str_append(sqlite3_str*, const char *zIn, int N); + void sqlite3_str_appendall(sqlite3_str*, const char *zIn); + void sqlite3_str_appendchar(sqlite3_str*, int N, char C); + void sqlite3_str_reset(sqlite3_str*); +# 7542 "./sqlite3.h" + int sqlite3_str_errcode(sqlite3_str*); + int sqlite3_str_length(sqlite3_str*); + char *sqlite3_str_value(sqlite3_str*); +# 7572 "./sqlite3.h" + int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); + int sqlite3_status64( + int op, + sqlite3_int64 *pCurrent, + sqlite3_int64 *pHighwater, + int resetFlag +); +# 7682 "./sqlite3.h" + int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); +# 7835 "./sqlite3.h" + int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); +# 7911 "./sqlite3.h" +typedef struct sqlite3_pcache sqlite3_pcache; +# 7923 "./sqlite3.h" +typedef struct sqlite3_pcache_page sqlite3_pcache_page; +struct sqlite3_pcache_page { + void *pBuf; + void *pExtra; +}; +# 8088 "./sqlite3.h" +typedef struct sqlite3_pcache_methods2 sqlite3_pcache_methods2; +struct sqlite3_pcache_methods2 { + int iVersion; + void *pArg; + int (*xInit)(void*); + void (*xShutdown)(void*); + sqlite3_pcache *(*xCreate)(int szPage, int szExtra, int bPurgeable); + void (*xCachesize)(sqlite3_pcache*, int nCachesize); + int (*xPagecount)(sqlite3_pcache*); + sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); + void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard); + void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*, + unsigned oldKey, unsigned newKey); + void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); + void (*xDestroy)(sqlite3_pcache*); + void (*xShrink)(sqlite3_pcache*); +}; + + + + + + +typedef struct sqlite3_pcache_methods sqlite3_pcache_methods; +struct sqlite3_pcache_methods { + void *pArg; + int (*xInit)(void*); + void (*xShutdown)(void*); + sqlite3_pcache *(*xCreate)(int szPage, int bPurgeable); + void (*xCachesize)(sqlite3_pcache*, int nCachesize); + int (*xPagecount)(sqlite3_pcache*); + void *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); + void (*xUnpin)(sqlite3_pcache*, void*, int discard); + void (*xRekey)(sqlite3_pcache*, void*, unsigned oldKey, unsigned newKey); + void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); + void (*xDestroy)(sqlite3_pcache*); +}; +# 8137 "./sqlite3.h" +typedef struct sqlite3_backup sqlite3_backup; +# 8325 "./sqlite3.h" + sqlite3_backup *sqlite3_backup_init( + sqlite3 *pDest, + const char *zDestName, + sqlite3 *pSource, + const char *zSourceName +); + int sqlite3_backup_step(sqlite3_backup *p, int nPage); + int sqlite3_backup_finish(sqlite3_backup *p); + int sqlite3_backup_remaining(sqlite3_backup *p); + int sqlite3_backup_pagecount(sqlite3_backup *p); +# 8451 "./sqlite3.h" + int sqlite3_unlock_notify( + sqlite3 *pBlocked, + void (*xNotify)(void **apArg, int nArg), + void *pNotifyArg +); +# 8466 "./sqlite3.h" + int sqlite3_stricmp(const char *, const char *); + int sqlite3_strnicmp(const char *, const char *, int); +# 8484 "./sqlite3.h" + int sqlite3_strglob(const char *zGlob, const char *zStr); +# 8507 "./sqlite3.h" + int sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc); +# 8530 "./sqlite3.h" + void sqlite3_log(int iErrCode, const char *zFormat, ...); +# 8566 "./sqlite3.h" + void *sqlite3_wal_hook( + sqlite3*, + int(*)(void *,sqlite3*,const char*,int), + void* +); +# 8601 "./sqlite3.h" + int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); +# 8623 "./sqlite3.h" + int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); +# 8717 "./sqlite3.h" + int sqlite3_wal_checkpoint_v2( + sqlite3 *db, + const char *zDb, + int eMode, + int *pnLog, + int *pnCkpt +); +# 8753 "./sqlite3.h" + int sqlite3_vtab_config(sqlite3*, int op, ...); +# 8807 "./sqlite3.h" + int sqlite3_vtab_on_conflict(sqlite3 *); +# 8826 "./sqlite3.h" + int sqlite3_vtab_nochange(sqlite3_context*); +# 8841 "./sqlite3.h" + const char *sqlite3_vtab_collation(sqlite3_index_info*,int); +# 8946 "./sqlite3.h" + int sqlite3_stmt_scanstatus( + sqlite3_stmt *pStmt, + int idx, + int iScanStatusOp, + void *pOut +); +# 8962 "./sqlite3.h" + void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); +# 8994 "./sqlite3.h" + int sqlite3_db_cacheflush(sqlite3*); +# 9108 "./sqlite3.h" + int sqlite3_system_errno(sqlite3*); +# 9130 "./sqlite3.h" +typedef struct sqlite3_snapshot { + unsigned char hidden[48]; +} sqlite3_snapshot; +# 9177 "./sqlite3.h" + int sqlite3_snapshot_get( + sqlite3 *db, + const char *zSchema, + sqlite3_snapshot **ppSnapshot +); +# 9226 "./sqlite3.h" + int sqlite3_snapshot_open( + sqlite3 *db, + const char *zSchema, + sqlite3_snapshot *pSnapshot +); +# 9243 "./sqlite3.h" + void sqlite3_snapshot_free(sqlite3_snapshot*); +# 9270 "./sqlite3.h" + int sqlite3_snapshot_cmp( + sqlite3_snapshot *p1, + sqlite3_snapshot *p2 +); +# 9298 "./sqlite3.h" + int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); +# 9336 "./sqlite3.h" + unsigned char *sqlite3_serialize( + sqlite3 *db, + const char *zSchema, + sqlite3_int64 *piSize, + unsigned int mFlags +); +# 9388 "./sqlite3.h" + int sqlite3_deserialize( + sqlite3 *db, + const char *zSchema, + unsigned char *pData, + sqlite3_int64 szDb, + sqlite3_int64 szBuf, + unsigned mFlags +); +# 9457 "./sqlite3.h" +typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry; +typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info; + + + + + + + + typedef double sqlite3_rtree_dbl; +# 9475 "./sqlite3.h" + int sqlite3_rtree_geometry_callback( + sqlite3 *db, + const char *zGeom, + int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*), + void *pContext +); + + + + + + +struct sqlite3_rtree_geometry { + void *pContext; + int nParam; + sqlite3_rtree_dbl *aParam; + void *pUser; + void (*xDelUser)(void *); +}; + + + + + + + + int sqlite3_rtree_query_callback( + sqlite3 *db, + const char *zQueryFunc, + int (*xQueryFunc)(sqlite3_rtree_query_info*), + void *pContext, + void (*xDestructor)(void*) +); +# 9519 "./sqlite3.h" +struct sqlite3_rtree_query_info { + void *pContext; + int nParam; + sqlite3_rtree_dbl *aParam; + void *pUser; + void (*xDelUser)(void*); + sqlite3_rtree_dbl *aCoord; + unsigned int *anQueue; + int nCoord; + int iLevel; + int mxLevel; + sqlite3_int64 iRowid; + sqlite3_rtree_dbl rParentScore; + int eParentWithin; + int eWithin; + sqlite3_rtree_dbl rScore; + + sqlite3_value **apSqlParam; +}; +# 11252 "./sqlite3.h" +typedef struct Fts5ExtensionApi Fts5ExtensionApi; +typedef struct Fts5Context Fts5Context; +typedef struct Fts5PhraseIter Fts5PhraseIter; + +typedef void (*fts5_extension_function)( + const Fts5ExtensionApi *pApi, + Fts5Context *pFts, + sqlite3_context *pCtx, + int nVal, + sqlite3_value **apVal +); + +struct Fts5PhraseIter { + const unsigned char *a; + const unsigned char *b; +}; +# 11480 "./sqlite3.h" +struct Fts5ExtensionApi { + int iVersion; + + void *(*xUserData)(Fts5Context*); + + int (*xColumnCount)(Fts5Context*); + int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); + int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken); + + int (*xTokenize)(Fts5Context*, + const char *pText, int nText, + void *pCtx, + int (*xToken)(void*, int, const char*, int, int, int) + ); + + int (*xPhraseCount)(Fts5Context*); + int (*xPhraseSize)(Fts5Context*, int iPhrase); + + int (*xInstCount)(Fts5Context*, int *pnInst); + int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff); + + sqlite3_int64 (*xRowid)(Fts5Context*); + int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn); + int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken); + + int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData, + int(*)(const Fts5ExtensionApi*,Fts5Context*,void*) + ); + int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*)); + void *(*xGetAuxdata)(Fts5Context*, int bClear); + + int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); + void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); + + int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); + void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); +}; +# 11714 "./sqlite3.h" +typedef struct Fts5Tokenizer Fts5Tokenizer; +typedef struct fts5_tokenizer fts5_tokenizer; +struct fts5_tokenizer { + int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); + void (*xDelete)(Fts5Tokenizer*); + int (*xTokenize)(Fts5Tokenizer*, + void *pCtx, + int flags, + const char *pText, int nText, + int (*xToken)( + void *pCtx, + int tflags, + const char *pToken, + int nToken, + int iStart, + int iEnd + ) + ); +}; +# 11751 "./sqlite3.h" +typedef struct fts5_api fts5_api; +struct fts5_api { + int iVersion; + + + int (*xCreateTokenizer)( + fts5_api *pApi, + const char *zName, + void *pContext, + fts5_tokenizer *pTokenizer, + void (*xDestroy)(void*) + ); + + + int (*xFindTokenizer)( + fts5_api *pApi, + const char *zName, + void **ppContext, + fts5_tokenizer *pTokenizer + ); + + + int (*xCreateFunction)( + fts5_api *pApi, + const char *zName, + void *pContext, + fts5_extension_function xFunction, + void (*xDestroy)(void*) + ); +}; +# 168 "src/sqliteInt.h" 2 +# 178 "src/sqliteInt.h" +# 1 "src/sqliteLimit.h" 1 +# 179 "src/sqliteInt.h" 2 +# 529 "src/sqliteInt.h" +# 1 "src/hash.h" 1 +# 19 "src/hash.h" +typedef struct Hash Hash; +typedef struct HashElem HashElem; +# 43 "src/hash.h" +struct Hash { + unsigned int htsize; + unsigned int count; + HashElem *first; + struct _ht { + unsigned int count; + HashElem *chain; + } *ht; +}; + + + + + + + +struct HashElem { + HashElem *next, *prev; + void *data; + const char *pKey; +}; + + + + +void sqlite3HashInit(Hash*); +void *sqlite3HashInsert(Hash*, const char *pKey, void *pData); +void *sqlite3HashFind(const Hash*, const char *pKey); +void sqlite3HashClear(Hash*); +# 530 "src/sqliteInt.h" 2 +# 1 "./parse.h" 1 +# 531 "src/sqliteInt.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 2 +# 532 "src/sqliteInt.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdlib.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdlib.h" 2 +# 533 "src/sqliteInt.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/string.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/string.h" 2 +# 534 "src/sqliteInt.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/assert.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/assert.h" 2 +# 535 "src/sqliteInt.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stddef.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stddef.h" 2 +# 536 "src/sqliteInt.h" 2 +# 734 "src/sqliteInt.h" +typedef sqlite_int64 i64; +typedef sqlite_uint64 u64; +typedef unsigned int u32; +typedef unsigned short int u16; +typedef short int i16; +typedef unsigned char u8; +typedef signed char i8; +# 759 "src/sqliteInt.h" + typedef u32 tRowcnt; +# 785 "src/sqliteInt.h" +typedef short int LogEst; +# 809 "src/sqliteInt.h" + typedef u64 uptr; +# 971 "src/sqliteInt.h" +typedef struct BusyHandler BusyHandler; +struct BusyHandler { + int (*xBusyHandler)(void *,int); + void *pBusyArg; + int nBusy; + u8 bExtraFileArg; +}; +# 1066 "src/sqliteInt.h" +typedef struct AggInfo AggInfo; +typedef struct AuthContext AuthContext; +typedef struct AutoincInfo AutoincInfo; +typedef struct Bitvec Bitvec; +typedef struct CollSeq CollSeq; +typedef struct Column Column; +typedef struct Db Db; +typedef struct Schema Schema; +typedef struct Expr Expr; +typedef struct ExprList ExprList; +typedef struct FKey FKey; +typedef struct FuncDestructor FuncDestructor; +typedef struct FuncDef FuncDef; +typedef struct FuncDefHash FuncDefHash; +typedef struct IdList IdList; +typedef struct Index Index; +typedef struct IndexSample IndexSample; +typedef struct KeyClass KeyClass; +typedef struct KeyInfo KeyInfo; +typedef struct Lookaside Lookaside; +typedef struct LookasideSlot LookasideSlot; +typedef struct Module Module; +typedef struct NameContext NameContext; +typedef struct Parse Parse; +typedef struct PreUpdate PreUpdate; +typedef struct PrintfArguments PrintfArguments; +typedef struct RenameToken RenameToken; +typedef struct RowSet RowSet; +typedef struct Savepoint Savepoint; +typedef struct Select Select; +typedef struct SQLiteThread SQLiteThread; +typedef struct SelectDest SelectDest; +typedef struct SrcList SrcList; +typedef struct sqlite3_str StrAccum; +typedef struct Table Table; +typedef struct TableLock TableLock; +typedef struct Token Token; +typedef struct TreeView TreeView; +typedef struct Trigger Trigger; +typedef struct TriggerPrg TriggerPrg; +typedef struct TriggerStep TriggerStep; +typedef struct UnpackedRecord UnpackedRecord; +typedef struct Upsert Upsert; +typedef struct VTable VTable; +typedef struct VtabCtx VtabCtx; +typedef struct Walker Walker; +typedef struct WhereInfo WhereInfo; +typedef struct Window Window; +typedef struct With With; +# 1127 "src/sqliteInt.h" + typedef u64 Bitmask; +# 1148 "src/sqliteInt.h" +typedef int VList; + + + + + + +# 1 "src/btree.h" 1 +# 39 "src/btree.h" +typedef struct Btree Btree; +typedef struct BtCursor BtCursor; +typedef struct BtShared BtShared; +typedef struct BtreePayload BtreePayload; + + +int sqlite3BtreeOpen( + sqlite3_vfs *pVfs, + const char *zFilename, + sqlite3 *db, + Btree **ppBtree, + int flags, + int vfsFlags +); +# 65 "src/btree.h" +int sqlite3BtreeClose(Btree*); +int sqlite3BtreeSetCacheSize(Btree*,int); +int sqlite3BtreeSetSpillSize(Btree*,int); + + int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64); + +int sqlite3BtreeSetPagerFlags(Btree*,unsigned); +int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix); +int sqlite3BtreeGetPageSize(Btree*); +int sqlite3BtreeMaxPageCount(Btree*,int); +u32 sqlite3BtreeLastPage(Btree*); +int sqlite3BtreeSecureDelete(Btree*,int); +int sqlite3BtreeGetOptimalReserve(Btree*); +int sqlite3BtreeGetReserveNoMutex(Btree *p); +int sqlite3BtreeSetAutoVacuum(Btree *, int); +int sqlite3BtreeGetAutoVacuum(Btree *); +int sqlite3BtreeBeginTrans(Btree*,int,int*); +int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster); +int sqlite3BtreeCommitPhaseTwo(Btree*, int); +int sqlite3BtreeCommit(Btree*); +int sqlite3BtreeRollback(Btree*,int,int); +int sqlite3BtreeBeginStmt(Btree*,int); +int sqlite3BtreeCreateTable(Btree*, int*, int flags); +int sqlite3BtreeIsInTrans(Btree*); +int sqlite3BtreeIsInReadTrans(Btree*); +int sqlite3BtreeIsInBackup(Btree*); +void *sqlite3BtreeSchema(Btree *, int, void(*)(void *)); +int sqlite3BtreeSchemaLocked(Btree *pBtree); + +int sqlite3BtreeLockTable(Btree *pBtree, int iTab, u8 isWriteLock); + +int sqlite3BtreeSavepoint(Btree *, int, int); + +const char *sqlite3BtreeGetFilename(Btree *); +const char *sqlite3BtreeGetJournalname(Btree *); +int sqlite3BtreeCopyFile(Btree *, Btree *); + +int sqlite3BtreeIncrVacuum(Btree *); +# 117 "src/btree.h" +int sqlite3BtreeDropTable(Btree*, int, int*); +int sqlite3BtreeClearTable(Btree*, int, int*); +int sqlite3BtreeClearTableOfCursor(BtCursor*); +int sqlite3BtreeTripAllCursors(Btree*, int, int); + +void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue); +int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); + +int sqlite3BtreeNewDb(Btree *p); +# 226 "src/btree.h" +int sqlite3BtreeCursor( + Btree*, + int iTable, + int wrFlag, + struct KeyInfo*, + BtCursor *pCursor +); +BtCursor *sqlite3BtreeFakeValidCursor(void); +int sqlite3BtreeCursorSize(void); +void sqlite3BtreeCursorZero(BtCursor*); +void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned); + + + + +int sqlite3BtreeCloseCursor(BtCursor*); +int sqlite3BtreeMovetoUnpacked( + BtCursor*, + UnpackedRecord *pUnKey, + i64 intKey, + int bias, + int *pRes +); +int sqlite3BtreeCursorHasMoved(BtCursor*); +int sqlite3BtreeCursorRestore(BtCursor*, int*); +int sqlite3BtreeDelete(BtCursor*, u8 flags); +# 291 "src/btree.h" +struct BtreePayload { + const void *pKey; + sqlite3_int64 nKey; + const void *pData; + sqlite3_value *aMem; + u16 nMem; + int nData; + int nZero; +}; + +int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload, + int flags, int seekResult); +int sqlite3BtreeFirst(BtCursor*, int *pRes); +int sqlite3BtreeLast(BtCursor*, int *pRes); +int sqlite3BtreeNext(BtCursor*, int flags); +int sqlite3BtreeEof(BtCursor*); +int sqlite3BtreePrevious(BtCursor*, int flags); +i64 sqlite3BtreeIntegerKey(BtCursor*); + + + +int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*); +const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt); +u32 sqlite3BtreePayloadSize(BtCursor*); +sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*); + +char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*); +struct Pager *sqlite3BtreePager(Btree*); +i64 sqlite3BtreeRowCountEst(BtCursor*); + + +int sqlite3BtreePayloadChecked(BtCursor*, u32 offset, u32 amt, void*); +int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*); +void sqlite3BtreeIncrblobCursor(BtCursor *); + +void sqlite3BtreeClearCursor(BtCursor *); +int sqlite3BtreeSetVersion(Btree *pBt, int iVersion); +int sqlite3BtreeCursorHasHint(BtCursor*, unsigned int mask); +int sqlite3BtreeIsReadonly(Btree *pBt); +int sqlite3HeaderSizeBtree(void); + + + + +int sqlite3BtreeCursorIsValidNN(BtCursor*); + + +int sqlite3BtreeCount(BtCursor *, i64 *); +# 347 "src/btree.h" + int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); +# 356 "src/btree.h" + void sqlite3BtreeEnter(Btree*); + void sqlite3BtreeEnterAll(sqlite3*); + int sqlite3BtreeSharable(Btree*); + void sqlite3BtreeEnterCursor(BtCursor*); + int sqlite3BtreeConnectionCount(Btree*); +# 370 "src/btree.h" + void sqlite3BtreeLeave(Btree*); + void sqlite3BtreeLeaveCursor(BtCursor*); + void sqlite3BtreeLeaveAll(sqlite3*); +# 1156 "src/sqliteInt.h" 2 +# 1 "src/vdbe.h" 1 +# 20 "src/vdbe.h" +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 2 +# 21 "src/vdbe.h" 2 + + + + + + +typedef struct Vdbe Vdbe; + + + + + +typedef struct sqlite3_value Mem; +typedef struct SubProgram SubProgram; + + + + + + +struct VdbeOp { + u8 opcode; + signed char p4type; + u16 p5; + int p1; + int p2; + int p3; + union p4union { + int i; + void *p; + char *z; + i64 *pI64; + double *pReal; + FuncDef *pFunc; + sqlite3_context *pCtx; + CollSeq *pColl; + Mem *pMem; + VTable *pVtab; + KeyInfo *pKeyInfo; + int *ai; + SubProgram *pProgram; + Table *pTab; + + + + int (*xAdvance)(BtCursor *, int); + } p4; +# 79 "src/vdbe.h" +}; +typedef struct VdbeOp VdbeOp; + + + + + +struct SubProgram { + VdbeOp *aOp; + int nOp; + int nMem; + int nCsr; + u8 *aOnce; + void *token; + SubProgram *pNext; +}; + + + + + +struct VdbeOpList { + u8 opcode; + signed char p1; + signed char p2; + signed char p3; +}; +typedef struct VdbeOpList VdbeOpList; +# 169 "src/vdbe.h" +# 1 "./opcodes.h" 1 +# 170 "src/vdbe.h" 2 +# 181 "src/vdbe.h" +Vdbe *sqlite3VdbeCreate(Parse*); +int sqlite3VdbeAddOp0(Vdbe*,int); +int sqlite3VdbeAddOp1(Vdbe*,int,int); +int sqlite3VdbeAddOp2(Vdbe*,int,int,int); +int sqlite3VdbeGoto(Vdbe*,int); +int sqlite3VdbeLoadString(Vdbe*,int,const char*); +void sqlite3VdbeMultiLoad(Vdbe*,int,const char*,...); +int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int); +int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int); +int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int); +int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int); +void sqlite3VdbeEndCoroutine(Vdbe*,int); +# 205 "src/vdbe.h" +VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno); + + void sqlite3VdbeExplain(Parse*,u8,const char*,...); + void sqlite3VdbeExplainPop(Parse*); + int sqlite3VdbeExplainParent(Parse*); +# 224 "src/vdbe.h" +void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*); +void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8); +void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1); +void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2); +void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3); +void sqlite3VdbeChangeP5(Vdbe*, u16 P5); +void sqlite3VdbeJumpHere(Vdbe*, int addr); +int sqlite3VdbeChangeToNoop(Vdbe*, int addr); +int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op); +void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); +void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type); +void sqlite3VdbeSetP4KeyInfo(Parse*, Index*); +void sqlite3VdbeUsesBtree(Vdbe*, int); +VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); +int sqlite3VdbeMakeLabel(Parse*); +void sqlite3VdbeRunOnlyOnce(Vdbe*); +void sqlite3VdbeReusable(Vdbe*); +void sqlite3VdbeDelete(Vdbe*); +void sqlite3VdbeClearObject(sqlite3*,Vdbe*); +void sqlite3VdbeMakeReady(Vdbe*,Parse*); +int sqlite3VdbeFinalize(Vdbe*); +void sqlite3VdbeResolveLabel(Vdbe*, int); +int sqlite3VdbeCurrentAddr(Vdbe*); + + + +void sqlite3VdbeResetStepResult(Vdbe*); +void sqlite3VdbeRewind(Vdbe*); +int sqlite3VdbeReset(Vdbe*); +void sqlite3VdbeSetNumCols(Vdbe*,int); +int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*)); +void sqlite3VdbeCountChanges(Vdbe*); +sqlite3 *sqlite3VdbeDb(Vdbe*); +u8 sqlite3VdbePrepareFlags(Vdbe*); +void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, u8); + + + + +void sqlite3VdbeSwap(Vdbe*,Vdbe*); +VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*); +sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8); +void sqlite3VdbeSetVarmask(Vdbe*, int); + + char *sqlite3VdbeExpandSql(Vdbe*, const char*); + +int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); +int sqlite3BlobCompare(const Mem*, const Mem*); + +void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); +int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); +int sqlite3VdbeRecordCompareWithSkip(int, const void *, UnpackedRecord *, int); +UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo*); + +typedef int (*RecordCompare)(int,const void*,UnpackedRecord*); +RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); + + +void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); + + +int sqlite3NotPureFunc(sqlite3_context*); +# 1157 "src/sqliteInt.h" 2 +# 1 "src/pager.h" 1 +# 33 "src/pager.h" +typedef u32 Pgno; + + + + +typedef struct Pager Pager; + + + + +typedef struct PgHdr DbPage; +# 116 "src/pager.h" +int sqlite3PagerOpen( + sqlite3_vfs*, + Pager **ppPager, + const char*, + int, + int, + int, + void(*)(DbPage*) +); +int sqlite3PagerClose(Pager *pPager, sqlite3*); +int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); + + +void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *); +int sqlite3PagerSetPagesize(Pager*, u32*, int); + + + +int sqlite3PagerMaxPageCount(Pager*, int); +void sqlite3PagerSetCachesize(Pager*, int); +int sqlite3PagerSetSpillsize(Pager*, int); +void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64); +void sqlite3PagerShrink(Pager*); +void sqlite3PagerSetFlags(Pager*,unsigned); +int sqlite3PagerLockingMode(Pager *, int); +int sqlite3PagerSetJournalMode(Pager *, int); +int sqlite3PagerGetJournalMode(Pager*); +int sqlite3PagerOkToChangeJournalMode(Pager*); +i64 sqlite3PagerJournalSizeLimit(Pager *, i64); +sqlite3_backup **sqlite3PagerBackupPtr(Pager*); +int sqlite3PagerFlush(Pager*); + + +int sqlite3PagerGet(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag); +DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno); +void sqlite3PagerRef(DbPage*); +void sqlite3PagerUnref(DbPage*); +void sqlite3PagerUnrefNotNull(DbPage*); +void sqlite3PagerUnrefPageOne(DbPage*); + + +int sqlite3PagerWrite(DbPage*); +void sqlite3PagerDontWrite(DbPage*); +int sqlite3PagerMovepage(Pager*,DbPage*,Pgno,int); +int sqlite3PagerPageRefcount(DbPage*); +void *sqlite3PagerGetData(DbPage *); +void *sqlite3PagerGetExtra(DbPage *); + + +void sqlite3PagerPagecount(Pager*, int*); +int sqlite3PagerBegin(Pager*, int exFlag, int); +int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, int); +int sqlite3PagerExclusiveLock(Pager*); +int sqlite3PagerSync(Pager *pPager, const char *zMaster); +int sqlite3PagerCommitPhaseTwo(Pager*); +int sqlite3PagerRollback(Pager*); +int sqlite3PagerOpenSavepoint(Pager *pPager, int n); +int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint); +int sqlite3PagerSharedLock(Pager *pPager); + + + int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*); + int sqlite3PagerWalSupported(Pager *pPager); + int sqlite3PagerWalCallback(Pager *pPager); + int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen); + int sqlite3PagerCloseWal(Pager *pPager, sqlite3*); +# 200 "src/pager.h" +u8 sqlite3PagerIsreadonly(Pager*); +u32 sqlite3PagerDataVersion(Pager*); + + + +int sqlite3PagerMemUsed(Pager*); +const char *sqlite3PagerFilename(Pager*, int); +sqlite3_vfs *sqlite3PagerVfs(Pager*); +sqlite3_file *sqlite3PagerFile(Pager*); +sqlite3_file *sqlite3PagerJrnlFile(Pager*); +const char *sqlite3PagerJournalname(Pager*); +void *sqlite3PagerTempSpace(Pager*); +int sqlite3PagerIsMemdb(Pager*); +void sqlite3PagerCacheStat(Pager *, int, int, int *); +void sqlite3PagerClearCache(Pager*); +int sqlite3SectorSize(sqlite3_file *); + + + + + + + +void sqlite3PagerTruncateImage(Pager*,Pgno); + +void sqlite3PagerRekey(DbPage*, Pgno, u16); +# 1158 "src/sqliteInt.h" 2 +# 1 "src/pcache.h" 1 +# 18 "src/pcache.h" +typedef struct PgHdr PgHdr; +typedef struct PCache PCache; + + + + + +struct PgHdr { + sqlite3_pcache_page *pPage; + void *pData; + void *pExtra; + PCache *pCache; + PgHdr *pDirty; + Pager *pPager; + Pgno pgno; + + + + u16 flags; + + + + + + + i16 nRef; + PgHdr *pDirtyNext; + PgHdr *pDirtyPrev; + + +}; +# 62 "src/pcache.h" +int sqlite3PcacheInitialize(void); +void sqlite3PcacheShutdown(void); + + + + +void sqlite3PCacheBufferSetup(void *, int sz, int n); + + + + + +int sqlite3PcacheOpen( + int szPage, + int szExtra, + int bPurgeable, + int (*xStress)(void*, PgHdr*), + void *pStress, + PCache *pToInit +); + + +int sqlite3PcacheSetPageSize(PCache *, int); + + + + +int sqlite3PcacheSize(void); + + + + +sqlite3_pcache_page *sqlite3PcacheFetch(PCache*, Pgno, int createFlag); +int sqlite3PcacheFetchStress(PCache*, Pgno, sqlite3_pcache_page**); +PgHdr *sqlite3PcacheFetchFinish(PCache*, Pgno, sqlite3_pcache_page *pPage); +void sqlite3PcacheRelease(PgHdr*); + +void sqlite3PcacheDrop(PgHdr*); +void sqlite3PcacheMakeDirty(PgHdr*); +void sqlite3PcacheMakeClean(PgHdr*); +void sqlite3PcacheCleanAll(PCache*); +void sqlite3PcacheClearWritable(PCache*); + + +void sqlite3PcacheMove(PgHdr*, Pgno); + + +void sqlite3PcacheTruncate(PCache*, Pgno x); + + +PgHdr *sqlite3PcacheDirtyList(PCache*); + + +void sqlite3PcacheClose(PCache*); + + +void sqlite3PcacheClearSyncFlags(PCache *); + + +void sqlite3PcacheClear(PCache*); + + +int sqlite3PcacheRefCount(PCache*); + + +void sqlite3PcacheRef(PgHdr*); + +int sqlite3PcachePageRefcount(PgHdr*); + + +int sqlite3PcachePagecount(PCache*); +# 153 "src/pcache.h" +void sqlite3PcacheSetCachesize(PCache *, int); +# 163 "src/pcache.h" +int sqlite3PcacheSetSpillsize(PCache *, int); + + +void sqlite3PcacheShrink(PCache*); +# 177 "src/pcache.h" +void sqlite3PCacheSetDefault(void); + + +int sqlite3HeaderSizePcache(void); +int sqlite3HeaderSizePcache1(void); + + +int sqlite3PCachePercentDirty(PCache*); +# 1159 "src/sqliteInt.h" 2 +# 1 "src/os.h" 1 +# 27 "src/os.h" +# 1 "src/os_setup.h" 1 +# 28 "src/os.h" 2 +# 158 "src/os.h" +int sqlite3OsInit(void); + + + + +void sqlite3OsClose(sqlite3_file*); +int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset); +int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset); +int sqlite3OsTruncate(sqlite3_file*, i64 size); +int sqlite3OsSync(sqlite3_file*, int); +int sqlite3OsFileSize(sqlite3_file*, i64 *pSize); +int sqlite3OsLock(sqlite3_file*, int); +int sqlite3OsUnlock(sqlite3_file*, int); +int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut); +int sqlite3OsFileControl(sqlite3_file*,int,void*); +void sqlite3OsFileControlHint(sqlite3_file*,int,void*); + +int sqlite3OsSectorSize(sqlite3_file *id); +int sqlite3OsDeviceCharacteristics(sqlite3_file *id); + +int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **); +int sqlite3OsShmLock(sqlite3_file *id, int, int, int); +void sqlite3OsShmBarrier(sqlite3_file *id); +int sqlite3OsShmUnmap(sqlite3_file *id, int); + +int sqlite3OsFetch(sqlite3_file *id, i64, int, void **); +int sqlite3OsUnfetch(sqlite3_file *, i64, void *); + + + + + +int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *); +int sqlite3OsDelete(sqlite3_vfs *, const char *, int); +int sqlite3OsAccess(sqlite3_vfs *, const char *, int, int *pResOut); +int sqlite3OsFullPathname(sqlite3_vfs *, const char *, int, char *); + +void *sqlite3OsDlOpen(sqlite3_vfs *, const char *); +void sqlite3OsDlError(sqlite3_vfs *, int, char *); +void (*sqlite3OsDlSym(sqlite3_vfs *, void *, const char *))(void); +void sqlite3OsDlClose(sqlite3_vfs *, void *); + +int sqlite3OsRandomness(sqlite3_vfs *, int, char *); +int sqlite3OsSleep(sqlite3_vfs *, int); +int sqlite3OsGetLastError(sqlite3_vfs*); +int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*); + + + + + +int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*); +void sqlite3OsCloseFree(sqlite3_file *); +# 1160 "src/sqliteInt.h" 2 +# 1 "src/mutex.h" 1 +# 1161 "src/sqliteInt.h" 2 +# 1200 "src/sqliteInt.h" +struct Db { + char *zDbSName; + Btree *pBt; + u8 safety_level; + u8 bSyncSet; + Schema *pSchema; +}; +# 1225 "src/sqliteInt.h" +struct Schema { + int schema_cookie; + int iGeneration; + Hash tblHash; + Hash idxHash; + Hash trigHash; + Hash fkeyHash; + Table *pSeqTab; + u8 file_format; + u8 enc; + u16 schemaFlags; + int cache_size; +}; +# 1289 "src/sqliteInt.h" +struct Lookaside { + u32 bDisable; + u16 sz; + u8 bMalloced; + u32 nSlot; + u32 anStat[3]; + LookasideSlot *pInit; + LookasideSlot *pFree; + void *pStart; + void *pEnd; +}; +struct LookasideSlot { + LookasideSlot *pNext; +}; +# 1313 "src/sqliteInt.h" +struct FuncDefHash { + FuncDef *a[23]; +}; +# 1352 "src/sqliteInt.h" + typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, + const char*); +# 1372 "src/sqliteInt.h" +struct sqlite3 { + sqlite3_vfs *pVfs; + struct Vdbe *pVdbe; + CollSeq *pDfltColl; + sqlite3_mutex *mutex; + Db *aDb; + int nDb; + u32 mDbFlags; + u64 flags; + i64 lastRowid; + i64 szMmap; + u32 nSchemaLock; + unsigned int openFlags; + int errCode; + int errMask; + int iSysErrno; + u16 dbOptFlags; + u8 enc; + u8 autoCommit; + u8 temp_store; + u8 mallocFailed; + u8 bBenignMalloc; + u8 dfltLockMode; + signed char nextAutovac; + u8 suppressErr; + u8 vtabOnConflict; + u8 isTransactionSavepoint; + u8 mTrace; + u8 noSharedCache; + u8 nSqlExec; + int nextPagesize; + u32 magic; + int nChange; + int nTotalChange; + int aLimit[(11 +1)]; + int nMaxSorterMmap; + struct sqlite3InitInfo { + int newTnum; + u8 iDb; + u8 busy; + unsigned orphanTrigger : 1; + unsigned imposterTable : 1; + unsigned reopenMemdb : 1; + } init; + int nVdbeActive; + int nVdbeRead; + int nVdbeWrite; + int nVdbeExec; + int nVDestroy; + int nExtension; + void **aExtension; + int (*xTrace)(u32,void*,void*,void*); + void *pTraceArg; + + void (*xProfile)(void*,const char*,u64); + void *pProfileArg; + + void *pCommitArg; + int (*xCommitCallback)(void*); + void *pRollbackArg; + void (*xRollbackCallback)(void*); + void *pUpdateArg; + void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64); + Parse *pParse; +# 1444 "src/sqliteInt.h" + int (*xWalCallback)(void *, sqlite3 *, const char *, int); + void *pWalArg; + + void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*); + void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*); + void *pCollNeededArg; + sqlite3_value *pErr; + union { + volatile int isInterrupted; + double notUsed1; + } u1; + Lookaside lookaside; + + sqlite3_xauth xAuth; + void *pAuthArg; + + + int (*xProgress)(void *); + void *pProgressArg; + unsigned nProgressOps; + + + int nVTrans; + Hash aModule; + VtabCtx *pVtabCtx; + VTable **aVTrans; + VTable *pDisconnect; + + Hash aFunc; + Hash aCollSeq; + BusyHandler busyHandler; + Db aDbStatic[2]; + Savepoint *pSavepoint; + int busyTimeout; + int nSavepoint; + int nStatement; + i64 nDeferredCons; + i64 nDeferredImmCons; + int *pnBytesFreed; +# 1503 "src/sqliteInt.h" +}; +# 1632 "src/sqliteInt.h" +struct FuncDef { + i8 nArg; + u32 funcFlags; + void *pUserData; + FuncDef *pNext; + void (*xSFunc)(sqlite3_context*,int,sqlite3_value**); + void (*xFinalize)(sqlite3_context*); + void (*xValue)(sqlite3_context*); + void (*xInverse)(sqlite3_context*,int,sqlite3_value**); + const char *zName; + union { + FuncDef *pHash; + FuncDestructor *pDestructor; + } u; +}; +# 1662 "src/sqliteInt.h" +struct FuncDestructor { + int nRef; + void (*xDestroy)(void *); + void *pUserData; +}; +# 1788 "src/sqliteInt.h" +struct Savepoint { + char *zName; + i64 nDeferredCons; + i64 nDeferredImmCons; + Savepoint *pNext; +}; +# 1809 "src/sqliteInt.h" +struct Module { + const sqlite3_module *pModule; + const char *zName; + void *pAux; + void (*xDestroy)(void *); + Table *pEpoTab; +}; + + + + + +struct Column { + char *zName; + Expr *pDflt; + char *zColl; + u8 notNull; + char affinity; + u8 szEst; + u8 colFlags; +}; +# 1848 "src/sqliteInt.h" +struct CollSeq { + char *zName; + u8 enc; + void *pUser; + int (*xCmp)(void*,int, const void*, int, const void*); + void (*xDel)(void*); +}; +# 1948 "src/sqliteInt.h" +struct VTable { + sqlite3 *db; + Module *pMod; + sqlite3_vtab *pVtab; + int nRef; + u8 bConstraint; + int iSavepoint; + VTable *pNext; +}; + + + + + +struct Table { + char *zName; + Column *aCol; + Index *pIndex; + Select *pSelect; + FKey *pFKey; + char *zColAff; + ExprList *pCheck; + + int tnum; + u32 nTabRef; + u32 tabFlags; + i16 iPKey; + i16 nCol; + LogEst nRowLogEst; + LogEst szTabRow; + + + + u8 keyConf; + + int addColOffset; + + + int nModuleArg; + char **azModuleArg; + VTable *pVTable; + + Trigger *pTrigger; + Schema *pSchema; + Table *pNextZombie; +}; +# 2078 "src/sqliteInt.h" +struct FKey { + Table *pFrom; + FKey *pNextFrom; + char *zTo; + FKey *pNextTo; + FKey *pPrevTo; + int nCol; + + u8 isDeferred; + u8 aAction[2]; + Trigger *apTrigger[2]; + struct sColMap { + int iFrom; + char *zCol; + } aCol[1]; +}; +# 2143 "src/sqliteInt.h" +struct KeyInfo { + u32 nRef; + u8 enc; + u16 nKeyField; + u16 nAllField; + sqlite3 *db; + u8 *aSortOrder; + CollSeq *aColl[1]; +}; +# 2188 "src/sqliteInt.h" +struct UnpackedRecord { + KeyInfo *pKeyInfo; + Mem *aMem; + u16 nField; + i8 default_rc; + u8 errCode; + i8 r1; + i8 r2; + u8 eqSeen; +}; +# 2234 "src/sqliteInt.h" +struct Index { + char *zName; + i16 *aiColumn; + LogEst *aiRowLogEst; + Table *pTable; + char *zColAff; + Index *pNext; + Schema *pSchema; + u8 *aSortOrder; + const char **azColl; + Expr *pPartIdxWhere; + ExprList *aColExpr; + int tnum; + LogEst szIdxRow; + u16 nKeyCol; + u16 nColumn; + u8 onError; + unsigned idxType:2; + unsigned bUnordered:1; + unsigned uniqNotNull:1; + unsigned isResized:1; + unsigned isCovering:1; + unsigned noSkipScan:1; + unsigned hasStat1:1; + unsigned bNoQuery:1; + unsigned bAscKeyBug:1; +# 2268 "src/sqliteInt.h" + Bitmask colNotIdxed; +}; +# 2296 "src/sqliteInt.h" +struct IndexSample { + void *p; + int n; + tRowcnt *anEq; + tRowcnt *anLt; + tRowcnt *anDLt; +}; +# 2320 "src/sqliteInt.h" +struct Token { + const char *z; + unsigned int n; +}; +# 2338 "src/sqliteInt.h" +struct AggInfo { + u8 directMode; + + u8 useSortingIdx; + + int sortingIdx; + int sortingIdxPTab; + int nSortingColumn; + int mnReg, mxReg; + ExprList *pGroupBy; + struct AggInfo_col { + Table *pTab; + int iTable; + int iColumn; + int iSorterColumn; + int iMem; + Expr *pExpr; + } *aCol; + int nColumn; + int nAccumulator; + + + struct AggInfo_func { + Expr *pExpr; + FuncDef *pFunc; + int iMem; + int iDistinct; + } *aFunc; + int nFunc; +}; +# 2380 "src/sqliteInt.h" +typedef i16 ynVar; +# 2448 "src/sqliteInt.h" +struct Expr { + u8 op; + char affinity; + u32 flags; + union { + char *zToken; + int iValue; + } u; + + + + + + + Expr *pLeft; + Expr *pRight; + union { + ExprList *pList; + Select *pSelect; + } x; + + + + + + + + int nHeight; + + int iTable; + + + + + ynVar iColumn; + + + i16 iAgg; + i16 iRightJoinTable; + u8 op2; + + + AggInfo *pAggInfo; + union { + Table *pTab; + + Window *pWin; + struct { + int iAddr; + int regReturn; + } sub; + } y; +}; +# 2598 "src/sqliteInt.h" +struct ExprList { + int nExpr; + struct ExprList_item { + Expr *pExpr; + char *zName; + char *zSpan; + u8 sortOrder; + unsigned done :1; + unsigned bSpanIsTab :1; + unsigned reusable :1; + unsigned bSorterRef :1; + union { + struct { + u16 iOrderByCol; + u16 iAlias; + } x; + int iConstExprReg; + } u; + } a[1]; +}; +# 2634 "src/sqliteInt.h" +struct IdList { + struct IdList_item { + char *zName; + int idx; + } *a; + int nId; +}; +# 2661 "src/sqliteInt.h" +struct SrcList { + int nSrc; + u32 nAlloc; + struct SrcList_item { + Schema *pSchema; + char *zDatabase; + char *zName; + char *zAlias; + Table *pTab; + Select *pSelect; + int addrFillSub; + int regReturn; + int regResult; + struct { + u8 jointype; + unsigned notIndexed :1; + unsigned isIndexedBy :1; + unsigned isTabFunc :1; + unsigned isCorrelated :1; + unsigned viaCoroutine :1; + unsigned isRecursive :1; + } fg; + int iCursor; + Expr *pOn; + IdList *pUsing; + Bitmask colUsed; + union { + char *zIndexedBy; + ExprList *pFuncArg; + } u1; + Index *pIBIndex; + } a[1]; +}; +# 2761 "src/sqliteInt.h" +struct NameContext { + Parse *pParse; + SrcList *pSrcList; + union { + ExprList *pEList; + AggInfo *pAggInfo; + Upsert *pUpsert; + } uNC; + NameContext *pNext; + int nRef; + int nErr; + int ncFlags; + Select *pWinSelect; +}; +# 2815 "src/sqliteInt.h" +struct Upsert { + ExprList *pUpsertTarget; + Expr *pUpsertTargetWhere; + ExprList *pUpsertSet; + Expr *pUpsertWhere; + + + + + Index *pUpsertIdx; + SrcList *pUpsertSrc; + int regData; + int iDataCur; + int iIdxCur; +}; +# 2848 "src/sqliteInt.h" +struct Select { + ExprList *pEList; + u8 op; + LogEst nSelectRow; + u32 selFlags; + int iLimit, iOffset; + u32 selId; + int addrOpenEphm[2]; + SrcList *pSrc; + Expr *pWhere; + ExprList *pGroupBy; + Expr *pHaving; + ExprList *pOrderBy; + Select *pPrior; + Select *pNext; + Expr *pLimit; + With *pWith; + + Window *pWin; + Window *pWinDefn; + +}; +# 2987 "src/sqliteInt.h" +struct SelectDest { + u8 eDest; + int iSDParm; + int iSdst; + int nSdst; + char *zAffSdst; + ExprList *pOrderBy; +}; +# 3005 "src/sqliteInt.h" +struct AutoincInfo { + AutoincInfo *pNext; + Table *pTab; + int iDb; + int regCtr; +}; +# 3030 "src/sqliteInt.h" +struct TriggerPrg { + Trigger *pTrigger; + TriggerPrg *pNext; + SubProgram *pProgram; + int orconf; + u32 aColmask[2]; +}; +# 3049 "src/sqliteInt.h" + typedef unsigned int yDbMask; +# 3073 "src/sqliteInt.h" +struct Parse { + sqlite3 *db; + char *zErrMsg; + Vdbe *pVdbe; + int rc; + u8 colNamesSet; + u8 checkSchema; + u8 nested; + u8 nTempReg; + u8 isMultiWrite; + u8 mayAbort; + u8 hasCompound; + u8 okConstFactor; + u8 disableLookaside; + u8 disableVtab; + int nRangeReg; + int iRangeReg; + int nErr; + int nTab; + int nMem; + int szOpAlloc; + int iSelfTab; + + int nLabel; + int nLabelAlloc; + int *aLabel; + ExprList *pConstExpr; + Token constraintName; + yDbMask writeMask; + yDbMask cookieMask; + int regRowid; + int regRoot; + int nMaxArg; + int nSelect; + + int nTableLock; + TableLock *aTableLock; + + AutoincInfo *pAinc; + Parse *pToplevel; + Table *pTriggerTab; + Parse *pParentParse; + int addrCrTab; + u32 nQueryLoop; + u32 oldmask; + u32 newmask; + u8 eTriggerOp; + u8 eOrconf; + u8 disableTriggers; +# 3130 "src/sqliteInt.h" + int aTempReg[8]; + Token sNameToken; +# 3140 "src/sqliteInt.h" + Token sLastToken; + ynVar nVar; + u8 iPkSortOrder; + u8 explain; + + u8 eParseMode; + + + int nVtabLock; + + int nHeight; + + int addrExplain; + + VList *pVList; + Vdbe *pReprepare; + const char *zTail; + Table *pNewTable; + Index *pNewIndex; + + + Trigger *pNewTrigger; + const char *zAuthContext; + + Token sArg; + Table **apVtabLock; + + Table *pZombieTab; + TriggerPrg *pTriggerPrg; + With *pWith; + With *pWithToFree; + + RenameToken *pRename; + +}; +# 3214 "src/sqliteInt.h" +struct AuthContext { + const char *zAuthContext; + Parse *pParse; +}; +# 3266 "src/sqliteInt.h" +struct Trigger { + char *zName; + char *table; + u8 op; + u8 tr_tm; + Expr *pWhen; + IdList *pColumns; + + Schema *pSchema; + Schema *pTabSchema; + TriggerStep *step_list; + Trigger *pNext; +}; +# 3328 "src/sqliteInt.h" +struct TriggerStep { + u8 op; + u8 orconf; + Trigger *pTrig; + Select *pSelect; + char *zTarget; + Expr *pWhere; + ExprList *pExprList; + IdList *pIdList; + Upsert *pUpsert; + char *zSpan; + TriggerStep *pNext; + TriggerStep *pLast; +}; + + + + + + +typedef struct DbFixer DbFixer; +struct DbFixer { + Parse *pParse; + Schema *pSchema; + int bVarOnly; + const char *zDb; + const char *zType; + const Token *pName; +}; + + + + + +struct sqlite3_str { + sqlite3 *db; + char *zText; + u32 nAlloc; + u32 mxAlloc; + u32 nChar; + u8 accError; + u8 printfFlags; +}; +# 3382 "src/sqliteInt.h" +typedef struct { + sqlite3 *db; + char **pzErrMsg; + int iDb; + int rc; + u32 mInitFlags; + u32 nInitRow; +} InitData; +# 3401 "src/sqliteInt.h" +struct Sqlite3Config { + int bMemstat; + int bCoreMutex; + int bFullMutex; + int bOpenUri; + int bUseCis; + int bSmallMalloc; + int mxStrlen; + int neverCorrupt; + int szLookaside; + int nLookaside; + int nStmtSpill; + sqlite3_mem_methods m; + sqlite3_mutex_methods mutex; + sqlite3_pcache_methods2 pcache2; + void *pHeap; + int nHeap; + int mnReq, mxReq; + sqlite3_int64 szMmap; + sqlite3_int64 mxMmap; + void *pPage; + int szPage; + int nPage; + int mxParserStack; + int sharedCacheEnabled; + u32 szPma; + + + int isInit; + int inProgress; + int isMutexInit; + int isMallocInit; + int isPCacheInit; + int nRefInitMutex; + sqlite3_mutex *pInitMutex; + void (*xLog)(void*,int,const char*); + void *pLogArg; +# 3453 "src/sqliteInt.h" + int (*xTestCallback)(int); + + int bLocaltimeFault; + int bInternalFunctions; + int iOnceResetThreshold; + u32 szSorterRef; +}; +# 3482 "src/sqliteInt.h" +struct Walker { + Parse *pParse; + int (*xExprCallback)(Walker*, Expr*); + int (*xSelectCallback)(Walker*,Select*); + void (*xSelectCallback2)(Walker*,Select*); + int walkerDepth; + u8 eCode; + union { + NameContext *pNC; + int n; + int iCur; + SrcList *pSrcList; + struct SrcCount *pSrcCount; + struct CCurHint *pCCurHint; + int *aiCol; + struct IdxCover *pIdxCover; + struct IdxExprTrans *pIdxTrans; + ExprList *pGroupBy; + Select *pSelect; + struct WindowRewrite *pRewrite; + struct WhereConst *pConst; + struct RenameCtx *pRename; + } u; +}; + + +int sqlite3WalkExpr(Walker*, Expr*); +int sqlite3WalkExprList(Walker*, ExprList*); +int sqlite3WalkSelect(Walker*, Select*); +int sqlite3WalkSelectExpr(Walker*, Select*); +int sqlite3WalkSelectFrom(Walker*, Select*); +int sqlite3ExprWalkNoop(Walker*, Expr*); +int sqlite3SelectWalkNoop(Walker*, Select*); +int sqlite3SelectWalkFail(Walker*, Select*); +# 3532 "src/sqliteInt.h" +struct With { + int nCte; + With *pOuter; + struct Cte { + char *zName; + ExprList *pCols; + Select *pSelect; + const char *zCteErr; + } a[1]; +}; +# 3572 "src/sqliteInt.h" +struct Window { + char *zName; + char *zBase; + ExprList *pPartition; + ExprList *pOrderBy; + u8 eFrmType; + u8 eStart; + u8 eEnd; + u8 bImplicitFrame; + u8 eExclude; + Expr *pStart; + Expr *pEnd; + Window *pNextWin; + Expr *pFilter; + FuncDef *pFunc; + int iEphCsr; + int regAccum; + int regResult; + int csrApp; + int regApp; + int regPart; + Expr *pOwner; + int nBufferCol; + int iArgCol; + int regOne; + int regStartRowid; + int regEndRowid; +}; + + +void sqlite3WindowDelete(sqlite3*, Window*); +void sqlite3WindowListDelete(sqlite3 *db, Window *p); +Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8); +void sqlite3WindowAttach(Parse*, Expr*, Window*); +int sqlite3WindowCompare(Parse*, Window*, Window*); +void sqlite3WindowCodeInit(Parse*, Window*); +void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int); +int sqlite3WindowRewrite(Parse*, Select*); +int sqlite3ExpandSubquery(Parse*, struct SrcList_item*); +void sqlite3WindowUpdate(Parse*, Window*, Window*, FuncDef*); +Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p); +Window *sqlite3WindowListDup(sqlite3 *db, Window *p); +void sqlite3WindowFunctions(void); +void sqlite3WindowChain(Parse*, Window*, Window*); +Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprList*, Token*); +# 3640 "src/sqliteInt.h" +int sqlite3ReportError(int iErr, int lineno, const char *zType); +int sqlite3CorruptError(int); +int sqlite3MisuseError(int); +int sqlite3CantopenError(int); +# 3710 "src/sqliteInt.h" +int sqlite3IsIdChar(u8); + + + + +int sqlite3StrICmp(const char*,const char*); +int sqlite3Strlen30(const char*); + +char *sqlite3ColumnType(Column*,char*); + + +int sqlite3MallocInit(void); +void sqlite3MallocEnd(void); +void *sqlite3Malloc(u64); +void *sqlite3MallocZero(u64); +void *sqlite3DbMallocZero(sqlite3*, u64); +void *sqlite3DbMallocRaw(sqlite3*, u64); +void *sqlite3DbMallocRawNN(sqlite3*, u64); +char *sqlite3DbStrDup(sqlite3*,const char*); +char *sqlite3DbStrNDup(sqlite3*,const char*, u64); +char *sqlite3DbSpanDup(sqlite3*,const char*,const char*); +void *sqlite3Realloc(void*, u64); +void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64); +void *sqlite3DbRealloc(sqlite3 *, void *, u64); +void sqlite3DbFree(sqlite3*, void*); +void sqlite3DbFreeNN(sqlite3*, void*); +int sqlite3MallocSize(void*); +int sqlite3DbMallocSize(sqlite3*, void*); +void *sqlite3PageMalloc(int); +void sqlite3PageFree(void*); +void sqlite3MemSetDefault(void); + +void sqlite3BenignMallocHooks(void (*)(void), void (*)(void)); + +int sqlite3HeapNearlyFull(void); +# 3777 "src/sqliteInt.h" + sqlite3_mutex_methods const *sqlite3DefaultMutex(void); + sqlite3_mutex_methods const *sqlite3NoopMutex(void); + sqlite3_mutex *sqlite3MutexAlloc(int); + int sqlite3MutexInit(void); + int sqlite3MutexEnd(void); + + + void sqlite3MemoryBarrier(void); + + + + +sqlite3_int64 sqlite3StatusValue(int); +void sqlite3StatusUp(int, int); +void sqlite3StatusDown(int, int); +void sqlite3StatusHighwater(int, int); +int sqlite3LookasideUsed(sqlite3*,int*); + + +sqlite3_mutex *sqlite3Pcache1Mutex(void); +sqlite3_mutex *sqlite3MallocMutex(void); +# 3809 "src/sqliteInt.h" + int sqlite3IsNaN(double); +# 3819 "src/sqliteInt.h" +struct PrintfArguments { + int nArg; + int nUsed; + sqlite3_value **apArg; +}; + +char *sqlite3MPrintf(sqlite3*,const char*, ...); +char *sqlite3VMPrintf(sqlite3*,const char*, va_list); +# 3848 "src/sqliteInt.h" +void sqlite3SetString(char **, sqlite3*, const char*); +void sqlite3ErrorMsg(Parse*, const char*, ...); +int sqlite3ErrorToParser(sqlite3*,int); +void sqlite3Dequote(char*); +void sqlite3DequoteExpr(Expr*); +void sqlite3TokenInit(Token*,char*); +int sqlite3KeywordCode(const unsigned char*, int); +int sqlite3RunParser(Parse*, const char*, char **); +void sqlite3FinishCoding(Parse*); +int sqlite3GetTempReg(Parse*); +void sqlite3ReleaseTempReg(Parse*,int); +int sqlite3GetTempRange(Parse*,int); +void sqlite3ReleaseTempRange(Parse*,int,int); +void sqlite3ClearTempRegCache(Parse*); + + + +Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int); +Expr *sqlite3Expr(sqlite3*,int,const char*); +void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*); +Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*); +void sqlite3PExprAddSelect(Parse*, Expr*, Select*); +Expr *sqlite3ExprAnd(Parse*,Expr*, Expr*); +Expr *sqlite3ExprSimplifiedAndOr(Expr*); +Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int); +void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); +void sqlite3ExprDelete(sqlite3*, Expr*); +void sqlite3ExprUnmapAndDelete(Parse*, Expr*); +ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); +ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*); +void sqlite3ExprListSetSortOrder(ExprList*,int); +void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int); +void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*); +void sqlite3ExprListDelete(sqlite3*, ExprList*); +u32 sqlite3ExprListFlags(const ExprList*); +int sqlite3IndexHasDuplicateRootPage(Index*); +int sqlite3Init(sqlite3*, char**); +int sqlite3InitCallback(void*, int, char**, char**); +int sqlite3InitOne(sqlite3*, int, char**, u32); +void sqlite3Pragma(Parse*,Token*,Token*,Token*,int); + +Module *sqlite3PragmaVtabRegister(sqlite3*,const char *zName); + +void sqlite3ResetAllSchemasOfConnection(sqlite3*); +void sqlite3ResetOneSchema(sqlite3*,int); +void sqlite3CollapseDatabaseArray(sqlite3*); +void sqlite3CommitInternalChanges(sqlite3*); +void sqlite3DeleteColumnNames(sqlite3*,Table*); +int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); +void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*); +Table *sqlite3ResultSetOfSelect(Parse*,Select*); +void sqlite3OpenMasterTable(Parse *, int); +Index *sqlite3PrimaryKeyIndex(Table*); +i16 sqlite3ColumnOfIndex(Index*, i16); +void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int); + + + + + +void sqlite3AddColumn(Parse*,Token*,Token*); +void sqlite3AddNotNull(Parse*, int); +void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int); +void sqlite3AddCheckConstraint(Parse*, Expr*); +void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*); +void sqlite3AddCollateType(Parse*, Token*); +void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*); +int sqlite3ParseUri(const char*,const char*,unsigned int*, + sqlite3_vfs**,char**,char **); + + + + + +Btree *sqlite3DbNameToBtree(sqlite3*,const char*); + + + + + int sqlite3FaultSim(int); + + +Bitvec *sqlite3BitvecCreate(u32); +int sqlite3BitvecTest(Bitvec*, u32); +int sqlite3BitvecTestNotNull(Bitvec*, u32); +int sqlite3BitvecSet(Bitvec*, u32); +void sqlite3BitvecClear(Bitvec*, u32, void*); +void sqlite3BitvecDestroy(Bitvec*); +u32 sqlite3BitvecSize(Bitvec*); + +int sqlite3BitvecBuiltinTest(int,int*); + + +RowSet *sqlite3RowSetInit(sqlite3*); +void sqlite3RowSetDelete(void*); +void sqlite3RowSetClear(void*); +void sqlite3RowSetInsert(RowSet*, i64); +int sqlite3RowSetTest(RowSet*, int iBatch, i64); +int sqlite3RowSetNext(RowSet*, i64*); + +void sqlite3CreateView(Parse*,Token*,Token*,Token*,ExprList*,Select*,int,int); + + + int sqlite3ViewGetColumnNames(Parse*,Table*); + + + + + + + +void sqlite3DropTable(Parse*, SrcList*, int, int); +void sqlite3CodeDropTable(Parse*, Table*, int, int); +void sqlite3DeleteTable(sqlite3*, Table*); +void sqlite3FreeIndex(sqlite3*, Index*); + + void sqlite3AutoincrementBegin(Parse *pParse); + void sqlite3AutoincrementEnd(Parse *pParse); + + + + +void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int, Upsert*); +void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*); +IdList *sqlite3IdListAppend(Parse*, IdList*, Token*); +int sqlite3IdListIndex(IdList*,const char*); +SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int); +SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*); +SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, + Token*, Select*, Expr*, IdList*); +void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *); +void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*); +int sqlite3IndexedByLookup(Parse *, struct SrcList_item *); +void sqlite3SrcListShiftJoinType(SrcList*); +void sqlite3SrcListAssignCursors(Parse*, SrcList*); +void sqlite3IdListDelete(sqlite3*, IdList*); +void sqlite3SrcListDelete(sqlite3*, SrcList*); +Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**); +void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, + Expr*, int, int, u8); +void sqlite3DropIndex(Parse*, SrcList*, int); +int sqlite3Select(Parse*, Select*, SelectDest*); +Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, + Expr*,ExprList*,u32,Expr*); +void sqlite3SelectDelete(sqlite3*, Select*); +Table *sqlite3SrcListLookup(Parse*, SrcList*); +int sqlite3IsReadOnly(Parse*, Table*, int); +void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); + + + +void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*); +void sqlite3Update(Parse*, SrcList*, ExprList*,Expr*,int,ExprList*,Expr*, + Upsert*); +WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int); +void sqlite3WhereEnd(WhereInfo*); +LogEst sqlite3WhereOutputRowCount(WhereInfo*); +int sqlite3WhereIsDistinct(WhereInfo*); +int sqlite3WhereIsOrdered(WhereInfo*); +int sqlite3WhereOrderByLimitOptLabel(WhereInfo*); +int sqlite3WhereIsSorted(WhereInfo*); +int sqlite3WhereContinueLabel(WhereInfo*); +int sqlite3WhereBreakLabel(WhereInfo*); +int sqlite3WhereOkOnePass(WhereInfo*, int*); + + + +void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int); +int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); +void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); +void sqlite3ExprCodeMove(Parse*, int, int, int); +void sqlite3ExprCode(Parse*, Expr*, int); +void sqlite3ExprCodeCopy(Parse*, Expr*, int); +void sqlite3ExprCodeFactorable(Parse*, Expr*, int); +int sqlite3ExprCodeAtInit(Parse*, Expr*, int); +int sqlite3ExprCodeTemp(Parse*, Expr*, int*); +int sqlite3ExprCodeTarget(Parse*, Expr*, int); +void sqlite3ExprCodeAndCache(Parse*, Expr*, int); +int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8); + + + + +void sqlite3ExprIfTrue(Parse*, Expr*, int, int); +void sqlite3ExprIfFalse(Parse*, Expr*, int, int); +void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int); +Table *sqlite3FindTable(sqlite3*,const char*, const char*); + + +Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*); +Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_item *); +Index *sqlite3FindIndex(sqlite3*,const char*, const char*); +void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); +void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); +void sqlite3Vacuum(Parse*,Token*,Expr*); +int sqlite3RunVacuum(char**, sqlite3*, int, sqlite3_value*); +char *sqlite3NameFromToken(sqlite3*, Token*); +int sqlite3ExprCompare(Parse*,Expr*, Expr*, int); +int sqlite3ExprCompareSkip(Expr*, Expr*, int); +int sqlite3ExprListCompare(ExprList*, ExprList*, int); +int sqlite3ExprImpliesExpr(Parse*,Expr*, Expr*, int); +int sqlite3ExprImpliesNonNullRow(Expr*,int); +void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); +void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); +int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx); +int sqlite3FunctionUsesThisSrc(Expr*, SrcList*); +Vdbe *sqlite3GetVdbe(Parse*); + +void sqlite3PrngSaveState(void); +void sqlite3PrngRestoreState(void); + +void sqlite3RollbackAll(sqlite3*,int); +void sqlite3CodeVerifySchema(Parse*, int); +void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb); +void sqlite3BeginTransaction(Parse*, int); +void sqlite3EndTransaction(Parse*,int); +void sqlite3Savepoint(Parse*, int, Token*); +void sqlite3CloseSavepoints(sqlite3 *); +void sqlite3LeaveMutexAndCloseZombie(sqlite3*); +int sqlite3ExprIdToTrueFalse(Expr*); +int sqlite3ExprTruthValue(const Expr*); +int sqlite3ExprIsConstant(Expr*); +int sqlite3ExprIsConstantNotJoin(Expr*); +int sqlite3ExprIsConstantOrFunction(Expr*, u8); +int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*); +int sqlite3ExprIsTableConstant(Expr*,int); + + + +int sqlite3ExprIsInteger(Expr*, int*); +int sqlite3ExprCanBeNull(const Expr*); +int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); +int sqlite3IsRowid(const char*); +void sqlite3GenerateRowDelete( + Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int); +void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int); +int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int); +void sqlite3ResolvePartIdxLabel(Parse*,int); +int sqlite3ExprReferencesUpdatedColumn(Expr*,int*,int); +void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int, + u8,u8,int,int*,int*,Upsert*); + + + + + +void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int); +int sqlite3OpenTableAndIndices(Parse*, Table*, int, u8, int, u8*, int*, int*); +void sqlite3BeginWriteOperation(Parse*, int, int); +void sqlite3MultiWrite(Parse*); +void sqlite3MayAbort(Parse*); +void sqlite3HaltConstraint(Parse*, int, int, char*, i8, u8); +void sqlite3UniqueConstraint(Parse*, int, Index*); +void sqlite3RowidConstraint(Parse*, int, Table*); +Expr *sqlite3ExprDup(sqlite3*,Expr*,int); +ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int); +SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int); +IdList *sqlite3IdListDup(sqlite3*,IdList*); +Select *sqlite3SelectDup(sqlite3*,Select*,int); +FuncDef *sqlite3FunctionSearch(int,const char*); +void sqlite3InsertBuiltinFuncs(FuncDef*,int); +FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8); +void sqlite3RegisterBuiltinFunctions(void); +void sqlite3RegisterDateTimeFunctions(void); +void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*); +int sqlite3SafetyCheckOk(sqlite3*); +int sqlite3SafetyCheckSickOrOk(sqlite3*); +void sqlite3ChangeCookie(Parse*, int); + + +void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int); + + + + void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*, + Expr*,int, int); + void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*); + void sqlite3DropTrigger(Parse*, SrcList*, int); + void sqlite3DropTriggerPtr(Parse*, Trigger*); + Trigger *sqlite3TriggersExist(Parse *, Table*, int, ExprList*, int *pMask); + Trigger *sqlite3TriggerList(Parse *, Table *); + void sqlite3CodeRowTrigger(Parse*, Trigger *, int, ExprList*, int, Table *, + int, int, int); + void sqlite3CodeRowTriggerDirect(Parse *, Trigger *, Table *, int, int, int); + void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*); + void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*); + TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*, + const char*,const char*); + TriggerStep *sqlite3TriggerInsertStep(Parse*,Token*, IdList*, + Select*,u8,Upsert*, + const char*,const char*); + TriggerStep *sqlite3TriggerUpdateStep(Parse*,Token*,ExprList*, Expr*, u8, + const char*,const char*); + TriggerStep *sqlite3TriggerDeleteStep(Parse*,Token*, Expr*, + const char*,const char*); + void sqlite3DeleteTrigger(sqlite3*, Trigger*); + void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*); + u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int); +# 4161 "src/sqliteInt.h" +int sqlite3JoinType(Parse*, Token*, Token*, Token*); +void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int); +void sqlite3DeferForeignKey(Parse*, int); + + void sqlite3AuthRead(Parse*,Expr*,Schema*,SrcList*); + int sqlite3AuthCheck(Parse*,int, const char*, const char*, const char*); + void sqlite3AuthContextPush(Parse*, AuthContext*, const char*); + void sqlite3AuthContextPop(AuthContext*); + int sqlite3AuthReadCol(Parse*, const char *, const char *, int); + + + + + + +void sqlite3Attach(Parse*, Expr*, Expr*, Expr*); +void sqlite3Detach(Parse*, Expr*); +void sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*); +int sqlite3FixSrcList(DbFixer*, SrcList*); +int sqlite3FixSelect(DbFixer*, Select*); +int sqlite3FixExpr(DbFixer*, Expr*); +int sqlite3FixExprList(DbFixer*, ExprList*); +int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); +int sqlite3RealSameAsInt(double,sqlite3_int64); +int sqlite3AtoF(const char *z, double*, int, u8); +int sqlite3GetInt32(const char *, int*); +int sqlite3Atoi(const char*); + +int sqlite3Utf16ByteLen(const void *pData, int nChar); + +int sqlite3Utf8CharLen(const char *pData, int nByte); +u32 sqlite3Utf8Read(const u8**); +LogEst sqlite3LogEst(u64); +LogEst sqlite3LogEstAdd(LogEst,LogEst); + +LogEst sqlite3LogEstFromDouble(double); + + + + + + +VList *sqlite3VListAdd(sqlite3*,VList*,const char*,int,int); +const char *sqlite3VListNumToName(VList*,int); +int sqlite3VListNameToNum(VList*,const char*,int); + + + + + + +int sqlite3PutVarint(unsigned char*, u64); +u8 sqlite3GetVarint(const unsigned char *, u64 *); +u8 sqlite3GetVarint32(const unsigned char *, u32 *); +int sqlite3VarintLen(u64 v); +# 4231 "src/sqliteInt.h" +const char *sqlite3IndexAffinityStr(sqlite3*, Index*); +void sqlite3TableAffinity(Vdbe*, Table*, int); +char sqlite3CompareAffinity(Expr *pExpr, char aff2); +int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); +char sqlite3TableColumnAffinity(Table*,int); +char sqlite3ExprAffinity(Expr *pExpr); +int sqlite3Atoi64(const char*, i64*, int, u8); +int sqlite3DecOrHexToI64(const char*, i64*); +void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...); +void sqlite3Error(sqlite3*,int); +void sqlite3SystemError(sqlite3*,int); +void *sqlite3HexToBlob(sqlite3*, const char *z, int n); +u8 sqlite3HexToInt(int h); +int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); +# 4254 "src/sqliteInt.h" +const char *sqlite3ErrStr(int); +int sqlite3ReadSchema(Parse *pParse); +CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); +int sqlite3IsBinary(const CollSeq*); +CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); +CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); +CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr); +int sqlite3ExprCollSeqMatch(Parse*,Expr*,Expr*); +Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int); +Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); +Expr *sqlite3ExprSkipCollate(Expr*); +int sqlite3CheckCollSeq(Parse *, CollSeq *); +int sqlite3WritableSchema(sqlite3*); +int sqlite3CheckObjectName(Parse *, const char *); +void sqlite3VdbeSetChanges(sqlite3 *, int); +int sqlite3AddInt64(i64*,i64); +int sqlite3SubInt64(i64*,i64); +int sqlite3MulInt64(i64*,i64); +int sqlite3AbsInt32(int); + + + + + +u8 sqlite3GetBoolean(const char *z,u8); + +const void *sqlite3ValueText(sqlite3_value*, u8); +int sqlite3ValueBytes(sqlite3_value*, u8); +void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, + void(*)(void*)); +void sqlite3ValueSetNull(sqlite3_value*); +void sqlite3ValueFree(sqlite3_value*); + +void sqlite3ResultIntReal(sqlite3_context*); + +sqlite3_value *sqlite3ValueNew(sqlite3 *); + +char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8); + +int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **); +void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8); + +extern const unsigned char sqlite3OpcodeProperty[]; +extern const char sqlite3StrBINARY[]; +extern const unsigned char sqlite3UpperToLower[]; +extern const unsigned char sqlite3CtypeMap[]; +extern const Token sqlite3IntTokens[]; +extern struct Sqlite3Config sqlite3Config; +extern FuncDefHash sqlite3BuiltinFunctions; + +extern int sqlite3PendingByte; + + + + + +void sqlite3RootPageMoved(sqlite3*, int, int, int); +void sqlite3Reindex(Parse*, Token*, Token*); +void sqlite3AlterFunctions(void); +void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); +void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*); +int sqlite3GetToken(const unsigned char *, int *); +void sqlite3NestedParse(Parse*, const char*, ...); +void sqlite3ExpirePreparedStatements(sqlite3*, int); +void sqlite3CodeRhsOfIN(Parse*, Expr*, int); +int sqlite3CodeSubselect(Parse*, Expr*); +void sqlite3SelectPrep(Parse*, Select*, NameContext*); +void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p); +int sqlite3MatchSpanName(const char*, const char*, const char*, const char*); +int sqlite3ResolveExprNames(NameContext*, Expr*); +int sqlite3ResolveExprListNames(NameContext*, ExprList*); +void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*); +int sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*); +int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*); +void sqlite3ColumnDefault(Vdbe *, Table *, int, int); +void sqlite3AlterFinishAddColumn(Parse *, Token *); +void sqlite3AlterBeginAddColumn(Parse *, SrcList *); +void *sqlite3RenameTokenMap(Parse*, void*, Token*); +void sqlite3RenameTokenRemap(Parse*, void *pTo, void *pFrom); +void sqlite3RenameExprUnmap(Parse*, Expr*); +void sqlite3RenameExprlistUnmap(Parse*, ExprList*); +CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*); +char sqlite3AffinityType(const char*, Column*); +void sqlite3Analyze(Parse*, Token*, Token*); +int sqlite3InvokeBusyHandler(BusyHandler*, sqlite3_file*); +int sqlite3FindDb(sqlite3*, Token*); +int sqlite3FindDbName(sqlite3 *, const char *); +int sqlite3AnalysisLoad(sqlite3*,int iDB); +void sqlite3DeleteIndexSamples(sqlite3*,Index*); +void sqlite3DefaultRowEst(Index*); +void sqlite3RegisterLikeFunctions(sqlite3*, int); +int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*); +void sqlite3SchemaClear(void *); +Schema *sqlite3SchemaGet(sqlite3 *, Btree *); +int sqlite3SchemaToIndex(sqlite3 *db, Schema *); +KeyInfo *sqlite3KeyInfoAlloc(sqlite3*,int,int); +void sqlite3KeyInfoUnref(KeyInfo*); +KeyInfo *sqlite3KeyInfoRef(KeyInfo*); +KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*); +KeyInfo *sqlite3KeyInfoFromExprList(Parse*, ExprList*, int, int); + + + + +int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, + void (*)(sqlite3_context*,int,sqlite3_value **), + void (*)(sqlite3_context*,int,sqlite3_value **), + void (*)(sqlite3_context*), + void (*)(sqlite3_context*), + void (*)(sqlite3_context*,int,sqlite3_value **), + FuncDestructor *pDestructor +); +void sqlite3NoopDestructor(void*); +void sqlite3OomFault(sqlite3*); +void sqlite3OomClear(sqlite3*); +int sqlite3ApiExit(sqlite3 *db, int); +int sqlite3OpenTempDatabase(Parse *); + +void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int); +char *sqlite3StrAccumFinish(StrAccum*); +void sqlite3SelectDestInit(SelectDest*,int,int); +Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int); + +void sqlite3BackupRestart(sqlite3_backup *); +void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *); + + +int sqlite3ExprCheckIN(Parse*, Expr*); +# 4400 "src/sqliteInt.h" + void *sqlite3ParserAlloc(void*(*)(u64), Parse*); + void sqlite3ParserFree(void*, void(*)(void*)); + +void sqlite3Parser(void*, int, Token); +int sqlite3ParserFallback(int); + + + + +void sqlite3AutoLoadExtensions(sqlite3*); + + void sqlite3CloseExtensions(sqlite3*); + + + + + + void sqlite3TableLock(Parse *, int, int, u8, const char *); +# 4438 "src/sqliteInt.h" + void sqlite3VtabClear(sqlite3 *db, Table*); + void sqlite3VtabDisconnect(sqlite3 *db, Table *p); + int sqlite3VtabSync(sqlite3 *db, Vdbe*); + int sqlite3VtabRollback(sqlite3 *db); + int sqlite3VtabCommit(sqlite3 *db); + void sqlite3VtabLock(VTable *); + void sqlite3VtabUnlock(VTable *); + void sqlite3VtabUnlockList(sqlite3*); + int sqlite3VtabSavepoint(sqlite3 *, int, int); + void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*); + VTable *sqlite3GetVTable(sqlite3*, Table*); + Module *sqlite3VtabCreateModule( + sqlite3*, + const char*, + const sqlite3_module*, + void*, + void(*)(void*) + ); + + +int sqlite3VtabEponymousTableInit(Parse*,Module*); +void sqlite3VtabEponymousTableClear(sqlite3*,Module*); +void sqlite3VtabMakeWritable(Parse*,Table*); +void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*, int); +void sqlite3VtabFinishParse(Parse*, Token*); +void sqlite3VtabArgInit(Parse*); +void sqlite3VtabArgExtend(Parse*, Token*); +int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **); +int sqlite3VtabCallConnect(Parse*, Table*); +int sqlite3VtabCallDestroy(sqlite3*, int, const char *); +int sqlite3VtabBegin(sqlite3 *, VTable *); +FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*); +sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*); +int sqlite3VdbeParameterIndex(Vdbe*, const char*, int); +int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *); +void sqlite3ParserReset(Parse*); + + + +int sqlite3Reprepare(Vdbe*); +void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*); +CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *); +int sqlite3TempInMemory(const sqlite3*); +const char *sqlite3JournalModename(int); + + int sqlite3Checkpoint(sqlite3*, int, int, int*, int*); + int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int); + + + With *sqlite3WithAdd(Parse*,With*,Token*,ExprList*,Select*); + void sqlite3WithDelete(sqlite3*,With*); + void sqlite3WithPush(Parse*, With*, u8); + + + + + + Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*); + void sqlite3UpsertDelete(sqlite3*,Upsert*); + Upsert *sqlite3UpsertDup(sqlite3*,Upsert*); + int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*); + void sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int); +# 4515 "src/sqliteInt.h" + void sqlite3FkCheck(Parse*, Table*, int, int, int*, int); + void sqlite3FkDropTable(Parse*, SrcList *, Table*); + void sqlite3FkActions(Parse*, Table*, ExprList*, int, int*, int); + int sqlite3FkRequired(Parse*, Table*, int*, int); + u32 sqlite3FkOldmask(Parse*, Table*); + FKey *sqlite3FkReferences(Table *); +# 4530 "src/sqliteInt.h" + void sqlite3FkDelete(sqlite3 *, Table*); + int sqlite3FkLocateIndex(Parse*,Table*,FKey*,Index**,int**); +# 4550 "src/sqliteInt.h" + void sqlite3BeginBenignMalloc(void); + void sqlite3EndBenignMalloc(void); +# 4571 "src/sqliteInt.h" +int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*, int*); + +int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); +int sqlite3JournalSize(sqlite3_vfs *); + + + + + +int sqlite3JournalIsInMemory(sqlite3_file *p); +void sqlite3MemJournalOpen(sqlite3_file *); + +void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p); + + int sqlite3SelectExprHeight(Select *); + int sqlite3ExprCheckHeight(Parse*, int); + + + + + +u32 sqlite3Get4byte(const u8*); +void sqlite3Put4byte(u8*, u32); +# 4671 "src/sqliteInt.h" +int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*); +int sqlite3ThreadJoin(SQLiteThread*, void**); +# 4682 "src/sqliteInt.h" +int sqlite3ExprVectorSize(Expr *pExpr); +int sqlite3ExprIsVector(Expr *pExpr); +Expr *sqlite3VectorFieldSubexpr(Expr*, int); +Expr *sqlite3ExprForVectorField(Parse*,Expr*,int); +void sqlite3VectorErrorMsg(Parse*, Expr*); + + +const char **sqlite3CompileOptions(int *pnOpt); +# 217 "src/btreeInt.h" 2 +# 232 "src/btreeInt.h" +typedef struct MemPage MemPage; +typedef struct BtLock BtLock; +typedef struct CellInfo CellInfo; +# 273 "src/btreeInt.h" +struct MemPage { + u8 isInit; + u8 bBusy; + u8 intKey; + u8 intKeyLeaf; + Pgno pgno; + + + u8 leaf; + u8 hdrOffset; + u8 childPtrSize; + u8 max1bytePayload; + u8 nOverflow; + u16 maxLocal; + u16 minLocal; + u16 cellOffset; + int nFree; + u16 nCell; + u16 maskPage; + u16 aiOvfl[4]; + + u8 *apOvfl[4]; + BtShared *pBt; + u8 *aData; + u8 *aDataEnd; + u8 *aCellIdx; + u8 *aDataOfst; + DbPage *pDbPage; + u16 (*xCellSize)(MemPage*,u8*); + void (*xParseCell)(MemPage*,u8*,CellInfo*); +}; +# 312 "src/btreeInt.h" +struct BtLock { + Btree *pBtree; + Pgno iTable; + u8 eLock; + BtLock *pNext; +}; +# 344 "src/btreeInt.h" +struct Btree { + sqlite3 *db; + BtShared *pBt; + u8 inTrans; + u8 sharable; + u8 locked; + u8 hasIncrblobCur; + int wantToLock; + int nBackup; + u32 iDataVersion; + Btree *pNext; + Btree *pPrev; + + BtLock lock; + +}; +# 407 "src/btreeInt.h" +struct BtShared { + Pager *pPager; + sqlite3 *db; + BtCursor *pCursor; + MemPage *pPage1; + u8 openFlags; + + u8 autoVacuum; + u8 incrVacuum; + u8 bDoTruncate; + + u8 inTransaction; + u8 max1bytePayload; + + + + u16 btsFlags; + u16 maxLocal; + u16 minLocal; + u16 maxLeaf; + u16 minLeaf; + u32 pageSize; + u32 usableSize; + int nTransaction; + u32 nPage; + void *pSchema; + void (*xFreeSchema)(void*); + sqlite3_mutex *mutex; + Bitvec *pHasContent; + + int nRef; + BtShared *pNext; + BtLock *pLock; + Btree *pWriter; + + u8 *pTmpSpace; +}; +# 463 "src/btreeInt.h" +struct CellInfo { + i64 nKey; + u8 *pPayload; + u32 nPayload; + u16 nLocal; + u16 nSize; +}; +# 508 "src/btreeInt.h" +struct BtCursor { + u8 eState; + u8 curFlags; + u8 curPagerFlags; + u8 hints; + int skipNext; + + Btree *pBtree; + Pgno *aOverflow; + void *pKey; + + + + + BtShared *pBt; + BtCursor *pNext; + CellInfo info; + i64 nKey; + Pgno pgnoRoot; + i8 iPage; + u8 curIntKey; + u16 ix; + u16 aiIdx[20 -1]; + struct KeyInfo *pKeyInfo; + MemPage *pPage; + MemPage *apPage[20 -1]; +}; +# 675 "src/btreeInt.h" +typedef struct IntegrityCk IntegrityCk; +struct IntegrityCk { + BtShared *pBt; + Pager *pPager; + u8 *aPgRef; + Pgno nPage; + int mxErr; + int nErr; + int mallocFailed; + const char *zPfx; + int v1, v2; + StrAccum errMsg; + u32 *heap; +}; +# 17 "src/btree.c" 2 + + + + + +static const char zMagicHeader[] = "SQLite format 3"; +# 77 "src/btree.c" +static BtShared * sqlite3SharedCacheList = 0; +# 89 "src/btree.c" +int sqlite3_enable_shared_cache(int enable){ + sqlite3Config.sharedCacheEnabled = enable; + return 0; +} +# 275 "src/btree.c" +static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){ + BtShared *pBt = p->pBt; + BtLock *pIter; + + assert( sqlite3BtreeHoldsMutex(p) ); + assert( eLock==1 || eLock==2 ); + assert( p->db!=0 ); + assert( !(p->db->flags&0x00000400)||eLock==2||iTab==1 ); + + + + + + assert( eLock==1 || (p==pBt->pWriter && p->inTrans==2) ); + assert( eLock==1 || pBt->inTransaction==2 ); + + + if( !p->sharable ){ + return 0; + } + + + + + if( pBt->pWriter!=p && (pBt->btsFlags & 0x0040)!=0 ){ + ; + return (6 | (1<<8)); + } + + for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ +# 314 "src/btree.c" + assert( pIter->eLock==1 || pIter->eLock==2 ); + assert( eLock==1 || pIter->pBtree==p || pIter->eLock==1); + if( pIter->pBtree!=p && pIter->iTable==iTab && pIter->eLock!=eLock ){ + ; + if( eLock==2 ){ + assert( p==pBt->pWriter ); + pBt->btsFlags |= 0x0080; + } + return (6 | (1<<8)); + } + } + return 0; +} +# 347 "src/btree.c" +static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){ + BtShared *pBt = p->pBt; + BtLock *pLock = 0; + BtLock *pIter; + + assert( sqlite3BtreeHoldsMutex(p) ); + assert( eLock==1 || eLock==2 ); + assert( p->db!=0 ); + + + + + + assert( 0==(p->db->flags&0x00000400) || eLock==2 ); + + + + assert( p->sharable ); + assert( 0==querySharedCacheTableLock(p, iTable, eLock) ); + + + for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ + if( pIter->iTable==iTable && pIter->pBtree==p ){ + pLock = pIter; + break; + } + } + + + + + if( !pLock ){ + pLock = (BtLock *)sqlite3MallocZero(sizeof(BtLock)); + if( !pLock ){ + return 7; + } + pLock->iTable = iTable; + pLock->pBtree = p; + pLock->pNext = pBt->pLock; + pBt->pLock = pLock; + } + + + + + + assert( 2>1 ); + if( eLock>pLock->eLock ){ + pLock->eLock = eLock; + } + + return 0; +} +# 411 "src/btree.c" +static void clearAllSharedCacheTableLocks(Btree *p){ + BtShared *pBt = p->pBt; + BtLock **ppIter = &pBt->pLock; + + assert( sqlite3BtreeHoldsMutex(p) ); + assert( p->sharable || 0==*ppIter ); + assert( p->inTrans>0 ); + + while( *ppIter ){ + BtLock *pLock = *ppIter; + assert( (pBt->btsFlags & 0x0040)==0 || pBt->pWriter==pLock->pBtree ); + assert( pLock->pBtree->inTrans>=pLock->eLock ); + if( pLock->pBtree==p ){ + *ppIter = pLock->pNext; + assert( pLock->iTable!=1 || pLock==&p->lock ); + if( pLock->iTable!=1 ){ + sqlite3_free(pLock); + } + }else{ + ppIter = &pLock->pNext; + } + } + + assert( (pBt->btsFlags & 0x0080)==0 || pBt->pWriter ); + if( pBt->pWriter==p ){ + pBt->pWriter = 0; + pBt->btsFlags &= ~(0x0040|0x0080); + }else if( pBt->nTransaction==2 ){ +# 448 "src/btree.c" + pBt->btsFlags &= ~0x0080; + } +} + + + + +static void downgradeAllSharedCacheTableLocks(Btree *p){ + BtShared *pBt = p->pBt; + if( pBt->pWriter==p ){ + BtLock *pLock; + pBt->pWriter = 0; + pBt->btsFlags &= ~(0x0040|0x0080); + for(pLock=pBt->pLock; pLock; pLock=pLock->pNext){ + assert( pLock->eLock==1 || pLock->pBtree==p ); + pLock->eLock = 1; + } + } +} + + + +static void releasePage(MemPage *pPage); +static void releasePageOne(MemPage *pPage); +static void releasePageNotNull(MemPage *pPage); +# 508 "src/btree.c" +static void invalidateAllOverflowCache(BtShared *pBt){ + BtCursor *p; + assert( sqlite3_mutex_held(pBt->mutex) ); + for(p=pBt->pCursor; p; p=p->pNext){ + (p->curFlags &= ~0x04); + } +} +# 530 "src/btree.c" +static void invalidateIncrblobCursors( + Btree *pBtree, + Pgno pgnoRoot, + i64 iRow, + int isClearTable +){ + BtCursor *p; + if( pBtree->hasIncrblobCur==0 ) return; + assert( sqlite3BtreeHoldsMutex(pBtree) ); + pBtree->hasIncrblobCur = 0; + for(p=pBtree->pBt->pCursor; p; p=p->pNext){ + if( (p->curFlags & 0x10)!=0 ){ + pBtree->hasIncrblobCur = 1; + if( p->pgnoRoot==pgnoRoot && (isClearTable || p->info.nKey==iRow) ){ + p->eState = 1; + } + } + } +} +# 590 "src/btree.c" +static int btreeSetHasContent(BtShared *pBt, Pgno pgno){ + int rc = 0; + if( !pBt->pHasContent ){ + assert( pgno<=pBt->nPage ); + pBt->pHasContent = sqlite3BitvecCreate(pBt->nPage); + if( !pBt->pHasContent ){ + rc = 7; + } + } + if( rc==0 && pgno<=sqlite3BitvecSize(pBt->pHasContent) ){ + rc = sqlite3BitvecSet(pBt->pHasContent, pgno); + } + return rc; +} +# 612 "src/btree.c" +static int btreeGetHasContent(BtShared *pBt, Pgno pgno){ + Bitvec *p = pBt->pHasContent; + return (p && (pgno>sqlite3BitvecSize(p) || sqlite3BitvecTest(p, pgno))); +} + + + + + +static void btreeClearHasContent(BtShared *pBt){ + sqlite3BitvecDestroy(pBt->pHasContent); + pBt->pHasContent = 0; +} + + + + +static void btreeReleaseAllCursorPages(BtCursor *pCur){ + int i; + if( pCur->iPage>=0 ){ + for(i=0; i<pCur->iPage; i++){ + releasePageNotNull(pCur->apPage[i]); + } + releasePageNotNull(pCur->pPage); + pCur->iPage = -1; + } +} +# 653 "src/btree.c" +static int saveCursorKey(BtCursor *pCur){ + int rc = 0; + assert( 0==pCur->eState ); + assert( 0==pCur->pKey ); + assert( cursorHoldsMutex(pCur) ); + + if( pCur->curIntKey ){ + + pCur->nKey = sqlite3BtreeIntegerKey(pCur); + }else{ + + + + + + + void *pKey; + pCur->nKey = sqlite3BtreePayloadSize(pCur); + pKey = sqlite3Malloc( pCur->nKey + 9 + 8 ); + if( pKey ){ + rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey); + if( rc==0 ){ + memset(((u8*)pKey)+pCur->nKey, 0, 9+8); + pCur->pKey = pKey; + }else{ + sqlite3_free(pKey); + } + }else{ + rc = 7; + } + } + assert( !pCur->curIntKey || !pCur->pKey ); + return rc; +} +# 695 "src/btree.c" +static int saveCursorPosition(BtCursor *pCur){ + int rc; + + assert( 0==pCur->eState || 2==pCur->eState ); + assert( 0==pCur->pKey ); + assert( cursorHoldsMutex(pCur) ); + + if( pCur->eState==2 ){ + pCur->eState = 0; + }else{ + pCur->skipNext = 0; + } + + rc = saveCursorKey(pCur); + if( rc==0 ){ + btreeReleaseAllCursorPages(pCur); + pCur->eState = 3; + } + + pCur->curFlags &= ~(0x02|0x04|0x08); + return rc; +} + + +static int saveCursorsOnList(BtCursor*,Pgno,BtCursor*); +# 742 "src/btree.c" +static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){ + BtCursor *p; + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( pExcept==0 || pExcept->pBt==pBt ); + for(p=pBt->pCursor; p; p=p->pNext){ + if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ) break; + } + if( p ) return saveCursorsOnList(p, iRoot, pExcept); + if( pExcept ) pExcept->curFlags &= ~0x20; + return 0; +} + + + + + + +static int saveCursorsOnList( + BtCursor *p, + Pgno iRoot, + BtCursor *pExcept +){ + do{ + if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ){ + if( p->eState==0 || p->eState==2 ){ + int rc = saveCursorPosition(p); + if( 0!=rc ){ + return rc; + } + }else{ + ; + btreeReleaseAllCursorPages(p); + } + } + p = p->pNext; + }while( p ); + return 0; +} + + + + +void sqlite3BtreeClearCursor(BtCursor *pCur){ + assert( cursorHoldsMutex(pCur) ); + sqlite3_free(pCur->pKey); + pCur->pKey = 0; + pCur->eState = 1; +} + + + + + + +static int btreeMoveto( + BtCursor *pCur, + const void *pKey, + i64 nKey, + int bias, + int *pRes +){ + int rc; + UnpackedRecord *pIdxKey; + + if( pKey ){ + KeyInfo *pKeyInfo = pCur->pKeyInfo; + assert( nKey==(i64)(int)nKey ); + pIdxKey = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); + if( pIdxKey==0 ) return 7; + sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey); + if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){ + rc = sqlite3CorruptError(813); + goto moveto_done; + } + }else{ + pIdxKey = 0; + } + rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes); +moveto_done: + if( pIdxKey ){ + sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey); + } + return rc; +} +# 834 "src/btree.c" +static int btreeRestoreCursorPosition(BtCursor *pCur){ + int rc; + int skipNext = 0; + assert( cursorOwnsBtShared(pCur) ); + assert( pCur->eState>=3 ); + if( pCur->eState==4 ){ + return pCur->skipNext; + } + pCur->eState = 1; + if( sqlite3FaultSim(410) ){ + rc = 10; + }else{ + rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext); + } + if( rc==0 ){ + sqlite3_free(pCur->pKey); + pCur->pKey = 0; + assert( pCur->eState==0 || pCur->eState==1 ); + if( skipNext ) pCur->skipNext = skipNext; + if( pCur->skipNext && pCur->eState==0 ){ + pCur->eState = 2; + } + } + return rc; +} +# 877 "src/btree.c" +int sqlite3BtreeCursorHasMoved(BtCursor *pCur){ + assert( ((((char*)(pCur) - (char*)0)&7)==0) + || pCur==sqlite3BtreeFakeValidCursor() ); + assert( ((int)((char*)&((BtCursor*)0)->eState))==0 ); + assert( sizeof(pCur->eState)==1 ); + return 0 != *(u8*)pCur; +} + + + + + + +BtCursor *sqlite3BtreeFakeValidCursor(void){ + static u8 fakeCursor = 0; + assert( ((int)((char*)&((BtCursor*)0)->eState))==0 ); + return (BtCursor*)&fakeCursor; +} +# 909 "src/btree.c" +int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow){ + int rc; + + assert( pCur!=0 ); + assert( pCur->eState!=0 ); + rc = (pCur->eState>=3 ? btreeRestoreCursorPosition(pCur) : 0); + if( rc ){ + *pDifferentRow = 1; + return rc; + } + if( pCur->eState!=0 ){ + *pDifferentRow = 1; + }else{ + *pDifferentRow = 0; + } + return 0; +} +# 941 "src/btree.c" +void sqlite3BtreeCursorHintFlags(BtCursor *pCur, unsigned x){ + assert( x==0x00000002 || x==0x00000001 || x==0 ); + pCur->hints = x; +} +# 957 "src/btree.c" +static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){ + int nPagesPerMapPage; + Pgno iPtrMap, ret; + assert( sqlite3_mutex_held(pBt->mutex) ); + if( pgno<2 ) return 0; + nPagesPerMapPage = (pBt->usableSize/5)+1; + iPtrMap = (pgno-2)/nPagesPerMapPage; + ret = (iPtrMap*nPagesPerMapPage) + 2; + if( ret==((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1)) ){ + ret++; + } + return ret; +} +# 981 "src/btree.c" +static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ + DbPage *pDbPage; + u8 *pPtrmap; + Pgno iPtrmap; + int offset; + int rc; + + if( *pRC ) return; + + assert( sqlite3_mutex_held(pBt->mutex) ); + + assert( 0==(ptrmapPageno((pBt), (((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1))))==(((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1)))) ); + + assert( pBt->autoVacuum ); + if( key==0 ){ + *pRC = sqlite3CorruptError(996); + return; + } + iPtrmap = ptrmapPageno(pBt, key); + rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage, 0); + if( rc!=0 ){ + *pRC = rc; + return; + } + if( ((char*)sqlite3PagerGetExtra(pDbPage))[0]!=0 ){ + + + + *pRC = sqlite3CorruptError(1009); + goto ptrmap_exit; + } + offset = (5*(key-iPtrmap-1)); + if( offset<0 ){ + *pRC = sqlite3CorruptError(1014); + goto ptrmap_exit; + } + assert( offset <= (int)pBt->usableSize-5 ); + pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); + + if( eType!=pPtrmap[offset] || sqlite3Get4byte(&pPtrmap[offset+1])!=parent ){ + ; + *pRC= rc = sqlite3PagerWrite(pDbPage); + if( rc==0 ){ + pPtrmap[offset] = eType; + sqlite3Put4byte(&pPtrmap[offset+1], parent); + } + } + +ptrmap_exit: + sqlite3PagerUnref(pDbPage); +} +# 1040 "src/btree.c" +static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ + DbPage *pDbPage; + int iPtrmap; + u8 *pPtrmap; + int offset; + int rc; + + assert( sqlite3_mutex_held(pBt->mutex) ); + + iPtrmap = ptrmapPageno(pBt, key); + rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage, 0); + if( rc!=0 ){ + return rc; + } + pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); + + offset = (5*(key-iPtrmap-1)); + if( offset<0 ){ + sqlite3PagerUnref(pDbPage); + return sqlite3CorruptError(1059); + } + assert( offset <= (int)pBt->usableSize-5 ); + assert( pEType!=0 ); + *pEType = pPtrmap[offset]; + if( pPgno ) *pPgno = sqlite3Get4byte(&pPtrmap[offset+1]); + + sqlite3PagerUnref(pDbPage); + if( *pEType<1 || *pEType>5 ) return sqlite3CorruptError(1067); + return 0; +} +# 1099 "src/btree.c" +static void btreeParseCellAdjustSizeForOverflow( + MemPage *pPage, + u8 *pCell, + CellInfo *pInfo +){ +# 1113 "src/btree.c" + int minLocal; + int maxLocal; + int surplus; + + minLocal = pPage->minLocal; + maxLocal = pPage->maxLocal; + surplus = minLocal + (pInfo->nPayload - minLocal)%(pPage->pBt->usableSize-4); + ; + ; + if( surplus <= maxLocal ){ + pInfo->nLocal = (u16)surplus; + }else{ + pInfo->nLocal = (u16)minLocal; + } + pInfo->nSize = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell) + 4; +} +# 1144 "src/btree.c" +static void btreeParseCellPtrNoPayload( + MemPage *pPage, + u8 *pCell, + CellInfo *pInfo +){ + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( pPage->leaf==0 ); + assert( pPage->childPtrSize==4 ); + + (void)(pPage); + + pInfo->nSize = 4 + sqlite3GetVarint(&pCell[4], (u64*)&pInfo->nKey); + pInfo->nPayload = 0; + pInfo->nLocal = 0; + pInfo->pPayload = 0; + return; +} +static void btreeParseCellPtr( + MemPage *pPage, + u8 *pCell, + CellInfo *pInfo +){ + u8 *pIter; + u32 nPayload; + u64 iKey; + + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( pPage->leaf==0 || pPage->leaf==1 ); + assert( pPage->intKeyLeaf ); + assert( pPage->childPtrSize==0 ); + pIter = pCell; + + + + + + + + nPayload = *pIter; + if( nPayload>=0x80 ){ + u8 *pEnd = &pIter[8]; + nPayload &= 0x7f; + do{ + nPayload = (nPayload<<7) | (*++pIter & 0x7f); + }while( (*pIter)>=0x80 && pIter<pEnd ); + } + pIter++; + + + + + + + + iKey = *pIter; + if( iKey>=0x80 ){ + u8 *pEnd = &pIter[7]; + iKey &= 0x7f; + while(1){ + iKey = (iKey<<7) | (*++pIter & 0x7f); + if( (*pIter)<0x80 ) break; + if( pIter>=pEnd ){ + iKey = (iKey<<8) | *++pIter; + break; + } + } + } + pIter++; + + pInfo->nKey = *(i64*)&iKey; + pInfo->nPayload = nPayload; + pInfo->pPayload = pIter; + ; + ; + if( nPayload<=pPage->maxLocal ){ + + + + pInfo->nSize = nPayload + (u16)(pIter - pCell); + if( pInfo->nSize<4 ) pInfo->nSize = 4; + pInfo->nLocal = (u16)nPayload; + }else{ + btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo); + } +} +static void btreeParseCellPtrIndex( + MemPage *pPage, + u8 *pCell, + CellInfo *pInfo +){ + u8 *pIter; + u32 nPayload; + + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( pPage->leaf==0 || pPage->leaf==1 ); + assert( pPage->intKeyLeaf==0 ); + pIter = pCell + pPage->childPtrSize; + nPayload = *pIter; + if( nPayload>=0x80 ){ + u8 *pEnd = &pIter[8]; + nPayload &= 0x7f; + do{ + nPayload = (nPayload<<7) | (*++pIter & 0x7f); + }while( *(pIter)>=0x80 && pIter<pEnd ); + } + pIter++; + pInfo->nKey = nPayload; + pInfo->nPayload = nPayload; + pInfo->pPayload = pIter; + ; + ; + if( nPayload<=pPage->maxLocal ){ + + + + pInfo->nSize = nPayload + (u16)(pIter - pCell); + if( pInfo->nSize<4 ) pInfo->nSize = 4; + pInfo->nLocal = (u16)nPayload; + }else{ + btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo); + } +} +static void btreeParseCell( + MemPage *pPage, + int iCell, + CellInfo *pInfo +){ + pPage->xParseCell(pPage, ((pPage)->aData + ((pPage)->maskPage & __builtin_bswap16(*(u16*)(&(pPage)->aCellIdx[2*(iCell)])))), pInfo); +} +# 1286 "src/btree.c" +static u16 cellSizePtr(MemPage *pPage, u8 *pCell){ + u8 *pIter = pCell + pPage->childPtrSize; + u8 *pEnd; + u32 nSize; +# 1300 "src/btree.c" + nSize = *pIter; + if( nSize>=0x80 ){ + pEnd = &pIter[8]; + nSize &= 0x7f; + do{ + nSize = (nSize<<7) | (*++pIter & 0x7f); + }while( *(pIter)>=0x80 && pIter<pEnd ); + } + pIter++; + if( pPage->intKey ){ + + + + pEnd = &pIter[9]; + while( (*pIter++)&0x80 && pIter<pEnd ); + } + ; + ; + if( nSize<=pPage->maxLocal ){ + nSize += (u32)(pIter - pCell); + if( nSize<4 ) nSize = 4; + }else{ + int minLocal = pPage->minLocal; + nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4); + ; + ; + if( nSize>pPage->maxLocal ){ + nSize = minLocal; + } + nSize += 4 + (u16)(pIter - pCell); + } + assert( nSize==debuginfo.nSize || (sqlite3Config.neverCorrupt==0) ); + return (u16)nSize; +} +static u16 cellSizePtrNoPayload(MemPage *pPage, u8 *pCell){ + u8 *pIter = pCell + 4; + u8 *pEnd; +# 1346 "src/btree.c" + (void)(pPage); + + + assert( pPage->childPtrSize==4 ); + pEnd = pIter + 9; + while( (*pIter++)&0x80 && pIter<pEnd ); + assert( debuginfo.nSize==(u16)(pIter - pCell) || (sqlite3Config.neverCorrupt==0) ); + return (u16)(pIter - pCell); +} +# 1372 "src/btree.c" +static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){ + CellInfo info; + if( *pRC ) return; + assert( pCell!=0 ); + pPage->xParseCell(pPage, pCell, &info); + if( info.nLocal<info.nPayload ){ + Pgno ovfl; + if( (((uptr)(pSrc->aDataEnd)>=(uptr)(pCell))&&((uptr)(pSrc->aDataEnd)<(uptr)(pCell+info.nLocal))) ){ + ; + *pRC = sqlite3CorruptError(1381); + return; + } + ovfl = sqlite3Get4byte(&pCell[info.nSize-4]); + ptrmapPut(pPage->pBt, ovfl, 3, pPage->pgno, pRC); + } +} +# 1403 "src/btree.c" +static int defragmentPage(MemPage *pPage, int nMaxFrag){ + int i; + int pc; + int hdr; + int size; + int usableSize; + int cellOffset; + int cbrk; + int nCell; + unsigned char *data; + unsigned char *temp; + unsigned char *src; + int iCellFirst; + int iCellLast; + + assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + assert( pPage->pBt!=0 ); + assert( pPage->pBt->usableSize <= 65536 ); + assert( pPage->nOverflow==0 ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + temp = 0; + src = data = pPage->aData; + hdr = pPage->hdrOffset; + cellOffset = pPage->cellOffset; + nCell = pPage->nCell; + assert( nCell==((&data[hdr+3])[0]<<8 | (&data[hdr+3])[1]) || (sqlite3Config.neverCorrupt==0) ); + iCellFirst = cellOffset + 2*nCell; + usableSize = pPage->pBt->usableSize; + + + + + + + if( (int)data[hdr+7]<=nMaxFrag ){ + int iFree = ((&data[hdr+1])[0]<<8 | (&data[hdr+1])[1]); + if( iFree>usableSize-4 ) return sqlite3CorruptError(1439); + if( iFree ){ + int iFree2 = ((&data[iFree])[0]<<8 | (&data[iFree])[1]); + if( iFree2>usableSize-4 ) return sqlite3CorruptError(1442); + if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){ + u8 *pEnd = &data[cellOffset + nCell*2]; + u8 *pAddr; + int sz2 = 0; + int sz = ((&data[iFree+2])[0]<<8 | (&data[iFree+2])[1]); + int top = ((&data[hdr+5])[0]<<8 | (&data[hdr+5])[1]); + if( top>=iFree ){ + return sqlite3CorruptError(1450); + } + if( iFree2 ){ + if( iFree+sz>iFree2 ) return sqlite3CorruptError(1453); + sz2 = ((&data[iFree2+2])[0]<<8 | (&data[iFree2+2])[1]); + if( iFree2+sz2 > usableSize ) return sqlite3CorruptError(1455); + memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz)); + sz += sz2; + }else if( iFree+sz>usableSize ){ + return sqlite3CorruptError(1459); + } + + cbrk = top+sz; + assert( cbrk+(iFree-top) <= usableSize ); + memmove(&data[cbrk], &data[top], iFree-top); + for(pAddr=&data[cellOffset]; pAddr<pEnd; pAddr+=2){ + pc = ((pAddr)[0]<<8 | (pAddr)[1]); + if( pc<iFree ){ ((pAddr)[0] = (u8)((pc+sz)>>8), (pAddr)[1] = (u8)(pc+sz)); } + else if( pc<iFree2 ){ ((pAddr)[0] = (u8)((pc+sz2)>>8), (pAddr)[1] = (u8)(pc+sz2)); } + } + goto defragment_out; + } + } + } + + cbrk = usableSize; + iCellLast = usableSize - 4; + for(i=0; i<nCell; i++){ + u8 *pAddr; + pAddr = &data[cellOffset + i*2]; + pc = ((pAddr)[0]<<8 | (pAddr)[1]); + ; + ; + + + + if( pc<iCellFirst || pc>iCellLast ){ + return sqlite3CorruptError(1487); + } + assert( pc>=iCellFirst && pc<=iCellLast ); + size = pPage->xCellSize(pPage, &src[pc]); + cbrk -= size; + if( cbrk<iCellFirst || pc+size>usableSize ){ + return sqlite3CorruptError(1493); + } + assert( cbrk+size<=usableSize && cbrk>=iCellFirst ); + ; + ; + ((pAddr)[0] = (u8)((cbrk)>>8), (pAddr)[1] = (u8)(cbrk)); + if( temp==0 ){ + int x; + if( cbrk==pc ) continue; + temp = sqlite3PagerTempSpace(pPage->pBt->pPager); + x = ((&data[hdr+5])[0]<<8 | (&data[hdr+5])[1]); + memcpy(&temp[x], &data[x], (cbrk+size) - x); + src = temp; + } + memcpy(&data[cbrk], &src[pc], size); + } + data[hdr+7] = 0; + + defragment_out: + assert( pPage->nFree>=0 ); + if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){ + return sqlite3CorruptError(1514); + } + assert( cbrk>=iCellFirst ); + ((&data[hdr+5])[0] = (u8)((cbrk)>>8), (&data[hdr+5])[1] = (u8)(cbrk)); + data[hdr+1] = 0; + data[hdr+2] = 0; + memset(&data[iCellFirst], 0, cbrk-iCellFirst); + assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + return 0; +} +# 1539 "src/btree.c" +static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ + const int hdr = pPg->hdrOffset; + u8 * const aData = pPg->aData; + int iAddr = hdr + 1; + int pc = ((&aData[iAddr])[0]<<8 | (&aData[iAddr])[1]); + int x; + int maxPC = pPg->pBt->usableSize - nByte; + int size; + + assert( pc>0 ); + while( pc<=maxPC ){ + + + + size = ((&aData[pc+2])[0]<<8 | (&aData[pc+2])[1]); + if( (x = size - nByte)>=0 ){ + ; + ; + if( x<4 ){ + + + if( aData[hdr+7]>57 ) return 0; + + + + memcpy(&aData[iAddr], &aData[pc], 2); + aData[hdr+7] += (u8)x; + }else if( x+pc > maxPC ){ + + *pRc = sqlite3CorruptError(1568); + return 0; + }else{ + + + ((&aData[pc+2])[0] = (u8)((x)>>8), (&aData[pc+2])[1] = (u8)(x)); + } + return &aData[pc + x]; + } + iAddr = pc; + pc = ((&aData[pc])[0]<<8 | (&aData[pc])[1]); + if( pc<=iAddr+size ){ + if( pc ){ + + *pRc = sqlite3CorruptError(1582); + } + return 0; + } + } + if( pc>maxPC+nByte-4 ){ + + *pRc = sqlite3CorruptError(1589); + } + return 0; +} +# 1607 "src/btree.c" +static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ + const int hdr = pPage->hdrOffset; + u8 * const data = pPage->aData; + int top; + int rc = 0; + int gap; + + assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + assert( pPage->pBt ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( nByte>=0 ); + assert( pPage->nFree>=nByte ); + assert( pPage->nOverflow==0 ); + assert( nByte < (int)(pPage->pBt->usableSize-8) ); + + assert( pPage->cellOffset == hdr + 12 - 4*pPage->leaf ); + gap = pPage->cellOffset + 2*pPage->nCell; + assert( gap<=65536 ); + + + + + + top = ((&data[hdr+5])[0]<<8 | (&data[hdr+5])[1]); + assert( top<=(int)pPage->pBt->usableSize ); + if( gap>top ){ + if( top==0 && pPage->pBt->usableSize==65536 ){ + top = 65536; + }else{ + return sqlite3CorruptError(1636); + } + } + + + + + + ; + ; + ; + if( (data[hdr+2] || data[hdr+1]) && gap+2<=top ){ + u8 *pSpace = pageFindSlot(pPage, nByte, &rc); + if( pSpace ){ + assert( pSpace>=data && (pSpace - data)<65536 ); + *pIdx = (int)(pSpace - data); + return 0; + }else if( rc ){ + return rc; + } + } + + + + + ; + if( gap+2+nByte>top ){ + assert( pPage->nCell>0 || (sqlite3Config.neverCorrupt==0) ); + assert( pPage->nFree>=0 ); + rc = defragmentPage(pPage, ((4)<(pPage->nFree - (2+nByte))?(4):(pPage->nFree - (2+nByte)))); + if( rc ) return rc; + top = (((((int)((&data[hdr+5])[0]<<8 | (&data[hdr+5])[1]))-1)&0xffff)+1); + assert( gap+2+nByte<=top ); + } +# 1678 "src/btree.c" + top -= nByte; + ((&data[hdr+5])[0] = (u8)((top)>>8), (&data[hdr+5])[1] = (u8)(top)); + assert( top+nByte <= (int)pPage->pBt->usableSize ); + *pIdx = top; + return 0; +} +# 1698 "src/btree.c" +static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ + u16 iPtr; + u16 iFreeBlk; + u8 hdr; + u8 nFrag = 0; + u16 iOrigSize = iSize; + u16 x; + u32 iEnd = iStart + iSize; + unsigned char *data = pPage->aData; + + assert( pPage->pBt!=0 ); + assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + assert( (sqlite3Config.neverCorrupt==0) || iStart>=pPage->hdrOffset+6+pPage->childPtrSize ); + assert( (sqlite3Config.neverCorrupt==0) || iEnd <= pPage->pBt->usableSize ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( iSize>=4 ); + assert( iStart<=pPage->pBt->usableSize-4 ); + + + + + hdr = pPage->hdrOffset; + iPtr = hdr + 1; + if( data[iPtr+1]==0 && data[iPtr]==0 ){ + iFreeBlk = 0; + }else{ + while( (iFreeBlk = ((&data[iPtr])[0]<<8 | (&data[iPtr])[1]))<iStart ){ + if( iFreeBlk<iPtr+4 ){ + if( iFreeBlk==0 ) break; + return sqlite3CorruptError(1727); + } + iPtr = iFreeBlk; + } + if( iFreeBlk>pPage->pBt->usableSize-4 ){ + return sqlite3CorruptError(1732); + } + assert( iFreeBlk>iPtr || iFreeBlk==0 ); + + + + + + + + if( iFreeBlk && iEnd+3>=iFreeBlk ){ + nFrag = iFreeBlk - iEnd; + if( iEnd>iFreeBlk ) return sqlite3CorruptError(1744); + iEnd = iFreeBlk + ((&data[iFreeBlk+2])[0]<<8 | (&data[iFreeBlk+2])[1]); + if( iEnd > pPage->pBt->usableSize ){ + return sqlite3CorruptError(1747); + } + iSize = iEnd - iStart; + iFreeBlk = ((&data[iFreeBlk])[0]<<8 | (&data[iFreeBlk])[1]); + } + + + + + + if( iPtr>hdr+1 ){ + int iPtrEnd = iPtr + ((&data[iPtr+2])[0]<<8 | (&data[iPtr+2])[1]); + if( iPtrEnd+3>=iStart ){ + if( iPtrEnd>iStart ) return sqlite3CorruptError(1760); + nFrag += iStart - iPtrEnd; + iSize = iEnd - iPtr; + iStart = iPtr; + } + } + if( nFrag>data[hdr+7] ) return sqlite3CorruptError(1766); + data[hdr+7] -= nFrag; + } + x = ((&data[hdr+5])[0]<<8 | (&data[hdr+5])[1]); + if( iStart<=x ){ + + + + if( iStart<x || iPtr!=hdr+1 ) return sqlite3CorruptError(1774); + ((&data[hdr+1])[0] = (u8)((iFreeBlk)>>8), (&data[hdr+1])[1] = (u8)(iFreeBlk)); + ((&data[hdr+5])[0] = (u8)((iEnd)>>8), (&data[hdr+5])[1] = (u8)(iEnd)); + }else{ + + ((&data[iPtr])[0] = (u8)((iStart)>>8), (&data[iPtr])[1] = (u8)(iStart)); + } + if( pPage->pBt->btsFlags & 0x000c ){ + + + memset(&data[iStart], 0, iSize); + } + ((&data[iStart])[0] = (u8)((iFreeBlk)>>8), (&data[iStart])[1] = (u8)(iFreeBlk)); + ((&data[iStart+2])[0] = (u8)((iSize)>>8), (&data[iStart+2])[1] = (u8)(iSize)); + pPage->nFree += iOrigSize; + return 0; +} +# 1804 "src/btree.c" +static int decodeFlags(MemPage *pPage, int flagByte){ + BtShared *pBt; + + assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + pPage->leaf = (u8)(flagByte>>3); assert( 0x08 == 1<<3 ); + flagByte &= ~0x08; + pPage->childPtrSize = 4-4*pPage->leaf; + pPage->xCellSize = cellSizePtr; + pBt = pPage->pBt; + if( flagByte==(0x04 | 0x01) ){ + + + assert( (0x04|0x01)==5 ); + + + assert( (0x04|0x01|0x08)==13 ); + pPage->intKey = 1; + if( pPage->leaf ){ + pPage->intKeyLeaf = 1; + pPage->xParseCell = btreeParseCellPtr; + }else{ + pPage->intKeyLeaf = 0; + pPage->xCellSize = cellSizePtrNoPayload; + pPage->xParseCell = btreeParseCellPtrNoPayload; + } + pPage->maxLocal = pBt->maxLeaf; + pPage->minLocal = pBt->minLeaf; + }else if( flagByte==0x02 ){ + + + assert( (0x02)==2 ); + + + assert( (0x02|0x08)==10 ); + pPage->intKey = 0; + pPage->intKeyLeaf = 0; + pPage->xParseCell = btreeParseCellPtrIndex; + pPage->maxLocal = pBt->maxLocal; + pPage->minLocal = pBt->minLocal; + }else{ + + + return sqlite3CorruptError(1847); + } + pPage->max1bytePayload = pBt->max1bytePayload; + return 0; +} + + + + + +static int btreeComputeFreeSpace(MemPage *pPage){ + int pc; + u8 hdr; + u8 *data; + int usableSize; + int nFree; + int top; + int iCellFirst; + int iCellLast; + + assert( pPage->pBt!=0 ); + assert( pPage->pBt->db!=0 ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); + assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); + assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); + assert( pPage->isInit==1 ); + assert( pPage->nFree<0 ); + + usableSize = pPage->pBt->usableSize; + hdr = pPage->hdrOffset; + data = pPage->aData; + + + + top = (((((int)((&data[hdr+5])[0]<<8 | (&data[hdr+5])[1]))-1)&0xffff)+1); + iCellFirst = hdr + 8 + pPage->childPtrSize + 2*pPage->nCell; + iCellLast = usableSize - 4; + + + + + + pc = ((&data[hdr+1])[0]<<8 | (&data[hdr+1])[1]); + nFree = data[hdr+7] + top; + if( pc>0 ){ + u32 next, size; + if( pc<iCellFirst ){ + + + + return sqlite3CorruptError(1898); + } + while( 1 ){ + if( pc>iCellLast ){ + + return sqlite3CorruptError(1903); + } + next = ((&data[pc])[0]<<8 | (&data[pc])[1]); + size = ((&data[pc+2])[0]<<8 | (&data[pc+2])[1]); + nFree = nFree + size; + if( next<=pc+size+3 ) break; + pc = next; + } + if( next>0 ){ + + return sqlite3CorruptError(1913); + } + if( pc+size>(unsigned int)usableSize ){ + + return sqlite3CorruptError(1917); + } + } +# 1928 "src/btree.c" + if( nFree>usableSize || nFree<iCellFirst ){ + return sqlite3CorruptError(1929); + } + pPage->nFree = (u16)(nFree - iCellFirst); + return 0; +} + + + + + +static int btreeCellSizeCheck(MemPage *pPage){ + int iCellFirst; + int iCellLast; + int i; + int sz; + int pc; + u8 *data; + int usableSize; + int cellOffset; + + iCellFirst = pPage->cellOffset + 2*pPage->nCell; + usableSize = pPage->pBt->usableSize; + iCellLast = usableSize - 4; + data = pPage->aData; + cellOffset = pPage->cellOffset; + if( !pPage->leaf ) iCellLast--; + for(i=0; i<pPage->nCell; i++){ + pc = __builtin_bswap16(*(u16*)(&data[cellOffset+i*2])); + ; + ; + if( pc<iCellFirst || pc>iCellLast ){ + return sqlite3CorruptError(1960); + } + sz = pPage->xCellSize(pPage, &data[pc]); + ; + if( pc+sz>usableSize ){ + return sqlite3CorruptError(1965); + } + } + return 0; +} +# 1980 "src/btree.c" +static int btreeInitPage(MemPage *pPage){ + u8 *data; + BtShared *pBt; + + assert( pPage->pBt!=0 ); + assert( pPage->pBt->db!=0 ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); + assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); + assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); + assert( pPage->isInit==0 ); + + pBt = pPage->pBt; + data = pPage->aData + pPage->hdrOffset; + + + if( decodeFlags(pPage, data[0]) ){ + return sqlite3CorruptError(1997); + } + assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); + pPage->maskPage = (u16)(pBt->pageSize - 1); + pPage->nOverflow = 0; + pPage->cellOffset = pPage->hdrOffset + 8 + pPage->childPtrSize; + pPage->aCellIdx = data + pPage->childPtrSize + 8; + pPage->aDataEnd = pPage->aData + pBt->usableSize; + pPage->aDataOfst = pPage->aData + pPage->childPtrSize; + + + pPage->nCell = ((&data[3])[0]<<8 | (&data[3])[1]); + if( pPage->nCell>((pBt->pageSize-8)/6) ){ + + return sqlite3CorruptError(2011); + } + ; + + + + + assert( pPage->nCell>0 + || (((((int)((&data[5])[0]<<8 | (&data[5])[1]))-1)&0xffff)+1)==(int)pBt->usableSize + || (sqlite3Config.neverCorrupt==0) ); + pPage->nFree = -1; + pPage->isInit = 1; + if( pBt->db->flags & 0x00200000 ){ + return btreeCellSizeCheck(pPage); + } + return 0; +} + + + + + +static void zeroPage(MemPage *pPage, int flags){ + unsigned char *data = pPage->aData; + BtShared *pBt = pPage->pBt; + u8 hdr = pPage->hdrOffset; + u16 first; + + assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno ); + assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); + assert( sqlite3PagerGetData(pPage->pDbPage) == data ); + assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + assert( sqlite3_mutex_held(pBt->mutex) ); + if( pBt->btsFlags & 0x000c ){ + memset(&data[hdr], 0, pBt->usableSize - hdr); + } + data[hdr] = (char)flags; + first = hdr + ((flags&0x08)==0 ? 12 : 8); + memset(&data[hdr+1], 0, 4); + data[hdr+7] = 0; + ((&data[hdr+5])[0] = (u8)((pBt->usableSize)>>8), (&data[hdr+5])[1] = (u8)(pBt->usableSize)); + pPage->nFree = (u16)(pBt->usableSize - first); + decodeFlags(pPage, flags); + pPage->cellOffset = first; + pPage->aDataEnd = &data[pBt->usableSize]; + pPage->aCellIdx = &data[first]; + pPage->aDataOfst = &data[pPage->childPtrSize]; + pPage->nOverflow = 0; + assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); + pPage->maskPage = (u16)(pBt->pageSize - 1); + pPage->nCell = 0; + pPage->isInit = 1; +} + + + + + + +static MemPage *btreePageFromDbPage(DbPage *pDbPage, Pgno pgno, BtShared *pBt){ + MemPage *pPage = (MemPage*)sqlite3PagerGetExtra(pDbPage); + if( pgno!=pPage->pgno ){ + pPage->aData = sqlite3PagerGetData(pDbPage); + pPage->pDbPage = pDbPage; + pPage->pBt = pBt; + pPage->pgno = pgno; + pPage->hdrOffset = pgno==1 ? 100 : 0; + } + assert( pPage->aData==sqlite3PagerGetData(pDbPage) ); + return pPage; +} +# 2094 "src/btree.c" +static int btreeGetPage( + BtShared *pBt, + Pgno pgno, + MemPage **ppPage, + int flags +){ + int rc; + DbPage *pDbPage; + + assert( flags==0 || flags==0x01 || flags==0x02 ); + assert( sqlite3_mutex_held(pBt->mutex) ); + rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, flags); + if( rc ) return rc; + *ppPage = btreePageFromDbPage(pDbPage, pgno, pBt); + return 0; +} + + + + + + +static MemPage *btreePageLookup(BtShared *pBt, Pgno pgno){ + DbPage *pDbPage; + assert( sqlite3_mutex_held(pBt->mutex) ); + pDbPage = sqlite3PagerLookup(pBt->pPager, pgno); + if( pDbPage ){ + return btreePageFromDbPage(pDbPage, pgno, pBt); + } + return 0; +} + + + + + +static Pgno btreePagecount(BtShared *pBt){ + return pBt->nPage; +} +u32 sqlite3BtreeLastPage(Btree *p){ + assert( sqlite3BtreeHoldsMutex(p) ); + assert( ((p->pBt->nPage)&0x80000000)==0 ); + return btreePagecount(p->pBt); +} +# 2152 "src/btree.c" +static int getAndInitPage( + BtShared *pBt, + Pgno pgno, + MemPage **ppPage, + BtCursor *pCur, + int bReadOnly +){ + int rc; + DbPage *pDbPage; + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( pCur==0 || ppPage==&pCur->pPage ); + assert( pCur==0 || bReadOnly==pCur->curPagerFlags ); + assert( pCur==0 || pCur->iPage>0 ); + + if( pgno>btreePagecount(pBt) ){ + rc = sqlite3CorruptError(2167); + goto getAndInitPage_error1; + } + rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly); + if( rc ){ + goto getAndInitPage_error1; + } + *ppPage = (MemPage*)sqlite3PagerGetExtra(pDbPage); + if( (*ppPage)->isInit==0 ){ + btreePageFromDbPage(pDbPage, pgno, pBt); + rc = btreeInitPage(*ppPage); + if( rc!=0 ){ + goto getAndInitPage_error2; + } + } + assert( (*ppPage)->pgno==pgno ); + assert( (*ppPage)->aData==sqlite3PagerGetData(pDbPage) ); + + + + if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){ + rc = sqlite3CorruptError(2188); + goto getAndInitPage_error2; + } + return 0; + +getAndInitPage_error2: + releasePage(*ppPage); +getAndInitPage_error1: + if( pCur ){ + pCur->iPage--; + pCur->pPage = pCur->apPage[pCur->iPage]; + } + ; + assert( pgno!=0 || rc==11 ); + return rc; +} + + + + + + + +static void releasePageNotNull(MemPage *pPage){ + assert( pPage->aData ); + assert( pPage->pBt ); + assert( pPage->pDbPage!=0 ); + assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); + assert( sqlite3PagerGetData(pPage->pDbPage)==pPage->aData ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + sqlite3PagerUnrefNotNull(pPage->pDbPage); +} +static void releasePage(MemPage *pPage){ + if( pPage ) releasePageNotNull(pPage); +} +static void releasePageOne(MemPage *pPage){ + assert( pPage!=0 ); + assert( pPage->aData ); + assert( pPage->pBt ); + assert( pPage->pDbPage!=0 ); + assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); + assert( sqlite3PagerGetData(pPage->pDbPage)==pPage->aData ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + sqlite3PagerUnrefPageOne(pPage->pDbPage); +} +# 2243 "src/btree.c" +static int btreeGetUnusedPage( + BtShared *pBt, + Pgno pgno, + MemPage **ppPage, + int flags +){ + int rc = btreeGetPage(pBt, pgno, ppPage, flags); + if( rc==0 ){ + if( sqlite3PagerPageRefcount((*ppPage)->pDbPage)>1 ){ + releasePage(*ppPage); + *ppPage = 0; + return sqlite3CorruptError(2254); + } + (*ppPage)->isInit = 0; + }else{ + *ppPage = 0; + } + return rc; +} +# 2272 "src/btree.c" +static void pageReinit(DbPage *pData){ + MemPage *pPage; + pPage = (MemPage *)sqlite3PagerGetExtra(pData); + assert( sqlite3PagerPageRefcount(pData)>0 ); + if( pPage->isInit ){ + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + pPage->isInit = 0; + if( sqlite3PagerPageRefcount(pData)>1 ){ + + + + + + + btreeInitPage(pPage); + } + } +} + + + + +static int btreeInvokeBusyHandler(void *pArg){ + BtShared *pBt = (BtShared*)pArg; + assert( pBt->db ); + assert( sqlite3_mutex_held(pBt->db->mutex) ); + return sqlite3InvokeBusyHandler(&pBt->db->busyHandler, + sqlite3PagerFile(pBt->pPager)); +} +# 2323 "src/btree.c" +int sqlite3BtreeOpen( + sqlite3_vfs *pVfs, + const char *zFilename, + sqlite3 *db, + Btree **ppBtree, + int flags, + int vfsFlags +){ + BtShared *pBt = 0; + Btree *p; + sqlite3_mutex *mutexOpen = 0; + int rc = 0; + u8 nReserve; + unsigned char zDbHeader[100]; + + + const int isTempDb = zFilename==0 || zFilename[0]==0; + + + + + + + + const int isMemdb = (zFilename && strcmp(zFilename, ":memory:")==0) + || (isTempDb && sqlite3TempInMemory(db)) + || (vfsFlags & 0x00000080)!=0; + + + assert( db!=0 ); + assert( pVfs!=0 ); + assert( sqlite3_mutex_held(db->mutex) ); + assert( (flags&0xff)==flags ); + + + assert( (flags & 8)==0 || (flags & 4)!=0 ); + + + assert( (flags & 4)==0 || isTempDb ); + + if( isMemdb ){ + flags |= 2; + } + if( (vfsFlags & 0x00000100)!=0 && (isMemdb || isTempDb) ){ + vfsFlags = (vfsFlags & ~0x00000100) | 0x00000200; + } + p = sqlite3MallocZero(sizeof(Btree)); + if( !p ){ + return 7; + } + p->inTrans = 0; + p->db = db; + + p->lock.pBtree = p; + p->lock.iTable = 1; + + + + + + + + if( isTempDb==0 && (isMemdb==0 || (vfsFlags&0x00000040)!=0) ){ + if( vfsFlags & 0x00020000 ){ + int nFilename = sqlite3Strlen30(zFilename)+1; + int nFullPathname = pVfs->mxPathname+1; + char *zFullPathname = sqlite3Malloc(((nFullPathname)>(nFilename)?(nFullPathname):(nFilename))); + sqlite3_mutex *mutexShared; + + p->sharable = 1; + if( !zFullPathname ){ + sqlite3_free(p); + return 7; + } + if( isMemdb ){ + memcpy(zFullPathname, zFilename, nFilename); + }else{ + rc = sqlite3OsFullPathname(pVfs, zFilename, + nFullPathname, zFullPathname); + if( rc ){ + sqlite3_free(zFullPathname); + sqlite3_free(p); + return rc; + } + } + + mutexOpen = sqlite3MutexAlloc(4); + sqlite3_mutex_enter(mutexOpen); + mutexShared = sqlite3MutexAlloc(2); + sqlite3_mutex_enter(mutexShared); + + for(pBt=sqlite3SharedCacheList; pBt; pBt=pBt->pNext){ + assert( pBt->nRef>0 ); + if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt->pPager, 0)) + && sqlite3PagerVfs(pBt->pPager)==pVfs ){ + int iDb; + for(iDb=db->nDb-1; iDb>=0; iDb--){ + Btree *pExisting = db->aDb[iDb].pBt; + if( pExisting && pExisting->pBt==pBt ){ + sqlite3_mutex_leave(mutexShared); + sqlite3_mutex_leave(mutexOpen); + sqlite3_free(zFullPathname); + sqlite3_free(p); + return 19; + } + } + p->pBt = pBt; + pBt->nRef++; + break; + } + } + sqlite3_mutex_leave(mutexShared); + sqlite3_free(zFullPathname); + } +# 2447 "src/btree.c" + } + + if( pBt==0 ){ + + + + + + assert( sizeof(i64)==8 ); + assert( sizeof(u64)==8 ); + assert( sizeof(u32)==4 ); + assert( sizeof(u16)==2 ); + assert( sizeof(Pgno)==4 ); + + pBt = sqlite3MallocZero( sizeof(*pBt) ); + if( pBt==0 ){ + rc = 7; + goto btree_open_out; + } + rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename, + sizeof(MemPage), flags, vfsFlags, pageReinit); + if( rc==0 ){ + sqlite3PagerSetMmapLimit(pBt->pPager, db->szMmap); + rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader); + } + if( rc!=0 ){ + goto btree_open_out; + } + pBt->openFlags = (u8)flags; + pBt->db = db; + sqlite3PagerSetBusyHandler(pBt->pPager, btreeInvokeBusyHandler, pBt); + p->pBt = pBt; + + pBt->pCursor = 0; + pBt->pPage1 = 0; + if( sqlite3PagerIsreadonly(pBt->pPager) ) pBt->btsFlags |= 0x0001; +# 2491 "src/btree.c" + pBt->pageSize = (zDbHeader[16]<<8) | (zDbHeader[17]<<16); + if( pBt->pageSize<512 || pBt->pageSize>65536 + || ((pBt->pageSize-1)&pBt->pageSize)!=0 ){ + pBt->pageSize = 0; + + + + + + + + if( zFilename && !isMemdb ){ + pBt->autoVacuum = (0 ? 1 : 0); + pBt->incrVacuum = (0==2 ? 1 : 0); + } + + nReserve = 0; + }else{ + + + + nReserve = zDbHeader[20]; + pBt->btsFlags |= 0x0002; + + pBt->autoVacuum = (sqlite3Get4byte(&zDbHeader[36 + 4*4])?1:0); + pBt->incrVacuum = (sqlite3Get4byte(&zDbHeader[36 + 7*4])?1:0); + + } + rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, nReserve); + if( rc ) goto btree_open_out; + pBt->usableSize = pBt->pageSize - nReserve; + assert( (pBt->pageSize & 7)==0 ); + + + + + pBt->nRef = 1; + if( p->sharable ){ + sqlite3_mutex *mutexShared; + mutexShared = sqlite3MutexAlloc(2); + if( 1 && sqlite3Config.bCoreMutex ){ + pBt->mutex = sqlite3MutexAlloc(0); + if( pBt->mutex==0 ){ + rc = 7; + goto btree_open_out; + } + } + sqlite3_mutex_enter(mutexShared); + pBt->pNext = sqlite3SharedCacheList; + sqlite3SharedCacheList = pBt; + sqlite3_mutex_leave(mutexShared); + } + + } + + + + + + + if( p->sharable ){ + int i; + Btree *pSib; + for(i=0; i<db->nDb; i++){ + if( (pSib = db->aDb[i].pBt)!=0 && pSib->sharable ){ + while( pSib->pPrev ){ pSib = pSib->pPrev; } + if( (uptr)p->pBt<(uptr)pSib->pBt ){ + p->pNext = pSib; + p->pPrev = 0; + pSib->pPrev = p; + }else{ + while( pSib->pNext && (uptr)pSib->pNext->pBt<(uptr)p->pBt ){ + pSib = pSib->pNext; + } + p->pNext = pSib->pNext; + p->pPrev = pSib; + if( p->pNext ){ + p->pNext->pPrev = p; + } + pSib->pNext = p; + } + break; + } + } + } + + *ppBtree = p; + +btree_open_out: + if( rc!=0 ){ + if( pBt && pBt->pPager ){ + sqlite3PagerClose(pBt->pPager, 0); + } + sqlite3_free(pBt); + sqlite3_free(p); + *ppBtree = 0; + }else{ + sqlite3_file *pFile; + + + + + + if( sqlite3BtreeSchema(p, 0, 0)==0 ){ + sqlite3PagerSetCachesize(p->pBt->pPager, -2000); + } + + pFile = sqlite3PagerFile(pBt->pPager); + if( pFile->pMethods ){ + sqlite3OsFileControlHint(pFile, 30, (void*)&pBt->db); + } + } + if( mutexOpen ){ + assert( sqlite3_mutex_held(mutexOpen) ); + sqlite3_mutex_leave(mutexOpen); + } + assert( rc!=0 || sqlite3BtreeConnectionCount(*ppBtree)>0 ); + return rc; +} + + + + + + + +static int removeFromSharingList(BtShared *pBt){ + + sqlite3_mutex *pMaster; + BtShared *pList; + int removed = 0; + + assert( sqlite3_mutex_notheld(pBt->mutex) ); + pMaster = sqlite3MutexAlloc(2); + sqlite3_mutex_enter(pMaster); + pBt->nRef--; + if( pBt->nRef<=0 ){ + if( sqlite3SharedCacheList==pBt ){ + sqlite3SharedCacheList = pBt->pNext; + }else{ + pList = sqlite3SharedCacheList; + while( (pList) && pList->pNext!=pBt ){ + pList=pList->pNext; + } + if( (pList) ){ + pList->pNext = pBt->pNext; + } + } + if( 1 ){ + sqlite3_mutex_free(pBt->mutex); + } + removed = 1; + } + sqlite3_mutex_leave(pMaster); + return removed; + + + +} + + + + + + +static void allocateTempSpace(BtShared *pBt){ + if( !pBt->pTmpSpace ){ + pBt->pTmpSpace = sqlite3PageMalloc( pBt->pageSize ); +# 2675 "src/btree.c" + if( pBt->pTmpSpace ){ + memset(pBt->pTmpSpace, 0, 8); + pBt->pTmpSpace += 4; + } + } +} + + + + +static void freeTempSpace(BtShared *pBt){ + if( pBt->pTmpSpace ){ + pBt->pTmpSpace -= 4; + sqlite3PageFree(pBt->pTmpSpace); + pBt->pTmpSpace = 0; + } +} + + + + +int sqlite3BtreeClose(Btree *p){ + BtShared *pBt = p->pBt; + BtCursor *pCur; + + + assert( sqlite3_mutex_held(p->db->mutex) ); + sqlite3BtreeEnter(p); + pCur = pBt->pCursor; + while( pCur ){ + BtCursor *pTmp = pCur; + pCur = pCur->pNext; + if( pTmp->pBtree==p ){ + sqlite3BtreeCloseCursor(pTmp); + } + } + + + + + + sqlite3BtreeRollback(p, 0, 0); + sqlite3BtreeLeave(p); + + + + + + assert( p->wantToLock==0 && p->locked==0 ); + if( !p->sharable || removeFromSharingList(pBt) ){ + + + + + + assert( !pBt->pCursor ); + sqlite3PagerClose(pBt->pPager, p->db); + if( pBt->xFreeSchema && pBt->pSchema ){ + pBt->xFreeSchema(pBt->pSchema); + } + sqlite3DbFree(0, pBt->pSchema); + freeTempSpace(pBt); + sqlite3_free(pBt); + } + + + assert( p->wantToLock==0 ); + assert( p->locked==0 ); + if( p->pPrev ) p->pPrev->pNext = p->pNext; + if( p->pNext ) p->pNext->pPrev = p->pPrev; + + + sqlite3_free(p); + return 0; +} +# 2758 "src/btree.c" +int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){ + BtShared *pBt = p->pBt; + assert( sqlite3_mutex_held(p->db->mutex) ); + sqlite3BtreeEnter(p); + sqlite3PagerSetCachesize(pBt->pPager, mxPage); + sqlite3BtreeLeave(p); + return 0; +} +# 2777 "src/btree.c" +int sqlite3BtreeSetSpillSize(Btree *p, int mxPage){ + BtShared *pBt = p->pBt; + int res; + assert( sqlite3_mutex_held(p->db->mutex) ); + sqlite3BtreeEnter(p); + res = sqlite3PagerSetSpillsize(pBt->pPager, mxPage); + sqlite3BtreeLeave(p); + return res; +} + + + + + + +int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){ + BtShared *pBt = p->pBt; + assert( sqlite3_mutex_held(p->db->mutex) ); + sqlite3BtreeEnter(p); + sqlite3PagerSetMmapLimit(pBt->pPager, szMmap); + sqlite3BtreeLeave(p); + return 0; +} +# 2811 "src/btree.c" +int sqlite3BtreeSetPagerFlags( + Btree *p, + unsigned pgFlags +){ + BtShared *pBt = p->pBt; + assert( sqlite3_mutex_held(p->db->mutex) ); + sqlite3BtreeEnter(p); + sqlite3PagerSetFlags(pBt->pPager, pgFlags); + sqlite3BtreeLeave(p); + return 0; +} +# 2844 "src/btree.c" +int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){ + int rc = 0; + BtShared *pBt = p->pBt; + assert( nReserve>=-1 && nReserve<=255 ); + sqlite3BtreeEnter(p); + + + + if( pBt->btsFlags & 0x0002 ){ + sqlite3BtreeLeave(p); + return 8; + } + if( nReserve<0 ){ + nReserve = pBt->pageSize - pBt->usableSize; + } + assert( nReserve>=0 && nReserve<=255 ); + if( pageSize>=512 && pageSize<=65536 && + ((pageSize-1)&pageSize)==0 ){ + assert( (pageSize & 7)==0 ); + assert( !pBt->pCursor ); + pBt->pageSize = (u32)pageSize; + freeTempSpace(pBt); + } + rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, nReserve); + pBt->usableSize = pBt->pageSize - (u16)nReserve; + if( iFix ) pBt->btsFlags |= 0x0002; + sqlite3BtreeLeave(p); + return rc; +} + + + + +int sqlite3BtreeGetPageSize(Btree *p){ + return p->pBt->pageSize; +} +# 2892 "src/btree.c" +int sqlite3BtreeGetReserveNoMutex(Btree *p){ + int n; + assert( sqlite3_mutex_held(p->pBt->mutex) ); + n = p->pBt->pageSize - p->pBt->usableSize; + return n; +} +# 2908 "src/btree.c" +int sqlite3BtreeGetOptimalReserve(Btree *p){ + int n; + sqlite3BtreeEnter(p); + n = sqlite3BtreeGetReserveNoMutex(p); + + + + sqlite3BtreeLeave(p); + return n; +} + + + + + + + +int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){ + int n; + sqlite3BtreeEnter(p); + n = sqlite3PagerMaxPageCount(p->pBt->pPager, mxPage); + sqlite3BtreeLeave(p); + return n; +} +# 2951 "src/btree.c" +int sqlite3BtreeSecureDelete(Btree *p, int newFlag){ + int b; + if( p==0 ) return 0; + sqlite3BtreeEnter(p); + assert( 0x0008==0x0004*2 ); + assert( 0x000c==(0x0008|0x0004) ); + if( newFlag>=0 ){ + p->pBt->btsFlags &= ~0x000c; + p->pBt->btsFlags |= 0x0004*newFlag; + } + b = (p->pBt->btsFlags & 0x000c)/0x0004; + sqlite3BtreeLeave(p); + return b; +} + + + + + + + +int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){ + + + + BtShared *pBt = p->pBt; + int rc = 0; + u8 av = (u8)autoVacuum; + + sqlite3BtreeEnter(p); + if( (pBt->btsFlags & 0x0002)!=0 && (av ?1:0)!=pBt->autoVacuum ){ + rc = 8; + }else{ + pBt->autoVacuum = av ?1:0; + pBt->incrVacuum = av==2 ?1:0; + } + sqlite3BtreeLeave(p); + return rc; + +} + + + + + +int sqlite3BtreeGetAutoVacuum(Btree *p){ + + + + int rc; + sqlite3BtreeEnter(p); + rc = ( + (!p->pBt->autoVacuum)?0: + (!p->pBt->incrVacuum)?1: + 2 + ); + sqlite3BtreeLeave(p); + return rc; + +} +# 3040 "src/btree.c" +static int newDatabase(BtShared*); +# 3052 "src/btree.c" +static int lockBtree(BtShared *pBt){ + int rc; + MemPage *pPage1; + u32 nPage; + u32 nPageFile = 0; + u32 nPageHeader; + + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( pBt->pPage1==0 ); + rc = sqlite3PagerSharedLock(pBt->pPager); + if( rc!=0 ) return rc; + rc = btreeGetPage(pBt, 1, &pPage1, 0); + if( rc!=0 ) return rc; + + + + + nPage = nPageHeader = sqlite3Get4byte(28+(u8*)pPage1->aData); + sqlite3PagerPagecount(pBt->pPager, (int*)&nPageFile); + if( nPage==0 || memcmp(24+(u8*)pPage1->aData, 92+(u8*)pPage1->aData,4)!=0 ){ + nPage = nPageFile; + } + if( (pBt->db->flags & 0x02000000)!=0 ){ + nPage = 0; + } + if( nPage>0 ){ + u32 pageSize; + u32 usableSize; + u8 *page1 = pPage1->aData; + rc = 26; + + + + if( memcmp(page1, zMagicHeader, 16)!=0 ){ + goto page1_init_failed; + } +# 3097 "src/btree.c" + if( page1[18]>2 ){ + pBt->btsFlags |= 0x0001; + } + if( page1[19]>2 ){ + goto page1_init_failed; + } +# 3112 "src/btree.c" + if( page1[19]==2 && (pBt->btsFlags & 0x0020)==0 ){ + int isOpen = 0; + rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen); + if( rc!=0 ){ + goto page1_init_failed; + }else{ + ; + if( isOpen==0 ){ + releasePageOne(pPage1); + return 0; + } + } + rc = 26; + }else{ + ; + } +# 3136 "src/btree.c" + if( memcmp(&page1[21], "\100\040\040",3)!=0 ){ + goto page1_init_failed; + } + + + + pageSize = (page1[16]<<8) | (page1[17]<<16); + + + if( ((pageSize-1)&pageSize)!=0 + || pageSize>65536 + || pageSize<=256 + ){ + goto page1_init_failed; + } + pBt->btsFlags |= 0x0002; + assert( (pageSize & 7)==0 ); + + + + + + + + usableSize = pageSize - page1[20]; + if( (u32)pageSize!=pBt->pageSize ){ + + + + + + + releasePageOne(pPage1); + pBt->usableSize = usableSize; + pBt->pageSize = pageSize; + freeTempSpace(pBt); + rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, + pageSize-usableSize); + return rc; + } + if( sqlite3WritableSchema(pBt->db)==0 && nPage>nPageFile ){ + rc = sqlite3CorruptError(3177); + goto page1_init_failed; + } + + + + if( usableSize<480 ){ + goto page1_init_failed; + } + pBt->pageSize = pageSize; + pBt->usableSize = usableSize; + + pBt->autoVacuum = (sqlite3Get4byte(&page1[36 + 4*4])?1:0); + pBt->incrVacuum = (sqlite3Get4byte(&page1[36 + 7*4])?1:0); + + } +# 3207 "src/btree.c" + pBt->maxLocal = (u16)((pBt->usableSize-12)*64/255 - 23); + pBt->minLocal = (u16)((pBt->usableSize-12)*32/255 - 23); + pBt->maxLeaf = (u16)(pBt->usableSize - 35); + pBt->minLeaf = (u16)((pBt->usableSize-12)*32/255 - 23); + if( pBt->maxLocal>127 ){ + pBt->max1bytePayload = 127; + }else{ + pBt->max1bytePayload = (u8)pBt->maxLocal; + } + assert( pBt->maxLeaf + 23 <= ((int)(pBt->pageSize-8)) ); + pBt->pPage1 = pPage1; + pBt->nPage = nPage; + return 0; + +page1_init_failed: + releasePageOne(pPage1); + pBt->pPage1 = 0; + return rc; +} +# 3259 "src/btree.c" +static void unlockBtreeIfUnused(BtShared *pBt){ + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( countValidCursors(pBt,0)==0 || pBt->inTransaction>0 ); + if( pBt->inTransaction==0 && pBt->pPage1!=0 ){ + MemPage *pPage1 = pBt->pPage1; + assert( pPage1->aData ); + assert( sqlite3PagerRefcount(pBt->pPager)==1 ); + pBt->pPage1 = 0; + releasePageOne(pPage1); + } +} + + + + + + +static int newDatabase(BtShared *pBt){ + MemPage *pP1; + unsigned char *data; + int rc; + + assert( sqlite3_mutex_held(pBt->mutex) ); + if( pBt->nPage>0 ){ + return 0; + } + pP1 = pBt->pPage1; + assert( pP1!=0 ); + data = pP1->aData; + rc = sqlite3PagerWrite(pP1->pDbPage); + if( rc ) return rc; + memcpy(data, zMagicHeader, sizeof(zMagicHeader)); + assert( sizeof(zMagicHeader)==16 ); + data[16] = (u8)((pBt->pageSize>>8)&0xff); + data[17] = (u8)((pBt->pageSize>>16)&0xff); + data[18] = 1; + data[19] = 1; + assert( pBt->usableSize<=pBt->pageSize && pBt->usableSize+255>=pBt->pageSize); + data[20] = (u8)(pBt->pageSize - pBt->usableSize); + data[21] = 64; + data[22] = 32; + data[23] = 32; + memset(&data[24], 0, 100-24); + zeroPage(pP1, 0x01|0x08|0x04 ); + pBt->btsFlags |= 0x0002; + + assert( pBt->autoVacuum==1 || pBt->autoVacuum==0 ); + assert( pBt->incrVacuum==1 || pBt->incrVacuum==0 ); + sqlite3Put4byte(&data[36 + 4*4], pBt->autoVacuum); + sqlite3Put4byte(&data[36 + 7*4], pBt->incrVacuum); + + pBt->nPage = 1; + data[31] = 1; + return 0; +} + + + + + + +int sqlite3BtreeNewDb(Btree *p){ + int rc; + sqlite3BtreeEnter(p); + p->pBt->nPage = 0; + rc = newDatabase(p->pBt); + sqlite3BtreeLeave(p); + return rc; +} +# 3364 "src/btree.c" +int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){ + BtShared *pBt = p->pBt; + int rc = 0; + + sqlite3BtreeEnter(p); + assert( p->pBt->inTransaction!=0 || p->pBt->nTransaction==0 ); assert( p->pBt->inTransaction>=p->inTrans );; + + + + + + if( p->inTrans==2 || (p->inTrans==1 && !wrflag) ){ + goto trans_begun; + } + assert( pBt->inTransaction==2 || (pBt->bDoTruncate)==0 ); + + if( (p->db->flags & 0x02000000) + && sqlite3PagerIsreadonly(pBt->pPager)==0 + ){ + pBt->btsFlags &= ~0x0001; + } + + + if( (pBt->btsFlags & 0x0001)!=0 && wrflag ){ + rc = 8; + goto trans_begun; + } + + + { + sqlite3 *pBlock = 0; + + + + + if( (wrflag && pBt->inTransaction==2) + || (pBt->btsFlags & 0x0080)!=0 + ){ + pBlock = pBt->pWriter->db; + }else if( wrflag>1 ){ + BtLock *pIter; + for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ + if( pIter->pBtree!=p ){ + pBlock = pIter->pBtree->db; + break; + } + } + } + if( pBlock ){ + ; + rc = (6 | (1<<8)); + goto trans_begun; + } + } + + + + + + rc = querySharedCacheTableLock(p, 1, 1); + if( 0!=rc ) goto trans_begun; + + pBt->btsFlags &= ~0x0010; + if( pBt->nPage==0 ) pBt->btsFlags |= 0x0010; + do { + + + + + + + + while( pBt->pPage1==0 && 0==(rc = lockBtree(pBt)) ); + + if( rc==0 && wrflag ){ + if( (pBt->btsFlags & 0x0001)!=0 ){ + rc = 8; + }else{ + rc = sqlite3PagerBegin(pBt->pPager,wrflag>1,sqlite3TempInMemory(p->db)); + if( rc==0 ){ + rc = newDatabase(pBt); + }else if( rc==(5 | (2<<8)) && pBt->inTransaction==0 ){ + + + + rc = 5; + } + } + } + + if( rc!=0 ){ + unlockBtreeIfUnused(pBt); + } + }while( (rc&0xFF)==5 && pBt->inTransaction==0 && + btreeInvokeBusyHandler(pBt) ); + ; + + if( rc==0 ){ + if( p->inTrans==0 ){ + pBt->nTransaction++; + + if( p->sharable ){ + assert( p->lock.pBtree==p && p->lock.iTable==1 ); + p->lock.eLock = 1; + p->lock.pNext = pBt->pLock; + pBt->pLock = &p->lock; + } + + } + p->inTrans = (wrflag?2:1); + if( p->inTrans>pBt->inTransaction ){ + pBt->inTransaction = p->inTrans; + } + if( wrflag ){ + MemPage *pPage1 = pBt->pPage1; + + assert( !pBt->pWriter ); + pBt->pWriter = p; + pBt->btsFlags &= ~0x0040; + if( wrflag>1 ) pBt->btsFlags |= 0x0040; +# 3492 "src/btree.c" + if( pBt->nPage!=sqlite3Get4byte(&pPage1->aData[28]) ){ + rc = sqlite3PagerWrite(pPage1->pDbPage); + if( rc==0 ){ + sqlite3Put4byte(&pPage1->aData[28], pBt->nPage); + } + } + } + } + +trans_begun: + if( rc==0 ){ + if( pSchemaVersion ){ + *pSchemaVersion = sqlite3Get4byte(&pBt->pPage1->aData[40]); + } + if( wrflag ){ + + + + + rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint); + } + } + + assert( p->pBt->inTransaction!=0 || p->pBt->nTransaction==0 ); assert( p->pBt->inTransaction>=p->inTrans );; + sqlite3BtreeLeave(p); + return rc; +} +# 3527 "src/btree.c" +static int setChildPtrmaps(MemPage *pPage){ + int i; + int nCell; + int rc; + BtShared *pBt = pPage->pBt; + Pgno pgno = pPage->pgno; + + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + rc = pPage->isInit ? 0 : btreeInitPage(pPage); + if( rc!=0 ) return rc; + nCell = pPage->nCell; + + for(i=0; i<nCell; i++){ + u8 *pCell = ((pPage)->aData + ((pPage)->maskPage & __builtin_bswap16(*(u16*)(&(pPage)->aCellIdx[2*(i)])))); + + ptrmapPutOvflPtr(pPage, pPage, pCell, &rc); + + if( !pPage->leaf ){ + Pgno childPgno = sqlite3Get4byte(pCell); + ptrmapPut(pBt, childPgno, 5, pgno, &rc); + } + } + + if( !pPage->leaf ){ + Pgno childPgno = sqlite3Get4byte(&pPage->aData[pPage->hdrOffset+8]); + ptrmapPut(pBt, childPgno, 5, pgno, &rc); + } + + return rc; +} +# 3572 "src/btree.c" +static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + if( eType==4 ){ + + if( sqlite3Get4byte(pPage->aData)!=iFrom ){ + return sqlite3CorruptError(3578); + } + sqlite3Put4byte(pPage->aData, iTo); + }else{ + int i; + int nCell; + int rc; + + rc = pPage->isInit ? 0 : btreeInitPage(pPage); + if( rc ) return rc; + nCell = pPage->nCell; + + for(i=0; i<nCell; i++){ + u8 *pCell = ((pPage)->aData + ((pPage)->maskPage & __builtin_bswap16(*(u16*)(&(pPage)->aCellIdx[2*(i)])))); + if( eType==3 ){ + CellInfo info; + pPage->xParseCell(pPage, pCell, &info); + if( info.nLocal<info.nPayload ){ + if( pCell+info.nSize > pPage->aData+pPage->pBt->usableSize ){ + return sqlite3CorruptError(3597); + } + if( iFrom==sqlite3Get4byte(pCell+info.nSize-4) ){ + sqlite3Put4byte(pCell+info.nSize-4, iTo); + break; + } + } + }else{ + if( sqlite3Get4byte(pCell)==iFrom ){ + sqlite3Put4byte(pCell, iTo); + break; + } + } + } + + if( i==nCell ){ + if( eType!=5 || + sqlite3Get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){ + return sqlite3CorruptError(3615); + } + sqlite3Put4byte(&pPage->aData[pPage->hdrOffset+8], iTo); + } + } + return 0; +} +# 3633 "src/btree.c" +static int relocatePage( + BtShared *pBt, + MemPage *pDbPage, + u8 eType, + Pgno iPtrPage, + Pgno iFreePage, + int isCommit +){ + MemPage *pPtrPage; + Pgno iDbPage = pDbPage->pgno; + Pager *pPager = pBt->pPager; + int rc; + + assert( eType==4 || eType==3 || + eType==5 || eType==1 ); + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( pDbPage->pBt==pBt ); + if( iDbPage<3 ) return sqlite3CorruptError(3650); + + + + ; + rc = sqlite3PagerMovepage(pPager, pDbPage->pDbPage, iFreePage, isCommit); + if( rc!=0 ){ + return rc; + } + pDbPage->pgno = iFreePage; +# 3669 "src/btree.c" + if( eType==5 || eType==1 ){ + rc = setChildPtrmaps(pDbPage); + if( rc!=0 ){ + return rc; + } + }else{ + Pgno nextOvfl = sqlite3Get4byte(pDbPage->aData); + if( nextOvfl!=0 ){ + ptrmapPut(pBt, nextOvfl, 4, iFreePage, &rc); + if( rc!=0 ){ + return rc; + } + } + } + + + + + + if( eType!=1 ){ + rc = btreeGetPage(pBt, iPtrPage, &pPtrPage, 0); + if( rc!=0 ){ + return rc; + } + rc = sqlite3PagerWrite(pPtrPage->pDbPage); + if( rc!=0 ){ + releasePage(pPtrPage); + return rc; + } + rc = modifyPagePointer(pPtrPage, iDbPage, iFreePage, eType); + releasePage(pPtrPage); + if( rc==0 ){ + ptrmapPut(pBt, iFreePage, eType, iPtrPage, &rc); + } + } + return rc; +} + + +static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8); +# 3727 "src/btree.c" +static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){ + Pgno nFreeList; + int rc; + + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( iLastPg>nFin ); + + if( !(ptrmapPageno((pBt), (iLastPg))==(iLastPg)) && iLastPg!=((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1)) ){ + u8 eType; + Pgno iPtrPage; + + nFreeList = sqlite3Get4byte(&pBt->pPage1->aData[36]); + if( nFreeList==0 ){ + return 101; + } + + rc = ptrmapGet(pBt, iLastPg, &eType, &iPtrPage); + if( rc!=0 ){ + return rc; + } + if( eType==1 ){ + return sqlite3CorruptError(3748); + } + + if( eType==2 ){ + if( bCommit==0 ){ + + + + + + Pgno iFreePg; + MemPage *pFreePg; + rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, 1); + if( rc!=0 ){ + return rc; + } + assert( iFreePg==iLastPg ); + releasePage(pFreePg); + } + } else { + Pgno iFreePg; + MemPage *pLastPg; + u8 eMode = 0; + Pgno iNear = 0; + + rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0); + if( rc!=0 ){ + return rc; + } +# 3785 "src/btree.c" + if( bCommit==0 ){ + eMode = 2; + iNear = nFin; + } + do { + MemPage *pFreePg; + rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iNear, eMode); + if( rc!=0 ){ + releasePage(pLastPg); + return rc; + } + releasePage(pFreePg); + }while( bCommit && iFreePg>nFin ); + assert( iFreePg<iLastPg ); + + rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg, bCommit); + releasePage(pLastPg); + if( rc!=0 ){ + return rc; + } + } + } + + if( bCommit==0 ){ + do { + iLastPg--; + }while( iLastPg==((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1)) || (ptrmapPageno((pBt), (iLastPg))==(iLastPg)) ); + pBt->bDoTruncate = 1; + pBt->nPage = iLastPg; + } + return 0; +} + + + + + + +static Pgno finalDbSize(BtShared *pBt, Pgno nOrig, Pgno nFree){ + int nEntry; + Pgno nPtrmap; + Pgno nFin; + + nEntry = pBt->usableSize/5; + nPtrmap = (nFree-nOrig+ptrmapPageno(pBt, nOrig)+nEntry)/nEntry; + nFin = nOrig - nFree - nPtrmap; + if( nOrig>((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1)) && nFin<((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1)) ){ + nFin--; + } + while( (ptrmapPageno((pBt), (nFin))==(nFin)) || nFin==((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1)) ){ + nFin--; + } + + return nFin; +} +# 3849 "src/btree.c" +int sqlite3BtreeIncrVacuum(Btree *p){ + int rc; + BtShared *pBt = p->pBt; + + sqlite3BtreeEnter(p); + assert( pBt->inTransaction==2 && p->inTrans==2 ); + if( !pBt->autoVacuum ){ + rc = 101; + }else{ + Pgno nOrig = btreePagecount(pBt); + Pgno nFree = sqlite3Get4byte(&pBt->pPage1->aData[36]); + Pgno nFin = finalDbSize(pBt, nOrig, nFree); + + if( nOrig<nFin ){ + rc = sqlite3CorruptError(3863); + }else if( nFree>0 ){ + rc = saveAllCursors(pBt, 0, 0); + if( rc==0 ){ + invalidateAllOverflowCache(pBt); + rc = incrVacuumStep(pBt, nFin, nOrig, 0); + } + if( rc==0 ){ + rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); + sqlite3Put4byte(&pBt->pPage1->aData[28], pBt->nPage); + } + }else{ + rc = 101; + } + } + sqlite3BtreeLeave(p); + return rc; +} +# 3891 "src/btree.c" +static int autoVacuumCommit(BtShared *pBt){ + int rc = 0; + Pager *pPager = pBt->pPager; + + + assert( sqlite3_mutex_held(pBt->mutex) ); + invalidateAllOverflowCache(pBt); + assert(pBt->autoVacuum); + if( !pBt->incrVacuum ){ + Pgno nFin; + Pgno nFree; + Pgno iFree; + Pgno nOrig; + + nOrig = btreePagecount(pBt); + if( (ptrmapPageno((pBt), (nOrig))==(nOrig)) || nOrig==((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1)) ){ + + + + + return sqlite3CorruptError(3911); + } + + nFree = sqlite3Get4byte(&pBt->pPage1->aData[36]); + nFin = finalDbSize(pBt, nOrig, nFree); + if( nFin>nOrig ) return sqlite3CorruptError(3916); + if( nFin<nOrig ){ + rc = saveAllCursors(pBt, 0, 0); + } + for(iFree=nOrig; iFree>nFin && rc==0; iFree--){ + rc = incrVacuumStep(pBt, nFin, iFree, 1); + } + if( (rc==101 || rc==0) && nFree>0 ){ + rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); + sqlite3Put4byte(&pBt->pPage1->aData[32], 0); + sqlite3Put4byte(&pBt->pPage1->aData[36], 0); + sqlite3Put4byte(&pBt->pPage1->aData[28], nFin); + pBt->bDoTruncate = 1; + pBt->nPage = nFin; + } + if( rc!=0 ){ + sqlite3PagerRollback(pPager); + } + } + + assert( nRef>=sqlite3PagerRefcount(pPager) ); + return rc; +} +# 3970 "src/btree.c" +int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){ + int rc = 0; + if( p->inTrans==2 ){ + BtShared *pBt = p->pBt; + sqlite3BtreeEnter(p); + + if( pBt->autoVacuum ){ + rc = autoVacuumCommit(pBt); + if( rc!=0 ){ + sqlite3BtreeLeave(p); + return rc; + } + } + if( pBt->bDoTruncate ){ + sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage); + } + + rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0); + sqlite3BtreeLeave(p); + } + return rc; +} + + + + + +static void btreeEndTransaction(Btree *p){ + BtShared *pBt = p->pBt; + sqlite3 *db = p->db; + assert( sqlite3BtreeHoldsMutex(p) ); + + + pBt->bDoTruncate = 0; + + if( p->inTrans>0 && db->nVdbeRead>1 ){ + + + + downgradeAllSharedCacheTableLocks(p); + p->inTrans = 1; + }else{ + + + + + if( p->inTrans!=0 ){ + clearAllSharedCacheTableLocks(p); + pBt->nTransaction--; + if( 0==pBt->nTransaction ){ + pBt->inTransaction = 0; + } + } + + + + p->inTrans = 0; + unlockBtreeIfUnused(pBt); + } + + assert( p->pBt->inTransaction!=0 || p->pBt->nTransaction==0 ); assert( p->pBt->inTransaction>=p->inTrans );; +} +# 4059 "src/btree.c" +int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){ + + if( p->inTrans==0 ) return 0; + sqlite3BtreeEnter(p); + assert( p->pBt->inTransaction!=0 || p->pBt->nTransaction==0 ); assert( p->pBt->inTransaction>=p->inTrans );; + + + + + if( p->inTrans==2 ){ + int rc; + BtShared *pBt = p->pBt; + assert( pBt->inTransaction==2 ); + assert( pBt->nTransaction>0 ); + rc = sqlite3PagerCommitPhaseTwo(pBt->pPager); + if( rc!=0 && bCleanup==0 ){ + sqlite3BtreeLeave(p); + return rc; + } + p->iDataVersion--; + pBt->inTransaction = 1; + btreeClearHasContent(pBt); + } + + btreeEndTransaction(p); + sqlite3BtreeLeave(p); + return 0; +} + + + + +int sqlite3BtreeCommit(Btree *p){ + int rc; + sqlite3BtreeEnter(p); + rc = sqlite3BtreeCommitPhaseOne(p, 0); + if( rc==0 ){ + rc = sqlite3BtreeCommitPhaseTwo(p, 0); + } + sqlite3BtreeLeave(p); + return rc; +} +# 4128 "src/btree.c" +int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){ + BtCursor *p; + int rc = 0; + + assert( (writeOnly==0 || writeOnly==1) && 0x01==1 ); + if( pBtree ){ + sqlite3BtreeEnter(pBtree); + for(p=pBtree->pBt->pCursor; p; p=p->pNext){ + if( writeOnly && (p->curFlags & 0x01)==0 ){ + if( p->eState==0 || p->eState==2 ){ + rc = saveCursorPosition(p); + if( rc!=0 ){ + (void)sqlite3BtreeTripAllCursors(pBtree, rc, 0); + break; + } + } + }else{ + sqlite3BtreeClearCursor(p); + p->eState = 4; + p->skipNext = errCode; + } + btreeReleaseAllCursorPages(p); + } + sqlite3BtreeLeave(pBtree); + } + return rc; +} + + + + + +static void btreeSetNPage(BtShared *pBt, MemPage *pPage1){ + int nPage = sqlite3Get4byte(&pPage1->aData[28]); + ; + if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage); + ; + pBt->nPage = nPage; +} +# 4179 "src/btree.c" +int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){ + int rc; + BtShared *pBt = p->pBt; + MemPage *pPage1; + + assert( writeOnly==1 || writeOnly==0 ); + assert( tripCode==(4 | (2<<8)) || tripCode==0 ); + sqlite3BtreeEnter(p); + if( tripCode==0 ){ + rc = tripCode = saveAllCursors(pBt, 0, 0); + if( rc ) writeOnly = 0; + }else{ + rc = 0; + } + if( tripCode ){ + int rc2 = sqlite3BtreeTripAllCursors(p, tripCode, writeOnly); + assert( rc==0 || (writeOnly==0 && rc2==0) ); + if( rc2!=0 ) rc = rc2; + } + assert( p->pBt->inTransaction!=0 || p->pBt->nTransaction==0 ); assert( p->pBt->inTransaction>=p->inTrans );; + + if( p->inTrans==2 ){ + int rc2; + + assert( 2==pBt->inTransaction ); + rc2 = sqlite3PagerRollback(pBt->pPager); + if( rc2!=0 ){ + rc = rc2; + } + + + + + if( btreeGetPage(pBt, 1, &pPage1, 0)==0 ){ + btreeSetNPage(pBt, pPage1); + releasePageOne(pPage1); + } + assert( countValidCursors(pBt, 1)==0 ); + pBt->inTransaction = 1; + btreeClearHasContent(pBt); + } + + btreeEndTransaction(p); + sqlite3BtreeLeave(p); + return rc; +} +# 4244 "src/btree.c" +int sqlite3BtreeBeginStmt(Btree *p, int iStatement){ + int rc; + BtShared *pBt = p->pBt; + sqlite3BtreeEnter(p); + assert( p->inTrans==2 ); + assert( (pBt->btsFlags & 0x0001)==0 ); + assert( iStatement>0 ); + assert( iStatement>p->db->nSavepoint ); + assert( pBt->inTransaction==2 ); + + + + + + rc = sqlite3PagerOpenSavepoint(pBt->pPager, iStatement); + sqlite3BtreeLeave(p); + return rc; +} +# 4275 "src/btree.c" +int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){ + int rc = 0; + if( p && p->inTrans==2 ){ + BtShared *pBt = p->pBt; + assert( op==1 || op==2 ); + assert( iSavepoint>=0 || (iSavepoint==-1 && op==2) ); + sqlite3BtreeEnter(p); + if( op==2 ){ + rc = saveAllCursors(pBt, 0, 0); + } + if( rc==0 ){ + rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint); + } + if( rc==0 ){ + if( iSavepoint<0 && (pBt->btsFlags & 0x0010)!=0 ){ + pBt->nPage = 0; + } + rc = newDatabase(pBt); + btreeSetNPage(pBt, pBt->pPage1); + + + + assert( (sqlite3Config.neverCorrupt==0) || pBt->nPage>0 ); + } + sqlite3BtreeLeave(p); + } + return rc; +} +# 4346 "src/btree.c" +static int btreeCursor( + Btree *p, + int iTable, + int wrFlag, + struct KeyInfo *pKeyInfo, + BtCursor *pCur +){ + BtShared *pBt = p->pBt; + BtCursor *pX; + + assert( sqlite3BtreeHoldsMutex(p) ); + assert( wrFlag==0 + || wrFlag==0x00000004 + || wrFlag==(0x00000004|0x00000008) + ); + + + + + + assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, (wrFlag?2:1)) ); + assert( wrFlag==0 || !hasReadConflicts(p, iTable) ); + + + assert( p->inTrans>0 ); + assert( wrFlag==0 || p->inTrans==2 ); + assert( pBt->pPage1 && pBt->pPage1->aData ); + assert( wrFlag==0 || (pBt->btsFlags & 0x0001)==0 ); + + if( wrFlag ){ + allocateTempSpace(pBt); + if( pBt->pTmpSpace==0 ) return 7; + } + if( iTable==1 && btreePagecount(pBt)==0 ){ + assert( wrFlag==0 ); + iTable = 0; + } + + + + pCur->pgnoRoot = (Pgno)iTable; + pCur->iPage = -1; + pCur->pKeyInfo = pKeyInfo; + pCur->pBtree = p; + pCur->pBt = pBt; + pCur->curFlags = wrFlag ? 0x01 : 0; + pCur->curPagerFlags = wrFlag ? 0 : 0x02; + + + for(pX=pBt->pCursor; pX; pX=pX->pNext){ + if( pX->pgnoRoot==(Pgno)iTable ){ + pX->curFlags |= 0x20; + pCur->curFlags |= 0x20; + } + } + pCur->pNext = pBt->pCursor; + pBt->pCursor = pCur; + pCur->eState = 1; + return 0; +} +int sqlite3BtreeCursor( + Btree *p, + int iTable, + int wrFlag, + struct KeyInfo *pKeyInfo, + BtCursor *pCur +){ + int rc; + if( iTable<1 ){ + rc = sqlite3CorruptError(4415); + }else{ + sqlite3BtreeEnter(p); + rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur); + sqlite3BtreeLeave(p); + } + return rc; +} +# 4432 "src/btree.c" +int sqlite3BtreeCursorSize(void){ + return (((sizeof(BtCursor))+7)&~7); +} +# 4444 "src/btree.c" +void sqlite3BtreeCursorZero(BtCursor *p){ + memset(p, 0, ((int)((char*)&((BtCursor*)0)->pBt))); +} + + + + + +int sqlite3BtreeCloseCursor(BtCursor *pCur){ + Btree *pBtree = pCur->pBtree; + if( pBtree ){ + BtShared *pBt = pCur->pBt; + sqlite3BtreeEnter(pBtree); + assert( pBt->pCursor!=0 ); + if( pBt->pCursor==pCur ){ + pBt->pCursor = pCur->pNext; + }else{ + BtCursor *pPrev = pBt->pCursor; + do{ + if( pPrev->pNext==pCur ){ + pPrev->pNext = pCur->pNext; + break; + } + pPrev = pPrev->pNext; + }while( (pPrev) ); + } + btreeReleaseAllCursorPages(pCur); + unlockBtreeIfUnused(pBt); + sqlite3_free(pCur->aOverflow); + sqlite3_free(pCur->pKey); + sqlite3BtreeLeave(pBtree); + pCur->pBtree = 0; + } + return 0; +} +# 4506 "src/btree.c" +static void getCellInfo(BtCursor *pCur){ + if( pCur->info.nSize==0 ){ + pCur->curFlags |= 0x02; + btreeParseCell(pCur->pPage,pCur->ix,&pCur->info); + }else{ + ; + } +} +# 4525 "src/btree.c" +int sqlite3BtreeCursorIsValidNN(BtCursor *pCur){ + assert( pCur!=0 ); + return pCur->eState==0; +} + + + + + + + +i64 sqlite3BtreeIntegerKey(BtCursor *pCur){ + assert( cursorHoldsMutex(pCur) ); + assert( pCur->eState==0 ); + assert( pCur->curIntKey ); + getCellInfo(pCur); + return pCur->info.nKey; +} +# 4567 "src/btree.c" +u32 sqlite3BtreePayloadSize(BtCursor *pCur){ + assert( cursorHoldsMutex(pCur) ); + assert( pCur->eState==0 ); + getCellInfo(pCur); + return pCur->info.nPayload; +} +# 4587 "src/btree.c" +sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor *pCur){ + assert( cursorHoldsMutex(pCur) ); + assert( pCur->eState==0 ); + return pCur->pBt->pageSize * (sqlite3_int64)pCur->pBt->nPage; +} +# 4612 "src/btree.c" +static int getOverflowPage( + BtShared *pBt, + Pgno ovfl, + MemPage **ppPage, + Pgno *pPgnoNext +){ + Pgno next = 0; + MemPage *pPage = 0; + int rc = 0; + + assert( sqlite3_mutex_held(pBt->mutex) ); + assert(pPgnoNext); +# 4632 "src/btree.c" + if( pBt->autoVacuum ){ + Pgno pgno; + Pgno iGuess = ovfl+1; + u8 eType; + + while( (ptrmapPageno((pBt), (iGuess))==(iGuess)) || iGuess==((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1)) ){ + iGuess++; + } + + if( iGuess<=btreePagecount(pBt) ){ + rc = ptrmapGet(pBt, iGuess, &eType, &pgno); + if( rc==0 && eType==4 && pgno==ovfl ){ + next = iGuess; + rc = 101; + } + } + } + + + assert( next==0 || rc==101 ); + if( rc==0 ){ + rc = btreeGetPage(pBt, ovfl, &pPage, (ppPage==0) ? 0x02 : 0); + assert( rc==0 || pPage==0 ); + if( rc==0 ){ + next = sqlite3Get4byte(pPage->aData); + } + } + + *pPgnoNext = next; + if( ppPage ){ + *ppPage = pPage; + }else{ + releasePage(pPage); + } + return (rc==101 ? 0 : rc); +} +# 4680 "src/btree.c" +static int copyPayload( + void *pPayload, + void *pBuf, + int nByte, + int eOp, + DbPage *pDbPage +){ + if( eOp ){ + + int rc = sqlite3PagerWrite(pDbPage); + if( rc!=0 ){ + return rc; + } + memcpy(pPayload, pBuf, nByte); + }else{ + + memcpy(pBuf, pPayload, nByte); + } + return 0; +} +# 4730 "src/btree.c" +static int accessPayload( + BtCursor *pCur, + u32 offset, + u32 amt, + unsigned char *pBuf, + int eOp +){ + unsigned char *aPayload; + int rc = 0; + int iIdx = 0; + MemPage *pPage = pCur->pPage; + BtShared *pBt = pCur->pBt; + + + + + assert( pPage ); + assert( eOp==0 || eOp==1 ); + assert( pCur->eState==0 ); + assert( pCur->ix<pPage->nCell ); + assert( cursorHoldsMutex(pCur) ); + + getCellInfo(pCur); + aPayload = pCur->info.pPayload; + assert( offset+amt <= pCur->info.nPayload ); + + assert( aPayload > pPage->aData ); + if( (uptr)(aPayload - pPage->aData) > (pBt->usableSize - pCur->info.nLocal) ){ + + + + + + return sqlite3CorruptError(4763); + } + + + if( offset<pCur->info.nLocal ){ + int a = amt; + if( a+offset>pCur->info.nLocal ){ + a = pCur->info.nLocal - offset; + } + rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage); + offset = 0; + pBuf += a; + amt -= a; + }else{ + offset -= pCur->info.nLocal; + } + + + if( rc==0 && amt>0 ){ + const u32 ovflSize = pBt->usableSize - 4; + Pgno nextPage; + + nextPage = sqlite3Get4byte(&aPayload[pCur->info.nLocal]); +# 4794 "src/btree.c" + if( (pCur->curFlags & 0x04)==0 ){ + int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; + if( pCur->aOverflow==0 + || nOvfl*(int)sizeof(Pgno) > sqlite3MallocSize(pCur->aOverflow) + ){ + Pgno *aNew = (Pgno*)sqlite3Realloc( + pCur->aOverflow, nOvfl*2*sizeof(Pgno) + ); + if( aNew==0 ){ + return 7; + }else{ + pCur->aOverflow = aNew; + } + } + memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno)); + pCur->curFlags |= 0x04; + }else{ + + + + + if( pCur->aOverflow[offset/ovflSize] ){ + iIdx = (offset/ovflSize); + nextPage = pCur->aOverflow[iIdx]; + offset = (offset%ovflSize); + } + } + + assert( rc==0 && amt>0 ); + while( nextPage ){ + + assert( pCur->aOverflow[iIdx]==0 + || pCur->aOverflow[iIdx]==nextPage + || (sqlite3Config.neverCorrupt==0) ); + pCur->aOverflow[iIdx] = nextPage; + + if( offset>=ovflSize ){ + + + + + + + assert( pCur->curFlags & 0x04 ); + assert( pCur->pBtree->db==pBt->db ); + if( pCur->aOverflow[iIdx+1] ){ + nextPage = pCur->aOverflow[iIdx+1]; + }else{ + rc = getOverflowPage(pBt, nextPage, 0, &nextPage); + } + offset -= ovflSize; + }else{ + + + + int a = amt; + if( a + offset > ovflSize ){ + a = ovflSize - offset; + } +# 4884 "src/btree.c" + { + DbPage *pDbPage; + rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage, + (eOp==0 ? 0x02 : 0) + ); + if( rc==0 ){ + aPayload = sqlite3PagerGetData(pDbPage); + nextPage = sqlite3Get4byte(aPayload); + rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage); + sqlite3PagerUnref(pDbPage); + offset = 0; + } + } + amt -= a; + if( amt==0 ) return rc; + pBuf += a; + } + if( rc ) break; + iIdx++; + } + } + + if( rc==0 && amt>0 ){ + + return sqlite3CorruptError(4908); + } + return rc; +} +# 4930 "src/btree.c" +int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ + assert( cursorHoldsMutex(pCur) ); + assert( pCur->eState==0 ); + assert( pCur->iPage>=0 && pCur->pPage ); + assert( pCur->ix<pCur->pPage->nCell ); + return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); +} + + + + + + + +static int accessPayloadChecked( + BtCursor *pCur, + u32 offset, + u32 amt, + void *pBuf +){ + int rc; + if ( pCur->eState==1 ){ + return 4; + } + assert( cursorOwnsBtShared(pCur) ); + rc = btreeRestoreCursorPosition(pCur); + return rc ? rc : accessPayload(pCur, offset, amt, pBuf, 0); +} +int sqlite3BtreePayloadChecked(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ + if( pCur->eState==0 ){ + assert( cursorOwnsBtShared(pCur) ); + return accessPayload(pCur, offset, amt, pBuf, 0); + }else{ + return accessPayloadChecked(pCur, offset, amt, pBuf); + } +} +# 4987 "src/btree.c" +static const void *fetchPayload( + BtCursor *pCur, + u32 *pAmt +){ + int amt; + assert( pCur!=0 && pCur->iPage>=0 && pCur->pPage); + assert( pCur->eState==0 ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); + assert( cursorOwnsBtShared(pCur) ); + assert( pCur->ix<pCur->pPage->nCell ); + assert( pCur->info.nSize>0 ); + assert( pCur->info.pPayload>pCur->pPage->aData || (sqlite3Config.neverCorrupt==0) ); + assert( pCur->info.pPayload<pCur->pPage->aDataEnd ||(sqlite3Config.neverCorrupt==0)); + amt = pCur->info.nLocal; + if( amt>(int)(pCur->pPage->aDataEnd - pCur->info.pPayload) ){ + + + assert( (sqlite3Config.neverCorrupt==0) ); + amt = ((0)>((int)(pCur->pPage->aDataEnd - pCur->info.pPayload))?(0):((int)(pCur->pPage->aDataEnd - pCur->info.pPayload))); + } + *pAmt = (u32)amt; + return (void*)pCur->info.pPayload; +} +# 5026 "src/btree.c" +const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){ + return fetchPayload(pCur, pAmt); +} +# 5040 "src/btree.c" +static int moveToChild(BtCursor *pCur, u32 newPgno){ + BtShared *pBt = pCur->pBt; + + assert( cursorOwnsBtShared(pCur) ); + assert( pCur->eState==0 ); + assert( pCur->iPage<20 ); + assert( pCur->iPage>=0 ); + if( pCur->iPage>=(20 -1) ){ + return sqlite3CorruptError(5048); + } + pCur->info.nSize = 0; + pCur->curFlags &= ~(0x02|0x04); + pCur->aiIdx[pCur->iPage] = pCur->ix; + pCur->apPage[pCur->iPage] = pCur->pPage; + pCur->ix = 0; + pCur->iPage++; + return getAndInitPage(pBt, newPgno, &pCur->pPage, pCur, pCur->curPagerFlags); +} +# 5089 "src/btree.c" +static void moveToParent(BtCursor *pCur){ + MemPage *pLeaf; + assert( cursorOwnsBtShared(pCur) ); + assert( pCur->eState==0 ); + assert( pCur->iPage>0 ); + assert( pCur->pPage ); + + + + + ; + ; + pCur->info.nSize = 0; + pCur->curFlags &= ~(0x02|0x04); + pCur->ix = pCur->aiIdx[pCur->iPage-1]; + pLeaf = pCur->pPage; + pCur->pPage = pCur->apPage[--pCur->iPage]; + releasePageNotNull(pLeaf); +} +# 5130 "src/btree.c" +static int moveToRoot(BtCursor *pCur){ + MemPage *pRoot; + int rc = 0; + + assert( cursorOwnsBtShared(pCur) ); + assert( 1 < 3 ); + assert( 0 < 3 ); + assert( 4 > 3 ); + assert( pCur->eState < 3 || pCur->iPage<0 ); + assert( pCur->pgnoRoot>0 || pCur->iPage<0 ); + + if( pCur->iPage>=0 ){ + if( pCur->iPage ){ + releasePageNotNull(pCur->pPage); + while( --pCur->iPage ){ + releasePageNotNull(pCur->apPage[pCur->iPage]); + } + pCur->pPage = pCur->apPage[0]; + goto skip_init; + } + }else if( pCur->pgnoRoot==0 ){ + pCur->eState = 1; + return 16; + }else{ + assert( pCur->iPage==(-1) ); + if( pCur->eState>=3 ){ + if( pCur->eState==4 ){ + assert( pCur->skipNext!=0 ); + return pCur->skipNext; + } + sqlite3BtreeClearCursor(pCur); + } + rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->pPage, + 0, pCur->curPagerFlags); + if( rc!=0 ){ + pCur->eState = 1; + return rc; + } + pCur->iPage = 0; + pCur->curIntKey = pCur->pPage->intKey; + } + pRoot = pCur->pPage; + assert( pRoot->pgno==pCur->pgnoRoot ); +# 5184 "src/btree.c" + assert( pRoot->intKey==1 || pRoot->intKey==0 ); + if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){ + return sqlite3CorruptError(5186); + } + +skip_init: + pCur->ix = 0; + pCur->info.nSize = 0; + pCur->curFlags &= ~(0x08|0x02|0x04); + + pRoot = pCur->pPage; + if( pRoot->nCell>0 ){ + pCur->eState = 0; + }else if( !pRoot->leaf ){ + Pgno subpage; + if( pRoot->pgno!=1 ) return sqlite3CorruptError(5199); + subpage = sqlite3Get4byte(&pRoot->aData[pRoot->hdrOffset+8]); + pCur->eState = 0; + rc = moveToChild(pCur, subpage); + }else{ + pCur->eState = 1; + rc = 16; + } + return rc; +} +# 5217 "src/btree.c" +static int moveToLeftmost(BtCursor *pCur){ + Pgno pgno; + int rc = 0; + MemPage *pPage; + + assert( cursorOwnsBtShared(pCur) ); + assert( pCur->eState==0 ); + while( rc==0 && !(pPage = pCur->pPage)->leaf ){ + assert( pCur->ix<pPage->nCell ); + pgno = sqlite3Get4byte(((pPage)->aData + ((pPage)->maskPage & __builtin_bswap16(*(u16*)(&(pPage)->aCellIdx[2*(pCur->ix)]))))); + rc = moveToChild(pCur, pgno); + } + return rc; +} +# 5242 "src/btree.c" +static int moveToRightmost(BtCursor *pCur){ + Pgno pgno; + int rc = 0; + MemPage *pPage = 0; + + assert( cursorOwnsBtShared(pCur) ); + assert( pCur->eState==0 ); + while( !(pPage = pCur->pPage)->leaf ){ + pgno = sqlite3Get4byte(&pPage->aData[pPage->hdrOffset+8]); + pCur->ix = pPage->nCell; + rc = moveToChild(pCur, pgno); + if( rc ) return rc; + } + pCur->ix = pPage->nCell-1; + assert( pCur->info.nSize==0 ); + assert( (pCur->curFlags & 0x02)==0 ); + return 0; +} + + + + + +int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ + int rc; + + assert( cursorOwnsBtShared(pCur) ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); + rc = moveToRoot(pCur); + if( rc==0 ){ + assert( pCur->pPage->nCell>0 ); + *pRes = 0; + rc = moveToLeftmost(pCur); + }else if( rc==16 ){ + assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); + *pRes = 1; + rc = 0; + } + return rc; +} + + + + + +int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ + int rc; + + assert( cursorOwnsBtShared(pCur) ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); + + + if( 0==pCur->eState && (pCur->curFlags & 0x08)!=0 ){ +# 5305 "src/btree.c" + *pRes = 0; + return 0; + } + + rc = moveToRoot(pCur); + if( rc==0 ){ + assert( pCur->eState==0 ); + *pRes = 0; + rc = moveToRightmost(pCur); + if( rc==0 ){ + pCur->curFlags |= 0x08; + }else{ + pCur->curFlags &= ~0x08; + } + }else if( rc==16 ){ + assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); + *pRes = 1; + rc = 0; + } + return rc; +} +# 5357 "src/btree.c" +int sqlite3BtreeMovetoUnpacked( + BtCursor *pCur, + UnpackedRecord *pIdxKey, + i64 intKey, + int biasRight, + int *pRes +){ + int rc; + RecordCompare xRecordCompare; + + assert( cursorOwnsBtShared(pCur) ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); + assert( pRes ); + assert( (pIdxKey==0)==(pCur->pKeyInfo==0) ); + assert( pCur->eState!=0 || (pIdxKey==0)==(pCur->curIntKey!=0) ); + + + + if( pIdxKey==0 + && pCur->eState==0 && (pCur->curFlags & 0x02)!=0 + ){ + if( pCur->info.nKey==intKey ){ + *pRes = 0; + return 0; + } + if( pCur->info.nKey<intKey ){ + if( (pCur->curFlags & 0x08)!=0 ){ + *pRes = -1; + return 0; + } + + + + + if( pCur->info.nKey+1==intKey ){ + *pRes = 0; + rc = sqlite3BtreeNext(pCur, 0); + if( rc==0 ){ + getCellInfo(pCur); + if( pCur->info.nKey==intKey ){ + return 0; + } + }else if( rc==101 ){ + rc = 0; + }else{ + return rc; + } + } + } + } + + if( pIdxKey ){ + xRecordCompare = sqlite3VdbeFindCompare(pIdxKey); + pIdxKey->errCode = 0; + assert( pIdxKey->default_rc==1 + || pIdxKey->default_rc==0 + || pIdxKey->default_rc==-1 + ); + }else{ + xRecordCompare = 0; + } + + rc = moveToRoot(pCur); + if( rc ){ + if( rc==16 ){ + assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); + *pRes = -1; + return 0; + } + return rc; + } + assert( pCur->pPage ); + assert( pCur->pPage->isInit ); + assert( pCur->eState==0 ); + assert( pCur->pPage->nCell > 0 ); + assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey ); + assert( pCur->curIntKey || pIdxKey ); + for(;;){ + int lwr, upr, idx, c; + Pgno chldPg; + MemPage *pPage = pCur->pPage; + u8 *pCell; + + + + + + + + assert( pPage->nCell>0 ); + assert( pPage->intKey==(pIdxKey==0) ); + lwr = 0; + upr = pPage->nCell-1; + assert( biasRight==0 || biasRight==1 ); + idx = upr>>(1-biasRight); + pCur->ix = (u16)idx; + if( xRecordCompare==0 ){ + for(;;){ + i64 nCellKey; + pCell = ((pPage)->aDataOfst + ((pPage)->maskPage & __builtin_bswap16(*(u16*)(&(pPage)->aCellIdx[2*(idx)])))); + if( pPage->intKeyLeaf ){ + while( 0x80 <= *(pCell++) ){ + if( pCell>=pPage->aDataEnd ){ + return sqlite3CorruptError(5460); + } + } + } + sqlite3GetVarint(pCell, (u64*)&nCellKey); + if( nCellKey<intKey ){ + lwr = idx+1; + if( lwr>upr ){ c = -1; break; } + }else if( nCellKey>intKey ){ + upr = idx-1; + if( lwr>upr ){ c = +1; break; } + }else{ + assert( nCellKey==intKey ); + pCur->ix = (u16)idx; + if( !pPage->leaf ){ + lwr = idx; + goto moveto_next_layer; + }else{ + pCur->curFlags |= 0x02; + pCur->info.nKey = nCellKey; + pCur->info.nSize = 0; + *pRes = 0; + return 0; + } + } + assert( lwr+upr>=0 ); + idx = (lwr+upr)>>1; + } + }else{ + for(;;){ + int nCell; + pCell = ((pPage)->aDataOfst + ((pPage)->maskPage & __builtin_bswap16(*(u16*)(&(pPage)->aCellIdx[2*(idx)])))); +# 5501 "src/btree.c" + nCell = pCell[0]; + if( nCell<=pPage->max1bytePayload ){ + + + + ; + c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); + }else if( !(pCell[1] & 0x80) + && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal + ){ + + + ; + c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); + }else{ +# 5525 "src/btree.c" + void *pCellKey; + u8 * const pCellBody = pCell - pPage->childPtrSize; + const int nOverrun = 18; + pPage->xParseCell(pPage, pCellBody, &pCur->info); + nCell = (int)pCur->info.nKey; + ; + ; + ; + ; + if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){ + rc = sqlite3CorruptError(5535); + goto moveto_finish; + } + pCellKey = sqlite3Malloc( nCell+nOverrun ); + if( pCellKey==0 ){ + rc = 7; + goto moveto_finish; + } + pCur->ix = (u16)idx; + rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); + memset(((u8*)pCellKey)+nCell,0,nOverrun); + pCur->curFlags &= ~0x04; + if( rc ){ + sqlite3_free(pCellKey); + goto moveto_finish; + } + c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey); + sqlite3_free(pCellKey); + } + assert( + (pIdxKey->errCode!=11 || c==0) + && (pIdxKey->errCode!=7 || pCur->pBtree->db->mallocFailed) + ); + if( c<0 ){ + lwr = idx+1; + }else if( c>0 ){ + upr = idx-1; + }else{ + assert( c==0 ); + *pRes = 0; + rc = 0; + pCur->ix = (u16)idx; + if( pIdxKey->errCode ) rc = sqlite3CorruptError(5567); + goto moveto_finish; + } + if( lwr>upr ) break; + assert( lwr+upr>=0 ); + idx = (lwr+upr)>>1; + } + } + assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) ); + assert( pPage->isInit ); + if( pPage->leaf ){ + assert( pCur->ix<pCur->pPage->nCell ); + pCur->ix = (u16)idx; + *pRes = c; + rc = 0; + goto moveto_finish; + } +moveto_next_layer: + if( lwr>=pPage->nCell ){ + chldPg = sqlite3Get4byte(&pPage->aData[pPage->hdrOffset+8]); + }else{ + chldPg = sqlite3Get4byte(((pPage)->aData + ((pPage)->maskPage & __builtin_bswap16(*(u16*)(&(pPage)->aCellIdx[2*(lwr)]))))); + } + pCur->ix = (u16)lwr; + rc = moveToChild(pCur, chldPg); + if( rc ) break; + } +moveto_finish: + pCur->info.nSize = 0; + assert( (pCur->curFlags & 0x04)==0 ); + return rc; +} +# 5608 "src/btree.c" +int sqlite3BtreeEof(BtCursor *pCur){ + + + + + return (0!=pCur->eState); +} + + + + + + +i64 sqlite3BtreeRowCountEst(BtCursor *pCur){ + i64 n; + u8 i; + + assert( cursorOwnsBtShared(pCur) ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); + + + + + if( (pCur->eState!=0) ) return -1; + if( (pCur->pPage->leaf==0) ) return -1; + + n = pCur->pPage->nCell; + for(i=0; i<pCur->iPage; i++){ + n *= pCur->apPage[i]->nCell; + } + return n; +} +# 5661 "src/btree.c" +static int btreeNext(BtCursor *pCur){ + int rc; + int idx; + MemPage *pPage; + + assert( cursorOwnsBtShared(pCur) ); + if( pCur->eState!=0 ){ + assert( (pCur->curFlags & 0x04)==0 ); + rc = (pCur->eState>=3 ? btreeRestoreCursorPosition(pCur) : 0); + if( rc!=0 ){ + return rc; + } + if( 1==pCur->eState ){ + return 101; + } + if( pCur->eState==2 ){ + pCur->eState = 0; + if( pCur->skipNext>0 ) return 0; + } + } + + pPage = pCur->pPage; + idx = ++pCur->ix; + if( !pPage->isInit ){ + + + + + + + + return sqlite3CorruptError(5692); + } + + + + + + + ; + + if( idx>=pPage->nCell ){ + if( !pPage->leaf ){ + rc = moveToChild(pCur, sqlite3Get4byte(&pPage->aData[pPage->hdrOffset+8])); + if( rc ) return rc; + return moveToLeftmost(pCur); + } + do{ + if( pCur->iPage==0 ){ + pCur->eState = 1; + return 101; + } + moveToParent(pCur); + pPage = pCur->pPage; + }while( pCur->ix>=pPage->nCell ); + if( pPage->intKey ){ + return sqlite3BtreeNext(pCur, 0); + }else{ + return 0; + } + } + if( pPage->leaf ){ + return 0; + }else{ + return moveToLeftmost(pCur); + } +} +int sqlite3BtreeNext(BtCursor *pCur, int flags){ + MemPage *pPage; + (void)(flags); + assert( cursorOwnsBtShared(pCur) ); + assert( flags==0 || flags==1 ); + pCur->info.nSize = 0; + pCur->curFlags &= ~(0x02|0x04); + if( pCur->eState!=0 ) return btreeNext(pCur); + pPage = pCur->pPage; + if( (++pCur->ix)>=pPage->nCell ){ + pCur->ix--; + return btreeNext(pCur); + } + if( pPage->leaf ){ + return 0; + }else{ + return moveToLeftmost(pCur); + } +} +# 5768 "src/btree.c" +static int btreePrevious(BtCursor *pCur){ + int rc; + MemPage *pPage; + + assert( cursorOwnsBtShared(pCur) ); + assert( (pCur->curFlags & (0x08|0x04|0x02))==0 ); + assert( pCur->info.nSize==0 ); + if( pCur->eState!=0 ){ + rc = (pCur->eState>=3 ? btreeRestoreCursorPosition(pCur) : 0); + if( rc!=0 ){ + return rc; + } + if( 1==pCur->eState ){ + return 101; + } + if( 2==pCur->eState ){ + pCur->eState = 0; + if( pCur->skipNext<0 ) return 0; + } + } + + pPage = pCur->pPage; + assert( pPage->isInit ); + if( !pPage->leaf ){ + int idx = pCur->ix; + rc = moveToChild(pCur, sqlite3Get4byte(((pPage)->aData + ((pPage)->maskPage & __builtin_bswap16(*(u16*)(&(pPage)->aCellIdx[2*(idx)])))))); + if( rc ) return rc; + rc = moveToRightmost(pCur); + }else{ + while( pCur->ix==0 ){ + if( pCur->iPage==0 ){ + pCur->eState = 1; + return 101; + } + moveToParent(pCur); + } + assert( pCur->info.nSize==0 ); + assert( (pCur->curFlags & (0x04))==0 ); + + pCur->ix--; + pPage = pCur->pPage; + if( pPage->intKey && !pPage->leaf ){ + rc = sqlite3BtreePrevious(pCur, 0); + }else{ + rc = 0; + } + } + return rc; +} +int sqlite3BtreePrevious(BtCursor *pCur, int flags){ + assert( cursorOwnsBtShared(pCur) ); + assert( flags==0 || flags==1 ); + (void)(flags); + pCur->curFlags &= ~(0x08|0x04|0x02); + pCur->info.nSize = 0; + if( pCur->eState!=0 + || pCur->ix==0 + || pCur->pPage->leaf==0 + ){ + return btreePrevious(pCur); + } + pCur->ix--; + return 0; +} +# 5855 "src/btree.c" +static int allocateBtreePage( + BtShared *pBt, + MemPage **ppPage, + Pgno *pPgno, + Pgno nearby, + u8 eMode +){ + MemPage *pPage1; + int rc; + u32 n; + u32 k; + MemPage *pTrunk = 0; + MemPage *pPrevTrunk = 0; + Pgno mxPage; + + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( eMode==0 || (nearby>0 && (pBt->autoVacuum)) ); + pPage1 = pBt->pPage1; + mxPage = btreePagecount(pBt); + + + n = sqlite3Get4byte(&pPage1->aData[36]); + ; + if( n>=mxPage ){ + return sqlite3CorruptError(5879); + } + if( n>0 ){ + + Pgno iTrunk; + u8 searchList = 0; + u32 nSearch = 0; + + + + + + + if( eMode==1 ){ + if( nearby<=mxPage ){ + u8 eType; + assert( nearby>0 ); + assert( pBt->autoVacuum ); + rc = ptrmapGet(pBt, nearby, &eType, 0); + if( rc ) return rc; + if( eType==2 ){ + searchList = 1; + } + } + }else if( eMode==2 ){ + searchList = 1; + } + + + + + + rc = sqlite3PagerWrite(pPage1->pDbPage); + if( rc ) return rc; + sqlite3Put4byte(&pPage1->aData[36], n-1); + + + + + + + do { + pPrevTrunk = pTrunk; + if( pPrevTrunk ){ + + + + iTrunk = sqlite3Get4byte(&pPrevTrunk->aData[0]); + }else{ + + + + iTrunk = sqlite3Get4byte(&pPage1->aData[32]); + } + ; + if( iTrunk>mxPage || nSearch++ > n ){ + rc = sqlite3CorruptError(5935); + }else{ + rc = btreeGetUnusedPage(pBt, iTrunk, &pTrunk, 0); + } + if( rc ){ + pTrunk = 0; + goto end_allocate_page; + } + assert( pTrunk!=0 ); + assert( pTrunk->aData!=0 ); + + + k = sqlite3Get4byte(&pTrunk->aData[4]); + if( k==0 && !searchList ){ + + + + assert( pPrevTrunk==0 ); + rc = sqlite3PagerWrite(pTrunk->pDbPage); + if( rc ){ + goto end_allocate_page; + } + *pPgno = iTrunk; + memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4); + *ppPage = pTrunk; + pTrunk = 0; + ; + }else if( k>(u32)(pBt->usableSize/4 - 2) ){ + + rc = sqlite3CorruptError(5964); + goto end_allocate_page; + + }else if( searchList + && (nearby==iTrunk || (iTrunk<nearby && eMode==2)) + ){ + + + + *pPgno = iTrunk; + *ppPage = pTrunk; + searchList = 0; + rc = sqlite3PagerWrite(pTrunk->pDbPage); + if( rc ){ + goto end_allocate_page; + } + if( k==0 ){ + if( !pPrevTrunk ){ + memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4); + }else{ + rc = sqlite3PagerWrite(pPrevTrunk->pDbPage); + if( rc!=0 ){ + goto end_allocate_page; + } + memcpy(&pPrevTrunk->aData[0], &pTrunk->aData[0], 4); + } + }else{ + + + + + MemPage *pNewTrunk; + Pgno iNewTrunk = sqlite3Get4byte(&pTrunk->aData[8]); + if( iNewTrunk>mxPage ){ + rc = sqlite3CorruptError(5998); + goto end_allocate_page; + } + ; + rc = btreeGetUnusedPage(pBt, iNewTrunk, &pNewTrunk, 0); + if( rc!=0 ){ + goto end_allocate_page; + } + rc = sqlite3PagerWrite(pNewTrunk->pDbPage); + if( rc!=0 ){ + releasePage(pNewTrunk); + goto end_allocate_page; + } + memcpy(&pNewTrunk->aData[0], &pTrunk->aData[0], 4); + sqlite3Put4byte(&pNewTrunk->aData[4], k-1); + memcpy(&pNewTrunk->aData[8], &pTrunk->aData[12], (k-1)*4); + releasePage(pNewTrunk); + if( !pPrevTrunk ){ + assert( sqlite3PagerIswriteable(pPage1->pDbPage) ); + sqlite3Put4byte(&pPage1->aData[32], iNewTrunk); + }else{ + rc = sqlite3PagerWrite(pPrevTrunk->pDbPage); + if( rc ){ + goto end_allocate_page; + } + sqlite3Put4byte(&pPrevTrunk->aData[0], iNewTrunk); + } + } + pTrunk = 0; + ; + + }else if( k>0 ){ + + u32 closest; + Pgno iPage; + unsigned char *aData = pTrunk->aData; + if( nearby>0 ){ + u32 i; + closest = 0; + if( eMode==2 ){ + for(i=0; i<k; i++){ + iPage = sqlite3Get4byte(&aData[8+i*4]); + if( iPage<=nearby ){ + closest = i; + break; + } + } + }else{ + int dist; + dist = sqlite3AbsInt32(sqlite3Get4byte(&aData[8]) - nearby); + for(i=1; i<k; i++){ + int d2 = sqlite3AbsInt32(sqlite3Get4byte(&aData[8+i*4]) - nearby); + if( d2<dist ){ + closest = i; + dist = d2; + } + } + } + }else{ + closest = 0; + } + + iPage = sqlite3Get4byte(&aData[8+closest*4]); + ; + if( iPage>mxPage ){ + rc = sqlite3CorruptError(6063); + goto end_allocate_page; + } + ; + if( !searchList + || (iPage==nearby || (iPage<nearby && eMode==2)) + ){ + int noContent; + *pPgno = iPage; + + + ; + rc = sqlite3PagerWrite(pTrunk->pDbPage); + if( rc ) goto end_allocate_page; + if( closest<k-1 ){ + memcpy(&aData[8+closest*4], &aData[4+k*4], 4); + } + sqlite3Put4byte(&aData[4], k-1); + noContent = !btreeGetHasContent(pBt, *pPgno)? 0x01 : 0; + rc = btreeGetUnusedPage(pBt, *pPgno, ppPage, noContent); + if( rc==0 ){ + rc = sqlite3PagerWrite((*ppPage)->pDbPage); + if( rc!=0 ){ + releasePage(*ppPage); + *ppPage = 0; + } + } + searchList = 0; + } + } + releasePage(pPrevTrunk); + pPrevTrunk = 0; + }while( searchList ); + }else{ +# 6115 "src/btree.c" + int bNoContent = (0==(pBt->bDoTruncate))? 0x01:0; + + rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); + if( rc ) return rc; + pBt->nPage++; + if( pBt->nPage==((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1)) ) pBt->nPage++; + + + if( pBt->autoVacuum && (ptrmapPageno((pBt), (pBt->nPage))==(pBt->nPage)) ){ + + + + + MemPage *pPg = 0; + ; + assert( pBt->nPage!=((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1)) ); + rc = btreeGetUnusedPage(pBt, pBt->nPage, &pPg, bNoContent); + if( rc==0 ){ + rc = sqlite3PagerWrite(pPg->pDbPage); + releasePage(pPg); + } + if( rc ) return rc; + pBt->nPage++; + if( pBt->nPage==((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1)) ){ pBt->nPage++; } + } + + sqlite3Put4byte(28 + (u8*)pBt->pPage1->aData, pBt->nPage); + *pPgno = pBt->nPage; + + assert( *pPgno!=((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1)) ); + rc = btreeGetUnusedPage(pBt, *pPgno, ppPage, bNoContent); + if( rc ) return rc; + rc = sqlite3PagerWrite((*ppPage)->pDbPage); + if( rc!=0 ){ + releasePage(*ppPage); + *ppPage = 0; + } + ; + } + + assert( (sqlite3Config.neverCorrupt==0) || *pPgno!=((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1)) ); + +end_allocate_page: + releasePage(pTrunk); + releasePage(pPrevTrunk); + assert( rc!=0 || sqlite3PagerPageRefcount((*ppPage)->pDbPage)<=1 ); + assert( rc!=0 || (*ppPage)->isInit==0 ); + return rc; +} +# 6177 "src/btree.c" +static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ + MemPage *pTrunk = 0; + Pgno iTrunk = 0; + MemPage *pPage1 = pBt->pPage1; + MemPage *pPage; + int rc; + u32 nFree; + + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( (sqlite3Config.neverCorrupt==0) || iPage>1 ); + assert( !pMemPage || pMemPage->pgno==iPage ); + + if( iPage<2 || iPage>pBt->nPage ){ + return sqlite3CorruptError(6190); + } + if( pMemPage ){ + pPage = pMemPage; + sqlite3PagerRef(pPage->pDbPage); + }else{ + pPage = btreePageLookup(pBt, iPage); + } + + + rc = sqlite3PagerWrite(pPage1->pDbPage); + if( rc ) goto freepage_out; + nFree = sqlite3Get4byte(&pPage1->aData[36]); + sqlite3Put4byte(&pPage1->aData[36], nFree+1); + + if( pBt->btsFlags & 0x0004 ){ + + + + if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0) ) + || ((rc = sqlite3PagerWrite(pPage->pDbPage))!=0) + ){ + goto freepage_out; + } + memset(pPage->aData, 0, pPage->pBt->pageSize); + } + + + + + if( (pBt->autoVacuum) ){ + ptrmapPut(pBt, iPage, 2, 0, &rc); + if( rc ) goto freepage_out; + } +# 6232 "src/btree.c" + if( nFree!=0 ){ + u32 nLeaf; + + iTrunk = sqlite3Get4byte(&pPage1->aData[32]); + rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0); + if( rc!=0 ){ + goto freepage_out; + } + + nLeaf = sqlite3Get4byte(&pTrunk->aData[4]); + assert( pBt->usableSize>32 ); + if( nLeaf > (u32)pBt->usableSize/4 - 2 ){ + rc = sqlite3CorruptError(6244); + goto freepage_out; + } + if( nLeaf < (u32)pBt->usableSize/4 - 8 ){ +# 6267 "src/btree.c" + rc = sqlite3PagerWrite(pTrunk->pDbPage); + if( rc==0 ){ + sqlite3Put4byte(&pTrunk->aData[4], nLeaf+1); + sqlite3Put4byte(&pTrunk->aData[8+nLeaf*4], iPage); + if( pPage && (pBt->btsFlags & 0x0004)==0 ){ + sqlite3PagerDontWrite(pPage->pDbPage); + } + rc = btreeSetHasContent(pBt, iPage); + } + ; + goto freepage_out; + } + } + + + + + + + + if( pPage==0 && 0!=(rc = btreeGetPage(pBt, iPage, &pPage, 0)) ){ + goto freepage_out; + } + rc = sqlite3PagerWrite(pPage->pDbPage); + if( rc!=0 ){ + goto freepage_out; + } + sqlite3Put4byte(pPage->aData, iTrunk); + sqlite3Put4byte(&pPage->aData[4], 0); + sqlite3Put4byte(&pPage1->aData[32], iPage); + ; + +freepage_out: + if( pPage ){ + pPage->isInit = 0; + } + releasePage(pPage); + releasePage(pTrunk); + return rc; +} +static void freePage(MemPage *pPage, int *pRC){ + if( (*pRC)==0 ){ + *pRC = freePage2(pPage->pBt, pPage, pPage->pgno); + } +} + + + + + +static int clearCell( + MemPage *pPage, + unsigned char *pCell, + CellInfo *pInfo +){ + BtShared *pBt; + Pgno ovflPgno; + int rc; + int nOvfl; + u32 ovflPageSize; + + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + pPage->xParseCell(pPage, pCell, pInfo); + if( pInfo->nLocal==pInfo->nPayload ){ + return 0; + } + ; + ; + if( pCell + pInfo->nSize > pPage->aDataEnd ){ + + return sqlite3CorruptError(6337); + } + ovflPgno = sqlite3Get4byte(pCell + pInfo->nSize - 4); + pBt = pPage->pBt; + assert( pBt->usableSize > 4 ); + ovflPageSize = pBt->usableSize - 4; + nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1)/ovflPageSize; + assert( nOvfl>0 || + ((sqlite3Config.neverCorrupt==0) && (pInfo->nPayload + ovflPageSize)<ovflPageSize) + ); + while( nOvfl-- ){ + Pgno iNext = 0; + MemPage *pOvfl = 0; + if( ovflPgno<2 || ovflPgno>btreePagecount(pBt) ){ + + + + return sqlite3CorruptError(6354); + } + if( nOvfl ){ + rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext); + if( rc ) return rc; + } + + if( ( pOvfl || ((pOvfl = btreePageLookup(pBt, ovflPgno))!=0) ) + && sqlite3PagerPageRefcount(pOvfl->pDbPage)!=1 + ){ +# 6374 "src/btree.c" + rc = sqlite3CorruptError(6374); + }else{ + rc = freePage2(pBt, pOvfl, ovflPgno); + } + + if( pOvfl ){ + sqlite3PagerUnref(pOvfl->pDbPage); + } + if( rc ) return rc; + ovflPgno = iNext; + } + return 0; +} +# 6400 "src/btree.c" +static int fillInCell( + MemPage *pPage, + unsigned char *pCell, + const BtreePayload *pX, + int *pnSize +){ + int nPayload; + const u8 *pSrc; + int nSrc, n, rc, mn; + int spaceLeft; + MemPage *pToRelease; + unsigned char *pPrior; + unsigned char *pPayload; + BtShared *pBt; + Pgno pgnoOvfl; + int nHeader; + + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + + + + assert( pCell<pPage->aData || pCell>=&pPage->aData[pPage->pBt->pageSize] + || sqlite3PagerIswriteable(pPage->pDbPage) ); + + + nHeader = pPage->childPtrSize; + if( pPage->intKey ){ + nPayload = pX->nData + pX->nZero; + pSrc = pX->pData; + nSrc = pX->nData; + assert( pPage->intKeyLeaf ); + nHeader += (u8)(((u32)(nPayload)<(u32)0x80)?(*(&pCell[nHeader])=(unsigned char)(nPayload)),1: sqlite3PutVarint((&pCell[nHeader]),(nPayload))); + nHeader += sqlite3PutVarint(&pCell[nHeader], *(u64*)&pX->nKey); + }else{ + assert( pX->nKey<=0x7fffffff && pX->pKey!=0 ); + nSrc = nPayload = (int)pX->nKey; + pSrc = pX->pKey; + nHeader += (u8)(((u32)(nPayload)<(u32)0x80)?(*(&pCell[nHeader])=(unsigned char)(nPayload)),1: sqlite3PutVarint((&pCell[nHeader]),(nPayload))); + } + + + pPayload = &pCell[nHeader]; + if( nPayload<=pPage->maxLocal ){ + + + n = nHeader + nPayload; + ; + ; + if( n<4 ) n = 4; + *pnSize = n; + assert( nSrc<=nPayload ); + ; + memcpy(pPayload, pSrc, nSrc); + memset(pPayload+nSrc, 0, nPayload-nSrc); + return 0; + } + + + + + mn = pPage->minLocal; + n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4); + ; + ; + if( n > pPage->maxLocal ) n = mn; + spaceLeft = n; + *pnSize = n + nHeader + 4; + pPrior = &pCell[nHeader+n]; + pToRelease = 0; + pgnoOvfl = 0; + pBt = pPage->pBt; +# 6496 "src/btree.c" + while( 1 ){ + n = nPayload; + if( n>spaceLeft ) n = spaceLeft; + + + + assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) ); + + + + assert( pPayload<pPage->aData || pPayload>=&pPage->aData[pBt->pageSize] + || sqlite3PagerIswriteable(pPage->pDbPage) ); + + if( nSrc>=n ){ + memcpy(pPayload, pSrc, n); + }else if( nSrc>0 ){ + n = nSrc; + memcpy(pPayload, pSrc, n); + }else{ + memset(pPayload, 0, n); + } + nPayload -= n; + if( nPayload<=0 ) break; + pPayload += n; + pSrc += n; + nSrc -= n; + spaceLeft -= n; + if( spaceLeft==0 ){ + MemPage *pOvfl = 0; + + Pgno pgnoPtrmap = pgnoOvfl; + if( pBt->autoVacuum ){ + do{ + pgnoOvfl++; + } while( + (ptrmapPageno((pBt), (pgnoOvfl))==(pgnoOvfl)) || pgnoOvfl==((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1)) + ); + } + + rc = allocateBtreePage(pBt, &pOvfl, &pgnoOvfl, pgnoOvfl, 0); +# 6547 "src/btree.c" + if( pBt->autoVacuum && rc==0 ){ + u8 eType = (pgnoPtrmap?4:3); + ptrmapPut(pBt, pgnoOvfl, eType, pgnoPtrmap, &rc); + if( rc ){ + releasePage(pOvfl); + } + } + + if( rc ){ + releasePage(pToRelease); + return rc; + } + + + + assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) ); + + + + assert( pPrior<pPage->aData || pPrior>=&pPage->aData[pBt->pageSize] + || sqlite3PagerIswriteable(pPage->pDbPage) ); + + sqlite3Put4byte(pPrior, pgnoOvfl); + releasePage(pToRelease); + pToRelease = pOvfl; + pPrior = pOvfl->aData; + sqlite3Put4byte(pPrior, 0); + pPayload = &pOvfl->aData[4]; + spaceLeft = pBt->usableSize - 4; + } + } + releasePage(pToRelease); + return 0; +} +# 6590 "src/btree.c" +static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ + u32 pc; + u8 *data; + u8 *ptr; + int rc; + int hdr; + + if( *pRC ) return; + assert( idx>=0 && idx<pPage->nCell ); + assert( (sqlite3Config.neverCorrupt==0) || sz==cellSize(pPage, idx) ); + assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( pPage->nFree>=0 ); + data = pPage->aData; + ptr = &pPage->aCellIdx[2*idx]; + pc = ((ptr)[0]<<8 | (ptr)[1]); + hdr = pPage->hdrOffset; + ; + ; + if( pc+sz > pPage->pBt->usableSize ){ + *pRC = sqlite3CorruptError(6610); + return; + } + rc = freeSpace(pPage, pc, sz); + if( rc ){ + *pRC = rc; + return; + } + pPage->nCell--; + if( pPage->nCell==0 ){ + memset(&data[hdr+1], 0, 4); + data[hdr+7] = 0; + ((&data[hdr+5])[0] = (u8)((pPage->pBt->usableSize)>>8), (&data[hdr+5])[1] = (u8)(pPage->pBt->usableSize)); + pPage->nFree = pPage->pBt->usableSize - pPage->hdrOffset + - pPage->childPtrSize - 8; + }else{ + memmove(ptr, ptr+2, 2*(pPage->nCell - idx)); + ((&data[hdr+3])[0] = (u8)((pPage->nCell)>>8), (&data[hdr+3])[1] = (u8)(pPage->nCell)); + pPage->nFree += 2; + } +} +# 6646 "src/btree.c" +static void insertCell( + MemPage *pPage, + int i, + u8 *pCell, + int sz, + u8 *pTemp, + Pgno iChild, + int *pRC +){ + int idx = 0; + int j; + u8 *data; + u8 *pIns; + + assert( *pRC==0 ); + assert( i>=0 && i<=pPage->nCell+pPage->nOverflow ); + assert( ((pPage->pBt->pageSize-8)/6)<=10921 ); + assert( pPage->nCell<=((pPage->pBt->pageSize-8)/6) || (sqlite3Config.neverCorrupt==0) ); + assert( pPage->nOverflow<=((int)(sizeof(pPage->apOvfl)/sizeof(pPage->apOvfl[0]))) ); + assert( ((int)(sizeof(pPage->apOvfl)/sizeof(pPage->apOvfl[0])))==((int)(sizeof(pPage->aiOvfl)/sizeof(pPage->aiOvfl[0]))) ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + + + + + + assert( sz==pPage->xCellSize(pPage, pCell) || (sz==8 && iChild>0) ); + assert( pPage->nFree>=0 ); + if( pPage->nOverflow || sz+2>pPage->nFree ){ + if( pTemp ){ + memcpy(pTemp, pCell, sz); + pCell = pTemp; + } + if( iChild ){ + sqlite3Put4byte(pCell, iChild); + } + j = pPage->nOverflow++; + + + + assert( j < ((int)(sizeof(pPage->apOvfl)/sizeof(pPage->apOvfl[0])))-1 ); + pPage->apOvfl[j] = pCell; + pPage->aiOvfl[j] = (u16)i; + + + + + + + assert( j==0 || pPage->aiOvfl[j-1]<(u16)i ); + assert( j==0 || i==pPage->aiOvfl[j-1]+1 ); + }else{ + int rc = sqlite3PagerWrite(pPage->pDbPage); + if( rc!=0 ){ + *pRC = rc; + return; + } + assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + data = pPage->aData; + assert( &data[pPage->cellOffset]==pPage->aCellIdx ); + rc = allocateSpace(pPage, sz, &idx); + if( rc ){ *pRC = rc; return; } + + + assert( idx >= 0 ); + assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || (sqlite3Config.neverCorrupt==0) ); + assert( idx+sz <= (int)pPage->pBt->usableSize ); + pPage->nFree -= (u16)(2 + sz); + if( iChild ){ + + + + + + memcpy(&data[idx+4], pCell+4, sz-4); + sqlite3Put4byte(&data[idx], iChild); + }else{ + memcpy(&data[idx], pCell, sz); + } + pIns = pPage->aCellIdx + i*2; + memmove(pIns+2, pIns, 2*(pPage->nCell - i)); + ((pIns)[0] = (u8)((idx)>>8), (pIns)[1] = (u8)(idx)); + pPage->nCell++; + + if( (++data[pPage->hdrOffset+4])==0 ) data[pPage->hdrOffset+3]++; + assert( ((&data[pPage->hdrOffset+3])[0]<<8 | (&data[pPage->hdrOffset+3])[1])==pPage->nCell || (sqlite3Config.neverCorrupt==0) ); + + if( pPage->pBt->autoVacuum ){ + + + + ptrmapPutOvflPtr(pPage, pPage, pCell, pRC); + } + + } +} +# 6826 "src/btree.c" +typedef struct CellArray CellArray; +struct CellArray { + int nCell; + MemPage *pRef; + u8 **apCell; + u16 *szCell; + u8 *apEnd[3*2]; + int ixNx[3*2]; +}; + + + + + +static void populateCellCache(CellArray *p, int idx, int N){ + assert( idx>=0 && idx+N<=p->nCell ); + while( N>0 ){ + assert( p->apCell[idx]!=0 ); + if( p->szCell[idx]==0 ){ + p->szCell[idx] = p->pRef->xCellSize(p->pRef, p->apCell[idx]); + }else{ + assert( (sqlite3Config.neverCorrupt==0) || + p->szCell[idx]==p->pRef->xCellSize(p->pRef, p->apCell[idx]) ); + } + idx++; + N--; + } +} + + + + +static u16 computeCellSize(CellArray *p, int N){ + assert( N>=0 && N<p->nCell ); + assert( p->szCell[N]==0 ); + p->szCell[N] = p->pRef->xCellSize(p->pRef, p->apCell[N]); + return p->szCell[N]; +} +static u16 cachedCellSize(CellArray *p, int N){ + assert( N>=0 && N<p->nCell ); + if( p->szCell[N] ) return p->szCell[N]; + return computeCellSize(p, N); +} +# 6883 "src/btree.c" +static int rebuildPage( + CellArray *pCArray, + int iFirst, + int nCell, + MemPage *pPg +){ + const int hdr = pPg->hdrOffset; + u8 * const aData = pPg->aData; + const int usableSize = pPg->pBt->usableSize; + u8 * const pEnd = &aData[usableSize]; + int i = iFirst; + u32 j; + int iEnd = i+nCell; + u8 *pCellptr = pPg->aCellIdx; + u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager); + u8 *pData; + int k; + u8 *pSrcEnd; + + assert( i<iEnd ); + j = ((&aData[hdr+5])[0]<<8 | (&aData[hdr+5])[1]); + if( (j>(u32)usableSize) ){ j = 0; } + memcpy(&pTmp[j], &aData[j], usableSize - j); + + for(k=0; pCArray->ixNx[k]<=i && (k<3*2); k++){} + pSrcEnd = pCArray->apEnd[k]; + + pData = pEnd; + while( 1 ){ + u8 *pCell = pCArray->apCell[i]; + u16 sz = pCArray->szCell[i]; + assert( sz>0 ); + if( (((uptr)(pCell)>=(uptr)(aData))&&((uptr)(pCell)<(uptr)(pEnd))) ){ + if( ((uptr)(pCell+sz))>(uptr)pEnd ) return sqlite3CorruptError(6916); + pCell = &pTmp[pCell - aData]; + }else if( (uptr)(pCell+sz)>(uptr)pSrcEnd + && (uptr)(pCell)<(uptr)pSrcEnd + ){ + return sqlite3CorruptError(6921); + } + + pData -= sz; + ((pCellptr)[0] = (u8)(((pData - aData))>>8), (pCellptr)[1] = (u8)((pData - aData))); + pCellptr += 2; + if( pData < pCellptr ) return sqlite3CorruptError(6927); + memcpy(pData, pCell, sz); + assert( sz==pPg->xCellSize(pPg, pCell) || (sqlite3Config.neverCorrupt==0) ); + ; + i++; + if( i>=iEnd ) break; + if( pCArray->ixNx[k]<=i ){ + k++; + pSrcEnd = pCArray->apEnd[k]; + } + } + + + pPg->nCell = nCell; + pPg->nOverflow = 0; + + ((&aData[hdr+1])[0] = (u8)((0)>>8), (&aData[hdr+1])[1] = (u8)(0)); + ((&aData[hdr+3])[0] = (u8)((pPg->nCell)>>8), (&aData[hdr+3])[1] = (u8)(pPg->nCell)); + ((&aData[hdr+5])[0] = (u8)((pData - aData)>>8), (&aData[hdr+5])[1] = (u8)(pData - aData)); + aData[hdr+7] = 0x00; + return 0; +} +# 6974 "src/btree.c" +static int pageInsertArray( + MemPage *pPg, + u8 *pBegin, + u8 **ppData, + u8 *pCellptr, + int iFirst, + int nCell, + CellArray *pCArray +){ + int i = iFirst; + u8 *aData = pPg->aData; + u8 *pData = *ppData; + int iEnd = iFirst + nCell; + int k; + u8 *pEnd; + assert( (sqlite3Config.neverCorrupt==0) || pPg->hdrOffset==0 ); + if( iEnd<=iFirst ) return 0; + for(k=0; pCArray->ixNx[k]<=i && (k<3*2); k++){} + pEnd = pCArray->apEnd[k]; + while( 1 ){ + int sz, rc; + u8 *pSlot; + sz = cachedCellSize(pCArray, i); + if( (aData[1]==0 && aData[2]==0) || (pSlot = pageFindSlot(pPg,sz,&rc))==0 ){ + if( (pData - pBegin)<sz ) return 1; + pData -= sz; + pSlot = pData; + } + + + + assert( (pSlot+sz)<=pCArray->apCell[i] + || pSlot>=(pCArray->apCell[i]+sz) + || (sqlite3Config.neverCorrupt==0) ); + if( (uptr)(pCArray->apCell[i]+sz)>(uptr)pEnd + && (uptr)(pCArray->apCell[i])<(uptr)pEnd + ){ + assert( (sqlite3Config.neverCorrupt==0) ); + (void)sqlite3CorruptError(7012); + return 1; + } + memmove(pSlot, pCArray->apCell[i], sz); + ((pCellptr)[0] = (u8)(((pSlot - aData))>>8), (pCellptr)[1] = (u8)((pSlot - aData))); + pCellptr += 2; + i++; + if( i>=iEnd ) break; + if( pCArray->ixNx[k]<=i ){ + k++; + pEnd = pCArray->apEnd[k]; + } + } + *ppData = pData; + return 0; +} +# 7038 "src/btree.c" +static int pageFreeArray( + MemPage *pPg, + int iFirst, + int nCell, + CellArray *pCArray +){ + u8 * const aData = pPg->aData; + u8 * const pEnd = &aData[pPg->pBt->usableSize]; + u8 * const pStart = &aData[pPg->hdrOffset + 8 + pPg->childPtrSize]; + int nRet = 0; + int i; + int iEnd = iFirst + nCell; + u8 *pFree = 0; + int szFree = 0; + + for(i=iFirst; i<iEnd; i++){ + u8 *pCell = pCArray->apCell[i]; + if( (((uptr)(pCell)>=(uptr)(pStart))&&((uptr)(pCell)<(uptr)(pEnd))) ){ + int sz; + + + + sz = pCArray->szCell[i]; assert( sz>0 ); + if( pFree!=(pCell + sz) ){ + if( pFree ){ + assert( pFree>aData && (pFree - aData)<65536 ); + freeSpace(pPg, (u16)(pFree - aData), szFree); + } + pFree = pCell; + szFree = sz; + if( pFree+sz>pEnd ) return 0; + }else{ + pFree = pCell; + szFree += sz; + } + nRet++; + } + } + if( pFree ){ + assert( pFree>aData && (pFree - aData)<65536 ); + freeSpace(pPg, (u16)(pFree - aData), szFree); + } + return nRet; +} +# 7095 "src/btree.c" +static int editPage( + MemPage *pPg, + int iOld, + int iNew, + int nNew, + CellArray *pCArray +){ + u8 * const aData = pPg->aData; + const int hdr = pPg->hdrOffset; + u8 *pBegin = &pPg->aCellIdx[nNew * 2]; + int nCell = pPg->nCell; + u8 *pData; + u8 *pCellptr; + int i; + int iOldEnd = iOld + pPg->nCell + pPg->nOverflow; + int iNewEnd = iNew + nNew; + + + + + + + + assert( nCell>=0 ); + if( iOld<iNew ){ + int nShift = pageFreeArray(pPg, iOld, iNew-iOld, pCArray); + if( nShift>nCell ) return sqlite3CorruptError(7121); + memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2); + nCell -= nShift; + } + if( iNewEnd < iOldEnd ){ + int nTail = pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray); + assert( nCell>=nTail ); + nCell -= nTail; + } + + pData = &aData[(((((int)((&aData[hdr+5])[0]<<8 | (&aData[hdr+5])[1]))-1)&0xffff)+1)]; + if( pData<pBegin ) goto editpage_fail; + + + if( iNew<iOld ){ + int nAdd = ((nNew)<(iOld-iNew)?(nNew):(iOld-iNew)); + assert( (iOld-iNew)<nNew || nCell==0 || (sqlite3Config.neverCorrupt==0) ); + assert( nAdd>=0 ); + pCellptr = pPg->aCellIdx; + memmove(&pCellptr[nAdd*2], pCellptr, nCell*2); + if( pageInsertArray( + pPg, pBegin, &pData, pCellptr, + iNew, nAdd, pCArray + ) ) goto editpage_fail; + nCell += nAdd; + } + + + for(i=0; i<pPg->nOverflow; i++){ + int iCell = (iOld + pPg->aiOvfl[i]) - iNew; + if( iCell>=0 && iCell<nNew ){ + pCellptr = &pPg->aCellIdx[iCell * 2]; + if( nCell>iCell ){ + memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2); + } + nCell++; + if( pageInsertArray( + pPg, pBegin, &pData, pCellptr, + iCell+iNew, 1, pCArray + ) ) goto editpage_fail; + } + } + + + assert( nCell>=0 ); + pCellptr = &pPg->aCellIdx[nCell*2]; + if( pageInsertArray( + pPg, pBegin, &pData, pCellptr, + iNew+nCell, nNew-nCell, pCArray + ) ) goto editpage_fail; + + pPg->nCell = nNew; + pPg->nOverflow = 0; + + ((&aData[hdr+3])[0] = (u8)((pPg->nCell)>>8), (&aData[hdr+3])[1] = (u8)(pPg->nCell)); + ((&aData[hdr+5])[0] = (u8)((pData - aData)>>8), (&aData[hdr+5])[1] = (u8)(pData - aData)); +# 7190 "src/btree.c" + return 0; + editpage_fail: + + populateCellCache(pCArray, iNew, nNew); + return rebuildPage(pCArray, iNew, nNew, pPg); +} +# 7222 "src/btree.c" +static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){ + BtShared *const pBt = pPage->pBt; + MemPage *pNew; + int rc; + Pgno pgnoNew; + + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( sqlite3PagerIswriteable(pParent->pDbPage) ); + assert( pPage->nOverflow==1 ); + + if( pPage->nCell==0 ) return sqlite3CorruptError(7232); + assert( pPage->nFree>=0 ); + assert( pParent->nFree>=0 ); + + + + + + rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0); + + if( rc==0 ){ + + u8 *pOut = &pSpace[4]; + u8 *pCell = pPage->apOvfl[0]; + u16 szCell = pPage->xCellSize(pPage, pCell); + u8 *pStop; + CellArray b; + + assert( sqlite3PagerIswriteable(pNew->pDbPage) ); + assert( (sqlite3Config.neverCorrupt==0) || pPage->aData[0]==(0x01|0x04|0x08) ); + zeroPage(pNew, 0x01|0x04|0x08); + b.nCell = 1; + b.pRef = pPage; + b.apCell = &pCell; + b.szCell = &szCell; + b.apEnd[0] = pPage->aDataEnd; + b.ixNx[0] = 2; + rc = rebuildPage(&b, 0, 1, pNew); + if( (rc) ){ + releasePage(pNew); + return rc; + } + pNew->nFree = pBt->usableSize - pNew->cellOffset - 2 - szCell; +# 7275 "src/btree.c" + if( (pBt->autoVacuum) ){ + ptrmapPut(pBt, pgnoNew, 5, pParent->pgno, &rc); + if( szCell>pNew->minLocal ){ + ptrmapPutOvflPtr(pNew, pNew, pCell, &rc); + } + } +# 7295 "src/btree.c" + pCell = ((pPage)->aData + ((pPage)->maskPage & __builtin_bswap16(*(u16*)(&(pPage)->aCellIdx[2*(pPage->nCell-1)])))); + pStop = &pCell[9]; + while( (*(pCell++)&0x80) && pCell<pStop ); + pStop = &pCell[9]; + while( ((*(pOut++) = *(pCell++))&0x80) && pCell<pStop ); + + + if( rc==0 ){ + insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace), + 0, pPage->pgno, &rc); + } + + + sqlite3Put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew); + + + releasePage(pNew); + } + + return rc; +} +# 7377 "src/btree.c" +static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){ + if( (*pRC)==0 ){ + BtShared * const pBt = pFrom->pBt; + u8 * const aFrom = pFrom->aData; + u8 * const aTo = pTo->aData; + int const iFromHdr = pFrom->hdrOffset; + int const iToHdr = ((pTo->pgno==1) ? 100 : 0); + int rc; + int iData; + + + assert( pFrom->isInit ); + assert( pFrom->nFree>=iToHdr ); + assert( ((&aFrom[iFromHdr+5])[0]<<8 | (&aFrom[iFromHdr+5])[1]) <= (int)pBt->usableSize ); + + + iData = ((&aFrom[iFromHdr+5])[0]<<8 | (&aFrom[iFromHdr+5])[1]); + memcpy(&aTo[iData], &aFrom[iData], pBt->usableSize-iData); + memcpy(&aTo[iToHdr], &aFrom[iFromHdr], pFrom->cellOffset + 2*pFrom->nCell); + + + + + + + pTo->isInit = 0; + rc = btreeInitPage(pTo); + if( rc==0 ) rc = btreeComputeFreeSpace(pTo); + if( rc!=0 ){ + *pRC = rc; + return; + } + + + + + if( (pBt->autoVacuum) ){ + *pRC = setChildPtrmaps(pTo); + } + } +} +# 7459 "src/btree.c" +static int balance_nonroot( + MemPage *pParent, + int iParentIdx, + u8 *aOvflSpace, + int isRoot, + int bBulk +){ + BtShared *pBt; + int nMaxCells = 0; + int nNew = 0; + int nOld; + int i, j, k; + int nxDiv; + int rc = 0; + u16 leafCorrection; + int leafData; + int usableSpace; + int pageFlags; + int iSpace1 = 0; + int iOvflSpace = 0; + int szScratch; + MemPage *apOld[3]; + MemPage *apNew[3 +2]; + u8 *pRight; + u8 *apDiv[3 -1]; + int cntNew[3 +2]; + int cntOld[3 +2]; + int szNew[3 +2]; + u8 *aSpace1; + Pgno pgno; + u8 abDone[3 +2]; + Pgno aPgno[3 +2]; + Pgno aPgOrder[3 +2]; + u16 aPgFlags[3 +2]; + CellArray b; + + memset(abDone, 0, sizeof(abDone)); + b.nCell = 0; + b.apCell = 0; + pBt = pParent->pBt; + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( sqlite3PagerIswriteable(pParent->pDbPage) ); + + + + + + + assert( pParent->nOverflow==0 || pParent->nOverflow==1 ); + assert( pParent->nOverflow==0 || pParent->aiOvfl[0]==iParentIdx ); + + if( !aOvflSpace ){ + return 7; + } + assert( pParent->nFree>=0 ); +# 7526 "src/btree.c" + i = pParent->nOverflow + pParent->nCell; + if( i<2 ){ + nxDiv = 0; + }else{ + assert( bBulk==0 || bBulk==1 ); + if( iParentIdx==0 ){ + nxDiv = 0; + }else if( iParentIdx==i ){ + nxDiv = i-2+bBulk; + }else{ + nxDiv = iParentIdx-1; + } + i = 2-bBulk; + } + nOld = i+1; + if( (i+nxDiv-pParent->nOverflow)==pParent->nCell ){ + pRight = &pParent->aData[pParent->hdrOffset+8]; + }else{ + pRight = ((pParent)->aData + ((pParent)->maskPage & __builtin_bswap16(*(u16*)(&(pParent)->aCellIdx[2*(i+nxDiv-pParent->nOverflow)])))); + } + pgno = sqlite3Get4byte(pRight); + while( 1 ){ + rc = getAndInitPage(pBt, pgno, &apOld[i], 0, 0); + if( rc ){ + memset(apOld, 0, (i+1)*sizeof(MemPage*)); + goto balance_cleanup; + } + if( apOld[i]->nFree<0 ){ + rc = btreeComputeFreeSpace(apOld[i]); + if( rc ){ + memset(apOld, 0, (i)*sizeof(MemPage*)); + goto balance_cleanup; + } + } + if( (i--)==0 ) break; + + if( pParent->nOverflow && i+nxDiv==pParent->aiOvfl[0] ){ + apDiv[i] = pParent->apOvfl[0]; + pgno = sqlite3Get4byte(apDiv[i]); + szNew[i] = pParent->xCellSize(pParent, apDiv[i]); + pParent->nOverflow = 0; + }else{ + apDiv[i] = ((pParent)->aData + ((pParent)->maskPage & __builtin_bswap16(*(u16*)(&(pParent)->aCellIdx[2*(i+nxDiv-pParent->nOverflow)])))); + pgno = sqlite3Get4byte(apDiv[i]); + szNew[i] = pParent->xCellSize(pParent, apDiv[i]); +# 7584 "src/btree.c" + if( pBt->btsFlags & 0x000c ){ + int iOff; + + iOff = ((int)(long int)(apDiv[i])) - ((int)(long int)(pParent->aData)); + if( (iOff+szNew[i])>(int)pBt->usableSize ){ + rc = sqlite3CorruptError(7589); + memset(apOld, 0, (i+1)*sizeof(MemPage*)); + goto balance_cleanup; + }else{ + memcpy(&aOvflSpace[iOff], apDiv[i], szNew[i]); + apDiv[i] = &aOvflSpace[apDiv[i]-pParent->aData]; + } + } + dropCell(pParent, i+nxDiv-pParent->nOverflow, szNew[i], &rc); + } + } + + + + nMaxCells = nOld*(((pBt->pageSize-8)/6) + ((int)(sizeof(pParent->apOvfl)/sizeof(pParent->apOvfl[0])))); + nMaxCells = (nMaxCells + 3)&~3; + + + + + szScratch = + nMaxCells*sizeof(u8*) + + nMaxCells*sizeof(u16) + + pBt->pageSize; + + assert( szScratch<=7*(int)pBt->pageSize ); + b.apCell = sqlite3DbMallocRaw(0,szScratch); + if( b.apCell==0 ){ + rc = 7; + goto balance_cleanup; + } + b.szCell = (u16*)&b.apCell[nMaxCells]; + aSpace1 = (u8*)&b.szCell[nMaxCells]; + assert( ((((char*)(aSpace1) - (char*)0)&7)==0) ); +# 7640 "src/btree.c" + b.pRef = apOld[0]; + leafCorrection = b.pRef->leaf*4; + leafData = b.pRef->intKeyLeaf; + for(i=0; i<nOld; i++){ + MemPage *pOld = apOld[i]; + int limit = pOld->nCell; + u8 *aData = pOld->aData; + u16 maskPage = pOld->maskPage; + u8 *piCell = aData + pOld->cellOffset; + u8 *piEnd; + + + + + + if( pOld->aData[0]!=apOld[0]->aData[0] ){ + rc = sqlite3CorruptError(7656); + goto balance_cleanup; + } +# 7677 "src/btree.c" + memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow)); + if( pOld->nOverflow>0 ){ + if( limit<pOld->aiOvfl[0] ){ + rc = sqlite3CorruptError(7680); + goto balance_cleanup; + } + limit = pOld->aiOvfl[0]; + for(j=0; j<limit; j++){ + b.apCell[b.nCell] = aData + (maskPage & __builtin_bswap16(*(u16*)(piCell))); + piCell += 2; + b.nCell++; + } + for(k=0; k<pOld->nOverflow; k++){ + assert( k==0 || pOld->aiOvfl[k-1]+1==pOld->aiOvfl[k] ); + b.apCell[b.nCell] = pOld->apOvfl[k]; + b.nCell++; + } + } + piEnd = aData + pOld->cellOffset + 2*pOld->nCell; + while( piCell<piEnd ){ + assert( b.nCell<nMaxCells ); + b.apCell[b.nCell] = aData + (maskPage & __builtin_bswap16(*(u16*)(piCell))); + piCell += 2; + b.nCell++; + } + assert( (b.nCell-nCellAtStart)==(pOld->nCell+pOld->nOverflow) ); + + cntOld[i] = b.nCell; + if( i<nOld-1 && !leafData){ + u16 sz = (u16)szNew[i]; + u8 *pTemp; + assert( b.nCell<nMaxCells ); + b.szCell[b.nCell] = sz; + pTemp = &aSpace1[iSpace1]; + iSpace1 += sz; + assert( sz<=pBt->maxLocal+23 ); + assert( iSpace1 <= (int)pBt->pageSize ); + memcpy(pTemp, apDiv[i], sz); + b.apCell[b.nCell] = pTemp+leafCorrection; + assert( leafCorrection==0 || leafCorrection==4 ); + b.szCell[b.nCell] = b.szCell[b.nCell] - leafCorrection; + if( !pOld->leaf ){ + assert( leafCorrection==0 ); + assert( pOld->hdrOffset==0 ); + + + memcpy(b.apCell[b.nCell], &pOld->aData[8], 4); + }else{ + assert( leafCorrection==4 ); + while( b.szCell[b.nCell]<4 ){ + + + assert( b.szCell[b.nCell]==3 || (sqlite3Config.neverCorrupt==0) ); + assert( b.apCell[b.nCell]==&aSpace1[iSpace1-3] || (sqlite3Config.neverCorrupt==0) ); + aSpace1[iSpace1++] = 0x00; + b.szCell[b.nCell]++; + } + } + b.nCell++; + } + } +# 7755 "src/btree.c" + usableSpace = pBt->usableSize - 12 + leafCorrection; + for(i=k=0; i<nOld; i++, k++){ + MemPage *p = apOld[i]; + b.apEnd[k] = p->aDataEnd; + b.ixNx[k] = cntOld[i]; + if( k && b.ixNx[k]==b.ixNx[k-1] ){ + k--; + } + if( !leafData ){ + k++; + b.apEnd[k] = pParent->aDataEnd; + b.ixNx[k] = cntOld[i]+1; + } + assert( p->nFree>=0 ); + szNew[i] = usableSpace - p->nFree; + for(j=0; j<p->nOverflow; j++){ + szNew[i] += 2 + p->xCellSize(p, p->apOvfl[j]); + } + cntNew[i] = cntOld[i]; + } + k = nOld; + for(i=0; i<k; i++){ + int sz; + while( szNew[i]>usableSpace ){ + if( i+1>=k ){ + k = i+2; + if( k>3 +2 ){ rc = sqlite3CorruptError(7781); goto balance_cleanup; } + szNew[k-1] = 0; + cntNew[k-1] = b.nCell; + } + sz = 2 + cachedCellSize(&b, cntNew[i]-1); + szNew[i] -= sz; + if( !leafData ){ + if( cntNew[i]<b.nCell ){ + sz = 2 + cachedCellSize(&b, cntNew[i]); + }else{ + sz = 0; + } + } + szNew[i+1] += sz; + cntNew[i]--; + } + while( cntNew[i]<b.nCell ){ + sz = 2 + cachedCellSize(&b, cntNew[i]); + if( szNew[i]+sz>usableSpace ) break; + szNew[i] += sz; + cntNew[i]++; + if( !leafData ){ + if( cntNew[i]<b.nCell ){ + sz = 2 + cachedCellSize(&b, cntNew[i]); + }else{ + sz = 0; + } + } + szNew[i+1] -= sz; + } + if( cntNew[i]>=b.nCell ){ + k = i+1; + }else if( cntNew[i] <= (i>0 ? cntNew[i-1] : 0) ){ + rc = sqlite3CorruptError(7814); + goto balance_cleanup; + } + } +# 7830 "src/btree.c" + for(i=k-1; i>0; i--){ + int szRight = szNew[i]; + int szLeft = szNew[i-1]; + int r; + int d; + + r = cntNew[i-1] - 1; + d = r + 1 - leafData; + (void)cachedCellSize(&b, d); + do{ + assert( d<nMaxCells ); + assert( r<nMaxCells ); + (void)cachedCellSize(&b, r); + if( szRight!=0 + && (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+(i==k-1?0:2)))){ + break; + } + szRight += b.szCell[d] + 2; + szLeft -= b.szCell[r] + 2; + cntNew[i-1] = r; + r--; + d--; + }while( r>=0 ); + szNew[i] = szRight; + szNew[i-1] = szLeft; + if( cntNew[i-1] <= (i>1 ? cntNew[i-2] : 0) ){ + rc = sqlite3CorruptError(7856); + goto balance_cleanup; + } + } +# 7868 "src/btree.c" + assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) || (sqlite3Config.neverCorrupt==0)); + + + + + ; + + + + + pageFlags = apOld[0]->aData[0]; + for(i=0; i<k; i++){ + MemPage *pNew; + if( i<nOld ){ + pNew = apNew[i] = apOld[i]; + apOld[i] = 0; + rc = sqlite3PagerWrite(pNew->pDbPage); + nNew++; + if( rc ) goto balance_cleanup; + }else{ + assert( i>0 ); + rc = allocateBtreePage(pBt, &pNew, &pgno, (bBulk ? 1 : pgno), 0); + if( rc ) goto balance_cleanup; + zeroPage(pNew, pageFlags); + apNew[i] = pNew; + nNew++; + cntOld[i] = b.nCell; + + + if( (pBt->autoVacuum) ){ + ptrmapPut(pBt, pNew->pgno, 5, pParent->pgno, &rc); + if( rc!=0 ){ + goto balance_cleanup; + } + } + } + } +# 7918 "src/btree.c" + for(i=0; i<nNew; i++){ + aPgOrder[i] = aPgno[i] = apNew[i]->pgno; + aPgFlags[i] = apNew[i]->pDbPage->flags; + for(j=0; j<i; j++){ + if( aPgno[j]==aPgno[i] ){ + + + + + + + assert( (sqlite3Config.neverCorrupt==0) ); + rc = sqlite3CorruptError(7930); + goto balance_cleanup; + } + } + } + for(i=0; i<nNew; i++){ + int iBest = 0; + for(j=1; j<nNew; j++){ + if( aPgOrder[j]<aPgOrder[iBest] ) iBest = j; + } + pgno = aPgOrder[iBest]; + aPgOrder[iBest] = 0xffffffff; + if( iBest!=i ){ + if( iBest>i ){ + sqlite3PagerRekey(apNew[iBest]->pDbPage, pBt->nPage+iBest+1, 0); + } + sqlite3PagerRekey(apNew[i]->pDbPage, pgno, aPgFlags[iBest]); + apNew[i]->pgno = pgno; + } + } + + +# 7962 "src/btree.c" + ; + + assert( sqlite3PagerIswriteable(pParent->pDbPage) ); + sqlite3Put4byte(pRight, apNew[nNew-1]->pgno); + + + + + if( (pageFlags & 0x08)==0 && nOld!=nNew ){ + MemPage *pOld = (nNew>nOld ? apNew : apOld)[nOld-1]; + memcpy(&apNew[nNew-1]->aData[8], &pOld->aData[8], 4); + } +# 7991 "src/btree.c" + if( (pBt->autoVacuum) ){ + MemPage *pOld; + MemPage *pNew = pOld = apNew[0]; + int cntOldNext = pNew->nCell + pNew->nOverflow; + int iNew = 0; + int iOld = 0; + + for(i=0; i<b.nCell; i++){ + u8 *pCell = b.apCell[i]; + while( i==cntOldNext ){ + iOld++; + assert( iOld<nNew || iOld<nOld ); + assert( iOld>=0 && iOld<3 ); + pOld = iOld<nNew ? apNew[iOld] : apOld[iOld]; + cntOldNext += pOld->nCell + pOld->nOverflow + !leafData; + } + if( i==cntNew[iNew] ){ + pNew = apNew[++iNew]; + if( !leafData ) continue; + } + + + + + + + + if( iOld>=nNew + || pNew->pgno!=aPgno[iOld] + || !(((uptr)(pCell)>=(uptr)(pOld->aData))&&((uptr)(pCell)<(uptr)(pOld->aDataEnd))) + ){ + if( !leafCorrection ){ + ptrmapPut(pBt, sqlite3Get4byte(pCell), 5, pNew->pgno, &rc); + } + if( cachedCellSize(&b,i)>pNew->minLocal ){ + ptrmapPutOvflPtr(pNew, pOld, pCell, &rc); + } + if( rc ) goto balance_cleanup; + } + } + } + + + for(i=0; i<nNew-1; i++){ + u8 *pCell; + u8 *pTemp; + int sz; + MemPage *pNew = apNew[i]; + j = cntNew[i]; + + assert( j<nMaxCells ); + assert( b.apCell[j]!=0 ); + pCell = b.apCell[j]; + sz = b.szCell[j] + leafCorrection; + pTemp = &aOvflSpace[iOvflSpace]; + if( !pNew->leaf ){ + memcpy(&pNew->aData[8], pCell, 4); + }else if( leafData ){ + + + + + + CellInfo info; + j--; + pNew->xParseCell(pNew, b.apCell[j], &info); + pCell = pTemp; + sz = 4 + sqlite3PutVarint(&pCell[4], info.nKey); + pTemp = 0; + }else{ + pCell -= 4; +# 8073 "src/btree.c" + if( b.szCell[j]==4 ){ + assert(leafCorrection==4); + sz = pParent->xCellSize(pParent, pCell); + } + } + iOvflSpace += sz; + assert( sz<=pBt->maxLocal+23 ); + assert( iOvflSpace <= (int)pBt->pageSize ); + insertCell(pParent, nxDiv+i, pCell, sz, pTemp, pNew->pgno, &rc); + if( rc!=0 ) goto balance_cleanup; + assert( sqlite3PagerIswriteable(pParent->pDbPage) ); + } +# 8108 "src/btree.c" + for(i=1-nNew; i<nNew; i++){ + int iPg = i<0 ? -i : i; + assert( iPg>=0 && iPg<nNew ); + if( abDone[iPg] ) continue; + if( i>=0 + || cntOld[iPg-1]>=cntNew[iPg-1] + ){ + int iNew; + int iOld; + int nNewCell; + + + + assert( iPg==0 || cntOld[iPg-1]>=cntNew[iPg-1] || abDone[iPg-1] ); + + + + assert( cntNew[iPg]>=cntOld[iPg] || abDone[iPg+1] ); + + if( iPg==0 ){ + iNew = iOld = 0; + nNewCell = cntNew[0]; + }else{ + iOld = iPg<nOld ? (cntOld[iPg-1] + !leafData) : b.nCell; + iNew = cntNew[iPg-1] + !leafData; + nNewCell = cntNew[iPg] - iNew; + } + + rc = editPage(apNew[iPg], iOld, iNew, nNewCell, &b); + if( rc ) goto balance_cleanup; + abDone[iPg]++; + apNew[iPg]->nFree = usableSpace-szNew[iPg]; + assert( apNew[iPg]->nOverflow==0 ); + assert( apNew[iPg]->nCell==nNewCell ); + } + } + + + assert( memcmp(abDone, "\01\01\01\01\01", nNew)==0 ); + + assert( nOld>0 ); + assert( nNew>0 ); + + if( isRoot && pParent->nCell==0 && pParent->hdrOffset<=apNew[0]->nFree ){ +# 8167 "src/btree.c" + assert( nNew==1 || (sqlite3Config.neverCorrupt==0) ); + rc = defragmentPage(apNew[0], -1); + ; + assert( apNew[0]->nFree == + ((((((int)((&apNew[0]->aData[5])[0]<<8 | (&apNew[0]->aData[5])[1]))-1)&0xffff)+1) - apNew[0]->cellOffset + - apNew[0]->nCell*2) + || rc!=0 + ); + copyNodeContent(apNew[0], pParent, &rc); + freePage(apNew[0], &rc); + }else if( (pBt->autoVacuum) && !leafCorrection ){ + + + + for(i=0; i<nNew; i++){ + u32 key = sqlite3Get4byte(&apNew[i]->aData[8]); + ptrmapPut(pBt, key, 5, apNew[i]->pgno, &rc); + } + } + + assert( pParent->isInit ); + + ; + + + + for(i=nNew; i<nOld; i++){ + freePage(apOld[i], &rc); + } +# 8211 "src/btree.c" +balance_cleanup: + sqlite3DbFree(0,b.apCell); + for(i=0; i<nOld; i++){ + releasePage(apOld[i]); + } + for(i=0; i<nNew; i++){ + releasePage(apNew[i]); + } + + return rc; +} +# 8243 "src/btree.c" +static int balance_deeper(MemPage *pRoot, MemPage **ppChild){ + int rc; + MemPage *pChild = 0; + Pgno pgnoChild = 0; + BtShared *pBt = pRoot->pBt; + + assert( pRoot->nOverflow>0 ); + assert( sqlite3_mutex_held(pBt->mutex) ); + + + + + + rc = sqlite3PagerWrite(pRoot->pDbPage); + if( rc==0 ){ + rc = allocateBtreePage(pBt,&pChild,&pgnoChild,pRoot->pgno,0); + copyNodeContent(pRoot, pChild, &rc); + if( (pBt->autoVacuum) ){ + ptrmapPut(pBt, pgnoChild, 5, pRoot->pgno, &rc); + } + } + if( rc ){ + *ppChild = 0; + releasePage(pChild); + return rc; + } + assert( sqlite3PagerIswriteable(pChild->pDbPage) ); + assert( sqlite3PagerIswriteable(pRoot->pDbPage) ); + assert( pChild->nCell==pRoot->nCell || (sqlite3Config.neverCorrupt==0) ); + + ; + + + memcpy(pChild->aiOvfl, pRoot->aiOvfl, + pRoot->nOverflow*sizeof(pRoot->aiOvfl[0])); + memcpy(pChild->apOvfl, pRoot->apOvfl, + pRoot->nOverflow*sizeof(pRoot->apOvfl[0])); + pChild->nOverflow = pRoot->nOverflow; + + + zeroPage(pRoot, pChild->aData[0] & ~0x08); + sqlite3Put4byte(&pRoot->aData[pRoot->hdrOffset+8], pgnoChild); + + *ppChild = pChild; + return 0; +} +# 8300 "src/btree.c" +static int balance(BtCursor *pCur){ + int rc = 0; + const int nMin = pCur->pBt->usableSize * 2 / 3; + u8 aBalanceQuickSpace[13]; + u8 *pFree = 0; + + ; + ; + + do { + int iPage = pCur->iPage; + MemPage *pPage = pCur->pPage; + + if( (pPage->nFree<0) && btreeComputeFreeSpace(pPage) ) break; + if( iPage==0 ){ + if( pPage->nOverflow ){ + + + + + + assert( balance_deeper_called==0 ); + ; + rc = balance_deeper(pPage, &pCur->apPage[1]); + if( rc==0 ){ + pCur->iPage = 1; + pCur->ix = 0; + pCur->aiIdx[0] = 0; + pCur->apPage[0] = pPage; + pCur->pPage = pCur->apPage[1]; + assert( pCur->pPage->nOverflow ); + } + }else{ + break; + } + }else if( pPage->nOverflow==0 && pPage->nFree<=nMin ){ + break; + }else{ + MemPage * const pParent = pCur->apPage[iPage-1]; + int const iIdx = pCur->aiIdx[iPage-1]; + + rc = sqlite3PagerWrite(pParent->pDbPage); + if( rc==0 && pParent->nFree<0 ){ + rc = btreeComputeFreeSpace(pParent); + } + if( rc==0 ){ + + if( pPage->intKeyLeaf + && pPage->nOverflow==1 + && pPage->aiOvfl[0]==pPage->nCell + && pParent->pgno!=1 + && pParent->nCell==iIdx + ){ +# 8366 "src/btree.c" + assert( balance_quick_called==0 ); + ; + rc = balance_quick(pParent, pPage, aBalanceQuickSpace); + }else + + { +# 8389 "src/btree.c" + u8 *pSpace = sqlite3PageMalloc(pCur->pBt->pageSize); + rc = balance_nonroot(pParent, iIdx, pSpace, iPage==1, + pCur->hints&0x00000001); + if( pFree ){ + + + + + sqlite3PageFree(pFree); + } + + + + + pFree = pSpace; + } + } + + pPage->nOverflow = 0; + + + releasePage(pPage); + pCur->iPage--; + assert( pCur->iPage>=0 ); + pCur->pPage = pCur->apPage[pCur->iPage]; + } + }while( rc==0 ); + + if( pFree ){ + sqlite3PageFree(pFree); + } + return rc; +} + + + + +static int btreeOverwriteContent( + MemPage *pPage, + u8 *pDest, + const BtreePayload *pX, + int iOffset, + int iAmt +){ + int nData = pX->nData - iOffset; + if( nData<=0 ){ + + int i; + for(i=0; i<iAmt && pDest[i]==0; i++){} + if( i<iAmt ){ + int rc = sqlite3PagerWrite(pPage->pDbPage); + if( rc ) return rc; + memset(pDest + i, 0, iAmt - i); + } + }else{ + if( nData<iAmt ){ + + + int rc = btreeOverwriteContent(pPage, pDest+nData, pX, iOffset+nData, + iAmt-nData); + if( rc ) return rc; + iAmt = nData; + } + if( memcmp(pDest, ((u8*)pX->pData) + iOffset, iAmt)!=0 ){ + int rc = sqlite3PagerWrite(pPage->pDbPage); + if( rc ) return rc; + + + + + memmove(pDest, ((u8*)pX->pData) + iOffset, iAmt); + } + } + return 0; +} + + + + + +static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){ + int iOffset; + int nTotal = pX->nData + pX->nZero; + int rc; + MemPage *pPage = pCur->pPage; + BtShared *pBt; + Pgno ovflPgno; + u32 ovflPageSize; + + if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd ){ + return sqlite3CorruptError(8479); + } + + rc = btreeOverwriteContent(pPage, pCur->info.pPayload, pX, + 0, pCur->info.nLocal); + if( rc ) return rc; + if( pCur->info.nLocal==nTotal ) return 0; + + + iOffset = pCur->info.nLocal; + assert( nTotal>=0 ); + assert( iOffset>=0 ); + ovflPgno = sqlite3Get4byte(pCur->info.pPayload + iOffset); + pBt = pPage->pBt; + ovflPageSize = pBt->usableSize - 4; + do{ + rc = btreeGetPage(pBt, ovflPgno, &pPage, 0); + if( rc ) return rc; + if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 ){ + rc = sqlite3CorruptError(8498); + }else{ + if( iOffset+ovflPageSize<(u32)nTotal ){ + ovflPgno = sqlite3Get4byte(pPage->aData); + }else{ + ovflPageSize = nTotal - iOffset; + } + rc = btreeOverwriteContent(pPage, pPage->aData+4, pX, + iOffset, ovflPageSize); + } + sqlite3PagerUnref(pPage->pDbPage); + if( rc ) return rc; + iOffset += ovflPageSize; + }while( iOffset<nTotal ); + return 0; +} +# 8546 "src/btree.c" +int sqlite3BtreeInsert( + BtCursor *pCur, + const BtreePayload *pX, + int flags, + int seekResult +){ + int rc; + int loc = seekResult; + int szNew = 0; + int idx; + MemPage *pPage; + Btree *p = pCur->pBtree; + BtShared *pBt = p->pBt; + unsigned char *oldCell; + unsigned char *newCell = 0; + + assert( (flags & (0x02|0x08))==flags ); + + if( pCur->eState==4 ){ + assert( pCur->skipNext!=0 ); + return pCur->skipNext; + } + + assert( cursorOwnsBtShared(pCur) ); + assert( (pCur->curFlags & 0x01)!=0 + && pBt->inTransaction==2 + && (pBt->btsFlags & 0x0001)==0 ); + assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); + + + + + + + assert( (pX->pKey==0)==(pCur->pKeyInfo==0) ); +# 8593 "src/btree.c" + if( pCur->curFlags & 0x20 ){ + rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur); + if( rc ) return rc; + } + + if( pCur->pKeyInfo==0 ){ + assert( pX->pKey==0 ); + + + invalidateIncrblobCursors(p, pCur->pgnoRoot, pX->nKey, 0); +# 8620 "src/btree.c" + if( (pCur->curFlags&0x02)!=0 && pX->nKey==pCur->info.nKey ){ + + + assert( pX->nData>=0 && pX->nZero>=0 ); + if( pCur->info.nSize!=0 + && pCur->info.nPayload==(u32)pX->nData+pX->nZero + ){ + + return btreeOverwriteCell(pCur, pX); + } + assert( loc==0 ); + }else if( loc==0 ){ + + + + + rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, flags!=0, &loc); + if( rc ) return rc; + } + }else{ + + + + + + assert( (flags & 0x02)==0 || loc==0 ); + + + + + + + if( loc==0 && (flags & 0x02)==0 ){ + if( pX->nMem ){ + UnpackedRecord r; + r.pKeyInfo = pCur->pKeyInfo; + r.aMem = pX->aMem; + r.nField = pX->nMem; + r.default_rc = 0; + r.errCode = 0; + r.r1 = 0; + r.r2 = 0; + r.eqSeen = 0; + rc = sqlite3BtreeMovetoUnpacked(pCur, &r, 0, flags!=0, &loc); + }else{ + rc = btreeMoveto(pCur, pX->pKey, pX->nKey, flags!=0, &loc); + } + if( rc ) return rc; + } + + + + + + if( loc==0 ){ + getCellInfo(pCur); + if( pCur->info.nKey==pX->nKey ){ + BtreePayload x2; + x2.pData = pX->pKey; + x2.nData = pX->nKey; + x2.nZero = 0; + return btreeOverwriteCell(pCur, &x2); + } + } + + } + assert( pCur->eState==0 || (pCur->eState==1 && loc) ); + + pPage = pCur->pPage; + assert( pPage->intKey || pX->nKey>=0 ); + assert( pPage->leaf || !pPage->intKey ); + if( pPage->nFree<0 ){ + rc = btreeComputeFreeSpace(pPage); + if( rc ) return rc; + } + + + + ; + assert( pPage->isInit ); + newCell = pBt->pTmpSpace; + assert( newCell!=0 ); + rc = fillInCell(pPage, newCell, pX, &szNew); + if( rc ) goto end_insert; + assert( szNew==pPage->xCellSize(pPage, newCell) ); + assert( szNew <= ((int)(pBt->pageSize-8)) ); + idx = pCur->ix; + if( loc==0 ){ + CellInfo info; + assert( idx<pPage->nCell ); + rc = sqlite3PagerWrite(pPage->pDbPage); + if( rc ){ + goto end_insert; + } + oldCell = ((pPage)->aData + ((pPage)->maskPage & __builtin_bswap16(*(u16*)(&(pPage)->aCellIdx[2*(idx)])))); + if( !pPage->leaf ){ + memcpy(newCell, oldCell, 4); + } + rc = clearCell(pPage, oldCell, &info); + if( info.nSize==szNew && info.nLocal==info.nPayload + && (!(pBt->autoVacuum) || szNew<pPage->minLocal) + ){ +# 8731 "src/btree.c" + assert( rc==0 ); + if( oldCell+szNew > pPage->aDataEnd ) return sqlite3CorruptError(8732); + memcpy(oldCell, newCell, szNew); + return 0; + } + dropCell(pPage, idx, info.nSize, &rc); + if( rc ) goto end_insert; + }else if( loc<0 && pPage->nCell>0 ){ + assert( pPage->leaf ); + idx = ++pCur->ix; + pCur->curFlags &= ~0x02; + }else{ + assert( pPage->leaf ); + } + insertCell(pPage, idx, newCell, szNew, 0, 0, &rc); + assert( pPage->nOverflow==0 || rc==0 ); + assert( rc!=0 || pPage->nCell>0 || pPage->nOverflow>0 ); +# 8769 "src/btree.c" + pCur->info.nSize = 0; + if( pPage->nOverflow ){ + assert( rc==0 ); + pCur->curFlags &= ~(0x02); + rc = balance(pCur); + + + + + + pCur->pPage->nOverflow = 0; + pCur->eState = 1; + if( (flags & 0x02) && rc==0 ){ + btreeReleaseAllCursorPages(pCur); + if( pCur->pKeyInfo ){ + assert( pCur->pKey==0 ); + pCur->pKey = sqlite3Malloc( pX->nKey ); + if( pCur->pKey==0 ){ + rc = 7; + }else{ + memcpy(pCur->pKey, pX->pKey, pX->nKey); + } + } + pCur->eState = 3; + pCur->nKey = pX->nKey; + } + } + assert( pCur->iPage<0 || pCur->pPage->nOverflow==0 ); + +end_insert: + return rc; +} +# 8819 "src/btree.c" +int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ + Btree *p = pCur->pBtree; + BtShared *pBt = p->pBt; + int rc; + MemPage *pPage; + unsigned char *pCell; + int iCellIdx; + int iCellDepth; + CellInfo info; + int bSkipnext = 0; + u8 bPreserve = flags & 0x02; + + assert( cursorOwnsBtShared(pCur) ); + assert( pBt->inTransaction==2 ); + assert( (pBt->btsFlags & 0x0001)==0 ); + assert( pCur->curFlags & 0x01 ); + assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); + assert( !hasReadConflicts(p, pCur->pgnoRoot) ); + assert( (flags & ~(0x02 | 0x04))==0 ); + if( pCur->eState==3 ){ + rc = btreeRestoreCursorPosition(pCur); + if( rc ) return rc; + } + assert( pCur->eState==0 ); + + iCellDepth = pCur->iPage; + iCellIdx = pCur->ix; + pPage = pCur->pPage; + pCell = ((pPage)->aData + ((pPage)->maskPage & __builtin_bswap16(*(u16*)(&(pPage)->aCellIdx[2*(iCellIdx)])))); + if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ) return 11; +# 8859 "src/btree.c" + if( bPreserve ){ + if( !pPage->leaf + || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3) + || pPage->nCell==1 + ){ + + + rc = saveCursorKey(pCur); + if( rc ) return rc; + }else{ + bSkipnext = 1; + } + } +# 8880 "src/btree.c" + if( !pPage->leaf ){ + rc = sqlite3BtreePrevious(pCur, 0); + assert( rc!=101 ); + if( rc ) return rc; + } + + + + if( pCur->curFlags & 0x20 ){ + rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur); + if( rc ) return rc; + } + + + + if( pCur->pKeyInfo==0 ){ + invalidateIncrblobCursors(p, pCur->pgnoRoot, pCur->info.nKey, 0); + } + + + + + rc = sqlite3PagerWrite(pPage->pDbPage); + if( rc ) return rc; + rc = clearCell(pPage, pCell, &info); + dropCell(pPage, iCellIdx, info.nSize, &rc); + if( rc ) return rc; + + + + + + + if( !pPage->leaf ){ + MemPage *pLeaf = pCur->pPage; + int nCell; + Pgno n; + unsigned char *pTmp; + + if( pLeaf->nFree<0 ){ + rc = btreeComputeFreeSpace(pLeaf); + if( rc ) return rc; + } + if( iCellDepth<pCur->iPage-1 ){ + n = pCur->apPage[iCellDepth+1]->pgno; + }else{ + n = pCur->pPage->pgno; + } + pCell = ((pLeaf)->aData + ((pLeaf)->maskPage & __builtin_bswap16(*(u16*)(&(pLeaf)->aCellIdx[2*(pLeaf->nCell-1)])))); + if( pCell<&pLeaf->aData[4] ) return sqlite3CorruptError(8929); + nCell = pLeaf->xCellSize(pLeaf, pCell); + assert( ((int)(pBt->pageSize-8)) >= nCell ); + pTmp = pBt->pTmpSpace; + assert( pTmp!=0 ); + rc = sqlite3PagerWrite(pLeaf->pDbPage); + if( rc==0 ){ + insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc); + } + dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc); + if( rc ) return rc; + } +# 8957 "src/btree.c" + rc = balance(pCur); + if( rc==0 && pCur->iPage>iCellDepth ){ + releasePageNotNull(pCur->pPage); + pCur->iPage--; + while( pCur->iPage>iCellDepth ){ + releasePage(pCur->apPage[pCur->iPage--]); + } + pCur->pPage = pCur->apPage[pCur->iPage]; + rc = balance(pCur); + } + + if( rc==0 ){ + if( bSkipnext ){ + assert( bPreserve && (pCur->iPage==iCellDepth || (sqlite3Config.neverCorrupt==0)) ); + assert( pPage==pCur->pPage || (sqlite3Config.neverCorrupt==0) ); + assert( (pPage->nCell>0 || (sqlite3Config.neverCorrupt==0)) && iCellIdx<=pPage->nCell ); + pCur->eState = 2; + if( iCellIdx>=pPage->nCell ){ + pCur->skipNext = -1; + pCur->ix = pPage->nCell-1; + }else{ + pCur->skipNext = 1; + } + }else{ + rc = moveToRoot(pCur); + if( bPreserve ){ + btreeReleaseAllCursorPages(pCur); + pCur->eState = 3; + } + if( rc==16 ) rc = 0; + } + } + return rc; +} +# 9003 "src/btree.c" +static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){ + BtShared *pBt = p->pBt; + MemPage *pRoot; + Pgno pgnoRoot; + int rc; + int ptfFlags; + + assert( sqlite3BtreeHoldsMutex(p) ); + assert( pBt->inTransaction==2 ); + assert( (pBt->btsFlags & 0x0001)==0 ); + + + + + + + + if( pBt->autoVacuum ){ + Pgno pgnoMove; + MemPage *pPageMove; + + + + + + + invalidateAllOverflowCache(pBt); + + + + + + sqlite3BtreeGetMeta(p, 4, &pgnoRoot); + pgnoRoot++; + + + + + while( pgnoRoot==ptrmapPageno(pBt, pgnoRoot) || + pgnoRoot==((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1)) ){ + pgnoRoot++; + } + assert( pgnoRoot>=3 || (sqlite3Config.neverCorrupt==0) ); + ; + + + + + + rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, 1); + if( rc!=0 ){ + return rc; + } + + if( pgnoMove!=pgnoRoot ){ + + + + + + + u8 eType = 0; + Pgno iPtrPage = 0; + + + + + rc = saveAllCursors(pBt, 0, 0); + releasePage(pPageMove); + if( rc!=0 ){ + return rc; + } + + + rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0); + if( rc!=0 ){ + return rc; + } + rc = ptrmapGet(pBt, pgnoRoot, &eType, &iPtrPage); + if( eType==1 || eType==2 ){ + rc = sqlite3CorruptError(9083); + } + if( rc!=0 ){ + releasePage(pRoot); + return rc; + } + assert( eType!=1 ); + assert( eType!=2 ); + rc = relocatePage(pBt, pRoot, eType, iPtrPage, pgnoMove, 0); + releasePage(pRoot); + + + if( rc!=0 ){ + return rc; + } + rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0); + if( rc!=0 ){ + return rc; + } + rc = sqlite3PagerWrite(pRoot->pDbPage); + if( rc!=0 ){ + releasePage(pRoot); + return rc; + } + }else{ + pRoot = pPageMove; + } + + + ptrmapPut(pBt, pgnoRoot, 1, 0, &rc); + if( rc ){ + releasePage(pRoot); + return rc; + } + + + + + + assert( sqlite3PagerIswriteable(pBt->pPage1->pDbPage) ); + rc = sqlite3BtreeUpdateMeta(p, 4, pgnoRoot); + if( (rc) ){ + releasePage(pRoot); + return rc; + } + + }else{ + rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0); + if( rc ) return rc; + } + + assert( sqlite3PagerIswriteable(pRoot->pDbPage) ); + if( createTabFlags & 1 ){ + ptfFlags = 0x01 | 0x04 | 0x08; + }else{ + ptfFlags = 0x02 | 0x08; + } + zeroPage(pRoot, ptfFlags); + sqlite3PagerUnref(pRoot->pDbPage); + assert( (pBt->openFlags & 4)==0 || pgnoRoot==2 ); + *piTable = (int)pgnoRoot; + return 0; +} +int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){ + int rc; + sqlite3BtreeEnter(p); + rc = btreeCreateTable(p, piTable, flags); + sqlite3BtreeLeave(p); + return rc; +} + + + + + +static int clearDatabasePage( + BtShared *pBt, + Pgno pgno, + int freePageFlag, + int *pnChange +){ + MemPage *pPage; + int rc; + unsigned char *pCell; + int i; + int hdr; + CellInfo info; + + assert( sqlite3_mutex_held(pBt->mutex) ); + if( pgno>btreePagecount(pBt) ){ + return sqlite3CorruptError(9173); + } + rc = getAndInitPage(pBt, pgno, &pPage, 0, 0); + if( rc ) return rc; + if( pPage->bBusy ){ + rc = sqlite3CorruptError(9178); + goto cleardatabasepage_out; + } + pPage->bBusy = 1; + hdr = pPage->hdrOffset; + for(i=0; i<pPage->nCell; i++){ + pCell = ((pPage)->aData + ((pPage)->maskPage & __builtin_bswap16(*(u16*)(&(pPage)->aCellIdx[2*(i)])))); + if( !pPage->leaf ){ + rc = clearDatabasePage(pBt, sqlite3Get4byte(pCell), 1, pnChange); + if( rc ) goto cleardatabasepage_out; + } + rc = clearCell(pPage, pCell, &info); + if( rc ) goto cleardatabasepage_out; + } + if( !pPage->leaf ){ + rc = clearDatabasePage(pBt, sqlite3Get4byte(&pPage->aData[hdr+8]), 1, pnChange); + if( rc ) goto cleardatabasepage_out; + }else if( pnChange ){ + assert( pPage->intKey || (sqlite3Config.neverCorrupt==0) ); + ; + *pnChange += pPage->nCell; + } + if( freePageFlag ){ + freePage(pPage, &rc); + }else if( (rc = sqlite3PagerWrite(pPage->pDbPage))==0 ){ + zeroPage(pPage, pPage->aData[hdr] | 0x08); + } + +cleardatabasepage_out: + pPage->bBusy = 0; + releasePage(pPage); + return rc; +} +# 9225 "src/btree.c" +int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){ + int rc; + BtShared *pBt = p->pBt; + sqlite3BtreeEnter(p); + assert( p->inTrans==2 ); + + rc = saveAllCursors(pBt, (Pgno)iTable, 0); + + if( 0==rc ){ + + + + invalidateIncrblobCursors(p, (Pgno)iTable, 0, 1); + rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange); + } + sqlite3BtreeLeave(p); + return rc; +} + + + + + + +int sqlite3BtreeClearTableOfCursor(BtCursor *pCur){ + return sqlite3BtreeClearTable(pCur->pBtree, pCur->pgnoRoot, 0); +} +# 9273 "src/btree.c" +static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){ + int rc; + MemPage *pPage = 0; + BtShared *pBt = p->pBt; + + assert( sqlite3BtreeHoldsMutex(p) ); + assert( p->inTrans==2 ); + assert( iTable>=2 ); + if( iTable>btreePagecount(pBt) ){ + return sqlite3CorruptError(9282); + } + + rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0); + if( rc ) return rc; + rc = sqlite3BtreeClearTable(p, iTable, 0); + if( rc ){ + releasePage(pPage); + return rc; + } + + *piMoved = 0; + + + + + + if( pBt->autoVacuum ){ + Pgno maxRootPgno; + sqlite3BtreeGetMeta(p, 4, &maxRootPgno); + + if( iTable==maxRootPgno ){ + + + + freePage(pPage, &rc); + releasePage(pPage); + if( rc!=0 ){ + return rc; + } + }else{ + + + + + MemPage *pMove; + releasePage(pPage); + rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); + if( rc!=0 ){ + return rc; + } + rc = relocatePage(pBt, pMove, 1, 0, iTable, 0); + releasePage(pMove); + if( rc!=0 ){ + return rc; + } + pMove = 0; + rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); + freePage(pMove, &rc); + releasePage(pMove); + if( rc!=0 ){ + return rc; + } + *piMoved = maxRootPgno; + } + + + + + + + maxRootPgno--; + while( maxRootPgno==((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1)) + || (ptrmapPageno((pBt), (maxRootPgno))==(maxRootPgno)) ){ + maxRootPgno--; + } + assert( maxRootPgno!=((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1)) ); + + rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno); + }else{ + freePage(pPage, &rc); + releasePage(pPage); + } + + return rc; +} +int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ + int rc; + sqlite3BtreeEnter(p); + rc = btreeDropTable(p, iTable, piMoved); + sqlite3BtreeLeave(p); + return rc; +} +# 9387 "src/btree.c" +void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ + BtShared *pBt = p->pBt; + + sqlite3BtreeEnter(p); + assert( p->inTrans>0 ); + assert( 0==querySharedCacheTableLock(p, 1, 1) ); + assert( pBt->pPage1 ); + assert( idx>=0 && idx<=15 ); + + if( idx==15 ){ + *pMeta = sqlite3PagerDataVersion(pBt->pPager) + p->iDataVersion; + }else{ + *pMeta = sqlite3Get4byte(&pBt->pPage1->aData[36 + idx*4]); + } +# 9410 "src/btree.c" + sqlite3BtreeLeave(p); +} + + + + + +int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ + BtShared *pBt = p->pBt; + unsigned char *pP1; + int rc; + assert( idx>=1 && idx<=15 ); + sqlite3BtreeEnter(p); + assert( p->inTrans==2 ); + assert( pBt->pPage1!=0 ); + pP1 = pBt->pPage1->aData; + rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); + if( rc==0 ){ + sqlite3Put4byte(&pP1[36 + idx*4], iMeta); + + if( idx==7 ){ + assert( pBt->autoVacuum || iMeta==0 ); + assert( iMeta==0 || iMeta==1 ); + pBt->incrVacuum = (u8)iMeta; + } + + } + sqlite3BtreeLeave(p); + return rc; +} +# 9450 "src/btree.c" +int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){ + i64 nEntry = 0; + int rc; + + rc = moveToRoot(pCur); + if( rc==16 ){ + *pnEntry = 0; + return 0; + } + + + + + while( rc==0 ){ + int iIdx; + MemPage *pPage; + + + + + + pPage = pCur->pPage; + if( pPage->leaf || !pPage->intKey ){ + nEntry += pPage->nCell; + } +# 9486 "src/btree.c" + if( pPage->leaf ){ + do { + if( pCur->iPage==0 ){ + + *pnEntry = nEntry; + return moveToRoot(pCur); + } + moveToParent(pCur); + }while ( pCur->ix>=pCur->pPage->nCell ); + + pCur->ix++; + pPage = pCur->pPage; + } + + + + + iIdx = pCur->ix; + if( iIdx==pPage->nCell ){ + rc = moveToChild(pCur, sqlite3Get4byte(&pPage->aData[pPage->hdrOffset+8])); + }else{ + rc = moveToChild(pCur, sqlite3Get4byte(((pPage)->aData + ((pPage)->maskPage & __builtin_bswap16(*(u16*)(&(pPage)->aCellIdx[2*(iIdx)])))))); + } + } + + + return rc; +} + + + + + + +Pager *sqlite3BtreePager(Btree *p){ + return p->pBt->pPager; +} + + + + + +static void checkAppendMsg( + IntegrityCk *pCheck, + const char *zFormat, + ... +){ + va_list ap; + if( !pCheck->mxErr ) return; + pCheck->mxErr--; + pCheck->nErr++; + __builtin_va_start((ap)); + if( pCheck->errMsg.nChar ){ + sqlite3_str_append(&pCheck->errMsg, "\n", 1); + } + if( pCheck->zPfx ){ + sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2); + } + sqlite3_str_vappendf(&pCheck->errMsg, zFormat, ap); + ; + if( pCheck->errMsg.accError==7 ){ + pCheck->mallocFailed = 1; + } +} +# 9558 "src/btree.c" +static int getPageReferenced(IntegrityCk *pCheck, Pgno iPg){ + assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 ); + return (pCheck->aPgRef[iPg/8] & (1 << (iPg & 0x07))); +} + + + + +static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){ + assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 ); + pCheck->aPgRef[iPg/8] |= (1 << (iPg & 0x07)); +} +# 9580 "src/btree.c" +static int checkRef(IntegrityCk *pCheck, Pgno iPage){ + if( iPage>pCheck->nPage || iPage==0 ){ + checkAppendMsg(pCheck, "invalid page number %d", iPage); + return 1; + } + if( getPageReferenced(pCheck, iPage) ){ + checkAppendMsg(pCheck, "2nd reference to page %d", iPage); + return 1; + } + setPageReferenced(pCheck, iPage); + return 0; +} + + + + + + + +static void checkPtrmap( + IntegrityCk *pCheck, + Pgno iChild, + u8 eType, + Pgno iParent +){ + int rc; + u8 ePtrmapType; + Pgno iPtrmapParent; + + rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent); + if( rc!=0 ){ + if( rc==7 || rc==(10 | (12<<8)) ) pCheck->mallocFailed = 1; + checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", iChild); + return; + } + + if( ePtrmapType!=eType || iPtrmapParent!=iParent ){ + checkAppendMsg(pCheck, + "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)", + iChild, eType, iParent, ePtrmapType, iPtrmapParent); + } +} + + + + + + +static void checkList( + IntegrityCk *pCheck, + int isFreeList, + int iPage, + u32 N +){ + int i; + u32 expected = N; + int nErrAtStart = pCheck->nErr; + while( iPage!=0 && pCheck->mxErr ){ + DbPage *pOvflPage; + unsigned char *pOvflData; + if( checkRef(pCheck, iPage) ) break; + N--; + if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){ + checkAppendMsg(pCheck, "failed to get page %d", iPage); + break; + } + pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage); + if( isFreeList ){ + u32 n = (u32)sqlite3Get4byte(&pOvflData[4]); + + if( pCheck->pBt->autoVacuum ){ + checkPtrmap(pCheck, iPage, 2, 0); + } + + if( n>pCheck->pBt->usableSize/4-2 ){ + checkAppendMsg(pCheck, + "freelist leaf count too big on page %d", iPage); + N--; + }else{ + for(i=0; i<(int)n; i++){ + Pgno iFreePage = sqlite3Get4byte(&pOvflData[8+i*4]); + + if( pCheck->pBt->autoVacuum ){ + checkPtrmap(pCheck, iFreePage, 2, 0); + } + + checkRef(pCheck, iFreePage); + } + N -= n; + } + } + + else{ + + + + + if( pCheck->pBt->autoVacuum && N>0 ){ + i = sqlite3Get4byte(pOvflData); + checkPtrmap(pCheck, i, 4, iPage); + } + } + + iPage = sqlite3Get4byte(pOvflData); + sqlite3PagerUnref(pOvflPage); + } + if( N && nErrAtStart==pCheck->nErr ){ + checkAppendMsg(pCheck, + "%s is %d but should be %d", + isFreeList ? "size" : "overflow list length", + expected-N, expected); + } +} +# 9717 "src/btree.c" +static void btreeHeapInsert(u32 *aHeap, u32 x){ + u32 j, i = ++aHeap[0]; + aHeap[i] = x; + while( (j = i/2)>0 && aHeap[j]>aHeap[i] ){ + x = aHeap[j]; + aHeap[j] = aHeap[i]; + aHeap[i] = x; + i = j; + } +} +static int btreeHeapPull(u32 *aHeap, u32 *pOut){ + u32 j, i, x; + if( (x = aHeap[0])==0 ) return 0; + *pOut = aHeap[1]; + aHeap[1] = aHeap[x]; + aHeap[x] = 0xffffffff; + aHeap[0]--; + i = 1; + while( (j = i*2)<=aHeap[0] ){ + if( aHeap[j]>aHeap[j+1] ) j++; + if( aHeap[i]<aHeap[j] ) break; + x = aHeap[i]; + aHeap[i] = aHeap[j]; + aHeap[j] = x; + i = j; + } + return 1; +} +# 9761 "src/btree.c" +static int checkTreePage( + IntegrityCk *pCheck, + int iPage, + i64 *piMinKey, + i64 maxKey +){ + MemPage *pPage = 0; + int i; + int rc; + int depth = -1, d2; + int pgno; + int nFrag; + int hdr; + int cellStart; + int nCell; + int doCoverageCheck = 1; + int keyCanBeEqual = 1; + + u8 *data; + u8 *pCell; + u8 *pCellIdx; + BtShared *pBt; + u32 pc; + u32 usableSize; + u32 contentOffset; + u32 *heap = 0; + u32 x, prev = 0; + const char *saved_zPfx = pCheck->zPfx; + int saved_v1 = pCheck->v1; + int saved_v2 = pCheck->v2; + u8 savedIsInit = 0; + + + + pBt = pCheck->pBt; + usableSize = pBt->usableSize; + if( iPage==0 ) return 0; + if( checkRef(pCheck, iPage) ) return 0; + pCheck->zPfx = "Page %d: "; + pCheck->v1 = iPage; + if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){ + checkAppendMsg(pCheck, + "unable to get the page. error code=%d", rc); + goto end_of_check; + } + + + + savedIsInit = pPage->isInit; + pPage->isInit = 0; + if( (rc = btreeInitPage(pPage))!=0 ){ + assert( rc==11 ); + checkAppendMsg(pCheck, + "btreeInitPage() returns error code %d", rc); + goto end_of_check; + } + if( (rc = btreeComputeFreeSpace(pPage))!=0 ){ + assert( rc==11 ); + checkAppendMsg(pCheck, "free space corruption", rc); + goto end_of_check; + } + data = pPage->aData; + hdr = pPage->hdrOffset; + + + pCheck->zPfx = "On tree page %d cell %d: "; + contentOffset = (((((int)((&data[hdr+5])[0]<<8 | (&data[hdr+5])[1]))-1)&0xffff)+1); + assert( contentOffset<=usableSize ); + + + + nCell = ((&data[hdr+3])[0]<<8 | (&data[hdr+3])[1]); + assert( pPage->nCell==nCell ); + + + + cellStart = hdr + 12 - 4*pPage->leaf; + assert( pPage->aCellIdx==&data[cellStart] ); + pCellIdx = &data[cellStart + 2*(nCell-1)]; + + if( !pPage->leaf ){ + + pgno = sqlite3Get4byte(&data[hdr+8]); + + if( pBt->autoVacuum ){ + pCheck->zPfx = "On page %d at right child: "; + checkPtrmap(pCheck, pgno, 5, iPage); + } + + depth = checkTreePage(pCheck, pgno, &maxKey, maxKey); + keyCanBeEqual = 0; + }else{ + + + heap = pCheck->heap; + heap[0] = 0; + } + + + + for(i=nCell-1; i>=0 && pCheck->mxErr; i--){ + CellInfo info; + + + pCheck->v2 = i; + assert( pCellIdx==&data[cellStart + i*2] ); + pc = __builtin_bswap16(*(u16*)(pCellIdx)); + pCellIdx -= 2; + if( pc<contentOffset || pc>usableSize-4 ){ + checkAppendMsg(pCheck, "Offset %d out of range %d..%d", + pc, contentOffset, usableSize-4); + doCoverageCheck = 0; + continue; + } + pCell = &data[pc]; + pPage->xParseCell(pPage, pCell, &info); + if( pc+info.nSize>usableSize ){ + checkAppendMsg(pCheck, "Extends off end of page"); + doCoverageCheck = 0; + continue; + } + + + if( pPage->intKey ){ + if( keyCanBeEqual ? (info.nKey > maxKey) : (info.nKey >= maxKey) ){ + checkAppendMsg(pCheck, "Rowid %lld out of order", info.nKey); + } + maxKey = info.nKey; + keyCanBeEqual = 0; + } + + + if( info.nPayload>info.nLocal ){ + u32 nPage; + Pgno pgnoOvfl; + assert( pc + info.nSize - 4 <= usableSize ); + nPage = (info.nPayload - info.nLocal + usableSize - 5)/(usableSize - 4); + pgnoOvfl = sqlite3Get4byte(&pCell[info.nSize - 4]); + + if( pBt->autoVacuum ){ + checkPtrmap(pCheck, pgnoOvfl, 3, iPage); + } + + checkList(pCheck, 0, pgnoOvfl, nPage); + } + + if( !pPage->leaf ){ + + pgno = sqlite3Get4byte(pCell); + + if( pBt->autoVacuum ){ + checkPtrmap(pCheck, pgno, 5, iPage); + } + + d2 = checkTreePage(pCheck, pgno, &maxKey, maxKey); + keyCanBeEqual = 0; + if( d2!=depth ){ + checkAppendMsg(pCheck, "Child page depth differs"); + depth = d2; + } + }else{ + + btreeHeapInsert(heap, (pc<<16)|(pc+info.nSize-1)); + } + } + *piMinKey = maxKey; + + + + pCheck->zPfx = 0; + if( doCoverageCheck && pCheck->mxErr>0 ){ + + + + if( !pPage->leaf ){ + heap = pCheck->heap; + heap[0] = 0; + for(i=nCell-1; i>=0; i--){ + u32 size; + pc = __builtin_bswap16(*(u16*)(&data[cellStart+i*2])); + size = pPage->xCellSize(pPage, &data[pc]); + btreeHeapInsert(heap, (pc<<16)|(pc+size-1)); + } + } + + + + + + + i = ((&data[hdr+1])[0]<<8 | (&data[hdr+1])[1]); + while( i>0 ){ + int size, j; + assert( (u32)i<=usableSize-4 ); + size = ((&data[i+2])[0]<<8 | (&data[i+2])[1]); + assert( (u32)(i+size)<=usableSize ); + btreeHeapInsert(heap, (((u32)i)<<16)|(i+size-1)); + + + + + j = ((&data[i])[0]<<8 | (&data[i])[1]); + + + assert( j==0 || j>i+size ); + assert( (u32)j<=usableSize-4 ); + i = j; + } +# 9982 "src/btree.c" + nFrag = 0; + prev = contentOffset - 1; + while( btreeHeapPull(heap,&x) ){ + if( (prev&0xffff)>=(x>>16) ){ + checkAppendMsg(pCheck, + "Multiple uses for byte %u of page %d", x>>16, iPage); + break; + }else{ + nFrag += (x>>16) - (prev&0xffff) - 1; + prev = x; + } + } + nFrag += usableSize - (prev&0xffff) - 1; + + + + + + if( heap[0]==0 && nFrag!=data[hdr+7] ){ + checkAppendMsg(pCheck, + "Fragmentation of %d bytes reported as %d on page %d", + nFrag, data[hdr+7], iPage); + } + } + +end_of_check: + if( !doCoverageCheck ) pPage->isInit = savedIsInit; + releasePage(pPage); + pCheck->zPfx = saved_zPfx; + pCheck->v1 = saved_v1; + pCheck->v2 = saved_v2; + return depth+1; +} +# 10031 "src/btree.c" +char *sqlite3BtreeIntegrityCheck( + Btree *p, + int *aRoot, + int nRoot, + int mxErr, + int *pnErr +){ + Pgno i; + IntegrityCk sCheck; + BtShared *pBt = p->pBt; + u64 savedDbFlags = pBt->db->flags; + char zErr[100]; + ; + + sqlite3BtreeEnter(p); + assert( p->inTrans>0 && pBt->inTransaction>0 ); + ; + assert( nRef>=0 ); + sCheck.pBt = pBt; + sCheck.pPager = pBt->pPager; + sCheck.nPage = btreePagecount(sCheck.pBt); + sCheck.mxErr = mxErr; + sCheck.nErr = 0; + sCheck.mallocFailed = 0; + sCheck.zPfx = 0; + sCheck.v1 = 0; + sCheck.v2 = 0; + sCheck.aPgRef = 0; + sCheck.heap = 0; + sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), 1000000000); + sCheck.errMsg.printfFlags = 0x01; + if( sCheck.nPage==0 ){ + goto integrity_ck_cleanup; + } + + sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1); + if( !sCheck.aPgRef ){ + sCheck.mallocFailed = 1; + goto integrity_ck_cleanup; + } + sCheck.heap = (u32*)sqlite3PageMalloc( pBt->pageSize ); + if( sCheck.heap==0 ){ + sCheck.mallocFailed = 1; + goto integrity_ck_cleanup; + } + + i = ((Pgno)((sqlite3PendingByte/((pBt)->pageSize))+1)); + if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i); + + + + sCheck.zPfx = "Main freelist: "; + checkList(&sCheck, 1, sqlite3Get4byte(&pBt->pPage1->aData[32]), + sqlite3Get4byte(&pBt->pPage1->aData[36])); + sCheck.zPfx = 0; + + + + + if( pBt->autoVacuum ){ + int mx = 0; + int mxInHdr; + for(i=0; (int)i<nRoot; i++) if( mx<aRoot[i] ) mx = aRoot[i]; + mxInHdr = sqlite3Get4byte(&pBt->pPage1->aData[52]); + if( mx!=mxInHdr ){ + checkAppendMsg(&sCheck, + "max rootpage (%d) disagrees with header (%d)", + mx, mxInHdr + ); + } + }else if( sqlite3Get4byte(&pBt->pPage1->aData[64])!=0 ){ + checkAppendMsg(&sCheck, + "incremental_vacuum enabled with a max rootpage of zero" + ); + } + + ; + pBt->db->flags &= ~(u64)0x00200000; + for(i=0; (int)i<nRoot && sCheck.mxErr; i++){ + i64 notUsed; + if( aRoot[i]==0 ) continue; + + if( pBt->autoVacuum && aRoot[i]>1 ){ + checkPtrmap(&sCheck, aRoot[i], 1, 0); + } + + checkTreePage(&sCheck, aRoot[i], ¬Used, (0xffffffff|(((i64)0x7fffffff)<<32))); + } + pBt->db->flags = savedDbFlags; + + + + for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){ +# 10132 "src/btree.c" + if( getPageReferenced(&sCheck, i)==0 && + (ptrmapPageno(pBt, i)!=i || !pBt->autoVacuum) ){ + checkAppendMsg(&sCheck, "Page %d is never used", i); + } + if( getPageReferenced(&sCheck, i)!=0 && + (ptrmapPageno(pBt, i)==i && pBt->autoVacuum) ){ + checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i); + } + + } + + + +integrity_ck_cleanup: + sqlite3PageFree(sCheck.heap); + sqlite3_free(sCheck.aPgRef); + if( sCheck.mallocFailed ){ + sqlite3_str_reset(&sCheck.errMsg); + sCheck.nErr++; + } + *pnErr = sCheck.nErr; + if( sCheck.nErr==0 ) sqlite3_str_reset(&sCheck.errMsg); + + assert( nRef==sqlite3PagerRefcount(pBt->pPager) ); + sqlite3BtreeLeave(p); + return sqlite3StrAccumFinish(&sCheck.errMsg); +} +# 10168 "src/btree.c" +const char *sqlite3BtreeGetFilename(Btree *p){ + assert( p->pBt->pPager!=0 ); + return sqlite3PagerFilename(p->pBt->pPager, 1); +} +# 10181 "src/btree.c" +const char *sqlite3BtreeGetJournalname(Btree *p){ + assert( p->pBt->pPager!=0 ); + return sqlite3PagerJournalname(p->pBt->pPager); +} + + + + +int sqlite3BtreeIsInTrans(Btree *p){ + assert( p==0 || sqlite3_mutex_held(p->db->mutex) ); + return (p && (p->inTrans==2)); +} +# 10203 "src/btree.c" +int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int *pnCkpt){ + int rc = 0; + if( p ){ + BtShared *pBt = p->pBt; + sqlite3BtreeEnter(p); + if( pBt->inTransaction!=0 ){ + rc = 6; + }else{ + rc = sqlite3PagerCheckpoint(pBt->pPager, p->db, eMode, pnLog, pnCkpt); + } + sqlite3BtreeLeave(p); + } + return rc; +} + + + + + +int sqlite3BtreeIsInReadTrans(Btree *p){ + assert( p ); + assert( sqlite3_mutex_held(p->db->mutex) ); + return p->inTrans!=0; +} + +int sqlite3BtreeIsInBackup(Btree *p){ + assert( p ); + assert( sqlite3_mutex_held(p->db->mutex) ); + return p->nBackup!=0; +} +# 10254 "src/btree.c" +void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){ + BtShared *pBt = p->pBt; + sqlite3BtreeEnter(p); + if( !pBt->pSchema && nBytes ){ + pBt->pSchema = sqlite3DbMallocZero(0, nBytes); + pBt->xFreeSchema = xFree; + } + sqlite3BtreeLeave(p); + return pBt->pSchema; +} + + + + + + +int sqlite3BtreeSchemaLocked(Btree *p){ + int rc; + assert( sqlite3_mutex_held(p->db->mutex) ); + sqlite3BtreeEnter(p); + rc = querySharedCacheTableLock(p, 1, 1); + assert( rc==0 || rc==(6 | (1<<8)) ); + sqlite3BtreeLeave(p); + return rc; +} +# 10287 "src/btree.c" +int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){ + int rc = 0; + assert( p->inTrans!=0 ); + if( p->sharable ){ + u8 lockType = 1 + isWriteLock; + assert( 1 +1==2 ); + assert( isWriteLock==0 || isWriteLock==1 ); + + sqlite3BtreeEnter(p); + rc = querySharedCacheTableLock(p, iTab, lockType); + if( rc==0 ){ + rc = setSharedCacheTableLock(p, iTab, lockType); + } + sqlite3BtreeLeave(p); + } + return rc; +} +# 10317 "src/btree.c" +int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ + int rc; + assert( cursorOwnsBtShared(pCsr) ); + assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) ); + assert( pCsr->curFlags & 0x10 ); + + rc = (pCsr->eState>=3 ? btreeRestoreCursorPosition(pCsr) : 0); + if( rc!=0 ){ + return rc; + } + assert( pCsr->eState!=3 ); + if( pCsr->eState!=0 ){ + return 4; + } +# 10340 "src/btree.c" + saveAllCursors(pCsr->pBt, pCsr->pgnoRoot, pCsr); + assert( rc==0 ); +# 10350 "src/btree.c" + if( (pCsr->curFlags & 0x01)==0 ){ + return 8; + } + assert( (pCsr->pBt->btsFlags & 0x0001)==0 + && pCsr->pBt->inTransaction==2 ); + assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) ); + assert( !hasReadConflicts(pCsr->pBtree, pCsr->pgnoRoot) ); + assert( pCsr->pPage->intKey ); + + return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1); +} + + + + +void sqlite3BtreeIncrblobCursor(BtCursor *pCur){ + pCur->curFlags |= 0x10; + pCur->pBtree->hasIncrblobCur = 1; +} + + + + + + + +int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){ + BtShared *pBt = pBtree->pBt; + int rc; + + assert( iVersion==1 || iVersion==2 ); + + + + + pBt->btsFlags &= ~0x0020; + if( iVersion==1 ) pBt->btsFlags |= 0x0020; + + rc = sqlite3BtreeBeginTrans(pBtree, 0, 0); + if( rc==0 ){ + u8 *aData = pBt->pPage1->aData; + if( aData[18]!=(u8)iVersion || aData[19]!=(u8)iVersion ){ + rc = sqlite3BtreeBeginTrans(pBtree, 2, 0); + if( rc==0 ){ + rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); + if( rc==0 ){ + aData[18] = (u8)iVersion; + aData[19] = (u8)iVersion; + } + } + } + } + + pBt->btsFlags &= ~0x0020; + return rc; +} + + + + + +int sqlite3BtreeCursorHasHint(BtCursor *pCsr, unsigned int mask){ + return (pCsr->hints & mask)!=0; +} + + + + +int sqlite3BtreeIsReadonly(Btree *p){ + return (p->pBt->btsFlags & 0x0001)!=0; +} + + + + +int sqlite3HeaderSizeBtree(void){ return (((sizeof(MemPage))+7)&~7); } + + + + + +int sqlite3BtreeSharable(Btree *p){ + return p->sharable; +} + + + + + + +int sqlite3BtreeConnectionCount(Btree *p){ + ; + return p->pBt->nRef; +} diff --git a/utils/benchmark/inputs/tccgen.c.ppout b/utils/benchmark/inputs/tccgen.c.ppout new file mode 100644 index 0000000..b007f19 --- /dev/null +++ b/utils/benchmark/inputs/tccgen.c.ppout @@ -0,0 +1,9993 @@ +# 1 "tccgen.c" +# 1 "<built-in>" +# 1 "<command-line>" +# 1 "tccgen.c" +# 21 "tccgen.c" +# 1 "tcc.h" 1 +# 25 "tcc.h" +# 1 "config.h" 1 +# 26 "tcc.h" 2 + +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdlib.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdlib.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_typedefs.h" 1 + + + +typedef int size_t; +typedef int __builtin_va_list; +typedef int __gnuc_va_list; +typedef int va_list; +typedef int __int8_t; +typedef int __uint8_t; +typedef int __int16_t; +typedef int __uint16_t; +typedef int __int_least16_t; +typedef int __uint_least16_t; +typedef int __int32_t; +typedef int __uint32_t; +typedef int __int64_t; +typedef int __uint64_t; +typedef int __int_least32_t; +typedef int __uint_least32_t; +typedef int __s8; +typedef int __u8; +typedef int __s16; +typedef int __u16; +typedef int __s32; +typedef int __u32; +typedef int __s64; +typedef int __u64; +typedef int _LOCK_T; +typedef int _LOCK_RECURSIVE_T; +typedef int _off_t; +typedef int __dev_t; +typedef int __uid_t; +typedef int __gid_t; +typedef int _off64_t; +typedef int _fpos_t; +typedef int _ssize_t; +typedef int wint_t; +typedef int _mbstate_t; +typedef int _flock_t; +typedef int _iconv_t; +typedef int __ULong; +typedef int __FILE; +typedef int ptrdiff_t; +typedef int wchar_t; +typedef int __off_t; +typedef int __pid_t; +typedef int __loff_t; +typedef int u_char; +typedef int u_short; +typedef int u_int; +typedef int u_long; +typedef int ushort; +typedef int uint; +typedef int clock_t; +typedef int time_t; +typedef int daddr_t; +typedef int caddr_t; +typedef int ino_t; +typedef int off_t; +typedef int dev_t; +typedef int uid_t; +typedef int gid_t; +typedef int pid_t; +typedef int key_t; +typedef int ssize_t; +typedef int mode_t; +typedef int nlink_t; +typedef int fd_mask; +typedef int _types_fd_set; +typedef int clockid_t; +typedef int timer_t; +typedef int useconds_t; +typedef int suseconds_t; +typedef int FILE; +typedef int fpos_t; +typedef int cookie_read_function_t; +typedef int cookie_write_function_t; +typedef int cookie_seek_function_t; +typedef int cookie_close_function_t; +typedef int cookie_io_functions_t; +typedef int div_t; +typedef int ldiv_t; +typedef int lldiv_t; +typedef int sigset_t; +typedef int __sigset_t; +typedef int _sig_func_ptr; +typedef int sig_atomic_t; +typedef int __tzrule_type; +typedef int __tzinfo_type; +typedef int mbstate_t; +typedef int sem_t; +typedef int pthread_t; +typedef int pthread_attr_t; +typedef int pthread_mutex_t; +typedef int pthread_mutexattr_t; +typedef int pthread_cond_t; +typedef int pthread_condattr_t; +typedef int pthread_key_t; +typedef int pthread_once_t; +typedef int pthread_rwlock_t; +typedef int pthread_rwlockattr_t; +typedef int pthread_spinlock_t; +typedef int pthread_barrier_t; +typedef int pthread_barrierattr_t; +typedef int jmp_buf; +typedef int rlim_t; +typedef int sa_family_t; +typedef int sigjmp_buf; +typedef int stack_t; +typedef int siginfo_t; +typedef int z_stream; + + +typedef int int8_t; +typedef int uint8_t; +typedef int int16_t; +typedef int uint16_t; +typedef int int32_t; +typedef int uint32_t; +typedef int int64_t; +typedef int uint64_t; + + +typedef int int_least8_t; +typedef int uint_least8_t; +typedef int int_least16_t; +typedef int uint_least16_t; +typedef int int_least32_t; +typedef int uint_least32_t; +typedef int int_least64_t; +typedef int uint_least64_t; + + +typedef int int_fast8_t; +typedef int uint_fast8_t; +typedef int int_fast16_t; +typedef int uint_fast16_t; +typedef int int_fast32_t; +typedef int uint_fast32_t; +typedef int int_fast64_t; +typedef int uint_fast64_t; + + +typedef int intptr_t; +typedef int uintptr_t; + + +typedef int intmax_t; +typedef int uintmax_t; + + +typedef _Bool bool; + + +typedef void* MirEGLNativeWindowType; +typedef void* MirEGLNativeDisplayType; +typedef struct MirConnection MirConnection; +typedef struct MirSurface MirSurface; +typedef struct MirSurfaceSpec MirSurfaceSpec; +typedef struct MirScreencast MirScreencast; +typedef struct MirPromptSession MirPromptSession; +typedef struct MirBufferStream MirBufferStream; +typedef struct MirPersistentId MirPersistentId; +typedef struct MirBlob MirBlob; +typedef struct MirDisplayConfig MirDisplayConfig; + + +typedef struct xcb_connection_t xcb_connection_t; +typedef uint32_t xcb_window_t; +typedef uint32_t xcb_visualid_t; +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdlib.h" 2 +# 28 "tcc.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 2 +# 29 "tcc.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 2 +# 30 "tcc.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/string.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/string.h" 2 +# 31 "tcc.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/errno.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/errno.h" 2 +# 32 "tcc.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/math.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/math.h" 2 +# 33 "tcc.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/fcntl.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/fcntl.h" 2 +# 34 "tcc.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/setjmp.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/setjmp.h" 2 +# 35 "tcc.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 2 +# 36 "tcc.h" 2 + + +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/unistd.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/unistd.h" 2 +# 39 "tcc.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 2 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_typedefs.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 2 +# 40 "tcc.h" 2 + +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/dlfcn.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/dlfcn.h" 2 +# 42 "tcc.h" 2 + + +extern float strtof (const char *__nptr, char **__endptr); +extern long double strtold (const char *__nptr, char **__endptr); +# 283 "tcc.h" +# 1 "libtcc.h" 1 +# 12 "libtcc.h" +struct TCCState; + +typedef struct TCCState TCCState; + + + TCCState *tcc_new(void); + + + void tcc_delete(TCCState *s); + + + void tcc_set_lib_path(TCCState *s, const char *path); + + + void tcc_set_error_func(TCCState *s, void *error_opaque, + void (*error_func)(void *opaque, const char *msg)); + + + void tcc_set_options(TCCState *s, const char *str); + + + + + + int tcc_add_include_path(TCCState *s, const char *pathname); + + + int tcc_add_sysinclude_path(TCCState *s, const char *pathname); + + + void tcc_define_symbol(TCCState *s, const char *sym, const char *value); + + + void tcc_undefine_symbol(TCCState *s, const char *sym); + + + + + + int tcc_add_file(TCCState *s, const char *filename); + + + int tcc_compile_string(TCCState *s, const char *buf); + + + + + + int tcc_set_output_type(TCCState *s, int output_type); + + + + + + + + int tcc_add_library_path(TCCState *s, const char *pathname); + + + int tcc_add_library(TCCState *s, const char *libraryname); + + + int tcc_add_symbol(TCCState *s, const char *name, const void *val); + + + + int tcc_output_file(TCCState *s, const char *filename); + + + + int tcc_run(TCCState *s, int argc, char **argv); + + + int tcc_relocate(TCCState *s1, void *ptr); +# 94 "libtcc.h" + void *tcc_get_symbol(TCCState *s, const char *name); +# 284 "tcc.h" 2 +# 1 "elf.h" 1 +# 23 "elf.h" +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/inttypes.h" 1 +# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 +# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/inttypes.h" 2 +# 24 "elf.h" 2 +# 41 "elf.h" +typedef uint16_t Elf32_Half; +typedef uint16_t Elf64_Half; + + +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; + + +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + + +typedef uint32_t Elf32_Addr; +typedef uint64_t Elf64_Addr; + + +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Off; + + +typedef uint16_t Elf32_Section; +typedef uint16_t Elf64_Section; + + +typedef Elf32_Half Elf32_Versym; +typedef Elf64_Half Elf64_Versym; + + + + + + +typedef struct +{ + unsigned char e_ident[(16)]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +typedef struct +{ + unsigned char e_ident[(16)]; + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +} Elf64_Ehdr; +# 282 "elf.h" +typedef struct +{ + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +typedef struct +{ + Elf64_Word sh_name; + Elf64_Word sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Word sh_link; + Elf64_Word sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; +} Elf64_Shdr; +# 392 "elf.h" +typedef struct +{ + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Section st_shndx; +} Elf32_Sym; + +typedef struct +{ + Elf64_Word st_name; + unsigned char st_info; + unsigned char st_other; + Elf64_Section st_shndx; + Elf64_Addr st_value; + Elf64_Xword st_size; +} Elf64_Sym; + + + + +typedef struct +{ + Elf32_Half si_boundto; + Elf32_Half si_flags; +} Elf32_Syminfo; + +typedef struct +{ + Elf64_Half si_boundto; + Elf64_Half si_flags; +} Elf64_Syminfo; +# 507 "elf.h" +typedef struct +{ + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + + + + + + +typedef struct +{ + Elf64_Addr r_offset; + Elf64_Xword r_info; +} Elf64_Rel; + + + +typedef struct +{ + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +typedef struct +{ + Elf64_Addr r_offset; + Elf64_Xword r_info; + Elf64_Sxword r_addend; +} Elf64_Rela; +# 552 "elf.h" +typedef struct +{ + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +typedef struct +{ + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf64_Xword p_filesz; + Elf64_Xword p_memsz; + Elf64_Xword p_align; +} Elf64_Phdr; +# 658 "elf.h" +typedef struct +{ + Elf32_Sword d_tag; + union + { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +typedef struct +{ + Elf64_Sxword d_tag; + union + { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; +# 834 "elf.h" +typedef struct +{ + Elf32_Half vd_version; + Elf32_Half vd_flags; + Elf32_Half vd_ndx; + Elf32_Half vd_cnt; + Elf32_Word vd_hash; + Elf32_Word vd_aux; + Elf32_Word vd_next; + +} Elf32_Verdef; + +typedef struct +{ + Elf64_Half vd_version; + Elf64_Half vd_flags; + Elf64_Half vd_ndx; + Elf64_Half vd_cnt; + Elf64_Word vd_hash; + Elf64_Word vd_aux; + Elf64_Word vd_next; + +} Elf64_Verdef; +# 876 "elf.h" +typedef struct +{ + Elf32_Word vda_name; + Elf32_Word vda_next; + +} Elf32_Verdaux; + +typedef struct +{ + Elf64_Word vda_name; + Elf64_Word vda_next; + +} Elf64_Verdaux; + + + + +typedef struct +{ + Elf32_Half vn_version; + Elf32_Half vn_cnt; + Elf32_Word vn_file; + + Elf32_Word vn_aux; + Elf32_Word vn_next; + +} Elf32_Verneed; + +typedef struct +{ + Elf64_Half vn_version; + Elf64_Half vn_cnt; + Elf64_Word vn_file; + + Elf64_Word vn_aux; + Elf64_Word vn_next; + +} Elf64_Verneed; +# 923 "elf.h" +typedef struct +{ + Elf32_Word vna_hash; + Elf32_Half vna_flags; + Elf32_Half vna_other; + Elf32_Word vna_name; + Elf32_Word vna_next; + +} Elf32_Vernaux; + +typedef struct +{ + Elf64_Word vna_hash; + Elf64_Half vna_flags; + Elf64_Half vna_other; + Elf64_Word vna_name; + Elf64_Word vna_next; + +} Elf64_Vernaux; +# 957 "elf.h" +typedef struct +{ + uint32_t a_type; + union + { + uint32_t a_val; + + + + } a_un; +} Elf32_auxv_t; + +typedef struct +{ + uint64_t a_type; + union + { + uint64_t a_val; + + + + } a_un; +} Elf64_auxv_t; +# 1041 "elf.h" +typedef struct +{ + Elf32_Word n_namesz; + Elf32_Word n_descsz; + Elf32_Word n_type; +} Elf32_Nhdr; + +typedef struct +{ + Elf64_Word n_namesz; + Elf64_Word n_descsz; + Elf64_Word n_type; +} Elf64_Nhdr; +# 1105 "elf.h" +typedef struct +{ + Elf32_Xword m_value; + Elf32_Word m_info; + Elf32_Word m_poffset; + Elf32_Half m_repeat; + Elf32_Half m_stride; +} Elf32_Move; + +typedef struct +{ + Elf64_Xword m_value; + Elf64_Xword m_info; + Elf64_Xword m_poffset; + Elf64_Half m_repeat; + Elf64_Half m_stride; +} Elf64_Move; +# 1489 "elf.h" +typedef union +{ + struct + { + Elf32_Word gt_current_g_value; + Elf32_Word gt_unused; + } gt_header; + struct + { + Elf32_Word gt_g_value; + Elf32_Word gt_bytes; + } gt_entry; +} Elf32_gptab; + + + +typedef struct +{ + Elf32_Word ri_gprmask; + Elf32_Word ri_cprmask[4]; + Elf32_Sword ri_gp_value; +} Elf32_RegInfo; + + + +typedef struct +{ + unsigned char kind; + + unsigned char size; + Elf32_Section section; + + Elf32_Word info; +} Elf_Options; +# 1565 "elf.h" +typedef struct +{ + Elf32_Word hwp_flags1; + Elf32_Word hwp_flags2; +} Elf_Options_Hw; +# 1726 "elf.h" +typedef struct +{ + Elf32_Word l_name; + Elf32_Word l_time_stamp; + Elf32_Word l_checksum; + Elf32_Word l_version; + Elf32_Word l_flags; +} Elf32_Lib; + +typedef struct +{ + Elf64_Word l_name; + Elf64_Word l_time_stamp; + Elf64_Word l_checksum; + Elf64_Word l_version; + Elf64_Word l_flags; +} Elf64_Lib; +# 1757 "elf.h" +typedef Elf32_Addr Elf32_Conflict; +# 285 "tcc.h" 2 +# 1 "stab.h" 1 +# 9 "stab.h" +enum __stab_debug_code +{ +# 1 "stab.def" 1 +# 24 "stab.def" +N_GSYM=0x20, + + + +N_FNAME=0x22, + + + + +N_FUN=0x24, + + + +N_STSYM=0x26, + + +N_LCSYM=0x28, + + + +N_MAIN=0x2a, + + + +N_PC=0x30, + + +N_NSYMS=0x32, + + +N_NOMAP=0x34, + + + +N_OBJ=0x38, + + + + +N_OPT=0x3c, + + +N_RSYM=0x40, + + +N_M2C=0x42, + + + +N_SLINE=0x44, + + +N_DSLINE=0x46, + + +N_BSLINE=0x48, + + + + +N_BROWS=0x48, + + + + + +N_DEFD=0x4a, + + + + +N_EHDECL=0x50, + +N_MOD2=0x50, + + + + + + +N_CATCH=0x54, + + +N_SSYM=0x60, + + + +N_SO=0x64, + + + +N_LSYM=0x80, + + + + +N_BINCL=0x82, + + + +N_SOL=0x84, + + + +N_PSYM=0xa0, + + + + + +N_EINCL=0xa2, + + +N_ENTRY=0xa4, + + + + + +N_LBRAC=0xc0, + + + + + +N_EXCL=0xc2, + + +N_SCOPE=0xc4, + + + +N_RBRAC=0xe0, + + +N_BCOMM=0xe2, + + + +N_ECOMM=0xe4, + + + +N_ECOML=0xe8, + + + + +N_NBTEXT=0xF0, +N_NBDATA=0xF2, +N_NBBSS=0xF4, +N_NBSTS=0xF6, +N_NBLCS=0xF8, + + + +N_LENG=0xfe, +# 12 "stab.h" 2 +LAST_UNUSED_STAB_CODE +}; +# 286 "tcc.h" 2 +# 320 "tcc.h" +# 1 "x86_64-gen.c" 1 +# 57 "x86_64-gen.c" +enum { + TREG_RAX = 0, + TREG_RCX = 1, + TREG_RDX = 2, + TREG_RSP = 4, + TREG_RSI = 6, + TREG_RDI = 7, + + TREG_R8 = 8, + TREG_R9 = 9, + TREG_R10 = 10, + TREG_R11 = 11, + + TREG_XMM0 = 16, + TREG_XMM1 = 17, + TREG_XMM2 = 18, + TREG_XMM3 = 19, + TREG_XMM4 = 20, + TREG_XMM5 = 21, + TREG_XMM6 = 22, + TREG_XMM7 = 23, + + TREG_ST0 = 24, + + TREG_MEM = 0x20 +}; +# 321 "tcc.h" 2 +# 1 "x86_64-link.c" 1 +# 322 "tcc.h" 2 +# 381 "tcc.h" +typedef struct TokenSym { + struct TokenSym *hash_next; + struct Sym *sym_define; + struct Sym *sym_label; + struct Sym *sym_struct; + struct Sym *sym_identifier; + int tok; + int len; + char str[1]; +} TokenSym; + + + + +typedef int nwchar_t; + + +typedef struct CString { + int size; + void *data; + int size_allocated; +} CString; + + +typedef struct CType { + int t; + struct Sym *ref; +} CType; + + +typedef union CValue { + long double ld; + double d; + float f; + uint64_t i; + struct { + int size; + const void *data; + } str; + int tab[16/4]; +} CValue; + + +typedef struct SValue { + CType type; + unsigned short r; + unsigned short r2; + + CValue c; + struct Sym *sym; + +} SValue; + + +struct SymAttr { + unsigned short + aligned : 5, + packed : 1, + weak : 1, + visibility : 2, + dllexport : 1, + dllimport : 1, + unused : 5; +}; + + +struct FuncAttr { + unsigned + func_call : 3, + func_type : 2, + func_args : 8; +}; + + +typedef struct AttributeDef { + struct SymAttr a; + struct FuncAttr f; + struct Section *section; + int alias_target; + int asm_label; + char attr_mode; +} AttributeDef; + + +typedef struct Sym { + int v; + unsigned short r; + struct SymAttr a; + union { + struct { + int c; + union { + int sym_scope; + int jnext; + struct FuncAttr f; + int auxtype; + }; + }; + long long enum_val; + int *d; + }; + CType type; + union { + struct Sym *next; + int asm_label; + }; + struct Sym *prev; + struct Sym *prev_tok; +} Sym; + + +typedef struct Section { + unsigned long data_offset; + unsigned char *data; + unsigned long data_allocated; + int sh_name; + int sh_num; + int sh_type; + int sh_flags; + int sh_info; + int sh_addralign; + int sh_entsize; + unsigned long sh_size; + Elf64_Addr sh_addr; + unsigned long sh_offset; + int nb_hashed_syms; + struct Section *link; + struct Section *reloc; + struct Section *hash; + struct Section *prev; + char name[1]; +} Section; + +typedef struct DLLReference { + int level; + void *handle; + char name[1]; +} DLLReference; +# 554 "tcc.h" +typedef struct BufferedFile { + uint8_t *buf_ptr; + uint8_t *buf_end; + int fd; + struct BufferedFile *prev; + int line_num; + int line_ref; + int ifndef_macro; + int ifndef_macro_saved; + int *ifdef_stack_ptr; + int include_next_index; + char filename[1024]; + char *true_filename; + unsigned char unget[4]; + unsigned char buffer[1]; +} BufferedFile; + + + + + +typedef struct TokenString { + int *str; + int len; + int lastlen; + int allocated_len; + int last_line_num; + int save_line_num; + + struct TokenString *prev; + const int *prev_ptr; + char alloc; +} TokenString; + + +typedef struct InlineFunc { + TokenString *func_str; + Sym *sym; + char filename[1]; +} InlineFunc; + + + +typedef struct CachedInclude { + int ifndef_macro; + int once; + int hash_next; + char filename[1]; +} CachedInclude; + + + + +typedef struct ExprValue { + uint64_t v; + Sym *sym; + int pcrel; +} ExprValue; + + +typedef struct ASMOperand { + int id; + char *constraint; + char asm_str[16]; + SValue *vt; + int ref_index; + int input_index; + int priority; + int reg; + int is_llong; + int is_memory; + int is_rw; +} ASMOperand; + + + +struct sym_attr { + unsigned got_offset; + unsigned plt_offset; + int plt_sym; + int dyn_index; + + + +}; + +struct TCCState { + + int verbose; + int nostdinc; + int nostdlib; + int nocommon; + int static_link; + int rdynamic; + int symbolic; + int alacarte_link; + + char *tcc_lib_path; + char *soname; + char *rpath; + int enable_new_dtags; + + + int output_type; + + int output_format; + + + int char_is_unsigned; + int leading_underscore; + int ms_extensions; + int dollars_in_identifiers; + int ms_bitfields; + + + int warn_write_strings; + int warn_unsupported; + int warn_error; + int warn_none; + int warn_implicit_function_declaration; + int warn_gcc_compat; + + + int do_debug; + + + int do_bounds_check; + + + + + int run_test; + + Elf64_Addr text_addr; + int has_text_addr; + + unsigned section_align; + + char *init_symbol; + char *fini_symbol; + + + + + + int nosse; + + + + DLLReference **loaded_dlls; + int nb_loaded_dlls; + + + char **include_paths; + int nb_include_paths; + + char **sysinclude_paths; + int nb_sysinclude_paths; + + + char **library_paths; + int nb_library_paths; + + + char **crt_paths; + int nb_crt_paths; + + + char **cmd_include_files; + int nb_cmd_include_files; + + + void *error_opaque; + void (*error_func)(void *opaque, const char *msg); + int error_set_jmp_enabled; + jmp_buf error_jmp_buf; + int nb_errors; + + + FILE *ppfp; + enum { + LINE_MACRO_OUTPUT_FORMAT_GCC, + LINE_MACRO_OUTPUT_FORMAT_NONE, + LINE_MACRO_OUTPUT_FORMAT_STD, + LINE_MACRO_OUTPUT_FORMAT_P10 = 11 + } Pflag; + char dflag; + + + char **target_deps; + int nb_target_deps; + + + BufferedFile *include_stack[32]; + BufferedFile **include_stack_ptr; + + int ifdef_stack[64]; + int *ifdef_stack_ptr; + + + int cached_includes_hash[32]; + CachedInclude **cached_includes; + int nb_cached_includes; + + + int pack_stack[8]; + int *pack_stack_ptr; + char **pragma_libs; + int nb_pragma_libs; + + + + struct InlineFunc **inline_fns; + int nb_inline_fns; + + + Section **sections; + int nb_sections; + + Section **priv_sections; + int nb_priv_sections; + + + Section *got; + Section *plt; + + + Section *dynsymtab_section; + + Section *dynsym; + + Section *symtab; + + struct sym_attr *sym_attrs; + int nb_sym_attrs; +# 805 "tcc.h" + const char *runtime_main; + void **runtime_mem; + int nb_runtime_mem; + + + + struct filespec **files; + int nb_files; + int nb_libraries; + int filetype; + char *outfile; + int option_r; + int do_bench; + int gen_deps; + char *deps_outfile; + int option_pthread; + int argc; + char **argv; +}; + +struct filespec { + char type; + char alacarte; + char name[1]; +}; +# 1070 "tcc.h" +enum tcc_token { + TOK_LAST = 256 - 1 + +# 1 "tcctok.h" 1 + + ,TOK_INT + ,TOK_VOID + ,TOK_CHAR + ,TOK_IF + ,TOK_ELSE + ,TOK_WHILE + ,TOK_BREAK + ,TOK_RETURN + ,TOK_FOR + ,TOK_EXTERN + ,TOK_STATIC + ,TOK_UNSIGNED + ,TOK_GOTO + ,TOK_DO + ,TOK_CONTINUE + ,TOK_SWITCH + ,TOK_CASE + + ,TOK_CONST1 + ,TOK_CONST2 + ,TOK_CONST3 + ,TOK_VOLATILE1 + ,TOK_VOLATILE2 + ,TOK_VOLATILE3 + ,TOK_LONG + ,TOK_REGISTER + ,TOK_SIGNED1 + ,TOK_SIGNED2 + ,TOK_SIGNED3 + ,TOK_AUTO + ,TOK_INLINE1 + ,TOK_INLINE2 + ,TOK_INLINE3 + ,TOK_RESTRICT1 + ,TOK_RESTRICT2 + ,TOK_RESTRICT3 + ,TOK_EXTENSION + + ,TOK_GENERIC + + ,TOK_FLOAT + ,TOK_DOUBLE + ,TOK_BOOL + ,TOK_SHORT + ,TOK_STRUCT + ,TOK_UNION + ,TOK_TYPEDEF + ,TOK_DEFAULT + ,TOK_ENUM + ,TOK_SIZEOF + ,TOK_ATTRIBUTE1 + ,TOK_ATTRIBUTE2 + ,TOK_ALIGNOF1 + ,TOK_ALIGNOF2 + ,TOK_TYPEOF1 + ,TOK_TYPEOF2 + ,TOK_TYPEOF3 + ,TOK_LABEL + ,TOK_ASM1 + ,TOK_ASM2 + ,TOK_ASM3 +# 71 "tcctok.h" + ,TOK_DEFINE + ,TOK_INCLUDE + ,TOK_INCLUDE_NEXT + ,TOK_IFDEF + ,TOK_IFNDEF + ,TOK_ELIF + ,TOK_ENDIF + ,TOK_DEFINED + ,TOK_UNDEF + ,TOK_ERROR + ,TOK_WARNING + ,TOK_LINE + ,TOK_PRAGMA + ,TOK___LINE__ + ,TOK___FILE__ + ,TOK___DATE__ + ,TOK___TIME__ + ,TOK___FUNCTION__ + ,TOK___VA_ARGS__ + ,TOK___COUNTER__ + + + ,TOK___FUNC__ + + + ,TOK___NAN__ + ,TOK___SNAN__ + ,TOK___INF__ + + + + ,TOK_SECTION1 + ,TOK_SECTION2 + ,TOK_ALIGNED1 + ,TOK_ALIGNED2 + ,TOK_PACKED1 + ,TOK_PACKED2 + ,TOK_WEAK1 + ,TOK_WEAK2 + ,TOK_ALIAS1 + ,TOK_ALIAS2 + ,TOK_UNUSED1 + ,TOK_UNUSED2 + ,TOK_CDECL1 + ,TOK_CDECL2 + ,TOK_CDECL3 + ,TOK_STDCALL1 + ,TOK_STDCALL2 + ,TOK_STDCALL3 + ,TOK_FASTCALL1 + ,TOK_FASTCALL2 + ,TOK_FASTCALL3 + ,TOK_REGPARM1 + ,TOK_REGPARM2 + + ,TOK_MODE + ,TOK_MODE_QI + ,TOK_MODE_DI + ,TOK_MODE_HI + ,TOK_MODE_SI + ,TOK_MODE_word + + ,TOK_DLLEXPORT + ,TOK_DLLIMPORT + ,TOK_NORETURN1 + ,TOK_NORETURN2 + ,TOK_VISIBILITY1 + ,TOK_VISIBILITY2 + + ,TOK_builtin_types_compatible_p + ,TOK_builtin_choose_expr + ,TOK_builtin_constant_p + ,TOK_builtin_frame_address + ,TOK_builtin_return_address + ,TOK_builtin_expect + + + + + ,TOK_builtin_va_arg_types + + + + + + + ,TOK_pack + + + + + + ,TOK_comment + ,TOK_lib + ,TOK_push_macro + ,TOK_pop_macro + ,TOK_once + ,TOK_option + + + + ,TOK_memcpy + ,TOK_memmove + ,TOK_memset + ,TOK___divdi3 + ,TOK___moddi3 + ,TOK___udivdi3 + ,TOK___umoddi3 + ,TOK___ashrdi3 + ,TOK___lshrdi3 + ,TOK___ashldi3 + ,TOK___floatundisf + ,TOK___floatundidf + + ,TOK___floatundixf + ,TOK___fixunsxfdi + + ,TOK___fixunssfdi + ,TOK___fixunsdfdi +# 251 "tcctok.h" + ,TOK_alloca +# 285 "tcctok.h" + ,TOK___bound_ptr_add + ,TOK___bound_ptr_indir1 + ,TOK___bound_ptr_indir2 + ,TOK___bound_ptr_indir4 + ,TOK___bound_ptr_indir8 + ,TOK___bound_ptr_indir12 + ,TOK___bound_ptr_indir16 + ,TOK___bound_main_arg + ,TOK___bound_local_new + ,TOK___bound_local_delete + + + + + + + + ,TOK_strlen + ,TOK_strcpy + + + + ,TOK_ASMDIR_byte + ,TOK_ASMDIR_word + ,TOK_ASMDIR_align + ,TOK_ASMDIR_balign + ,TOK_ASMDIR_p2align + ,TOK_ASMDIR_set + ,TOK_ASMDIR_skip + ,TOK_ASMDIR_space + ,TOK_ASMDIR_string + ,TOK_ASMDIR_asciz + ,TOK_ASMDIR_ascii + ,TOK_ASMDIR_file + ,TOK_ASMDIR_globl + ,TOK_ASMDIR_global + ,TOK_ASMDIR_weak + ,TOK_ASMDIR_hidden + ,TOK_ASMDIR_ident + ,TOK_ASMDIR_size + ,TOK_ASMDIR_type + ,TOK_ASMDIR_text + ,TOK_ASMDIR_data + ,TOK_ASMDIR_bss + ,TOK_ASMDIR_previous + ,TOK_ASMDIR_pushsection + ,TOK_ASMDIR_popsection + ,TOK_ASMDIR_fill + ,TOK_ASMDIR_rept + ,TOK_ASMDIR_endr + ,TOK_ASMDIR_org + ,TOK_ASMDIR_quad + + + + + ,TOK_ASMDIR_code64 + + ,TOK_ASMDIR_short + ,TOK_ASMDIR_long + ,TOK_ASMDIR_int + ,TOK_ASMDIR_section + + +# 1 "i386-tok.h" 1 + + + + + ,TOK_ASM_al + ,TOK_ASM_cl + ,TOK_ASM_dl + ,TOK_ASM_bl + ,TOK_ASM_ah + ,TOK_ASM_ch + ,TOK_ASM_dh + ,TOK_ASM_bh + ,TOK_ASM_ax + ,TOK_ASM_cx + ,TOK_ASM_dx + ,TOK_ASM_bx + ,TOK_ASM_sp + ,TOK_ASM_bp + ,TOK_ASM_si + ,TOK_ASM_di + ,TOK_ASM_eax + ,TOK_ASM_ecx + ,TOK_ASM_edx + ,TOK_ASM_ebx + ,TOK_ASM_esp + ,TOK_ASM_ebp + ,TOK_ASM_esi + ,TOK_ASM_edi + + ,TOK_ASM_rax + ,TOK_ASM_rcx + ,TOK_ASM_rdx + ,TOK_ASM_rbx + ,TOK_ASM_rsp + ,TOK_ASM_rbp + ,TOK_ASM_rsi + ,TOK_ASM_rdi + + ,TOK_ASM_mm0 + ,TOK_ASM_mm1 + ,TOK_ASM_mm2 + ,TOK_ASM_mm3 + ,TOK_ASM_mm4 + ,TOK_ASM_mm5 + ,TOK_ASM_mm6 + ,TOK_ASM_mm7 + ,TOK_ASM_xmm0 + ,TOK_ASM_xmm1 + ,TOK_ASM_xmm2 + ,TOK_ASM_xmm3 + ,TOK_ASM_xmm4 + ,TOK_ASM_xmm5 + ,TOK_ASM_xmm6 + ,TOK_ASM_xmm7 + ,TOK_ASM_cr0 + ,TOK_ASM_cr1 + ,TOK_ASM_cr2 + ,TOK_ASM_cr3 + ,TOK_ASM_cr4 + ,TOK_ASM_cr5 + ,TOK_ASM_cr6 + ,TOK_ASM_cr7 + ,TOK_ASM_tr0 + ,TOK_ASM_tr1 + ,TOK_ASM_tr2 + ,TOK_ASM_tr3 + ,TOK_ASM_tr4 + ,TOK_ASM_tr5 + ,TOK_ASM_tr6 + ,TOK_ASM_tr7 + ,TOK_ASM_db0 + ,TOK_ASM_db1 + ,TOK_ASM_db2 + ,TOK_ASM_db3 + ,TOK_ASM_db4 + ,TOK_ASM_db5 + ,TOK_ASM_db6 + ,TOK_ASM_db7 + ,TOK_ASM_dr0 + ,TOK_ASM_dr1 + ,TOK_ASM_dr2 + ,TOK_ASM_dr3 + ,TOK_ASM_dr4 + ,TOK_ASM_dr5 + ,TOK_ASM_dr6 + ,TOK_ASM_dr7 + ,TOK_ASM_es + ,TOK_ASM_cs + ,TOK_ASM_ss + ,TOK_ASM_ds + ,TOK_ASM_fs + ,TOK_ASM_gs + ,TOK_ASM_st + ,TOK_ASM_rip + + + + + ,TOK_ASM_spl + ,TOK_ASM_bpl + ,TOK_ASM_sil + ,TOK_ASM_dil + + + ,TOK_ASM_movb ,TOK_ASM_movw ,TOK_ASM_movl ,TOK_ASM_movq ,TOK_ASM_mov + + ,TOK_ASM_addb ,TOK_ASM_addw ,TOK_ASM_addl ,TOK_ASM_addq ,TOK_ASM_add + ,TOK_ASM_orb ,TOK_ASM_orw ,TOK_ASM_orl ,TOK_ASM_orq ,TOK_ASM_or + ,TOK_ASM_adcb ,TOK_ASM_adcw ,TOK_ASM_adcl ,TOK_ASM_adcq ,TOK_ASM_adc + ,TOK_ASM_sbbb ,TOK_ASM_sbbw ,TOK_ASM_sbbl ,TOK_ASM_sbbq ,TOK_ASM_sbb + ,TOK_ASM_andb ,TOK_ASM_andw ,TOK_ASM_andl ,TOK_ASM_andq ,TOK_ASM_and + ,TOK_ASM_subb ,TOK_ASM_subw ,TOK_ASM_subl ,TOK_ASM_subq ,TOK_ASM_sub + ,TOK_ASM_xorb ,TOK_ASM_xorw ,TOK_ASM_xorl ,TOK_ASM_xorq ,TOK_ASM_xor + ,TOK_ASM_cmpb ,TOK_ASM_cmpw ,TOK_ASM_cmpl ,TOK_ASM_cmpq ,TOK_ASM_cmp + + + ,TOK_ASM_incb ,TOK_ASM_incw ,TOK_ASM_incl ,TOK_ASM_incq ,TOK_ASM_inc + ,TOK_ASM_decb ,TOK_ASM_decw ,TOK_ASM_decl ,TOK_ASM_decq ,TOK_ASM_dec + ,TOK_ASM_notb ,TOK_ASM_notw ,TOK_ASM_notl ,TOK_ASM_notq ,TOK_ASM_not + ,TOK_ASM_negb ,TOK_ASM_negw ,TOK_ASM_negl ,TOK_ASM_negq ,TOK_ASM_neg + ,TOK_ASM_mulb ,TOK_ASM_mulw ,TOK_ASM_mull ,TOK_ASM_mulq ,TOK_ASM_mul + ,TOK_ASM_imulb ,TOK_ASM_imulw ,TOK_ASM_imull ,TOK_ASM_imulq ,TOK_ASM_imul + ,TOK_ASM_divb ,TOK_ASM_divw ,TOK_ASM_divl ,TOK_ASM_divq ,TOK_ASM_div + ,TOK_ASM_idivb ,TOK_ASM_idivw ,TOK_ASM_idivl ,TOK_ASM_idivq ,TOK_ASM_idiv + + ,TOK_ASM_xchgb ,TOK_ASM_xchgw ,TOK_ASM_xchgl ,TOK_ASM_xchgq ,TOK_ASM_xchg + ,TOK_ASM_testb ,TOK_ASM_testw ,TOK_ASM_testl ,TOK_ASM_testq ,TOK_ASM_test + + + ,TOK_ASM_rolb ,TOK_ASM_rolw ,TOK_ASM_roll ,TOK_ASM_rolq ,TOK_ASM_rol + ,TOK_ASM_rorb ,TOK_ASM_rorw ,TOK_ASM_rorl ,TOK_ASM_rorq ,TOK_ASM_ror + ,TOK_ASM_rclb ,TOK_ASM_rclw ,TOK_ASM_rcll ,TOK_ASM_rclq ,TOK_ASM_rcl + ,TOK_ASM_rcrb ,TOK_ASM_rcrw ,TOK_ASM_rcrl ,TOK_ASM_rcrq ,TOK_ASM_rcr + ,TOK_ASM_shlb ,TOK_ASM_shlw ,TOK_ASM_shll ,TOK_ASM_shlq ,TOK_ASM_shl + ,TOK_ASM_shrb ,TOK_ASM_shrw ,TOK_ASM_shrl ,TOK_ASM_shrq ,TOK_ASM_shr + ,TOK_ASM_sarb ,TOK_ASM_sarw ,TOK_ASM_sarl ,TOK_ASM_sarq ,TOK_ASM_sar + + ,TOK_ASM_shldw ,TOK_ASM_shldl ,TOK_ASM_shldq ,TOK_ASM_shld + ,TOK_ASM_shrdw ,TOK_ASM_shrdl ,TOK_ASM_shrdq ,TOK_ASM_shrd + + ,TOK_ASM_pushw + ,TOK_ASM_pushl + + ,TOK_ASM_pushq + + ,TOK_ASM_push + + ,TOK_ASM_popw + ,TOK_ASM_popl + + ,TOK_ASM_popq + + ,TOK_ASM_pop + + ,TOK_ASM_inb ,TOK_ASM_inw ,TOK_ASM_inl ,TOK_ASM_in + ,TOK_ASM_outb ,TOK_ASM_outw ,TOK_ASM_outl ,TOK_ASM_out + + ,TOK_ASM_movzbw ,TOK_ASM_movzbl ,TOK_ASM_movzbq ,TOK_ASM_movzb + ,TOK_ASM_movzwl + ,TOK_ASM_movsbw + ,TOK_ASM_movsbl + ,TOK_ASM_movswl + + ,TOK_ASM_movsbq + ,TOK_ASM_movswq + ,TOK_ASM_movzwq + ,TOK_ASM_movslq + + + ,TOK_ASM_leaw ,TOK_ASM_leal ,TOK_ASM_leaq ,TOK_ASM_lea + + ,TOK_ASM_les + ,TOK_ASM_lds + ,TOK_ASM_lss + ,TOK_ASM_lfs + ,TOK_ASM_lgs + + ,TOK_ASM_call + ,TOK_ASM_jmp + ,TOK_ASM_lcall + ,TOK_ASM_ljmp + + ,TOK_ASM_jo ,TOK_ASM_jno ,TOK_ASM_jb ,TOK_ASM_jc ,TOK_ASM_jnae ,TOK_ASM_jnb ,TOK_ASM_jnc ,TOK_ASM_jae ,TOK_ASM_je ,TOK_ASM_jz ,TOK_ASM_jne ,TOK_ASM_jnz ,TOK_ASM_jbe ,TOK_ASM_jna ,TOK_ASM_jnbe ,TOK_ASM_ja ,TOK_ASM_js ,TOK_ASM_jns ,TOK_ASM_jp ,TOK_ASM_jpe ,TOK_ASM_jnp ,TOK_ASM_jpo ,TOK_ASM_jl ,TOK_ASM_jnge ,TOK_ASM_jnl ,TOK_ASM_jge ,TOK_ASM_jle ,TOK_ASM_jng ,TOK_ASM_jnle ,TOK_ASM_jg + + ,TOK_ASM_seto ,TOK_ASM_setno ,TOK_ASM_setb ,TOK_ASM_setc ,TOK_ASM_setnae ,TOK_ASM_setnb ,TOK_ASM_setnc ,TOK_ASM_setae ,TOK_ASM_sete ,TOK_ASM_setz ,TOK_ASM_setne ,TOK_ASM_setnz ,TOK_ASM_setbe ,TOK_ASM_setna ,TOK_ASM_setnbe ,TOK_ASM_seta ,TOK_ASM_sets ,TOK_ASM_setns ,TOK_ASM_setp ,TOK_ASM_setpe ,TOK_ASM_setnp ,TOK_ASM_setpo ,TOK_ASM_setl ,TOK_ASM_setnge ,TOK_ASM_setnl ,TOK_ASM_setge ,TOK_ASM_setle ,TOK_ASM_setng ,TOK_ASM_setnle ,TOK_ASM_setg + ,TOK_ASM_setob ,TOK_ASM_setnob ,TOK_ASM_setbb ,TOK_ASM_setcb ,TOK_ASM_setnaeb ,TOK_ASM_setnbb ,TOK_ASM_setncb ,TOK_ASM_setaeb ,TOK_ASM_seteb ,TOK_ASM_setzb ,TOK_ASM_setneb ,TOK_ASM_setnzb ,TOK_ASM_setbeb ,TOK_ASM_setnab ,TOK_ASM_setnbeb ,TOK_ASM_setab ,TOK_ASM_setsb ,TOK_ASM_setnsb ,TOK_ASM_setpb ,TOK_ASM_setpeb ,TOK_ASM_setnpb ,TOK_ASM_setpob ,TOK_ASM_setlb ,TOK_ASM_setngeb ,TOK_ASM_setnlb ,TOK_ASM_setgeb ,TOK_ASM_setleb ,TOK_ASM_setngb ,TOK_ASM_setnleb ,TOK_ASM_setgb + ,TOK_ASM_cmovo ,TOK_ASM_cmovno ,TOK_ASM_cmovb ,TOK_ASM_cmovc ,TOK_ASM_cmovnae ,TOK_ASM_cmovnb ,TOK_ASM_cmovnc ,TOK_ASM_cmovae ,TOK_ASM_cmove ,TOK_ASM_cmovz ,TOK_ASM_cmovne ,TOK_ASM_cmovnz ,TOK_ASM_cmovbe ,TOK_ASM_cmovna ,TOK_ASM_cmovnbe ,TOK_ASM_cmova ,TOK_ASM_cmovs ,TOK_ASM_cmovns ,TOK_ASM_cmovp ,TOK_ASM_cmovpe ,TOK_ASM_cmovnp ,TOK_ASM_cmovpo ,TOK_ASM_cmovl ,TOK_ASM_cmovnge ,TOK_ASM_cmovnl ,TOK_ASM_cmovge ,TOK_ASM_cmovle ,TOK_ASM_cmovng ,TOK_ASM_cmovnle ,TOK_ASM_cmovg + + ,TOK_ASM_bsfw ,TOK_ASM_bsfl ,TOK_ASM_bsfq ,TOK_ASM_bsf + ,TOK_ASM_bsrw ,TOK_ASM_bsrl ,TOK_ASM_bsrq ,TOK_ASM_bsr + ,TOK_ASM_btw ,TOK_ASM_btl ,TOK_ASM_btq ,TOK_ASM_bt + ,TOK_ASM_btsw ,TOK_ASM_btsl ,TOK_ASM_btsq ,TOK_ASM_bts + ,TOK_ASM_btrw ,TOK_ASM_btrl ,TOK_ASM_btrq ,TOK_ASM_btr + ,TOK_ASM_btcw ,TOK_ASM_btcl ,TOK_ASM_btcq ,TOK_ASM_btc + + ,TOK_ASM_larw ,TOK_ASM_larl ,TOK_ASM_larq ,TOK_ASM_lar + ,TOK_ASM_lslw ,TOK_ASM_lsll ,TOK_ASM_lslq ,TOK_ASM_lsl + + + ,TOK_ASM_fadd ,TOK_ASM_faddp ,TOK_ASM_fadds ,TOK_ASM_fiaddl ,TOK_ASM_faddl ,TOK_ASM_fiadds + ,TOK_ASM_fmul ,TOK_ASM_fmulp ,TOK_ASM_fmuls ,TOK_ASM_fimull ,TOK_ASM_fmull ,TOK_ASM_fimuls + + ,TOK_ASM_fcom + ,TOK_ASM_fcom_1 + ,TOK_ASM_fcoms ,TOK_ASM_ficoml ,TOK_ASM_fcoml ,TOK_ASM_ficoms + + ,TOK_ASM_fcomp ,TOK_ASM_fcompp ,TOK_ASM_fcomps ,TOK_ASM_ficompl ,TOK_ASM_fcompl ,TOK_ASM_ficomps + ,TOK_ASM_fsub ,TOK_ASM_fsubp ,TOK_ASM_fsubs ,TOK_ASM_fisubl ,TOK_ASM_fsubl ,TOK_ASM_fisubs + ,TOK_ASM_fsubr ,TOK_ASM_fsubrp ,TOK_ASM_fsubrs ,TOK_ASM_fisubrl ,TOK_ASM_fsubrl ,TOK_ASM_fisubrs + ,TOK_ASM_fdiv ,TOK_ASM_fdivp ,TOK_ASM_fdivs ,TOK_ASM_fidivl ,TOK_ASM_fdivl ,TOK_ASM_fidivs + ,TOK_ASM_fdivr ,TOK_ASM_fdivrp ,TOK_ASM_fdivrs ,TOK_ASM_fidivrl ,TOK_ASM_fdivrl ,TOK_ASM_fidivrs + + ,TOK_ASM_xaddb ,TOK_ASM_xaddw ,TOK_ASM_xaddl ,TOK_ASM_xaddq ,TOK_ASM_xadd + ,TOK_ASM_cmpxchgb ,TOK_ASM_cmpxchgw ,TOK_ASM_cmpxchgl ,TOK_ASM_cmpxchgq ,TOK_ASM_cmpxchg + + + ,TOK_ASM_cmpsb ,TOK_ASM_cmpsw ,TOK_ASM_cmpsl ,TOK_ASM_cmpsq ,TOK_ASM_cmps + ,TOK_ASM_scmpb ,TOK_ASM_scmpw ,TOK_ASM_scmpl ,TOK_ASM_scmpq ,TOK_ASM_scmp + ,TOK_ASM_insb ,TOK_ASM_insw ,TOK_ASM_insl ,TOK_ASM_ins + ,TOK_ASM_outsb ,TOK_ASM_outsw ,TOK_ASM_outsl ,TOK_ASM_outs + ,TOK_ASM_lodsb ,TOK_ASM_lodsw ,TOK_ASM_lodsl ,TOK_ASM_lodsq ,TOK_ASM_lods + ,TOK_ASM_slodb ,TOK_ASM_slodw ,TOK_ASM_slodl ,TOK_ASM_slodq ,TOK_ASM_slod + ,TOK_ASM_movsb ,TOK_ASM_movsw ,TOK_ASM_movsl ,TOK_ASM_movsq ,TOK_ASM_movs + ,TOK_ASM_smovb ,TOK_ASM_smovw ,TOK_ASM_smovl ,TOK_ASM_smovq ,TOK_ASM_smov + ,TOK_ASM_scasb ,TOK_ASM_scasw ,TOK_ASM_scasl ,TOK_ASM_scasq ,TOK_ASM_scas + ,TOK_ASM_sscab ,TOK_ASM_sscaw ,TOK_ASM_sscal ,TOK_ASM_sscaq ,TOK_ASM_ssca + ,TOK_ASM_stosb ,TOK_ASM_stosw ,TOK_ASM_stosl ,TOK_ASM_stosq ,TOK_ASM_stos + ,TOK_ASM_sstob ,TOK_ASM_sstow ,TOK_ASM_sstol ,TOK_ASM_sstoq ,TOK_ASM_ssto +# 238 "i386-tok.h" +# 1 "x86_64-asm.h" 1 + ,TOK_ASM_clc + ,TOK_ASM_cld + ,TOK_ASM_cli + ,TOK_ASM_clts + ,TOK_ASM_cmc + ,TOK_ASM_lahf + ,TOK_ASM_sahf + ,TOK_ASM_pushfq + ,TOK_ASM_popfq + ,TOK_ASM_pushf + ,TOK_ASM_popf + ,TOK_ASM_stc + ,TOK_ASM_std + ,TOK_ASM_sti + ,TOK_ASM_aaa + ,TOK_ASM_aas + ,TOK_ASM_daa + ,TOK_ASM_das + ,TOK_ASM_aad + ,TOK_ASM_aam + ,TOK_ASM_cbw + ,TOK_ASM_cwd + ,TOK_ASM_cwde + ,TOK_ASM_cdq + ,TOK_ASM_cbtw + ,TOK_ASM_cwtl + ,TOK_ASM_cwtd + ,TOK_ASM_cltd + ,TOK_ASM_cqto + ,TOK_ASM_int3 + ,TOK_ASM_into + ,TOK_ASM_iret + ,TOK_ASM_rsm + ,TOK_ASM_hlt + ,TOK_ASM_wait + ,TOK_ASM_nop + ,TOK_ASM_pause + ,TOK_ASM_xlat + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ,TOK_ASM_lock + ,TOK_ASM_rep + ,TOK_ASM_repe + ,TOK_ASM_repz + ,TOK_ASM_repne + ,TOK_ASM_repnz + + ,TOK_ASM_invd + ,TOK_ASM_wbinvd + ,TOK_ASM_cpuid + ,TOK_ASM_wrmsr + ,TOK_ASM_rdtsc + ,TOK_ASM_rdmsr + ,TOK_ASM_rdpmc + + ,TOK_ASM_syscall + ,TOK_ASM_sysret + + ,TOK_ASM_ud2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ,TOK_ASM_leave + ,TOK_ASM_ret + ,TOK_ASM_retq + + + ,TOK_ASM_lret + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ,TOK_ASM_fucompp + ,TOK_ASM_ftst + ,TOK_ASM_fxam + ,TOK_ASM_fld1 + ,TOK_ASM_fldl2t + ,TOK_ASM_fldl2e + ,TOK_ASM_fldpi + ,TOK_ASM_fldlg2 + ,TOK_ASM_fldln2 + ,TOK_ASM_fldz + + ,TOK_ASM_f2xm1 + ,TOK_ASM_fyl2x + ,TOK_ASM_fptan + ,TOK_ASM_fpatan + ,TOK_ASM_fxtract + ,TOK_ASM_fprem1 + ,TOK_ASM_fdecstp + ,TOK_ASM_fincstp + ,TOK_ASM_fprem + ,TOK_ASM_fyl2xp1 + ,TOK_ASM_fsqrt + ,TOK_ASM_fsincos + ,TOK_ASM_frndint + ,TOK_ASM_fscale + ,TOK_ASM_fsin + ,TOK_ASM_fcos + ,TOK_ASM_fchs + ,TOK_ASM_fabs + ,TOK_ASM_fninit + ,TOK_ASM_fnclex + ,TOK_ASM_fnop + ,TOK_ASM_fwait + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ,TOK_ASM_fxch + + + + + + + + + + + ,TOK_ASM_fnstsw + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ,TOK_ASM_emms + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 239 "i386-tok.h" 2 +# 250 "i386-tok.h" +# 1 "x86_64-asm.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ,TOK_ASM_sysretq + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ,TOK_ASM_ljmpw + ,TOK_ASM_ljmpl + + + + + ,TOK_ASM_enter + + + + + + + + + + ,TOK_ASM_loopne + ,TOK_ASM_loopnz + ,TOK_ASM_loope + ,TOK_ASM_loopz + ,TOK_ASM_loop + ,TOK_ASM_jecxz + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ,TOK_ASM_fld + ,TOK_ASM_fldl + ,TOK_ASM_flds + + ,TOK_ASM_fildl + ,TOK_ASM_fildq + ,TOK_ASM_fildll + ,TOK_ASM_fldt + ,TOK_ASM_fbld + + + ,TOK_ASM_fst + ,TOK_ASM_fstl + ,TOK_ASM_fsts + ,TOK_ASM_fstps + + ,TOK_ASM_fstpl + ,TOK_ASM_fist + ,TOK_ASM_fistp + ,TOK_ASM_fistl + ,TOK_ASM_fistpl + + ,TOK_ASM_fstp + ,TOK_ASM_fistpq + ,TOK_ASM_fistpll + ,TOK_ASM_fstpt + ,TOK_ASM_fbstp + + + + + + + ,TOK_ASM_fucom + ,TOK_ASM_fucomp + + ,TOK_ASM_finit + ,TOK_ASM_fldcw + ,TOK_ASM_fnstcw + ,TOK_ASM_fstcw + + + + ,TOK_ASM_fstsw + + + ,TOK_ASM_fclex + ,TOK_ASM_fnstenv + ,TOK_ASM_fstenv + ,TOK_ASM_fldenv + ,TOK_ASM_fnsave + ,TOK_ASM_fsave + ,TOK_ASM_frstor + ,TOK_ASM_ffree + ,TOK_ASM_ffreep + ,TOK_ASM_fxsave + ,TOK_ASM_fxrstor + + + + + ,TOK_ASM_fxsaveq + ,TOK_ASM_fxrstorq + + + ,TOK_ASM_arpl + + ,TOK_ASM_lgdt + ,TOK_ASM_lgdtq + ,TOK_ASM_lidt + ,TOK_ASM_lidtq + ,TOK_ASM_lldt + ,TOK_ASM_lmsw + + ,TOK_ASM_ltr + ,TOK_ASM_sgdt + ,TOK_ASM_sgdtq + ,TOK_ASM_sidt + ,TOK_ASM_sidtq + ,TOK_ASM_sldt + ,TOK_ASM_smsw + ,TOK_ASM_str + + + ,TOK_ASM_verr + ,TOK_ASM_verw + ,TOK_ASM_swapgs + + + + ,TOK_ASM_bswap + ,TOK_ASM_bswapl + ,TOK_ASM_bswapq + + + + ,TOK_ASM_invlpg + + + ,TOK_ASM_cmpxchg8b + + + ,TOK_ASM_cmpxchg16b + + + + + ,TOK_ASM_fcmovb + ,TOK_ASM_fcmove + ,TOK_ASM_fcmovbe + ,TOK_ASM_fcmovu + ,TOK_ASM_fcmovnb + ,TOK_ASM_fcmovne + ,TOK_ASM_fcmovnbe + ,TOK_ASM_fcmovnu + + ,TOK_ASM_fucomi + ,TOK_ASM_fcomi + ,TOK_ASM_fucomip + ,TOK_ASM_fcomip + + + + ,TOK_ASM_movd + + + + + + + + + + + + + ,TOK_ASM_packssdw + ,TOK_ASM_packsswb + ,TOK_ASM_packuswb + ,TOK_ASM_paddb + ,TOK_ASM_paddw + ,TOK_ASM_paddd + ,TOK_ASM_paddsb + ,TOK_ASM_paddsw + ,TOK_ASM_paddusb + ,TOK_ASM_paddusw + ,TOK_ASM_pand + ,TOK_ASM_pandn + ,TOK_ASM_pcmpeqb + ,TOK_ASM_pcmpeqw + ,TOK_ASM_pcmpeqd + ,TOK_ASM_pcmpgtb + ,TOK_ASM_pcmpgtw + ,TOK_ASM_pcmpgtd + ,TOK_ASM_pmaddwd + ,TOK_ASM_pmulhw + ,TOK_ASM_pmullw + ,TOK_ASM_por + ,TOK_ASM_psllw + + ,TOK_ASM_pslld + + ,TOK_ASM_psllq + + ,TOK_ASM_psraw + + ,TOK_ASM_psrad + + ,TOK_ASM_psrlw + + ,TOK_ASM_psrld + + ,TOK_ASM_psrlq + + ,TOK_ASM_psubb + ,TOK_ASM_psubw + ,TOK_ASM_psubd + ,TOK_ASM_psubsb + ,TOK_ASM_psubsw + ,TOK_ASM_psubusb + ,TOK_ASM_psubusw + ,TOK_ASM_punpckhbw + ,TOK_ASM_punpckhwd + ,TOK_ASM_punpckhdq + ,TOK_ASM_punpcklbw + ,TOK_ASM_punpcklwd + ,TOK_ASM_punpckldq + ,TOK_ASM_pxor + + + ,TOK_ASM_movups + + ,TOK_ASM_movaps + + ,TOK_ASM_movhps + + ,TOK_ASM_addps + ,TOK_ASM_cvtpi2ps + ,TOK_ASM_cvtps2pi + ,TOK_ASM_cvttps2pi + ,TOK_ASM_divps + ,TOK_ASM_maxps + ,TOK_ASM_minps + ,TOK_ASM_mulps + ,TOK_ASM_pavgb + ,TOK_ASM_pavgw + ,TOK_ASM_pmaxsw + ,TOK_ASM_pmaxub + ,TOK_ASM_pminsw + ,TOK_ASM_pminub + ,TOK_ASM_rcpss + ,TOK_ASM_rsqrtps + ,TOK_ASM_sqrtps + ,TOK_ASM_subps + + ,TOK_ASM_prefetchnta + ,TOK_ASM_prefetcht0 + ,TOK_ASM_prefetcht1 + ,TOK_ASM_prefetcht2 + ,TOK_ASM_prefetchw + ,TOK_ASM_lfence + ,TOK_ASM_mfence + ,TOK_ASM_sfence + ,TOK_ASM_clflush +# 251 "i386-tok.h" 2 +# 350 "tcctok.h" 2 +# 1074 "tcc.h" 2 + +}; + + + + + + + +static int gnu_ext; + +static int tcc_ext; + +static struct TCCState *tcc_state; + + +static char *pstrcpy(char *buf, int buf_size, const char *s); +static char *pstrcat(char *buf, int buf_size, const char *s); +static char *pstrncpy(char *out, const char *in, size_t num); + char *tcc_basename(const char *name); + char *tcc_fileextension (const char *name); + + + void tcc_free(void *ptr); + void *tcc_malloc(unsigned long size); + void *tcc_mallocz(unsigned long size); + void *tcc_realloc(void *ptr, unsigned long size); + char *tcc_strdup(const char *str); +# 1120 "tcc.h" + void tcc_memcheck(void); + void tcc_error_noabort(const char *fmt, ...); + void tcc_error(const char *fmt, ...); + void tcc_warning(const char *fmt, ...); + + +static void dynarray_add(void *ptab, int *nb_ptr, void *data); +static void dynarray_reset(void *pp, int *n); +static inline void cstr_ccat(CString *cstr, int ch); +static void cstr_cat(CString *cstr, const char *str, int len); +static void cstr_wccat(CString *cstr, int ch); +static void cstr_new(CString *cstr); +static void cstr_free(CString *cstr); +static void cstr_reset(CString *cstr); + +static inline void sym_free(Sym *sym); +static Sym *sym_push2(Sym **ps, int v, int t, int c); +static Sym *sym_find2(Sym *s, int v); +static Sym *sym_push(int v, CType *type, int r, int c); +static void sym_pop(Sym **ptop, Sym *b, int keep); +static inline Sym *struct_find(int v); +static inline Sym *sym_find(int v); +static Sym *global_identifier_push(int v, int t, int c); + +static void tcc_open_bf(TCCState *s1, const char *filename, int initlen); +static int tcc_open(TCCState *s1, const char *filename); +static void tcc_close(void); + +static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags); +# 1166 "tcc.h" +static int tcc_add_crt(TCCState *s, const char *filename); +static int tcc_add_dll(TCCState *s, const char *filename, int flags); +static void tcc_add_pragma_libs(TCCState *s1); + int tcc_add_library_err(TCCState *s, const char *f); + void tcc_print_stats(TCCState *s, unsigned total_time); + int tcc_parse_args(TCCState *s, int *argc, char ***argv, int optind); +# 1188 "tcc.h" +static struct BufferedFile *file; +static int ch, tok; +static CValue tokc; +static const int *macro_ptr; +static int parse_flags; +static int tok_flags; +static CString tokcstr; + + +static int total_lines; +static int total_bytes; +static int tok_ident; +static TokenSym **table_ident; +# 1222 "tcc.h" +static TokenSym *tok_alloc(const char *str, int len); +static const char *get_tok_str(int v, CValue *cv); +static void begin_macro(TokenString *str, int alloc); +static void end_macro(void); +static int set_idnum(int c, int val); +static inline void tok_str_new(TokenString *s); +static TokenString *tok_str_alloc(void); +static void tok_str_free(TokenString *s); +static void tok_str_free_str(int *str); +static void tok_str_add(TokenString *s, int t); +static void tok_str_add_tok(TokenString *s); +static inline void define_push(int v, int macro_type, int *str, Sym *first_arg); +static void define_undef(Sym *s); +static inline Sym *define_find(int v); +static void free_defines(Sym *b); +static Sym *label_find(int v); +static Sym *label_push(Sym **ptop, int v, int flags); +static void label_pop(Sym **ptop, Sym *slast, int keep); +static void parse_define(void); +static void preprocess(int is_bof); +static void next_nomacro(void); +static void next(void); +static inline void unget_tok(int last_tok); +static void preprocess_start(TCCState *s1, int is_asm); +static void preprocess_end(TCCState *s1); +static void tccpp_new(TCCState *s); +static void tccpp_delete(TCCState *s); +static int tcc_preprocess(TCCState *s1); +static void skip(int c); +static void expect(const char *msg); + + +static inline int is_space(int ch) { + return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f' || ch == '\r'; +} +static inline int isid(int c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; +} +static inline int isnum(int c) { + return c >= '0' && c <= '9'; +} +static inline int isoct(int c) { + return c >= '0' && c <= '7'; +} +static inline int toup(int c) { + return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; +} + + + + +static Sym *sym_free_first; +static void **sym_pools; +static int nb_sym_pools; + +static Sym *global_stack; +static Sym *local_stack; +static Sym *local_label_stack; +static Sym *global_label_stack; +static Sym *define_stack; +static CType char_pointer_type, func_old_type, int_type, size_type; +static SValue __vstack[1+ 256], *vtop, *pvtop; + +static int rsym, anon_sym, ind, loc; + +static int const_wanted; +static int nocode_wanted; +static int global_expr; +static CType func_vt; +static int func_var; +static int func_vc; +static int last_line_num, last_ind, func_ind; +static const char *funcname; +static int g_debug; + +static void tcc_debug_start(TCCState *s1); +static void tcc_debug_end(TCCState *s1); +static void tcc_debug_funcstart(TCCState *s1, Sym *sym); +static void tcc_debug_funcend(TCCState *s1, int size); +static void tcc_debug_line(TCCState *s1); + +static int tccgen_compile(TCCState *s1); +static void free_inline_functions(TCCState *s); +static void check_vstack(void); + +static inline int is_float(int t); +static int ieee_finite(double d); +static void test_lvalue(void); +static void vpushi(int v); +static Elf64_Sym *elfsym(Sym *); +static void update_storage(Sym *sym); +static Sym *external_global_sym(int v, CType *type, int r); +static void vset(CType *type, int r, int v); +static void vswap(void); +static void vpush_global_sym(CType *type, int v); +static void vrote(SValue *e, int n); +static void vrott(int n); +static void vrotb(int n); + + + + +static void vpushv(SValue *v); +static void save_reg(int r); +static void save_reg_upstack(int r, int n); +static int get_reg(int rc); +static void save_regs(int n); +static void gaddrof(void); +static int gv(int rc); +static void gv2(int rc1, int rc2); +static void vpop(void); +static void gen_op(int op); +static int type_size(CType *type, int *a); +static void mk_pointer(CType *type); +static void vstore(void); +static void inc(int post, int c); +static void parse_mult_str (CString *astr, const char *msg); +static void parse_asm_str(CString *astr); +static int lvalue_type(int t); +static void indir(void); +static void unary(void); +static void expr_prod(void); +static void expr_sum(void); +static void gexpr(void); +static int expr_const(void); + +static Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size); + + +static int classify_x86_64_va_arg(CType *ty); +# 1362 "tcc.h" +typedef struct { + unsigned int n_strx; + unsigned char n_type; + unsigned char n_other; + unsigned short n_desc; + unsigned int n_value; +} Stab_Sym; + +static Section *text_section, *data_section, *bss_section; +static Section *common_section; +static Section *cur_text_section; + +static Section *last_text_section; + + + +static Section *bounds_section; +static Section *lbounds_section; +static void tccelf_bounds_new(TCCState *s); + + +static Section *symtab_section; + +static Section *stab_section, *stabstr_section; + +static void tccelf_new(TCCState *s); +static void tccelf_delete(TCCState *s); +static void tccelf_stab_new(TCCState *s); +static void tccelf_begin_file(TCCState *s1); +static void tccelf_end_file(TCCState *s1); + +static Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags); +static void section_realloc(Section *sec, unsigned long new_size); +static size_t section_add(Section *sec, Elf64_Addr size, int align); +static void *section_ptr_add(Section *sec, Elf64_Addr size); +static void section_reserve(Section *sec, unsigned long size); +static Section *find_section(TCCState *s1, const char *name); +static Section *new_symtab(TCCState *s1, const char *symtab_name, int sh_type, int sh_flags, const char *strtab_name, const char *hash_name, int hash_sh_flags); + +static void put_extern_sym2(Sym *sym, int sh_num, Elf64_Addr value, unsigned long size, int can_add_underscore); +static void put_extern_sym(Sym *sym, Section *section, Elf64_Addr value, unsigned long size); + + + +static void greloca(Section *s, Sym *sym, unsigned long offset, int type, Elf64_Addr addend); + +static int put_elf_str(Section *s, const char *sym); +static int put_elf_sym(Section *s, Elf64_Addr value, unsigned long size, int info, int other, int shndx, const char *name); +static int set_elf_sym(Section *s, Elf64_Addr value, unsigned long size, int info, int other, int shndx, const char *name); +static int find_elf_sym(Section *s, const char *name); +static void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, int type, int symbol); +static void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, int type, int symbol, Elf64_Addr addend); + +static void put_stabs(const char *str, int type, int other, int desc, unsigned long value); +static void put_stabs_r(const char *str, int type, int other, int desc, unsigned long value, Section *sec, int sym_index); +static void put_stabn(int type, int other, int desc, int value); +static void put_stabd(int type, int other, int desc); + +static void resolve_common_syms(TCCState *s1); +static void relocate_syms(TCCState *s1, Section *symtab, int do_resolve); +static void relocate_section(TCCState *s1, Section *s); + +static int tcc_object_type(int fd, Elf64_Ehdr *h); +static int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset); +static int tcc_load_archive(TCCState *s1, int fd); +static void tcc_add_bcheck(TCCState *s1); +static void tcc_add_runtime(TCCState *s1); + +static void build_got_entries(TCCState *s1); +static struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc); +static void squeeze_multi_relocs(Section *sec, size_t oldrelocoffset); + +static Elf64_Addr get_elf_sym_addr(TCCState *s, const char *name, int err); + +static void *tcc_get_symbol_err(TCCState *s, const char *name); + + + +static int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level); +static int tcc_load_ldscript(TCCState *s1); +static uint8_t *parse_comment(uint8_t *p); +static void minp(void); +static inline void inp(void); +static int handle_eob(void); + + + + + + +enum gotplt_entry { + NO_GOTPLT_ENTRY, + BUILD_GOT_ONLY, + AUTO_GOTPLT_ENTRY, + ALWAYS_GOTPLT_ENTRY +}; + +static int code_reloc (int reloc_type); +static int gotplt_entry_type (int reloc_type); +static unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr); +static void relocate_init(Section *sr); +static void relocate(TCCState *s1, Elf64_Rela *rel, int type, unsigned char *ptr, Elf64_Addr addr, Elf64_Addr val); +static void relocate_plt(TCCState *s1); + + + +static const int reg_classes[25]; + +static void gsym_addr(int t, int a); +static void gsym(int t); +static void load(int r, SValue *sv); +static void store(int r, SValue *v); +static int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize); +static void gfunc_call(int nb_args); +static void gfunc_prolog(CType *func_type); +static void gfunc_epilog(void); +static int gjmp(int t); +static void gjmp_addr(int a); +static int gtst(int inv, int t); + +static void gtst_addr(int inv, int a); + + + +static void gen_opi(int op); +static void gen_opf(int op); +static void gen_cvt_ftoi(int t); +static void gen_cvt_ftof(int t); +static void ggoto(void); + +static void o(unsigned int c); + + +static void gen_cvt_itof(int t); + +static void gen_vla_sp_save(int addr); +static void gen_vla_sp_restore(int addr); +static void gen_vla_alloc(CType *type, int align); + +static inline uint16_t read16le(unsigned char *p) { + return p[0] | (uint16_t)p[1] << 8; +} +static inline void write16le(unsigned char *p, uint16_t x) { + p[0] = x & 255; p[1] = x >> 8 & 255; +} +static inline uint32_t read32le(unsigned char *p) { + return read16le(p) | (uint32_t)read16le(p + 2) << 16; +} +static inline void write32le(unsigned char *p, uint32_t x) { + write16le(p, x); write16le(p + 2, x >> 16); +} +static inline void add32le(unsigned char *p, int32_t x) { + write32le(p, read32le(p) + x); +} +static inline uint64_t read64le(unsigned char *p) { + return read32le(p) | (uint64_t)read32le(p + 4) << 32; +} +static inline void write64le(unsigned char *p, uint64_t x) { + write32le(p, x); write32le(p + 4, x >> 32); +} +static inline void add64le(unsigned char *p, int64_t x) { + write64le(p, read64le(p) + x); +} + + + +static void g(int c); +static void gen_le16(int c); +static void gen_le32(int c); +static void gen_addr32(int r, Sym *sym, int c); +static void gen_addrpc32(int r, Sym *sym, int c); + + + +static void gen_bounded_ptr_add(void); +static void gen_bounded_ptr_deref(void); + + + + +static void gen_addr64(int r, Sym *sym, int64_t c); +static void gen_opl(int op); +# 1580 "tcc.h" +static void asm_instr(void); +static void asm_global_instr(void); + +static int find_constraint(ASMOperand *operands, int nb_operands, const char *name, const char **pp); +static Sym* get_asm_sym(int name, Sym *csym); +static void asm_expr(TCCState *s1, ExprValue *pe); +static int asm_int_expr(TCCState *s1); +static int tcc_assemble(TCCState *s1, int do_preprocess); + +static void gen_expr32(ExprValue *pe); + +static void gen_expr64(ExprValue *pe); + +static void asm_opcode(TCCState *s1, int opcode); +static int asm_parse_regvar(int t); +static void asm_compute_constraints(ASMOperand *operands, int nb_operands, int nb_outputs, const uint8_t *clobber_regs, int *pout_reg); +static void subst_asm_operand(CString *add_str, SValue *sv, int modifier); +static void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg); +static void asm_clobber(uint8_t *clobber_regs, const char *str); +# 1634 "tcc.h" +static int rt_num_callers; +static const char **rt_bound_error_msg; +static void *rt_prog_main; +static void tcc_set_num_callers(int n); + +static void tcc_run_free(TCCState *s1); +# 22 "tccgen.c" 2 +# 31 "tccgen.c" +static int rsym, anon_sym, ind, loc; + +static Sym *sym_free_first; +static void **sym_pools; +static int nb_sym_pools; + +static Sym *global_stack; +static Sym *local_stack; +static Sym *define_stack; +static Sym *global_label_stack; +static Sym *local_label_stack; +static int local_scope; +static int in_sizeof; +static int section_sym; + +static int vlas_in_scope; +static int vla_sp_root_loc; +static int vla_sp_loc; + +static SValue __vstack[1+256], *vtop, *pvtop; + +static int const_wanted; +static int nocode_wanted; + + +static int global_expr; +static CType func_vt; +static int func_var; +static int func_vc; +static int last_line_num, last_ind, func_ind; +static const char *funcname; +static int g_debug; + +static CType char_pointer_type, func_old_type, int_type, size_type, ptrdiff_type; + +static struct switch_t { + struct case_t { + int64_t v1, v2; + int sym; + } **p; int n; + int def_sym; +} *cur_switch; + + + +static void gen_cast(CType *type); +static void gen_cast_s(int t); +static inline CType *pointed_type(CType *type); +static int is_compatible_types(CType *type1, CType *type2); +static int parse_btype(CType *type, AttributeDef *ad); +static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td); +static void parse_expr_type(CType *type); +static void init_putv(CType *type, Section *sec, unsigned long c); +static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only); +static void block(int *bsym, int *csym, int is_expr); +static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope); +static void decl(int l); +static int decl0(int l, int is_for_loop_init, Sym *); +static void expr_eq(void); +static void vla_runtime_type_size(CType *type, int *a); +static void vla_sp_restore(void); +static void vla_sp_restore_root(void); +static int is_compatible_unqualified_types(CType *type1, CType *type2); +static inline int64_t expr_const64(void); +static void vpush64(int ty, unsigned long long v); +static void vpush(CType *type); +static int gvtst(int inv, int t); +static void gen_inline_functions(TCCState *s); +static void skip_or_save_block(TokenString **str); +static void gv_dup(void); + +static inline int is_float(int t) +{ + int bt; + bt = t & 0x000f; + return bt == 10 || bt == 9 || bt == 8 || bt == 14; +} + + + + +static int ieee_finite(double d) +{ + int p[4]; + memcpy(p, &d, sizeof(double)); + return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31; +} + + + + + + + +static void test_lvalue(void) +{ + if (!(vtop->r & 0x0100)) + expect("lvalue"); +} + +static void check_vstack(void) +{ + if (pvtop != vtop) + tcc_error("internal compiler error: vstack leak (%d)", vtop - pvtop); +} +# 154 "tccgen.c" +static void tcc_debug_start(TCCState *s1) +{ + if (s1->do_debug) { + char buf[512]; + + + section_sym = put_elf_sym(symtab_section, 0, 0, + ((((0)) << 4) + (((3)) & 0xf)), 0, + text_section->sh_num, 0); + getcwd(buf, sizeof(buf)); + + + + pstrcat(buf, sizeof(buf), "/"); + put_stabs_r(buf, N_SO, 0, 0, + text_section->data_offset, text_section, section_sym); + put_stabs_r(file->filename, N_SO, 0, 0, + text_section->data_offset, text_section, section_sym); + last_ind = 0; + last_line_num = 0; + } + + + + put_elf_sym(symtab_section, 0, 0, + ((((0)) << 4) + (((4)) & 0xf)), 0, + 0xfff1, file->filename); +} + + +static void tcc_debug_end(TCCState *s1) +{ + if (!s1->do_debug) + return; + put_stabs_r(0, N_SO, 0, 0, + text_section->data_offset, text_section, section_sym); + +} + + +static void tcc_debug_line(TCCState *s1) +{ + if (!s1->do_debug) + return; + if ((last_line_num != file->line_num || last_ind != ind)) { + put_stabn(N_SLINE, 0, file->line_num, ind - func_ind); + last_ind = ind; + last_line_num = file->line_num; + } +} + + +static void tcc_debug_funcstart(TCCState *s1, Sym *sym) +{ + char buf[512]; + + if (!s1->do_debug) + return; + + + + snprintf(buf, sizeof(buf), "%s:%c1", + funcname, sym->type.t & 0x00002000 ? 'f' : 'F'); + put_stabs_r(buf, N_FUN, 0, file->line_num, 0, + cur_text_section, sym->c); + + put_stabn(N_SLINE, 0, file->line_num, 0); + + last_ind = 0; + last_line_num = 0; +} + + +static void tcc_debug_funcend(TCCState *s1, int size) +{ + if (!s1->do_debug) + return; + put_stabn(N_FUN, 0, 0, size); +} + + +static int tccgen_compile(TCCState *s1) +{ + cur_text_section = 0; + funcname = ""; + anon_sym = 0x10000000; + section_sym = 0; + const_wanted = 0; + nocode_wanted = 0x80000000; + + + int_type.t = 3; + char_pointer_type.t = 1; + mk_pointer(&char_pointer_type); + + + + + + + + size_type.t = 0x0800 | 4 | 0x0010; + ptrdiff_type.t = 0x0800 | 4; + + func_old_type.t = 6; + func_old_type.ref = sym_push(0x20000000, &int_type, 0, 0); + func_old_type.ref->f.func_call = 0; + func_old_type.ref->f.func_type = 2; + + tcc_debug_start(s1); +# 273 "tccgen.c" + parse_flags = 0x0001 | 0x0002 | 0x0040; + next(); + decl(0x0030); + gen_inline_functions(s1); + check_vstack(); + + tcc_debug_end(s1); + return 0; +} + + +static Elf64_Sym *elfsym(Sym *s) +{ + if (!s || !s->c) + return 0; + return &((Elf64_Sym *)symtab_section->data)[s->c]; +} + + +static void update_storage(Sym *sym) +{ + Elf64_Sym *esym; + int sym_bind, old_sym_bind; + + esym = elfsym(sym); + if (!esym) + return; + + if (sym->a.visibility) + esym->st_other = (esym->st_other & ~((-1) & 0x03)) + | sym->a.visibility; + + if (sym->type.t & 0x00002000) + sym_bind = 0; + else if (sym->a.weak) + sym_bind = 2; + else + sym_bind = 1; + old_sym_bind = (((unsigned char) (esym->st_info)) >> 4); + if (sym_bind != old_sym_bind) { + esym->st_info = ((((sym_bind)) << 4) + (((((esym->st_info) & 0xf))) & 0xf)); + } +# 332 "tccgen.c" +} + + + + + +static void put_extern_sym2(Sym *sym, int sh_num, + Elf64_Addr value, unsigned long size, + int can_add_underscore) +{ + int sym_type, sym_bind, info, other, t; + Elf64_Sym *esym; + const char *name; + char buf1[256]; + + char buf[32]; + + + if (!sym->c) { + name = get_tok_str(sym->v, 0); + + if (tcc_state->do_bounds_check) { + + + + switch(sym->v) { +# 366 "tccgen.c" + case TOK_memcpy: + case TOK_memmove: + case TOK_memset: + case TOK_strlen: + case TOK_strcpy: + case TOK_alloca: + strcpy(buf, "__bound_"); + strcat(buf, name); + name = buf; + break; + } + } + + t = sym->type.t; + if ((t & 0x000f) == 6) { + sym_type = 2; + } else if ((t & 0x000f) == 0) { + sym_type = 0; + } else { + sym_type = 1; + } + if (t & 0x00002000) + sym_bind = 0; + else + sym_bind = 1; + other = 0; +# 403 "tccgen.c" + if (tcc_state->leading_underscore && can_add_underscore) { + buf1[0] = '_'; + pstrcpy(buf1 + 1, sizeof(buf1) - 1, name); + name = buf1; + } + if (sym->asm_label) + name = get_tok_str(sym->asm_label, 0); + info = ((((sym_bind)) << 4) + (((sym_type)) & 0xf)); + sym->c = put_elf_sym(symtab_section, value, size, info, other, sh_num, name); + } else { + esym = elfsym(sym); + esym->st_value = value; + esym->st_size = size; + esym->st_shndx = sh_num; + } + update_storage(sym); +} + +static void put_extern_sym(Sym *sym, Section *section, + Elf64_Addr value, unsigned long size) +{ + int sh_num = section ? section->sh_num : 0; + put_extern_sym2(sym, sh_num, value, size, 1); +} + + +static void greloca(Section *s, Sym *sym, unsigned long offset, int type, + Elf64_Addr addend) +{ + int c = 0; + + if (nocode_wanted && s == cur_text_section) + return; + + if (sym) { + if (0 == sym->c) + put_extern_sym(sym, 0, 0, 0); + c = sym->c; + } + + + put_elf_reloca(symtab_section, s, offset, type, c, addend); +} +# 456 "tccgen.c" +static Sym *__sym_malloc(void) +{ + Sym *sym_pool, *sym, *last_sym; + int i; + + sym_pool = tcc_malloc((8192 / sizeof(Sym)) * sizeof(Sym)); + dynarray_add(&sym_pools, &nb_sym_pools, sym_pool); + + last_sym = sym_free_first; + sym = sym_pool; + for(i = 0; i < (8192 / sizeof(Sym)); i++) { + sym->next = last_sym; + last_sym = sym; + sym++; + } + sym_free_first = last_sym; + return last_sym; +} + +static inline Sym *sym_malloc(void) +{ + Sym *sym; + + sym = sym_free_first; + if (!sym) + sym = __sym_malloc(); + sym_free_first = sym->next; + return sym; + + + + +} + +static inline void sym_free(Sym *sym) +{ + + sym->next = sym_free_first; + sym_free_first = sym; + + + +} + + +static Sym *sym_push2(Sym **ps, int v, int t, int c) +{ + Sym *s; + + s = sym_malloc(); + memset(s, 0, sizeof *s); + s->v = v; + s->type.t = t; + s->c = c; + + s->prev = *ps; + *ps = s; + return s; +} + + + +static Sym *sym_find2(Sym *s, int v) +{ + while (s) { + if (s->v == v) + return s; + else if (s->v == -1) + return 0; + s = s->prev; + } + return 0; +} + + +static inline Sym *struct_find(int v) +{ + v -= 256; + if ((unsigned)v >= (unsigned)(tok_ident - 256)) + return 0; + return table_ident[v]->sym_struct; +} + + +static inline Sym *sym_find(int v) +{ + v -= 256; + if ((unsigned)v >= (unsigned)(tok_ident - 256)) + return 0; + return table_ident[v]->sym_identifier; +} + + +static Sym *sym_push(int v, CType *type, int r, int c) +{ + Sym *s, **ps; + TokenSym *ts; + + if (local_stack) + ps = &local_stack; + else + ps = &global_stack; + s = sym_push2(ps, v, type->t, c); + s->type.ref = type->ref; + s->r = r; + + + if (!(v & 0x20000000) && (v & ~0x40000000) < 0x10000000) { + + ts = table_ident[(v & ~0x40000000) - 256]; + if (v & 0x40000000) + ps = &ts->sym_struct; + else + ps = &ts->sym_identifier; + s->prev_tok = *ps; + *ps = s; + s->sym_scope = local_scope; + if (s->prev_tok && s->prev_tok->sym_scope == s->sym_scope) + tcc_error("redeclaration of '%s'", + get_tok_str(v & ~0x40000000, 0)); + } + return s; +} + + +static Sym *global_identifier_push(int v, int t, int c) +{ + Sym *s, **ps; + s = sym_push2(&global_stack, v, t, c); + + if (v < 0x10000000) { + ps = &table_ident[v - 256]->sym_identifier; + + + while (*ps != 0 && (*ps)->sym_scope) + ps = &(*ps)->prev_tok; + s->prev_tok = *ps; + *ps = s; + } + return s; +} + + + +static void sym_pop(Sym **ptop, Sym *b, int keep) +{ + Sym *s, *ss, **ps; + TokenSym *ts; + int v; + + s = *ptop; + while(s != b) { + ss = s->prev; + v = s->v; + + + if (!(v & 0x20000000) && (v & ~0x40000000) < 0x10000000) { + ts = table_ident[(v & ~0x40000000) - 256]; + if (v & 0x40000000) + ps = &ts->sym_struct; + else + ps = &ts->sym_identifier; + *ps = s->prev_tok; + } + if (!keep) + sym_free(s); + s = ss; + } + if (!keep) + *ptop = b; +} + + + +static void vsetc(CType *type, int r, CValue *vc) +{ + int v; + + if (vtop >= (__vstack + 1) + (256 - 1)) + tcc_error("memory full (vstack)"); +# 649 "tccgen.c" + if (vtop >= (__vstack + 1) && !nocode_wanted) { + v = vtop->r & 0x003f; + if (v == 0x0033 || (v & ~1) == 0x0034) + gv(0x0001); + } + + vtop++; + vtop->type = *type; + vtop->r = r; + vtop->r2 = 0x0030; + vtop->c = *vc; + vtop->sym = 0; +} + +static void vswap(void) +{ + SValue tmp; + + if (vtop >= (__vstack + 1) && !nocode_wanted) { + int v = vtop->r & 0x003f; + if (v == 0x0033 || (v & ~1) == 0x0034) + gv(0x0001); + } + tmp = vtop[0]; + vtop[0] = vtop[-1]; + vtop[-1] = tmp; +} + + +static void vpop(void) +{ + int v; + v = vtop->r & 0x003f; + + + if (v == TREG_ST0) { + o(0xd8dd); + } else + + if (v == 0x0034 || v == 0x0035) { + + gsym(vtop->c.i); + } + vtop--; +} + + +static void vpush(CType *type) +{ + vset(type, 0x0030, 0); +} + + +static void vpushi(int v) +{ + CValue cval; + cval.i = v; + vsetc(&int_type, 0x0030, &cval); +} + + +static void vpushs(Elf64_Addr v) +{ + CValue cval; + cval.i = v; + vsetc(&size_type, 0x0030, &cval); +} + + +static void vpush64(int ty, unsigned long long v) +{ + CValue cval; + CType ctype; + ctype.t = ty; + ctype.ref = 0; + cval.i = v; + vsetc(&ctype, 0x0030, &cval); +} + + +static inline void vpushll(long long v) +{ + vpush64(4, v); +} + +static void vset(CType *type, int r, int v) +{ + CValue cval; + + cval.i = v; + vsetc(type, r, &cval); +} + +static void vseti(int r, int v) +{ + CType type; + type.t = 3; + type.ref = 0; + vset(&type, r, v); +} + +static void vpushv(SValue *v) +{ + if (vtop >= (__vstack + 1) + (256 - 1)) + tcc_error("memory full (vstack)"); + vtop++; + *vtop = *v; +} + +static void vdup(void) +{ + vpushv(vtop); +} + + + + +static void vrotb(int n) +{ + int i; + SValue tmp; + + tmp = vtop[-n + 1]; + for(i=-n+1;i!=0;i++) + vtop[i] = vtop[i+1]; + vtop[0] = tmp; +} + + + + +static void vrote(SValue *e, int n) +{ + int i; + SValue tmp; + + tmp = *e; + for(i = 0;i < n - 1; i++) + e[-i] = e[-i - 1]; + e[-n + 1] = tmp; +} + + + + +static void vrott(int n) +{ + vrote(vtop, n); +} + + +static inline void vpushsym(CType *type, Sym *sym) +{ + CValue cval; + cval.i = 0; + vsetc(type, 0x0030 | 0x0200, &cval); + vtop->sym = sym; +} + + +static Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) +{ + int v; + Sym *sym; + + v = anon_sym++; + sym = global_identifier_push(v, type->t | 0x00002000, 0); + sym->type.ref = type->ref; + sym->r = 0x0030 | 0x0200; + put_extern_sym(sym, sec, offset, size); + return sym; +} + + +static void vpush_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) +{ + vpushsym(type, get_sym_ref(type, sec, offset, size)); +} + + +static Sym *external_global_sym(int v, CType *type, int r) +{ + Sym *s; + + s = sym_find(v); + if (!s) { + + s = global_identifier_push(v, type->t | 0x00001000, 0); + s->type.ref = type->ref; + s->r = r | 0x0030 | 0x0200; + } else if ((((s)->type.t & (0x000f | (0 | 0x0010))) == (0 | 0x0010))) { + s->type.t = type->t | (s->type.t & 0x00001000); + s->type.ref = type->ref; + update_storage(s); + } + return s; +} + + +static void patch_type(Sym *sym, CType *type) +{ + if (!(type->t & 0x00001000)) { + if (!(sym->type.t & 0x00001000)) + tcc_error("redefinition of '%s'", get_tok_str(sym->v, 0)); + sym->type.t &= ~0x00001000; + } + + if ((((sym)->type.t & (0x000f | (0 | 0x0010))) == (0 | 0x0010))) { + + sym->type.t = type->t & (sym->type.t | ~0x00002000); + sym->type.ref = type->ref; + } + + if (!is_compatible_types(&sym->type, type)) { + tcc_error("incompatible types for redefinition of '%s'", + get_tok_str(sym->v, 0)); + + } else if ((sym->type.t & 0x000f) == 6) { + int static_proto = sym->type.t & 0x00002000; + + if ((type->t & 0x00002000) && !static_proto && !(type->t & 0x00008000)) + tcc_warning("static storage ignored for redefinition of '%s'", + get_tok_str(sym->v, 0)); + + if (0 == (type->t & 0x00001000)) { + + sym->type.t = (type->t & ~0x00002000) | static_proto; + if (type->t & 0x00008000) + sym->type.t = type->t; + sym->type.ref = type->ref; + } + + } else { + if ((sym->type.t & 0x0040) && type->ref->c >= 0) { + + if (sym->type.ref->c < 0) + sym->type.ref->c = type->ref->c; + else if (sym->type.ref->c != type->ref->c) + tcc_error("conflicting type for '%s'", get_tok_str(sym->v, 0)); + } + if ((type->t ^ sym->type.t) & 0x00002000) + tcc_warning("storage mismatch for redefinition of '%s'", + get_tok_str(sym->v, 0)); + } +} + + + +static void patch_storage(Sym *sym, AttributeDef *ad, CType *type) +{ + if (type) + patch_type(sym, type); + + + + + + + + sym->a.weak |= ad->a.weak; + if (ad->a.visibility) { + int vis = sym->a.visibility; + int vis2 = ad->a.visibility; + if (vis == 0) + vis = vis2; + else if (vis2 != 0) + vis = (vis < vis2) ? vis : vis2; + sym->a.visibility = vis; + } + if (ad->a.aligned) + sym->a.aligned = ad->a.aligned; + if (ad->asm_label) + sym->asm_label = ad->asm_label; + update_storage(sym); +} + + +static Sym *external_sym(int v, CType *type, int r, AttributeDef *ad) +{ + Sym *s; + s = sym_find(v); + if (!s) { + + s = sym_push(v, type, r | 0x0030 | 0x0200, 0); + s->type.t |= 0x00001000; + s->a = ad->a; + s->sym_scope = 0; + } else { + if (s->type.ref == func_old_type.ref) { + s->type.ref = type->ref; + s->r = r | 0x0030 | 0x0200; + s->type.t |= 0x00001000; + } + patch_storage(s, ad, type); + } + return s; +} + + +static void vpush_global_sym(CType *type, int v) +{ + vpushsym(type, external_global_sym(v, type, 0)); +} + + +static void save_regs(int n) +{ + SValue *p, *p1; + for(p = (__vstack + 1), p1 = vtop - n; p <= p1; p++) + save_reg(p->r); +} + + +static void save_reg(int r) +{ + save_reg_upstack(r, 0); +} + + + +static void save_reg_upstack(int r, int n) +{ + int l, saved, size, align; + SValue *p, *p1, sv; + CType *type; + + if ((r &= 0x003f) >= 0x0030) + return; + if (nocode_wanted) + return; + + + saved = 0; + l = 0; + for(p = (__vstack + 1), p1 = vtop - n; p <= p1; p++) { + if ((p->r & 0x003f) == r || + ((p->type.t & 0x000f) == 4 && (p->r2 & 0x003f) == r)) { + + if (!saved) { + + r = p->r & 0x003f; + + type = &p->type; + if ((p->r & 0x0100) || + (!is_float(type->t) && (type->t & 0x000f) != 4)) + + type = &char_pointer_type; + + + + size = type_size(type, &align); + loc = (loc - size) & -align; + sv.type.t = type->t; + sv.r = 0x0032 | 0x0100; + sv.c.i = loc; + store(r, &sv); + + + if (r == TREG_ST0) { + o(0xd8dd); + } +# 1018 "tccgen.c" + l = loc; + saved = 1; + } + + if (p->r & 0x0100) { + + + + p->r = (p->r & ~(0x003f | 0x8000)) | 0x0031; + } else { + p->r = lvalue_type(p->type.t) | 0x0032; + } + p->r2 = 0x0030; + p->c.i = l; + } + } +} +# 1062 "tccgen.c" +static int get_reg(int rc) +{ + int r; + SValue *p; + + + for(r=0;r<25;r++) { + if (reg_classes[r] & rc) { + if (nocode_wanted) + return r; + for(p=(__vstack + 1);p<=vtop;p++) { + if ((p->r & 0x003f) == r || + (p->r2 & 0x003f) == r) + goto notfound; + } + return r; + } + notfound: ; + } + + + + + for(p=(__vstack + 1);p<=vtop;p++) { + + r = p->r2 & 0x003f; + if (r < 0x0030 && (reg_classes[r] & rc)) + goto save_found; + r = p->r & 0x003f; + if (r < 0x0030 && (reg_classes[r] & rc)) { + save_found: + save_reg(r); + return r; + } + } + + return -1; +} + + + +static void move_reg(int r, int s, int t) +{ + SValue sv; + + if (r != s) { + save_reg(r); + sv.type.t = t; + sv.type.ref = 0; + sv.r = s; + sv.c.i = 0; + load(r, &sv); + } +} + + +static void gaddrof(void) +{ + vtop->r &= ~0x0100; + + if ((vtop->r & 0x003f) == 0x0031) + vtop->r = (vtop->r & ~(0x003f | (0x1000 | 0x2000 | 0x4000))) | 0x0032 | 0x0100; + + +} + + + +static void gbound(void) +{ + int lval_type; + CType type1; + + vtop->r &= ~0x0800; + + if (vtop->r & 0x0100) { + + if (!(vtop->r & 0x8000)) { + lval_type = vtop->r & ((0x1000 | 0x2000 | 0x4000) | 0x0100); + + type1 = vtop->type; + vtop->type.t = 5; + gaddrof(); + vpushi(0); + gen_bounded_ptr_add(); + vtop->r |= lval_type; + vtop->type = type1; + } + + gen_bounded_ptr_deref(); + } +} + + +static void incr_bf_adr(int o) +{ + vtop->type = char_pointer_type; + gaddrof(); + vpushi(o); + gen_op('+'); + vtop->type.t = (vtop->type.t & ~(0x000f|0x0020)) + | (1|0x0010); + vtop->r = (vtop->r & ~(0x1000 | 0x2000 | 0x4000)) + | (0x1000|0x4000|0x0100); +} + + +static void load_packed_bf(CType *type, int bit_pos, int bit_size) +{ + int n, o, bits; + save_reg_upstack(vtop->r, 1); + vpush64(type->t & 0x000f, 0); + bits = 0, o = bit_pos >> 3, bit_pos &= 7; + do { + vswap(); + incr_bf_adr(o); + vdup(); + n = 8 - bit_pos; + if (n > bit_size) + n = bit_size; + if (bit_pos) + vpushi(bit_pos), gen_op(0xc9), bit_pos = 0; + if (n < 8) + vpushi((1 << n) - 1), gen_op('&'); + gen_cast(type); + if (bits) + vpushi(bits), gen_op(0x01); + vrotb(3); + gen_op('|'); + bits += n, bit_size -= n, o = 1; + } while (bit_size); + vswap(), vpop(); + if (!(type->t & 0x0010)) { + n = ((type->t & 0x000f) == 4 ? 64 : 32) - bits; + vpushi(n), gen_op(0x01); + vpushi(n), gen_op(0x02); + } +} + + +static void store_packed_bf(int bit_pos, int bit_size) +{ + int bits, n, o, m, c; + + c = (vtop->r & (0x003f | 0x0100 | 0x0200)) == 0x0030; + vswap(); + save_reg_upstack(vtop->r, 1); + bits = 0, o = bit_pos >> 3, bit_pos &= 7; + do { + incr_bf_adr(o); + vswap(); + c ? vdup() : gv_dup(); + vrott(3); + if (bits) + vpushi(bits), gen_op(0xc9); + if (bit_pos) + vpushi(bit_pos), gen_op(0x01); + n = 8 - bit_pos; + if (n > bit_size) + n = bit_size; + if (n < 8) { + m = ((1 << n) - 1) << bit_pos; + vpushi(m), gen_op('&'); + vpushv(vtop-1); + vpushi(m & 0x80 ? ~m & 0x7f : ~m); + gen_op('&'); + gen_op('|'); + } + vdup(), vtop[-1] = vtop[-2]; + vstore(), vpop(); + bits += n, bit_size -= n, bit_pos = 0, o = 1; + } while (bit_size); + vpop(), vpop(); +} + +static int adjust_bf(SValue *sv, int bit_pos, int bit_size) +{ + int t; + if (0 == sv->type.ref) + return 0; + t = sv->type.ref->auxtype; + if (t != -1 && t != 7) { + sv->type.t = (sv->type.t & ~0x000f) | t; + sv->r = (sv->r & ~(0x1000 | 0x2000 | 0x4000)) | lvalue_type(sv->type.t); + } + return t; +} + + + + +static int gv(int rc) +{ + int r, bit_pos, bit_size, size, align, rc2; + + + if (vtop->type.t & 0x0080) { + CType type; + + bit_pos = (((vtop->type.t) >> 20) & 0x3f); + bit_size = (((vtop->type.t) >> (20 + 6)) & 0x3f); + + vtop->type.t &= ~(((1 << (6+6)) - 1) << 20 | 0x0080); + + type.ref = 0; + type.t = vtop->type.t & 0x0010; + if ((vtop->type.t & 0x000f) == 11) + type.t |= 0x0010; + + r = adjust_bf(vtop, bit_pos, bit_size); + + if ((vtop->type.t & 0x000f) == 4) + type.t |= 4; + else + type.t |= 3; + + if (r == 7) { + load_packed_bf(&type, bit_pos, bit_size); + } else { + int bits = (type.t & 0x000f) == 4 ? 64 : 32; + + gen_cast(&type); + + vpushi(bits - (bit_pos + bit_size)); + gen_op(0x01); + vpushi(bits - bit_size); + + gen_op(0x02); + } + r = gv(rc); + } else { + if (is_float(vtop->type.t) && + (vtop->r & (0x003f | 0x0100)) == 0x0030) { + unsigned long offset; + + + size = type_size(&vtop->type, &align); + if ((nocode_wanted > 0)) + size = 0, align = 1; + offset = section_add(data_section, size, align); + vpush_ref(&vtop->type, data_section, offset, size); + vswap(); + init_putv(&vtop->type, data_section, offset); + vtop->r |= 0x0100; + } + + if (vtop->r & 0x0800) + gbound(); + + + r = vtop->r & 0x003f; + rc2 = (rc & 0x0002) ? 0x0002 : 0x0001; + + if (rc == 0x0004) + rc2 = 0x0010; + + else if (rc == 0x1000) + rc2 = 0x2000; + + + + + + + if (r >= 0x0030 + || (vtop->r & 0x0100) + || !(reg_classes[r] & rc) + + || ((vtop->type.t & 0x000f) == 13 && !(reg_classes[vtop->r2] & rc2)) + || ((vtop->type.t & 0x000f) == 14 && !(reg_classes[vtop->r2] & rc2)) + + + + ) + { + r = get_reg(rc); + + if (((vtop->type.t & 0x000f) == 13) || ((vtop->type.t & 0x000f) == 14)) { + int addr_type = 4, load_size = 8, load_type = ((vtop->type.t & 0x000f) == 13) ? 4 : 9; + + + + + + int r2, original_type; + original_type = vtop->type.t; +# 1360 "tccgen.c" + if (vtop->r & 0x0100) { +# 1369 "tccgen.c" + save_reg_upstack(vtop->r, 1); + + + vtop->type.t = load_type; + load(r, vtop); + vdup(); + vtop[-1].r = r; + + vtop->type.t = addr_type; + gaddrof(); + vpushi(load_size); + gen_op('+'); + vtop->r |= 0x0100; + vtop->type.t = load_type; + } else { + + load(r, vtop); + vdup(); + vtop[-1].r = r; + vtop->r = vtop[-1].r2; + } + + + r2 = get_reg(rc2); + load(r2, vtop); + vpop(); + + vtop->r2 = r2; + vtop->type.t = original_type; + } else if ((vtop->r & 0x0100) && !is_float(vtop->type.t)) { + int t1, t; + + + t = vtop->type.t; + t1 = t; + + if (vtop->r & 0x1000) + t = 1; + else if (vtop->r & 0x2000) + t = 2; + if (vtop->r & 0x4000) + t |= 0x0010; + vtop->type.t = t; + load(r, vtop); + + vtop->type.t = t1; + } else { + + load(r, vtop); + } + } + vtop->r = r; + + + + + + } + return r; +} + + +static void gv2(int rc1, int rc2) +{ + int v; + + + + + v = vtop[0].r & 0x003f; + if (v != 0x0033 && (v & ~1) != 0x0034 && rc1 <= rc2) { + vswap(); + gv(rc1); + vswap(); + gv(rc2); + + if ((vtop[-1].r & 0x003f) >= 0x0030) { + vswap(); + gv(rc1); + vswap(); + } + } else { + gv(rc2); + vswap(); + gv(rc1); + vswap(); + + if ((vtop[0].r & 0x003f) >= 0x0030) { + gv(rc2); + } + } +} + + + +static int rc_fret(int t) +{ + + if (t == 10) { + return 0x0080; + } + + return 0x1000; +} + + + +static int reg_fret(int t) +{ + + if (t == 10) { + return TREG_ST0; + } + + return TREG_XMM0; +} +# 1550 "tccgen.c" +static void gv_dup(void) +{ + int rc, t, r, r1; + SValue sv; + + t = vtop->type.t; +# 1577 "tccgen.c" + { + + rc = 0x0001; + sv.type.t = 3; + if (is_float(t)) { + rc = 0x0002; + + if ((t & 0x000f) == 10) { + rc = 0x0080; + } + + sv.type.t = t; + } + r = gv(rc); + r1 = get_reg(rc); + sv.r = r; + sv.c.i = 0; + load(r1, &sv); + vdup(); + + if (r != r1) + vtop->r = r1; + } +} + + + + +static int gvtst(int inv, int t) +{ + int v = vtop->r & 0x003f; + if (v != 0x0033 && v != 0x0034 && v != 0x0035) { + vpushi(0); + gen_op(0x95); + } + if ((vtop->r & (0x003f | 0x0100 | 0x0200)) == 0x0030) { + + if ((vtop->c.i != 0) != inv) + t = gjmp(t); + vtop--; + return t; + } + return gtst(inv, t); +} +# 1851 "tccgen.c" +static uint64_t gen_opic_sdiv(uint64_t a, uint64_t b) +{ + uint64_t x = (a >> 63 ? -a : a) / (b >> 63 ? -b : b); + return (a ^ b) >> 63 ? -x : x; +} + +static int gen_opic_lt(uint64_t a, uint64_t b) +{ + return (a ^ (uint64_t)1 << 63) < (b ^ (uint64_t)1 << 63); +} + + + +static void gen_opic(int op) +{ + SValue *v1 = vtop - 1; + SValue *v2 = vtop; + int t1 = v1->type.t & 0x000f; + int t2 = v2->type.t & 0x000f; + int c1 = (v1->r & (0x003f | 0x0100 | 0x0200)) == 0x0030; + int c2 = (v2->r & (0x003f | 0x0100 | 0x0200)) == 0x0030; + uint64_t l1 = c1 ? v1->c.i : 0; + uint64_t l2 = c2 ? v2->c.i : 0; + int shm = (t1 == 4) ? 63 : 31; + + if (t1 != 4 && (8 != 8 || t1 != 5)) + l1 = ((uint32_t)l1 | + (v1->type.t & 0x0010 ? 0 : -(l1 & 0x80000000))); + if (t2 != 4 && (8 != 8 || t2 != 5)) + l2 = ((uint32_t)l2 | + (v2->type.t & 0x0010 ? 0 : -(l2 & 0x80000000))); + + if (c1 && c2) { + switch(op) { + case '+': l1 += l2; break; + case '-': l1 -= l2; break; + case '&': l1 &= l2; break; + case '^': l1 ^= l2; break; + case '|': l1 |= l2; break; + case '*': l1 *= l2; break; + + case 0xb2: + case '/': + case '%': + case 0xb0: + case 0xb1: + + if (l2 == 0) { + if (const_wanted) + tcc_error("division by zero in constant"); + goto general_case; + } + switch(op) { + default: l1 = gen_opic_sdiv(l1, l2); break; + case '%': l1 = l1 - l2 * gen_opic_sdiv(l1, l2); break; + case 0xb0: l1 = l1 / l2; break; + case 0xb1: l1 = l1 % l2; break; + } + break; + case 0x01: l1 <<= (l2 & shm); break; + case 0xc9: l1 >>= (l2 & shm); break; + case 0x02: + l1 = (l1 >> 63) ? ~(~l1 >> (l2 & shm)) : l1 >> (l2 & shm); + break; + + case 0x92: l1 = l1 < l2; break; + case 0x93: l1 = l1 >= l2; break; + case 0x94: l1 = l1 == l2; break; + case 0x95: l1 = l1 != l2; break; + case 0x96: l1 = l1 <= l2; break; + case 0x97: l1 = l1 > l2; break; + case 0x9c: l1 = gen_opic_lt(l1, l2); break; + case 0x9d: l1 = !gen_opic_lt(l1, l2); break; + case 0x9e: l1 = !gen_opic_lt(l2, l1); break; + case 0x9f: l1 = gen_opic_lt(l2, l1); break; + + case 0xa0: l1 = l1 && l2; break; + case 0xa1: l1 = l1 || l2; break; + default: + goto general_case; + } + if (t1 != 4 && (8 != 8 || t1 != 5)) + l1 = ((uint32_t)l1 | + (v1->type.t & 0x0010 ? 0 : -(l1 & 0x80000000))); + v1->c.i = l1; + vtop--; + } else { + + if (c1 && (op == '+' || op == '&' || op == '^' || + op == '|' || op == '*')) { + vswap(); + c2 = c1; + l2 = l1; + } + if (!const_wanted && + c1 && ((l1 == 0 && + (op == 0x01 || op == 0xc9 || op == 0x02)) || + (l1 == -1 && op == 0x02))) { + + vtop--; + } else if (!const_wanted && + c2 && ((l2 == 0 && (op == '&' || op == '*')) || + (op == '|' && + (l2 == -1 || (l2 == 0xFFFFFFFF && t2 != 4))) || + (l2 == 1 && (op == '%' || op == 0xb1)))) { + + if (l2 == 1) + vtop->c.i = 0; + vswap(); + vtop--; + } else if (c2 && (((op == '*' || op == '/' || op == 0xb0 || + op == 0xb2) && + l2 == 1) || + ((op == '+' || op == '-' || op == '|' || op == '^' || + op == 0x01 || op == 0xc9 || op == 0x02) && + l2 == 0) || + (op == '&' && + (l2 == -1 || (l2 == 0xFFFFFFFF && t2 != 4))))) { + + vtop--; + } else if (c2 && (op == '*' || op == 0xb2 || op == 0xb0)) { + + if (l2 > 0 && (l2 & (l2 - 1)) == 0) { + int n = -1; + while (l2) { + l2 >>= 1; + n++; + } + vtop->c.i = n; + if (op == '*') + op = 0x01; + else if (op == 0xb2) + op = 0x02; + else + op = 0xc9; + } + goto general_case; + } else if (c2 && (op == '+' || op == '-') && + (((vtop[-1].r & (0x003f | 0x0100 | 0x0200)) == (0x0030 | 0x0200)) + || (vtop[-1].r & (0x003f | 0x0100)) == 0x0032)) { + + if (op == '-') + l2 = -l2; + l2 += vtop[-1].c.i; + + + if ((int)l2 != l2) + goto general_case; + vtop--; + vtop->c.i = l2; + } else { + general_case: + + if (t1 == 4 || t2 == 4 || + (8 == 8 && (t1 == 5 || t2 == 5))) + gen_opl(op); + else + gen_opi(op); + } + } +} + + +static void gen_opif(int op) +{ + int c1, c2; + SValue *v1, *v2; + + + + + long double f1, f2; + + v1 = vtop - 1; + v2 = vtop; + + c1 = (v1->r & (0x003f | 0x0100 | 0x0200)) == 0x0030; + c2 = (v2->r & (0x003f | 0x0100 | 0x0200)) == 0x0030; + if (c1 && c2) { + if (v1->type.t == 8) { + f1 = v1->c.f; + f2 = v2->c.f; + } else if (v1->type.t == 9) { + f1 = v1->c.d; + f2 = v2->c.d; + } else { + f1 = v1->c.ld; + f2 = v2->c.ld; + } + + + + if (!ieee_finite(f1) || !ieee_finite(f2)) + goto general_case; + + switch(op) { + case '+': f1 += f2; break; + case '-': f1 -= f2; break; + case '*': f1 *= f2; break; + case '/': + if (f2 == 0.0) { + if (const_wanted) + tcc_error("division by zero in constant"); + goto general_case; + } + f1 /= f2; + break; + + default: + goto general_case; + } + + if (v1->type.t == 8) { + v1->c.f = f1; + } else if (v1->type.t == 9) { + v1->c.d = f1; + } else { + v1->c.ld = f1; + } + vtop--; + } else { + general_case: + gen_opf(op); + } +} + +static int pointed_size(CType *type) +{ + int align; + return type_size(pointed_type(type), &align); +} + +static void vla_runtime_pointed_size(CType *type) +{ + int align; + vla_runtime_type_size(pointed_type(type), &align); +} + +static inline int is_null_pointer(SValue *p) +{ + if ((p->r & (0x003f | 0x0100 | 0x0200)) != 0x0030) + return 0; + return ((p->type.t & 0x000f) == 3 && (uint32_t)p->c.i == 0) || + ((p->type.t & 0x000f) == 4 && p->c.i == 0) || + ((p->type.t & 0x000f) == 5 && + (8 == 4 ? (uint32_t)p->c.i == 0 : p->c.i == 0)); +} + +static inline int is_integer_btype(int bt) +{ + return (bt == 1 || bt == 2 || + bt == 3 || bt == 4); +} + + +static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op) +{ + CType *type1, *type2, tmp_type1, tmp_type2; + int bt1, bt2; + + + if (is_null_pointer(p1) || is_null_pointer(p2)) + return; + type1 = &p1->type; + type2 = &p2->type; + bt1 = type1->t & 0x000f; + bt2 = type2->t & 0x000f; + + if ((is_integer_btype(bt1) || is_integer_btype(bt2)) && op != '-') { + if (op != 0xa1 && op != 0xa0 ) + tcc_warning("comparison between pointer and integer"); + return; + } + + + if (bt1 == 5) { + type1 = pointed_type(type1); + } else if (bt1 != 6) + goto invalid_operands; + + if (bt2 == 5) { + type2 = pointed_type(type2); + } else if (bt2 != 6) { + invalid_operands: + tcc_error("invalid operands to binary %s", get_tok_str(op, 0)); + } + if ((type1->t & 0x000f) == 0 || + (type2->t & 0x000f) == 0) + return; + tmp_type1 = *type1; + tmp_type2 = *type2; + tmp_type1.t &= ~(0x0020 | 0x0010 | 0x0100 | 0x0200); + tmp_type2.t &= ~(0x0020 | 0x0010 | 0x0100 | 0x0200); + if (!is_compatible_types(&tmp_type1, &tmp_type2)) { + + if (op == '-') + goto invalid_operands; + else + tcc_warning("comparison of distinct pointer types lacks a cast"); + } +} + + +static void gen_op(int op) +{ + int u, t1, t2, bt1, bt2, t; + CType type1; + +redo: + t1 = vtop[-1].type.t; + t2 = vtop[0].type.t; + bt1 = t1 & 0x000f; + bt2 = t2 & 0x000f; + + if (bt1 == 7 || bt2 == 7) { + tcc_error("operation on a struct"); + } else if (bt1 == 6 || bt2 == 6) { + if (bt2 == 6) { + mk_pointer(&vtop->type); + gaddrof(); + } + if (bt1 == 6) { + vswap(); + mk_pointer(&vtop->type); + gaddrof(); + vswap(); + } + goto redo; + } else if (bt1 == 5 || bt2 == 5) { + + + if (op >= 0x92 && op <= 0xa1) { + check_comparison_pointer_types(vtop - 1, vtop, op); + + + t = 4 | 0x0010; + + + + goto std_op; + } + + if (bt1 == 5 && bt2 == 5) { + if (op != '-') + tcc_error("cannot use pointers here"); + check_comparison_pointer_types(vtop - 1, vtop, op); + + if (vtop[-1].type.t & 0x0400) { + vla_runtime_pointed_size(&vtop[-1].type); + } else { + vpushi(pointed_size(&vtop[-1].type)); + } + vrott(3); + gen_opic(op); + vtop->type.t = ptrdiff_type.t; + vswap(); + gen_op(0xb2); + } else { + + if (op != '-' && op != '+') + tcc_error("cannot use pointers here"); + + if (bt2 == 5) { + vswap(); + t = t1, t1 = t2, t2 = t; + } + + + + + + type1 = vtop[-1].type; + type1.t &= ~0x0040; + if (vtop[-1].type.t & 0x0400) + vla_runtime_pointed_size(&vtop[-1].type); + else { + u = pointed_size(&vtop[-1].type); + if (u < 0) + tcc_error("unknown array element size"); + + vpushll(u); + + + + + } + gen_op('*'); +# 2267 "tccgen.c" + { + gen_opic(op); + } + + vtop->type = type1; + } + } else if (is_float(bt1) || is_float(bt2)) { + + if (bt1 == 10 || bt2 == 10) { + t = 10; + } else if (bt1 == 9 || bt2 == 9) { + t = 9; + } else { + t = 8; + } + + if (op != '+' && op != '-' && op != '*' && op != '/' && + (op < 0x92 || op > 0x9f)) + tcc_error("invalid operands for binary operation"); + goto std_op; + } else if (op == 0xc9 || op == 0x02 || op == 0x01) { + t = bt1 == 4 ? 4 : 3; + if ((t1 & (0x000f | 0x0010 | 0x0080)) == (t | 0x0010)) + t |= 0x0010; + t |= (0x0800 & t1); + goto std_op; + } else if (bt1 == 4 || bt2 == 4) { + + t = 4 | 0x0800; + if (bt1 == 4) + t &= t1; + if (bt2 == 4) + t &= t2; + + if ((t1 & (0x000f | 0x0010 | 0x0080)) == (4 | 0x0010) || + (t2 & (0x000f | 0x0010 | 0x0080)) == (4 | 0x0010)) + t |= 0x0010; + goto std_op; + } else { + + t = 3 | (0x0800 & (t1 | t2)); + + if ((t1 & (0x000f | 0x0010 | 0x0080)) == (3 | 0x0010) || + (t2 & (0x000f | 0x0010 | 0x0080)) == (3 | 0x0010)) + t |= 0x0010; + std_op: + + + if (t & 0x0010) { + if (op == 0x02) + op = 0xc9; + else if (op == '/') + op = 0xb0; + else if (op == '%') + op = 0xb1; + else if (op == 0x9c) + op = 0x92; + else if (op == 0x9f) + op = 0x97; + else if (op == 0x9e) + op = 0x96; + else if (op == 0x9d) + op = 0x93; + } + vswap(); + type1.t = t; + type1.ref = 0; + gen_cast(&type1); + vswap(); + + + if (op == 0xc9 || op == 0x02 || op == 0x01) + type1.t = 3; + gen_cast(&type1); + if (is_float(t)) + gen_opif(op); + else + gen_opic(op); + if (op >= 0x92 && op <= 0x9f) { + + vtop->type.t = 3; + } else { + vtop->type.t = t; + } + } + + if (vtop->r & 0x0100) + gv(is_float(vtop->type.t & 0x000f) ? 0x0002 : 0x0001); +} + + + +static void gen_cvt_itof1(int t) +{ + + + + if ((vtop->type.t & (0x000f | 0x0010)) == + (4 | 0x0010)) { + + if (t == 8) + vpush_global_sym(&func_old_type, TOK___floatundisf); + + else if (t == 10) + vpush_global_sym(&func_old_type, TOK___floatundixf); + + else + vpush_global_sym(&func_old_type, TOK___floatundidf); + vrott(2); + gfunc_call(1); + vpushi(0); + vtop->r = reg_fret(t); + } else { + gen_cvt_itof(t); + } + +} + + + +static void gen_cvt_ftoi1(int t) +{ + + + + int st; + + if (t == (4 | 0x0010)) { + + st = vtop->type.t & 0x000f; + if (st == 8) + vpush_global_sym(&func_old_type, TOK___fixunssfdi); + + else if (st == 10) + vpush_global_sym(&func_old_type, TOK___fixunsxfdi); + + else + vpush_global_sym(&func_old_type, TOK___fixunsdfdi); + vrott(2); + gfunc_call(1); + vpushi(0); + vtop->r = TREG_RAX; + vtop->r2 = TREG_RDX; + } else { + gen_cvt_ftoi(t); + } + +} + + +static void force_charshort_cast(int t) +{ + int bits, dbt; + + + if ((nocode_wanted & 0xC0000000)) + return; + + dbt = t & 0x000f; + + if (dbt == 1) + bits = 8; + else + bits = 16; + if (t & 0x0010) { + vpushi((1 << bits) - 1); + gen_op('&'); + } else { + if ((vtop->type.t & 0x000f) == 4) + bits = 64 - bits; + else + bits = 32 - bits; + vpushi(bits); + gen_op(0x01); + + + + vtop->type.t &= ~0x0010; + vpushi(bits); + gen_op(0x02); + } +} + + +static void gen_cast_s(int t) +{ + CType type; + type.t = t; + type.ref = 0; + gen_cast(&type); +} + +static void gen_cast(CType *type) +{ + int sbt, dbt, sf, df, c, p; + + + + + if (vtop->r & 0x0400) { + vtop->r &= ~0x0400; + force_charshort_cast(vtop->type.t); + } + + + if (vtop->type.t & 0x0080) { + gv(0x0001); + } + + dbt = type->t & (0x000f | 0x0010); + sbt = vtop->type.t & (0x000f | 0x0010); + + if (sbt != dbt) { + sf = is_float(sbt); + df = is_float(dbt); + c = (vtop->r & (0x003f | 0x0100 | 0x0200)) == 0x0030; + p = (vtop->r & (0x003f | 0x0100 | 0x0200)) == (0x0030 | 0x0200); + + + + if (c) { + + + if (sbt == 8) + vtop->c.ld = vtop->c.f; + else if (sbt == 9) + vtop->c.ld = vtop->c.d; + + if (df) { + if ((sbt & 0x000f) == 4) { + if ((sbt & 0x0010) || !(vtop->c.i >> 63)) + vtop->c.ld = vtop->c.i; + else + vtop->c.ld = -(long double)-vtop->c.i; + } else if(!sf) { + if ((sbt & 0x0010) || !(vtop->c.i >> 31)) + vtop->c.ld = (uint32_t)vtop->c.i; + else + vtop->c.ld = -(long double)-(uint32_t)vtop->c.i; + } + + if (dbt == 8) + vtop->c.f = (float)vtop->c.ld; + else if (dbt == 9) + vtop->c.d = (double)vtop->c.ld; + } else if (sf && dbt == (4|0x0010)) { + vtop->c.i = vtop->c.ld; + } else if (sf && dbt == 11) { + vtop->c.i = (vtop->c.ld != 0); + } else { + if(sf) + vtop->c.i = vtop->c.ld; + else if (sbt == (4|0x0010)) + ; + else if (sbt & 0x0010) + vtop->c.i = (uint32_t)vtop->c.i; + + else if (sbt == 5) + ; + + else if (sbt != 4) + vtop->c.i = ((uint32_t)vtop->c.i | + -(vtop->c.i & 0x80000000)); + + if (dbt == (4|0x0010)) + ; + else if (dbt == 11) + vtop->c.i = (vtop->c.i != 0); + + else if (dbt == 5) + ; + + else if (dbt != 4) { + uint32_t m = ((dbt & 0x000f) == 1 ? 0xff : + (dbt & 0x000f) == 2 ? 0xffff : + 0xffffffff); + vtop->c.i &= m; + if (!(dbt & 0x0010)) + vtop->c.i |= -(vtop->c.i & ((m >> 1) + 1)); + } + } + } else if (p && dbt == 11) { + vtop->r = 0x0030; + vtop->c.i = 1; + } else { + + if (sf && df) { + + gen_cvt_ftof(dbt); + } else if (df) { + + gen_cvt_itof1(dbt); + } else if (sf) { + + if (dbt == 11) { + vpushi(0); + gen_op(0x95); + } else { + + if (dbt != (3 | 0x0010) && + dbt != (4 | 0x0010) && + dbt != 4) + dbt = 3; + gen_cvt_ftoi1(dbt); + if (dbt == 3 && (type->t & (0x000f | 0x0010)) != dbt) { + + vtop->type.t = dbt; + gen_cast(type); + } + } +# 2602 "tccgen.c" + } else if ((dbt & 0x000f) == 4 || + (dbt & 0x000f) == 5 || + (dbt & 0x000f) == 6) { + if ((sbt & 0x000f) != 4 && + (sbt & 0x000f) != 5 && + (sbt & 0x000f) != 6) { + + gv(0x0001); + if (sbt != (3 | 0x0010)) { + + + + int r = gv(0x0001); + + o(0x6348); + o(0xc0 + (((r) & 7) << 3) + ((r) & 7)); + + + + } + } + + } else if (dbt == 11) { + + vpushi(0); + gen_op(0x95); + } else if ((dbt & 0x000f) == 1 || + (dbt & 0x000f) == 2) { + if (sbt == 5) { + vtop->type.t = 3; + tcc_warning("nonportable conversion from pointer to char/short"); + } + force_charshort_cast(dbt); +# 2647 "tccgen.c" + } + } + } else if ((dbt & 0x000f) == 5 && !(vtop->r & 0x0100)) { + + + vtop->r = (vtop->r & ~(0x1000 | 0x2000 | 0x4000)) + | (lvalue_type(type->ref->type.t) & (0x1000 | 0x2000 | 0x4000)); + } + vtop->type = *type; +} + + +static int type_size(CType *type, int *a) +{ + Sym *s; + int bt; + + bt = type->t & 0x000f; + if (bt == 7) { + + s = type->ref; + *a = s->r; + return s->c; + } else if (bt == 5) { + if (type->t & 0x0040) { + int ts; + + s = type->ref; + ts = type_size(&s->type, a); + + if (ts < 0 && s->c < 0) + ts = -ts; + + return ts * s->c; + } else { + *a = 8; + return 8; + } + } else if (((type->t & (((1 << (6+6)) - 1) << 20 | 0x0080)) == (2 << 20)) && type->ref->c == -1) { + return -1; + } else if (bt == 10) { + *a = 16; + return 16; + } else if (bt == 9 || bt == 4) { +# 2704 "tccgen.c" + *a = 8; + + return 8; + } else if (bt == 3 || bt == 8) { + *a = 4; + return 4; + } else if (bt == 2) { + *a = 2; + return 2; + } else if (bt == 13 || bt == 14) { + *a = 8; + return 16; + } else { + + *a = 1; + return 1; + } +} + + + +static void vla_runtime_type_size(CType *type, int *a) +{ + if (type->t & 0x0400) { + type_size(&type->ref->type, a); + vset(&int_type, 0x0032|0x0100, type->ref->c); + } else { + vpushi(type_size(type, a)); + } +} + +static void vla_sp_restore(void) { + if (vlas_in_scope) { + gen_vla_sp_restore(vla_sp_loc); + } +} + +static void vla_sp_restore_root(void) { + if (vlas_in_scope) { + gen_vla_sp_restore(vla_sp_root_loc); + } +} + + +static inline CType *pointed_type(CType *type) +{ + return &type->ref->type; +} + + +static void mk_pointer(CType *type) +{ + Sym *s; + s = sym_push(0x20000000, type, 0, -1); + type->t = 5 | (type->t & (0x00001000 | 0x00002000 | 0x00004000 | 0x00008000)); + type->ref = s; +} + + +static int is_compatible_func(CType *type1, CType *type2) +{ + Sym *s1, *s2; + + s1 = type1->ref; + s2 = type2->ref; + if (!is_compatible_types(&s1->type, &s2->type)) + return 0; + + if (s1->f.func_call != s2->f.func_call) + return 0; + + if (s1->f.func_type == 2 || s2->f.func_type == 2) + return 1; + if (s1->f.func_type != s2->f.func_type) + return 0; + while (s1 != 0) { + if (s2 == 0) + return 0; + if (!is_compatible_unqualified_types(&s1->type, &s2->type)) + return 0; + s1 = s1->next; + s2 = s2->next; + } + if (s2) + return 0; + return 1; +} + + + + + + +static int compare_types(CType *type1, CType *type2, int unqualified) +{ + int bt1, t1, t2; + + t1 = type1->t & (~((0x00001000 | 0x00002000 | 0x00004000 | 0x00008000)|(((1 << (6+6)) - 1) << 20 | 0x0080))); + t2 = type2->t & (~((0x00001000 | 0x00002000 | 0x00004000 | 0x00008000)|(((1 << (6+6)) - 1) << 20 | 0x0080))); + if (unqualified) { + + t1 &= ~(0x0100 | 0x0200); + t2 &= ~(0x0100 | 0x0200); + } + + + if ((t1 & 0x000f) != 1) { + t1 &= ~0x0020; + t2 &= ~0x0020; + } + + if (t1 != t2) + return 0; + + bt1 = t1 & 0x000f; + if (bt1 == 5) { + type1 = pointed_type(type1); + type2 = pointed_type(type2); + return is_compatible_types(type1, type2); + } else if (bt1 == 7) { + return (type1->ref == type2->ref); + } else if (bt1 == 6) { + return is_compatible_func(type1, type2); + } else { + return 1; + } +} + + + + +static int is_compatible_types(CType *type1, CType *type2) +{ + return compare_types(type1,type2,0); +} + + + +static int is_compatible_unqualified_types(CType *type1, CType *type2) +{ + return compare_types(type1,type2,1); +} + + + + + +static void type_to_str(char *buf, int buf_size, + CType *type, const char *varstr) +{ + int bt, v, t; + Sym *s, *sa; + char buf1[256]; + const char *tstr; + + t = type->t; + bt = t & 0x000f; + buf[0] = '\0'; + + if (t & 0x00001000) + pstrcat(buf, buf_size, "extern "); + if (t & 0x00002000) + pstrcat(buf, buf_size, "static "); + if (t & 0x00004000) + pstrcat(buf, buf_size, "typedef "); + if (t & 0x00008000) + pstrcat(buf, buf_size, "inline "); + if (t & 0x0200) + pstrcat(buf, buf_size, "volatile "); + if (t & 0x0100) + pstrcat(buf, buf_size, "const "); + + if (((t & 0x0020) && bt == 1) + || ((t & 0x0010) + && (bt == 2 || bt == 3 || bt == 4) + && !((t & (((1 << (6+6)) - 1) << 20 | 0x0080)) == (2 << 20)) + )) + pstrcat(buf, buf_size, (t & 0x0010) ? "unsigned " : "signed "); + + buf_size -= strlen(buf); + buf += strlen(buf); + + switch(bt) { + case 0: + tstr = "void"; + goto add_tstr; + case 11: + tstr = "_Bool"; + goto add_tstr; + case 1: + tstr = "char"; + goto add_tstr; + case 2: + tstr = "short"; + goto add_tstr; + case 3: + tstr = "int"; + goto maybe_long; + case 4: + tstr = "long long"; + maybe_long: + if (t & 0x0800) + tstr = "long"; + if (!((t & (((1 << (6+6)) - 1) << 20 | 0x0080)) == (2 << 20))) + goto add_tstr; + tstr = "enum "; + goto tstruct; + case 8: + tstr = "float"; + goto add_tstr; + case 9: + tstr = "double"; + goto add_tstr; + case 10: + tstr = "long double"; + add_tstr: + pstrcat(buf, buf_size, tstr); + break; + case 7: + tstr = "struct "; + if (((t & ((((1 << (6+6)) - 1) << 20 | 0x0080)|0x000f)) == (1 << 20 | 7))) + tstr = "union "; + tstruct: + pstrcat(buf, buf_size, tstr); + v = type->ref->v & ~0x40000000; + if (v >= 0x10000000) + pstrcat(buf, buf_size, "<anonymous>"); + else + pstrcat(buf, buf_size, get_tok_str(v, 0)); + break; + case 6: + s = type->ref; + type_to_str(buf, buf_size, &s->type, varstr); + pstrcat(buf, buf_size, "("); + sa = s->next; + while (sa != 0) { + type_to_str(buf1, sizeof(buf1), &sa->type, 0); + pstrcat(buf, buf_size, buf1); + sa = sa->next; + if (sa) + pstrcat(buf, buf_size, ", "); + } + pstrcat(buf, buf_size, ")"); + goto no_var; + case 5: + s = type->ref; + if (t & 0x0040) { + snprintf(buf1, sizeof(buf1), "%s[%d]", varstr ? varstr : "", s->c); + type_to_str(buf, buf_size, &s->type, buf1); + goto no_var; + } + pstrcpy(buf1, sizeof(buf1), "*"); + if (t & 0x0100) + pstrcat(buf1, buf_size, "const "); + if (t & 0x0200) + pstrcat(buf1, buf_size, "volatile "); + if (varstr) + pstrcat(buf1, sizeof(buf1), varstr); + type_to_str(buf, buf_size, &s->type, buf1); + goto no_var; + } + if (varstr) { + pstrcat(buf, buf_size, " "); + pstrcat(buf, buf_size, varstr); + } + no_var: ; +} + + + +static void gen_assign_cast(CType *dt) +{ + CType *st, *type1, *type2; + char buf1[256], buf2[256]; + int dbt, sbt; + + st = &vtop->type; + dbt = dt->t & 0x000f; + sbt = st->t & 0x000f; + if (sbt == 0 || dbt == 0) { + if (sbt == 0 && dbt == 0) + ; +# 2994 "tccgen.c" + else + tcc_error("cannot cast from/to void"); + } + if (dt->t & 0x0100) + tcc_warning("assignment of read-only location"); + switch(dbt) { + case 5: + + + if (is_null_pointer(vtop)) + goto type_ok; + + if (is_integer_btype(sbt)) { + tcc_warning("assignment makes pointer from integer without a cast"); + goto type_ok; + } + type1 = pointed_type(dt); + + if (sbt == 6) { + if ((type1->t & 0x000f) != 0 && + !is_compatible_types(pointed_type(dt), st)) + tcc_warning("assignment from incompatible pointer type"); + goto type_ok; + } + if (sbt != 5) + goto error; + type2 = pointed_type(st); + if ((type1->t & 0x000f) == 0 || + (type2->t & 0x000f) == 0) { + + } else { + + + if (!is_compatible_unqualified_types(type1, type2)) { + + + + + if ((type1->t & (0x000f|0x0800)) != (type2->t & (0x000f|0x0800)) + || ((type1->t & (((1 << (6+6)) - 1) << 20 | 0x0080)) == (2 << 20)) || ((type2->t & (((1 << (6+6)) - 1) << 20 | 0x0080)) == (2 << 20)) + ) + tcc_warning("assignment from incompatible pointer type"); + } + } + + if ((!(type1->t & 0x0100) && (type2->t & 0x0100)) || + (!(type1->t & 0x0200) && (type2->t & 0x0200))) + tcc_warning("assignment discards qualifiers from pointer target type"); + break; + case 1: + case 2: + case 3: + case 4: + if (sbt == 5 || sbt == 6) { + tcc_warning("assignment makes integer from pointer without a cast"); + } else if (sbt == 7) { + goto case_VT_STRUCT; + } + + break; + case 7: + case_VT_STRUCT: + if (!is_compatible_unqualified_types(dt, st)) { + error: + type_to_str(buf1, sizeof(buf1), st, 0); + type_to_str(buf2, sizeof(buf2), dt, 0); + tcc_error("cannot cast '%s' to '%s'", buf1, buf2); + } + break; + } + type_ok: + gen_cast(dt); +} + + +static void vstore(void) +{ + int sbt, dbt, ft, r, t, size, align, bit_size, bit_pos, rc, delayed_cast; + + ft = vtop[-1].type.t; + sbt = vtop->type.t & 0x000f; + dbt = ft & 0x000f; + if ((((sbt == 3 || sbt == 2) && dbt == 1) || + (sbt == 3 && dbt == 2)) + && !(vtop->type.t & 0x0080)) { + + delayed_cast = 0x0400; + vtop->type.t = ft & (~((0x00001000 | 0x00002000 | 0x00004000 | 0x00008000)|(((1 << (6+6)) - 1) << 20 | 0x0080))); + + if (ft & 0x0100) + tcc_warning("assignment of read-only location"); + } else { + delayed_cast = 0; + if (!(ft & 0x0080)) + gen_assign_cast(&vtop[-1].type); + } + + if (sbt == 7) { + + + + size = type_size(&vtop->type, &align); + + + vswap(); + vtop->type.t = 5; + gaddrof(); +# 3111 "tccgen.c" + vpush_global_sym(&func_old_type, TOK_memmove); + + vswap(); + + vpushv(vtop - 2); + vtop->type.t = 5; + gaddrof(); + + vpushi(size); + gfunc_call(3); + + + } else if (ft & 0x0080) { + + + + vdup(), vtop[-1] = vtop[-2]; + + bit_pos = (((ft) >> 20) & 0x3f); + bit_size = (((ft) >> (20 + 6)) & 0x3f); + + vtop[-1].type.t = ft & ~(((1 << (6+6)) - 1) << 20 | 0x0080); + + if ((ft & 0x000f) == 11) { + gen_cast(&vtop[-1].type); + vtop[-1].type.t = (vtop[-1].type.t & ~0x000f) | (1 | 0x0010); + } + + r = adjust_bf(vtop - 1, bit_pos, bit_size); + if (r == 7) { + gen_cast_s((ft & 0x000f) == 4 ? 4 : 3); + store_packed_bf(bit_pos, bit_size); + } else { + unsigned long long mask = (1ULL << bit_size) - 1; + if ((ft & 0x000f) != 11) { + + if ((vtop[-1].type.t & 0x000f) == 4) + vpushll(mask); + else + vpushi((unsigned)mask); + gen_op('&'); + } + + vpushi(bit_pos); + gen_op(0x01); + vswap(); + + vdup(); + vrott(3); + + if ((vtop->type.t & 0x000f) == 4) + vpushll(~(mask << bit_pos)); + else + vpushi(~((unsigned)mask << bit_pos)); + gen_op('&'); + gen_op('|'); + + vstore(); + + vpop(); + } + } else if (dbt == 0) { + --vtop; + } else { + + + if (vtop[-1].r & 0x0800) { + vswap(); + gbound(); + vswap(); + } + + rc = 0x0001; + if (is_float(ft)) { + rc = 0x0002; + + if ((ft & 0x000f) == 10) { + rc = 0x0080; + } else if ((ft & 0x000f) == 14) { + rc = 0x1000; + } + + } + r = gv(rc); + + if ((vtop[-1].r & 0x003f) == 0x0031) { + SValue sv; + t = get_reg(0x0001); + + sv.type.t = 5; + + + + sv.r = 0x0032 | 0x0100; + sv.c.i = vtop[-1].c.i; + load(t, &sv); + vtop[-1].r = t | 0x0100; + } + + + if (((ft & 0x000f) == 13) || ((ft & 0x000f) == 14)) { + int addr_type = 4, load_size = 8, load_type = ((vtop->type.t & 0x000f) == 13) ? 4 : 9; + + + + + vtop[-1].type.t = load_type; + store(r, vtop - 1); + vswap(); + + vtop->type.t = addr_type; + gaddrof(); + vpushi(load_size); + gen_op('+'); + vtop->r |= 0x0100; + vswap(); + vtop[-1].type.t = load_type; + + store(vtop->r2, vtop - 1); + } else { + store(r, vtop - 1); + } + + vswap(); + vtop--; + vtop->r |= delayed_cast; + } +} + + +static void inc(int post, int c) +{ + test_lvalue(); + vdup(); + if (post) { + gv_dup(); + vrotb(3); + vrotb(3); + } + + vpushi(c - 0xa3); + gen_op('+'); + vstore(); + if (post) + vpop(); +} + +static void parse_mult_str (CString *astr, const char *msg) +{ + + if (tok != 0xb9) + expect(msg); + cstr_new(astr); + while (tok == 0xb9) { + + cstr_cat(astr, tokc.str.data, -1); + next(); + } + cstr_ccat(astr, '\0'); +} + + + +static int exact_log2p1(int i) +{ + int ret; + if (!i) + return 0; + for (ret = 1; i >= 1 << 8; ret += 8) + i >>= 8; + if (i >= 1 << 4) + ret += 4, i >>= 4; + if (i >= 1 << 2) + ret += 2, i >>= 2; + if (i >= 1 << 1) + ret++; + return ret; +} + + +static void parse_attribute(AttributeDef *ad) +{ + int t, n; + CString astr; + +redo: + if (tok != TOK_ATTRIBUTE1 && tok != TOK_ATTRIBUTE2) + return; + next(); + skip('('); + skip('('); + while (tok != ')') { + if (tok < 256) + expect("attribute name"); + t = tok; + next(); + switch(t) { + case TOK_SECTION1: + case TOK_SECTION2: + skip('('); + parse_mult_str(&astr, "section name"); + ad->section = find_section(tcc_state, (char *)astr.data); + skip(')'); + cstr_free(&astr); + break; + case TOK_ALIAS1: + case TOK_ALIAS2: + skip('('); + parse_mult_str(&astr, "alias(\"target\")"); + ad->alias_target = + tok_alloc((char*)astr.data, astr.size-1)->tok; + skip(')'); + cstr_free(&astr); + break; + case TOK_VISIBILITY1: + case TOK_VISIBILITY2: + skip('('); + parse_mult_str(&astr, + "visibility(\"default|hidden|internal|protected\")"); + if (!strcmp (astr.data, "default")) + ad->a.visibility = 0; + else if (!strcmp (astr.data, "hidden")) + ad->a.visibility = 2; + else if (!strcmp (astr.data, "internal")) + ad->a.visibility = 1; + else if (!strcmp (astr.data, "protected")) + ad->a.visibility = 3; + else + expect("visibility(\"default|hidden|internal|protected\")"); + skip(')'); + cstr_free(&astr); + break; + case TOK_ALIGNED1: + case TOK_ALIGNED2: + if (tok == '(') { + next(); + n = expr_const(); + if (n <= 0 || (n & (n - 1)) != 0) + tcc_error("alignment must be a positive power of two"); + skip(')'); + } else { + n = 16; + } + ad->a.aligned = exact_log2p1(n); + if (n != 1 << (ad->a.aligned - 1)) + tcc_error("alignment of %d is larger than implemented", n); + break; + case TOK_PACKED1: + case TOK_PACKED2: + ad->a.packed = 1; + break; + case TOK_WEAK1: + case TOK_WEAK2: + ad->a.weak = 1; + break; + case TOK_UNUSED1: + case TOK_UNUSED2: + + + break; + case TOK_NORETURN1: + case TOK_NORETURN2: + + + break; + case TOK_CDECL1: + case TOK_CDECL2: + case TOK_CDECL3: + ad->f.func_call = 0; + break; + case TOK_STDCALL1: + case TOK_STDCALL2: + case TOK_STDCALL3: + ad->f.func_call = 1; + break; +# 3405 "tccgen.c" + case TOK_MODE: + skip('('); + switch(tok) { + case TOK_MODE_DI: + ad->attr_mode = 4 + 1; + break; + case TOK_MODE_QI: + ad->attr_mode = 1 + 1; + break; + case TOK_MODE_HI: + ad->attr_mode = 2 + 1; + break; + case TOK_MODE_SI: + case TOK_MODE_word: + ad->attr_mode = 3 + 1; + break; + default: + tcc_warning("__mode__(%s) not supported\n", get_tok_str(tok, 0)); + break; + } + next(); + skip(')'); + break; + case TOK_DLLEXPORT: + ad->a.dllexport = 1; + break; + case TOK_DLLIMPORT: + ad->a.dllimport = 1; + break; + default: + if (tcc_state->warn_unsupported) + tcc_warning("'%s' attribute ignored", get_tok_str(t, 0)); + + if (tok == '(') { + int parenthesis = 0; + do { + if (tok == '(') + parenthesis++; + else if (tok == ')') + parenthesis--; + next(); + } while (parenthesis && tok != -1); + } + break; + } + if (tok != ',') + break; + next(); + } + skip(')'); + skip(')'); + goto redo; +} + +static Sym * find_field (CType *type, int v) +{ + Sym *s = type->ref; + v |= 0x20000000; + while ((s = s->next) != 0) { + if ((s->v & 0x20000000) && + (s->type.t & 0x000f) == 7 && + (s->v & ~0x20000000) >= 0x10000000) { + Sym *ret = find_field (&s->type, v); + if (ret) + return ret; + } + if (s->v == v) + break; + } + return s; +} + +static void struct_add_offset (Sym *s, int offset) +{ + while ((s = s->next) != 0) { + if ((s->v & 0x20000000) && + (s->type.t & 0x000f) == 7 && + (s->v & ~0x20000000) >= 0x10000000) { + struct_add_offset(s->type.ref, offset); + } else + s->c += offset; + } +} + +static void struct_layout(CType *type, AttributeDef *ad) +{ + int size, align, maxalign, offset, c, bit_pos, bit_size; + int packed, a, bt, prevbt, prev_bit_size; + int pcc = !tcc_state->ms_bitfields; + int pragma_pack = *tcc_state->pack_stack_ptr; + Sym *f; + + maxalign = 1; + offset = 0; + c = 0; + bit_pos = 0; + prevbt = 7; + prev_bit_size = 0; + + + + for (f = type->ref->next; f; f = f->next) { + if (f->type.t & 0x0080) + bit_size = (((f->type.t) >> (20 + 6)) & 0x3f); + else + bit_size = -1; + size = type_size(&f->type, &align); + a = f->a.aligned ? 1 << (f->a.aligned - 1) : 0; + packed = 0; + + if (pcc && bit_size == 0) { + + + } else { + + if (pcc && (f->a.packed || ad->a.packed)) + align = packed = 1; + + + if (pragma_pack) { + packed = 1; + if (pragma_pack < align) + align = pragma_pack; + + if (pcc && pragma_pack < a) + a = 0; + } + } + + if (a) + align = a; + + if (type->ref->type.t == (1 << 20 | 7)) { + if (pcc && bit_size >= 0) + size = (bit_size + 7) >> 3; + offset = 0; + if (size > c) + c = size; + + } else if (bit_size < 0) { + if (pcc) + c += (bit_pos + 7) >> 3; + c = (c + align - 1) & -align; + offset = c; + if (size > 0) + c += size; + bit_pos = 0; + prevbt = 7; + prev_bit_size = 0; + + } else { + + + if (pcc) { + + + + + + + if (bit_size == 0) { + new_field: + c = (c + ((bit_pos + 7) >> 3) + align - 1) & -align; + bit_pos = 0; + } else if (f->a.aligned) { + goto new_field; + } else if (!packed) { + int a8 = align * 8; + int ofs = ((c * 8 + bit_pos) % a8 + bit_size + a8 - 1) / a8; + if (ofs > size / align) + goto new_field; + } + + + if (size == 8 && bit_size <= 32) + f->type.t = (f->type.t & ~0x000f) | 3, size = 4; + + while (bit_pos >= align * 8) + c += align, bit_pos -= align * 8; + offset = c; + + + + + if (f->v & 0x10000000 + + ) + align = 1; + + } else { + bt = f->type.t & 0x000f; + if ((bit_pos + bit_size > size * 8) + || (bit_size > 0) == (bt != prevbt) + ) { + c = (c + align - 1) & -align; + offset = c; + bit_pos = 0; + + + + + if (bit_size || prev_bit_size) + c += size; + } + + + + + if (bit_size == 0 && prevbt != bt) + align = 1; + prevbt = bt; + prev_bit_size = bit_size; + } + + f->type.t = (f->type.t & ~(0x3f << 20)) + | (bit_pos << 20); + bit_pos += bit_size; + } + if (align > maxalign) + maxalign = align; +# 3638 "tccgen.c" + if (f->v & 0x10000000 && (f->type.t & 0x000f) == 7) { + Sym *ass; + + + + + + + + int v2 = f->type.ref->v; + if (!(v2 & 0x20000000) && + (v2 & ~0x40000000) < 0x10000000) { + Sym **pps; + + + + + + ass = f->type.ref; + f->type.ref = sym_push(anon_sym++ | 0x20000000, + &f->type.ref->type, 0, + f->type.ref->c); + pps = &f->type.ref->next; + while ((ass = ass->next) != 0) { + *pps = sym_push(ass->v, &ass->type, 0, ass->c); + pps = &((*pps)->next); + } + *pps = 0; + } + struct_add_offset(f->type.ref, offset); + f->c = 0; + } else { + f->c = offset; + } + + f->r = 0; + } + + if (pcc) + c += (bit_pos + 7) >> 3; + + + a = bt = ad->a.aligned ? 1 << (ad->a.aligned - 1) : 1; + if (a < maxalign) + a = maxalign; + type->ref->r = a; + if (pragma_pack && pragma_pack < maxalign && 0 == pcc) { + + + a = pragma_pack; + if (a < bt) + a = bt; + } + c = (c + a - 1) & -a; + type->ref->c = c; + + + + + + + for (f = type->ref->next; f; f = f->next) { + int s, px, cx, c0; + CType t; + + if (0 == (f->type.t & 0x0080)) + continue; + f->type.ref = f; + f->auxtype = -1; + bit_size = (((f->type.t) >> (20 + 6)) & 0x3f); + if (bit_size == 0) + continue; + bit_pos = (((f->type.t) >> 20) & 0x3f); + size = type_size(&f->type, &align); + if (bit_pos + bit_size <= size * 8 && f->c + size <= c) + continue; + + + c0 = -1, s = align = 1; + for (;;) { + px = f->c * 8 + bit_pos; + cx = (px >> 3) & -align; + px = px - (cx << 3); + if (c0 == cx) + break; + s = (px + bit_size + 7) >> 3; + if (s > 4) { + t.t = 4; + } else if (s > 2) { + t.t = 3; + } else if (s > 1) { + t.t = 2; + } else { + t.t = 1; + } + s = type_size(&t, &align); + c0 = cx; + } + + if (px + bit_size <= s * 8 && cx + s <= c) { + + f->c = cx; + bit_pos = px; + f->type.t = (f->type.t & ~(0x3f << 20)) + | (bit_pos << 20); + if (s != size) + f->auxtype = t.t; + + + + + + + } else { + + f->auxtype = 7; + + + + + } + } +} + + +static void struct_decl(CType *type, int u) +{ + int v, c, size, align, flexible; + int bit_size, bsize, bt; + Sym *s, *ss, **ps; + AttributeDef ad, ad1; + CType type1, btype; + + memset(&ad, 0, sizeof ad); + next(); + parse_attribute(&ad); + if (tok != '{') { + v = tok; + next(); + + if (v < 256) + expect("struct/union/enum name"); + s = struct_find(v); + if (s && (s->sym_scope == local_scope || tok != '{')) { + if (u == s->type.t) + goto do_decl; + if (u == (2 << 20) && ((s->type.t & (((1 << (6+6)) - 1) << 20 | 0x0080)) == (2 << 20))) + goto do_decl; + tcc_error("redefinition of '%s'", get_tok_str(v, 0)); + } + } else { + v = anon_sym++; + } + + type1.t = u == (2 << 20) ? u | 3 | 0x0010 : u; + type1.ref = 0; + + s = sym_push(v | 0x40000000, &type1, 0, -1); + s->r = 0; +do_decl: + type->t = s->type.t; + type->ref = s; + + if (tok == '{') { + next(); + if (s->c != -1) + tcc_error("struct/union/enum already defined"); + + + ps = &s->next; + if (u == (2 << 20)) { + long long ll = 0, pl = 0, nl = 0; + CType t; + t.ref = s; + + t.t = 3|0x00002000|(3 << 20); + for(;;) { + v = tok; + if (v < TOK_DEFINE) + expect("identifier"); + ss = sym_find(v); + if (ss && !local_stack) + tcc_error("redefinition of enumerator '%s'", + get_tok_str(v, 0)); + next(); + if (tok == '=') { + next(); + ll = expr_const64(); + } + ss = sym_push(v, &t, 0x0030, 0); + ss->enum_val = ll; + *ps = ss, ps = &ss->next; + if (ll < nl) + nl = ll; + if (ll > pl) + pl = ll; + if (tok != ',') + break; + next(); + ll++; + + if (tok == '}') + break; + } + skip('}'); + + t.t = 3; + if (nl >= 0) { + if (pl != (unsigned)pl) + t.t = (8==8 ? 4|0x0800 : 4); + t.t |= 0x0010; + } else if (pl != (int)pl || nl != (int)nl) + t.t = (8==8 ? 4|0x0800 : 4); + s->type.t = type->t = t.t | (2 << 20); + s->c = 0; + + for (ss = s->next; ss; ss = ss->next) { + ll = ss->enum_val; + if (ll == (int)ll) + continue; + if (t.t & 0x0010) { + ss->type.t |= 0x0010; + if (ll == (unsigned)ll) + continue; + } + ss->type.t = (ss->type.t & ~0x000f) + | (8==8 ? 4|0x0800 : 4); + } + } else { + c = 0; + flexible = 0; + while (tok != '}') { + if (!parse_btype(&btype, &ad1)) { + skip(';'); + continue; + } + while (1) { + if (flexible) + tcc_error("flexible array member '%s' not at the end of struct", + get_tok_str(v, 0)); + bit_size = -1; + v = 0; + type1 = btype; + if (tok != ':') { + if (tok != ';') + type_decl(&type1, &ad1, &v, 2); + if (v == 0) { + if ((type1.t & 0x000f) != 7) + expect("identifier"); + else { + int v = btype.ref->v; + if (!(v & 0x20000000) && (v & ~0x40000000) < 0x10000000) { + if (tcc_state->ms_extensions == 0) + expect("identifier"); + } + } + } + if (type_size(&type1, &align) < 0) { + if ((u == 7) && (type1.t & 0x0040) && c) + flexible = 1; + else + tcc_error("field '%s' has incomplete type", + get_tok_str(v, 0)); + } + if ((type1.t & 0x000f) == 6 || + (type1.t & (0x00001000 | 0x00002000 | 0x00004000 | 0x00008000))) + tcc_error("invalid type for '%s'", + get_tok_str(v, 0)); + } + if (tok == ':') { + next(); + bit_size = expr_const(); + + if (bit_size < 0) + tcc_error("negative width in bit-field '%s'", + get_tok_str(v, 0)); + if (v && bit_size == 0) + tcc_error("zero width for bit-field '%s'", + get_tok_str(v, 0)); + parse_attribute(&ad1); + } + size = type_size(&type1, &align); + if (bit_size >= 0) { + bt = type1.t & 0x000f; + if (bt != 3 && + bt != 1 && + bt != 2 && + bt != 11 && + bt != 4) + tcc_error("bitfields must have scalar type"); + bsize = size * 8; + if (bit_size > bsize) { + tcc_error("width of '%s' exceeds its type", + get_tok_str(v, 0)); + } else if (bit_size == bsize + && !ad.a.packed && !ad1.a.packed) { + + ; + } else if (bit_size == 64) { + tcc_error("field width 64 not implemented"); + } else { + type1.t = (type1.t & ~(((1 << (6+6)) - 1) << 20 | 0x0080)) + | 0x0080 + | (bit_size << (20 + 6)); + } + } + if (v != 0 || (type1.t & 0x000f) == 7) { + + + c = 1; + } + + + if (v == 0 && + ((type1.t & 0x000f) == 7 || + bit_size >= 0)) { + v = anon_sym++; + } + if (v) { + ss = sym_push(v | 0x20000000, &type1, 0, 0); + ss->a = ad1.a; + *ps = ss; + ps = &ss->next; + } + if (tok == ';' || tok == (-1)) + break; + skip(','); + } + skip(';'); + } + skip('}'); + parse_attribute(&ad); + struct_layout(type, &ad); + } + } +} + +static void sym_to_attr(AttributeDef *ad, Sym *s) +{ + if (s->a.aligned && 0 == ad->a.aligned) + ad->a.aligned = s->a.aligned; + if (s->f.func_call && 0 == ad->f.func_call) + ad->f.func_call = s->f.func_call; + if (s->f.func_type && 0 == ad->f.func_type) + ad->f.func_type = s->f.func_type; + if (s->a.packed) + ad->a.packed = 1; +} + + + +static void parse_btype_qualify(CType *type, int qualifiers) +{ + while (type->t & 0x0040) { + type->ref = sym_push(0x20000000, &type->ref->type, 0, type->ref->c); + type = &type->ref->type; + } + type->t |= qualifiers; +} + + + + +static int parse_btype(CType *type, AttributeDef *ad) +{ + int t, u, bt, st, type_found, typespec_found, g; + Sym *s; + CType type1; + + memset(ad, 0, sizeof(AttributeDef)); + type_found = 0; + typespec_found = 0; + t = 3; + bt = st = -1; + type->ref = 0; + + while(1) { + switch(tok) { + case TOK_EXTENSION: + + next(); + continue; + + + case TOK_CHAR: + u = 1; + basic_type: + next(); + basic_type1: + if (u == 2 || u == 0x0800) { + if (st != -1 || (bt != -1 && bt != 3)) + tmbt: tcc_error("too many basic types"); + st = u; + } else { + if (bt != -1 || (st != -1 && u != 3)) + goto tmbt; + bt = u; + } + if (u != 3) + t = (t & ~(0x000f|0x0800)) | u; + typespec_found = 1; + break; + case TOK_VOID: + u = 0; + goto basic_type; + case TOK_SHORT: + u = 2; + goto basic_type; + case TOK_INT: + u = 3; + goto basic_type; + case TOK_LONG: + if ((t & 0x000f) == 9) { + t = (t & ~(0x000f|0x0800)) | 10; + } else if ((t & (0x000f|0x0800)) == 0x0800) { + t = (t & ~(0x000f|0x0800)) | 4; + } else { + u = 0x0800; + goto basic_type; + } + next(); + break; + + + + + + + + case TOK_BOOL: + u = 11; + goto basic_type; + case TOK_FLOAT: + u = 8; + goto basic_type; + case TOK_DOUBLE: + if ((t & (0x000f|0x0800)) == 0x0800) { + t = (t & ~(0x000f|0x0800)) | 10; + } else { + u = 9; + goto basic_type; + } + next(); + break; + case TOK_ENUM: + struct_decl(&type1, (2 << 20)); + basic_type2: + u = type1.t; + type->ref = type1.ref; + goto basic_type1; + case TOK_STRUCT: + struct_decl(&type1, 7); + goto basic_type2; + case TOK_UNION: + struct_decl(&type1, (1 << 20 | 7)); + goto basic_type2; + + + case TOK_CONST1: + case TOK_CONST2: + case TOK_CONST3: + type->t = t; + parse_btype_qualify(type, 0x0100); + t = type->t; + next(); + break; + case TOK_VOLATILE1: + case TOK_VOLATILE2: + case TOK_VOLATILE3: + type->t = t; + parse_btype_qualify(type, 0x0200); + t = type->t; + next(); + break; + case TOK_SIGNED1: + case TOK_SIGNED2: + case TOK_SIGNED3: + if ((t & (0x0020|0x0010)) == (0x0020|0x0010)) + tcc_error("signed and unsigned modifier"); + t |= 0x0020; + next(); + typespec_found = 1; + break; + case TOK_REGISTER: + case TOK_AUTO: + case TOK_RESTRICT1: + case TOK_RESTRICT2: + case TOK_RESTRICT3: + next(); + break; + case TOK_UNSIGNED: + if ((t & (0x0020|0x0010)) == 0x0020) + tcc_error("signed and unsigned modifier"); + t |= 0x0020 | 0x0010; + next(); + typespec_found = 1; + break; + + + case TOK_EXTERN: + g = 0x00001000; + goto storage; + case TOK_STATIC: + g = 0x00002000; + goto storage; + case TOK_TYPEDEF: + g = 0x00004000; + goto storage; + storage: + if (t & (0x00001000|0x00002000|0x00004000) & ~g) + tcc_error("multiple storage classes"); + t |= g; + next(); + break; + case TOK_INLINE1: + case TOK_INLINE2: + case TOK_INLINE3: + t |= 0x00008000; + next(); + break; + + + case TOK_ATTRIBUTE1: + case TOK_ATTRIBUTE2: + parse_attribute(ad); + if (ad->attr_mode) { + u = ad->attr_mode -1; + t = (t & ~(0x000f|0x0800)) | u; + } + break; + + case TOK_TYPEOF1: + case TOK_TYPEOF2: + case TOK_TYPEOF3: + next(); + parse_expr_type(&type1); + + type1.t &= ~((0x00001000 | 0x00002000 | 0x00004000 | 0x00008000)&~0x00004000); + if (type1.ref) + sym_to_attr(ad, type1.ref); + goto basic_type2; + default: + if (typespec_found) + goto the_end; + s = sym_find(tok); + if (!s || !(s->type.t & 0x00004000)) + goto the_end; + t &= ~(0x000f|0x0800); + u = t & ~(0x0100 | 0x0200), t ^= u; + type->t = (s->type.t & ~0x00004000) | u; + type->ref = s->type.ref; + if (t) + parse_btype_qualify(type, t); + t = type->t; + + sym_to_attr(ad, s); + next(); + typespec_found = 1; + st = bt = -2; + break; + } + type_found = 1; + } +the_end: + if (tcc_state->char_is_unsigned) { + if ((t & (0x0020|0x000f)) == 1) + t |= 0x0010; + } + + bt = t & (0x000f|0x0800); + if (bt == 0x0800) + t |= 8 == 8 ? 4 : 3; + + + + + type->t = t; + return type_found; +} + + + +static inline void convert_parameter_type(CType *pt) +{ + + + pt->t &= ~(0x0100 | 0x0200); + + pt->t &= ~0x0040; + if ((pt->t & 0x000f) == 6) { + mk_pointer(pt); + } +} + +static void parse_asm_str(CString *astr) +{ + skip('('); + parse_mult_str(astr, "string constant"); +} + + +static int asm_label_instr(void) +{ + int v; + CString astr; + + next(); + parse_asm_str(&astr); + skip(')'); + + + + v = tok_alloc(astr.data, astr.size - 1)->tok; + cstr_free(&astr); + return v; +} + +static int post_type(CType *type, AttributeDef *ad, int storage, int td) +{ + int n, l, t1, arg_size, align; + Sym **plast, *s, *first; + AttributeDef ad1; + CType pt; + + if (tok == '(') { + + next(); + if (td && !(td & 1)) + return 0; + if (tok == ')') + l = 0; + else if (parse_btype(&pt, &ad1)) + l = 1; + else if (td) + return 0; + else + l = 2; + first = 0; + plast = &first; + arg_size = 0; + if (l) { + for(;;) { + + if (l != 2) { + if ((pt.t & 0x000f) == 0 && tok == ')') + break; + type_decl(&pt, &ad1, &n, 2 | 1); + if ((pt.t & 0x000f) == 0) + tcc_error("parameter declared as void"); + arg_size += (type_size(&pt, &align) + 8 - 1) / 8; + } else { + n = tok; + if (n < TOK_DEFINE) + expect("identifier"); + pt.t = 0; + next(); + } + convert_parameter_type(&pt); + s = sym_push(n | 0x20000000, &pt, 0, 0); + *plast = s; + plast = &s->next; + if (tok == ')') + break; + skip(','); + if (l == 1 && tok == 0xc8) { + l = 3; + next(); + break; + } + if (l == 1 && !parse_btype(&pt, &ad1)) + tcc_error("invalid type"); + } + } else + + l = 2; + skip(')'); + + + type->t &= ~0x0100; + + + + if (tok == '[') { + next(); + skip(']'); + mk_pointer(type); + } + + ad->f.func_args = arg_size; + ad->f.func_type = l; + s = sym_push(0x20000000, type, 0, 0); + s->a = ad->a; + s->f = ad->f; + s->next = first; + type->t = 6; + type->ref = s; + } else if (tok == '[') { + int saved_nocode_wanted = nocode_wanted; + + next(); + if (tok == TOK_RESTRICT1) + next(); + n = -1; + t1 = 0; + if (tok != ']') { + if (!local_stack || (storage & 0x00002000)) + vpushi(expr_const()); + else { + + + + + nocode_wanted = 0; + gexpr(); + } + if ((vtop->r & (0x003f | 0x0100 | 0x0200)) == 0x0030) { + n = vtop->c.i; + if (n < 0) + tcc_error("invalid array size"); + } else { + if (!is_integer_btype(vtop->type.t & 0x000f)) + tcc_error("size of variable length array should be an integer"); + t1 = 0x0400; + } + } + skip(']'); + + post_type(type, ad, storage, 0); + if (type->t == 6) + tcc_error("declaration of an array of functions"); + t1 |= type->t & 0x0400; + + if (t1 & 0x0400) { + loc -= type_size(&int_type, &align); + loc &= -align; + n = loc; + + vla_runtime_type_size(type, &align); + gen_op('*'); + vset(&int_type, 0x0032|0x0100, n); + vswap(); + vstore(); + } + if (n != -1) + vpop(); + nocode_wanted = saved_nocode_wanted; + + + + s = sym_push(0x20000000, type, 0, n); + type->t = (t1 ? 0x0400 : 0x0040) | 5; + type->ref = s; + } + return 1; +} +# 4401 "tccgen.c" +static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td) +{ + CType *post, *ret; + int qualifiers, storage; + + + storage = type->t & (0x00001000 | 0x00002000 | 0x00004000 | 0x00008000); + type->t &= ~(0x00001000 | 0x00002000 | 0x00004000 | 0x00008000); + post = ret = type; + + while (tok == '*') { + qualifiers = 0; + redo: + next(); + switch(tok) { + case TOK_CONST1: + case TOK_CONST2: + case TOK_CONST3: + qualifiers |= 0x0100; + goto redo; + case TOK_VOLATILE1: + case TOK_VOLATILE2: + case TOK_VOLATILE3: + qualifiers |= 0x0200; + goto redo; + case TOK_RESTRICT1: + case TOK_RESTRICT2: + case TOK_RESTRICT3: + goto redo; + + case TOK_ATTRIBUTE1: + case TOK_ATTRIBUTE2: + parse_attribute(ad); + break; + } + mk_pointer(type); + type->t |= qualifiers; + if (ret == type) + + ret = pointed_type(type); + } + + if (tok == '(') { + + + if (!post_type(type, ad, 0, td)) { + + + + + parse_attribute(ad); + post = type_decl(type, ad, v, td); + skip(')'); + } + } else if (tok >= 256 && (td & 2)) { + + *v = tok; + next(); + } else { + if (!(td & 1)) + expect("identifier"); + *v = 0; + } + post_type(post, ad, storage, 0); + parse_attribute(ad); + type->t |= storage; + return ret; +} + + +static int lvalue_type(int t) +{ + int bt, r; + r = 0x0100; + bt = t & 0x000f; + if (bt == 1 || bt == 11) + r |= 0x1000; + else if (bt == 2) + r |= 0x2000; + else + return r; + if (t & 0x0010) + r |= 0x4000; + return r; +} + + +static void indir(void) +{ + if ((vtop->type.t & 0x000f) != 5) { + if ((vtop->type.t & 0x000f) == 6) + return; + expect("pointer"); + } + if (vtop->r & 0x0100) + gv(0x0001); + vtop->type = *pointed_type(&vtop->type); + + if (!(vtop->type.t & 0x0040) && !(vtop->type.t & 0x0400) + && (vtop->type.t & 0x000f) != 6) { + vtop->r |= lvalue_type(vtop->type.t); + + + if (tcc_state->do_bounds_check) + vtop->r |= 0x0800; + + } +} + + +static void gfunc_param_typed(Sym *func, Sym *arg) +{ + int func_type; + CType type; + + func_type = func->f.func_type; + if (func_type == 2 || + (func_type == 3 && arg == 0)) { + + if ((vtop->type.t & 0x000f) == 8) { + gen_cast_s(9); + } else if (vtop->type.t & 0x0080) { + type.t = vtop->type.t & (0x000f | 0x0010); + type.ref = vtop->type.ref; + gen_cast(&type); + } + } else if (arg == 0) { + tcc_error("too many arguments to function"); + } else { + type = arg->type; + type.t &= ~0x0100; + gen_assign_cast(&type); + } +} + + +static void expr_type(CType *type, void (*expr_fn)(void)) +{ + nocode_wanted++; + expr_fn(); + *type = vtop->type; + vpop(); + nocode_wanted--; +} + + + +static void parse_expr_type(CType *type) +{ + int n; + AttributeDef ad; + + skip('('); + if (parse_btype(type, &ad)) { + type_decl(type, &ad, &n, 1); + } else { + expr_type(type, gexpr); + } + skip(')'); +} + +static void parse_type(CType *type) +{ + AttributeDef ad; + int n; + + if (!parse_btype(type, &ad)) { + expect("type"); + } + type_decl(type, &ad, &n, 1); +} + +static void parse_builtin_params(int nc, const char *args) +{ + char c, sep = '('; + CType t; + if (nc) + nocode_wanted++; + next(); + while ((c = *args++)) { + skip(sep); + sep = ','; + switch (c) { + case 'e': expr_eq(); continue; + case 't': parse_type(&t); vpush(&t); continue; + default: tcc_error("internal error"); break; + } + } + skip(')'); + if (nc) + nocode_wanted--; +} + +static void unary(void) +{ + int n, t, align, size, r, sizeof_caller; + CType type; + Sym *s; + AttributeDef ad; + + sizeof_caller = in_sizeof; + in_sizeof = 0; + type.ref = 0; + + + tok_next: + switch(tok) { + case TOK_EXTENSION: + next(); + goto tok_next; + case 0xb4: + + + + + case 0xb5: + case 0xb3: + t = 3; + push_tokc: + type.t = t; + vsetc(&type, 0x0030, &tokc); + next(); + break; + case 0xb6: + t = 3 | 0x0010; + goto push_tokc; + case 0xb7: + t = 4; + goto push_tokc; + case 0xb8: + t = 4 | 0x0010; + goto push_tokc; + case 0xbb: + t = 8; + goto push_tokc; + case 0xbc: + t = 9; + goto push_tokc; + case 0xbd: + t = 10; + goto push_tokc; + case 0xce: + t = (8 == 8 ? 4 : 3) | 0x0800; + goto push_tokc; + case 0xcf: + t = (8 == 8 ? 4 : 3) | 0x0800 | 0x0010; + goto push_tokc; + case TOK___FUNCTION__: + if (!gnu_ext) + goto tok_identifier; + + case TOK___FUNC__: + { + void *ptr; + int len; + + len = strlen(funcname) + 1; + + type.t = 1; + mk_pointer(&type); + type.t |= 0x0040; + type.ref->c = len; + vpush_ref(&type, data_section, data_section->data_offset, len); + if (!(nocode_wanted > 0)) { + ptr = section_ptr_add(data_section, len); + memcpy(ptr, funcname, len); + } + next(); + } + break; + case 0xba: + + + + t = 3; + + goto str_init; + case 0xb9: + + t = 1; + if (tcc_state->char_is_unsigned) + t = 1 | 0x0010; + str_init: + if (tcc_state->warn_write_strings) + t |= 0x0100; + type.t = t; + mk_pointer(&type); + type.t |= 0x0040; + memset(&ad, 0, sizeof(AttributeDef)); + decl_initializer_alloc(&type, &ad, 0x0030, 2, 0, 0); + break; + case '(': + next(); + + if (parse_btype(&type, &ad)) { + type_decl(&type, &ad, &n, 1); + skip(')'); + + if (tok == '{') { + + if (global_expr) + r = 0x0030; + else + r = 0x0032; + + if (!(type.t & 0x0040)) + r |= lvalue_type(type.t); + memset(&ad, 0, sizeof(AttributeDef)); + decl_initializer_alloc(&type, &ad, r, 1, 0, 0); + } else { + if (sizeof_caller) { + vpush(&type); + return; + } + unary(); + gen_cast(&type); + } + } else if (tok == '{') { + int saved_nocode_wanted = nocode_wanted; + if (const_wanted) + tcc_error("expected constant"); + + save_regs(0); + + + + + + block(0, 0, 1); + nocode_wanted = saved_nocode_wanted; + skip(')'); + } else { + gexpr(); + skip(')'); + } + break; + case '*': + next(); + unary(); + indir(); + break; + case '&': + next(); + unary(); + + + + + + if ((vtop->type.t & 0x000f) != 6 && + !(vtop->type.t & 0x0040)) + test_lvalue(); + mk_pointer(&vtop->type); + gaddrof(); + break; + case '!': + next(); + unary(); + if ((vtop->r & (0x003f | 0x0100 | 0x0200)) == 0x0030) { + gen_cast_s(11); + vtop->c.i = !vtop->c.i; + } else if ((vtop->r & 0x003f) == 0x0033) + vtop->c.i ^= 1; + else { + save_regs(1); + vseti(0x0034, gvtst(1, 0)); + } + break; + case '~': + next(); + unary(); + vpushi(-1); + gen_op('^'); + break; + case '+': + next(); + unary(); + if ((vtop->type.t & 0x000f) == 5) + tcc_error("pointer not accepted for unary plus"); + + + + if (!is_float(vtop->type.t)) { + vpushi(0); + gen_op('+'); + } + break; + case TOK_SIZEOF: + case TOK_ALIGNOF1: + case TOK_ALIGNOF2: + t = tok; + next(); + in_sizeof++; + expr_type(&type, unary); + s = vtop[1].sym; + size = type_size(&type, &align); + if (s && s->a.aligned) + align = 1 << (s->a.aligned - 1); + if (t == TOK_SIZEOF) { + if (!(type.t & 0x0400)) { + if (size < 0) + tcc_error("sizeof applied to an incomplete type"); + vpushs(size); + } else { + vla_runtime_type_size(&type, &align); + } + } else { + vpushs(align); + } + vtop->type.t |= 0x0010; + break; + + case TOK_builtin_expect: + + parse_builtin_params(0, "ee"); + vpop(); + break; + case TOK_builtin_types_compatible_p: + parse_builtin_params(0, "tt"); + vtop[-1].type.t &= ~(0x0100 | 0x0200); + vtop[0].type.t &= ~(0x0100 | 0x0200); + n = is_compatible_types(&vtop[-1].type, &vtop[0].type); + vtop -= 2; + vpushi(n); + break; + case TOK_builtin_choose_expr: + { + int64_t c; + next(); + skip('('); + c = expr_const64(); + skip(','); + if (!c) { + nocode_wanted++; + } + expr_eq(); + if (!c) { + vpop(); + nocode_wanted--; + } + skip(','); + if (c) { + nocode_wanted++; + } + expr_eq(); + if (c) { + vpop(); + nocode_wanted--; + } + skip(')'); + } + break; + case TOK_builtin_constant_p: + parse_builtin_params(1, "e"); + n = (vtop->r & (0x003f | 0x0100 | 0x0200)) == 0x0030; + vtop--; + vpushi(n); + break; + case TOK_builtin_frame_address: + case TOK_builtin_return_address: + { + int tok1 = tok; + int level; + next(); + skip('('); + if (tok != 0xb5) { + tcc_error("%s only takes positive integers", + tok1 == TOK_builtin_return_address ? + "__builtin_return_address" : + "__builtin_frame_address"); + } + level = (uint32_t)tokc.i; + next(); + skip(')'); + type.t = 0; + mk_pointer(&type); + vset(&type, 0x0032, 0); + while (level--) { + mk_pointer(&vtop->type); + indir(); + } + if (tok1 == TOK_builtin_return_address) { + + vpushi(8); + gen_op('+'); + mk_pointer(&vtop->type); + indir(); + } + } + break; +# 4906 "tccgen.c" + case TOK_builtin_va_arg_types: + parse_builtin_params(0, "t"); + vpushi(classify_x86_64_va_arg(&vtop->type)); + vswap(); + vpop(); + break; +# 4942 "tccgen.c" + case 0xa4: + case 0xa2: + t = tok; + next(); + unary(); + inc(0, t); + break; + case '-': + next(); + unary(); + t = vtop->type.t & 0x000f; + if (is_float(t)) { + + + vpush(&vtop->type); + if (t == 8) + vtop->c.f = -1.0 * 0.0; + else if (t == 9) + vtop->c.d = -1.0 * 0.0; + else + vtop->c.ld = -1.0 * 0.0; + } else + vpushi(0); + vswap(); + gen_op('-'); + break; + case 0xa0: + if (!gnu_ext) + goto tok_identifier; + next(); + + if (tok < TOK_DEFINE) + expect("label identifier"); + s = label_find(tok); + if (!s) { + s = label_push(&global_label_stack, tok, 1); + } else { + if (s->r == 2) + s->r = 1; + } + if (!s->type.t) { + s->type.t = 0; + mk_pointer(&s->type); + s->type.t |= 0x00002000; + } + vpushsym(&s->type, s); + next(); + break; + + case TOK_GENERIC: + { + CType controlling_type; + int has_default = 0; + int has_match = 0; + int learn = 0; + TokenString *str = 0; + + next(); + skip('('); + expr_type(&controlling_type, expr_eq); + controlling_type.t &= ~(0x0100 | 0x0200 | 0x0040); + for (;;) { + learn = 0; + skip(','); + if (tok == TOK_DEFAULT) { + if (has_default) + tcc_error("too many 'default'"); + has_default = 1; + if (!has_match) + learn = 1; + next(); + } else { + AttributeDef ad_tmp; + int itmp; + CType cur_type; + parse_btype(&cur_type, &ad_tmp); + type_decl(&cur_type, &ad_tmp, &itmp, 1); + if (compare_types(&controlling_type, &cur_type, 0)) { + if (has_match) { + tcc_error("type match twice"); + } + has_match = 1; + learn = 1; + } + } + skip(':'); + if (learn) { + if (str) + tok_str_free(str); + skip_or_save_block(&str); + } else { + skip_or_save_block(0); + } + if (tok == ')') + break; + } + if (!str) { + char buf[60]; + type_to_str(buf, sizeof buf, &controlling_type, 0); + tcc_error("type '%s' does not match any association", buf); + } + begin_macro(str, 1); + next(); + expr_eq(); + if (tok != (-1)) + expect(","); + end_macro(); + next(); + break; + } + + case TOK___NAN__: + vpush64(9, 0x7ff8000000000000ULL); + next(); + break; + case TOK___SNAN__: + vpush64(9, 0x7ff0000000000001ULL); + next(); + break; + case TOK___INF__: + vpush64(9, 0x7ff0000000000000ULL); + next(); + break; + + default: + tok_identifier: + t = tok; + next(); + if (t < TOK_DEFINE) + expect("identifier"); + s = sym_find(t); + if (!s || (((s)->type.t & (0x000f | (0 | 0x0010))) == (0 | 0x0010))) { + const char *name = get_tok_str(t, 0); + if (tok != '(') + tcc_error("'%s' undeclared", name); + + + if (tcc_state->warn_implicit_function_declaration + + + + + + ) + tcc_warning("implicit declaration of function '%s'", name); + s = external_global_sym(t, &func_old_type, 0); + } + + r = s->r; + + + if ((r & 0x003f) < 0x0030) + r = (r & ~0x003f) | 0x0032; + + vset(&s->type, r, s->c); + + + + vtop->sym = s; + + if (r & 0x0200) { + vtop->c.i = 0; + } else if (r == 0x0030 && ((s->type.t & (((1 << (6+6)) - 1) << 20 | 0x0080)) == (3 << 20))) { + vtop->c.i = s->enum_val; + } + break; + } + + + while (1) { + if (tok == 0xa4 || tok == 0xa2) { + inc(1, tok); + next(); + } else if (tok == '.' || tok == 0xc7 || tok == 0xbc) { + int qualifiers; + + if (tok == 0xc7) + indir(); + qualifiers = vtop->type.t & (0x0100 | 0x0200); + test_lvalue(); + gaddrof(); + + if ((vtop->type.t & 0x000f) != 7) + expect("struct or union"); + if (tok == 0xbc) + expect("field name"); + next(); + if (tok == 0xb5 || tok == 0xb6) + expect("field name"); + s = find_field(&vtop->type, tok); + if (!s) + tcc_error("field not found: %s", get_tok_str(tok & ~0x20000000, &tokc)); + + vtop->type = char_pointer_type; + vpushi(s->c); + gen_op('+'); + + vtop->type = s->type; + vtop->type.t |= qualifiers; + + if (!(vtop->type.t & 0x0040)) { + vtop->r |= lvalue_type(vtop->type.t); + + + if (tcc_state->do_bounds_check && (vtop->r & 0x003f) != 0x0032) + vtop->r |= 0x0800; + + } + next(); + } else if (tok == '[') { + next(); + gexpr(); + gen_op('+'); + indir(); + skip(']'); + } else if (tok == '(') { + SValue ret; + Sym *sa; + int nb_args, ret_nregs, ret_align, regsize, variadic; + + + if ((vtop->type.t & 0x000f) != 6) { + + if ((vtop->type.t & (0x000f | 0x0040)) == 5) { + vtop->type = *pointed_type(&vtop->type); + if ((vtop->type.t & 0x000f) != 6) + goto error_func; + } else { + error_func: + expect("function pointer"); + } + } else { + vtop->r &= ~0x0100; + } + + s = vtop->type.ref; + next(); + sa = s->next; + nb_args = regsize = 0; + ret.r2 = 0x0030; + + if ((s->type.t & 0x000f) == 7) { + variadic = (s->f.func_type == 3); + ret_nregs = gfunc_sret(&s->type, variadic, &ret.type, + &ret_align, ®size); + if (!ret_nregs) { + + size = type_size(&s->type, &align); +# 5199 "tccgen.c" + loc = (loc - size) & -align; + ret.type = s->type; + ret.r = 0x0032 | 0x0100; + + + vseti(0x0032, loc); + ret.c = vtop->c; + nb_args++; + } + } else { + ret_nregs = 1; + ret.type = s->type; + } + + if (ret_nregs) { + + if (is_float(ret.type.t)) { + ret.r = reg_fret(ret.type.t); + + if ((ret.type.t & 0x000f) == 14) + ret.r2 = TREG_XMM1; + + } else { + + + if ((ret.type.t & 0x000f) == 13) + + + + ret.r2 = TREG_RDX; + + ret.r = TREG_RAX; + } + ret.c.i = 0; + } + if (tok != ')') { + for(;;) { + expr_eq(); + gfunc_param_typed(s, sa); + nb_args++; + if (sa) + sa = sa->next; + if (tok == ')') + break; + skip(','); + } + } + if (sa) + tcc_error("too few arguments to function"); + skip(')'); + gfunc_call(nb_args); + + + for (r = ret.r + ret_nregs + !ret_nregs; r-- > ret.r;) { + vsetc(&ret.type, r, &ret.c); + vtop->r2 = ret.r2; + } + + + if (((s->type.t & 0x000f) == 7) && ret_nregs) { + int addr, offset; + + size = type_size(&s->type, &align); + + + if (regsize > align) + align = regsize; + loc = (loc - size) & -align; + addr = loc; + offset = 0; + for (;;) { + vset(&ret.type, 0x0032 | 0x0100, addr + offset); + vswap(); + vstore(); + vtop--; + if (--ret_nregs == 0) + break; + offset += regsize; + } + vset(&s->type, 0x0032 | 0x0100, addr); + } + } else { + break; + } + } +} + +static void expr_prod(void) +{ + int t; + + unary(); + while (tok == '*' || tok == '/' || tok == '%') { + t = tok; + next(); + unary(); + gen_op(t); + } +} + +static void expr_sum(void) +{ + int t; + + expr_prod(); + while (tok == '+' || tok == '-') { + t = tok; + next(); + expr_prod(); + gen_op(t); + } +} + +static void expr_shift(void) +{ + int t; + + expr_sum(); + while (tok == 0x01 || tok == 0x02) { + t = tok; + next(); + expr_sum(); + gen_op(t); + } +} + +static void expr_cmp(void) +{ + int t; + + expr_shift(); + while ((tok >= 0x96 && tok <= 0x9f) || + tok == 0x92 || tok == 0x93) { + t = tok; + next(); + expr_shift(); + gen_op(t); + } +} + +static void expr_cmpeq(void) +{ + int t; + + expr_cmp(); + while (tok == 0x94 || tok == 0x95) { + t = tok; + next(); + expr_cmp(); + gen_op(t); + } +} + +static void expr_and(void) +{ + expr_cmpeq(); + while (tok == '&') { + next(); + expr_cmpeq(); + gen_op('&'); + } +} + +static void expr_xor(void) +{ + expr_and(); + while (tok == '^') { + next(); + expr_and(); + gen_op('^'); + } +} + +static void expr_or(void) +{ + expr_xor(); + while (tok == '|') { + next(); + expr_xor(); + gen_op('|'); + } +} + +static void expr_land(void) +{ + expr_or(); + if (tok == 0xa0) { + int t = 0; + for(;;) { + if ((vtop->r & (0x003f | 0x0100 | 0x0200)) == 0x0030) { + gen_cast_s(11); + if (vtop->c.i) { + vpop(); + } else { + nocode_wanted++; + while (tok == 0xa0) { + next(); + expr_or(); + vpop(); + } + nocode_wanted--; + if (t) + gsym(t); + gen_cast_s(3); + break; + } + } else { + if (!t) + save_regs(1); + t = gvtst(1, t); + } + if (tok != 0xa0) { + if (t) + vseti(0x0035, t); + else + vpushi(1); + break; + } + next(); + expr_or(); + } + } +} + +static void expr_lor(void) +{ + expr_land(); + if (tok == 0xa1) { + int t = 0; + for(;;) { + if ((vtop->r & (0x003f | 0x0100 | 0x0200)) == 0x0030) { + gen_cast_s(11); + if (!vtop->c.i) { + vpop(); + } else { + nocode_wanted++; + while (tok == 0xa1) { + next(); + expr_land(); + vpop(); + } + nocode_wanted--; + if (t) + gsym(t); + gen_cast_s(3); + break; + } + } else { + if (!t) + save_regs(1); + t = gvtst(0, t); + } + if (tok != 0xa1) { + if (t) + vseti(0x0034, t); + else + vpushi(0); + break; + } + next(); + expr_land(); + } + } +} + + + + +static int condition_3way(void) +{ + int c = -1; + if ((vtop->r & (0x003f | 0x0100)) == 0x0030 && + (!(vtop->r & 0x0200) || !vtop->sym->a.weak)) { + vdup(); + gen_cast_s(11); + c = vtop->c.i; + vpop(); + } + return c; +} + +static void expr_cond(void) +{ + int tt, u, r1, r2, rc, t1, t2, bt1, bt2, islv, c, g; + SValue sv; + CType type, type1, type2; + + expr_lor(); + if (tok == '?') { + next(); + c = condition_3way(); + g = (tok == ':' && gnu_ext); + if (c < 0) { + + + if (is_float(vtop->type.t)) { + rc = 0x0002; + + if ((vtop->type.t & 0x000f) == 10) { + rc = 0x0080; + } + + } else + rc = 0x0001; + gv(rc); + save_regs(1); + if (g) + gv_dup(); + tt = gvtst(1, 0); + + } else { + if (!g) + vpop(); + tt = 0; + } + + if (1) { + if (c == 0) + nocode_wanted++; + if (!g) + gexpr(); + + type1 = vtop->type; + sv = *vtop; + vtop--; + skip(':'); + + u = 0; + if (c < 0) + u = gjmp(0); + gsym(tt); + + if (c == 0) + nocode_wanted--; + if (c == 1) + nocode_wanted++; + expr_cond(); + if (c == 1) + nocode_wanted--; + + type2 = vtop->type; + t1 = type1.t; + bt1 = t1 & 0x000f; + t2 = type2.t; + bt2 = t2 & 0x000f; + type.ref = 0; + + + if (is_float(bt1) || is_float(bt2)) { + if (bt1 == 10 || bt2 == 10) { + type.t = 10; + + } else if (bt1 == 9 || bt2 == 9) { + type.t = 9; + } else { + type.t = 8; + } + } else if (bt1 == 4 || bt2 == 4) { + + type.t = 4 | 0x0800; + if (bt1 == 4) + type.t &= t1; + if (bt2 == 4) + type.t &= t2; + + if ((t1 & (0x000f | 0x0010 | 0x0080)) == (4 | 0x0010) || + (t2 & (0x000f | 0x0010 | 0x0080)) == (4 | 0x0010)) + type.t |= 0x0010; + } else if (bt1 == 5 || bt2 == 5) { + + + if (is_null_pointer (vtop)) + type = type1; + else if (is_null_pointer (&sv)) + type = type2; + + + else + type = type1; + } else if (bt1 == 6 || bt2 == 6) { + + type = bt1 == 6 ? type1 : type2; + } else if (bt1 == 7 || bt2 == 7) { + + type = bt1 == 7 ? type1 : type2; + } else if (bt1 == 0 || bt2 == 0) { + + type.t = 0; + } else { + + type.t = 3 | (0x0800 & (t1 | t2)); + + if ((t1 & (0x000f | 0x0010 | 0x0080)) == (3 | 0x0010) || + (t2 & (0x000f | 0x0010 | 0x0080)) == (3 | 0x0010)) + type.t |= 0x0010; + } + + + islv = (vtop->r & 0x0100) && (sv.r & 0x0100) && 7 == (type.t & 0x000f); + islv &= c < 0; + + + if (c != 1) { + gen_cast(&type); + if (islv) { + mk_pointer(&vtop->type); + gaddrof(); + } else if (7 == (vtop->type.t & 0x000f)) + gaddrof(); + } + + rc = 0x0001; + if (is_float(type.t)) { + rc = 0x0002; + + if ((type.t & 0x000f) == 10) { + rc = 0x0080; + } + + } else if ((type.t & 0x000f) == 4) { + + + rc = 0x0004; + } + + tt = r2 = 0; + if (c < 0) { + r2 = gv(rc); + tt = gjmp(0); + } + gsym(u); + + + + if (c != 0) { + *vtop = sv; + gen_cast(&type); + if (islv) { + mk_pointer(&vtop->type); + gaddrof(); + } else if (7 == (vtop->type.t & 0x000f)) + gaddrof(); + } + + if (c < 0) { + r1 = gv(rc); + move_reg(r2, r1, type.t); + vtop->r = r2; + gsym(tt); + if (islv) + indir(); + } + } + } +} + +static void expr_eq(void) +{ + int t; + + expr_cond(); + if (tok == '=' || + (tok >= 0xa5 && tok <= 0xaf) || + tok == 0xde || tok == 0xfc || + tok == 0x81 || tok == 0x82) { + test_lvalue(); + t = tok; + next(); + if (t == '=') { + expr_eq(); + } else { + vdup(); + expr_eq(); + gen_op(t & 0x7f); + } + vstore(); + } +} + +static void gexpr(void) +{ + while (1) { + expr_eq(); + if (tok != ',') + break; + vpop(); + next(); + } +} + + +static void expr_const1(void) +{ + const_wanted++; + nocode_wanted++; + expr_cond(); + nocode_wanted--; + const_wanted--; +} + + +static inline int64_t expr_const64(void) +{ + int64_t c; + expr_const1(); + if ((vtop->r & (0x003f | 0x0100 | 0x0200)) != 0x0030) + expect("constant expression"); + c = vtop->c.i; + vpop(); + return c; +} + + + +static int expr_const(void) +{ + int c; + int64_t wc = expr_const64(); + c = wc; + if (c != wc && (unsigned)c != wc) + tcc_error("constant exceeds 32 bit"); + return c; +} + + + +static int is_label(void) +{ + int last_tok; + + + if (tok < TOK_DEFINE) + return 0; + + last_tok = tok; + next(); + if (tok == ':') { + return last_tok; + } else { + unget_tok(last_tok); + return 0; + } +} + + +static void gfunc_return(CType *func_type) +{ + if ((func_type->t & 0x000f) == 7) { + CType type, ret_type; + int ret_align, ret_nregs, regsize; + ret_nregs = gfunc_sret(func_type, func_var, &ret_type, + &ret_align, ®size); + if (0 == ret_nregs) { + + + type = *func_type; + mk_pointer(&type); + vset(&type, 0x0032 | 0x0100, func_vc); + indir(); + vswap(); + + vstore(); + } else { + + int r, size, addr, align; + size = type_size(func_type,&align); + if ((vtop->r != (0x0032 | 0x0100) || + (vtop->c.i & (ret_align-1))) + && (align & (ret_align-1))) { + loc = (loc - size) & -ret_align; + addr = loc; + type = *func_type; + vset(&type, 0x0032 | 0x0100, addr); + vswap(); + vstore(); + vpop(); + vset(&ret_type, 0x0032 | 0x0100, addr); + } + vtop->type = ret_type; + if (is_float(ret_type.t)) + r = rc_fret(ret_type.t); + else + r = 0x0004; + + if (ret_nregs == 1) + gv(r); + else { + for (;;) { + vdup(); + gv(r); + vpop(); + if (--ret_nregs == 0) + break; + + + + r <<= 1; + vtop->c.i += regsize; + } + } + } + } else if (is_float(func_type->t)) { + gv(rc_fret(func_type->t)); + } else { + gv(0x0004); + } + vtop--; +} + + +static int case_cmp(const void *pa, const void *pb) +{ + int64_t a = (*(struct case_t**) pa)->v1; + int64_t b = (*(struct case_t**) pb)->v1; + return a < b ? -1 : a > b; +} + +static void gcase(struct case_t **base, int len, int *bsym) +{ + struct case_t *p; + int e; + int ll = (vtop->type.t & 0x000f) == 4; + gv(0x0001); + while (len > 4) { + + p = base[len/2]; + vdup(); + if (ll) + vpushll(p->v2); + else + vpushi(p->v2); + gen_op(0x9e); + e = gtst(1, 0); + vdup(); + if (ll) + vpushll(p->v1); + else + vpushi(p->v1); + gen_op(0x9d); + gtst_addr(0, p->sym); + + gcase(base, len/2, bsym); + if (cur_switch->def_sym) + gjmp_addr(cur_switch->def_sym); + else + *bsym = gjmp(*bsym); + + gsym(e); + e = len/2 + 1; + base += e; len -= e; + } + + while (len--) { + p = *base++; + vdup(); + if (ll) + vpushll(p->v2); + else + vpushi(p->v2); + if (p->v1 == p->v2) { + gen_op(0x94); + gtst_addr(0, p->sym); + } else { + gen_op(0x9e); + e = gtst(1, 0); + vdup(); + if (ll) + vpushll(p->v1); + else + vpushi(p->v1); + gen_op(0x9d); + gtst_addr(0, p->sym); + gsym(e); + } + } +} + +static void block(int *bsym, int *csym, int is_expr) +{ + int a, b, c, d, cond; + Sym *s; + + + if (tcc_state->do_debug) + tcc_debug_line(tcc_state); + + if (is_expr) { + + vpushi(0); + vtop->type.t = 0; + } + + if (tok == TOK_IF) { + + int saved_nocode_wanted = nocode_wanted; + next(); + skip('('); + gexpr(); + skip(')'); + cond = condition_3way(); + if (cond == 1) + a = 0, vpop(); + else + a = gvtst(1, 0); + if (cond == 0) + nocode_wanted |= 0x20000000; + block(bsym, csym, 0); + if (cond != 1) + nocode_wanted = saved_nocode_wanted; + c = tok; + if (c == TOK_ELSE) { + next(); + d = gjmp(0); + gsym(a); + if (cond == 1) + nocode_wanted |= 0x20000000; + block(bsym, csym, 0); + gsym(d); + if (cond != 0) + nocode_wanted = saved_nocode_wanted; + } else + gsym(a); + } else if (tok == TOK_WHILE) { + int saved_nocode_wanted; + nocode_wanted &= ~0x20000000; + next(); + d = ind; + vla_sp_restore(); + skip('('); + gexpr(); + skip(')'); + a = gvtst(1, 0); + b = 0; + ++local_scope; + saved_nocode_wanted = nocode_wanted; + block(&a, &b, 0); + nocode_wanted = saved_nocode_wanted; + --local_scope; + gjmp_addr(d); + gsym(a); + gsym_addr(b, d); + } else if (tok == '{') { + Sym *llabel; + int block_vla_sp_loc = vla_sp_loc, saved_vlas_in_scope = vlas_in_scope; + + next(); + + s = local_stack; + llabel = local_label_stack; + ++local_scope; + + + if (tok == TOK_LABEL) { + next(); + for(;;) { + if (tok < TOK_DEFINE) + expect("label identifier"); + label_push(&local_label_stack, tok, 2); + next(); + if (tok == ',') { + next(); + } else { + skip(';'); + break; + } + } + } + while (tok != '}') { + if ((a = is_label())) + unget_tok(a); + else + decl(0x0032); + if (tok != '}') { + if (is_expr) + vpop(); + block(bsym, csym, is_expr); + } + } + + label_pop(&local_label_stack, llabel, is_expr); + + --local_scope; + + + + + + + + sym_pop(&local_stack, s, is_expr); + + + if (vlas_in_scope > saved_vlas_in_scope) { + vla_sp_loc = saved_vlas_in_scope ? block_vla_sp_loc : vla_sp_root_loc; + vla_sp_restore(); + } + vlas_in_scope = saved_vlas_in_scope; + + next(); + } else if (tok == TOK_RETURN) { + next(); + if (tok != ';') { + gexpr(); + gen_assign_cast(&func_vt); + if ((func_vt.t & 0x000f) == 0) + vtop--; + else + gfunc_return(&func_vt); + } + skip(';'); + + if (tok != '}' || local_scope != 1) + rsym = gjmp(rsym); + nocode_wanted |= 0x20000000; + } else if (tok == TOK_BREAK) { + + if (!bsym) + tcc_error("cannot break"); + *bsym = gjmp(*bsym); + next(); + skip(';'); + nocode_wanted |= 0x20000000; + } else if (tok == TOK_CONTINUE) { + + if (!csym) + tcc_error("cannot continue"); + vla_sp_restore_root(); + *csym = gjmp(*csym); + next(); + skip(';'); + } else if (tok == TOK_FOR) { + int e; + int saved_nocode_wanted; + nocode_wanted &= ~0x20000000; + next(); + skip('('); + s = local_stack; + ++local_scope; + if (tok != ';') { + + if (!decl0(0x0032, 1, 0)) { + + gexpr(); + vpop(); + } + } + skip(';'); + d = ind; + c = ind; + vla_sp_restore(); + a = 0; + b = 0; + if (tok != ';') { + gexpr(); + a = gvtst(1, 0); + } + skip(';'); + if (tok != ')') { + e = gjmp(0); + c = ind; + vla_sp_restore(); + gexpr(); + vpop(); + gjmp_addr(d); + gsym(e); + } + skip(')'); + saved_nocode_wanted = nocode_wanted; + block(&a, &b, 0); + nocode_wanted = saved_nocode_wanted; + gjmp_addr(c); + gsym(a); + gsym_addr(b, c); + --local_scope; + sym_pop(&local_stack, s, 0); + + } else + if (tok == TOK_DO) { + int saved_nocode_wanted; + nocode_wanted &= ~0x20000000; + next(); + a = 0; + b = 0; + d = ind; + vla_sp_restore(); + saved_nocode_wanted = nocode_wanted; + block(&a, &b, 0); + skip(TOK_WHILE); + skip('('); + gsym(b); + gexpr(); + c = gvtst(0, 0); + gsym_addr(c, d); + nocode_wanted = saved_nocode_wanted; + skip(')'); + gsym(a); + skip(';'); + } else + if (tok == TOK_SWITCH) { + struct switch_t *saved, sw; + int saved_nocode_wanted = nocode_wanted; + SValue switchval; + next(); + skip('('); + gexpr(); + skip(')'); + switchval = *vtop--; + a = 0; + b = gjmp(0); + sw.p = 0; sw.n = 0; sw.def_sym = 0; + saved = cur_switch; + cur_switch = &sw; + block(&a, csym, 0); + nocode_wanted = saved_nocode_wanted; + a = gjmp(a); + + gsym(b); + qsort(sw.p, sw.n, sizeof(void*), case_cmp); + for (b = 1; b < sw.n; b++) + if (sw.p[b - 1]->v2 >= sw.p[b]->v1) + tcc_error("duplicate case value"); + + + if ((switchval.type.t & 0x000f) == 4) + switchval.type.t &= ~0x0010; + vpushv(&switchval); + gcase(sw.p, sw.n, &a); + vpop(); + if (sw.def_sym) + gjmp_addr(sw.def_sym); + dynarray_reset(&sw.p, &sw.n); + cur_switch = saved; + + gsym(a); + } else + if (tok == TOK_CASE) { + struct case_t *cr = tcc_malloc(sizeof(struct case_t)); + if (!cur_switch) + expect("switch"); + nocode_wanted &= ~0x20000000; + next(); + cr->v1 = cr->v2 = expr_const64(); + if (gnu_ext && tok == 0xc8) { + next(); + cr->v2 = expr_const64(); + if (cr->v2 < cr->v1) + tcc_warning("empty case range"); + } + cr->sym = ind; + dynarray_add(&cur_switch->p, &cur_switch->n, cr); + skip(':'); + is_expr = 0; + goto block_after_label; + } else + if (tok == TOK_DEFAULT) { + next(); + skip(':'); + if (!cur_switch) + expect("switch"); + if (cur_switch->def_sym) + tcc_error("too many 'default'"); + cur_switch->def_sym = ind; + is_expr = 0; + goto block_after_label; + } else + if (tok == TOK_GOTO) { + next(); + if (tok == '*' && gnu_ext) { + + next(); + gexpr(); + if ((vtop->type.t & 0x000f) != 5) + expect("pointer"); + ggoto(); + } else if (tok >= TOK_DEFINE) { + s = label_find(tok); + + if (!s) { + s = label_push(&global_label_stack, tok, 1); + } else { + if (s->r == 2) + s->r = 1; + } + vla_sp_restore_root(); + if (s->r & 1) + s->jnext = gjmp(s->jnext); + else + gjmp_addr(s->jnext); + next(); + } else { + expect("label identifier"); + } + skip(';'); + } else if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) { + asm_instr(); + } else { + b = is_label(); + if (b) { + + next(); + s = label_find(b); + if (s) { + if (s->r == 0) + tcc_error("duplicate label '%s'", get_tok_str(s->v, 0)); + gsym(s->jnext); + s->r = 0; + } else { + s = label_push(&global_label_stack, b, 0); + } + s->jnext = ind; + vla_sp_restore(); + + block_after_label: + nocode_wanted &= ~0x20000000; + if (tok == '}') { + tcc_warning("deprecated use of label at end of compound statement"); + } else { + if (is_expr) + vpop(); + block(bsym, csym, is_expr); + } + } else { + + if (tok != ';') { + if (is_expr) { + vpop(); + gexpr(); + } else { + gexpr(); + vpop(); + } + } + skip(';'); + } + } +} + + + + + + +static void skip_or_save_block(TokenString **str) +{ + int braces = tok == '{'; + int level = 0; + if (str) + *str = tok_str_alloc(); + + while ((level > 0 || (tok != '}' && tok != ',' && tok != ';' && tok != ')'))) { + int t; + if (tok == (-1)) { + if (str || level > 0) + tcc_error("unexpected end of file"); + else + break; + } + if (str) + tok_str_add_tok(*str); + t = tok; + next(); + if (t == '{' || t == '(') { + level++; + } else if (t == '}' || t == ')') { + level--; + if (level == 0 && braces && t == '}') + break; + } + } + if (str) { + tok_str_add(*str, -1); + tok_str_add(*str, 0); + } +} + + + + +static void parse_init_elem(int expr_type) +{ + int saved_global_expr; + switch(expr_type) { + case 1: + + saved_global_expr = global_expr; + global_expr = 1; + expr_const1(); + global_expr = saved_global_expr; + + + if (((vtop->r & (0x003f | 0x0100)) != 0x0030 + && ((vtop->r & (0x0200|0x0100)) != (0x0200|0x0100) + || vtop->sym->v < 0x10000000)) + + + + ) + tcc_error("initializer element is not constant"); + break; + case 2: + expr_eq(); + break; + } +} + + +static void init_putz(Section *sec, unsigned long c, int size) +{ + if (sec) { + + } else { + vpush_global_sym(&func_old_type, TOK_memset); + vseti(0x0032, c); + + + + + vpushi(0); + vpushs(size); + + gfunc_call(3); + } +} + + + + + + + +static int decl_designator(CType *type, Section *sec, unsigned long c, + Sym **cur_field, int size_only, int al) +{ + Sym *s, *f; + int index, index_last, align, l, nb_elems, elem_size; + unsigned long corig = c; + + elem_size = 0; + nb_elems = 1; + if (gnu_ext && (l = is_label()) != 0) + goto struct_field; + + while (nb_elems == 1 && (tok == '[' || tok == '.')) { + if (tok == '[') { + if (!(type->t & 0x0040)) + expect("array type"); + next(); + index = index_last = expr_const(); + if (tok == 0xc8 && gnu_ext) { + next(); + index_last = expr_const(); + } + skip(']'); + s = type->ref; + if (index < 0 || (s->c >= 0 && index_last >= s->c) || + index_last < index) + tcc_error("invalid index"); + if (cur_field) + (*cur_field)->c = index_last; + type = pointed_type(type); + elem_size = type_size(type, &align); + c += index * elem_size; + nb_elems = index_last - index + 1; + } else { + next(); + l = tok; + struct_field: + next(); + if ((type->t & 0x000f) != 7) + expect("struct/union type"); + f = find_field(type, l); + if (!f) + expect("field"); + if (cur_field) + *cur_field = f; + type = &f->type; + c += f->c; + } + cur_field = 0; + } + if (!cur_field) { + if (tok == '=') { + next(); + } else if (!gnu_ext) { + expect("="); + } + } else { + if (type->t & 0x0040) { + index = (*cur_field)->c; + if (type->ref->c >= 0 && index >= type->ref->c) + tcc_error("index too large"); + type = pointed_type(type); + c += index * type_size(type, &align); + } else { + f = *cur_field; + while (f && (f->v & 0x10000000) && (f->type.t & 0x0080)) + *cur_field = f = f->next; + if (!f) + tcc_error("too many field init"); + type = &f->type; + c += f->c; + } + } + + + if (!size_only && c - corig > al) + init_putz(sec, corig + al, c - corig - al); + decl_initializer(type, sec, c, 0, size_only); + + + if (!size_only && nb_elems > 1) { + unsigned long c_end; + uint8_t *src, *dst; + int i; + + if (!sec) { + vset(type, 0x0032|0x0100, c); + for (i = 1; i < nb_elems; i++) { + vset(type, 0x0032|0x0100, c + elem_size * i); + vswap(); + vstore(); + } + vpop(); + } else if (!(nocode_wanted > 0)) { + c_end = c + nb_elems * elem_size; + if (c_end > sec->data_allocated) + section_realloc(sec, c_end); + src = sec->data + c; + dst = src; + for(i = 1; i < nb_elems; i++) { + dst += elem_size; + memcpy(dst, src, elem_size); + } + } + } + c += nb_elems * type_size(type, &align); + if (c - corig > al) + al = c - corig; + return al; +} + + +static void init_putv(CType *type, Section *sec, unsigned long c) +{ + int bt; + void *ptr; + CType dtype; + + dtype = *type; + dtype.t &= ~0x0100; + + if (sec) { + int size, align; + + + gen_assign_cast(&dtype); + bt = type->t & 0x000f; + + if ((vtop->r & 0x0200) + && bt != 5 + && bt != 6 + && (bt != (8 == 8 ? 4 : 3) + || (type->t & 0x0080)) + && !((vtop->r & 0x0030) && vtop->sym->v >= 0x10000000) + ) + tcc_error("initializer element is not computable at load time"); + + if ((nocode_wanted > 0)) { + vtop--; + return; + } + + size = type_size(type, &align); + section_reserve(sec, c + size); + ptr = sec->data + c; + + + if ((vtop->r & (0x0200|0x0030)) == (0x0200|0x0030) && + vtop->sym->v >= 0x10000000 && +# 6488 "tccgen.c" + (vtop->type.t & 0x000f) != 5) { + + Section *ssec; + Elf64_Sym *esym; + Elf64_Rela *rel; + esym = elfsym(vtop->sym); + ssec = tcc_state->sections[esym->st_shndx]; + memmove (ptr, ssec->data + esym->st_value, size); + if (ssec->reloc) { + + + + + int num_relocs = ssec->reloc->data_offset / sizeof(*rel); + rel = (Elf64_Rela*)(ssec->reloc->data + ssec->reloc->data_offset); + while (num_relocs--) { + rel--; + if (rel->r_offset >= esym->st_value + size) + continue; + if (rel->r_offset < esym->st_value) + break; + + + + + + + put_elf_reloca(symtab_section, sec, + c + rel->r_offset - esym->st_value, + ((rel->r_info) & 0xffffffff), + ((rel->r_info) >> 32), + + rel->r_addend + + + + ); + } + } + } else { + if (type->t & 0x0080) { + int bit_pos, bit_size, bits, n; + unsigned char *p, v, m; + bit_pos = (((vtop->type.t) >> 20) & 0x3f); + bit_size = (((vtop->type.t) >> (20 + 6)) & 0x3f); + p = (unsigned char*)ptr + (bit_pos >> 3); + bit_pos &= 7, bits = 0; + while (bit_size) { + n = 8 - bit_pos; + if (n > bit_size) + n = bit_size; + v = vtop->c.i >> bits << bit_pos; + m = ((1 << n) - 1) << bit_pos; + *p = (*p & ~m) | (v & m); + bits += n, bit_size -= n, bit_pos = 0, ++p; + } + } else + switch(bt) { + + + + case 11: + vtop->c.i = vtop->c.i != 0; + case 1: + *(char *)ptr |= vtop->c.i; + break; + case 2: + *(short *)ptr |= vtop->c.i; + break; + case 8: + *(float*)ptr = vtop->c.f; + break; + case 9: + *(double *)ptr = vtop->c.d; + break; + case 10: + + if (sizeof (long double) >= 10) + memcpy(ptr, &vtop->c.ld, 10); + + + + + else if (vtop->c.ld == 0.0) + ; + else + + if (sizeof(long double) == 16) + *(long double*)ptr = vtop->c.ld; + else if (sizeof(double) == 16) + *(double *)ptr = (double)vtop->c.ld; + else + tcc_error("can't cross compile long double constants"); + break; + + + + + + case 4: + + case 5: + { + Elf64_Addr val = vtop->c.i; + + if (vtop->r & 0x0200) + greloca(sec, vtop->sym, c, 1, val); + else + *(Elf64_Addr *)ptr |= val; + + + + + + break; + } + default: + { + int val = vtop->c.i; + + if (vtop->r & 0x0200) + greloca(sec, vtop->sym, c, 1, val); + else + *(int *)ptr |= val; + + + + + + break; + } + } + } + vtop--; + } else { + vset(&dtype, 0x0032|0x0100, c); + vswap(); + vstore(); + vpop(); + } +} + + + + + + +static void decl_initializer(CType *type, Section *sec, unsigned long c, + int first, int size_only) +{ + int len, n, no_oblock, nb, i; + int size1, align1; + int have_elem; + Sym *s, *f; + Sym indexsym; + CType *t1; + + + + have_elem = tok == '}' || tok == ','; + if (!have_elem && tok != '{' && + + + + tok != 0xba && tok != 0xb9 && + !size_only) { + parse_init_elem(!sec ? 2 : 1); + have_elem = 1; + } + + if (have_elem && + !(type->t & 0x0040) && + + + + is_compatible_unqualified_types(type, &vtop->type)) { + init_putv(type, sec, c); + } else if (type->t & 0x0040) { + s = type->ref; + n = s->c; + t1 = pointed_type(type); + size1 = type_size(t1, &align1); + + no_oblock = 1; + if ((first && tok != 0xba && tok != 0xb9) || + tok == '{') { + if (tok != '{') + tcc_error("character array initializer must be a literal," + " optionally enclosed in braces"); + skip('{'); + no_oblock = 0; + } + + + + if ((tok == 0xba && + + + + (t1->t & 0x000f) == 3 + + ) || (tok == 0xb9 && (t1->t & 0x000f) == 1)) { + len = 0; + while (tok == 0xb9 || tok == 0xba) { + int cstr_len, ch; + + + if (tok == 0xb9) + cstr_len = tokc.str.size; + else + cstr_len = tokc.str.size / sizeof(nwchar_t); + cstr_len--; + nb = cstr_len; + if (n >= 0 && nb > (n - len)) + nb = n - len; + if (!size_only) { + if (cstr_len > nb) + tcc_warning("initializer-string for array is too long"); + + + + if (sec && tok == 0xb9 && size1 == 1) { + if (!(nocode_wanted > 0)) + memcpy(sec->data + c + len, tokc.str.data, nb); + } else { + for(i=0;i<nb;i++) { + if (tok == 0xb9) + ch = ((unsigned char *)tokc.str.data)[i]; + else + ch = ((nwchar_t *)tokc.str.data)[i]; + vpushi(ch); + init_putv(t1, sec, c + (len + i) * size1); + } + } + } + len += nb; + next(); + } + + + if (n < 0 || len < n) { + if (!size_only) { + vpushi(0); + init_putv(t1, sec, c + (len * size1)); + } + len++; + } + len *= size1; + } else { + indexsym.c = 0; + f = &indexsym; + + do_init_list: + len = 0; + while (tok != '}' || have_elem) { + len = decl_designator(type, sec, c, &f, size_only, len); + have_elem = 0; + if (type->t & 0x0040) { + ++indexsym.c; + + + + if (no_oblock && len >= n*size1) + break; + } else { + if (s->type.t == (1 << 20 | 7)) + f = 0; + else + f = f->next; + if (no_oblock && f == 0) + break; + } + + if (tok == '}') + break; + skip(','); + } + } + + if (!size_only && len < n*size1) + init_putz(sec, c + len, n*size1 - len); + if (!no_oblock) + skip('}'); + + if (n < 0) + s->c = size1 == 1 ? len : ((len + size1 - 1)/size1); + } else if ((type->t & 0x000f) == 7) { + size1 = 1; + no_oblock = 1; + if (first || tok == '{') { + skip('{'); + no_oblock = 0; + } + s = type->ref; + f = s->next; + n = s->c; + goto do_init_list; + } else if (tok == '{') { + next(); + decl_initializer(type, sec, c, first, size_only); + skip('}'); + } else if (size_only) { + + + + + + + + skip_or_save_block(0); + } else { + if (!have_elem) { + + + + if (tok != 0xb9 && tok != 0xba) + expect("string constant"); + parse_init_elem(!sec ? 2 : 1); + } + init_putv(type, sec, c); + } +} +# 6818 "tccgen.c" +static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, + int has_init, int v, int scope) +{ + int size, align, addr; + TokenString *init_str = 0; + + Section *sec; + Sym *flexible_array; + Sym *sym = 0; + int saved_nocode_wanted = nocode_wanted; + + int bcheck = tcc_state->do_bounds_check && !(nocode_wanted > 0); + + + if (type->t & 0x00002000) + nocode_wanted |= (nocode_wanted > 0) ? 0x40000000 : 0x80000000; + + flexible_array = 0; + if ((type->t & 0x000f) == 7) { + Sym *field = type->ref->next; + if (field) { + while (field->next) + field = field->next; + if (field->type.t & 0x0040 && field->type.ref->c < 0) + flexible_array = field; + } + } + + size = type_size(type, &align); + + + + + + + if (size < 0 || (flexible_array && has_init)) { + if (!has_init) + tcc_error("unknown type size"); + + if (has_init == 2) { + init_str = tok_str_alloc(); + + while (tok == 0xb9 || tok == 0xba) { + tok_str_add_tok(init_str); + next(); + } + tok_str_add(init_str, -1); + tok_str_add(init_str, 0); + } else { + skip_or_save_block(&init_str); + } + unget_tok(0); + + + begin_macro(init_str, 1); + next(); + decl_initializer(type, 0, 0, 1, 1); + + macro_ptr = init_str->str; + next(); + + + size = type_size(type, &align); + if (size < 0) + tcc_error("unknown type size"); + } + + + if (flexible_array && + flexible_array->type.ref->c > 0) + size += flexible_array->type.ref->c + * pointed_size(&flexible_array->type); + + if (ad->a.aligned) { + int speca = 1 << (ad->a.aligned - 1); + if (speca > align) + align = speca; + } else if (ad->a.packed) { + align = 1; + } + + if ((nocode_wanted > 0)) + size = 0, align = 1; + + if ((r & 0x003f) == 0x0032) { + sec = 0; + + if (bcheck && (type->t & 0x0040)) { + loc--; + } + + loc = (loc - size) & -align; + addr = loc; + + + + + if (bcheck && (type->t & 0x0040)) { + Elf64_Addr *bounds_ptr; + + loc--; + + bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(Elf64_Addr)); + bounds_ptr[0] = addr; + bounds_ptr[1] = size; + } + + if (v) { + + + if (ad->asm_label) { + int reg = asm_parse_regvar(ad->asm_label); + if (reg >= 0) + r = (r & ~0x003f) | reg; + } + + sym = sym_push(v, type, r, addr); + sym->a = ad->a; + } else { + + vset(type, r, addr); + } + } else { + if (v && scope == 0x0030) { + + sym = sym_find(v); + if (sym) { + patch_storage(sym, ad, type); + + if (!has_init && sym->c && elfsym(sym)->st_shndx != 0) + goto no_alloc; + } + } + + + sec = ad->section; + if (!sec) { + if (has_init) + sec = data_section; + else if (tcc_state->nocommon) + sec = bss_section; + } + + if (sec) { + addr = section_add(sec, size, align); + + + if (bcheck) + section_add(sec, 1, 1); + + } else { + addr = align; + sec = common_section; + } + + if (v) { + if (!sym) { + sym = sym_push(v, type, r | 0x0200, 0); + patch_storage(sym, ad, 0); + } + + + sym->sym_scope = 0; + + put_extern_sym(sym, sec, addr, size); + } else { + + sym = get_sym_ref(type, sec, addr, size); + vpushsym(type, sym); + vtop->r |= r; + } + + + + + if (bcheck) { + Elf64_Addr *bounds_ptr; + + greloca(bounds_section, sym, bounds_section->data_offset, 1, 0); + + bounds_ptr = section_ptr_add(bounds_section, 2 * sizeof(Elf64_Addr)); + bounds_ptr[0] = 0; + bounds_ptr[1] = size; + } + + } + + if (type->t & 0x0400) { + int a; + + if ((nocode_wanted > 0)) + goto no_alloc; + + + if (vlas_in_scope == 0) { + if (vla_sp_root_loc == -1) + vla_sp_root_loc = (loc -= 8); + gen_vla_sp_save(vla_sp_root_loc); + } + + vla_runtime_type_size(type, &a); + gen_vla_alloc(type, a); + + + + + + gen_vla_sp_save(addr); + vla_sp_loc = addr; + vlas_in_scope++; + + } else if (has_init) { + size_t oldreloc_offset = 0; + if (sec && sec->reloc) + oldreloc_offset = sec->reloc->data_offset; + decl_initializer(type, sec, addr, 1, 0); + if (sec && sec->reloc) + squeeze_multi_relocs(sec, oldreloc_offset); + + + if (flexible_array) + flexible_array->type.ref->c = -1; + } + + no_alloc: + + if (init_str) { + end_macro(); + next(); + } + + nocode_wanted = saved_nocode_wanted; +} + + + +static void gen_function(Sym *sym) +{ + nocode_wanted = 0; + ind = cur_text_section->data_offset; + + put_extern_sym(sym, cur_text_section, ind, 0); + funcname = get_tok_str(sym->v, 0); + func_ind = ind; + + vla_sp_loc = -1; + vla_sp_root_loc = -1; + + tcc_debug_funcstart(tcc_state, sym); + + sym_push2(&local_stack, 0x20000000, 0, 0); + local_scope = 1; + gfunc_prolog(&sym->type); + local_scope = 0; + rsym = 0; + block(0, 0, 0); + nocode_wanted = 0; + gsym(rsym); + gfunc_epilog(); + cur_text_section->data_offset = ind; + label_pop(&global_label_stack, 0, 0); + + local_scope = 0; + sym_pop(&local_stack, 0, 0); + + + elfsym(sym)->st_size = ind - func_ind; + tcc_debug_funcend(tcc_state, ind - func_ind); + + cur_text_section = 0; + funcname = ""; + func_vt.t = 0; + func_var = 0; + ind = 0; + nocode_wanted = 0x80000000; + check_vstack(); +} + +static void gen_inline_functions(TCCState *s) +{ + Sym *sym; + int inline_generated, i, ln; + struct InlineFunc *fn; + + ln = file->line_num; + + do { + inline_generated = 0; + for (i = 0; i < s->nb_inline_fns; ++i) { + fn = s->inline_fns[i]; + sym = fn->sym; + if (sym && sym->c) { + + + fn->sym = 0; + if (file) + pstrcpy(file->filename, sizeof file->filename, fn->filename); + sym->type.t &= ~0x00008000; + + begin_macro(fn->func_str, 1); + next(); + cur_text_section = text_section; + gen_function(sym); + end_macro(); + + inline_generated = 1; + } + } + } while (inline_generated); + file->line_num = ln; +} + +static void free_inline_functions(TCCState *s) +{ + int i; + + for (i = 0; i < s->nb_inline_fns; ++i) { + struct InlineFunc *fn = s->inline_fns[i]; + if (fn->sym) + tok_str_free(fn->func_str); + } + dynarray_reset(&s->inline_fns, &s->nb_inline_fns); +} + + + +static int decl0(int l, int is_for_loop_init, Sym *func_sym) +{ + int v, has_init, r; + CType type, btype; + Sym *sym; + AttributeDef ad; + + while (1) { + if (!parse_btype(&btype, &ad)) { + if (is_for_loop_init) + return 0; + + if (tok == ';' && l != 0x0033) { + next(); + continue; + } + if (l != 0x0030) + break; + if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) { + + asm_global_instr(); + continue; + } + if (tok >= TOK_DEFINE) { + + + btype.t = 3; + } else { + if (tok != (-1)) + expect("declaration"); + break; + } + } + if (tok == ';') { + if ((btype.t & 0x000f) == 7) { + int v = btype.ref->v; + if (!(v & 0x20000000) && (v & ~0x40000000) >= 0x10000000) + tcc_warning("unnamed struct/union that defines no instances"); + next(); + continue; + } + if (((btype.t & (((1 << (6+6)) - 1) << 20 | 0x0080)) == (2 << 20))) { + next(); + continue; + } + } + while (1) { + type = btype; + + + + + + if ((type.t & 0x0040) && type.ref->c < 0) { + type.ref = sym_push(0x20000000, &type.ref->type, 0, type.ref->c); + } + type_decl(&type, &ad, &v, 2); + + + + + + + + if ((type.t & 0x000f) == 6) { + if ((type.t & 0x00002000) && (l == 0x0032)) { + tcc_error("function without file scope cannot be static"); + } + + + sym = type.ref; + if (sym->f.func_type == 2 && l == 0x0030) + decl0(0x0033, 0, sym); + } + + if (gnu_ext && (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) { + ad.asm_label = asm_label_instr(); + + parse_attribute(&ad); + if (tok == '{') + expect(";"); + } +# 7239 "tccgen.c" + if (tok == '{') { + if (l != 0x0030) + tcc_error("cannot use local functions"); + if ((type.t & 0x000f) != 6) + expect("function definition"); + + + + sym = type.ref; + while ((sym = sym->next) != 0) { + if (!(sym->v & ~0x20000000)) + expect("identifier"); + if (sym->type.t == 0) + sym->type = int_type; + } + + + if ((type.t & (0x00001000 | 0x00008000)) == (0x00001000 | 0x00008000)) + type.t = (type.t & ~0x00001000) | 0x00002000; + + + sym = external_global_sym(v, &type, 0); + type.t &= ~0x00001000; + patch_storage(sym, &ad, &type); + + + + + if ((type.t & (0x00008000 | 0x00002000)) == + (0x00008000 | 0x00002000)) { + struct InlineFunc *fn; + const char *filename; + + filename = file ? file->filename : ""; + fn = tcc_malloc(sizeof *fn + strlen(filename)); + strcpy(fn->filename, filename); + fn->sym = sym; + skip_or_save_block(&fn->func_str); + dynarray_add(&tcc_state->inline_fns, + &tcc_state->nb_inline_fns, fn); + } else { + + cur_text_section = ad.section; + if (!cur_text_section) + cur_text_section = text_section; + gen_function(sym); + } + break; + } else { + if (l == 0x0033) { + + for (sym = func_sym->next; sym; sym = sym->next) + if ((sym->v & ~0x20000000) == v) + goto found; + tcc_error("declaration for parameter '%s' but no such parameter", + get_tok_str(v, 0)); +found: + if (type.t & (0x00001000 | 0x00002000 | 0x00004000 | 0x00008000)) + tcc_error("storage class specified for '%s'", + get_tok_str(v, 0)); + if (sym->type.t != 0) + tcc_error("redefinition of parameter '%s'", + get_tok_str(v, 0)); + convert_parameter_type(&type); + sym->type = type; + } else if (type.t & 0x00004000) { + + + sym = sym_find(v); + if (sym && sym->sym_scope == local_scope) { + if (!is_compatible_types(&sym->type, &type) + || !(sym->type.t & 0x00004000)) + tcc_error("incompatible redefinition of '%s'", + get_tok_str(v, 0)); + sym->type = type; + } else { + sym = sym_push(v, &type, 0, 0); + } + sym->a = ad.a; + sym->f = ad.f; + } else { + r = 0; + if ((type.t & 0x000f) == 6) { + + + type.ref->f = ad.f; + } else if (!(type.t & 0x0040)) { + + r |= lvalue_type(type.t); + } + has_init = (tok == '='); + if (has_init && (type.t & 0x0400)) + tcc_error("variable length array cannot be initialized"); + if (((type.t & 0x00001000) && (!has_init || l != 0x0030)) || + ((type.t & 0x000f) == 6) || + ((type.t & 0x0040) && (type.t & 0x00002000) && + !has_init && l == 0x0030 && type.ref->c < 0)) { + + + + + type.t |= 0x00001000; + sym = external_sym(v, &type, r, &ad); + if (ad.alias_target) { + Elf64_Sym *esym; + Sym *alias_target; + alias_target = sym_find(ad.alias_target); + esym = elfsym(alias_target); + if (!esym) + tcc_error("unsupported forward __alias__ attribute"); + + + sym->sym_scope = 0; + put_extern_sym2(sym, esym->st_shndx, esym->st_value, esym->st_size, 0); + } + } else { + if (type.t & 0x00002000) + r |= 0x0030; + else + r |= l; + if (has_init) + next(); + else if (l == 0x0030) + + type.t |= 0x00001000; + decl_initializer_alloc(&type, &ad, r, has_init, v, l); + } + } + if (tok != ',') { + if (is_for_loop_init) + return 1; + skip(';'); + break; + } + next(); + } + ad.a.aligned = 0; + } + } + return 0; +} + +static void decl(int l) +{ + decl0(l, 0, 0); +} diff --git a/utils/fake_libc_include/_fake_defines.h b/utils/fake_libc_include/_fake_defines.h index 35bd4ad..a00a63b 100644 --- a/utils/fake_libc_include/_fake_defines.h +++ b/utils/fake_libc_include/_fake_defines.h @@ -199,3 +199,23 @@ #define va_end(_list) #endif + +/* Vectors */ +#define __m128 int +#define __m128_u int +#define __m128d int +#define __m128d_u int +#define __m128i int +#define __m128i_u int +#define __m256 int +#define __m256_u int +#define __m256d int +#define __m256d_u int +#define __m256i int +#define __m256i_u int +#define __m512 int +#define __m512_u int +#define __m512d int +#define __m512d_u int +#define __m512i int +#define __m512i_u int diff --git a/utils/fake_libc_include/emmintrin.h b/utils/fake_libc_include/emmintrin.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/emmintrin.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/immintrin.h b/utils/fake_libc_include/immintrin.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/immintrin.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/smmintrin.h b/utils/fake_libc_include/smmintrin.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/smmintrin.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" |