diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4256e47 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*~ +*# +#* +.#* +.DS_Store* diff --git a/README.md b/README.md new file mode 100644 index 0000000..6b64c3a --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# ECAI 2023 - Graph Neural Networks For Mapping Variables Between Programs + +This repository contains the code and data used for the paper "*Graph Neural Networks For Mapping Variables Between Programs*", accepted at ECAI 2023. + +We present a novel graph program representation that is agnostic to the names of the variables and for each variable in the program contains a representative variable node that is connected to all the variable's occurrences. Furthermore, we use GNNs for mapping variables between programs based on our program representation, ignoring the variables' identifiers; +We represent each program as a graph using the script gen_progs_repr.py, as explained in [1, 2]. + +To understand the entire pipeline, from the dataset generation to the repair process, the interested reader is refered to our main script 'run_all.sh'. + +The generation of the datasets (training, validation and evaluation) and the training of our GNN has been commented since it takes a few hours to compute. Only the mapping computations and the program repair tasks were left uncommented. In this repo only the evaluation dataset is available. + +- How to execute: + +``` +chmod +x run_all.sh +bash run_all.sh +``` + +## Installation Requirements + +The following script creates a new conda environment named 'gnn_env' and installs all the required dependencies in it. + +``` +chmod +x config_gnn.sh +bash confin_gnn.sh +``` + +## Introductory Programming Assignments (IPAs) Dataset + + +To generate our evaluation set of C programs we used [MultIPAs](https://github.com/pmorvalho/MultIPAs) [3], which is a program transformation framework, to augment our dataset of IPAs, [C-Pack-IPAs](https://github.com/pmorvalho/C-Pack-IPAs) [4]. + +## References + +[1] Pedro Orvalho, Jelle Piepenbrock, Mikoláš Janota, and Vasco Manquinho. Graph Neural Networks For Mapping Variables Between Programs. ECAI 2023. [PDF](). *[Accepted for Publication]* + +[2] Pedro Orvalho, Jelle Piepenbrock, Mikoláš Janota, and Vasco Manquinho. Project Proposal: Learning Variable Mappings to Repair Programs. AITP 2022. [PDF](http://aitp-conference.org/2022/abstract/AITP_2022_paper_15.pdf). + +[3] Pedro Orvalho, Mikoláš Janota, and Vasco Manquinho. MultIPAs: Applying Program Transformations to Introductory Programming Assignments for Data Augmentation. In 30th ACM Joint European Software Engineering Conference and Symposium on the Foundations of Software Engineering, ESEC/FSE 2022. [PDF](https://dl.acm.org/doi/10.1145/3540250.3558931). + +[4] Pedro Orvalho, Mikoláš Janota, and Vasco Manquinho. C-Pack of IPAs: A C90 Program Benchmark of Introductory Programming Assignments. 2022. [PDF](https://arxiv.org/pdf/2206.08768.pdf). \ No newline at end of file diff --git a/config_gnn.sh b/config_gnn.sh new file mode 100755 index 0000000..ea00ff8 --- /dev/null +++ b/config_gnn.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +#Title : config_gnn.sh +#Usage : bash config_gnn.sh +#Author : pmorvalho +#Date : July 29, 2022 +#Description : Jelle's commands to config the GNN's environment, plus the python packages needed to run MultIPAs +#Notes : +# (C) Copyright 2022 Pedro Orvalho. +#============================================================================== + +#!/usr/bin/env bash +source ~/anaconda3/etc/profile.d/conda.sh +conda create -n gnn_env python=3.9 +conda activate gnn_env +#conda install pytorch torchvision torchaudio cpuonly -c pytorch +#pip3 install torch torchvision torchaudio +pip install torch==1.11.0+cpu torchvision==0.12.0+cpu torchaudio==0.11.0 --extra-index-url https://download.pytorch.org/whl/cpu +# check with nvidia-smi if the 'cu102' should be replaced with another cuda version +pip install torch-scatter torch-sparse torch-cluster torch-spline-conv torch-geometric -f https://data.pyg.org/whl/torch-1.11.0+cpu.html +pip install pycparser==2.21 +conda activate gnn_env + + diff --git a/eval-dataset.zip b/eval-dataset.zip new file mode 100644 index 0000000..20e7d33 Binary files /dev/null and b/eval-dataset.zip differ diff --git a/eval.py b/eval.py new file mode 100644 index 0000000..b19a2d1 --- /dev/null +++ b/eval.py @@ -0,0 +1,110 @@ +import argparse +from sys import argv +import gzip +import pickle +from gnn import VariableMappingGNN +import torch +import time +import gzip + +def preprocess_data_test_time(left_ast, right_ast): + left_edge_index_pairs = [] + left_edge_types = [] + for triple in left_ast['edges']: + left_edge_index_pairs.append([triple[0], triple[1]]) + left_edge_types.append(triple[2]) + + left_node_types = [left_ast['nodes2types'][k] for k in left_ast['nodes2types']] + + right_edge_index_pairs = [] + right_edge_types = [] + + for triple in right_ast['edges']: + right_edge_index_pairs.append([triple[0], triple[1]]) + right_edge_types.append(triple[2]) + + right_node_types = [right_ast['nodes2types'][k] for k in right_ast['nodes2types']] + + # var_norm_index = {k: e for (e, k) in enumerate(left_ast['vars2id'])} + # var_norm_index2 = {k: e for (e, k) in enumerate(right_ast['vars2id'])} + + left_node_types = torch.as_tensor(left_node_types) + right_node_types = torch.as_tensor(right_node_types) + + left_edge_index_pairs = torch.as_tensor(left_edge_index_pairs) + right_edge_index_pairs = torch.as_tensor(right_edge_index_pairs) + + left_edge_types = torch.as_tensor(left_edge_types) + right_edge_types = torch.as_tensor(right_edge_types) + + return ((left_node_types, left_edge_index_pairs, left_edge_types, left_ast), + (right_node_types, right_edge_index_pairs, right_edge_types, right_ast)) + +def load_model(model_location): + device = "cpu" + with gzip.open("types2int.pkl.gz", 'rb') as f: + node_type_mapping = pickle.load(f) + print(node_type_mapping) + # find maximum index + num_types = node_type_mapping['diff_types'] + print(num_types) + + gnn = VariableMappingGNN(num_types, device).to(device) + + gnn.load_state_dict( + torch.load(model_location, map_location=torch.device('cpu'))) + + return gnn + +def predict(gnn_model, left_ast_file, right_ast_file): + + with gzip.open(left_ast_file, 'rb') as f: + left_ast = pickle.load(f) + + with gzip.open(right_ast_file, 'rb') as f: + right_ast = pickle.load(f) + + left_ast, right_ast = preprocess_data_test_time(left_ast, right_ast) + + op_var_dict, op_dist_dict = gnn_model.test_time_output((left_ast, right_ast)) + + return op_var_dict, op_dist_dict + +def save_var_maps(var_dict, p_name): + fp=gzip.open(p_name,'wb') + pickle.dump(var_dict,fp) + fp.close() + + +def parser(): + parser = argparse.ArgumentParser(prog='prog_fixer.py', formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('-ia', '--inc_ast', help='Incorrect Program\'s AST.') + parser.add_argument('-ca', '--cor_ast', help='Correct program\'s AST.') + parser.add_argument('-m', '--var_map', help='Variable mapping Path.') + parser.add_argument('-md', '--var_map_dist', help='Path for the each variable mapping distribution.') + parser.add_argument('-gm', '--gnn_model', help='GNN model to use.') + parser.add_argument('-t', '--time', help='File where the time spent predicting the model will be written to.') + parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Prints debugging information.') + args = parser.parse_args(argv[1:]) + return args + + +if __name__ == "__main__": + args = parser() + + model_location = args.gnn_model + model = load_model(model_location) + + buggy_ast_file = args.inc_ast + correct_ast_file = args.cor_ast + + time_0 = time.time() + model_output, model_output_distributions = predict(model, buggy_ast_file, correct_ast_file) + time_f = time.time()-time_0 + with open(args.time, 'w+') as writer: + writer.writelines("Time: {t}".format(t=round(time_f,3))) + + print(model_output) + save_var_maps(model_output, args.var_map) + save_var_maps(model_output_distributions, args.var_map_dist) + # TODO Use the {model_output_distributions} to sample diff --git a/gen_eval_dataset.py b/gen_eval_dataset.py new file mode 100755 index 0000000..4ffb930 --- /dev/null +++ b/gen_eval_dataset.py @@ -0,0 +1,65 @@ +#!/usr/bin/python +#Title : gen_eval_dataset.py +#Usage : python gen_eval_dataset.py -h +#Author : pmorvalho +#Date : July 25, 2022 +#Description : For each program mutation and mutilation configuration (input dir), this script chooses randomly a mutilated program for each student and guarantes that this program is semantically incorrect. +#Notes : +#Python Version: 3.8.5 +# (C) Copyright 2022 Pedro Orvalho. +#============================================================================== + +import argparse +from sys import argv +import os +import random + +from helper import * + + +def choose_incorrect_programs(input_dir, output_dir): + subfolders = [f.path for f in os.scandir(input_dir) if f.is_dir()] + for sf in subfolders: + stu_id = str(sf).split("/")[-1] + # print(sf+"/") + muts = list(pathlib.Path(sf+"/").glob('*/')) # mutations directories + prog_found = False + while len(muts) > 0 and not prog_found: + mut = random.sample(muts, 1)[0] + muts.remove(mut) + m = int(str(mut).split("/")[-1].replace("-","")) + if m == 0: # ignoring programs that were not mutated (index 0, 00, 000). E.g. programs that have a for-loop and are inside the for2while directory. + print("Ignoring ", mut) + continue + progs = list(pathlib.Path("{d}".format(d=mut)).glob('*.c')) # mutilated programs + while len(progs) > 0: + p = random.sample(progs, 1)[0] + progs.remove(p) + p = str(p) + if not check_program(p, args.ipa): + prog_found=True + if args.verbose: + print("Program ",p, " has been chosen.") + p=p.split("/")[-1][:-2] + os.system("cp {d}/{p}.c {o}/{s}.c".format(d=mut, p=p, o=args.output_dir, s=stu_id)) + os.system("cp {d}/ast-{p}.pkl.gz {o}/ast-{s}.pkl.gz".format(d=mut, p=p, o=args.output_dir, s=stu_id)) + os.system("cp {d}/bug_map-{z}-{p}.pkl.gz {o}/bug_map-{s}.pkl.gz".format(d=mut, z="0"*len(p),p=p, o=args.output_dir, s=stu_id)) + os.system("cp {d}/var_map-{z}_{p}.pkl.gz {o}/var_map-{s}.pkl.gz".format(d=mut, z="0"*len(p),p=p, o=args.output_dir, s=stu_id)) + os.system("rm {d}/*.o".format(d=mut)) + break + # os.system("rm {d}/*.o".format(d=mut)) + + +def parser(): + parser = argparse.ArgumentParser(prog='gen_eval_dataset.py', formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('-d', '--input_dir', nargs='?',help='input directory.') + parser.add_argument('-e', '--ipa', help='Name of the lab and exercise (IPA) so we can check the IO tests.') + parser.add_argument('-i', '--ignore', action='store_true', default=False, help='ignores...') + parser.add_argument('-o', '--output_dir', nargs='?', help='the name of the output dir.') + parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Prints debugging information.') + args = parser.parse_args(argv[1:]) + return args + +if __name__ == '__main__': + args = parser() + choose_incorrect_programs(args.input_dir, args.output_dir) diff --git a/gen_gnn_variable_mappings.sh b/gen_gnn_variable_mappings.sh new file mode 100755 index 0000000..3a734fe --- /dev/null +++ b/gen_gnn_variable_mappings.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +#Title : gen_gnn_variable_mappings.sh +#Usage : bash gen_gnn_variable_mappings.sh +#Author : pmorvalho +#Date : July 29, 2022 +#Description : Generates a var mapping for each pair of incorrect/correct programs in the eval dataset using the GNN +#Notes : +# (C) Copyright 2022 Pedro Orvalho. +#============================================================================== + +# to activate clara python-environment +if [ -f ~/opt/anaconda3/etc/profile.d/conda.sh ]; then + # if running on MacOS + source ~/opt/anaconda3/etc/profile.d/conda.sh +else + # if running on ARSR Machines (Linux) + source ~/anaconda3/etc/profile.d/conda.sh +fi + +conda activate gnn_env + +initial_dir=$(pwd) +data_dir="eval-dataset" +gnn_models_dir="gnn_models" +var_maps_dir=$initial_dir"/variable_mappings" +TIMEOUT_REPAIR=600 # in seconds + +#labs=("lab02" "lab03" "lab04") # we are not considering lab05 for this dataset, and only year 2020/2021 has lab05. +labs=("lab02") +# we will only use lab02 of the second year as the evaluation dataset +# models=("wco" "vm" "ed" "all") +#models=("wco") +#models=("vm") +#models=("ed") +models=("all") + +for((m=0;m<${#models[@]};m++)); +do + model=${models[$m]} + echo $model + results_dir="results/var_maps-"$model + mkdir -p $results_dir + for((l=0;l<${#labs[@]};l++)); + do + lab=${labs[$l]} + for ex in $(find $data_dir/incorrect_submissions/$lab/ex* -maxdepth 0 -type d); + do + ex=$(echo $ex | rev | cut -d '/' -f 1 | rev) + for mut_dir in $(find $data_dir/incorrect_submissions/$lab/$ex/* -maxdepth 0 -mindepth 0 -type d); + do + mut=$(echo $mut_dir | rev | cut -d '/' -f 1 | rev) + for mutl_dir in $(find $data_dir/incorrect_submissions/$lab/$ex/$mut/* -maxdepth 0 -mindepth 0 -type d); + do + mutl=$(echo $mutl_dir | rev | cut -d '/' -f 1 | rev) + echo "Dealing with "$mutl_dir + for p in $(find $data_dir/incorrect_submissions/$lab/$ex/$mut/$mutl/*.c -maxdepth 0 -mindepth 0 -type f); + do + stu_id=$(echo $p | rev | cut -d '/' -f 1 | rev) + stu_id=$(echo $stu_id | sed "s/.c//g") + d=$results_dir/$lab/$ex/$mut/$mutl/$stu_id-$model + mkdir -p $d $initial_dir/variable_mappings/$model/$lab/$ex/$mut/$mutl + c_prog_ast=$(find $data_dir/correct_submissions/$lab/$ex/"ast-"$stu_id* -type f | tail -n 1) + i_prog_ast=$mutl_dir/"ast-"$stu_id".pkl.gz" + gnn_model=$(find $gnn_models_dir/$model*.pt -type f | tail -1 ) + # /home/pmorvalho/runsolver/src/runsolver -o $d/out.o -w $d/watcher.w -v $d/var.v -W $TIMEOUT_REPAIR --rss-swap-limit 32000 \ + python3 eval.py -ia $i_prog_ast -ca $c_prog_ast -m $var_maps_dir/$model/$lab/$ex/$mut/$mutl"/var_map-"$stu_id".pkl.gz" -md $var_maps_dir/$model/$lab/$ex/$mut/$mutl"/var_map_distributions-"$stu_id".pkl.gz" -gm $gnn_model -t $d/var_map_time.txt > $d/out.o + done + # wait + done + done + done + done +done + diff --git a/gen_progs_repr.py b/gen_progs_repr.py new file mode 100755 index 0000000..3cff6ae --- /dev/null +++ b/gen_progs_repr.py @@ -0,0 +1,709 @@ +#!/usr/bin/python +#Title : gen_progs_repr.py +#Usage : python gen_progs_repr.py -h +#Author : pmorvalho +#Date : May 02, 2022 +#Description : ProgReprGNNVisitor tries to represent a program as a list of edges of the AST's nodes, each node has a type and each variable is represented by a unique id (the id of the node where the variable first appeared) +#Notes : +#Python Version: 3.8.5 +# (C) Copyright 2022 Pedro Orvalho. +#============================================================================== + +import argparse +from sys import argv +from helper import * +from numpy import binary_repr +import pickle +import gzip +import pathlib +import random + + +# Edge types: 0: AST, 1: children order +# AST edges are the edges one can encounter in the AST +AST_EDGE=0 +# Child edges establish an order between the children of an AST node. +CHILD_EDGE=1 +# Write edges are connections between an ID node and its variable node. This edge indicates that the variable is being written. +WRITE_EDGE=2 +# Read edges are connections between an ID node and its variable node. This edge indicates that the variable is being read. +READ_EDGE=3 +# Chrono edges to establish an order between all the ID nodes connected to some variable +CHRONO_EDGE=4 + +incr_decr_ops = ["p++", "++", "--", "p--"] + +#----------------------------------------------------------------- +# A visitor that represents a program as a list of lists of edges in the AST, a dictionary connecting each node to its type and a mapping between variables and the node_id that represents each variable. +class ProgReprGNNVisitor(c_ast.NodeVisitor): + + def __init__ (self): + super().__init__() + self.edge_list = list() + self.type_map = dict() + self.var_ids = dict() + self.var_nodes = dict() # We are going to save all nodes where a given variable appears, at the end we are going to replace all of these nodes by the same node id. + self.write_IDs = list() + self.read_IDs = list() + self.node_IDs_ordered = dict() + + + def _repr_node(self, n_id, n_type): + self.type_map[n_id] = get_type_id(n_type) + if args.verbose: + print("Node id:{i} of type {t}".format(i=n_id, t=n_type)) + + def add_variable_edge(self, id_node): + if id_node in self.var_nodes.keys(): + v_id = self.var_ids[self.var_nodes[id_node]] + del self.var_nodes[id_node] + if id_node in self.write_IDs and id_node in self.read_IDs: + if args.verbose: + print("variable edge (write and read) added: ", id_node, v_id) + return [[id_node, v_id, AST_EDGE],[v_id, id_node, AST_EDGE], [id_node, v_id, WRITE_EDGE], [v_id, id_node, READ_EDGE]] + elif id_node in self.write_IDs: + if args.verbose: + print("variable edge (write) added: ", id_node, v_id) + return [[id_node, v_id, AST_EDGE],[v_id, id_node, AST_EDGE], [id_node, v_id, WRITE_EDGE]] + else: + if args.verbose: + print("variable edge (read) added: ", id_node, v_id) + return [[id_node, v_id, AST_EDGE],[v_id, id_node, AST_EDGE], [v_id, id_node, READ_EDGE]] + return [] + + def connect_variable_nodes(self): + double_edges = [] + id_2_var_edges = [] + for e in range(len(self.edge_list)): + n1, n2, t = self.edge_list[e] + id_2_var_edges += self.add_variable_edge(n1) + self.add_variable_edge(n2) + if t == AST_EDGE: + double_edges.append([n2, n1, t]) + + self.edge_list += double_edges + self.edge_list += id_2_var_edges + + def add_chrono_edges(self): + for v in self.node_IDs_ordered.keys(): + id_nodes = self.node_IDs_ordered[v] + for n1 in range(len(id_nodes)-1): + id_1 = id_nodes[n1] + id_2 = id_nodes[n1+1] + if args.verbose: + print("Adding CHRONO edges:", id_1, id_2) + self.edge_list.append([id_1, id_2, CHRONO_EDGE]) + + _method_cache = None + + def visit(self, node, n_id): + """ Visit a node. + """ + + if self._method_cache is None: + self._method_cache = {} + + visitor = self._method_cache.get(node.__class__.__name__, None) + if visitor is None: + method = 'visit_' + node.__class__.__name__ + visitor = getattr(self, method, self.generic_visit) + self._method_cache[node.__class__.__name__] = visitor + + return visitor(node, n_id) + + def visit_FileAST(self, node, n_id): + #print('****************** Found FileAST Node *******************') + n_ext = [] + fakestart_pos = -1 #for the case of our injected function which do not have the fakestart function in their ast + for e in range(len(node.ext)): + x = node.ext[e] + # n_ext.append(self.visit(x, node_id(x.coord))) + if isinstance(x, c_ast.FuncDef) and "fakestart" in x.decl.type.type.declname: + fakestart_pos=e + + id_prev_child = -1 + for e in range(fakestart_pos+1, len(node.ext)): + x = node.ext[e] + n_ext.append(self.visit(x, node_id(x.coord))) + if id_prev_child != -1: + self.edge_list.append([id_prev_child, node_id(node.coord), CHILD_EDGE]) + id_prev_child = node_id(node.coord) + + n_file_ast = c_ast.FileAST(n_ext) + + self.connect_variable_nodes() + self.add_chrono_edges() + + + return n_file_ast + + def visit_Decl(self, node, n_id): + # print('****************** Found Decl Node *******************') + self._repr_node(n_id, "Decl") + id_prev_child=-1 + if node.name not in self.var_ids.keys() and isinstance(node.type, c_ast.TypeDecl): + id_prev_child = node_id(node.coord, t="-decl-var") + self.edge_list.append([n_id, id_prev_child, AST_EDGE]) + self.var_ids[node.name] = id_prev_child + self._repr_node(id_prev_child, "Var-"+node.type.type.names[0]) + elif isinstance(node.type, c_ast.ArrayDecl): + id_prev_child = node_id(node.type.coord, t="-decl-array") + self.edge_list.append([n_id, id_prev_child, AST_EDGE]) + self.type = self.visit(node.type, id_prev_child) + # else: + # id_prev_child = node_id(node.coord, t="-decl-var") + # self.var_ids[node.name] = id_prev_child + # self.edge_list.append([n_id, self.var_ids[node.name], AST_EDGE]) + + if not isinstance(node.type, c_ast.TypeDecl) and not isinstance(node.type, c_ast.ArrayDecl): + if node.init is not None: + new_child = node_id(node.init.coord, t="-decl-init") + if id_prev_child != -1: + self.edge_list.append([id_prev_child, new_child, CHILD_EDGE]) + + self.edge_list.append([n_id, new_child, AST_EDGE]) + node.init = self.visit(node.init, new_child) + id_prev_child=new_child + + # because it can be other type of declaration. Like func declarations. + new_child = node_id(node.type.coord, t="decl-type") + if id_prev_child != -1: + self.edge_list.append([id_prev_child, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + node.type = self.visit(node.type, new_child) + return node + + if node.init is not None: + new_child = node_id(node.init.coord, t="-decl-init") + if id_prev_child != -1: + self.edge_list.append([id_prev_child, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + node.init = self.visit(node.init, new_child) + + return node + + def visit_TypeDecl(self, node, n_id): + # print('****************** Found Type Decl Node *******************') + # attrs: declname, quals, align, type + self._repr_node(n_id, "TypeDecl") + if node.declname not in self.var_ids.keys(): + # id_prev_child = node_id(node.coord, t="TypeDecl-"+node.type.names[0]) + self.var_ids[node.declname] = n_id + else: + id_prev_child = self.var_ids[node.declname] + self.edge_list.append([n_id, id_prev_child, AST_EDGE]) + # self.type = self.visit(node.type) + return node + + def visit_ArrayDecl(self, node, n_id): + # print('****************** Found Array Decl Node *******************') + self._repr_node(n_id, "ArrayDecl") + child_id = node_id(node.type.coord, t="ptr-decl") + self.edge_list.append([n_id, child_id, AST_EDGE]) + node.type = self.visit(node.type, child_id) + # return node + # if node.type.declname not in self.var_ids.keys(): + # id_prev_child = node_id(node.coord, t="Array-"+node.type.type.names[0]) + # self.var_ids[node.type.declname] = id_prev_child + # else: + # id_prev_child = self.var_ids[node.type.declname] + # self.edge_list.append([n_id, id_prev_child, AST_EDGE]) + # self._repr_node(id_prev_child, "Array-"+node.type.type.names[0]) + id_prev_child = child_id + if node.dim is not None: + new_child = node_id(node.dim.coord, t="-array-dim") + self.edge_list.append([id_prev_child, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + node.dim = self.visit(node.dim, new_child) + return node + + def visit_PtrDecl(self, node, n_id): + #print('****************** Found Pointer Decl Node *******************') + self._repr_node(n_id, "PtrDecl") + child_id = node_id(node.type.coord, t="ptr-decl") + self.edge_list.append([n_id, child_id, AST_EDGE]) + node.type = self.visit(node.type, child_id) + return node + + def visit_ArrayRef(self, node, n_id): + #print('****************** Found Array Ref Node *******************') + self._repr_node(n_id, "ArrayRef") + id_prev_child = node_id(node.name.coord, t="array-name") + self.edge_list.append([n_id, id_prev_child, AST_EDGE]) + node.name = self.visit(node.name, id_prev_child) + new_child = node_id(node.subscript.coord, t="array-sub") + self.edge_list.append([id_prev_child, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + node.subscript = self.visit(node.subscript, new_child) + return node + + def visit_Assignment(self, node, n_id): + # print('****************** Found Assignment Node *******************') + self._repr_node(n_id, "Assignment") + id_prev_child = node_id(node.rvalue.coord, t="-rvalue") + self.edge_list.append([n_id, id_prev_child, AST_EDGE]) + node.rvalue = self.visit(node.rvalue, id_prev_child) + new_child = node_id(node.lvalue.coord, t="-lvalue") + self.edge_list.append([id_prev_child, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + node.lvalue = self.visit(node.lvalue, new_child) + if isinstance(node.lvalue, c_ast.ID): + if args.verbose: + print("Writing to variable in assignment in", new_child) + self.write_IDs.append(new_child) + self.read_IDs.remove(new_child) + return node + + def visit_ID(self, node, n_id): + #print('****************** Found ID Node *******************') + self._repr_node(n_id, "ID") + # the following is always true assuming that the variable is declared before being used + if node.name in self.var_ids.keys(): + self.var_nodes[n_id] = node.name + else: + child_id = node_id(node.coord, t="-decl-var") + # self.edge_list.append([n_id, child_id, AST_EDGE]) + self.var_ids[node.name] = child_id + # append every Id node that uses variable "name" + if node.name in self.node_IDs_ordered.keys(): + self.node_IDs_ordered[node.name].append(n_id) + else: + self.node_IDs_ordered[node.name] = [n_id] + # every ID is considered a read node, in case of assignment and & operators this read node will be removed afterwards + self.read_IDs.append(n_id) + return node + + def visit_Constant(self, node, n_id): + #print('****************** Found Constant Node *******************') + self._repr_node(n_id, "Constant-"+str(node.value)) + return node + + def visit_ExprList(self, node, n_id): + # print('****************** Found ExprList Node *******************') + self._repr_node(n_id, "ExprList") + id_prev_child=-1 + for e in node.exprs: + new_child = node_id(e.coord, t="-exp") + if id_prev_child != -1: + self.edge_list.append([id_prev_child, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + e = self.visit(e, new_child) + id_prev_child = new_child + return node + + def visit_ParamList(self, node, n_id): + # print('****************** Found ParamList Node *******************') + self._repr_node(n_id, "ParamList") + id_prev_child=-1 + for e in node.params: + new_child = node_id(e.coord, t="-param") + if id_prev_child != -1: + self.edge_list.append([id_prev_child, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + e = self.visit(e, new_child) + id_prev_child = new_child + return node + + def visit_Cast(self, node, n_id): + #print('******************** Found Cast Node *********************') + self._repr_node(n_id, "Cast") + child_id = node_id(node.expr.coord, t="-exp-cast") + self.edge_list.append([n_id, child_id, AST_EDGE]) + node.expr = self.visit(node.expr, child_id) + return node + + def visit_UnaryOp(self, node, n_id): + #print('****************** Found Unary Operation *******************') + self._repr_node(n_id, "UnaryOp-"+node.op) + child_id = node_id(node.expr.coord, t="-exp"+node.op) + self.edge_list.append([n_id, child_id, AST_EDGE]) + node.expr = self.visit(node.expr, child_id) + if (node.op == "&" or node.op in incr_decr_ops) and isinstance(node.expr, c_ast.ID): + if args.verbose: + print("Writing to variable with ", node.op," operator in", child_id) + self.write_IDs.append(child_id) + if node.op == "&": + self.read_IDs.remove(child_id) + return node + + def visit_BinaryOp(self, node, n_id): + #print('****************** Found Binary Operation *******************') + self._repr_node(n_id, "BinaryOp-"+node.op) + left_id = node_id(node.left.coord, t="-left"+node.op) + self.edge_list.append([n_id, left_id, AST_EDGE]) + left = self.visit(node.left, left_id) + right_id = node_id(node.right.coord, t="-right"+node.op) + self.edge_list.append([left_id, right_id, CHILD_EDGE]) + self.edge_list.append([n_id, right_id, AST_EDGE]) + right = self.visit(node.right, right_id) + return c_ast.BinaryOp(node.op, left, right, node.coord) + + def visit_TernaryOp(self, node, n_id): + #print('****************** Found TernaryOp Node *******************') + self._repr_node(n_id, "TernaryOp") + id_prev_child=node_id(node.cond.coord, t="-cond") + self.edge_list.append([n_id, id_prev_child, AST_EDGE]) + n_cond = self.visit(node.cond, id_prev_child) + new_child = node_id(node.iftrue.coord, t="-iftrue") + self.edge_list.append([n_id, new_child, AST_EDGE]) + self.edge_list.append([id_prev_child, new_child, CHILD_EDGE]) + if isinstance(node.iftrue, c_ast.Compound): + n_iftrue = self.visit(node.iftrue, new_child) + else: + n_iftrue = self.visit(c_ast.Compound([node.iftrue], node.iftrue.coord), new_child) + id_prev_child = new_child + n_iffalse = node.iffalse + if node.iffalse is not None and not isinstance(node.iffalse, c_ast.Compound): + node.iffalse = c_ast.Compound([node.iffalse], node.iffalse.coord) + if node.iffalse: + new_child = node_id(node.iffalse.coord, t="-iffalse") + self.edge_list.append([id_prev_child, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + n_iffalse = self.visit(node.iffalse, new_child) + #print('****************** New Cond Node *******************') + n_ternary = c_ast.TernaryOp(n_cond, n_iftrue, n_iffalse, node.coord) + return n_ternary + + def visit_DeclArgs(self, node, parent_id): + #print('****************** Found Declaration/Definition Parameters *******************') + # deals with args in the declarations and definitions of functions + child_id=None + if node.args: + child_id=node_id(node.args.coord, t="-larg") + self.edge_list.append([parent_id, child_id, AST_EDGE]) + node.args = self.visit(node.args, child_id) + + return node, child_id + + def visit_FuncDecl(self, node, n_id): + #print('****************** Found FuncDecl Node *******************') + self._repr_node(n_id, "FuncDecl") + node, _ = self.visit_DeclArgs(node, n_id) + return node + + def visit_FuncDef(self, node, n_id): + #print('****************** Found FuncDef Node *******************') + self._repr_node(n_id, "FuncDef") + decl = node.decl + param_decls = node.param_decls + id_prev_child=-1 + if node.param_decls: + id_prev_child=node_id(node.param_decls.coord, t="-param") + self.edge_list.append([n_id, id_prev_child, AST_EDGE]) + param_decls = self.visit(node.param_decls, id_prev_child) + if "main" != node.decl.name and "fakestart" != node.decl.name: #ignore main function + # if the function has parameters add them to the scope + decl, child_id = self.visit_DeclArgs(decl.type, n_id) + if child_id != None: + if id_prev_child != -1: + self.edge_list.append([id_prev_child, child_id, CHILD_EDGE]) + id_prev_child=child_id + + body = node.body + coord = node.coord + new_child = node_id(node.body.coord, t="-body") + if id_prev_child != -1: + self.edge_list.append([id_prev_child, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + n_body_1 = self.visit(body, new_child) + n_func_def_ast = c_ast.FuncDef(decl, param_decls, n_body_1, coord) + + return n_func_def_ast + + def visit_FuncCall(self, node, n_id): + #print('****************** Found FuncCall Node *******************') + self._repr_node(n_id, "FuncCall") + if node.args: + child_id = node_id(node.args.coord, t="-args") + self.edge_list.append([n_id, child_id, AST_EDGE]) + node.args = self.visit(node.args, child_id) + return c_ast.FuncCall(node.name, node.args, node.coord) + + def visit_Compound(self, node, n_id): + #print('****************** Found Compound Node *******************') + self._repr_node(n_id, "Block") + + block_items = node.block_items + coord = node.coord + n_block_items = [] + id_prev_child=-1 + if block_items is not None: + for x in block_items: + new_child=node_id(x.coord, t="-inst") + if id_prev_child != -1: + self.edge_list.append([id_prev_child, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + n_block_items.append(self.visit(x, new_child)) + id_prev_child = new_child + + n_compound_ast = c_ast.Compound(n_block_items, coord) + return n_compound_ast + + def visit_If(self, node, n_id): + #print('****************** Found IF Node *******************') + self._repr_node(n_id, "If") + id_prev_child=node_id(node.cond.coord, t="-cond") + self.edge_list.append([n_id, id_prev_child, AST_EDGE]) + n_cond = self.visit(node.cond, id_prev_child) + new_child = node_id(node.iftrue.coord, t="-iftrue") + self.edge_list.append([id_prev_child, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + n_iftrue = self.visit(node.iftrue, new_child) + if isinstance(node.iftrue, c_ast.Compound): + n_iftrue = self.visit(node.iftrue, new_child) + else: + n_iftrue = self.visit(c_ast.Compound([node.iftrue], node.iftrue.coord), new_child) + + id_prev_child = new_child + n_iffalse = node.iffalse + if node.iffalse is not None and not isinstance(node.iffalse, c_ast.Compound): + node.iffalse = c_ast.Compound([node.iffalse], node.iffalse.coord) + if node.iffalse: + new_child = node_id(node.iffalse.coord, t="-iffalse") + self.edge_list.append([id_prev_child, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + n_iffalse = self.visit(node.iffalse, new_child) + #print('****************** New Cond Node *******************') + n_if = c_ast.If(n_cond, n_iftrue, n_iffalse, node.coord) + return n_if + + def visit_For(self, node, n_id): + #print('****************** Found For Node *******************') + self._repr_node(n_id, "For") + id_prev_child = -1 + if node.init is not None: + id_prev_child = node_id(node.init.coord, t="-init") + self.edge_list.append([n_id, id_prev_child, AST_EDGE]) + n_init = self.visit(node.init, id_prev_child) + new_child = node_id(node.cond.coord, t="-cond") + if id_prev_child != -1: + self.edge_list.append([id_prev_child, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + n_cond = self.visit(node.cond, new_child) + id_prev_child = new_child + if not isinstance(node.stmt, c_ast.Compound): + node.stmt = c_ast.Compound([node.stmt], node.stmt.coord) + new_child = node_id(node.stmt.coord, t="-stmt") + self.edge_list.append([id_prev_child, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + n_stmt = self.visit(node.stmt, new_child) + id_prev_child = new_child + n_next = node.next + if n_next is not None: + new_child = node_id(node.next.coord, t="-next") + self.edge_list.append([id_prev_child, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + n_next = self.visit(node.next, new_child) + # We dont need to put a scope_info at the end of the for because the compound node already does that + n_for = c_ast.For(n_init, n_cond, n_next, n_stmt, node.coord) + return n_for + + def visit_While(self, node, n_id): + #print('****************** Found While Node *******************') + self._repr_node(n_id, "While") + child_id = node_id(node.cond.coord, t="-cond") + self.edge_list.append([n_id, child_id, AST_EDGE]) + n_cond = self.visit(node.cond, child_id) + if not isinstance(node.stmt, c_ast.Compound): + node.stmt = c_ast.Compound([node.stmt], node.stmt.coord) + new_child = node_id(node.stmt.coord, t="-stmt") + self.edge_list.append([child_id, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + n_stmt = self.visit(node.stmt, new_child) + n_while = c_ast.While(n_cond, n_stmt, node.coord) + return n_while + + def visit_DoWhile(self, node, n_id): + #print('****************** Found DoWhile Node *******************') + self._repr_node(n_id, "DoWhile") + child_id = node_id(node.cond.coord, t="-cond") + self.edge_list.append([n_id, child_id, AST_EDGE]) + n_cond = self.visit(node.cond, child_id) + if not isinstance(node.stmt, c_ast.Compound): + node.stmt = c_ast.Compound([node.stmt], node.stmt.coord) + new_child = node_id(node.stmt.coord, t="-stmt") + self.edge_list.append([child_id, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + n_stmt = self.visit(node.stmt, new_child) + n_dowhile = c_ast.DoWhile(n_cond, n_stmt, node.coord) + return n_dowhile + + def visit_Switch(self, node, n_id): + #print('****************** Found Switch Node *******************') + self._repr_node(n_id, "Switch") + child_id = node_id(node.cond.coord, t="-cond") + self.edge_list.append([n_id, child_id, AST_EDGE]) + n_cond = self.visit(node.cond, child_id) + if not isinstance(node.stmt, c_ast.Compound): + node.stmt = c_ast.Compound([node.stmt], node.stmt.coord) + new_child = node_id(node.stmt.coord, t="-stmt") + self.edge_list.append([child_id, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + n_stmt = self.visit(node.stmt, new_child) + n_switch = c_ast.Switch(n_cond, n_stmt, node.coord) + return n_switch + + def visit_Return(self, node, n_id): + #print('****************** Found Return Node *******************') + self._repr_node(n_id, "Return") + if node.expr: + child_id = node_id(node.expr.coord, t="-expr") + self.edge_list.append([n_id, child_id, AST_EDGE]) + node.expr = self.visit(node.expr, child_id) + return node + + def visit_Break(self, node, n_id): + #print('****************** Found Break Node *******************') + self._repr_node(n_id, "Break") + return node + + def visit_Continue(self, node, n_id): + #print('****************** Found Continue Node *******************') + self._repr_node(n_id, "Continue") + return node + + def visit_Case(self, node, n_id): + #print('****************** Found Case Node *******************') + self._repr_node(n_id, "Case") + n_stmts_1 = [] + id_prev_child = -1 + for x in node.stmts: + new_child = node_id(x.coord, t="-stmt") + if id_prev_child != -1: + self.edge_list.append([id_prev_child, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + n_stmts_1.append(self.visit(x, new_child)) + id_prev_child = new_child + + n_stmts_2 = c_ast.Compound (n_stmts_1, node.coord) + return c_ast.Case(node.expr, n_stmts_2, node.coord) + + def visit_Default(self, node, n_id): + #print('****************** Found Default Node *******************') + self._repr_node(n_id, "Default") + n_stmts_1 = [] + id_prev_child = -1 + for x in node.stmts: + new_child = node_id(x.coord, t="-stmt") + if id_prev_child != -1: + self.edge_list.append([id_prev_child, new_child, CHILD_EDGE]) + self.edge_list.append([n_id, new_child, AST_EDGE]) + n_stmts_1.append(self.visit(x, new_child)) + id_prev_child = new_child + + n_stmts_2 = c_ast.Compound(n_stmts_1, node.coord) + return c_ast.Default(n_stmts_2, node.coord) + + def visit_EmptyStatement(self, node, n_id): + #print('****************** Found EmptyStatement Node *******************') + self._repr_node(n_id, "EmptyStatement") + return node + + def generic_visit(self, node, n_id): + #print('****************** Something else ************') + return node + +#----------------------------------------------------------------- + +def load_types_dict(): + dict_name = "types2int.pkl.gz" + if not os.path.exists(dict_name): + types2int = dict() + types2int["diff_types"] = 0 + else: + fp=gzip.open(dict_name,'rb') # This assumes that primes.data is already packed with gzip + types2int=pickle.load(fp) + fp.close() + + return types2int + +def save_types_dict(): + dict_name = "types2int.pkl.gz" + fp=gzip.open(dict_name,'wb') + pickle.dump(types2int,fp) + fp.close() + +def get_type_id(t): + global types2int + if t in types2int.keys(): + return types2int[t] + else: + cur_cnt = types2int["diff_types"] + types2int[t] = cur_cnt + types2int["diff_types"] = cur_cnt+1 + return cur_cnt + +def save_progs_repr(p_dict, p_dir, p, rep): + stu=str(p).split("/")[-1].replace(".c","") + file_name = p_dir+"/{r}-{s}.pkl.gz".format(s=stu, r=rep) + fp=gzip.open(file_name,'wb') + pickle.dump(p_dict,fp) + fp.close() + +#----------------------------------------------------------------- + +def gen_program_repr_gnn(progs_dir): + reprs = [] + progs = list(pathlib.Path(progs_dir).glob('*.c')) + + for p in progs: + prog_repr = dict() + tmp_dir = "/tmp/tmp-{n}".format(n=int(random.random()*100000000)) + inst_file, sincludes, includes = make_output_dir(p, tmp_dir) + try: + ast = parse_file(inst_file, use_cpp=True, + cpp_path='gcc', + cpp_args=['-E', '-Iutils/fake_libc_include']) + except: + print("Error on compiling program:", p) + os.system("echo {p} >> programs_generations_err-programs-compilation-errors.txt".format(p=p)) + continue + + reset_ids() + v = ProgReprGNNVisitor() + n_ast = v.visit(ast, 0) + # n_ast.show() + prog_repr["edges"] = v.edge_list + prog_repr["nodes2types"] = v.type_map + prog_repr["vars2id"] = v.var_ids + if args.verbose: + print("Edge list with {e} edges:".format(e=len(v.edge_list))) + print(v.edge_list) + print("Type map with {v} nodes:".format(v=len(v.type_map.keys()))) + print(v.type_map) + print("Var map with {v} variables:".format(v=len(v.var_ids.keys()))) + print(v.var_ids) + print("General type dict with {t} types:".format(t=len(types2int.keys())-1)) + print(types2int) + try: + max_node = max(v.type_map.keys())+1 + assert(len(v.type_map.keys()) == max_node) + for e in v.edge_list: + assert(max(e) <= max_node) + except: + print("ERROR Unvisited Nodes in {p}!!".format(p=p)) + os.system("echo {p} >> programs_generations_err-unvisited_nodes.txt".format(p=p)) + # exit() # considers only one program for now + os.system("rm -rf {t}".format(t=tmp_dir)) + save_progs_repr(prog_repr, progs_dir, p, "ast") + +#----------------------------------------------------------------- + +def parser(): + parser = argparse.ArgumentParser(prog='gen_progs_repr.py', formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('-d', '--input_dir', help='Name of the input directory.') + # parser.add_argument('-o', '--output_dir', help='Name of the output directory.') + parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Prints debugging information.') + args = parser.parse_args(argv[1:]) + return args + +if __name__ == "__main__": + args = parser() + if len(sys.argv) >= 2: + progs_dir = args.input_dir + types2int = load_types_dict() + gen_program_repr_gnn(progs_dir) + # the following is commented so we can run this script in parallel. This only works if the dictionary was already previously computed. + # save_types_dict() + else: + print('python {0} -h'.format(sys.argv[0])) + diff --git a/get_baseline_repairs.sh b/get_baseline_repairs.sh new file mode 100755 index 0000000..7b1b9ed --- /dev/null +++ b/get_baseline_repairs.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +#Title : get_baseline_repairs.sh +#Usage : bash get_baseline_repairs.sh +#Author : pmorvalho +#Date : April 19, 2023 +#Description : Runs our repair script using our baseline i.e. random variable mappings +#Notes : +# (C) Copyright 2023 Pedro Orvalho. +#============================================================================== + + +initial_dir=$(pwd) +data_dir="eval-dataset" +var_maps_dir=$initial_dir"/variable_mappings" +TIMEOUT_REPAIR=122 # in seconds + +#labs=("lab02" "lab03" "lab04") # we are not considering lab05 for this dataset, and only year 2020/2021 has lab05. +labs=("lab02") +# we will only use lab02 of the second year as the evaluation dataset +model="all" +bugs=("wco" "vm" "ed" "all") + +for((l=0;l<${#labs[@]};l++)); +do + lab=${labs[$l]} + for ex in $(find $data_dir/incorrect_submissions/$lab/ex* -maxdepth 0 -type d); + do + ex=$(echo $ex | rev | cut -d '/' -f 1 | rev) + for mut_dir in $(find $data_dir/incorrect_submissions/$lab/$ex/* -maxdepth 0 -mindepth 0 -type d); + do + mut=$(echo $mut_dir | rev | cut -d '/' -f 1 | rev) + for mutl_dir in $(find $data_dir/incorrect_submissions/$lab/$ex/$mut/* -maxdepth 0 -mindepth 0 -type d); + do + mutl=$(echo $mutl_dir | rev | cut -d '/' -f 1 | rev) + echo "Dealing with "$mutl_dir + for p in $(find $data_dir/incorrect_submissions/$lab/$ex/$mut/$mutl/*.c -maxdepth 0 -mindepth 0 -type f); + do + stu_id=$(echo $p | rev | cut -d '/' -f 1 | rev) + stu_id=$(echo $stu_id | sed "s/.c//g") + c_prog=$(find $data_dir/correct_submissions/$lab/$ex/*$stu_id*.c -type f | tail -n 1) + for((b=0;b<${#bugs[@]};b++)); + do + bug=${bugs[$b]} + results_dir="results/baseline" + mkdir -p $results_dir + d=$results_dir/$lab/$ex/$mut/$mutl/$stu_id-$bug + mkdir -p $d + # /home/pmorvalho/runsolver/src/runsolver -o $d/out.o -w $d/watcher.w -v $d/var.v -W $TIMEOUT_REPAIR --rss-swap-limit 32000 \ + python3 prog_fixer.py -ip $p -cp $c_prog -m $var_maps_dir/$model/$lab/$ex/$mut/$mutl/"var_map-"$stu_id".pkl.gz" -md $var_maps_dir/$model/$lab/$ex/$mut/$mutl/"var_map_distributions-"$stu_id".pkl.gz" --$bug --ipa $lab/$ex -o $d/$stu_id"-fixed" -v -b > $d/out.o & + done + wait + done + # wait + done + done + done +done + diff --git a/get_eval_dataset.sh b/get_eval_dataset.sh new file mode 100755 index 0000000..fb997cf --- /dev/null +++ b/get_eval_dataset.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +#Title : get_eval_dataset.sh +#Usage : bash get_eval_dataset.sh +#Author : pmorvalho +#Date : July 25, 2022 +#Description : Generates an evaluation dataset randomly selecting an incorrect program for each student, considering all the program mutations and mutilations configurations. +#Notes : +# (C) Copyright 2022 Pedro Orvalho. +#============================================================================== + +dataset="C-Pack-IPAs" +eval_dir="eval-dataset" + +#labs=("lab02" "lab03" "lab04") # we are not considering lab05 for this dataset, and only year 2020/2021 has lab05. +labs=("lab02") +years=("year-2") +# we will only use lab02 of the second year as the evaluation dataset + +data_dir="mutilated_programs" + +mkdir -p $eval_dir/incorrect_submissions + +NUM_CPU_CORES=$(nproc --all) #Automatically detects your system's number of CPU cores. +NUM_CPU_CORES=$((NUM_CPU_CORES-62)) +function pwait() { + while [ $(jobs -p | wc -l) -ge $NUM_CPU_CORES ]; do + sleep 1 + done +} + +for((y=0;y<${#years[@]};y++)); +do + ys=${years[$y]} + for((l=0;l<${#labs[@]};l++)); + do + lab=${labs[$l]} + mkdir -p $eval_dir/correct_submissions/ + cp -r $dataset/correct_submissions/$ys/$lab $eval_dir/correct_submissions/$lab & + done +done +wait + +for((y=0;y<${#years[@]};y++)); +do + ys=${years[$y]} + for((l=0;l<${#labs[@]};l++)); + do + lab=${labs[$l]} + for ex in $(find $data_dir/$ys/$lab/ex* -maxdepth 0 -type d); + do + ex=$(echo $ex | rev | cut -d '/' -f 1 | rev) + for mut_dir in $(find $data_dir/$ys/$lab/$ex/* -maxdepth 1 -mindepth 1 -type d); + do + echo $mut_dir + m=$(echo $mut_dir | sed "s/.*${ex}//g") + d=$eval_dir/incorrect_submissions/$lab/$ex/$m + mkdir -p $d + python3 gen_eval_dataset.py -d $mut_dir -o $d --ipa $lab/$ex + #pwait $NUM_CPU_CORES + done + wait + done + done +done diff --git a/get_gnn_based_repairs.sh b/get_gnn_based_repairs.sh new file mode 100755 index 0000000..d2d3a9b --- /dev/null +++ b/get_gnn_based_repairs.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +#Title : get_gnn_based_repairs.sh +#Usage : bash get_gnn_based_repairs.sh +#Author : pmorvalho +#Date : July 26, 2022 +#Description : Runs our repair script using the variable mappins produced by our GNN models +#Notes : +# (C) Copyright 2022 Pedro Orvalho. +#============================================================================== + +initial_dir=$(pwd) +data_dir="eval-dataset" +var_maps_dir=$initial_dir"/variable_mappings" +TIMEOUT_REPAIR=122 # in seconds + +#labs=("lab02" "lab03" "lab04") # we are not considering lab05 for this dataset, and only year 2020/2021 has lab05. +labs=("lab02") +# we will only use lab02 of the second year as the evaluation dataset +# models=("wco" "vm" "ed" "all") +#models=("wco" "all") +#models=("vm") +#models=("ed") +models=("all") +# bugs=("wco" "vm" "ed" "all") # to check for specific types of bugs +bugs=("all") + +for((m=0;m<${#models[@]};m++)); +do + model=${models[$m]} + echo $model + for((l=0;l<${#labs[@]};l++)); + do + lab=${labs[$l]} + for ex in $(find $data_dir/incorrect_submissions/$lab/ex* -maxdepth 0 -type d); + do + ex=$(echo $ex | rev | cut -d '/' -f 1 | rev) + for mut_dir in $(find $data_dir/incorrect_submissions/$lab/$ex/* -maxdepth 0 -mindepth 0 -type d); + do + mut=$(echo $mut_dir | rev | cut -d '/' -f 1 | rev) + for mutl_dir in $(find $data_dir/incorrect_submissions/$lab/$ex/$mut/* -maxdepth 0 -mindepth 0 -type d); + do + mutl=$(echo $mutl_dir | rev | cut -d '/' -f 1 | rev) + echo "Dealing with "$mutl_dir + for p in $(find $data_dir/incorrect_submissions/$lab/$ex/$mut/$mutl/*.c -maxdepth 0 -mindepth 0 -type f); + do + stu_id=$(echo $p | rev | cut -d '/' -f 1 | rev) + stu_id=$(echo $stu_id | sed "s/.c//g") + var_map=$initial_dir/variable_mappings/$model/$lab/$ex/$mut/$mutl"/var_map-"$stu_id".pkl.gz" + c_prog=$(find $data_dir/correct_submissions/$lab/$ex/*$stu_id*.c -type f | tail -n 1) + for((b=0;b<${#bugs[@]};b++)); + do + bug=${bugs[$b]} + results_dir="/data/benchmarks/variable-alignment/results/gnn-"$model + mkdir -p $results_dir + d=$results_dir/$lab/$ex/$mut/$mutl/$stu_id-$bug + mkdir -p $d + # /home/pmorvalho/runsolver/src/runsolver -o $d/out.o -w $d/watcher.w -v $d/var.v -W $TIMEOUT_REPAIR --rss-swap-limit 32000 \ + python3 prog_fixer.py -ip $p -cp $c_prog -m $var_maps_dir/$model/$lab/$ex/$mut/$mutl/"/var_map-"$stu_id".pkl.gz" -md $var_maps_dir/$model/$lab/$ex/$mut/$mutl/"/var_map_distributions-"$stu_id".pkl.gz" --$bug --ipa $lab/$ex -o $d/$stu_id"-fixed" -v > $d/out.o & + done + wait + done + # wait + done + done + # telegram-send $lab/$ex" is done!" + done + # telegram-send "$lab is done!" + done +done diff --git a/get_ground_truth_repairs.sh b/get_ground_truth_repairs.sh new file mode 100755 index 0000000..54ca2e2 --- /dev/null +++ b/get_ground_truth_repairs.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +#Title : get_ground_truth_repairs.sh +#Usage : bash get_ground_truth_repairs.sh +#Author : pmorvalho +#Date : July 26, 2022 +#Description : Runs our repair script considering the real (ground truth) variable mappings +#Notes : +# (C) Copyright 2022 Pedro Orvalho. +#============================================================================== + +initial_dir=$(pwd) +data_dir="eval-dataset" +results_dir="results/ground_truth/" + +TIMEOUT_REPAIR=122 # in seconds + +#labs=("lab02" "lab03" "lab04") # we are not considering lab05 for this dataset, and only year 2020/2021 has lab05. +labs=("lab02") +# we will only use lab02 of the second year as the evaluation dataset +bugs=("wco" "vm" "ed" "all") +mkdir -p $results_dir + +for((l=0;l<${#labs[@]};l++)); +do + lab=${labs[$l]} + for ex in $(find $data_dir/incorrect_submissions/$lab/ex* -maxdepth 0 -type d); + do + ex=$(echo $ex | rev | cut -d '/' -f 1 | rev) + for mut_dir in $(find $data_dir/incorrect_submissions/$lab/$ex/* -maxdepth 0 -mindepth 0 -type d); + do + mut=$(echo $mut_dir | rev | cut -d '/' -f 1 | rev) + for mutl_dir in $(find $data_dir/incorrect_submissions/$lab/$ex/$mut/* -maxdepth 0 -mindepth 0 -type d); + do + mutl=$(echo $mutl_dir | rev | cut -d '/' -f 1 | rev) + echo "Dealing with "$mutl_dir + for p in $(find $data_dir/incorrect_submissions/$lab/$ex/$mut/$mutl/*.c -maxdepth 0 -mindepth 0 -type f); + do + stu_id=$(echo $p | rev | cut -d '/' -f 1 | rev) + stu_id=$(echo $stu_id | sed "s/.c//g") + for((b=0;b<${#bugs[@]};b++)); + do + bug=${bugs[$b]} + #bug="all" + d=$results_dir/$lab/$ex/$mut/$mutl/$stu_id-$bug + mkdir -p $d + c_prog=$(find $data_dir/correct_submissions/$lab/$ex/*$stu_id*.c -type f | tail -n 1) + #/home/pmorvalho/runsolver/src/runsolver -o $d/out.o -w $d/watcher.w -v $d/var.v -W $TIMEOUT_REPAIR --rss-swap-limit 32000 \ + python3 prog_fixer.py -ip $p -cp $c_prog -m $mutl_dir"/var_map-"$stu_id".pkl.gz" --$bug --ipa $lab/$ex -o $d/$stu_id"-fixed" -v > $d/out.o & + done + wait + done + #wait + #assuming that this script and the GNN script are not running at the same time, we can execute the following: + rm -rf tmp-* + done + done + done +done + diff --git a/gnn.py b/gnn.py new file mode 100644 index 0000000..20b13b7 --- /dev/null +++ b/gnn.py @@ -0,0 +1,180 @@ +from torch_geometric.data import Data +from torch_geometric.nn import RGCNConv +import torch + +class VariableMappingGNN(torch.nn.Module): + + def __init__(self, num_types, device, message_passing_rounds=5, channels=32): + super().__init__() + + self.device = device + self.num_types = num_types + self.channels = channels + self.message_passing_rounds = message_passing_rounds + + self.left_conv = RGCNConv(in_channels=self.channels, out_channels=self.channels, num_relations=5, aggr="mean") + self.right_conv = RGCNConv(in_channels=self.channels, out_channels=self.channels, num_relations=5, aggr="mean") + + self.node_embeddings = torch.nn.Parameter(torch.randn(num_types, self.channels), requires_grad=True) + + self.var_projector = torch.nn.Sequential(torch.nn.Linear(self.channels, self.channels), torch.nn.ReLU(), torch.nn.Linear(self.channels, self.channels)) + + self.relu = torch.nn.ReLU() + self.ln = torch.nn.LayerNorm(self.channels) + + def initial_embedding(self, indices): + + return torch.index_select(self.node_embeddings, 0, torch.as_tensor(indices, device=self.device)) + + def message_passing(self, left_data, right_data): + + left_x = left_data.x + right_x = right_data.x + + for i in range(self.message_passing_rounds): + # print(left_x) + # print(left_x.shape) + # print(left_data.edge_index) + left_x = self.left_conv.forward(left_x, left_data.edge_index, left_data.edge_attr) + left_x = self.ln(left_x) + + left_x = self.relu(left_x) + right_x = self.right_conv.forward(right_x, right_data.edge_index, right_data.edge_attr) + right_x = self.ln(right_x) + right_x = self.relu(right_x) + + return left_x, right_x + + + def forward(self, left_ast, right_ast, left_data, right_data): + + + left_mp_output, right_mp_output = self.message_passing(left_data, right_data) + + varindex1 = torch.as_tensor([left_ast['vars2id'][k] for k in left_ast['vars2id']], device=self.device) + varindex2 = torch.as_tensor([right_ast['vars2id'][k] for k in right_ast['vars2id']], device=self.device) + + vars1 = torch.index_select(left_mp_output, 0, varindex1) + + # vars1 = vars1 + vars1.mean(axis=0) + vars2 = torch.index_select(right_mp_output, 0, varindex2) + # vars2 = vars2 + vars2.mean(axis=0) + + # vars1 = self.var_projector(vars1) + # vars2 = self.var_projector(vars2) + dot_products = torch.einsum('in, jn->ij', vars1, vars2) + + # probability_distributions = torch.softmax(dot_products, dim=1) + + num_vars_left_program = len(left_ast['vars2id']) + num_vars_right_program = len(right_ast['vars2id']) + + split_res = torch.tensor_split(dot_products, num_vars_left_program) + + return split_res, left_mp_output + + + def test_time_output(self, sample): + + left_sample, right_sample = sample + l_data = Data(x=self.initial_embedding(left_sample[0]), edge_index=left_sample[1].t().contiguous(), + edge_attr=left_sample[2]).to(self.device) + + r_data = Data(x=self.initial_embedding(right_sample[0]), edge_index=right_sample[1].t().contiguous(), + edge_attr=right_sample[2]).to(self.device) + output, leftmean = self.forward(left_sample[3], right_sample[3], l_data, r_data) + + # convert back to strings from id + vars_left = left_sample[3]['vars2id'] + vars_right = right_sample[3]['vars2id'] + + # print(vars_left) + # print(vars_right) + # print(output) + indices = [torch.argmax(k) for k in output] + distributions = [k.tolist() for k in output] + + vars_left_list = [k for k in vars_left] + vars_right_list = [k for k in vars_right] + + varmap_result = {} + varmap_dist = {} + for e, o in enumerate(indices): + varmap_result[vars_left_list[e]] = vars_right_list[int(indices[e].item())] + # print(varmap_result) + + # assert 2 > 3 + for e, o in enumerate(distributions): + varmap_dist[vars_left_list[e]] = (distributions[e], vars_right_list) + + return varmap_result, varmap_dist + + def train_step(self, sample, loss_function, optimizer): + optimizer.zero_grad() + left_sample, right_sample, labels, orig_spec = sample + + l_data = Data(x=self.initial_embedding(left_sample[0]), edge_index=left_sample[1].t().contiguous(), + edge_attr=left_sample[2]).to(self.device) + + r_data = Data(x=self.initial_embedding(right_sample[0]), edge_index=right_sample[1].t().contiguous(), + edge_attr=right_sample[2]).to(self.device) + output, leftmean = self.forward(left_sample[3], right_sample[3], l_data, r_data) + # global_orig_sample_list.append(orig_spec.parents[0]) + # global_representation_list.append(torch.mean(leftmean, dim=0).detach().cpu().numpy()) + total_loss = 0 + # print(labels) + # print(len(labels)) + for lab, spl in zip(labels, output): + # print(lab) + # print(torch.softmax(spl, dim=1)) + + l = loss_function(spl.reshape(1, -1), torch.tensor(lab, device=self.device).reshape(1)) + # print(l.item()) + total_loss += l + # print(total_loss.item()) + # print() + total_loss = total_loss / len(labels) + total_loss.backward() + # + optimizer.step() + + def eval_step(self, sample, loss_function): + + left_sample, right_sample, labels, _ = sample + + l_data = Data(x=self.initial_embedding(left_sample[0]), edge_index=left_sample[1].t().contiguous(), + edge_attr=left_sample[2]).to(self.device) + + r_data = Data(x=self.initial_embedding(right_sample[0]), edge_index=right_sample[1].t().contiguous(), + edge_attr=right_sample[2]).to(self.device) + output, leftmean = self.forward(left_sample[3], right_sample[3], l_data, r_data) + + total_loss = 0 + # + corr = 0 + total = 0 + for lab, spl in zip(labels, output): + # print(lab) + # print(torch.softmax(spl, dim=1)) + + # print(lab, torch.argmax(spl).item()) + if lab == torch.argmax(spl).item(): + + corr += 1 + + l = loss_function(spl.reshape(1, -1), torch.tensor(lab, device=self.device).reshape(1)) + # print(l.item()) + total_loss += l + + total += 1 + + if total == corr: + fully_correct = 1 + else: + fully_correct = 0 + # print(total_loss.item()) + + # print(f"Eval: {corr} / {total}") + + + return corr, total, fully_correct \ No newline at end of file diff --git a/gnn_models.zip b/gnn_models.zip new file mode 100644 index 0000000..d86dcd4 Binary files /dev/null and b/gnn_models.zip differ diff --git a/helper.py b/helper.py new file mode 100755 index 0000000..27147e5 --- /dev/null +++ b/helper.py @@ -0,0 +1,517 @@ +#!/usr/bin/python +#Title : helper.py +#Usage : python helper.py -h +#Author : pmorvalho +#Date : May 02, 2022 +#Description : Script with generic functions used in several scripts +#Notes : This script is from: https://github.com/pmorvalho/MultIPAs +#Python Version: 3.8.5 +# (C) Copyright 2022 Pedro Orvalho. +#============================================================================== + +from __future__ import print_function +import sys, os +import re +from copy import deepcopy +import argparse +from sys import argv +from shutil import copyfile +import random +from numpy import binary_repr +import pickle +import gzip +import pathlib +# This is not required if you've installed pycparser into +# your site-packages/ with setup.py +sys.path.extend(['.', '..']) + +from pycparser import c_parser, c_ast, parse_file, c_generator + +#----------------------------------------------------------------- + +id_dict = dict() +cur_id = 0 + +def reset_ids(): + global id_dict, cur_id + id_dict = dict() + cur_id = 0 + +def node_id(coord, t=""): + global id_dict + global cur_id + file = coord.file + line = coord.line + column = coord.column + s = file+str(line)+str(column)+str(t) + # print('node_id') + # print(s) + # print(id_dict) + if s in id_dict.keys(): + return id_dict[s] + else: + id_dict[s] = cur_id + cur_id += 1 + return id_dict[s] + +def node_repr(coord): + file = coord.file + line = coord.line + column = coord.column + return "l"+str(line)+"-c"+str(column) + +#----------------------------------------------------------------- +def make_output_dir(input_file, output_dir): + sincludes = [] + includes = [] + noincludes = [] + with open(input_file, 'r') as reader: + for line in reader: + m = re.match('^\s*#\s*include\s*<', line) + if m: + sincludes.append(line) + else: + m = re.match('^\s*#\s*include', line) + if m: + includes.append(line) + else: + noincludes.append(line) + try: + if not os.path.exists(output_dir): + os.makedirs(output_dir) + except OSError: + print("Creation of the directory {0} failed".format(output_dir)) + + # output_file = output_dir + '/' + os.path.basename(input_file) + output_file = output_dir + '/tmp_input_file.c' + with open(output_file, 'w') as writer: + writer.writelines(sincludes) + writer.writelines(includes) + writer.write('void fakestart() {;}\n') + writer.writelines(noincludes) + + return output_file, sincludes, includes + +def get_output_file_name(filename, output_dir): + return output_dir + '/' + filename + ".c" + +def gen_output_file(c_gen, ast, includes, filename, output_dir): + output_file = get_output_file_name(filename, output_dir) + str_ast = c_gen.visit(ast) + # print(str_ast) + # str_ast = remove_fakestart(str_ast) + with open(output_file, 'w') as writer: + writer.writelines(includes) + writer.write(str_ast) + +def write_program(ast, c_gen, output_file, includes): + # write a clean program without any fakestart info + cu = CleanUpVisitor() + ast_cleaned = cu.visit(ast) + str_ast = c_gen.visit(ast_cleaned) + # print(str_ast) + with open(output_file, 'w') as writer: + writer.writelines(includes) + writer.write(str_ast) + +def program_checker(ast, c_gen, includes, ipa): + tmp_file = "/tmp/tmp-{n}.c".format(n=int(random.random()*100000000)) + write_program(ast, c_gen, tmp_file, includes) + # print(tmp_file) + return check_program(tmp_file, ipa) + +def check_program(tmp_file, ipa): + os.system("./prog_checker.sh {p} {lab} > {o}".format(p=tmp_file, lab=ipa, o=tmp_file[:-2]+".o")) + with open(tmp_file[:-2]+".o", 'r') as f: + lines = f.readlines() + # print(lines) + if "WRONG\n" in lines: + return False + return True + +#----------------------------------------------------------------- +# A visitor that removes the fakestart +class CleanUpVisitor(c_ast.NodeVisitor): + def __init__ (self): + super().__init__() + + def visit_FileAST(self, node): + #print('****************** Found FileAST Node *******************') + n_ext = [] + fakestart_pos = -1 #for the case of our injected function which do not have the fakestart function in their ast + for e in range(len(node.ext)): + x = node.ext[e] + if fakestart_pos==-1 and isinstance(x, c_ast.FuncDef) and "fakestart" in x.decl.type.type.declname: + fakestart_pos=e + + n_file_ast = c_ast.FileAST(node.ext[fakestart_pos+1:]) + return n_file_ast + + +#----------------------------------------------------------------- +# A generic visitor that visits the entire AST (at least that's the idea :') ) +class ASTVisitor(c_ast.NodeVisitor): + + def __init__ (self): + super().__init__() + self.pn = None # parent node + + _method_cache = None + + def visit(self, node): + """ Visit a node. + """ + + if self._method_cache is None: + self._method_cache = {} + + visitor = self._method_cache.get(node.__class__.__name__, None) + if visitor is None: + method = 'visit_' + node.__class__.__name__ + visitor = getattr(self, method, self.generic_visit) + self._method_cache[node.__class__.__name__] = visitor + + return visitor(node) + + def get_node_name(self, node): + return node.__class__.__name__ + + def visit_FileAST(self, node): + #print('****************** Found FileAST Node with Parent Node ****************') + n_ext = [] + fakestart_pos = -1 #for the case of our injected function which do not have the fakestart function in their ast + prv_pn = self.pn + self.pn = self.get_node_name(node) + for e in range(len(node.ext)): + x = node.ext[e] + # n_ext.append(self.visit(x, node_id(x.coord))) + if isinstance(x, c_ast.FuncDef) and "fakestart" in x.decl.type.type.declname: + fakestart_pos=e + + + fakestart_pos = -1 + for e in range(fakestart_pos+1, len(node.ext)): + x = node.ext[e] + n_ext.append(self.visit(x)) + + self.pn = prv_pn + n_file_ast = c_ast.FileAST(n_ext) + return n_file_ast + + def visit_Decl(self, node): + #print('****************** Found Decl Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + if not isinstance(node.type, c_ast.TypeDecl) and not isinstance(node.type, c_ast.ArrayDecl): + if node.init is not None: + node.init = self.visit(node.init) + + # because it can be other type of declaration. Like func declarations. + node.type = self.visit(node.type) + self.pn = prv_pn + return node + + if node.init is not None: + node.init = self.visit(node.init) + + self.pn = prv_pn + return node + + def visit_TypeDecl(self, node): + #print('****************** Found Type Decl Node with Parent Node '+self.pn+'****************') + # attrs: declname, quals, align, type + prv_pn = self.pn + self.pn = self.get_node_name(node) + self.type = self.visit(node.type) + self.pn = prv_pn + return node + + def visit_ArrayDecl(self, node): + #print('****************** Found Array Decl Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + if node.dim is not None: + node.dim = self.visit(node.dim) + self.pn = prv_pn + return node + + def visit_PtrDecl(self, node): + #print('****************** Found Pointer Decl Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + node.type = self.visit(node.type) + self.pn = prv_pn + return node + + def visit_ArrayRef(self, node): + #print('****************** Found Array Ref Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + node.name = self.visit(node.name) + node.subscript = self.visit(node.subscript) + self.pn = prv_pn + return node + + def visit_Assignment(self, node): + #print('****************** Found Assignment Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + node.rvalue = self.visit(node.rvalue) + node.lvalue = self.visit(node.lvalue) + self.pn = prv_pn + return node + + def visit_ID(self, node): + #print('****************** Found ID Node with Parent Node '+self.pn+'****************') + return node + + def visit_Constant(self, node): + #print('****************** Found Constant Node with Parent Node '+self.pn+'****************') + return node + + def visit_ExprList(self, node): + #print('****************** Found ExprList Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + for e in node.exprs: + e = self.visit(e) + self.pn = prv_pn + return node + + def visit_ParamList(self, node): + #print('****************** Found ParamList Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + for e in node.params: + e = self.visit(e) + self.pn = prv_pn + return node + + def visit_Cast(self, node): + #print('******************** Found Cast Node with Parent Node '+self.pn+'******************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + node.expr = self.visit(node.expr) + self.pn = prv_pn + return node + + def visit_UnaryOp(self, node): + #print('****************** Found Unary Operation with Parent Node '+self.pn+'*******************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + node.expr = self.visit(node.expr) + self.pn = prv_pn + return node + + def visit_BinaryOp(self, node): + #print('****************** Found Binary Operation with Parent Node '+self.pn+'*******************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + left = self.visit(node.left) + right = self.visit(node.right) + self.pn = prv_pn + return c_ast.BinaryOp(node.op, left, right, node.coord) + + def visit_TernaryOp(self, node): + #print('****************** Found TernaryOp Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + n_cond = self.visit(node.cond) + if isinstance(node.iftrue, c_ast.Compound): + n_iftrue = self.visit(node.iftrue) + else: + n_iftrue = self.visit(c_ast.Compound([node.iftrue], node.iftrue.coord)) + + n_iffalse = node.iffalse + if node.iffalse is not None: + if not isinstance(node.iffalse, c_ast.Compound): + node.iffalse = c_ast.Compound([node.iffalse], node.iffalse.coord) + node.iffalse = self.visit(node.iffalse) + + #print('****************** New Cond Node with Parent Node '+self.pn+'****************') + n_ternary = c_ast.TernaryOp(n_cond, n_iftrue, n_iffalse, node.coord) + self.pn = prv_pn + return n_ternary + + def visit_FuncDecl(self, node): + #print('****************** Found FuncDecl Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + if node.args: + node.args = self.visit(node.args) + self.pn = prv_pn + return node + + def visit_FuncDef(self, node): + #print('****************** Found FuncDef Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + decl = node.decl + param_decls = node.param_decls + if node.param_decls: + param_decls = self.visit(node.param_decls) + if "main" != node.decl.name and "fakestart" != node.decl.name: #ignore main function + # if the function has parameters add them to the scope + if decl.type.args: + decl.type.args = self.visit(decl.type.args) + + body = node.body + coord = node.coord + n_body_1 = self.visit(body) + n_func_def_ast = c_ast.FuncDef(decl, param_decls, n_body_1, coord) + self.pn = prv_pn + return n_func_def_ast + + def visit_FuncCall(self, node): + #print('****************** Found FuncCall Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + if node.args: + node.args = self.visit(node.args) + self.pn = prv_pn + return node + + def visit_Compound(self, node): + #print('****************** Found Compound Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + block_items = node.block_items + coord = node.coord + n_block_items = [] + if block_items is not None: + for x in block_items: + n_block_items.append(self.visit(x)) + + n_compound_ast = c_ast.Compound(n_block_items, coord) + self.pn = prv_pn + return n_compound_ast + + def visit_If(self, node): + #print('****************** Found IF Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + n_cond = self.visit(node.cond) + if isinstance(node.iftrue, c_ast.Compound): + n_iftrue = self.visit(node.iftrue) + else: + n_iftrue = self.visit(c_ast.Compound([node.iftrue], node.iftrue.coord)) + + n_iffalse = node.iffalse + if node.iffalse is not None: + if not isinstance(node.iffalse, c_ast.Compound): + node.iffalse = c_ast.Compound([node.iffalse], node.iffalse.coord) + node.iffalse = self.visit(node.iffalse) + #print('****************** New Cond Node with Parent Node '+self.pn+'****************') + n_if = c_ast.If(n_cond, n_iftrue, n_iffalse, node.coord) + self.pn = prv_pn + return n_if + + def visit_For(self, node): + #print('****************** Found For Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + n_init = self.visit(node.init) + n_cond = self.visit(node.cond) + if isinstance(node.stmt, c_ast.Compound): + n_stmt = self.visit(node.stmt) + else: + n_stmt = self.visit(c_ast.Compound([node.stmt], node.stmt.coord)) + n_next = node.next + if n_next is not None: + n_next = self.visit(node.next) + + n_for = c_ast.For(n_init, n_cond, n_next, n_stmt, node.coord) + self.pn = prv_pn + return n_for + + def visit_While(self, node): + #print('****************** Found While Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + n_cond = self.visit(node.cond) + if isinstance(node.stmt, c_ast.Compound): + n_stmt = self.visit(node.stmt) + else: + n_stmt = self.visit(c_ast.Compound([node.stmt], node.stmt.coord)) + n_while = c_ast.While(n_cond, n_stmt, node.coord) + self.pn = prv_pn + return n_while + + def visit_DoWhile(self, node): + #print('****************** Found DoWhile Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + n_cond = self.visit(node.cond) + if isinstance(node.stmt, c_ast.Compound): + n_stmt = self.visit(node.stmt) + else: + n_stmt = self.visit(c_ast.Compound([node.stmt], node.stmt.coord)) + n_dowhile = c_ast.DoWhile(n_cond, n_stmt, node.coord) + self.pn = prv_pn + return n_dowhile + + def visit_Switch(self, node): + #print('****************** Found Switch Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + n_cond = self.visit(node.cond) + if isinstance(node.stmt, c_ast.Compound): + n_stmt = self.visit(node.stmt) + else: + n_stmt = self.visit(c_ast.Compound([node.stmt], node.stmt.coord)) + n_switch = c_ast.Switch(n_cond, n_stmt, node.coord) + self.pn = prv_pn + return n_switch + + def visit_Return(self, node): + #print('****************** Found Return Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + if node.expr: + node.expr = self.visit(node.expr) + self.pn = prv_pn + return node + + def visit_Break(self, node): + #print('****************** Found Break Node with Parent Node '+self.pn+'****************') + return node + + def visit_Continue(self, node): + #print('****************** Found Continue Node with Parent Node '+self.pn+'****************') + return node + + def visit_Case(self, node): + #print('****************** Found Case Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + n_stmts_1 = [] + for x in node.stmts: + n_stmts_1.append(self.visit(x)) + + n_stmts_2 = c_ast.Compound (n_stmts_1, node.coord) + self.pn = prv_pn + return c_ast.Case(node.expr, n_stmts_2, node.coord) + + def visit_Default(self, node): + #print('****************** Found Default Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + n_stmts_1 = [] + for x in node.stmts: + n_stmts_1.append(self.visit(x)) + + n_stmts_2 = c_ast.Compound(n_stmts_1, node.coord) + self.pn = prv_pn + return c_ast.Default(n_stmts_2, node.coord) + + def visit_EmptyStatement(self, node): + #print('****************** Found EmptyStatement Node with Parent Node '+self.pn+'****************') + return node + + def generic_visit(self, node): + #print('****************** Something else ************') + return node + + +if __name__ == '__main__': + pass diff --git a/motivating_example/motivating_example.c b/motivating_example/motivating_example.c new file mode 100644 index 0000000..cabce79 --- /dev/null +++ b/motivating_example/motivating_example.c @@ -0,0 +1,8 @@ +int main(){ + int n, i; + scanf("%d", &n); + for(i = 1; i <= n; i++){ + printf("%d\n", i); + } + return 0; +} diff --git a/motivating_example/motivating_example_incorrect.c b/motivating_example/motivating_example_incorrect.c new file mode 100644 index 0000000..7af6b7a --- /dev/null +++ b/motivating_example/motivating_example_incorrect.c @@ -0,0 +1,13 @@ +void loop(int j, int l){ + while (l >= j){ + printf("%d\n", j); + ++j; + } +} + +int main(){ + int j, l; + scanf("%d", &l); + loop(j, l); + return 0; +} diff --git a/motivating_example/motivating_example_tests/t_0.in b/motivating_example/motivating_example_tests/t_0.in new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/motivating_example/motivating_example_tests/t_0.in @@ -0,0 +1 @@ +1 diff --git a/motivating_example/motivating_example_tests/t_0.out b/motivating_example/motivating_example_tests/t_0.out new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/motivating_example/motivating_example_tests/t_0.out @@ -0,0 +1 @@ +1 diff --git a/motivating_example/motivating_example_tests/t_1.in b/motivating_example/motivating_example_tests/t_1.in new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/motivating_example/motivating_example_tests/t_1.in @@ -0,0 +1 @@ +2 diff --git a/motivating_example/motivating_example_tests/t_1.out b/motivating_example/motivating_example_tests/t_1.out new file mode 100644 index 0000000..1191247 --- /dev/null +++ b/motivating_example/motivating_example_tests/t_1.out @@ -0,0 +1,2 @@ +1 +2 diff --git a/motivating_example/motivating_example_tests/t_2.in b/motivating_example/motivating_example_tests/t_2.in new file mode 100644 index 0000000..00750ed --- /dev/null +++ b/motivating_example/motivating_example_tests/t_2.in @@ -0,0 +1 @@ +3 diff --git a/motivating_example/motivating_example_tests/t_2.out b/motivating_example/motivating_example_tests/t_2.out new file mode 100644 index 0000000..01e79c3 --- /dev/null +++ b/motivating_example/motivating_example_tests/t_2.out @@ -0,0 +1,3 @@ +1 +2 +3 diff --git a/motivating_example/motivating_example_tests/t_3.in b/motivating_example/motivating_example_tests/t_3.in new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/motivating_example/motivating_example_tests/t_3.in @@ -0,0 +1 @@ +4 diff --git a/motivating_example/motivating_example_tests/t_3.out b/motivating_example/motivating_example_tests/t_3.out new file mode 100644 index 0000000..94ebaf9 --- /dev/null +++ b/motivating_example/motivating_example_tests/t_3.out @@ -0,0 +1,4 @@ +1 +2 +3 +4 diff --git a/motivating_example/var_map.pkl.gz b/motivating_example/var_map.pkl.gz new file mode 100644 index 0000000..d151060 Binary files /dev/null and b/motivating_example/var_map.pkl.gz differ diff --git a/prog_checker.sh b/prog_checker.sh new file mode 100755 index 0000000..097a284 --- /dev/null +++ b/prog_checker.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +#Title : prog_checker.sh +#Usage : bash prog_checker.sh program.c labX/exY +#Author : pmorvalho +#Date : July 20, 2022 +#Description : Checks if a program is consistent with a set of IO tests for a given lab and exercise +#Notes : +# (C) Copyright 2022 Pedro Orvalho. +#============================================================================== + +initial_dir=$(pwd) +prog_2_check=$1 +exercise=$2 +dataset=$initial_dir"/C-Pack-IPAs" +# reference implementation for the given exercise, we will use this program to confirm the output. +ref_impl=$dataset"/reference_implementations/"$exercise".c" + +prog_name=$(echo $prog_2_check | rev | cut -d '/' -f 1 | rev) +wdir="/data/tmp/variable-alignment/"$(python3 -c "import random; print('tmp-{n}/'.format(n=int(random.random()*100000000)))") + +if [[ ! -d $wdir ]]; then + mkdir -p $wdir"outputs" +else + rm -rf $wdir + mkdir -p $wdir"outputs" +fi + +cp $prog_2_check $wdir/$prog_name +cp $ref_impl $wdir/. +cd $wdir + +gcc -O3 -ansi -Wall $prog_name -lm -o prog_2_check.out +gcc -O3 -ansi -Wall ex* -lm -o ref_impl.out + +for t in $(find $dataset/tests/$exercise/*.in -maxdepth 0 -type f); +do + t_id=$(echo $t | rev | cut -d '/' -f 1 | rev) + t_id=$(echo $t_id | sed -e "s/\.in//") + timeout 5s ./prog_2_check.out < $t > "outputs/p-"$t_id".out" + timeout 5s ./ref_impl.out < $t > "outputs/r-"$t_id".out" + d=$(diff "outputs/p-"$t_id".out" "outputs/r-"$t_id".out") + if [[ $d == "" ]]; + then + continue; + fi + echo "WRONG" + cd $initial_dir + rm -rf $wdir + exit +done + +echo "CORRECT" +cd $initial_dir +rm -rf $wdir diff --git a/prog_fixer.py b/prog_fixer.py new file mode 100755 index 0000000..d7093e4 --- /dev/null +++ b/prog_fixer.py @@ -0,0 +1,933 @@ +#!/usr/bin/python +#Title : prog_fixer.py +#Usage : python prog_fixer.py -h +#Author : pmorvalho +#Date : July 12, 2022 +#Description : Module responsible for renaming the variables of the incorrect program with the variables of the correct program and to call the independent repair processes. +#Notes : +#Python Version: 3.8.5 +# (C) Copyright 2022 Pedro Orvalho. +#============================================================================== + +import argparse +from sys import argv +import sys, os +from copy import deepcopy +import argparse +from shutil import copyfile +from itertools import product +from numpy import binary_repr +import pickle +import gzip +import pathlib +import numpy as np +import time + +# This is not required if you've installed pycparser into +# your site-packages/ with setup.py +sys.path.extend(['.', '..']) + +from pycparser import c_parser, c_ast, parse_file, c_generator +from helper import * + +#----------------------------------------------------------------- + +bin_ops_mirror = {"<" : ">", ">" : "<", "<=" : ">=", ">=" : "<=", "==" : "==", "!=" : "!="} +bin_ops_2_swap = {"<" : "<=", ">" : ">=", "<=" : "<", ">=" : ">", "==" : "=", "!=" : "=="} +bin_ops_2_fix = dict((v, k) for k, v in bin_ops_2_swap.items()) +incr_decr_ops = {"p++" : "++", "++" : "p++", "--" : "p--", "p--" : "--"} +inc_decr_ops_2_fix = dict((v, k) for k, v in incr_decr_ops.items()) + +#----------------------------------------------------------------- +# A visitor that renames all the variables' IDs in a program with the variable mapping passed as input +class VariableRenamerVisitor(ASTVisitor): + def __init__ (self, var_map): + super().__init__() + self.var_map = var_map + + def visit_Decl(self, node): + #print('****************** Found Decl Node *******************') + # print(node) + if not isinstance(node.type, c_ast.TypeDecl): + # print(node) + # if node.init is not None: + # node.init = self.visit(node.init) + # # because it can be other type of declaration. Like func declarations. + # node.type = self.visit(node.type) + return node + + if node.init != None: + node.init=self.visit(node.init) + + if node.type.declname in self.var_map.keys(): + node.type.declname = self.var_map[node.type.declname] + + return node + + def visit_ID(self, node): + #print('****************** Found ID Node *******************') + if node.name in self.var_map.keys(): + node.name = self.var_map[node.name] + return node + +#----------------------------------------------------------------- + + # WRONG COMPARISON OPERATOR + +#----------------------------------------------------------------- +# A visitor that visit all the comparison operations and saves a list of interesting operations to fix +class CompOpVisitor(ASTVisitor): + + def __init__ (self): + super().__init__() + self.bin_ops_2_fix = list() + self.binary_ops = dict() + + def visit_BinaryOp(self, node): + # print('****************** Found Binary Operation *******************') + # print(node.show()) + left = self.visit(node.left) + right = self.visit(node.right) + # if node.op in bin_ops_2_fix.keys(): + # print(node.show()) + r_node = str(node.right) if not isinstance(node.right, c_ast.ID) else node.right.name + l_node = str(node.left) if not isinstance(node.left, c_ast.ID) else node.left.name + op = node.op + if (l_node, r_node) in self.binary_ops.keys(): + self.binary_ops[(l_node, r_node)].append([op, node_id(node.coord)]) + else: + self.binary_ops[(l_node, r_node)] = list([[op, node_id(node.coord)]]) + if "p++" in l_node or "p--" in l_node or "p++" in r_node or "p--" in r_node: + l_node = l_node.replace("p++","++") if "p++" in l_node else l_node.replace("p--","--") + r_node = r_node.replace("p++","++") if "p++" in r_node else r_node.replace("p--","--") + if (l_node, r_node) in self.binary_ops.keys(): + self.binary_ops[(l_node, r_node)].append([op, node_id(node.coord)]) + else: + self.binary_ops[(l_node, r_node)] = list([[op, node_id(node.coord)]]) + + return c_ast.BinaryOp(node.op, left, right, node.coord) + +#----------------------------------------------------------------- +# A visitor that tries to fix the wrong comparison operator bug +class WrongCompOpFixerVisitor(ASTVisitor): + + def __init__ (self, inc_prog_bin_ops, correct_prog_bin_ops): + super().__init__() + self.possible_fixes = list() + for k in correct_prog_bin_ops.keys(): + if k in inc_prog_bin_ops.keys(): + inc_prog_ops, cor_prog_ops = inc_prog_bin_ops[k], correct_prog_bin_ops[k] + for o, _ in cor_prog_ops: + if o not in inc_prog_ops or inc_prog_ops.count(o) < cor_prog_ops.count(o): + for o2, i in inc_prog_ops: + if o == o2: + continue + fix = [i, o, k] + if fix not in self.possible_fixes: + self.possible_fixes.append(fix) + if o == '==': + self.possible_fixes.append([None, '==', k[0], k[1]]) + + else: + inv_k=k[::-1] + if inv_k in inc_prog_bin_ops: + for o, _ in correct_prog_bin_ops[k]: + inc_prog_ops, cor_prog_ops = inc_prog_bin_ops[inv_k], correct_prog_bin_ops[k] + if o not in bin_ops_mirror.keys(): + continue + inv_o=bin_ops_mirror[o] + if inv_o not in inc_prog_ops or inc_prog_ops.count(inv_o) < cor_prog_ops.count(o): + for o2, i in inc_prog_ops: + if inv_o == o2: + continue + fix = [i, inv_o, inv_k] + if fix not in self.possible_fixes: + self.possible_fixes.append(fix) + if o == '==': + self.possible_fixes.append([None, '==', inv_k[0], inv_k[1]]) + for o, _ in correct_prog_bin_ops[k]: + if o == '==': + self.possible_fixes.append([None, '==', k[0], k[1]]) + self.possible_fixes.append([None, '==', k[1], k[0]]) + + def next_repair(self): + if len(self.possible_fixes) > 0: + self.possible_fixes.pop(0) + + def visit_Assignment(self, node): + # print('****************** Found Assignment Node *******************') + prv_pn = self.pn # parent node, declared in ASTVisitor + self.pn = self.get_node_name(node) + n_str = str(node) + r_node = str(node.rvalue) if not isinstance(node.rvalue, c_ast.ID) else node.rvalue.name + l_node = str(node.lvalue) if not isinstance(node.lvalue, c_ast.ID) else node.lvalue.name + + if len(self.possible_fixes) > 0: + if self.possible_fixes[0][0] is None: + _, op, lv, rv = self.possible_fixes[0] + if lv == l_node and rv == r_node: + node.op = op + self.pn = prv_pn + return node + node.rvalue = self.visit(node.rvalue) + node.lvalue = self.visit(node.lvalue) + self.pn = prv_pn + return node + + def visit_BinaryOp(self, node): + # print('****************** Found Binary Operation *******************') + # print(node.show()) + prv_pn = self.pn # parent node, declared in ASTVisitor + self.pn = self.get_node_name(node) + left = self.visit(node.left) + right = self.visit(node.right) + r_node = str(node.right) if not isinstance(node.right, c_ast.ID) else node.right.name + l_node = str(node.left) if not isinstance(node.left, c_ast.ID) else node.left.name + n_id = node_id(node.coord) + if len(self.possible_fixes) > 0: + if n_id == self.possible_fixes[0][0] and (l_node,r_node) == self.possible_fixes[0][2]: + node.op = self.possible_fixes[0][1] # the fixed comparison operator + + self.pn = prv_pn + return c_ast.BinaryOp(node.op, left, right, node.coord) + +#----------------------------------------------------------------- + + # VARIABLE MISUSE + +#----------------------------------------------------------------- +# A visitor that visits all the ID nodes and saves the info for every variable in the AST +# the idea is in the future to keep also the information about the parent node for each ID node. +class VarInfoVisitor(ASTVisitor): + + def __init__ (self): + super().__init__() + self.var_usage = dict() + self.var_node_ids = dict() + + def visit_Decl(self, node): + #print('****************** Found Decl Node *******************') + if not isinstance(node.type, c_ast.TypeDecl): + return node + if node.init != None: + node.init=self.visit(node.init) + + v_id = node.type.declname + if v_id in self.var_usage.keys(): + self.var_usage[v_id] += 1 + # self.var_node_ids[v_id].append(node_id(node.coord)) + else: + self.var_usage[v_id] = 0 + self.var_node_ids[v_id] = list() # [node_id(node.coord)] + return node + + def visit_ID(self, node): + #print('****************** Found ID Node *******************') + v_id = node.name + if v_id in self.var_usage.keys(): + self.var_usage[v_id] += 1 + self.var_node_ids[v_id].append(node_id(node.coord)) + else: + self.var_usage[v_id] = 1 + self.var_node_ids[v_id] = [node_id(node.coord)] + + return node + +#----------------------------------------------------------------- +# A visitor that tries to fix the bug of variable misuse +class VarMisuseFixerVisitor(ASTVisitor): + + def __init__ (self, inc_prog_var_usage, cor_prog_var_usage, inc_prog_vars_ids, cor_prog_vars_ids): + super().__init__() + self.inc_prog_vars_ids = inc_prog_vars_ids + self.cor_prog_vars_ids = cor_prog_vars_ids + self.var_2_del = None + self.var_2_insert = None + for k in inc_prog_var_usage.keys(): + if k in cor_prog_var_usage.keys(): + v_i, v_c = inc_prog_var_usage[k], cor_prog_var_usage[k] + if v_i == v_c: + continue + if v_i < v_c: + self.var_2_insert = k + else: + self.var_2_del = k + + + self.var_2_del_ids = self.inc_prog_vars_ids[self.var_2_del] if self.var_2_del is not None else [] + + def next_repair(self): + if len(self.var_2_del_ids) > 0: + self.var_2_del_ids.pop(0) + + def visit_Decl(self, node): + #print('****************** Found Decl Node *******************') + if not isinstance(node.type, c_ast.TypeDecl): + return node + if node.init != None: + node.init=self.visit(node.init) + + v_id = node.type.declname + if len(self.var_2_del_ids) > 0 and v_id == self.var_2_del: + if self.var_2_del_ids[0] == node_id(node.coord): + node.type.declname = self.var_2_insert + + return node + + def visit_ID(self, node): + #print('****************** Found ID Node *******************') + v_id = node.name + if len(self.var_2_del_ids) > 0 and v_id == self.var_2_del: + if self.var_2_del_ids[0] == node_id(node.coord): + node.name = self.var_2_insert + + return node + +#----------------------------------------------------------------- + + # EXPRESSION DELETION + +#----------------------------------------------------------------- +# A visitor that visits all the assignment nodes and saves their info +class AssignmentVisitor(ASTVisitor): + + def __init__ (self): + super().__init__() + self.assignments = dict() + + def visit_Assignment(self, node): + # print('****************** Found Assignment Node *******************') + prv_pn = self.pn # parent node, declared in ASTVisitor + self.pn = self.get_node_name(node) + n_str = str(node)+"-"+prv_pn + + if n_str not in self.assignments.keys(): + self.assignments[n_str] = {"pn":prv_pn, "cnt": 1, "obj": deepcopy(node)} + else: + self.assignments[n_str] = {"pn":prv_pn, "cnt": self.assignments[n_str]["cnt"]+1, "obj": deepcopy(node)} + + node.rvalue = self.visit(node.rvalue) + node.lvalue = self.visit(node.lvalue) + self.pn = prv_pn + return node + +#----------------------------------------------------------------- +# A visitor that finds possible places to insert assignment expressions +class Places4AssignmentsVisitor(ASTVisitor): + + def __init__ (self, asg_2_ins): + super().__init__() + self.parents_names = dict() + for x,y in asg_2_ins: + if x not in self.parents_names.keys(): + self.parents_names[x] = [y] + else: + self.parents_names[x].append(y) + + self.possible_places = list() + + def get_possible_places(self): + return self.possible_places + + def visit_FileAST(self, node): + #print('****************** Found FileAST Node with Parent Node ****************') + n_ext = [] + fakestart_pos = -1 #for the case of our injected function which do not have the fakestart function in their ast + prv_pn = self.pn + self.pn = self.get_node_name(node) + for e in range(len(node.ext)): + x = node.ext[e] + # n_ext.append(self.visit(x, node_id(x.coord))) + if isinstance(x, c_ast.FuncDef) and "fakestart" in x.decl.type.type.declname: + fakestart_pos=e + + for e in range(fakestart_pos+1, len(node.ext)): + x = node.ext[e] + n_ext.append(self.visit(x)) + + self.pn = prv_pn + n_file_ast = c_ast.FileAST(n_ext) + return n_file_ast + + def visit_ExprList(self, node): + #print('****************** Found ExprList Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + coord = node.coord + if self.pn in self.parents_names.keys(): + if node.exprs: + for a in self.parents_names[self.pn]: + self.possible_places = self.possible_places + [[node_id(coord), i, a] for i in range(len(self.exprs)+1)] + for e in node.exprs: + e = self.visit(e) + self.pn = prv_pn + return node + + def visit_TernaryOp(self, node): + #print('****************** Found TernaryOp Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + coord = node.coord + n_cond = self.visit(node.cond) + if self.pn in self.parents_names.keys() and (n_cond is None or isinstance(n_cond, c_ast.EmptyStatement)): + for a in self.parents_names[self.pn]: + self.possible_places.append([node_id(coord), 0, a]) + + n_iftrue = self.visit(node.iftrue) + n_iffalse = node.iffalse + if node.iffalse: + n_iffalse = self.visit(node.iffalse) + #print('****************** New Cond Node with Parent Node '+self.pn+'****************') + n_ternary = c_ast.TernaryOp(n_cond, n_iftrue, n_iffalse, node.coord) + self.pn = prv_pn + return n_ternary + + def visit_Compound(self, node): + #print('****************** Found Compound Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + block_items = node.block_items + coord = node.coord + n_block_items = [] + idx_last_decl = 0 + if self.pn in self.parents_names.keys(): + if block_items is not None: + for i in range(len(block_items)): + x = block_items[i] + if isinstance(x, c_ast.Decl): + idx_last_decl=i+1 + continue + else: + break + + for a in self.parents_names[self.pn]: + if block_items is None: + self.possible_places.append([node_id(coord), 0, a]) + else: + self.possible_places = self.possible_places + [[node_id(coord), i, a] for i in range(idx_last_decl, len(block_items)+1)] + + if "For" in self.parents_names.keys(): + if block_items is not None: + for i in range(len(block_items)): + x = block_items[i] + if isinstance(x, c_ast.Decl): + idx_last_decl=i+1 + continue + else: + break + + for a in self.parents_names["For"]: + if block_items is not None: + for i in range(idx_last_decl,len(block_items)): + x = block_items[i] + if isinstance(x, c_ast.While): + self.possible_places.append([node_id(coord), i, a]) + self.possible_places.append([node_id(coord), len(block_items), a]) + + if block_items is not None: + for x in block_items: + n_block_items.append(self.visit(x)) + + n_compound_ast = c_ast.Compound(n_block_items, coord) + self.pn = prv_pn + return n_compound_ast + + def visit_If(self, node): + #print('****************** Found IF Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + coord = node.coord + n_cond = self.visit(node.cond) + if self.pn in self.parents_names.keys() and (n_cond is None or isinstance(n_cond, c_ast.EmptyStatement)): + for a in self.parents_names[self.pn]: + self.possible_places.append([node_id(coord), 0, a]) + n_iftrue = self.visit(node.iftrue) + n_iffalse = node.iffalse + if node.iffalse: + n_iffalse = self.visit(node.iffalse) + #print('****************** New Cond Node with Parent Node '+self.pn+'****************') + n_if = c_ast.If(n_cond, n_iftrue, n_iffalse, node.coord) + self.pn = prv_pn + return n_if + + def visit_For(self, node): + #print('****************** Found For Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + coord = node.coord + n_init = self.visit(node.init) + if self.pn in self.parents_names.keys() and (n_init is None or isinstance(n_init, c_ast.EmptyStatement)): + for a in self.parents_names[self.pn]: + self.possible_places.append([node_id(coord), 0, a]) + n_cond = self.visit(node.cond) + if self.pn in self.parents_names.keys() and (n_cond is None or isinstance(n_cond, c_ast.EmptyStatement)): + for a in self.parents_names[self.pn]: + self.possible_places.append([node_id(coord), 1, a]) + n_stmt = self.visit(node.stmt) + n_next = node.next + if self.pn in self.parents_names.keys() and (n_next is None or isinstance(n_next, c_ast.EmptyStatement)): + for a in self.parents_names[self.pn]: + self.possible_places.append([node_id(coord), 2, a]) + if n_next is not None: + n_next = self.visit(node.next) + + + n_for = c_ast.For(n_init, n_cond, n_next, n_stmt, node.coord) + self.pn = prv_pn + return n_for + + def visit_While(self, node): + #print('****************** Found While Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + coord = node.coord + n_cond = self.visit(node.cond) + if self.pn in self.parents_names.keys() and (n_cond is None or isinstance(n_cond, c_ast.EmptyStatement)): + for a in self.parents_names[self.pn]: + self.possible_places.append([node_id(coord), 0, a]) + n_stmt = self.visit(node.stmt) + n_while = c_ast.While(n_cond, n_stmt, node.coord) + self.pn = prv_pn + return n_while + + def visit_DoWhile(self, node): + #print('****************** Found DoWhile Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + coord = node.coord + n_cond = self.visit(node.cond) + if self.pn in self.parents_names.keys() and (n_cond is None or isinstance(n_cond, c_ast.EmptyStatement)): + for a in self.parents_names[self.pn]: + self.possible_places.append([node_id(coord), 0, a]) + n_stmt = self.visit(node.stmt) + n_dowhile = c_ast.DoWhile(n_cond, n_stmt, node.coord) + self.pn = prv_pn + return n_dowhile + + +#----------------------------------------------------------------- +# A visitor that finds possible places to insert assignment expressions +class AssignmentInsertionVisitor(ASTVisitor): + + def __init__ (self, ast, assigns_inc_prog, assigns_cor_prog): + super().__init__() + self.asg_2_ins = list() # list of assignments that can be inserted + self.possible_fixes = list() + for k in assigns_cor_prog: + if (k not in assigns_inc_prog) or (k in assigns_inc_prog and assigns_cor_prog[k]["cnt"] > assigns_inc_prog[k]["cnt"]): + self.asg_2_ins.append([assigns_cor_prog[k]["pn"], assigns_cor_prog[k]["obj"]]) # a tuple with the parent node name and the object of the assignment to use as replacement + + l4p = Places4AssignmentsVisitor(self.asg_2_ins) + l4p.visit(ast) + self.possible_fixes = l4p.get_possible_places() + # print(self.possible_fixes) + if self.possible_fixes is not None and len(self.possible_fixes) > 0: + self.n_id, self.idx, self.asg = self.possible_fixes[0] + + def next_repair(self): + self.possible_fixes.pop(0) + if len(self.possible_fixes) > 0: + self.n_id, self.idx, self.asg = self.possible_fixes[0] + + def visit_ExprList(self, node): + #print('****************** Found ExprList Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + n_id = node_id(node.coord) + if n_id == self.n_id: + node.exprs.insert(self.idx, self.asg) + self.pn = prv_pn + return node + for e in node.exprs: + e = self.visit(e) + self.pn = prv_pn + return node + + def visit_TernaryOp(self, node): + #print('****************** Found TernaryOp Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + n_id = node_id(node.coord) + if n_id == self.n_id and self.idx == 0: + node.cond = self.asg + self.pn = prv_pn + return node + n_cond = self.visit(node.cond) + n_iftrue = self.visit(node.iftrue) + n_iffalse = node.iffalse + if node.iffalse: + n_iffalse = self.visit(node.iffalse) + #print('****************** New Cond Node with Parent Node '+self.pn+'****************') + n_ternary = c_ast.TernaryOp(n_cond, n_iftrue, n_iffalse, node.coord) + self.pn = prv_pn + return n_ternary + + def visit_Compound(self, node): + #print('****************** Found Compound Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + block_items = node.block_items + coord = node.coord + n_id = node_id(node.coord) + + n_block_items = [] + if block_items is not None: + if n_id == self.n_id: + node.block_items.insert(self.idx, self.asg) + self.pn = prv_pn + return node + for x in block_items: + n_block_items.append(self.visit(x)) + else: + if n_id == self.n_id: + node.block_items=[self.asg] + self.pn = prv_pn + return node + n_compound_ast = c_ast.Compound(n_block_items, coord) + self.pn = prv_pn + return n_compound_ast + + def visit_If(self, node): + #print('****************** Found IF Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + n_cond = self.visit(node.cond) + n_id = node_id(node.coord) + if n_id == self.n_id and self.idx == 0: + node.cond = self.asg + self.pn = prv_pn + return node + n_iftrue = self.visit(node.iftrue) + n_iffalse = node.iffalse + if node.iffalse: + n_iffalse = self.visit(node.iffalse) + #print('****************** New Cond Node with Parent Node '+self.pn+'****************') + n_if = c_ast.If(n_cond, n_iftrue, n_iffalse, node.coord) + self.pn = prv_pn + return n_if + + def visit_For(self, node): + #print('****************** Found For Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + n_id = node_id(node.coord) + n_init = self.visit(node.init) + if n_id == self.n_id and self.idx == 0: + node.init = self.asg + self.pn = prv_pn + return node + n_cond = self.visit(node.cond) + if n_id == self.n_id and self.idx == 1: + node.cond = self.asg + self.pn = prv_pn + return node + n_stmt = self.visit(node.stmt) + n_next = node.next + if n_next is not None: + n_next = self.visit(node.next) + elif n_id == self.n_id and self.idx == 2: + node.next = self.asg + self.pn = prv_pn + return node + + n_for = c_ast.For(n_init, n_cond, n_next, n_stmt, node.coord) + self.pn = prv_pn + return n_for + + def visit_While(self, node): + #print('****************** Found While Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + n_id = node_id(node.coord) + n_cond = self.visit(node.cond) + if n_id == self.n_id and self.idx == 0: + node.cond = self.asg + self.pn = prv_pn + return node + n_stmt = self.visit(node.stmt) + n_while = c_ast.While(n_cond, n_stmt, node.coord) + self.pn = prv_pn + return n_while + + def visit_DoWhile(self, node): + #print('****************** Found DoWhile Node with Parent Node '+self.pn+'****************') + prv_pn = self.pn + self.pn = self.get_node_name(node) + n_id = node_id(node.coord) + n_cond = self.visit(node.cond) + if n_id == self.n_id and self.idx == 0: + node.cond = self.asg + self.pn = prv_pn + return node + n_stmt = self.visit(node.stmt) + n_dowhile = c_ast.DoWhile(n_cond, n_stmt, node.coord) + self.pn = prv_pn + return n_dowhile + + +#----------------------------------------------------------------- + +def load_dict(vm): + fp=gzip.open(vm,'rb') # This assumes that primes.data is already packed with gzip + var_map=pickle.load(fp) + fp.close() + return var_map + +def softmax(x): + """Compute softmax values for each sets of scores in x.""" + return np.exp(x) / np.sum(np.exp(x), axis=0) + + +def variables_distributions(d): + # given a dictionary with a non-normalized distribution per variable, this function normalizes the distribution ['distribution'] considering the possible mappings ['mapped_to'] + dists=dict() + for k in d.keys(): + dists[k] = dict() + dst = d[k][0][0] + # dst = softmax(dst) + # dists[k]['distribution'] = [i/sum(dst) for i in dst] + dists[k]['distribution'] = softmax(dst) + dists[k]['mapped_to'] = d[k][1] + return dists + +def baseline_distributions(d): + # given a dictionary with a non-normalized distribution per variable, this function returns a random distribution from a variable to any other variable + dists=dict() + for k in d.keys(): + dists[k] = dict() + dst = d[k][0][0] + dists[k]['mapped_to'] = d[k][1] + dists[k]['distribution'] = [1/len( dists[k]['mapped_to']) for _ in dst] + + return dists + + +def get_next_mapping(): + used_mappings.append(var_map) + while True: + d = dict() + for k in vars_dists.keys(): + d[k] = np.random.choice(vars_dists[k]['mapped_to'], 1, p=vars_dists[k]['distribution'])[0] + if d not in used_mappings: + return d + +def save_fixed_program(ast, c_gen, sincludes, var_map): + inv_map = dict((v, k) for k, v in var_map.items()) + v = VariableRenamerVisitor(inv_map) + v.visit(ast) + write_program(ast, c_gen, args.output_prog+".c", sincludes) + if args.verbose: + print("#Tries:", num_of_tries) + print("#Mappings used:", len(used_mappings)+1) + print("Last variable mapping:", var_map) + print("\n\nFixed Program:") + cu = CleanUpVisitor() + ast_cleaned = cu.visit(ast) + print(c_gen.visit(ast_cleaned)) + print("\nFIXED") + else: + print("FIXED") + + os.system("rm -rf "+args.output_prog) + return True + +def enumerate_repairs(v, possible_fixes, ast, c_gen, sincludes, var_map): + global num_of_tries + original_ast = deepcopy(ast) + fixed=False + for _ in range(len(possible_fixes)): + v.visit(ast) + + if program_checker(ast, c_gen, sincludes, args.ipa): + fixed=True + break + + ast = deepcopy(original_ast) + v.next_repair() + + num_of_tries += 1 + + if fixed: + return save_fixed_program(ast, c_gen, sincludes, var_map) + + return False + +def instrument_file(incorrect_program, correct_program, output_prog, var_map): + output_file, sincludes, includes = make_output_dir(incorrect_program, output_prog)#, logfilename, loglibpath) + try: + ast = parse_file(output_file, use_cpp=True, + cpp_path='gcc', + cpp_args=['-E', '-Iutils/fake_libc_include']) + except: + print("Error while comoiling ", output_file) + os.system("echo {p} >> repairing_programs_compilations_errs.txt".format(p=output_file)) + return 0 + + try: + correct_ast = parse_file(correct_program, use_cpp=True, + cpp_path='gcc', + cpp_args=['-E', '-Iutils/fake_libc_include']) + except: + print("Error while compiling ", correct_program) + os.system("echo {p} >> repairing_programs_compilations_errs.txt".format(p=correct_program)) + return 0 + + # print('******************** INPUT FILE: ********************') + c_gen = c_generator.CGenerator() + v = c_ast.NodeVisitor() + v.visit(ast) + if args.verbose: + print("\n\nIncorrect submission's AST") + cu = CleanUpVisitor() + ast_aux = deepcopy(ast) + ast_cleaned = cu.visit(ast_aux) + print(c_gen.visit(ast_cleaned)) + # ast.show() + + untouched_ast = deepcopy(ast) + while True: + if args.verbose: + print("Using variable mapping:", var_map) + print("\n\nIncorrect submission's AST") + cu = CleanUpVisitor() + ast_aux = deepcopy(ast) + ast_cleaned = cu.visit(ast_aux) + print(c_gen.visit(ast_cleaned)) + v = VariableRenamerVisitor(var_map) + v.visit(ast) + original_ast = deepcopy(ast) + # ast.show() + # return + if program_checker(ast, c_gen, sincludes, args.ipa): + return save_fixed_program(ast, c_gen, sincludes, var_map) + + if args.all or args.wco: + cov = CompOpVisitor() + cov.visit(ast) + inc_prog_bin_ops = cov.binary_ops + cov = CompOpVisitor() + cov.visit(correct_ast) + cor_prog_bin_ops = cov.binary_ops + if args.verbose: + print("Incorrect program binary operations:\n", inc_prog_bin_ops) + print("\nCorrect program binary operations:\n", cor_prog_bin_ops) + print() + + # Dealing with wrong comparison operator + wco = WrongCompOpFixerVisitor(inc_prog_bin_ops, cor_prog_bin_ops) + if args.verbose: + print("Possible fixes:", wco.possible_fixes) + + original_ast = deepcopy(ast) + if enumerate_repairs(wco, wco.possible_fixes, ast, c_gen, sincludes, var_map): + return True + + if args.all or args.vm: + ast = deepcopy(original_ast) + # Dealing with the bug of variable misused + vi = VarInfoVisitor() + vi.visit(ast) + inc_prog_var_usage = vi.var_usage + inc_prog_var_ids = vi.var_node_ids + vi = VarInfoVisitor() + vi.visit(correct_ast) + cor_prog_var_usage = vi.var_usage + cor_prog_var_ids = vi.var_node_ids + if args.verbose: + print("\n\nIncorrect program variable usage:\n", inc_prog_var_usage) + print("\nCorrect program variable usage:\n", cor_prog_var_usage) + print() + + # ast = deepcopy(original_ast) + vm = VarMisuseFixerVisitor(inc_prog_var_usage, cor_prog_var_usage, inc_prog_var_ids, cor_prog_var_ids) + if args.verbose: + print("Possible fix: replace {v1} with {v2}".format(v1=vm.var_2_del, v2=vm.var_2_insert)) + print("Possible places:", len(vm.var_2_del_ids)) + print(vm.var_2_del_ids) + + if enumerate_repairs(vm, vm.var_2_del_ids, ast, c_gen, sincludes, var_map): + return True + + if args.all or args.ed: + # Dealing with the bug of expression deletion + ast = deepcopy(original_ast) + ev = AssignmentVisitor() + ev.visit(ast) + ev2 = AssignmentVisitor() + ev2.visit(correct_ast) + if args.verbose: + print("\n\nIncorrect program's assignments:\n", ev.assignments) + print("\nCorrect program's assignments:\n", ev2.assignments) + print() + + # ast = deepcopy(original_ast) + aiv = AssignmentInsertionVisitor(ast, ev.assignments, ev2.assignments) + if args.verbose: + print("Possible fixes") + # print(aiv.possible_fixes) + + if enumerate_repairs(aiv, aiv.possible_fixes, ast, c_gen, sincludes, var_map): + return True + + ast = deepcopy(untouched_ast) + var_map = get_next_mapping() + + if args.verbose: + print("Program not fixed after {a} attempts!\nFAILED".format(a=num_of_tries)) + else: + print("FAILED") + + return False + +def parser(): + parser = argparse.ArgumentParser(prog='prog_fixer.py', formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('-ip', '--inc_prog', help='Program to be repaired.') + parser.add_argument('-cp', '--cor_prog', help='Correct program to be used by the repair process.') + parser.add_argument('-m', '--var_map', help='Variable mapping, where each incorrect program\'s variable has a corresponding variable identifier of the correct program.') + parser.add_argument('-md', '--var_map_dist', help='Path for the each variable mapping distribution.') + parser.add_argument('-b', '--baseline', action='store_true', default=False, help='Uses the baseline i.e. random mapping between the incorrect/correct programs\' variables.') + parser.add_argument('-wco', '--wco', action='store_true', default=False, help='Tries to fix bugs of wrong comparison operators.') + parser.add_argument('-vm', '--vm', action='store_true', default=False, help='Tries to fix bugs of variable misuse.') + parser.add_argument('-ed', '--ed', action='store_true', default=False, help='Tries to fix bugs of expression deletion (assignments).') + parser.add_argument('-a', '--all', action='store_true', default=False, help='Tries to fix all the mutilations above.') + parser.add_argument('-e', '--ipa', help='Name of the lab and exercise (IPA) so we can check the IO tests.') + parser.add_argument('-o', '--output_prog', nargs='?', help='Output program (program fixed).') + parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Prints debugging information.') + args = parser.parse_args(argv[1:]) + return args + +if __name__ == '__main__': + args = parser() + var_map = load_dict(args.var_map) + # var_map = {'cont': 'maior', 'i': 'i', 'maior': 'maior'} + used_mappings = list() + vars_dists = variables_distributions(load_dict(args.var_map_dist)) + + if args.baseline: + vars_dists = baseline_distributions(load_dict(args.var_map_dist)) + var_map=dict() + var_map=get_next_mapping() + used_mappings=list() + # print(args) + # for k in var_map.keys(): + # var_map[k] = var_map[k]+"_mod" + + + if args.verbose: + print("Program Fixer") + print("Incorrect Program:", args.inc_prog) + # print("Correct Program:", args.cor_prog) + print("Using variable mapping:", var_map) + + fixed = False + num_of_tries=0 + while not fixed: + try: + fixed = instrument_file(args.inc_prog, args.cor_prog, args.output_prog, var_map) + except: + print("ERROR") + print(var_map) + print("#Mappings:", len(used_mappings)+1) + var_map = get_next_mapping() + + # instrument_file(args.inc_prog, args.cor_prog, args.output_prog, var_map) diff --git a/prog_mutator.py b/prog_mutator.py new file mode 100755 index 0000000..d64ea06 --- /dev/null +++ b/prog_mutator.py @@ -0,0 +1,846 @@ +#!/usr/bin/python +#Title : prog_mutator.py +#Usage : python prog_mutator.py -h +#Author : pmorvalho +#Date : April 29, 2022 +#Description : A visitor for C programs based on pycparser, that mutates programs based on some specific rules. +#Notes : This script is from: https://github.com/pmorvalho/MultIPAs +#Python Version: 3.8.5 +# (C) Copyright 2022 Pedro Orvalho. +#============================================================================== + +from __future__ import print_function +import sys, os +import re +from copy import deepcopy +import argparse +from sys import argv +from shutil import copyfile +from topological_sorting import getTopologicalOrders + +from itertools import product +from numpy import binary_repr +import pickle +import gzip +import pathlib +import random + +# This is not required if you've installed pycparser into +# your site-packages/ with setup.py +sys.path.extend(['.', '..']) + +from pycparser import c_parser, c_ast, parse_file, c_generator + +from helper import * + +#----------------------------------------------------------------- + +bin_ops_2_swap = {"<" : ">", ">" : "<", "<=" : ">=", ">=" : "<=", "==" : "==", "!=" : "!="} +incr_decr_ops = {"p++" : "++", "++" : "p++", "--" : "p--", "p--" : "--"} + +#----------------------------------------------------------------- +class MutatorVisitor(ASTVisitor): + + def __init__ (self): + # list with the program variables + self.scope_vars = dict() + # number of binary operations to swap + self.num_bin_ops_2_swap = 0 + # coords of the if nodes to swap + self.if_2_swap_ids = list() + # flag to use while checking an if-statement + self.check_simple_if_else = False + # coord of the increment/decrement nodes to swap + self.inc_ops_2_swap_ids = list() + # flag to check if the increment/decrement operator is being used inside an assignment or a binary op + self.safe_inc_op = 1 + # dict with infromations about the variables declared inside each scope + self.blocks_vars = dict() + # flag to know if we are inside a variable declaration + self.declaring_var = False + # variable to know the coord of the current block + self.curr_block = "global" + # variable to know the name of the current variable being declared + self.curr_var = None + # info aboout the variable declaration for each code block + self.blocks_vars[self.curr_block] = dict() + self.blocks_vars[self.curr_block]["decls_id"] = [] + self.blocks_vars[self.curr_block]["var_2_coord"] = dict() + self.blocks_vars[self.curr_block]["decls_dependencies"] = [] + self.blocks_vars[self.curr_block]["permutations"] = [] + # translating for-loops into while-loops + self.found_continue = False + self.for_ids_2_swap = [] + + def visit(self, node): + #node.show() + return c_ast.NodeVisitor.visit(self, node) + + def visit_FileAST(self, node): + #print('****************** Found FileAST Node *******************') + n_ext = [] + fakestart_pos = -1 #for the case of our injected function which do not have the fakestart function in their ast + for e in range(len(node.ext)): + x = node.ext[e] + n_ext.append(self.visit(x)) + if fakestart_pos==-1 and isinstance(x, c_ast.FuncDef) and "fakestart" in x.decl.type.type.declname: + fakestart_pos=e + + + n_file_ast = c_ast.FileAST(n_ext[fakestart_pos+1:]) + if self.blocks_vars[self.curr_block]["decls_id"] == []: + del self.blocks_vars[self.curr_block] + return n_file_ast + + def visit_Decl(self, node): + # print('****************** Found Decl Node *******************') + if not isinstance(node.type, c_ast.TypeDecl): + # because it can be other type of declaration. Like func declarations. + node.type = self.visit(node.type) + if isinstance(node.type, c_ast.Enum): + # Enum are declared in the var_info.h file! + return + else: + return node + # node.show() + type = node.type + if isinstance(type.type, c_ast.Enum): + # type = type.type.name + # node.type = self.visit(node.type) + type = node.type.type + else: + type = type.type.names[0] + + if self.curr_block is not None: + self.blocks_vars[self.curr_block]["decls_id"].append(node_id(node.coord)) + self.blocks_vars[self.curr_block]["var_2_coord"][node.name] = node_id(node.coord) + self.scope_vars[node.name] = type + self.curr_var = node.name + if node.init != None: + node.init = self.visit(node.init) + + self.curr_var = None + + return node + + + def visit_ArrayDecl(self, node): + #print('****************** Found Decl Node *******************') + # node.show() + if isinstance(node.type, c_ast.TypeDecl): + if self.curr_block is not None: + self.blocks_vars[self.curr_block]["decls_id"].append(node_id(node.coord)) + self.blocks_vars[self.curr_block]["var_2_coord"][node.type.declname] = node_id(node.coord) + self.scope_vars[node.type.declname] = "array-"+node.type.type.names[0] + self.curr_var = node.type.declname + + return node + + def visit_Assignment(self, node): + # print('****************** Found Assignment Node *******************') + self.safe_inc_op -= 1 + node.rvalue = self.visit(node.rvalue) + node.lvalue = self.visit(node.lvalue) + self.safe_inc_op += 1 + return node + + def visit_ID(self, node): + #print('****************** Found ID Node *******************') + if self.curr_var is not None and node.name in self.blocks_vars[self.curr_block]["var_2_coord"].keys(): + self.blocks_vars[self.curr_block]["decls_dependencies"].append((self.blocks_vars[self.curr_block]["var_2_coord"][node.name], self.blocks_vars[self.curr_block]["var_2_coord"][self.curr_var])) + return node + + def visit_Enum(self, node): + # #print('****************** Found Enum Node *******************') + # insert each enum on the .h file, after the scope functions of the fakestart function + return node + + def visit_ExprList(self, node): + #print('****************** Found ExprList Node *******************') + for e in node.exprs: + e = self.visit(e) + return node + + def visit_UnaryOp(self, node): + #print('****************** Found Unary Operation *******************') + if self.safe_inc_op == 1 and node.op in incr_decr_ops.keys(): + self.inc_ops_2_swap_ids.append(node.coord) + node.expr = self.visit(node.expr) + return node + + def visit_BinaryOp(self, node): + # print('****************** Found Binary Operation *******************') + # print(node.show()) + self.safe_inc_op -= 1 + left = self.visit(node.left) + right = self.visit(node.right) + self.safe_inc_op += 1 + if node.op in bin_ops_2_swap.keys(): + self.num_bin_ops_2_swap += 1 + return c_ast.BinaryOp(node.op, left, right, node.coord) + + def visit_TernaryOp(self, node): + # print('****************** Found Ternary Op Node *******************') + if_id = node_id(node.coord) + self.if_2_swap_ids.append(if_id) + n_cond = self.visit(node.cond) + n_iftrue = self.visit(node.iftrue) + n_iffalse = node.iffalse + # if there exists and else statement + if n_iffalse is not None: + n_iffalse = self.visit(n_iffalse) + #print('****************** New Cond Node *******************') + n_ternary = c_ast.TernaryOp(n_cond, n_iftrue, n_iffalse, node.coord) + return n_ternary + + def visit_FuncDef(self, node): + #print('****************** Found FuncDef Node *******************') + decl = node.decl + param_decls = node.param_decls + if "main" != node.decl.name and "fakestart" != node.decl.name: #ignore main function + # if the function has parameters add them to the scope + if node.decl.type.args: + pass + body = node.body + coord = node.coord + n_body_1 = self.visit(body) + n_func_def_ast = c_ast.FuncDef(decl, param_decls, n_body_1, coord) + + return n_func_def_ast + + def visit_FuncCall(self, node): + #print('****************** Found FuncCall Node *******************') + if node.args: + node.args = self.visit(node.args) + return c_ast.FuncCall(node.name, node.args, node.coord) + + def visit_ExprList(self, node): + # print('****************** Found ExprList Node *******************') + for e in range(len(node.exprs)): + node.exprs[e] = self.visit(node.exprs[e]) + return node + + def visit_ParamList(self, node): + # print('****************** Found ParamList Node *******************') + for e in range(len(node.params)): + node.params[e] = self.visit(node.params[e]) + return node + + def visit_Compound(self, node): + #print('****************** Found Compound Node *******************') + block_items = node.block_items + coord = node_id(node.coord) + self.curr_block = str(coord) + self.blocks_vars[self.curr_block] = dict() + self.blocks_vars[self.curr_block]["decls_id"] = [] + self.blocks_vars[self.curr_block]["var_2_coord"] = dict() + self.blocks_vars[self.curr_block]["decls_dependencies"] = [] + self.blocks_vars[self.curr_block]["permutations"] = [] + n_block_items = [] + if block_items is not None: + for x in block_items: + if isinstance(x, c_ast.Decl): + self.declaring_var = True + + n_block_items.append(self.visit(x)) + + self.declaring_var = False + self.curr_block = str(coord) + + self.blocks_vars[self.curr_block]["permutations"] = getTopologicalOrders(self.blocks_vars[self.curr_block]["decls_id"], self.blocks_vars[self.curr_block]["decls_dependencies"]) + # print(self.blocks_vars[self.curr_block]["var_2_coord"]) + # print("dependencies") + # print(self.blocks_vars[self.curr_block]["decls_dependencies"]) + # print(len(self.blocks_vars[self.curr_block]["permutations"])) + # print(self.blocks_vars[self.curr_block]["permutations"]) + if self.blocks_vars[self.curr_block]["decls_id"] == []: + del self.blocks_vars[self.curr_block] + + self.curr_block = "global" + n_compound_ast = c_ast.Compound(n_block_items, node.coord) + return n_compound_ast + + def visit_If(self, node): + #print('****************** Found IF Node *******************') + if_id = node_id(node.coord) + n_cond = self.visit(node.cond) + if isinstance(node.iftrue, c_ast.Compound): + n_iftrue = self.visit(node.iftrue) + else: + n_iftrue = self.visit(c_ast.Compound([node.iftrue], node.iftrue.coord)) + if self.check_simple_if_else: + self.check_simple_if_else = False + else: + self.check_simple_if_else = True + + if node.iffalse is not None and not isinstance(node.iffalse, c_ast.Compound): + node.iffalse = c_ast.Compound([node.iffalse], node.iffalse.coord) + n_iffalse = self.visit(node.iffalse) + # if there exists and else statement + if n_iffalse is not None and self.check_simple_if_else: + self.if_2_swap_ids.append(if_id) + # if is just an if without and else or if we already saved the id of the node we can turn off the flag. + self.check_simple_if_else = False + #print('****************** New Cond Node *******************') + n_if = c_ast.If(n_cond, n_iftrue, n_iffalse, node.coord) + return n_if + + def visit_For(self, node): + # print('****************** Found For Node *******************') + for_id = node_id(node.coord) + n_init = self.visit(node.init) + n_cond = self.visit(node.cond) + self.find_continue = False + if not isinstance(node.stmt, c_ast.Compound): + node.stmt = c_ast.Compound([node.stmt], node.stmt.coord) + n_stmt = self.visit(node.stmt) + if self.found_continue: + self.found_continue = False + else: + self.for_ids_2_swap.append(for_id) + n_next = self.visit(node.next) + # We dont need to put a scope_info at the end of the for because the compound node already does that + n_for = c_ast.For(n_init, n_cond, n_next, n_stmt, node.coord) + return n_for + + def visit_While(self, node): + #print('****************** Found While Node *******************') + while_id = node_id(node.coord) + n_cond = self.visit(node.cond) + n_stmt = self.visit(node.stmt) + n_while = c_ast.While(c_ast.ExprList([n_cond]), n_stmt, node.coord) + return n_while + + def visit_Continue(self, node): + # print('****************** Found Continue Node *******************') + self.found_continue = True + return node + + def generic_visit(self, node): + #print('****************** Something else ************') + return node + +#----------------------------------------------------------------- +# A visitor that swaps the arguments of binary operators such as >, < <=, >= +class SwapBinOpsVisitor(MutatorVisitor): + + def __init__ (self, bin_ops_2_swap): + super().__init__() + # bin_ops_2_swap is a list of booleans that says if each binary operation is to swap or not + self.bin_ops_2_swap = bin_ops_2_swap + + def visit(self, node): + return MutatorVisitor.visit(self, node) + + def visit_BinaryOp(self, node): + # print('****************** Found Binary Operation *******************') + # print(node.show()) + left = self.visit(node.left) + right = self.visit(node.right) + if node.op in bin_ops_2_swap.keys() and len(self.bin_ops_2_swap) > 0: + if self.bin_ops_2_swap[0]: + self.bin_ops_2_swap.pop(0) + return c_ast.BinaryOp(bin_ops_2_swap[node.op], right, left, node.coord) + else: + self.bin_ops_2_swap.pop(0) + + return c_ast.BinaryOp(node.op, left, right, node.coord) + +#----------------------------------------------------------------- +# A visitor that swaps the simple if-statements by negating its test condition and swapping the if-block with the else-block. +class SwapIfElseVisitor(MutatorVisitor): + + def __init__ (self, ifs_2_swap, if_ids): + super().__init__() + self.ifs_2_swap = ifs_2_swap + self.ifs_ids = if_ids + + def visit(self, node): + return MutatorVisitor.visit(self, node) + + def visit_If(self, node): + #print('****************** Found IF Node *******************') + if_id = node_id(node.coord) + n_cond = self.visit(node.cond) + n_iftrue = self.visit(node.iftrue) + n_iffalse = self.visit(node.iffalse) + # if there exists and else statement + if if_id in self.ifs_ids and len(self.ifs_2_swap) > 0: + if self.ifs_2_swap[0]: + self.ifs_2_swap.pop(0) + return c_ast.If(c_ast.UnaryOp("!", n_cond, node.coord) , n_iffalse, n_iftrue, node.coord) + self.ifs_2_swap.pop(0) + n_if = c_ast.If(n_cond, n_iftrue, n_iffalse, node.coord) + return n_if + + def visit_TernaryOp(self, node): + # print('****************** Found Ternary Op Node *******************') + if_id = node_id(node.coord) + n_cond = self.visit(node.cond) + n_iftrue = self.visit(node.iftrue) + n_iffalse = self.visit(node.iffalse) + if if_id in self.ifs_ids and len(self.ifs_2_swap) > 0: + if self.ifs_2_swap[0]: + self.ifs_2_swap.pop(0) + return c_ast.TernaryOp(c_ast.UnaryOp("!", n_cond, node.coord), n_iffalse, n_iftrue, node.coord) + self.ifs_2_swap.pop(0) + return c_ast.TernaryOp(n_cond, n_iftrue, n_iffalse, node.coord) + +#----------------------------------------------------------------- +# A visitor that swaps the increment/decrement operators (++, --) when these are not being used inside an assignment or a binary operation. +class SwapIncrDecrOpsVisitor(MutatorVisitor): + def __init__ (self, inc_ops_2_swap, inc_ops_ids): + super().__init__() + self.inc_ops_2_swap = inc_ops_2_swap + self.inc_ops_ids = inc_ops_ids + + def visit(self, node): + return MutatorVisitor.visit(self, node) + + def visit_UnaryOp(self, node): + # print('****************** Found Binary Operation *******************') + # print(node.show()) + expr = self.visit(node.expr) + if node.op in incr_decr_ops.keys() and len(self.inc_ops_2_swap) > 0: + if self.inc_ops_2_swap[0]: + self.inc_ops_2_swap.pop(0) + return c_ast.UnaryOp(incr_decr_ops[node.op], expr, node.coord) + else: + self.inc_ops_2_swap.pop(0) + + return c_ast.UnaryOp(node.op, expr, node.coord) + + +#----------------------------------------------------------------- +# A visitor that declares a new dummy variable in the main's block. A variable that is not used througout the program. +class DeclDumVarVisitor(MutatorVisitor): + def __init__ (self, vars_set, new_var=True): + super().__init__() + self.new_var = new_var + self.vars_set = vars_set + + def visit(self, node): + return MutatorVisitor.visit(self, node) + + def visit_FuncDef(self, node): + #print('****************** Found FuncDef Node *******************') + body = node.body + coord = node.coord + if "main" == node.decl.name and self.new_var: + last_decl = -1 + # each functions definition has a compound node inside a compound node for some reason. + # that why we are using body.block_items[0].block_items + for i in range(len(body.block_items)): + x = body.block_items[i] + if isinstance(x, c_ast.Compound): + for j in range(len(x.block_items)): + z = x.block_items[j] + if isinstance(z, c_ast.Decl) and isinstance(z.type, c_ast.TypeDecl): + last_decl = j + continue + else: + break + new_var_name = gen_fresh_var_name(self.vars_set, "int") + body.block_items[i].block_items.insert(last_decl+1, c_ast.Decl(name=new_var_name, + quals=[], + storage=[], + funcspec=[], + align=[], + type=c_ast.TypeDecl(new_var_name, quals=[], align=[], type=c_ast.IdentifierType(['int']), coord=node.coord), + init=None, + bitsize=None , + coord=None)) + else: + if isinstance(x, c_ast.Decl) and isinstance(x.type, c_ast.TypeDecl): + last_decl = i + continue + else: + new_var_name = gen_fresh_var_name(self.vars_set, "int") + body.block_items.insert(last_decl+1, c_ast.Decl(name=new_var_name, + quals=[], + storage=[], + funcspec=[], + align=[], + type=c_ast.TypeDecl(new_var_name, quals=[], align=[], type=c_ast.IdentifierType(['int']), coord=node.coord), + init=None, + bitsize=None , + coord=None)) + break + n_body = self.visit(body) + n_func_def_ast = c_ast.FuncDef(node.decl, node.param_decls, n_body, coord) + return n_func_def_ast + +#----------------------------------------------------------------- +# A visitor that reorder the variable declarations in a program based on the provided topological sorting. +class ReorderVarDeclsVisitor(MutatorVisitor): + def __init__ (self, blocks_reordering): + super().__init__() + self.blocks_reordering = blocks_reordering + + def visit(self, node): + return MutatorVisitor.visit(self, node) + + def visit_Compound (self, node): + #print('****************** Found Compound Node *******************') + block_items = node.block_items + coord = node_id(node.coord) + n_block_items = [] + if block_items is not None: + if str(coord) in self.blocks_reordering.keys(): + last_decl = 0 + for i in range(len(block_items)): + x = block_items[i] + if isinstance(x, c_ast.Decl): + last_decl = i + continue + else: + break + new_order = [] + for d in self.blocks_reordering[str(coord)]: + for x in block_items: + if str(node_id(x.coord)) == str(d): + new_order.append(x) + break + # block_items = new_order + block_items[last_decl:] if args.dummy_var or args.all_mut else new_order + block_items[last_decl+1:] + block_items = new_order + block_items[last_decl+1:] + + for x in block_items: + n_block_items.append(self.visit(x)) + + n_compound_ast = c_ast.Compound(n_block_items, node.coord) + return n_compound_ast + +def get_possible_blocks_permutations(blocks_info): + blocks = [] + num_decls_per_block = [] + blocks_permutations = [] + for b in blocks_info.keys(): + perms = blocks_info[b]["permutations"] + if len(perms) == 0: + continue + blocks.append(b) + blocks_permutations.append(perms) + num_decls_per_block.append(list(range(len(perms)))) + + permutations = list(product(*num_decls_per_block)) + blocks_reorderings = [] + for p in permutations: + d = dict() + for b in range(len(p)): + # b is the position of the block we are dealing with + i = p[b] # i is the permuation i of block n + d[str(blocks[b])] = blocks_permutations[b][i] + blocks_reorderings.append(d) + + if blocks_reorderings == []: + return [list()] + + return blocks_reorderings + +#----------------------------------------------------------------- +# A visitor that translates simple for-loops (without any continue instruction) into a while-loop +class For2WhileVisitor(MutatorVisitor): + def __init__ (self, fors_2_swap, fors_ids_2_swap): + super().__init__() + self.fors_2_swap = fors_2_swap + self.fors_ids_2_swap = fors_ids_2_swap + + def visit(self, node): + return MutatorVisitor.visit(self, node) + + def visit_Compound(self, node): + #print('****************** Found Compound Node *******************') + block_items = node.block_items + coord = node.coord + n_block_items = [] + if block_items is not None: + for i in range(len(block_items)): + x = block_items[i] + if isinstance(x, c_ast.For) and (node_id(x.coord) in self.fors_ids_2_swap) and len(self.fors_2_swap) > 0: + if self.fors_2_swap[0]: + self.fors_2_swap.pop(0) + n_block_items.append(self.visit(x.init)) + if isinstance(x.stmt, c_ast.Compound): + x.stmt.block_items.append(x.next) + n_block_items.append(self.visit(c_ast.While(x.cond, x.stmt, coord=x.coord))) + else: + n_block_items.append(self.visit(c_ast.While(x.cond, c_ast.Compound([x.stmt, x.next], coord=x.coord), coord=x.coord))) + else: + self.fors_2_swap.pop(0) + n_block_items.append(self.visit(x)) + else: + n_block_items.append(self.visit(x)) + + n_compound_ast = c_ast.Compound(n_block_items, coord) + return n_compound_ast + +#----------------------------------------------------------------- + +def gen_binary_lists(num_ops): + # Given a natural number num_ops, returns a lists of list of booleans. + # each sublist corresponds to a binary number from 0 to num_ops + # the binary number is represented as boolean values e.g. 10 -> ["10", ["True", "False"]] + bin_lists = [] + # w = len(binary_repr(num_ops)) + w = num_ops + for n in range(2**(num_ops)): + bl = [] + bn = binary_repr(n, width=w) + for b in bn: + if b == "0": + bl.append(False) + elif b == "1": + bl.append(True) + bin_lists.append([bn,bl]) + return bin_lists + +def gen_fresh_var_name(var_maps, t): + for i in range(len(var_maps.keys())): + n_v = "_{t}_{i}_".format(t=t, i=i) + if n_v in var_maps.keys(): + continue + return n_v + +def gen_variable_mappings(var_maps, bn, bin_numbers, output_dir): + # for bn_a in bin_numbers: + # if bn_a == bn: + # break + bn_a = bin_numbers[0] + var_dict = dict() + # print(var_maps) + other_d = var_maps[bn_a] + d = var_maps[bn] + for v in other_d.keys(): + if v in d.keys() and d[v] == other_d[v] and v not in var_dict.keys(): + var_dict[v] = v + elif v not in d.keys() and v not in var_dict.keys(): + var_dict[v] = "UnkVar" + + for v in d.keys(): + if v in other_d.keys() and d[v] == other_d[v] and v not in var_dict.keys(): + var_dict[v] = v + elif v not in other_d.keys() and v not in var_dict.keys(): + var_dict["UnkVar"] = v + + p_name = output_dir+'/var_map-{bn1}_{bn2}.pkl.gz'.format(bn1=bn_a, bn2=bn) + fp=gzip.open(p_name,'wb') + pickle.dump(var_dict,fp) + fp.close() + +def get_prog_name(bops, bifs, biops, dv, block, fors): + # based on the users' arguments the name of the program will contain information about the mutations required + p_name = "" + p_name = bops+"-" if args.comp_ops or args.all_mut else p_name + p_name = p_name+bifs+"-" if args.if_else or args.all_mut else p_name + p_name = p_name+biops+"-" if args.incr_ops or args.all_mut else p_name + p_name = p_name+str(dv)+"-" if args.dummy_var or args.all_mut else p_name + p_name = p_name+block+"-" if args.reord_decls or args.all_mut else p_name + p_name = p_name+fors+"-" if args.for_2_while or args.all_mut else p_name + return p_name[:-1] + +def instrument_file(input_file, output_dir): + output_file, sincludes, includes = make_output_dir(input_file, output_dir)#, logfilename, loglibpath) + try: + ast = parse_file(output_file, use_cpp=True, + cpp_path='gcc', + cpp_args=['-E', '-Iutils/fake_libc_include']) + except: + return 0 + + # print('******************** INPUT FILE: ********************') + v = c_ast.NodeVisitor() + v.visit(ast) + # ast.show() + # exit() + # v = VariablesVisitor() + v = MutatorVisitor() + gen = c_generator.CGenerator () + n_ast = v.visit(ast) + # n_ast.show() + # return + if args.verbose: + print() + print(input_file) + print("Variables :", v.scope_vars) + print("Number of BinOps of interest:", v.num_bin_ops_2_swap) + print("Number of simple if-statements to swap", len(v.if_2_swap_ids)) + print("Number of increment operators to swap", len(v.inc_ops_2_swap_ids)) + print("Number of for-loops that can be translated into while-loops:", len(v.for_ids_2_swap)) + print("Declaration of variables:") + print(" Number of blocks with vars declared:", len(v.blocks_vars)) + ord = 0 + for k in v.blocks_vars.keys(): + ord += len(v.blocks_vars[k]["permutations"]) + # print(v.blocks_vars[k]) + print(" Number of permutations:", ord) + # return + + bin_ops_2_swap = gen_binary_lists(v.num_bin_ops_2_swap) if args.comp_ops or args.all_mut else gen_binary_lists(0) + if_elses_2_swap = gen_binary_lists(len(v.if_2_swap_ids)) if args.if_else or args.all_mut else gen_binary_lists(0) + inc_ops_2_swap = gen_binary_lists(len(v.inc_ops_2_swap_ids)) if args.incr_ops or args.all_mut else gen_binary_lists(0) + dv_limit = -1 if args.dummy_var or args.all_mut else 0 + fors_2_swap = gen_binary_lists(len(v.for_ids_2_swap)) if args.for_2_while or args.all_mut else gen_binary_lists(0) + block_permutations = get_possible_blocks_permutations(v.blocks_vars) if args.reord_decls or args.all_mut else [list()] + n_reorderings = len(block_permutations) + + total_progs = len(bin_ops_2_swap)*len(if_elses_2_swap)*len(inc_ops_2_swap)*len(range(1, dv_limit, -1))*n_reorderings*len(fors_2_swap) + if args.verbose: + print("Number of possible reorderings: :", n_reorderings) + print("\n#Total number of programs:", str(total_progs)) + + if not args.enumerate_all or args.percentage_total_progs is not None: + perc = 0.2 + if args.percentage_total_progs is not None: + perc = float(args.percentage_total_progs) + elif total_progs > 500: + perc = 0.1 if total_progs < 100000 else 0.01 + + min_per_mutation = 25 + while total_progs > 250: + if len(bin_ops_2_swap) > min_per_mutation: + bin_ops_2_swap = [bin_ops_2_swap[0]] + random.sample(bin_ops_2_swap[1:], max(int(perc * len(bin_ops_2_swap)-1), 1)) + if len(if_elses_2_swap) > min_per_mutation: + if_elses_2_swap = [if_elses_2_swap[0]] + random.sample(if_elses_2_swap[1:], max(int(perc * len(if_elses_2_swap)-1), 1)) + if len(inc_ops_2_swap) > min_per_mutation: + inc_ops_2_swap = [inc_ops_2_swap[0]] + random.sample(inc_ops_2_swap[1:], max(int(perc * len(inc_ops_2_swap)-1), 1)) + if len(fors_2_swap) > min_per_mutation: + fors_2_swap = [fors_2_swap[0]] + random.sample(fors_2_swap[1:], max(int(perc * len(fors_2_swap)-1), 1)) + if len(block_permutations) > min_per_mutation: + block_permutations = [block_permutations[0]] + random.sample(block_permutations[1:], max(int(perc*len(block_permutations)), 1)) + n_reorderings = len(block_permutations) + total_progs = len(bin_ops_2_swap)*len(if_elses_2_swap)*len(inc_ops_2_swap)*len(range(1, dv_limit, -1))*n_reorderings*len(fors_2_swap) + perc = perc*0.9 + min_per_mutation = 1 if min_per_mutation == 1 else min_per_mutation - 1 + + if args.verbose: + print() + print("Number of Programs with BinOps swapped:", len(bin_ops_2_swap)) + print("Number of Programs with if-statements swapped:", len(if_elses_2_swap)) + print("Number of Programs with swapped increment operators:", len(inc_ops_2_swap)) + print("Number of Programs with for translated 2 whiles loops:", len(fors_2_swap)) + print(" Number of blocks reorders:", n_reorderings) + + if args.verbose: + print("\n\nNumber of possible reorderings (Sampled):", n_reorderings) + total_progs = len(bin_ops_2_swap)*len(if_elses_2_swap)*len(inc_ops_2_swap)*len(range(1, dv_limit, -1))*n_reorderings*len(fors_2_swap) + print("#Total number of programs (Sampled):", total_progs) + print() + + total_progs = len(bin_ops_2_swap)*len(if_elses_2_swap)*len(inc_ops_2_swap)*len(range(1, dv_limit, -1))*n_reorderings*len(fors_2_swap) + if args.info: + #Total number of programs:" + os.system("rm "+output_file) + return total_progs + # print(bin_numbers) + var_maps = dict() + prev_nums = list() + for bops_n, bops_l in bin_ops_2_swap: + # print(bops_n, bops_l) + for bifs_n, bifs_l in if_elses_2_swap: + for biops_n, biops_l in inc_ops_2_swap: + for dummy_var in range(1, dv_limit, -1): # declaring new dummy variable + for b in range(n_reorderings): + for bfors_n, bfors_l in fors_2_swap: + block_bin = binary_repr(b, width=len(binary_repr(n_reorderings))) + b_ast = parse_file(output_file, use_cpp=True, cpp_path='gcc', cpp_args=['-E', '-Iutils/fake_libc_include']) + prev_nums.append(get_prog_name(bops_n, bifs_n, biops_n, dummy_var, block_bin, bfors_n)) + curr_num = prev_nums[-1] + if args.comp_ops or args.all_mut: + v_h = SwapBinOpsVisitor(list(bops_l)) + b_ast = v_h.visit(b_ast) + var_maps[curr_num] = v.scope_vars + # if args.verbose: + # print("SwapBinOpsVisitor done") + if args.if_else or args.all_mut: + v_h = SwapIfElseVisitor(list(bifs_l), v.if_2_swap_ids) + b_ast = v_h.visit(b_ast) + var_maps[curr_num] = v.scope_vars + # if args.verbose: + # print("SwapIfElseVisitor done") + if args.incr_ops or args.all_mut: + v_h = SwapIncrDecrOpsVisitor(list(biops_l), v.inc_ops_2_swap_ids) + b_ast = v_h.visit(b_ast) + var_maps[curr_num] = v.scope_vars + # if args.verbose: + # print("SwapIncrDecrOpsVisitor done") + if (args.reord_decls or args.all_mut) and block_permutations[b]!=[]: + # we need to verify if the program has no variables + v_h = ReorderVarDeclsVisitor(block_permutations[b]) + b_ast = v_h.visit(b_ast) + var_maps[curr_num] = v.scope_vars + # if args.verbose: + # print("ReorderVarDeclsVisitor done") + if args.for_2_while or args.all_mut: + v_h = For2WhileVisitor(list(bfors_l), v.for_ids_2_swap) + b_ast = v_h.visit(b_ast) + var_maps[curr_num] = v.scope_vars + # if args.verbose: + # print("For2WhileVisitor done") + if args.dummy_var or args.all_mut: + v_h = DeclDumVarVisitor(v.scope_vars, True if dummy_var == 1 else False) + b_ast = v_h.visit(b_ast) + v2 = MutatorVisitor() + n_ast = v2.visit(b_ast) + var_maps[curr_num] = v2.scope_vars + # if args.verbose: + # print("DeclDumVarVisitor done") + + gen_output_file(gen, b_ast, sincludes + includes, curr_num, output_dir) + gen_variable_mappings(var_maps, curr_num, prev_nums, output_dir) + + os.system("rm "+output_file) + +#----------------------------------------------------------------- + +def gen_program_mutations(progs_dir, output_dir): + total_progs = 0 + progs = list(pathlib.Path(progs_dir).glob('*.c')) + for p in progs: + np = str(p) + if "/" in np: + np = np.split("/")[-1] + stu_id = np.split("-")[1] if "-" in np else np.replace(".c", "") + if args.verbose: + print("Dealing with student ", stu_id) + try: + s_muts = instrument_file(p, output_dir+"/"+stu_id) + except: + continue + s_muts = instrument_file(p, output_dir+"/"+stu_id) + if args.info and s_muts is not None: + total_progs += s_muts + if args.info: + print(total_progs) + os.system("rm -rf "+output_dir) + + +#----------------------------------------------------------------- + +def parser(): + parser = argparse.ArgumentParser(prog='prog_mutator.py', formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('-c', '--comp_ops', action='store_true', default=False, help='Swaps the comparison operators.') + parser.add_argument('-if', '--if_else', action='store_true', default=False, help='Swaps the simple if-else-statements.') + parser.add_argument('-io', '--incr_ops', action='store_true', default=False, help='Swaps the increment operators (e.g. i++, ++i and i+=1) if these are not used in a binary operation or in an assignment.') + parser.add_argument('-dv', '--dummy_var', action='store_true', default=False, help='Declares a dummy variable in the beginning of the main function.') + parser.add_argument('-rd', '--reord_decls', action='store_true', default=False, help='Reorder the order of variable declarations, when it is possible i.e., when two variables\' declarations do not depend on each other') + parser.add_argument('-fw', '--for_2_while', action='store_true', default=False, help='Translates simple for-loops (without any continue instruction) into a while-loop.') + parser.add_argument('-a', '--all_mut', action='store_true', default=False, help='Performs all the mutations above.') + parser.add_argument('-p', '--percentage_total_progs', type=float, help='Instead of generating all possible mutations the script only generates this percentage. Default 0.01 if the total number of possible mutations is higher than 100k or 0.1 otherwise.') + parser.add_argument('-d', '--input_dir', help='Name of the input directory.') + parser.add_argument('-o', '--output_dir', help='Name of the output directory.') + parser.add_argument('-info', '--info', action='store_true', default=False, help='Prints the total number of programs the required mutations can produced and exits without producing the sets of programs.') + parser.add_argument('-ea', '--enumerate_all', action='store_true', default=False, help='Enumerates all possible mutated programs. NOTE: Sometimes the number of mutated programs is more than 200K Millions of programs.') + parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Prints debugging information.') + args = parser.parse_args(argv[1:]) + return args + + +if __name__ == "__main__": + args = parser() + if len(sys.argv) >= 2: + input_dir = args.input_dir + output_dir = args.output_dir + gen_program_mutations(input_dir, output_dir) + else: + print('{0} -h'.format(sys.argv[0])) + diff --git a/prog_mutilator.py b/prog_mutilator.py new file mode 100755 index 0000000..ce89903 --- /dev/null +++ b/prog_mutilator.py @@ -0,0 +1,523 @@ +#!/usr/bin/python +#Title : prog_mutilator.py +#Usage : python prog_mutilator.py -h +#Author : pmorvalho +#Date : May 31, 2022 +#Description : Program Mutilator - Mutilates programs by: (1) swapping comparison operators; (2) changing the variable being used by another; and (3) deleting expressions from the code. Or applying more than one of these mutilations. +#Notes : This script is from: https://github.com/pmorvalho/MultIPAs +#Python Version: 3.8.5 +# (C) Copyright 2022 Pedro Orvalho. +#============================================================================== + +from __future__ import print_function +import sys, os +import re +from copy import deepcopy +import argparse +from sys import argv +from shutil import copyfile +from topological_sorting import getTopologicalOrders + +from itertools import product, combinations, chain +from numpy import binary_repr +import pickle +import gzip +import pathlib + +import random + +# This is not required if you've installed pycparser into +# your site-packages/ with setup.py +sys.path.extend(['.', '..']) + +from pycparser import c_parser, c_ast, parse_file, c_generator + +from helper import * + +#----------------------------------------------------------------- + +bin_ops_2_swap = {"<" : "<=", ">" : ">=", "<=" : "<", ">=" : ">", "==" : "=", "!=" : "=="} + +#----------------------------------------------------------------- +class MutilatorVisitor(c_ast.NodeVisitor): + + def __init__ (self): + # list with the program variables + self.scope_vars = dict() + # number of binary operations to swap + self.bin_ops_2_swap = list() + # list of bugs introduced + self.bugs_list = dict() + # inside a declaration flag + self.inside_declaration = False + # the following is a list of lists of every possible variable misuse one can perform. + # Each sublist contains for each identifier nodes which are identifiers one can swap and maintain the same type in order for the program to compile. + self.possible_variable_misuses = list() + # The list of node_ids of assignments we can safely remove i.e. that are not part of some variable declaration + self.possible_assignment_deletion = list() + + def visit(self, node): + #node.show() + return c_ast.NodeVisitor.visit(self, node) + + def visit_FileAST(self, node): + #print('****************** Found FileAST Node *******************') + n_ext = [] + fakestart_pos = -1 #for the case of our injected function which do not have the fakestart function in their ast + for e in range(len(node.ext)): + x = node.ext[e] + n_ext.append(self.visit(x)) + if fakestart_pos==-1 and isinstance(x, c_ast.FuncDef) and "fakestart" in x.decl.type.type.declname: + fakestart_pos=e + + + n_file_ast = c_ast.FileAST(n_ext[fakestart_pos+1:]) + return n_file_ast + + def visit_Decl(self, node): + # print('****************** Found Decl Node *******************') + self.inside_declaration = True + if not isinstance(node.type, c_ast.TypeDecl): + # because it can be other type of declaration. Like func declarations. + node.type = self.visit(node.type) + self.inside_declaration = False + if isinstance(node.type, c_ast.Enum): + # Enum are declared in the var_info.h file! + return + else: + return node + # node.show() + type = node.type + if isinstance(type.type, c_ast.Enum): + # type = type.type.name + # node.type = self.visit(node.type) + type = node.type.type + else: + type = type.type.names[0] + + self.scope_vars[node.name] = type + if node.init != None: + node.init = self.visit(node.init) + + self.inside_declaration = False + return node + + + def visit_ArrayDecl(self, node): + #print('****************** Found Decl Node *******************') + # node.show() + return node + + def visit_Assignment(self, node): + # print('****************** Found Assignment Node *******************') + if not self.inside_declaration: + node_info = node_repr(node.coord) + self.possible_assignment_deletion.append(node_info) + node.rvalue = self.visit(node.rvalue) + node.lvalue = self.visit(node.lvalue) + return node + + def visit_ID(self, node): + #print('****************** Found ID Node *******************') + curr_id = node.name + if not self.inside_declaration and curr_id in self.scope_vars.keys(): + # if we are not inside a declaration node then it is safe to change this node's id for other variable already declared of the same type. + # for this we only need to consult the scope_vars map that contains all the variables declared until now and their respective types + var_type = self.scope_vars[curr_id] + node_info = node_repr(node.coord) + var_misuses = [] + for v in self.scope_vars.keys(): + if v == curr_id: + continue # we do not want to swap by the same identifier + if var_type == self.scope_vars[v]: + var_misuses.append((node_info, v)) + + if var_misuses != []: + self.possible_variable_misuses.append(var_misuses) + + return node + + def visit_Enum(self, node): + # #print('****************** Found Enum Node *******************') + # insert each enum on the .h file, after the scope functions of the fakestart function + return node + + def visit_ExprList(self, node): + #print('****************** Found ExprList Node *******************') + for e in node.exprs: + e = self.visit(e) + return node + + def visit_UnaryOp(self, node): + #print('****************** Found Unary Operation *******************') + node.expr = self.visit(node.expr) + return node + + def visit_BinaryOp(self, node): + # print('****************** Found Binary Operation *******************') + # print(node.show()) + left = self.visit(node.left) + right = self.visit(node.right) + if node.op in bin_ops_2_swap.keys(): + self.bin_ops_2_swap.append(node_id(node.coord)) + return c_ast.BinaryOp(node.op, left, right, node.coord) + + def visit_TernaryOp(self, node): + # print('****************** Found Ternary Op Node *******************') + if_id = node_id(node.coord) + n_cond = self.visit(node.cond) + n_iftrue = self.visit(node.iftrue) + n_iffalse = node.iffalse + # if there exists and else statement + if n_iffalse is not None: + n_iffalse = self.visit(n_iffalse) + #print('****************** New Cond Node *******************') + n_ternary = c_ast.TernaryOp(n_cond, n_iftrue, n_iffalse, node.coord) + return n_ternary + + def visit_FuncDef(self, node): + #print('****************** Found FuncDef Node *******************') + decl = node.decl + param_decls = node.param_decls + if "main" != node.decl.name and "fakestart" != node.decl.name: #ignore main function + # if the function has parameters add them to the scope + if node.decl.type.args: + pass + body = node.body + coord = node.coord + n_body_1 = self.visit(body) + n_func_def_ast = c_ast.FuncDef(decl, param_decls, n_body_1, coord) + + return n_func_def_ast + + def visit_FuncCall(self, node): + #print('****************** Found FuncCall Node *******************') + if node.args: + node.args = self.visit(node.args) + return c_ast.FuncCall(node.name, node.args, node.coord) + + def visit_ExprList(self, node): + # print('****************** Found ExprList Node *******************') + for e in range(len(node.exprs)): + node.exprs[e] = self.visit(node.exprs[e]) + return node + + def visit_ParamList(self, node): + # print('****************** Found ParamList Node *******************') + for e in range(len(node.params)): + node.params[e] = self.visit(node.params[e]) + return node + + def visit_Compound(self, node): + #print('****************** Found Compound Node *******************') + block_items = node.block_items + coord = node.coord + n_block_items = [] + if block_items is not None: + for x in block_items: + n_block_items.append(self.visit(x)) + + n_compound_ast = c_ast.Compound(n_block_items, coord) + return n_compound_ast + + def visit_If(self, node): + #print('****************** Found IF Node *******************') + if_id = node_id(node.coord) + n_cond = self.visit(node.cond) + if isinstance(node.iftrue, c_ast.Compound): + n_iftrue = self.visit(node.iftrue) + else: + n_iftrue = self.visit(c_ast.Compound([node.iftrue], node.iftrue.coord)) + + if node.iffalse is not None and not isinstance(node.iffalse, c_ast.Compound): + node.iffalse = c_ast.Compound([node.iffalse], node.iffalse.coord) + n_iffalse = self.visit(node.iffalse) + #print('****************** New Cond Node *******************') + n_if = c_ast.If(n_cond, n_iftrue, n_iffalse, node.coord) + return n_if + + def visit_For(self, node): + # print('****************** Found For Node *******************') + for_id = node_id(node.coord) + n_init = self.visit(node.init) + n_cond = self.visit(node.cond) + if not isinstance(node.stmt, c_ast.Compound): + node.stmt = c_ast.Compound([node.stmt], node.stmt.coord) + n_stmt = self.visit(node.stmt) + n_next = self.visit(node.next) + # We dont need to put a scope_info at the end of the for because the compound node already does that + n_for = c_ast.For(n_init, n_cond, n_next, n_stmt, node.coord) + return n_for + + def visit_While(self, node): + #print('****************** Found While Node *******************') + while_id = node_id(node.coord) + n_cond = self.visit(node.cond) + n_stmt = self.visit(node.stmt) + n_while = c_ast.While(c_ast.ExprList([n_cond]), n_stmt, node.coord) + return n_while + + def visit_Continue(self, node): + # print('****************** Found Continue Node *******************') + return node + + def generic_visit(self, node): + #print('****************** Something else ************') + return node + +#----------------------------------------------------------------- +# A visitor that swaps the comparison operators of simple binary comparisons >, < <=, >= +class SwapBinOpsVisitor(MutilatorVisitor): + + def __init__ (self, bin_ops_2_swap_ids): + super().__init__() + # bin_ops_2_swap is a list of booleans that says if each binary operation is to swap or not + self.bin_ops_2_swap_ids = bin_ops_2_swap_ids + + def visit(self, node): + return MutilatorVisitor.visit(self, node) + + def visit_BinaryOp(self, node): + # print('****************** Found Binary Operation *******************') + # print(node.show()) + left = self.visit(node.left) + right = self.visit(node.right) + if node.op in bin_ops_2_swap.keys() and node_id(node.coord) in self.bin_ops_2_swap_ids: + self.bugs_list[node_repr(node.coord)] = ("BinaryOp-"+node.op, "BinaryOp-"+bin_ops_2_swap[node.op]) + return c_ast.BinaryOp(bin_ops_2_swap[node.op], left, right, node.coord) + return c_ast.BinaryOp(node.op, left, right, node.coord) + +#----------------------------------------------------------------- +# A visitor that introduces a bug of variable misuse i.e., changes the name of some variable occurrence by another variable's identifier +class VariableMisuseVisitor(MutilatorVisitor): + def __init__ (self, var_2_misused): + super().__init__() + self.var_2_misused, self.new_var = var_2_misused + + def visit(self, node): + return MutilatorVisitor.visit(self, node) + + def visit_ID(self, node): + #print('****************** Found ID Node *******************') + node_info = node_repr(node.coord) + if node_info == self.var_2_misused: + self.bugs_list[node_repr(node.coord)] = ("VarMisuse-"+node.name, "VarMisuse-"+self.new_var) + node.name = self.new_var + + return node + +#----------------------------------------------------------------- +#A visitor that introduces the bug of a missing expression in the program in our case we delete assignments that are not related to variables' declarations +class AssignmentDeletionVisitor(MutilatorVisitor): + def __init__ (self, expr_2_delete): + super().__init__() + self.expr_2_delete = expr_2_delete + + def visit(self, node): + return MutilatorVisitor.visit(self, node) + + def visit_Assignment(self, node): + # print('****************** Found Assignment Node *******************') + node_info = node_repr(node.coord) + if node_info == self.expr_2_delete: + self.bugs_list[node_info] = ("AssignmentDeletion",str(node)) + return None + node.rvalue = self.visit(node.rvalue) + node.lvalue = self.visit(node.lvalue) + return node + +#----------------------------------------------------------------- + +def gen_variable_mappings(var_maps, bn, corr_impl_id, output_dir): + var_dict = dict() + other_d = var_maps[corr_impl_id] # the correct program + d = var_maps[bn] + for v in other_d.keys(): + if v in d.keys() and d[v] == other_d[v] and v not in var_dict.keys(): + var_dict[v] = v + elif v not in d.keys() and v not in var_dict.keys(): + var_dict[v] = "UnkVar" + + for v in d.keys(): + if v in other_d.keys() and d[v] == other_d[v] and v not in var_dict.keys(): + var_dict[v] = v + elif v not in other_d.keys() and v not in var_dict.keys(): + var_dict["UnkVar"] = v + + p_name = output_dir+'/var_map-{bn1}_{bn2}.pkl.gz'.format(bn1=corr_impl_id, bn2=bn) + fp=gzip.open(p_name,'wb') + pickle.dump(var_dict,fp) + fp.close() + +def save_bugs_map(bugs_maps, bn, corr_impl_id, output_dir): + p_name = output_dir+'/bug_map-{bn1}-{bn2}.pkl.gz'.format(bn1=corr_impl_id, bn2=bn) + fp=gzip.open(p_name,'wb') + pickle.dump(bugs_maps[bn],fp) + fp.close() + +def get_prog_name(bops, var_mu, exp_del): + # based on the users' arguments the name of the program will contain information about the mutations required + p_name = "" + p_name = bops+"-" if args.comp_ops or args.all_mut else p_name + p_name = p_name+var_mu+"-" if args.var_mu or args.all_mut else p_name + p_name = p_name+exp_del+"-" if args.asg_del or args.all_mut else p_name + return p_name[:-1] + +def instrument_file(input_file, output_dir): + output_file, sincludes, includes = make_output_dir(input_file, output_dir)#, logfilename, loglibpath) + try: + ast = parse_file(output_file, use_cpp=True, + cpp_path='gcc', + cpp_args=['-E', '-Iutils/fake_libc_include']) + except: + return + + # print('******************** INPUT FILE: ********************') + v = c_ast.NodeVisitor() + v.visit(ast) + # ast.show() + # exit() + # v = VariablesVisitor() + v = MutilatorVisitor() + gen = c_generator.CGenerator () + n_ast = v.visit(ast) + original_ast=deepcopy(n_ast) + # n_ast.show() + # return + if args.verbose: + print() + print(input_file) + print("Variables :", v.scope_vars) + print("Number of BinOps of interest:", len(v.bin_ops_2_swap)) + print("Number of possible locations where we can misuse variables", len(v.possible_variable_misuses)) + print("Number of assignment expressions safe to delete:", len(v.possible_assignment_deletion)) + + n_mutilations = int(args.num_mut) + bin_ops_2_swap = list([[]]) + if args.comp_ops or args.all_mut: + if args.single: + bin_ops_2_swap += random.sample(v.bin_ops_2_swap, min(n_mutilations, len(v.bin_ops_2_swap))) + else: + bin_ops_2_swap += list(combinations(v.bin_ops_2_swap, min(n_mutilations, len(v.bin_ops_2_swap)))) + + variable_misuses = list([(None, None)]) # To generatre the correct program without any bug introduced as the first program + if args.var_mu or args.all_mut: + if args.num_mut > 1: + exit("Currently this program can only perform 1 mutilation per program for the variable misuse task. The user is asking for {m} mutilations!".format(m=args.num_mut)) + variable_misuses += list(chain(*v.possible_variable_misuses)) + if args.single: + variable_misuses = [(None,None)] + random.sample(variable_misuses[1:], min(n_mutilations, len(variable_misuses))) + + if args.verbose: + print(" #Variable misuse possibilities: ", len(variable_misuses)) + + assignments_2_delete = list([[]]) + if args.asg_del or args.all_mut: + if args.single: + assignments_2_delete += random.sample(v.possible_assignment_deletion, min(n_mutilations, len(v.possible_assignment_deletion))) + else: + assignments_2_delete += list(v.possible_assignment_deletion) + + if args.info: + total_progs = len(bin_ops_2_swap)*len(variable_misuses)*len(assignments_2_delete) + return total_progs + + var_maps = dict() + prev_nums = list() + bugs_map = dict() + corr_impl_id = None + for b in range(len(bin_ops_2_swap)): + b_id = str(b).rjust(len(str(len(bin_ops_2_swap))), '0') + for vm in range(len(variable_misuses)): + var_misused = variable_misuses[vm] + vm_id = str(vm).rjust(len(str(len(variable_misuses))), '0') + for ad in range(len(assignments_2_delete)): + exp = assignments_2_delete[ad] + exp_id = str(ad).rjust(len(str(len(assignments_2_delete))), '0') + # b_ast = parse_file(output_file, use_cpp=True, cpp_path='gcc', cpp_args=['-E', '-Iutils/fake_libc_include']) + prev_nums.append(get_prog_name(b_id, vm_id, exp_id)) + curr_num = prev_nums[-1] + n_ast=deepcopy(original_ast) + if corr_impl_id is None: + corr_impl_id = curr_num + if args.comp_ops or args.all_mut: + v_h = SwapBinOpsVisitor(bin_ops_2_swap[b]) + b_ast = v_h.visit(n_ast) + var_maps[curr_num] = v.scope_vars + bugs_map[curr_num] = v_h.bugs_list + if args.var_mu or args.all_mut: + v_h = VariableMisuseVisitor(var_misused) + b_ast = v_h.visit(n_ast) + var_maps[curr_num] = v.scope_vars + bugs_map[curr_num] = bugs_map[curr_num] | v_h.bugs_list if curr_num in bugs_map.keys() else v_h.bugs_list + if args.asg_del or args.all_mut: + v_h = AssignmentDeletionVisitor(exp) + b_ast = v_h.visit(n_ast) + var_maps[curr_num] = v.scope_vars + bugs_map[curr_num] = bugs_map[curr_num] | v_h.bugs_list if curr_num in bugs_map.keys() else v_h.bugs_list + + if args.verbose: + print("Bug mapping:", curr_num, bugs_map[curr_num]) + + gen_output_file(gen, b_ast, sincludes + includes, curr_num, output_dir) + tmp_file = get_output_file_name(curr_num, output_dir) + try: + ast = parse_file(tmp_file, use_cpp=True, + cpp_path='gcc', + cpp_args=['-E', '-Iutils/fake_libc_include']) + except: + os.system("rm "+tmp_file) + continue + gen_variable_mappings(var_maps, curr_num, corr_impl_id, output_dir) + save_bugs_map(bugs_map, curr_num, corr_impl_id, output_dir) + + os.system("rm "+output_file) + +#----------------------------------------------------------------- + +def gen_program_mutilations(progs_dir, output_dir): + total_progs = 0 + progs = list(pathlib.Path(progs_dir).glob('*.c')) + progs = random.sample(progs, min(args.num_progs_2_process, len(progs))) + for p in progs: + stu_id = str(p).split("/")[-1][:-2] # to remove the .c + if args.verbose: + print("Dealing with program ", stu_id) + new_dir = output_dir+"/"+stu_id + s_mutils = instrument_file(p, new_dir) + if len(list(pathlib.Path(new_dir).glob('tmp*'))) > 0: + os.system("rm -rf "+new_dir) + if args.info and s_mutils is not None: + total_progs += s_mutils + if args.info: + print(total_progs) + os.system("rm -rf "+output_dir) + +#----------------------------------------------------------------- + +def parser(): + parser = argparse.ArgumentParser(prog='prog_mutilator.py', formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('-c', '--comp_ops', action='store_true', default=False, help='Swaps the comparison operators.') + parser.add_argument('-vm', '--var_mu', action='store_true', default=False, help='Introduces a bug of variable misuse.') + parser.add_argument('-ad', '--asg_del', action='store_true', default=False, help='Introduces a bug of expression deletion (assignments).') + parser.add_argument('-a', '--all_mut', action='store_true', default=False, help='Performs all the mutilations above.') + parser.add_argument('-s', '--single', action='store_true', default=False, help='Generates a single erroneous programs, instead of enumerating all possibilities.') + parser.add_argument('-n', '--num_mut', type=int, default=1, help='Number of mutilations to be performed. (Default = 1).') + parser.add_argument('-pp', '--num_progs_2_process', type=int, default=50, help='Number of programs to process from the input directory. (Default = 50).') + parser.add_argument('-info', '--info', action='store_true', default=False, help='Prints the total number of programs the required mutilations can produced and exits without producing the sets of programs.') + parser.add_argument('-d', '--input_dir', help='Name of the input directory.') + parser.add_argument('-o', '--output_dir', help='Name of the output directory.') + parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Prints debugging information.') + args = parser.parse_args(argv[1:]) + return args + + +if __name__ == "__main__": + args = parser() + if len(sys.argv) >= 2: + input_dir = args.input_dir + output_dir = args.output_dir + gen_program_mutilations(input_dir, output_dir) + else: + print('python {0} -h'.format(sys.argv[0])) + diff --git a/run_all.sh b/run_all.sh new file mode 100755 index 0000000..4e46e6c --- /dev/null +++ b/run_all.sh @@ -0,0 +1,290 @@ +#!/usr/bin/env bash +#Title : run_all.sh +#Usage : bash run_all.sh +#Author : pmorvalho +#Date : May 03, 2022 +#Description : Bash commands to mutate and mutilate programs and generate their representations +#Notes : For each new mutation added to the mutations vector a new for-loop is needed to compute all possible mutations (permutations) +# (C) Copyright 2022 Pedro Orvalho. +#============================================================================== + +# The following command installs the dependencies (pycparser, ..) and creates a conda environment. +# ./config_gnn.sh +conda activate gnn_env + +# mutations=("swap_comp_ops" "swap_if_else_sttms" "swap_incr_decr_ops" "decl_dummy_vars" "reorder_decls" "for_2_while") +mutations=("swap_comp_ops" "swap_if_else_sttms" "swap_incr_decr_ops" "reorder_decls" "for_2_while") +mutations_flags=("-c" "-if" "-io" "-rd" "-fw") + +dataset="C-Pack-IPAs" +#labs=("lab02" "lab03" "lab04") # we are not considering lab05 for this dataset, and only year 2020/2021 has lab05. +labs=("lab02") +years=() + +for y in $(find $dataset/correct_submissions/* -maxdepth 0 -type d); +do + y=$(echo $y | rev | cut -d '/' -f 1 | rev) + years+=("$y") + echo "Found year: "$y +done + +data_dir="mutated_programs" + +mutate_programs(){ +# $1 - year directory +# $2 - submissions directory + year=$1 + sub_dir=$2 + sub_type=$(echo $sub_dir | rev | cut -d '/' -f 1 | rev) + for((l=0;l<${#labs[@]};l++)); + do + lab=${labs[$l]} + for ex in $(find $sub_dir/$year/$lab/ex* -maxdepth 0 -type d); + do + ex=$(echo $ex | rev | cut -d '/' -f 1 | rev) + mkdir -p $data_dir/$sub_type/$year/$lab/$ex + n_mut=0 + echo "Mutating "$dataset/$sub_type/$year/$lab/$ex + for((m1=0;m1<${#mutations[@]};m1++)); + do + mut1=${mutations[$m1]} + f1=${mutations_flags[$m1]} + # echo $mut1 + python prog_mutator.py -d $sub_dir/$year/$lab/$ex -o $data_dir/$sub_type/$year/$lab/$ex/$mut1 $f1 & + n_mut=$((n_mut+1)) + for((m2=m1+1;m2<${#mutations[@]};m2++)); + do + mut2=${mutations[$m2]} + f2=${mutations_flags[$m2]} + # # echo $mut1-$mut2 + python prog_mutator.py -d $sub_dir/$year/$lab/$ex -o $data_dir/$sub_type/$year/$lab/$ex/$mut1-$mut2 $f1 $f2 & + n_mut=$((n_mut+1)) + for((m3=m2+1;m3<${#mutations[@]};m3++)); + do + mut3=${mutations[$m3]} + f3=${mutations_flags[$m3]} + # echo $mut1-$mut2-$mut3 + python prog_mutator.py -d $sub_dir/$year/$lab/$ex -o $data_dir/$sub_type/$year/$lab/$ex/$mut1-$mut2-$mut3 $f1 $f2 $f3 & + n_mut=$((n_mut+1)) + for((m4=m3+1;m4<${#mutations[@]};m4++)); + do + mut4=${mutations[$m4]} + f4=${mutations_flags[$m4]} + # echo $mut1-$mut2-$mut3-$mut4 + python prog_mutator.py -d $sub_dir/$year/$lab/$ex -o $data_dir/$sub_type/$year/$lab/$ex/$mut1-$mut2-$mut3-$mut4 $f1 $f2 $f3 $f4 & + n_mut=$((n_mut+1)) + for((m5=m4+1;m5<${#mutations[@]};m5++)); + do + mut5=${mutations[$m5]} + f5=${mutations_flags[$m5]} + # echo $mut1-$mut2-$mut3-$mut4-$mut5 + python prog_mutator.py -d $sub_dir/$year/$lab/$ex -o $data_dir/$sub_type/$year/$lab/$ex/$mut1-$mut2-$mut3-$mut4-$mut5 $f1 $f2 $f3 $f4 $f5 & + n_mut=$((n_mut+1)) + for((m6=m5+1;m6<${#mutations[@]};m6++)); + do + mut6=${mutations[$m6]} + f6=${mutations_flags[$m6]} + # echo $mut1-$mut2-$mut3-$mut4-$mut5 + python prog_mutator.py -d $sub_dir/$year/$lab/$ex -o $data_dir/$sub_type/$year/$lab/$ex/$mut1-$mut2-$mut3-$mut4-$mut5-$mut6 $f1 $f2 $f3 $f4 $f5 $f6 & + n_mut=$((n_mut+1)) + done + done + done + done + #wait + done + done + wait + echo "In total "$n_mut" different mutations were perform to "$sub_type/$year/$lab/$ex + echo + echo + done + done + wait +} + +represent_programs() +{ + local year=$1 + local sub_dir=$2 + for((l=0;l<${#labs[@]};l++)); + do + lab=${labs[$l]} + for ex in $(find $sub_dir/$year/$lab/ex* -maxdepth 0 -type d); + do + ex=$(echo $ex | rev | cut -d '/' -f 1 | rev) + for mut_d in $(find $sub_dir/$year/$lab/$ex/* -maxdepth 0 -type d); + do + mut=$(echo $mut_d | rev | cut -d '/' -f 1 | rev) + echo "Generating program representations for "$sub_dir/$year/$lab/$ex/$mut + for s in $(find $sub_dir/$year/$lab/$ex/$mut/* -maxdepth 0 -mindepth 0 -type d); + do + python gen_progs_repr.py -d $s & + done + wait + done + done + done +} + +# echo "Starting program mutation..." +# for((y=0;y<${#years[@]};y++)); +# do +# ys=${years[$y]} +# mutate_programs $ys $dataset/correct_submissions +# done + +# echo "Starting to compute program representations" +# for((y=0;y<${#years[@]};y++)); +# do +# ys=${years[$y]} +# represent_programs $ys $data_dir/correct_submissions +# done + +# wait + +mutilations=("wrong_comp_op" "variable_misuse" "expression_deletion") +mutilations_flags=("-c" "-vm" "-ad") +num_progs_2_mutilate=5 + +mutilate_programs(){ +# $1 - year directory +# $2 - submissions directory + local year=$1 + local sub_dir=$2 + local sub_type="mutilated_programs" + for((l=0;l<${#labs[@]};l++)); + do + lab=${labs[$l]} + for ex in $(find $sub_dir/$year/$lab/ex* -maxdepth 0 -type d); + do + ex=$(echo $ex | rev | cut -d '/' -f 1 | rev) + for mut_d in $(find $sub_dir/$year/$lab/$ex/* -maxdepth 0 -type d); + do + mut=$(echo $mut_d | rev | cut -d '/' -f 1 | rev) + n_mutil=0 + echo "Mutilating "$dataset/$sub_type/$year/$lab/$ex/$mut + for s_d in $(find $sub_dir/$year/$lab/$ex/$mut/* -maxdepth 0 -type d); + do + s=$(echo $s_d | rev | cut -d '/' -f 1 | rev) + for((m1=0;m1<${#mutilations[@]};m1++)); + do + mutil1=${mutilations[$m1]} + f1=${mutilations_flags[$m1]} + mkdir -p $data_dir$sub_type/$year/$lab/$ex/$mut/$mutil1/$s + # echo $mutil1 + python prog_mutilator.py -pp $num_progs_2_mutilate -d $sub_dir/$year/$lab/$ex/$mut/$s -o $data_dir$sub_type/$year/$lab/$ex/$mut/$mutil1/$s $f1 & + n_mutil=$((n_mutil+1)) + done + wait + done + wait + echo "In total "$n_mutil" different mutilations were perform to "$sub_type/$year/$lab/$ex/$mut + echo + echo + done + done + done + wait +} + +represent_mutilated_programs() +{ + local year=$1 + local sub_dir=$2 + for((l=0;l<${#labs[@]};l++)); + do + lab=${labs[$l]} + for ex in $(find $sub_dir/$year/$lab/ex* -maxdepth 0 -type d); + do + ex=$(echo $ex | rev | cut -d '/' -f 1 | rev) + for mut_d in $(find $sub_dir/$year/$lab/$ex/* -maxdepth 0 -type d); + do + mut=$(echo $mut_d | rev | cut -d '/' -f 1 | rev) + for mutil_d in $(find $sub_dir/$year/$lab/$ex/$mut/* -maxdepth 0 -type d); + do + mutil=$(echo $mutil_d | rev | cut -d '/' -f 1 | rev) + echo "Generating program representations for "$sub_dir/$year/$lab/$ex/$mut/$mutil + for s in $(find $sub_dir/$year/$lab/$ex/$mut/$mutil/* -maxdepth 0 -mindepth 0 -type d); + do + for d in $(find $s/* -maxdepth 0 -mindepth 0 -type d); + do + python gen_progs_repr.py -d $d & + done + wait + done + done + done + wait + done + done +} + +data_dir="" + +# echo "Starting program mutilation..." +# for((y=0;y<${#years[@]};y++)); +# do +# ys=${years[$y]} +# mutilate_programs $ys $data_dir"mutated_programs/correct_submissions" +# done + +# echo "Starting to compute program representations for our set of erroneous programs" +# for((y=0;y<${#years[@]};y++)); +# do +# ys=${years[$y]} +# represent_mutilated_programs $ys $data_dir"mutilated_programs" +# done + +represent_correct_programs() +{ + local year=$1 + local sub_dir=$2 + echo "Representing "$year" and directory "$sub_dir + for((l=0;l<${#labs[@]};l++)); + do + lab=${labs[$l]} + for ex in $(find $sub_dir/$year/$lab/ex* -maxdepth 0 -type d); + do + #ex=$(echo $ex | rev | cut -d '/' -f 1 | rev) + python gen_progs_repr.py -d $ex + for ast in $(find $sub_dir/$year/$lab/ex*/ast* -maxdepth 0 -type f); + do + prog_ast=$(echo $ast | rev | cut -d '/' -f 1 | rev) + stu=$(echo $prog_ast | rev | cut -d '-' -f 2 | rev) + echo $ex/$prog_ast" to "$ex/"ast-"$stu + mv $ex/$prog_ast $ex/"ast-"$stu".pkl.gz" + done + done + done +} + +# echo "Starting to compute program representations for our set of erroneous programs" +# for((y=0;y<${#years[@]};y++)); +# do +# ys=${years[$y]} +# represent_correct_programs $ys $dataset/"correct_submissions" +# done + +## the following command will regenerate the evaluation dataset. +## ./get_eval_dataset.sh + +# dataset="C-Pack-IPAs" +# labs=("lab02") +# years=() + +# for y in $(find $dataset/correct_submissions/* -maxdepth 0 -type d); +# do +# y=$(echo $y | rev | cut -d '/' -f 1 | rev) +# years+=("$y") +# echo "Found year: "$y +# done + +# ./get_clara_repairs.sh +# ./get_verifix_repairs.sh + +./get_ground_truth_repairs.sh + +./gen_gnn_variable_mappings.sh +./get_baseline_mappings.sh +./get_gnn_based_repairs.sh diff --git a/topological_sorting.py b/topological_sorting.py new file mode 100755 index 0000000..1b23fea --- /dev/null +++ b/topological_sorting.py @@ -0,0 +1,100 @@ +#!/usr/bin/python +#Title : topological_sorting.py +#Usage : python topological_sorting.py +#Author : pmorvalho +#Date : May 17, 2022 +#Description : Computes all the topological ordering from a set of nodes and their respective edges. +#Notes : Code adapted from https://www.techiedelight.com/find-all-possible-topological-orderings-of-dag/ +#Python Version: 3.8.5 +# (C) Copyright 2022 Pedro Orvalho. +#============================================================================== + +import argparse +from sys import argv + +class Graph: + + def __init__(self, edges, nodes): + + # A list of lists to represent an adjacency list + self.paths = [] + self.nodes = nodes + self.adjList = dict() + for n in nodes: + self.adjList[n] = [] + + # stores in-degree of a vertex + # initialize in-degree of each vertex by 0 + self.indegree = dict() + + for n in nodes: + self.indegree[n] = 0 + # add edges to the directed graph + for (src, dest) in edges: + + # add an edge from source to destination + self.adjList[src].append(dest) + + # increment in-degree of destination vertex by 1 + self.indegree[dest] = self.indegree[dest] + 1 + +# Recursive function to find all topological orderings of a given DAG +def findAllTopologicalOrderings(graph, path, discovered, nodes): + # do for every vertex + for v in nodes: + + # proceed only if the current node's in-degree is 0 and + # the current node is not processed yet + if graph.indegree[v] == 0 and not discovered[v]: + + # for every adjacent vertex `u` of `v`, reduce the in-degree of `u` by 1 + for u in graph.adjList[v]: + graph.indegree[u] = graph.indegree[u] - 1 + + # include the current node in the path and mark it as discovered + path.append(v) + discovered[v] = True + + # recur + findAllTopologicalOrderings(graph, list(path), discovered, nodes) + + # backtrack: reset in-degree information for the current node + for u in graph.adjList[v]: + graph.indegree[u] = graph.indegree[u] + 1 + + # backtrack: remove the current node from the path and + # mark it as undiscovered + path.pop() + discovered[v] = False + + # print the topological order if all vertices are included in the path + if len(path) == len(nodes): + graph.paths.append(list(path)) + + +# Print all topological orderings of a given DAG +def getTopologicalOrders(nodes, edges): + + graph = Graph(edges, nodes) + discovered = dict() + for n in nodes: + discovered[n] = False + + # list to store the topological order + path = [] + # find all topological ordering and print + findAllTopologicalOrderings(graph, path, discovered, nodes) + return graph.paths + + +if __name__ == '__main__': + # int a = 0; + # int b = a; + # int c = 2; + # List of graph edges as per the above diagram + edges = [(41, 44)] + # total number of nodes in the graph (labelled from 0 to 7) + n = [40, 41, 44, 39] + + # print all topological ordering of the graph + print(getTopologicalOrders(n, edges)) diff --git a/training.py b/training.py new file mode 100644 index 0000000..b65a046 --- /dev/null +++ b/training.py @@ -0,0 +1,411 @@ +import numpy as np +import gzip +import pickle +from pathlib import Path +import torch +import random +from gnn import VariableMappingGNN +import argparse + +data_dir="data" + +def preprocess_data_test_time(left_ast, right_ast): + left_edge_index_pairs = [] + left_edge_types = [] + for triple in left_ast['edges']: + left_edge_index_pairs.append([triple[0], triple[1]]) + left_edge_types.append(triple[2]) + + left_node_types = [left_ast['nodes2types'][k] for k in left_ast['nodes2types']] + + right_edge_index_pairs = [] + right_edge_types = [] + + for triple in right_ast['edges']: + right_edge_index_pairs.append([triple[0], triple[1]]) + right_edge_types.append(triple[2]) + + right_node_types = [right_ast['nodes2types'][k] for k in right_ast['nodes2types']] + + # var_norm_index = {k: e for (e, k) in enumerate(left_ast['vars2id'])} + # var_norm_index2 = {k: e for (e, k) in enumerate(right_ast['vars2id'])} + + left_node_types = torch.as_tensor(left_node_types) + right_node_types = torch.as_tensor(right_node_types) + + left_edge_index_pairs = torch.as_tensor(left_edge_index_pairs) + right_edge_index_pairs = torch.as_tensor(right_edge_index_pairs) + + left_edge_types = torch.as_tensor(left_edge_types) + right_edge_types = torch.as_tensor(right_edge_types) + + return ((left_node_types, left_edge_index_pairs, left_edge_types, left_ast), + (right_node_types, right_edge_index_pairs, right_edge_types, right_ast)) + +def preprocess_data(left_ast, right_ast, varmap, sample_spec): + + left_edge_index_pairs = [] + left_edge_types = [] + for triple in left_ast['edges']: + + if triple[2] in ablation_edges: + left_edge_index_pairs.append([triple[0], triple[1]]) + left_edge_types.append(triple[2]) + + max_node_described = -1 + for e in left_edge_index_pairs: + if e[0] > max_node_described: + max_node_described = e[0] + + if e[1] > max_node_described: + max_node_described = e[1] + + left_node_types = [left_ast['nodes2types'][k] for k in left_ast['nodes2types']] + + right_edge_index_pairs = [] + right_edge_types = [] + + for triple in right_ast['edges']: + right_edge_index_pairs.append([triple[0], triple[1]]) + right_edge_types.append(triple[2]) + + max_node_described = -1 + for e in right_edge_index_pairs: + if e[0] > max_node_described: + max_node_described = e[0] + + if e[1] > max_node_described: + max_node_described = e[1] + + + right_node_types = [right_ast['nodes2types'][k] for k in right_ast['nodes2types']] + + var_norm_index = {k: e for (e, k) in enumerate(left_ast['vars2id'])} + var_norm_index2 = {k: e for (e, k) in enumerate(right_ast['vars2id'])} + + labels = [] + + # TODO ATTENTION varmap needs to be reversed! + + varmap = {varmap[key]:key for key in varmap} # reversal + for k in varmap: + labels.append(var_norm_index2[varmap[k]]) + + left_node_types = torch.as_tensor(left_node_types) + right_node_types = torch.as_tensor(right_node_types) + + left_edge_index_pairs = torch.as_tensor(left_edge_index_pairs) + right_edge_index_pairs = torch.as_tensor(right_edge_index_pairs) + + left_edge_types = torch.as_tensor(left_edge_types) + right_edge_types = torch.as_tensor(right_edge_types) + + + return ((left_node_types, left_edge_index_pairs, left_edge_types, left_ast), (right_node_types, right_edge_index_pairs, right_edge_types, right_ast), labels, sample_spec) + + +if __name__ == "__main__": + torch.set_num_threads(20) + parser = argparse.ArgumentParser(description='Train a model.') + parser.add_argument('--error', type=str, + help='What bug we want to train on.') + parser.add_argument('--gpu', type=str, + help='Which gpu to use') + parser.add_argument('--expname', type=str, + help='Name of the experiment; defines where trained model is stored.') + parser.add_argument('--samplecap', type=int, + help='How many samples to take from each folder.') + parser.add_argument('--edgetypes', type=str, help='comma-separated list of which edgetypes to used') + + + args = parser.parse_args() + + student_sample_cap = 1 + + path = Path(f"{data_dir}/variable-alignment/mutilated_programs/year-1/lab02/") + + device = torch.device(f"cuda:{args.gpu}" if torch.cuda.is_available() else "cpu") + + # error = "wrong_comp_op" + # error = "variable_misuse" + # error = "expression_deletion" + # error = "all" + errorlist = ["wrong_comp_op", "variable_misuse", "expression_deletion", "all"] + + ablation_edges = [int(k) for k in args.edgetypes.split(",")] + + error = args.error + if error not in errorlist: + raise ValueError("This error is not supported, did you misspell? Use one of these: wrong_comp_op, variable_misuse, expression_deletion or all") + expname = f"{args.expname}_{error}_cap{args.samplecap}" + if error == "all": + use_all_errors = True + else: + use_all_errors = False + + all_exercises = [] + for p in path.glob("*"): + + if p.is_dir(): + all_exercises.append(p) + + print(all_exercises) + print(len(all_exercises)) + + mut_paths = [] + for exercise in all_exercises: + + ex_path = Path(exercise) + for p in ex_path.glob("*"): + if p.is_dir(): + mut_paths.append(p) + + print(mut_paths) + print(len(mut_paths)) + + mutil_paths = [] + for mut in mut_paths: + + mut_path = Path(mut) + for p in mut_path.glob("*"): + if p.is_dir(): + if p.name == error or use_all_errors: + mutil_paths.append(p) + + print(mutil_paths) + print(len(mutil_paths)) + + student_paths = [] + + for mutil in mutil_paths: + + mutil_path = Path(mutil) + for p in mutil_path.glob("*"): + if p.is_dir(): + + student_paths.append(p) + + print(student_paths) + print(len(student_paths)) + student_names = [] + for stu in student_paths: + # print(stu.name) + if not stu.name in student_names: + student_names.append(stu.name) + + # make deterministic + #student_names = sorted(student_names) + + print(len(student_names)) + # assert 2 > 3 + print(len(student_paths)) + student_paths = [k for k in student_paths if not "tmp_input_file" in str(k.absolute())] + print(len(student_paths)) + # assert 2 > 3 + random.seed(18) + student_names.remove("reference_implementation") + #random.shuffle(sorted(student_names)) # sort first to ensure determinism + random.shuffle(student_names) + no_stud = len(student_names) + train_end = int(np.floor(0.8*no_stud)) + train_set = student_names[:train_end] + val_set = student_names[train_end:] + print(val_set) + #valset used last + #valset ['stu_002', 'stu_014', 'stu_009', 'stu_015', 'stu_008'] + #assert 2 > 3 + training_data = [] + val_data = [] + for p in student_paths: + print(p) + assert "year-2" not in str(p.absolute()) + + + for p in student_paths: + + print(p.name) + if p.name in train_set: + print(f"{p.name} in train set") + training_data.append(p) + elif p.name in val_set: + print(f"{p.name} in val set") + val_data.append(p) + else: + print(f"{p.name} not found") + + + # assert (len(val_data) + len(training_data)) == len(student_paths) + # training_data = random.sample(training_data, k = 400) + # val_data = random.sample(val_data, k=20) + + print(len(training_data)) + print(len(val_data)) + print(len(val_data) + len(training_data)) + #assert 2 > 3 + + error_files = [] + + train_samples = [] + for path in training_data: + + files_c = [] + files_ast = [] + files_varmap = [] + + for p in path.rglob("*"): + + if p.name.startswith("var_map"): + files_varmap.append(p) + + + + random.shuffle(files_varmap) + + for sample_specification in files_varmap[:student_sample_cap]: + + original_mutation_file = sample_specification.parents[0].name + + prefix = "var_map-" + postfix = ".pkl.gz" + + tmp_str = str(sample_specification.name)[len(prefix):] + tmp_str = tmp_str[:(len(tmp_str) - len(postfix))] + + left, right = tmp_str.split("_") + + + if not all([k == '0' for k in right]): + # if not (int(left) == 0 and int(right) == 0): + left_ast_file = str(sample_specification.parents[0]) + "/" + "ast-" + right + postfix + right_ast_file = str(sample_specification.parents[0]) + "/" + "ast-" + left + postfix + + student = str(right_ast_file).replace("mutilated_programs", "C-Pack-IPAs_blocks/correct_submissions") + student = Path(student) + student_stump = student.parents[0].parents[0].parents[0].parents[0].parents[0] + student = Path(right_ast_file).parents[0].parents[0].name + + correct_file_path = str(student_stump.absolute()) + "/ast-" + student + ".pkl.gz" + right_ast_file = correct_file_path + # print(left_ast_file) + # print(right_ast_file) + # assert 2 > 3 + + with gzip.open(sample_specification, 'rb') as f: + varmap = pickle.load(f) + print(varmap) + + with gzip.open(left_ast_file, 'rb') as f: + left_ast = pickle.load(f) + + with gzip.open(right_ast_file, 'rb') as f: + right_ast = pickle.load(f) + + # perhaps also add the right to left combo + train_samples.append(preprocess_data(left_ast, right_ast, varmap, sample_specification)) + + + # assert 2 > 3 + val_samples = [] + for path in val_data: + + files_c = [] + files_ast = [] + files_varmap = [] + + for p in path.rglob("*"): + + if p.name.startswith("var_map"): + files_varmap.append(p) + + for sample_specification in files_varmap[:student_sample_cap]: + print(sample_specification) + # try: + prefix = "var_map-" + postfix = ".pkl.gz" + + tmp_str = str(sample_specification.name)[len(prefix):] + tmp_str = tmp_str[:(len(tmp_str) - len(postfix))] + + left, right = tmp_str.split("_") + + print("Program Names: ") + print(left, right) # + if not all([k == '0' for k in right]): + left_ast_file = str(sample_specification.parents[0]) + "/" + "ast-" + right + postfix + right_ast_file = str(sample_specification.parents[0]) + "/" + "ast-" + left + postfix + + student = str(right_ast_file).replace("mutilated_programs", "C-Pack-IPAs_blocks/correct_submissions") + student = Path(student) + student_stump = student.parents[0].parents[0].parents[0].parents[0].parents[0] + student = Path(right_ast_file).parents[0].parents[0].name + + correct_file_path = str(student_stump.absolute()) + "/ast-" + student + ".pkl.gz" + + with gzip.open(sample_specification, 'rb') as f: + varmap = pickle.load(f) + + with gzip.open(left_ast_file, 'rb') as f: + left_ast = pickle.load(f) + + with gzip.open(right_ast_file, 'rb') as f: + right_ast = pickle.load(f) + + # perhaps also add the right to left combo + val_samples.append(preprocess_data(left_ast, right_ast, varmap, sample_specification)) + + # Some global information about which types of nodes exist + with gzip.open("types2int.pkl.gz", 'rb') as f: + node_type_mapping = pickle.load(f) + print(node_type_mapping) + # find maximum index + num_types = node_type_mapping['diff_types'] + print(num_types) + + print(error_files) + print(len(error_files)) + + gnn = VariableMappingGNN(num_types, device).to(device) + + loss = torch.nn.CrossEntropyLoss() + optimizer = torch.optim.Adam(gnn.parameters()) + + + print(len(training_data), len(train_samples)) + print(len(val_data), len(val_samples)) + assert 2>3 + + acc_list = [] + fc_l = [] + + from tqdm import tqdm + + for i in tqdm(range(20)): + global_representation_list = [] + global_orig_sample_list = [] + ep_corr = 0 + ep_total = 0 + random.shuffle(train_samples) + for j in tqdm(range(len(train_samples))): + + gnn.train_step(train_samples[j], loss, optimizer) + + random.shuffle(val_samples) + fully_correct_list = [] + with torch.no_grad(): + for j in tqdm(range(len(val_samples))): + + corr, total, fully_correct = gnn.eval_step(val_samples[j], loss) + + ep_corr += corr + ep_total += total + fully_correct_list.append(fully_correct) + + print(f"Epoch Evaluation Accuracy: {ep_corr} / {ep_total}") + print(f"Epoch Evaluation Samples Fully Correct: {np.mean(fully_correct_list) * 100} %") + fc_l.append(np.mean(fully_correct_list) * 100) + acc_list.append(float(ep_corr) / float(ep_total)) + + torch.save(gnn.state_dict(), f"{data_dir}/{expname}.pt") + +# Example command +# python -u training.py --error variable_misuse --gpu 0 --samplecap 1 --expname dev_cl diff --git a/types2int.pkl.gz b/types2int.pkl.gz new file mode 100644 index 0000000..b145a3e Binary files /dev/null and b/types2int.pkl.gz differ 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 ") + 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 "" +# 1 "" +# 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 @\" to get a list of commands in \n" + " \"help \" for help on \n" + " \"help \" 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,"")) color = "bold"; + if (strstr(s,"")) color = "green"; + if (strstr(s,"")) color = "cyan"; + if (strstr(s,"")) color = "red"; + if (strstr(s,"")) color = "bold"; + if (strstr(s,"") || strstr(s,"")) 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,"") == 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 Server hostname (default: 127.0.0.1).\n" +" -p Server port (default: 6379).\n" +" -s Server socket (overrides hostname and port).\n" +" -a Password to use when connecting to the server.\n" +" -u Server URI.\n" +" -r Execute specified command N times.\n" +" -i When -r is used, waits seconds per command.\n" +" It is possible to specify sub-second times like -i 0.1.\n" +" -n Database number.\n" +" -x Read last argument from STDIN.\n" +" -d 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 Simulate a cache workload with an 80-20 distribution.\n" +" --slave Simulate a slave showing commands received from the master.\n" +" --rdb Transfer an RDB dump from remote server to local file.\n" +" --pipe Transfer raw Redis protocol from stdin to server.\n" +" --pipe-timeout In --pipe mode, abort with error if after sending all data.\n" +" no reply is received within 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 Useful with --scan to specify a SCAN pattern.\n" +" --intrinsic-latency Run a test to measure intrinsic system latency.\n" +" The test will run for the specified amount of seconds.\n" +" --eval Send an EVAL command using the Lua script at .\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;ielements;i++) { + redisAppendCommand(context, "TYPE %s", keys->element[i]->str); + } + + + for(i=0;ielements;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;ielements;i++) { + + if(types[i]==5) + continue; + + redisAppendCommand(context, "%s %s", sizecmds[types[i]], + keys->element[i]->str); + } + + + for(i=0;ielements;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;ielements;i++) { + if((type = types[i]) == 5) + continue; + + totalsize[type] += sizes[i]; + counts[type]++; + totlen += keys->element[i]->len; + sampled++; + + if(biggest[type]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;ielements;i++) { + redisAppendCommand(context, "OBJECT freq %s", keys->element[i]->str); + } + + + for(i=0;ielements;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;ielements;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 "" +# 1 "" +# 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; iiPage; 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=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 && pIternKey = 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 && pIterintKey ){ + + + + pEnd = &pIter[9]; + while( (*pIter++)&0x80 && pItermaxLocal ){ + 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 && pIterxParseCell(pPage, pCell, &info); + if( info.nLocalaDataEnd)>=(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>8), (pAddr)[1] = (u8)(pc+sz)); } + else if( pc>8), (pAddr)[1] = (u8)(pc+sz2)); } + } + goto defragment_out; + } + } + } + + cbrk = usableSize; + iCellLast = usableSize - 4; + for(i=0; iiCellLast ){ + return sqlite3CorruptError(1487); + } + assert( pc>=iCellFirst && pc<=iCellLast ); + size = pPage->xCellSize(pPage, &src[pc]); + cbrk -= size; + if( cbrkusableSize ){ + 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]))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>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( pciCellLast ){ + + 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 || nFreenFree = (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; inCell; i++){ + pc = __builtin_bswap16(*(u16*)(&data[cellOffset+i*2])); + ; + ; + if( pciCellLast ){ + 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; inDb; 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; iaData + ((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; iaData + ((pPage)->maskPage & __builtin_bswap16(*(u16*)(&(pPage)->aCellIdx[2*(i)])))); + if( eType==3 ){ + CellInfo info; + pPage->xParseCell(pPage, pCell, &info); + if( info.nLocal 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( iFreePgpageSize))+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( nOrig0 ){ + 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( nFinnFin && 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->ixnCell ); + 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( offsetinfo.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->ixpPage->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->ixpPage->nCell ); + assert( pCur->info.nSize>0 ); + assert( pCur->info.pPayload>pCur->pPage->aData || (sqlite3Config.neverCorrupt==0) ); + assert( pCur->info.pPayloadpPage->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->ixnCell ); + 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.nKeycurFlags & 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( nCellKeyupr ){ 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->ixpPage->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; iiPage; 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 || (iTrunkpDbPage); + 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; imxPage ){ + rc = sqlite3CorruptError(6063); + goto end_allocate_page; + } + ; + if( !searchList + || (iPage==nearby || (iPagepDbPage); + if( rc ) goto end_allocate_page; + if( closestpDbPage); + 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)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( pCellaData || 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( pPayloadaData || 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( pPrioraData || 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 && idxnCell ); + 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 && NnCell ); + 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 && NnCell ); + 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(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)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; iapCell[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( iOldnCell ) 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=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; inOverflow; i++){ + int iCell = (iOld + pPg->aiOvfl[i]) - iNew; + if( iCell>=0 && iCellaCellIdx[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) && pCellnCell, 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; inCell; + 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( limitaiOvfl[0] ){ + rc = sqlite3CorruptError(7680); + goto balance_cleanup; + } + limit = pOld->aiOvfl[0]; + for(j=0; jnOverflow; 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( piCellnCell+pOld->nOverflow) ); + + cntOld[i] = b.nCell; + if( imaxLocal+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; iaDataEnd; + 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; jnOverflow; j++){ + szNew[i] += 2 + p->xCellSize(p, p->apOvfl[j]); + } + cntNew[i] = cntOld[i]; + } + k = nOld; + for(i=0; iusableSpace ){ + 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]usableSpace ) break; + szNew[i] += sz; + cntNew[i]++; + if( !leafData ){ + 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 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; ipDbPage); + 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; ipgno; + aPgFlags[i] = apNew[i]->pDbPage->flags; + for(j=0; ji ){ + 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=0 && iOld<3 ); + pOld = iOldnCell + 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; ileaf ){ + 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=0 && iPg=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 = iPgnFree = 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; iaData[8]); + ptrmapPut(pBt, key, 5, apNew[i]->pgno, &rc); + } + } + + assert( pParent->isInit ); + + ; + + + + for(i=nNew; ipBt; + + 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; ipDbPage); + if( rc ) return rc; + memset(pDest + i, 0, iAmt - i); + } + }else{ + if( nDatapData) + 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( iOffsetpBtree; + 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( idxnCell ); + 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) || szNewminLocal) + ){ +# 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( iCellDepthiPage-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; inCell; 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]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( pcusableSize-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)ipPage1->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)iautoVacuum && 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 "" +# 1 "" +# 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, ""); + 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;it & 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/X11/Intrinsic.h b/utils/fake_libc_include/X11/Intrinsic.h new file mode 100644 index 0000000..ab7ebb3 --- /dev/null +++ b/utils/fake_libc_include/X11/Intrinsic.h @@ -0,0 +1,4 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" +#include "_X11_fake_defines.h" +#include "_X11_fake_typedefs.h" diff --git a/utils/fake_libc_include/X11/Xlib.h b/utils/fake_libc_include/X11/Xlib.h new file mode 100644 index 0000000..ab7ebb3 --- /dev/null +++ b/utils/fake_libc_include/X11/Xlib.h @@ -0,0 +1,4 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" +#include "_X11_fake_defines.h" +#include "_X11_fake_typedefs.h" diff --git a/utils/fake_libc_include/X11/_X11_fake_defines.h b/utils/fake_libc_include/X11/_X11_fake_defines.h new file mode 100644 index 0000000..c88774b --- /dev/null +++ b/utils/fake_libc_include/X11/_X11_fake_defines.h @@ -0,0 +1,16 @@ +#ifndef _X11_FAKE_DEFINES_H +#define _X11_FAKE_DEFINES_H + +#define Atom CARD32 +#define Bool int +#define KeySym CARD32 +#define Pixmap CARD32 +#define Time CARD32 +#define _XFUNCPROTOBEGIN +#define _XFUNCPROTOEND +#define _Xconst const + +#define _X_RESTRICT_KYWD +#define Cardinal unsigned int +#define Boolean int +#endif diff --git a/utils/fake_libc_include/X11/_X11_fake_typedefs.h b/utils/fake_libc_include/X11/_X11_fake_typedefs.h new file mode 100644 index 0000000..3901142 --- /dev/null +++ b/utils/fake_libc_include/X11/_X11_fake_typedefs.h @@ -0,0 +1,38 @@ +#ifndef _X11_FAKE_TYPEDEFS_H +#define _X11_FAKE_TYPEDEFS_H + +typedef char* XPointer; +typedef unsigned char KeyCode; +typedef unsigned int CARD32; +typedef unsigned long VisualID; +typedef unsigned long XIMResetState; +typedef unsigned long XID; +typedef XID Window; +typedef XID Colormap; +typedef XID Cursor; +typedef XID Drawable; +typedef void* XtPointer; +typedef XtPointer XtRequestId; +typedef struct Display Display; +typedef struct Screen Screen; +typedef struct Status Status; +typedef struct Visual Visual; +typedef struct Widget *Widget; +typedef struct XColor XColor; +typedef struct XClassHint XClassHint; +typedef struct XEvent XEvent; +typedef struct XFontStruct XFontStruct; +typedef struct XGCValues XGCValues; +typedef struct XKeyEvent XKeyEvent; +typedef struct XKeyPressedEvent XKeyPressedEvent; +typedef struct XPoint XPoint; +typedef struct XRectangle XRectangle; +typedef struct XSelectionRequestEvent XSelectionRequestEvent; +typedef struct XWindowChanges XWindowChanges; +typedef struct _XGC _XCG; +typedef struct _XGC *GC; +typedef struct _XIC *XIC; +typedef struct _XIM *XIM; +typedef struct _XImage XImage; + +#endif diff --git a/utils/fake_libc_include/_ansi.h b/utils/fake_libc_include/_ansi.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/_ansi.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/_fake_defines.h b/utils/fake_libc_include/_fake_defines.h new file mode 100644 index 0000000..24cc0ab --- /dev/null +++ b/utils/fake_libc_include/_fake_defines.h @@ -0,0 +1,229 @@ +#ifndef _FAKE_DEFINES_H +#define _FAKE_DEFINES_H + +#define NULL 0 +#define BUFSIZ 1024 +#define FOPEN_MAX 20 +#define FILENAME_MAX 1024 + +#ifndef SEEK_SET +#define SEEK_SET 0 /* set file offset to offset */ +#endif +#ifndef SEEK_CUR +#define SEEK_CUR 1 /* set file offset to current plus offset */ +#endif +#ifndef SEEK_END +#define SEEK_END 2 /* set file offset to EOF plus offset */ +#endif + +#define __LITTLE_ENDIAN 1234 +#define LITTLE_ENDIAN __LITTLE_ENDIAN +#define __BIG_ENDIAN 4321 +#define BIG_ENDIAN __BIG_ENDIAN +#define __BYTE_ORDER __LITTLE_ENDIAN +#define BYTE_ORDER __BYTE_ORDER + +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 + +#define CHAR_MIN -128 +#define CHAR_MAX 127 +#define UCHAR_MAX 255 +#define SHRT_MIN -32768 +#define SHRT_MAX 32767 +#define USHRT_MAX 65535 +#define INT_MIN -2147483648 +#define INT_MAX 2147483647 +#define UINT_MAX 4294967295U +#define LONG_MIN -9223372036854775808L +#define LONG_MAX 9223372036854775807L +#define ULONG_MAX 18446744073709551615UL +#define RAND_MAX 32767 + +/* C99 inttypes.h defines */ +#define PRId8 "d" +#define PRIi8 "i" +#define PRIo8 "o" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" +#define PRId16 "d" +#define PRIi16 "i" +#define PRIo16 "o" +#define PRIu16 "u" +#define PRIx16 "x" +#define PRIX16 "X" +#define PRId32 "d" +#define PRIi32 "i" +#define PRIo32 "o" +#define PRIu32 "u" +#define PRIx32 "x" +#define PRIX32 "X" +#define PRId64 "d" +#define PRIi64 "i" +#define PRIo64 "o" +#define PRIu64 "u" +#define PRIx64 "x" +#define PRIX64 "X" +#define PRIdLEAST8 "d" +#define PRIiLEAST8 "i" +#define PRIoLEAST8 "o" +#define PRIuLEAST8 "u" +#define PRIxLEAST8 "x" +#define PRIXLEAST8 "X" +#define PRIdLEAST16 "d" +#define PRIiLEAST16 "i" +#define PRIoLEAST16 "o" +#define PRIuLEAST16 "u" +#define PRIxLEAST16 "x" +#define PRIXLEAST16 "X" +#define PRIdLEAST32 "d" +#define PRIiLEAST32 "i" +#define PRIoLEAST32 "o" +#define PRIuLEAST32 "u" +#define PRIxLEAST32 "x" +#define PRIXLEAST32 "X" +#define PRIdLEAST64 "d" +#define PRIiLEAST64 "i" +#define PRIoLEAST64 "o" +#define PRIuLEAST64 "u" +#define PRIxLEAST64 "x" +#define PRIXLEAST64 "X" +#define PRIdFAST8 "d" +#define PRIiFAST8 "i" +#define PRIoFAST8 "o" +#define PRIuFAST8 "u" +#define PRIxFAST8 "x" +#define PRIXFAST8 "X" +#define PRIdFAST16 "d" +#define PRIiFAST16 "i" +#define PRIoFAST16 "o" +#define PRIuFAST16 "u" +#define PRIxFAST16 "x" +#define PRIXFAST16 "X" +#define PRIdFAST32 "d" +#define PRIiFAST32 "i" +#define PRIoFAST32 "o" +#define PRIuFAST32 "u" +#define PRIxFAST32 "x" +#define PRIXFAST32 "X" +#define PRIdFAST64 "d" +#define PRIiFAST64 "i" +#define PRIoFAST64 "o" +#define PRIuFAST64 "u" +#define PRIxFAST64 "x" +#define PRIXFAST64 "X" +#define PRIdPTR "d" +#define PRIiPTR "i" +#define PRIoPTR "o" +#define PRIuPTR "u" +#define PRIxPTR "x" +#define PRIXPTR "X" +#define PRIdMAX "d" +#define PRIiMAX "i" +#define PRIoMAX "o" +#define PRIuMAX "u" +#define PRIxMAX "x" +#define PRIXMAX "X" +#define SCNd8 "d" +#define SCNi8 "i" +#define SCNo8 "o" +#define SCNu8 "u" +#define SCNx8 "x" +#define SCNd16 "d" +#define SCNi16 "i" +#define SCNo16 "o" +#define SCNu16 "u" +#define SCNx16 "x" +#define SCNd32 "d" +#define SCNi32 "i" +#define SCNo32 "o" +#define SCNu32 "u" +#define SCNx32 "x" +#define SCNd64 "d" +#define SCNi64 "i" +#define SCNo64 "o" +#define SCNu64 "u" +#define SCNx64 "x" +#define SCNdLEAST8 "d" +#define SCNiLEAST8 "i" +#define SCNoLEAST8 "o" +#define SCNuLEAST8 "u" +#define SCNxLEAST8 "x" +#define SCNdLEAST16 "d" +#define SCNiLEAST16 "i" +#define SCNoLEAST16 "o" +#define SCNuLEAST16 "u" +#define SCNxLEAST16 "x" +#define SCNdLEAST32 "d" +#define SCNiLEAST32 "i" +#define SCNoLEAST32 "o" +#define SCNuLEAST32 "u" +#define SCNxLEAST32 "x" +#define SCNdLEAST64 "d" +#define SCNiLEAST64 "i" +#define SCNoLEAST64 "o" +#define SCNuLEAST64 "u" +#define SCNxLEAST64 "x" +#define SCNdFAST8 "d" +#define SCNiFAST8 "i" +#define SCNoFAST8 "o" +#define SCNuFAST8 "u" +#define SCNxFAST8 "x" +#define SCNdFAST16 "d" +#define SCNiFAST16 "i" +#define SCNoFAST16 "o" +#define SCNuFAST16 "u" +#define SCNxFAST16 "x" +#define SCNdFAST32 "d" +#define SCNiFAST32 "i" +#define SCNoFAST32 "o" +#define SCNuFAST32 "u" +#define SCNxFAST32 "x" +#define SCNdFAST64 "d" +#define SCNiFAST64 "i" +#define SCNoFAST64 "o" +#define SCNuFAST64 "u" +#define SCNxFAST64 "x" +#define SCNdPTR "d" +#define SCNiPTR "i" +#define SCNoPTR "o" +#define SCNuPTR "u" +#define SCNxPTR "x" +#define SCNdMAX "d" +#define SCNiMAX "i" +#define SCNoMAX "o" +#define SCNuMAX "u" +#define SCNxMAX "x" + +/* C99 stdbool.h defines */ +#define __bool_true_false_are_defined 1 +#define false 0 +#define true 1 + +/* va_arg macros and type*/ +#define va_start(_ap, _type) __builtin_va_start((_ap)) +#define va_arg(_ap, _type) __builtin_va_arg((_ap)) +#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/_fake_typedefs.h b/utils/fake_libc_include/_fake_typedefs.h new file mode 100644 index 0000000..dfcc653 --- /dev/null +++ b/utils/fake_libc_include/_fake_typedefs.h @@ -0,0 +1,172 @@ +#ifndef _FAKE_TYPEDEFS_H +#define _FAKE_TYPEDEFS_H + +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; + +/* C99 exact-width integer types */ +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; + +/* C99 minimum-width integer types */ +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; + +/* C99 fastest minimum-width integer types */ +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; + +/* C99 integer types capable of holding object pointers */ +typedef int intptr_t; +typedef int uintptr_t; + +/* C99 greatest-width integer types */ +typedef int intmax_t; +typedef int uintmax_t; + +/* C99 stdbool.h bool type. _Bool is built-in in C99 */ +typedef _Bool bool; + +/* Mir typedefs */ +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; + +/* xcb typedefs */ +typedef struct xcb_connection_t xcb_connection_t; +typedef uint32_t xcb_window_t; +typedef uint32_t xcb_visualid_t; + +#endif diff --git a/utils/fake_libc_include/_syslist.h b/utils/fake_libc_include/_syslist.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/_syslist.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/aio.h b/utils/fake_libc_include/aio.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/aio.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/alloca.h b/utils/fake_libc_include/alloca.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/alloca.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/ar.h b/utils/fake_libc_include/ar.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/ar.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/argz.h b/utils/fake_libc_include/argz.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/argz.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/arpa/inet.h b/utils/fake_libc_include/arpa/inet.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/arpa/inet.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/asm-generic/int-ll64.h b/utils/fake_libc_include/asm-generic/int-ll64.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/asm-generic/int-ll64.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/assert.h b/utils/fake_libc_include/assert.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/assert.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/complex.h b/utils/fake_libc_include/complex.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/complex.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/cpio.h b/utils/fake_libc_include/cpio.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/cpio.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/ctype.h b/utils/fake_libc_include/ctype.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/ctype.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/dirent.h b/utils/fake_libc_include/dirent.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/dirent.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/dlfcn.h b/utils/fake_libc_include/dlfcn.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/dlfcn.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" 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/endian.h b/utils/fake_libc_include/endian.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/endian.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/envz.h b/utils/fake_libc_include/envz.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/envz.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/errno.h b/utils/fake_libc_include/errno.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/errno.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/fastmath.h b/utils/fake_libc_include/fastmath.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/fastmath.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/fcntl.h b/utils/fake_libc_include/fcntl.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/fcntl.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/features.h b/utils/fake_libc_include/features.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/features.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/fenv.h b/utils/fake_libc_include/fenv.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/fenv.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/float.h b/utils/fake_libc_include/float.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/float.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/fmtmsg.h b/utils/fake_libc_include/fmtmsg.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/fmtmsg.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/fnmatch.h b/utils/fake_libc_include/fnmatch.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/fnmatch.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/ftw.h b/utils/fake_libc_include/ftw.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/ftw.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/getopt.h b/utils/fake_libc_include/getopt.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/getopt.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/glob.h b/utils/fake_libc_include/glob.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/glob.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/grp.h b/utils/fake_libc_include/grp.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/grp.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/iconv.h b/utils/fake_libc_include/iconv.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/iconv.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/ieeefp.h b/utils/fake_libc_include/ieeefp.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/ieeefp.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/inttypes.h b/utils/fake_libc_include/inttypes.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/inttypes.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/iso646.h b/utils/fake_libc_include/iso646.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/iso646.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/langinfo.h b/utils/fake_libc_include/langinfo.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/langinfo.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/libgen.h b/utils/fake_libc_include/libgen.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/libgen.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/libintl.h b/utils/fake_libc_include/libintl.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/libintl.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/limits.h b/utils/fake_libc_include/limits.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/limits.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/linux/socket.h b/utils/fake_libc_include/linux/socket.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/linux/socket.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/linux/version.h b/utils/fake_libc_include/linux/version.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/linux/version.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/locale.h b/utils/fake_libc_include/locale.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/locale.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/malloc.h b/utils/fake_libc_include/malloc.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/malloc.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/math.h b/utils/fake_libc_include/math.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/math.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/mir_toolkit/client_types.h b/utils/fake_libc_include/mir_toolkit/client_types.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/mir_toolkit/client_types.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/monetary.h b/utils/fake_libc_include/monetary.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/monetary.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/mqueue.h b/utils/fake_libc_include/mqueue.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/mqueue.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/ndbm.h b/utils/fake_libc_include/ndbm.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/ndbm.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/net/if.h b/utils/fake_libc_include/net/if.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/net/if.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/netdb.h b/utils/fake_libc_include/netdb.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/netdb.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/netinet/in.h b/utils/fake_libc_include/netinet/in.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/netinet/in.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/netinet/tcp.h b/utils/fake_libc_include/netinet/tcp.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/netinet/tcp.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/newlib.h b/utils/fake_libc_include/newlib.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/newlib.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/nl_types.h b/utils/fake_libc_include/nl_types.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/nl_types.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/openssl/err.h b/utils/fake_libc_include/openssl/err.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/openssl/err.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/openssl/evp.h b/utils/fake_libc_include/openssl/evp.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/openssl/evp.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/openssl/hmac.h b/utils/fake_libc_include/openssl/hmac.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/openssl/hmac.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/openssl/ssl.h b/utils/fake_libc_include/openssl/ssl.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/openssl/ssl.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/openssl/x509v3.h b/utils/fake_libc_include/openssl/x509v3.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/openssl/x509v3.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/paths.h b/utils/fake_libc_include/paths.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/paths.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/poll.h b/utils/fake_libc_include/poll.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/poll.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/process.h b/utils/fake_libc_include/process.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/process.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/pthread.h b/utils/fake_libc_include/pthread.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/pthread.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/pwd.h b/utils/fake_libc_include/pwd.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/pwd.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/reent.h b/utils/fake_libc_include/reent.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/reent.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/regdef.h b/utils/fake_libc_include/regdef.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/regdef.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/regex.h b/utils/fake_libc_include/regex.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/regex.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sched.h b/utils/fake_libc_include/sched.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sched.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/search.h b/utils/fake_libc_include/search.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/search.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/semaphore.h b/utils/fake_libc_include/semaphore.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/semaphore.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/setjmp.h b/utils/fake_libc_include/setjmp.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/setjmp.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/signal.h b/utils/fake_libc_include/signal.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/signal.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" diff --git a/utils/fake_libc_include/spawn.h b/utils/fake_libc_include/spawn.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/spawn.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/stdarg.h b/utils/fake_libc_include/stdarg.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/stdarg.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/stdbool.h b/utils/fake_libc_include/stdbool.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/stdbool.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/stddef.h b/utils/fake_libc_include/stddef.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/stddef.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/stdint.h b/utils/fake_libc_include/stdint.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/stdint.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/stdio.h b/utils/fake_libc_include/stdio.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/stdio.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/stdlib.h b/utils/fake_libc_include/stdlib.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/stdlib.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/string.h b/utils/fake_libc_include/string.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/string.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/strings.h b/utils/fake_libc_include/strings.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/strings.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/stropts.h b/utils/fake_libc_include/stropts.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/stropts.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/ioctl.h b/utils/fake_libc_include/sys/ioctl.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/ioctl.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/ipc.h b/utils/fake_libc_include/sys/ipc.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/ipc.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/mman.h b/utils/fake_libc_include/sys/mman.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/mman.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/msg.h b/utils/fake_libc_include/sys/msg.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/msg.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/poll.h b/utils/fake_libc_include/sys/poll.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/poll.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/resource.h b/utils/fake_libc_include/sys/resource.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/resource.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/select.h b/utils/fake_libc_include/sys/select.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/select.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/sem.h b/utils/fake_libc_include/sys/sem.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/sem.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/shm.h b/utils/fake_libc_include/sys/shm.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/shm.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/socket.h b/utils/fake_libc_include/sys/socket.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/socket.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/stat.h b/utils/fake_libc_include/sys/stat.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/stat.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/statvfs.h b/utils/fake_libc_include/sys/statvfs.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/statvfs.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/sysctl.h b/utils/fake_libc_include/sys/sysctl.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/sysctl.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/time.h b/utils/fake_libc_include/sys/time.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/time.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/times.h b/utils/fake_libc_include/sys/times.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/times.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/types.h b/utils/fake_libc_include/sys/types.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/types.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/uio.h b/utils/fake_libc_include/sys/uio.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/uio.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/un.h b/utils/fake_libc_include/sys/un.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/un.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/utsname.h b/utils/fake_libc_include/sys/utsname.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/utsname.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/sys/wait.h b/utils/fake_libc_include/sys/wait.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/sys/wait.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/syslog.h b/utils/fake_libc_include/syslog.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/syslog.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/tar.h b/utils/fake_libc_include/tar.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/tar.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/termios.h b/utils/fake_libc_include/termios.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/termios.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/tgmath.h b/utils/fake_libc_include/tgmath.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/tgmath.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/time.h b/utils/fake_libc_include/time.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/time.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/trace.h b/utils/fake_libc_include/trace.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/trace.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/ulimit.h b/utils/fake_libc_include/ulimit.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/ulimit.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/unctrl.h b/utils/fake_libc_include/unctrl.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/unctrl.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/unistd.h b/utils/fake_libc_include/unistd.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/unistd.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/utime.h b/utils/fake_libc_include/utime.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/utime.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/utmp.h b/utils/fake_libc_include/utmp.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/utmp.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/utmpx.h b/utils/fake_libc_include/utmpx.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/utmpx.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/wchar.h b/utils/fake_libc_include/wchar.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/wchar.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/wctype.h b/utils/fake_libc_include/wctype.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/wctype.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/wordexp.h b/utils/fake_libc_include/wordexp.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/wordexp.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/xcb/xcb.h b/utils/fake_libc_include/xcb/xcb.h new file mode 100644 index 0000000..f952c1d --- /dev/null +++ b/utils/fake_libc_include/xcb/xcb.h @@ -0,0 +1,2 @@ +#include "_fake_defines.h" +#include "_fake_typedefs.h" diff --git a/utils/fake_libc_include/zlib.h b/utils/fake_libc_include/zlib.h new file mode 100644 index 0000000..af32600 --- /dev/null +++ b/utils/fake_libc_include/zlib.h @@ -0,0 +1,33 @@ +#ifndef ZLIB_H +#define ZLIB_H + +#include "_fake_defines.h" +#include "_fake_typedefs.h" + +typedef int uInt; +typedef int uLong; +#if !defined(__MACTYPES__) +typedef int Byte; +#endif + +typedef int Bytef; +typedef int charf; +typedef int intf; +typedef int uIntf; +typedef int uLongf; + +typedef int voidpc; +typedef int voidpf; +typedef int voidp; + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +typedef int Z_U4; +#endif + +typedef int z_crc_t; +typedef int z_size_t; + +typedef int alloc_func; +typedef int free_func; + +#endif diff --git a/utils/internal/constptr.c b/utils/internal/constptr.c new file mode 100644 index 0000000..2fe14bf --- /dev/null +++ b/utils/internal/constptr.c @@ -0,0 +1,9 @@ +void foo(char * const * arg) { + arg += 1; + (*arg) += 1; +} + +void foo2(char ** const arg) { + arg += 1; + (*arg) += 1; +} diff --git a/utils/internal/cppify.bat b/utils/internal/cppify.bat new file mode 100644 index 0000000..af69f5f --- /dev/null +++ b/utils/internal/cppify.bat @@ -0,0 +1,3 @@ +REM ~ ..\cpp -D__i386__ -I"D:\eli\cpp_stuff\libc_include" -D__extension__ example_c_file.c > example_c_file_pp.c +REM ~ ..\cpp -D__i386__ -I"D:\eli\c_analyzing\pycparser-trunk\utils\fake_libc_include" example_c_file.c > example_c_file_pp.c +..\cpp -D__i386__ -I"D:\eli\c_analyzing\pycparser-trunk\utils\fake_libc_include" zc.c > zc_pp.c diff --git a/utils/internal/example_c_file.c b/utils/internal/example_c_file.c new file mode 100644 index 0000000..35da01d --- /dev/null +++ b/utils/internal/example_c_file.c @@ -0,0 +1,25 @@ +/* a comment / */ +/* "not a string" */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* + multiline comment + comment +*/ + +int main() +{ + auto char* multi = "a multi"; /* and a comment !*/ +} + +/* A final comment for good measure /* /* /* */ + + + diff --git a/utils/internal/fake_includes.py b/utils/internal/fake_includes.py new file mode 100644 index 0000000..1ce69fa --- /dev/null +++ b/utils/internal/fake_includes.py @@ -0,0 +1,13 @@ +import os.path + +for cur_path, dirs, files in os.walk('.'): + if cur_path == '.': + for f in files: + if f.endswith('.h'): + print f + fo = open(f, 'w') + fo.write('#include "_fake_defines.h"\n') + fo.write('#include "_fake_typedefs.h"\n') + fo.close() + + diff --git a/utils/internal/make_fake_typedefs.py b/utils/internal/make_fake_typedefs.py new file mode 100644 index 0000000..b82e92f --- /dev/null +++ b/utils/internal/make_fake_typedefs.py @@ -0,0 +1,21 @@ +import sys +sys.path.insert(0, '../..') + +from pycparser import c_parser, c_ast, parse_file + + +class MyVisitor(c_ast.NodeVisitor): + def visit_Typedef(self, node): + print 'typedef int %s;' % node.name + + + +def generate_fake_typedefs(filename): + ast = parse_file(filename, use_cpp=True, cpp_path="../cpp.exe") + v = MyVisitor() + v.visit(ast) + + +if __name__ == "__main__": + generate_fake_typedefs('example_c_file_pp.c') + diff --git a/utils/internal/memprofiling.py b/utils/internal/memprofiling.py new file mode 100644 index 0000000..5b25120 --- /dev/null +++ b/utils/internal/memprofiling.py @@ -0,0 +1,121 @@ +import sys +from pycparser import parse_file +from pycparser.c_ast import * +from pycparser.c_parser import CParser, Coord, ParseError +from pycparser.c_lexer import CLexer + + +def expand_decl(decl): + """ Converts the declaration into a nested list. + """ + typ = type(decl) + + if typ == TypeDecl: + return ['TypeDecl', expand_decl(decl.type)] + elif typ == IdentifierType: + return ['IdentifierType', decl.names] + elif typ == ID: + return ['ID', decl.name] + elif typ in [Struct, Union]: + decls = [expand_decl(d) for d in decl.decls or []] + return [typ.__name__, decl.name, decls] + else: + nested = expand_decl(decl.type) + + if typ == Decl: + if decl.quals: + return ['Decl', decl.quals, decl.name, nested] + else: + return ['Decl', decl.name, nested] + elif typ == Typename: # for function parameters + if decl.quals: + return ['Typename', decl.quals, nested] + else: + return ['Typename', nested] + elif typ == ArrayDecl: + dimval = decl.dim.value if decl.dim else '' + return ['ArrayDecl', dimval, nested] + elif typ == PtrDecl: + return ['PtrDecl', nested] + elif typ == Typedef: + return ['Typedef', decl.name, nested] + elif typ == FuncDecl: + if decl.args: + params = [expand_decl(param) for param in decl.args.params] + else: + params = [] + return ['FuncDecl', params, nested] + +#----------------------------------------------------------------- +class NodeVisitor(object): + def __init__(self): + self.current_parent = None + + def visit(self, node): + """ Visit a node. + """ + method = 'visit_' + node.__class__.__name__ + visitor = getattr(self, method, self.generic_visit) + return visitor(node) + + def visit_FuncCall(self, node): + print("Visiting FuncCall") + print(node.show()) + print('---- parent ----') + print(self.current_parent.show()) + + def generic_visit(self, node): + """ Called if no explicit visitor function exists for a + node. Implements preorder visiting of the node. + """ + oldparent = self.current_parent + self.current_parent = node + for c in node.children(): + self.visit(c) + self.current_parent = oldparent + + +def heapyprofile(): + # pip install guppy + # [works on python 2.7, AFAIK] + from guppy import hpy + import gc + + hp = hpy() + ast = parse_file('/tmp/197.c') + gc.collect() + h = hp.heap() + print(h) + + +def memprofile(): + import resource + import tracemalloc + + tracemalloc.start() + + ast = parse_file('/tmp/197.c') + + print('Memory usage: %s (kb)' % + resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) + + snapshot = tracemalloc.take_snapshot() + print("[ tracemalloc stats ]") + for stat in snapshot.statistics('lineno')[:20]: + print(stat) + + +if __name__ == "__main__": + source_code = r'''void foo() { + L"hi" L"there"; +} + ''' + + memprofile() + #heapyprofile() + + #parser = CParser() + #ast = parser.parse(source_code, filename='zz') + #ast.show(showcoord=True, attrnames=True, nodenames=True) + + diff --git a/utils/internal/zc.c b/utils/internal/zc.c new file mode 100644 index 0000000..5e56974 --- /dev/null +++ b/utils/internal/zc.c @@ -0,0 +1,107 @@ +#include +#include +#include +#include + +#define PACKAGE "wgram" +#define VERSION "0.0.4" +#define MAXLINE 1024 +#define MAXGRAM 32 + +/* status epilepticus .. print help */ +void print_help(int exval); + +int main (int argc, char *argv[]) { + /* word delimeter for strtok() */ + char delim[] = ".,:;`/\"+-_(){}[]<>*&^%$#@!?~/|\\=1234567890 \t\n"; + char line[MAXLINE]; /* input buff, fgets() */ + char *stray = NULL; /* returned value by strtok() */ + char **strarray = NULL; /* array to hold all entrys */ + int i = 0; /* general counter */ + int strcount = 0; /* number of entrys in pointer array */ + int N = 3, pos = 0; /* ngram size, 3 in this case */ + int opt = 0; /* holds command line opt nr.. */ + int word_flag = 0; /* print only the `raw' words */ + FILE *fp = stdin; /* read input from `FILE', default is stdin */ + + while((opt = getopt(argc, argv, "hvn:wf:")) != -1) { + switch(opt) { + case 'h': + print_help(0); + break; + case 'v': + exit(0); + break; + case 'n': + N = atoi(optarg); + if(N > MAXGRAM || N < 2) { + fprintf(stderr, "%s: Error - Ngram length `%d' out of range `0-%d'\n", + PACKAGE, N, MAXGRAM); + return 1; + } + break; + case 'w': + word_flag = 1; + break; + case 'f': + if(freopen(optarg, "r", fp) == NULL) { + fprintf(stderr, "%s: Error - opening `%s'\n", PACKAGE, optarg); + return 1; + } + break; + case '?': + fprintf(stderr, "%s: Error - No such option: `%c'\n\n", PACKAGE, optopt); + print_help(1); + } /* switch */ + } /* while */ + + /* start reading lines from file pointer, add all entrys to **strarray */ + while((fgets(line, MAXLINE, fp)) != NULL) { + if(strlen(line) < 2) + continue; + + stray = strtok(line, delim); + while(stray != NULL) { + strarray = (char **)realloc(strarray, (strcount + 1) * sizeof(char *)); + strarray[strcount++] = strdup(stray); + stray = strtok(NULL, delim); + } + } + + if(word_flag == 0) { + /* + // print the array of strings, jumping back each time + // (N - 1) positions if a whole ngram of words has been printed + */ + for(i = 0, pos = N; i < strcount; i++, pos--) { + if(pos == 0) pos = N, i -= (N - 1), printf("\n"); + printf("%s ", strarray[i]); + } + printf("\n"); + } else { + /* print raw words */ + for(i = 0; i < strcount; i++) + printf("%s\n", strarray[i]); + } + + /* free the string array */ + for(i = 0; i < strcount; i++) + free(strarray[i]); + + free(strarray); + return 0; +} + +/* status epilepticus .. print help */ +void print_help(int exval) { + printf("%s,%s extract N-grams from text data\n", PACKAGE, VERSION); + printf("Usage: %s [-h] [-v] [-n INT] [-w] [-f FILE]\n\n", PACKAGE); + + printf(" -h print this help and exit\n"); + printf(" -v print version and exit\n\n"); + + printf(" -n INT set ngram length (default=3)\n"); + printf(" -w print only the extracted words\n"); + printf(" -f FILE read input from `FILE' (default=stdin)\n\n"); + exit(exval); +} diff --git a/utils/internal/zz-ctoc.py b/utils/internal/zz-ctoc.py new file mode 100644 index 0000000..434f9bc --- /dev/null +++ b/utils/internal/zz-ctoc.py @@ -0,0 +1,27 @@ +from __future__ import print_function +from pycparser import parse_file, c_parser, c_generator + +if __name__ == '__main__': + src = r''' + + void f(char * restrict joe){} + +int main(void) +{ + unsigned int long k = 4; + int p = - - k; + return 0; +} +''' + parser = c_parser.CParser() + ast = parser.parse(src) + ast.show() + generator = c_generator.CGenerator() + + print(generator.visit(ast)) + + # tracing the generator for debugging + #~ import trace + #~ tr = trace.Trace(countcallers=1) + #~ tr.runfunc(generator.visit, ast) + #~ tr.results().write_results() diff --git a/utils/internal/zz_parse.py b/utils/internal/zz_parse.py new file mode 100644 index 0000000..39978d1 --- /dev/null +++ b/utils/internal/zz_parse.py @@ -0,0 +1,21 @@ +from __future__ import print_function + +import sys +from pycparser import c_parser, c_generator, c_ast, parse_file + + +if __name__ == "__main__": + parser = c_parser.CParser() + code = r''' + void* ptr = (int[ ]){0}; + ''' + + print(code) + ast = parser.parse(code) + ast.show(attrnames=True, nodenames=True) + print(ast.ext[0].__slots__) + print(dir(ast.ext[0])) + + print("==== From C generator:") + generator = c_generator.CGenerator() + print(generator.visit(ast)) diff --git a/variable_mappings.zip b/variable_mappings.zip new file mode 100644 index 0000000..1ad928a Binary files /dev/null and b/variable_mappings.zip differ