Commit ee45b627 authored by Vysheng's avatar Vysheng

Deleted unneeded files

parent a9b5fbe6
/*
This file is part of tgl-library
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Copyright Vitaly Valtman 2014
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
static int cur_token_len;
static char *cur_token;
static int cur_token_real_len;
static int cur_token_quoted;
static int multiline_output = 1;
static int multiline_offset;
static int multiline_offset_size = 2;
static int *in_ptr, *in_end;
static inline int fetch_int (void) {
return *(in_ptr ++);
}
static inline int fetch_long (void) {
long long r = *(long long *)in_ptr;
in_ptr += 2;
return r;
}
static inline int fetch_long (void) {
long long r = *(long long *)in_ptr;
in_ptr += 2;
return r;
}
static inline void out_int (int a) {}
static inline void out_double (double a) {}
static inline void out_string (char *s, int l) {}
static inline void out_long (long long a) {}
static int disable_field_names;
#define expect_token(token,len) \
if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return -1; } \
local_next_token ();
#define expect_token_ptr(token,len) \
if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return 0; } \
local_next_token ();
#define expect_token_autocomplete(token,len) \
if (cur_token_len == -3 && len >= cur_token_real_len && !memcmp (cur_token, token, cur_token_real_len)) { set_autocomplete_string (token); return -1; }\
if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return -1; } \
local_next_token ();
#define expect_token_ptr_autocomplete(token,len) \
if (cur_token_len == -3 && len >= cur_token_real_len && !memcmp (cur_token, token, cur_token_real_len)) { set_autocomplete_string (token); return 0; }\
if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return 0; } \
local_next_token ();
static int autocomplete_mode;
static char *autocomplete_string;
static int (*autocomplete_fun)(const char *, int, int, char **);
static void set_autocomplete_string (const char *s) {
if (autocomplete_string) { free (autocomplete_string); }
autocomplete_string = strdup (s);
assert (autocomplete_string);
autocomplete_mode = 1;
}
static void set_autocomplete_type (int (*f)(const char *, int, int, char **)) {
autocomplete_fun = f;
autocomplete_mode = 2;
}
static int is_int (void) {
if (cur_token_len <= 0) { return 0; }
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
char *p = 0;
if (strtoll (cur_token, &p, 10)) {}
cur_token[cur_token_len] = c;
return p == cur_token + cur_token_len;
}
static long long get_int (void) {
if (cur_token_len <= 0) { return 0; }
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
char *p = 0;
long long val = strtoll (cur_token, &p, 0);
cur_token[cur_token_len] = c;
return val;
}
static int is_double (void) {
if (cur_token_len <= 0) { return 0; }
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
char *p = 0;
if (strtod (cur_token, &p)) {}
cur_token[cur_token_len] = c;
return p == cur_token + cur_token_len;
}
static double get_double (void) {
if (cur_token_len <= 0) { return 0; }
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
char *p = 0;
double val = strtod (cur_token, &p);
cur_token[cur_token_len] = c;
return val;
}
static struct paramed_type *paramed_type_dup (struct paramed_type *P) {
if (ODDP (P)) { return P; }
struct paramed_type *R = malloc (sizeof (*R));
assert (R);
R->type = malloc (sizeof (*R->type));
assert (R->type);
memcpy (R->type, P->type, sizeof (*P->type));
R->type->id = strdup (P->type->id);
assert (R->type->id);
if (P->type->params_num) {
R->params = malloc (sizeof (void *) * P->type->params_num);
assert (R->params);
int i;
for (i = 0; i < P->type->params_num; i++) {
R->params[i] = paramed_type_dup (P->params[i]);
}
}
return R;
}
void tgl_paramed_type_free (struct paramed_type *P) {
if (ODDP (P)) { return; }
if (P->type->params_num) {
int i;
for (i = 0; i < P->type->params_num; i++) {
tgl_paramed_type_free (P->params[i]);
}
free (P->params);
}
free (P->type->id);
free (P->type);
free (P);
}
static char *buffer_pos, *buffer_end;
static int is_wspc (char c) {
return c <= 32 && c > 0;
}
static void skip_wspc (void) {
while (buffer_pos < buffer_end && is_wspc (*buffer_pos)) {
buffer_pos ++;
}
}
static int is_letter (char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '.' || c == '_' || c == '-';
}
static char exp_buffer[1 << 25];;
static int exp_buffer_pos;
static inline int is_hex (char c) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
}
static inline int hex2dec (char c) {
if (c >= '0' && c <= '9') { return c - '0'; }
else { return c - 'a' + 10; }
}
static void expand_backslashed (char *s, int len) {
int backslashed = 0;
exp_buffer_pos = 0;
int i = 0;
while (i < len) {
assert (i + 3 <= (1 << 25));
if (backslashed) {
backslashed = 0;
switch (s[i ++]) {
case 'n':
exp_buffer[exp_buffer_pos ++] = '\n';
break;
case 'r':
exp_buffer[exp_buffer_pos ++] = '\r';
break;
case 't':
exp_buffer[exp_buffer_pos ++] = '\t';
break;
case 'b':
exp_buffer[exp_buffer_pos ++] = '\b';
break;
case 'a':
exp_buffer[exp_buffer_pos ++] = '\a';
break;
case '\\':
exp_buffer[exp_buffer_pos ++] = '\\';
break;
case 'x':
if (i + 2 > len || !is_hex (s[i]) || !is_hex (s[i + 1])) {
exp_buffer_pos = -1;
return;
}
exp_buffer[exp_buffer_pos ++] = hex2dec (s[i]) * 16 + hex2dec (s[i + 1]);
i += 2;
break;
default:
break;
}
} else {
if (s[i] == '\\') {
backslashed = 1;
i ++;
} else {
exp_buffer[exp_buffer_pos ++] = s[i ++];
}
}
}
}
static void local_next_token (void) {
skip_wspc ();
cur_token_quoted = 0;
if (buffer_pos >= buffer_end) {
cur_token_len = -3;
cur_token_real_len = 0;
return;
}
char c = *buffer_pos;
if (is_letter (c)) {
cur_token = buffer_pos;
while (buffer_pos < buffer_end && is_letter (*buffer_pos)) {
buffer_pos ++;
}
if (buffer_pos < buffer_end) {
cur_token_len = buffer_pos - cur_token;
} else {
cur_token_real_len = buffer_pos - cur_token;
cur_token_len = -3;
}
return;
} else if (c == '"') {
cur_token_quoted = 1;
cur_token = buffer_pos ++;
int backslashed = 0;
while (buffer_pos < buffer_end && (*buffer_pos != '"' || backslashed)) {
if (*buffer_pos == '\\') {
backslashed ^= 1;
} else {
backslashed = 0;
}
buffer_pos ++;
}
if (*buffer_pos == '"') {
buffer_pos ++;
expand_backslashed (cur_token + 1, buffer_pos - cur_token - 2);
if (exp_buffer_pos < 0) {
cur_token_len = -2;
} else {
cur_token_len = exp_buffer_pos;
cur_token = exp_buffer;
}
} else {
cur_token_len = -2;
}
return;
} else {
if (c) {
cur_token = buffer_pos ++;
cur_token_len = 1;
} else {
cur_token_len = -3;
cur_token_real_len = 0;
}
}
}
#define MAX_FVARS 100
static struct paramed_type *fvars[MAX_FVARS];
static int fvars_pos;
static void add_var_to_be_freed (struct paramed_type *P) {
assert (fvars_pos < MAX_FVARS);
fvars[fvars_pos ++] = P;
}
static void free_vars_to_be_freed (void) {
int i;
for (i = 0; i < fvars_pos; i++) {
tgl_paramed_type_free (fvars[i]);
}
fvars_pos = 0;
}
int tglf_extf_autocomplete (const char *text, int text_len, int index, char **R, char *data, int data_len) {
if (index == -1) {
buffer_pos = data;
buffer_end = data + data_len;
autocomplete_mode = 0;
local_next_token ();
struct paramed_type *P = autocomplete_function_any ();
free_vars_to_be_freed ();
if (P) { tgl_paramed_type_free (P); }
}
if (autocomplete_mode == 0) { return -1; }
int len = strlen (text);
if (autocomplete_mode == 1) {
if (index >= 0) { return -1; }
index = 0;
if (!strncmp (text, autocomplete_string, len)) {
*R = strdup (autocomplete_string);
assert (*R);
return index;
} else {
return -1;
}
} else {
return autocomplete_fun (text, len, index, R);
}
}
struct paramed_type *tglf_extf_store (const char *data, int data_len) {
buffer_pos = (char *)data;
buffer_end = (char *)(data + data_len);
local_next_token ();
return store_function_any ();
}
#define OUT_BUF_SIZE (1 << 25)
static char out_buf[OUT_BUF_SIZE];
static int out_buf_pos;
#define eprintf(...) \
do { \
out_buf_pos += snprintf (out_buf + out_buf_pos, OUT_BUF_SIZE - out_buf_pos, __VA_ARGS__);\
assert (out_buf_pos < OUT_BUF_SIZE);\
} while (0)\
static int valid_utf8_char (const char *str) {
unsigned char c = (unsigned char) *str;
int n = 0;
if ((c & 0x80) == 0x00) {
n = 0;
} else if ((c & 0xe0) == 0xc0) {
n = 1;
} else if ((c & 0xf0) == 0xe0) {
n = 2;
} else if ((c & 0xf8) == 0xf0) {
n = 3;
} else if ((c & 0xfc) == 0xf8) {
n = 4;
} else if ((c & 0xfe) == 0xfc) {
n = 5;
} else {
return -1;
}
int i;
for (i = 0; i < n; i ++) {
if ((((unsigned char)(str[i + 1])) & 0xc0) != 0x80) {
return -1;
}
}
return n + 1;
}
static void print_escaped_string (const char *str, int len) {
eprintf ("\"");
const char *end = str + len;
while (str < end) {
int n = valid_utf8_char (str);
if (n < 0) {
eprintf ("\\x%02x", (int)(unsigned char)*str);
str ++;
} else if (n >= 2) {
int i;
for (i = 0; i < n; i++) {
eprintf ("%c", *(str ++));
}
} else if (((unsigned char)*str) >= ' ' && *str != '"' && *str != '\\') {
eprintf ("%c", *str);
str ++;
} else {
switch (*str) {
case '\n':
eprintf("\\n");
break;
case '\r':
eprintf("\\r");
break;
case '\t':
eprintf("\\t");
break;
case '\b':
eprintf("\\b");
break;
case '\a':
eprintf("\\a");
break;
case '\\':
eprintf ("\\\\");
break;
case '"':
eprintf ("\\\"");
break;
default:
eprintf ("\\x%02x", (int)(unsigned char)*str);
break;
}
str ++;
}
}
eprintf ("\"");
}
static void print_offset (void) {
int i;
for (i = 0; i < multiline_offset; i++) {
eprintf (" ");
}
}
char *tglf_extf_fetch (struct paramed_type *T) {
out_buf_pos = 0;
fetch_type_any (T);
return out_buf;
}
/*
This file is part of tgl-library
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Copyright Vitaly Valtman 2014
*/
#include "mtproto-common.h"
#include "config.h"
#include <string.h>
#ifndef DISABLE_EXTF
static int cur_token_len;
static char *cur_token;
static int cur_token_real_len;
static int cur_token_quoted;
static int multiline_output = 1;
static int multiline_offset;
static int multiline_offset_size = 2;
static int disable_field_names;
#define expect_token(token,len) \
if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return -1; } \
local_next_token ();
#define expect_token_ptr(token,len) \
if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return 0; } \
local_next_token ();
#define expect_token_autocomplete(token,len) \
if (cur_token_len == -3 && len >= cur_token_real_len && !memcmp (cur_token, token, cur_token_real_len)) { set_autocomplete_string (token); return -1; }\
if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return -1; } \
local_next_token ();
#define expect_token_ptr_autocomplete(token,len) \
if (cur_token_len == -3 && len >= cur_token_real_len && !memcmp (cur_token, token, cur_token_real_len)) { set_autocomplete_string (token); return 0; }\
if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return 0; } \
local_next_token ();
static int autocomplete_mode;
static char *autocomplete_string;
static int (*autocomplete_fun)(const char *, int, int, char **);
static void set_autocomplete_string (const char *s) {
if (autocomplete_string) { free (autocomplete_string); }
autocomplete_string = strdup (s);
assert (autocomplete_string);
autocomplete_mode = 1;
}
static void set_autocomplete_type (int (*f)(const char *, int, int, char **)) {
autocomplete_fun = f;
autocomplete_mode = 2;
}
static int is_int (void) {
if (cur_token_len <= 0) { return 0; }
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
char *p = 0;
if (strtoll (cur_token, &p, 10)) {}
cur_token[cur_token_len] = c;
return p == cur_token + cur_token_len;
}
static long long get_int (void) {
if (cur_token_len <= 0) { return 0; }
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
char *p = 0;
long long val = strtoll (cur_token, &p, 0);
cur_token[cur_token_len] = c;
return val;
}
static int is_double (void) {
if (cur_token_len <= 0) { return 0; }
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
char *p = 0;
if (strtod (cur_token, &p)) {}
cur_token[cur_token_len] = c;
return p == cur_token + cur_token_len;
}
static double get_double (void) {
if (cur_token_len <= 0) { return 0; }
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
char *p = 0;
double val = strtod (cur_token, &p);
cur_token[cur_token_len] = c;
return val;
}
static struct paramed_type *paramed_type_dup (struct paramed_type *P) {
if (ODDP (P)) { return P; }
struct paramed_type *R = malloc (sizeof (*R));
assert (R);
R->type = malloc (sizeof (*R->type));
assert (R->type);
memcpy (R->type, P->type, sizeof (*P->type));
R->type->id = strdup (P->type->id);
assert (R->type->id);
if (P->type->params_num) {
R->params = malloc (sizeof (void *) * P->type->params_num);
assert (R->params);
int i;
for (i = 0; i < P->type->params_num; i++) {
R->params[i] = paramed_type_dup (P->params[i]);
}
}
return R;
}
void tgl_paramed_type_free (struct paramed_type *P) {
if (ODDP (P)) { return; }
if (P->type->params_num) {
int i;
for (i = 0; i < P->type->params_num; i++) {
tgl_paramed_type_free (P->params[i]);
}
free (P->params);
}
free (P->type->id);
free (P->type);
free (P);
}
static char *buffer_pos, *buffer_end;
static int is_wspc (char c) {
return c <= 32 && c > 0;
}
static void skip_wspc (void) {
while (buffer_pos < buffer_end && is_wspc (*buffer_pos)) {
buffer_pos ++;
}
}
static int is_letter (char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '.' || c == '_' || c == '-';
}
static char exp_buffer[1 << 25];;
static int exp_buffer_pos;
static inline int is_hex (char c) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
}
static inline int hex2dec (char c) {
if (c >= '0' && c <= '9') { return c - '0'; }
else { return c - 'a' + 10; }
}
static void expand_backslashed (char *s, int len) {
int backslashed = 0;
exp_buffer_pos = 0;
int i = 0;
while (i < len) {
assert (i + 3 <= (1 << 25));
if (backslashed) {
backslashed = 0;
switch (s[i ++]) {
case 'n':
exp_buffer[exp_buffer_pos ++] = '\n';
break;
case 'r':
exp_buffer[exp_buffer_pos ++] = '\r';
break;
case 't':
exp_buffer[exp_buffer_pos ++] = '\t';
break;
case 'b':
exp_buffer[exp_buffer_pos ++] = '\b';
break;
case 'a':
exp_buffer[exp_buffer_pos ++] = '\a';
break;
case '\\':
exp_buffer[exp_buffer_pos ++] = '\\';
break;
case 'x':
if (i + 2 > len || !is_hex (s[i]) || !is_hex (s[i + 1])) {
exp_buffer_pos = -1;
return;
}
exp_buffer[exp_buffer_pos ++] = hex2dec (s[i]) * 16 + hex2dec (s[i + 1]);
i += 2;
break;
default:
break;
}
} else {
if (s[i] == '\\') {
backslashed = 1;
i ++;
} else {
exp_buffer[exp_buffer_pos ++] = s[i ++];
}
}
}
}
static void local_next_token (void) {
skip_wspc ();
cur_token_quoted = 0;
if (buffer_pos >= buffer_end) {
cur_token_len = -3;
cur_token_real_len = 0;
return;
}
char c = *buffer_pos;
if (is_letter (c)) {
cur_token = buffer_pos;
while (buffer_pos < buffer_end && is_letter (*buffer_pos)) {
buffer_pos ++;
}
if (buffer_pos < buffer_end) {
cur_token_len = buffer_pos - cur_token;
} else {
cur_token_real_len = buffer_pos - cur_token;
cur_token_len = -3;
}
return;
} else if (c == '"') {
cur_token_quoted = 1;
cur_token = buffer_pos ++;
int backslashed = 0;
while (buffer_pos < buffer_end && (*buffer_pos != '"' || backslashed)) {
if (*buffer_pos == '\\') {
backslashed ^= 1;
} else {
backslashed = 0;
}
buffer_pos ++;
}
if (*buffer_pos == '"') {
buffer_pos ++;
expand_backslashed (cur_token + 1, buffer_pos - cur_token - 2);
if (exp_buffer_pos < 0) {
cur_token_len = -2;
} else {
cur_token_len = exp_buffer_pos;
cur_token = exp_buffer;
}
} else {
cur_token_len = -2;
}
return;
} else {
if (c) {
cur_token = buffer_pos ++;
cur_token_len = 1;
} else {
cur_token_len = -3;
cur_token_real_len = 0;
}
}
}
#define MAX_FVARS 100
static struct paramed_type *fvars[MAX_FVARS];
static int fvars_pos;
static void add_var_to_be_freed (struct paramed_type *P) {
assert (fvars_pos < MAX_FVARS);
fvars[fvars_pos ++] = P;
}
static void free_vars_to_be_freed (void) {
int i;
for (i = 0; i < fvars_pos; i++) {
tgl_paramed_type_free (fvars[i]);
}
fvars_pos = 0;
}
int tglf_extf_autocomplete (struct tgl_state *TLS, const char *text, int text_len, int index, char **R, char *data, int data_len) {
if (index == -1) {
buffer_pos = data;
buffer_end = data + data_len;
autocomplete_mode = 0;
local_next_token ();
struct paramed_type *P = autocomplete_function_any ();
free_vars_to_be_freed ();
if (P) { tgl_paramed_type_free (P); }
}
if (autocomplete_mode == 0) { return -1; }
int len = strlen (text);
if (autocomplete_mode == 1) {
if (index >= 0) { return -1; }
index = 0;
if (!strncmp (text, autocomplete_string, len)) {
*R = strdup (autocomplete_string);
assert (*R);
return index;
} else {
return -1;
}
} else {
return autocomplete_fun (text, len, index, R);
}
}
struct paramed_type *tglf_extf_store (struct tgl_state *TLS, const char *data, int data_len) {
buffer_pos = (char *)data;
buffer_end = (char *)(data + data_len);
local_next_token ();
return store_function_any ();
}
#define OUT_BUF_SIZE (1 << 25)
static char out_buf[OUT_BUF_SIZE];
static int out_buf_pos;
#define eprintf(...) \
do { \
out_buf_pos += snprintf (out_buf + out_buf_pos, OUT_BUF_SIZE - out_buf_pos, __VA_ARGS__);\
assert (out_buf_pos < OUT_BUF_SIZE);\
} while (0)\
static int valid_utf8_char (const char *str) {
unsigned char c = (unsigned char) *str;
int n = 0;
if ((c & 0x80) == 0x00) {
n = 0;
} else if ((c & 0xe0) == 0xc0) {
n = 1;
} else if ((c & 0xf0) == 0xe0) {
n = 2;
} else if ((c & 0xf8) == 0xf0) {
n = 3;
} else if ((c & 0xfc) == 0xf8) {
n = 4;
} else if ((c & 0xfe) == 0xfc) {
n = 5;
} else {
return -1;
}
int i;
for (i = 0; i < n; i ++) {
if ((((unsigned char)(str[i + 1])) & 0xc0) != 0x80) {
return -1;
}
}
return n + 1;
}
static void print_escaped_string (const char *str, int len) {
eprintf ("\"");
const char *end = str + len;
while (str < end) {
int n = valid_utf8_char (str);
if (n < 0) {
eprintf ("\\x%02x", (int)(unsigned char)*str);
str ++;
} else if (n >= 2) {
int i;
for (i = 0; i < n; i++) {
eprintf ("%c", *(str ++));
}
} else if (((unsigned char)*str) >= ' ' && *str != '"' && *str != '\\') {
eprintf ("%c", *str);
str ++;
} else {
switch (*str) {
case '\n':
eprintf("\\n");
break;
case '\r':
eprintf("\\r");
break;
case '\t':
eprintf("\\t");
break;
case '\b':
eprintf("\\b");
break;
case '\a':
eprintf("\\a");
break;
case '\\':
eprintf ("\\\\");
break;
case '"':
eprintf ("\\\"");
break;
default:
eprintf ("\\x%02x", (int)(unsigned char)*str);
break;
}
str ++;
}
}
eprintf ("\"");
}
static void print_offset (void) {
int i;
for (i = 0; i < multiline_offset; i++) {
eprintf (" ");
}
}
char *tglf_extf_fetch (struct tgl_state *TLS, struct paramed_type *T) {
out_buf_pos = 0;
if (fetch_type_any (T) < 0) { return 0; }
return out_buf;
}
#endif
/*
This file is part of tgl-library
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Copyright Vitaly Valtman 2014
*/
#ifndef __AUTO_H__
#define __AUTO_H__
struct tl_type_descr {
unsigned name;
char *id;
int params_num;
long long params_types;
};
struct paramed_type {
struct tl_type_descr *type;
struct paramed_type **params;
};
#define NAME_ARRAY 0x89932ad9
#define TYPE_TO_PARAM(NAME) (&(struct paramed_type) {.type = &tl_type_## NAME, .params=0})
#define TYPE_TO_PARAM_1(NAME,PARAM1) (&(struct paramed_type) {.type = &tl_type_## NAME, .params=(struct paramed_type *[1]){PARAM1}})
#define ODDP(x) (((long)(x)) & 1)
#define EVENP(x) (!ODDP(x))
#define INT2PTR(x) (void *)(long)(((long)x) * 2 + 1)
#define PTR2INT(x) ((((long)x) - 1) / 2)
void tgl_paramed_type_free (struct paramed_type *P);
#include "auto/auto-header.h"
#endif
/*
This file is part of tgl-library
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Copyright Vitaly Valtman 2013-2014
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <openssl/bn.h>
#include "binlog.h"
#include "mtproto-common.h"
//#include "net.h"
#include "include.h"
#include "mtproto-client.h"
#include "tgl.h"
#include "auto.h"
#include "structures.h"
#include <openssl/sha.h>
#define BINLOG_BUFFER_SIZE (1 << 20)
static int binlog_buffer[BINLOG_BUFFER_SIZE];
static int *rptr;
static int *wptr;
//static int TLS->binlog_fd;
static int in_replay_log; // should be used ONLY for DEBUG
#define MAX_LOG_EVENT_SIZE (1 << 17)
char *get_binlog_file_name (void);
static void *alloc_log_event (int l UU) {
return binlog_buffer;
}
static long long binlog_pos;
static int fetch_comb_binlog_start (struct tgl_state *TLS, void *extra) {
return 0;
}
static int fetch_comb_binlog_dc_option (struct tgl_state *TLS, void *extra) {
int id = fetch_int ();
int l1 = prefetch_strlen ();
assert (l1 >= 0);
char *name = fetch_str (l1);
int l2 = prefetch_strlen ();
assert (l2 >= 0);
char *ip = fetch_str (l2);
int port = fetch_int ();
vlogprintf (E_NOTICE, "DC%d '%.*s' update: %.*s:%d\n", id, l1, name, l2, ip, port);
tglmp_alloc_dc (TLS, id, tstrndup (ip, l2), port);
return 0;
}
static int fetch_comb_binlog_auth_key (struct tgl_state *TLS, void *extra) {
int num = fetch_int ();
assert (num >= 0 && num <= MAX_DC_ID);
assert (TLS->DC_list[num]);
TLS->DC_list[num]->auth_key_id = fetch_long ();
fetch_ints (TLS->DC_list[num]->auth_key, 64);
TLS->DC_list[num]->flags |= 1;
return 0;
}
static int fetch_comb_binlog_default_dc (struct tgl_state *TLS, void *extra) {
int num = fetch_int ();
assert (num >= 0 && num <= MAX_DC_ID);
TLS->DC_working = TLS->DC_list[num];
TLS->dc_working_num = num;
return 0;
}
static int fetch_comb_binlog_our_id (struct tgl_state *TLS, void *extra) {
TLS->our_id = fetch_int ();
if (TLS->callback.our_id) {
TLS->callback.our_id (TLS, TLS->our_id);
}
return 0;
}
static int fetch_comb_binlog_dc_signed (struct tgl_state *TLS, void *extra) {
int num = fetch_int ();
assert (num >= 0 && num <= MAX_DC_ID);
assert (TLS->DC_list[num]);
TLS->DC_list[num]->has_auth = 1;
return 0;
}
static int fetch_comb_binlog_dc_salt (struct tgl_state *TLS, void *extra) {
int num = fetch_int ();
assert (num >= 0 && num <= MAX_DC_ID);
assert (TLS->DC_list[num]);
TLS->DC_list[num]->server_salt = fetch_long ();
return 0;
}
static int fetch_comb_binlog_set_dh_params (struct tgl_state *TLS, void *extra) {
if (TLS->encr_prime) { tfree (TLS->encr_prime, 256); }
TLS->encr_root = fetch_int ();
TLS->encr_prime = talloc (256);
fetch_ints (TLS->encr_prime, 64);
TLS->encr_param_version = fetch_int ();
return 0;
}
static int fetch_comb_binlog_set_pts (struct tgl_state *TLS, void *extra) {
int new_pts = fetch_int ();
assert (new_pts >= TLS->pts);
vlogprintf (E_DEBUG - 1 + 2 * in_replay_log, "pts %d=>%d\n", TLS->pts, new_pts);
TLS->pts = new_pts;
return 0;
}
static int fetch_comb_binlog_set_qts (struct tgl_state *TLS, void *extra) {
int new_qts = fetch_int ();
assert (new_qts >= TLS->qts);
vlogprintf (E_DEBUG - 1 + 2 * in_replay_log, "qts %d=>%d\n", TLS->qts, new_qts);
TLS->qts = new_qts;
return 0;
}
static int fetch_comb_binlog_set_date (struct tgl_state *TLS, void *extra) {
int new_date = fetch_int ();
if (new_date < TLS->date) { return 0; }
assert (new_date >= TLS->date);
TLS->date = new_date;
return 0;
}
static int fetch_comb_binlog_set_seq (struct tgl_state *TLS, void *extra) {
int new_seq = fetch_int ();
if (new_seq < TLS->seq) {
vlogprintf (E_ERROR, "Error: old_seq = %d, new_seq = %d\n", TLS->seq, new_seq);
}
assert (new_seq >= TLS->seq);
vlogprintf (E_DEBUG - 1 + 2 * in_replay_log, "seq %d=>%d\n", TLS->seq, new_seq);
TLS->seq = new_seq;
return 0;
}
static int fetch_comb_binlog_user_add (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_USER (fetch_int ());
tgl_peer_t *_U = tgl_peer_get (TLS, id);
if (!_U) {
_U = talloc0 (sizeof (*_U));
_U->id = id;
tglp_insert_user (TLS, _U);
} else {
assert (!(_U->flags & FLAG_CREATED));
}
struct tgl_user *U = (void *)_U;
U->flags |= FLAG_CREATED;
if (tgl_get_peer_id (id) == TLS->our_id) {
U->flags |= FLAG_USER_SELF;
}
U->first_name = fetch_str_dup ();
U->last_name = fetch_str_dup ();
assert (!U->print_name);
U->print_name = TLS->callback.create_print_name (TLS, U->id, U->first_name, U->last_name, 0, 0);
tglp_peer_insert_name (TLS, (void *)U);
U->access_hash = fetch_long ();
U->phone = fetch_str_dup ();
if (fetch_int ()) {
U->flags |= FLAG_USER_CONTACT;
}
if (TLS->callback.user_update) {
TLS->callback.user_update (TLS, U, TGL_UPDATE_CREATED);
}
return 0;
}
static int fetch_comb_binlog_user_delete (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_USER (fetch_int ());
tgl_peer_t *U = tgl_peer_get (TLS, id);
assert (U);
U->flags |= FLAG_DELETED;
if (TLS->callback.user_update) {
TLS->callback.user_update (TLS, (void *)U, TGL_UPDATE_DELETED);
}
return 0;
}
static int fetch_comb_binlog_user_set_access_hash (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_USER (fetch_int ());
tgl_peer_t *U = tgl_peer_get (TLS, id);
assert (U);
U->user.access_hash = fetch_long ();
if (TLS->callback.user_update) {
TLS->callback.user_update (TLS, (void *)U, TGL_UPDATE_ACCESS_HASH);
}
return 0;
}
static int fetch_comb_binlog_user_set_phone (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_USER (fetch_int ());
tgl_peer_t *U = tgl_peer_get (TLS, id);
assert (U);
if (U->user.phone) {
tfree_str (U->user.phone);
}
U->user.phone = fetch_str_dup ();
if (TLS->callback.user_update) {
TLS->callback.user_update (TLS, (void *)U, TGL_UPDATE_PHONE);
}
return 0;
}
static int fetch_comb_binlog_user_set_friend (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_USER (fetch_int ());
tgl_peer_t *U = tgl_peer_get (TLS, id);
assert (U);
int friend = fetch_int ();
if (friend) { U->flags |= FLAG_USER_CONTACT; }
else { U->flags &= ~FLAG_USER_CONTACT; }
if (TLS->callback.user_update) {
TLS->callback.user_update (TLS, (void *)U, TGL_UPDATE_CONTACT);
}
return 0;
}
static int fetch_comb_binlog_user_set_full_photo (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_USER (fetch_int ());
tgl_peer_t *U = tgl_peer_get (TLS, id);
assert (U);
if (U->flags & FLAG_HAS_PHOTO) {
tgls_free_photo (TLS, &U->user.photo);
}
tglf_fetch_photo (TLS, &U->user.photo);
U->flags |= FLAG_HAS_PHOTO;
if (TLS->callback.user_update) {
TLS->callback.user_update (TLS, (void *)U, TGL_UPDATE_PHOTO);
}
return 0;
}
static int fetch_comb_binlog_user_set_blocked (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_USER (fetch_int ());
tgl_peer_t *U = tgl_peer_get (TLS, id);
assert (U);
U->user.blocked = fetch_int ();
if (TLS->callback.user_update) {
TLS->callback.user_update (TLS, (void *)U, TGL_UPDATE_BLOCKED);
}
return 0;
}
static int fetch_comb_binlog_user_set_real_name (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_USER (fetch_int ());
tgl_peer_t *U = tgl_peer_get (TLS, id);
assert (U);
assert (U->flags & FLAG_CREATED);
if (U->user.real_first_name) { tfree_str (U->user.real_first_name); }
if (U->user.real_last_name) { tfree_str (U->user.real_last_name); }
U->user.real_first_name = fetch_str_dup ();
U->user.real_last_name = fetch_str_dup ();
if (TLS->callback.user_update) {
TLS->callback.user_update (TLS, (void *)U, TGL_UPDATE_REAL_NAME);
}
return 0;
}
static int fetch_comb_binlog_user_set_name (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_USER (fetch_int ());
tgl_peer_t *U = tgl_peer_get (TLS, id);
assert (U);
if (U->user.first_name) { tfree_str (U->user.first_name); }
if (U->user.last_name) { tfree_str (U->user.last_name); }
U->user.first_name = fetch_str_dup ();
U->user.last_name = fetch_str_dup ();
if (U->print_name) {
tglp_peer_delete_name (TLS, U);
tfree_str (U->print_name);
}
U->print_name = TLS->callback.create_print_name (TLS, U->id, U->user.first_name, U->user.last_name, 0, 0);
tglp_peer_insert_name (TLS, (void *)U);
if (TLS->callback.user_update) {
TLS->callback.user_update (TLS, (void *)U, TGL_UPDATE_NAME);
}
return 0;
}
static int fetch_comb_binlog_user_set_username (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_USER (fetch_int ());
tgl_peer_t *U = tgl_peer_get (TLS, id);
assert (U);
if (U->user.username) { tfree_str (U->user.username); }
U->user.username = fetch_str_dup ();
if (TLS->callback.user_update) {
TLS->callback.user_update (TLS, (void *)U, TGL_UPDATE_USERNAME);
}
return 0;
}
static int fetch_comb_binlog_user_set_photo (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_USER (fetch_int ());
tgl_peer_t *U = tgl_peer_get (TLS, id);
assert (U);
unsigned y = fetch_int ();
if (y == CODE_user_profile_photo_empty) {
U->user.photo_id = 0;
U->user.photo_big.dc = -2;
U->user.photo_small.dc = -2;
} else {
assert (y == CODE_user_profile_photo);
U->user.photo_id = fetch_long ();
tglf_fetch_file_location (TLS, &U->user.photo_small);
tglf_fetch_file_location (TLS, &U->user.photo_big);
}
if (TLS->callback.user_update) {
TLS->callback.user_update (TLS, (void *)U, TGL_UPDATE_PHOTO);
}
return 0;
}
static int fetch_comb_binlog_encr_chat_delete (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_ENCR_CHAT (fetch_int ());
tgl_peer_t *_U = tgl_peer_get (TLS, id);
assert (_U);
struct tgl_secret_chat *U = &_U->encr_chat;
memset (U->key, 0, sizeof (U->key));
U->flags |= FLAG_DELETED;
U->state = sc_deleted;
if (U->nonce) {
tfree_secure (U->nonce, 256);
U->nonce = 0;
}
if (U->g_key) {
tfree_secure (U->g_key, 256);
U->g_key = 0;
}
if (TLS->callback.secret_chat_update) {
TLS->callback.secret_chat_update (TLS, U, TGL_UPDATE_DELETED);
}
return 0;
}
static int fetch_comb_binlog_encr_chat_requested (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_ENCR_CHAT (fetch_int ());
tgl_peer_t *_U = tgl_peer_get (TLS, id);
if (!_U) {
_U = talloc0 (sizeof (*_U));
_U->id = id;
tglp_insert_encrypted_chat (TLS, _U);
} else {
assert (!(_U->flags & FLAG_CREATED));
}
struct tgl_secret_chat *U = (void *)_U;
U->access_hash = fetch_long ();
U->date = fetch_int ();
U->admin_id = fetch_int ();
U->user_id = fetch_int ();
tgl_peer_t *Us = tgl_peer_get (TLS, TGL_MK_USER (U->user_id));
assert (!U->print_name);
if (Us) {
U->print_name = TLS->callback.create_print_name (TLS, id, "!", Us->user.first_name, Us->user.last_name, 0);
} else {
static char buf[100];
tsnprintf (buf, 99, "user#%d", U->user_id);
U->print_name = TLS->callback.create_print_name (TLS, id, "!", buf, 0, 0);
}
tglp_peer_insert_name (TLS, (void *)U);
U->g_key = talloc (256);
U->nonce = talloc (256);
fetch_ints (U->g_key, 64);
fetch_ints (U->nonce, 64);
U->flags |= FLAG_CREATED;
U->state = sc_request;
if (TLS->callback.secret_chat_update) {
TLS->callback.secret_chat_update (TLS, U, TGL_UPDATE_REQUESTED);
}
return 0;
}
static int fetch_comb_binlog_encr_chat_set_access_hash (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_ENCR_CHAT (fetch_int ());
tgl_peer_t *U = tgl_peer_get (TLS, id);
assert (U);
U->encr_chat.access_hash = fetch_long ();
if (TLS->callback.secret_chat_update) {
TLS->callback.secret_chat_update (TLS, (void *)U, TGL_UPDATE_ACCESS_HASH);
}
return 0;
}
static int fetch_comb_binlog_encr_chat_set_date (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_ENCR_CHAT (fetch_int ());
tgl_peer_t *U = tgl_peer_get (TLS, id);
assert (U);
U->encr_chat.date = fetch_int ();
return 0;
}
static int fetch_comb_binlog_encr_chat_set_ttl (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_ENCR_CHAT (fetch_int ());
tgl_peer_t *U = tgl_peer_get (TLS, id);
assert (U);
U->encr_chat.ttl = fetch_int ();
return 0;
}
static int fetch_comb_binlog_encr_chat_set_layer (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_ENCR_CHAT (fetch_int ());
tgl_peer_t *U = tgl_peer_get (TLS, id);
assert (U);
U->encr_chat.layer = fetch_int ();
return 0;
}
static int fetch_comb_binlog_encr_chat_set_state (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_ENCR_CHAT (fetch_int ());
tgl_peer_t *U = tgl_peer_get (TLS, id);
assert (U);
U->encr_chat.state = fetch_int ();
return 0;
}
static int fetch_comb_binlog_encr_chat_accepted (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_ENCR_CHAT (fetch_int ());
tgl_peer_t *_U = tgl_peer_get (TLS, id);
assert (_U);
struct tgl_secret_chat *U = &_U->encr_chat;
if (!U->g_key) {
U->g_key = talloc (256);
}
if (!U->nonce) {
U->nonce = talloc (256);
}
fetch_ints (U->g_key, 64);
fetch_ints (U->nonce, 64);
U->key_fingerprint = fetch_long ();
if (U->state == sc_waiting) {
tgl_do_create_keys_end (TLS, U);
}
U->state = sc_ok;
if (TLS->callback.secret_chat_update) {
TLS->callback.secret_chat_update (TLS, U, TGL_UPDATE_WORKING);
}
return 0;
}
static int fetch_comb_binlog_encr_chat_set_key (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_ENCR_CHAT (fetch_int ());
tgl_peer_t *_U = tgl_peer_get (TLS, id);
assert (_U);
struct tgl_secret_chat *U = &_U->encr_chat;
fetch_ints (U->key, 64);
U->key_fingerprint = fetch_long ();
return 0;
}
static int fetch_comb_binlog_encr_chat_update_seq (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_ENCR_CHAT (fetch_int ());
tgl_peer_t *_U = tgl_peer_get (TLS, id);
assert (_U);
_U->encr_chat.in_seq_no = fetch_int ();
_U->encr_chat.last_in_seq_no = fetch_int ();
return 0;
}
static int fetch_comb_binlog_encr_chat_set_seq (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_ENCR_CHAT (fetch_int ());
tgl_peer_t *_U = tgl_peer_get (TLS, id);
assert (_U);
_U->encr_chat.in_seq_no = fetch_int ();
_U->encr_chat.last_in_seq_no = fetch_int ();
_U->encr_chat.out_seq_no = fetch_int ();
return 0;
}
static int fetch_comb_binlog_encr_chat_init (struct tgl_state *TLS, void *extra) {
tgl_peer_t *P = talloc0 (sizeof (*P));
P->id = TGL_MK_ENCR_CHAT (fetch_int ());
assert (!tgl_peer_get (TLS, P->id));
P->encr_chat.user_id = fetch_int ();
P->encr_chat.admin_id = TLS->our_id;
tglp_insert_encrypted_chat (TLS, P);
tgl_peer_t *Us = tgl_peer_get (TLS, TGL_MK_USER (P->encr_chat.user_id));
assert (Us);
P->print_name = TLS->callback.create_print_name (TLS, P->id, "!", Us->user.first_name, Us->user.last_name, 0);
tglp_peer_insert_name (TLS, P);
P->encr_chat.g_key = talloc (256);
fetch_ints (P->encr_chat.key, 64);
fetch_ints (P->encr_chat.g_key, 64);
P->flags |= FLAG_CREATED;
if (TLS->callback.secret_chat_update) {
TLS->callback.secret_chat_update (TLS, (void *)P, TGL_UPDATE_CREATED);
}
return 0;
}
static int fetch_comb_binlog_encr_chat_create (struct tgl_state *TLS, void *extra) {
tgl_peer_t *P = talloc0 (sizeof (*P));
P->id = TGL_MK_ENCR_CHAT (fetch_int ());
assert (!tgl_peer_get (TLS, P->id));
P->encr_chat.user_id = fetch_int ();
P->encr_chat.admin_id = fetch_int ();
tglp_insert_encrypted_chat (TLS, P);
P->print_name = fetch_str_dup ();
tglp_peer_insert_name (TLS, P);
P->flags |= FLAG_CREATED;
if (TLS->callback.secret_chat_update) {
TLS->callback.secret_chat_update (TLS, (void *)P, TGL_UPDATE_CREATED);
}
return 0;
}
static int fetch_comb_binlog_chat_create (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_CHAT (fetch_int ());
tgl_peer_t *_C = tgl_peer_get (TLS, id);
if (!_C) {
_C = talloc0 (sizeof (*_C));
_C->id = id;
tglp_insert_chat (TLS, _C);
} else {
assert (!(_C->flags & FLAG_CREATED));
}
struct tgl_chat *C = &_C->chat;
C->flags = FLAG_CREATED | fetch_int ();
C->title = fetch_str_dup ();
assert (!C->print_title);
C->print_title = TLS->callback.create_print_name (TLS, id, C->title, 0, 0, 0);
tglp_peer_insert_name (TLS, (void *)C);
C->users_num = fetch_int ();
C->date = fetch_int ();
C->version = fetch_int ();
fetch_data (&C->photo_big, sizeof (struct tgl_file_location));
fetch_data (&C->photo_small, sizeof (struct tgl_file_location));
if (TLS->callback.chat_update) {
TLS->callback.chat_update (TLS, C, TGL_UPDATE_CREATED);
}
return 0;
}
static int fetch_comb_binlog_chat_change_flags (struct tgl_state *TLS, void *extra) {
tgl_peer_t *C = tgl_peer_get (TLS, TGL_MK_CHAT (fetch_int ()));
assert (C && (C->flags & FLAG_CREATED));
C->chat.flags |= fetch_int ();
C->chat.flags &= ~fetch_int ();
if (TLS->callback.chat_update) {
TLS->callback.chat_update (TLS, (void *)C, TGL_UPDATE_FLAGS);
}
return 0;
}
static int fetch_comb_binlog_chat_set_title (struct tgl_state *TLS, void *extra) {
tgl_peer_t *C = tgl_peer_get (TLS, TGL_MK_CHAT (fetch_int ()));
assert (C && (C->flags & FLAG_CREATED));
if (C->chat.title) { tfree_str (C->chat.title); }
C->chat.title = fetch_str_dup ();
if (C->print_name) {
tglp_peer_delete_name (TLS, (void *)C);
tfree_str (C->print_name);
}
C->print_name = TLS->callback.create_print_name (TLS, C->id, C->chat.title, 0, 0, 0);
tglp_peer_insert_name (TLS, (void *)C);
if (TLS->callback.chat_update) {
TLS->callback.chat_update (TLS, (void *)C, TGL_UPDATE_TITLE);
}
return 0;
}
static int fetch_comb_binlog_chat_set_photo (struct tgl_state *TLS, void *extra) {
tgl_peer_t *C = tgl_peer_get (TLS, TGL_MK_CHAT (fetch_int ()));
assert (C && (C->flags & FLAG_CREATED));
fetch_data (&C->photo_big, sizeof (struct tgl_file_location));
fetch_data (&C->photo_small, sizeof (struct tgl_file_location));
if (TLS->callback.chat_update) {
TLS->callback.chat_update (TLS, (void *)C, TGL_UPDATE_PHOTO);
}
return 0;
}
static int fetch_comb_binlog_chat_set_date (struct tgl_state *TLS, void *extra) {
tgl_peer_t *C = tgl_peer_get (TLS, TGL_MK_CHAT (fetch_int ()));
assert (C && (C->flags & FLAG_CREATED));
C->chat.date = fetch_int ();
return 0;
}
static int fetch_comb_binlog_chat_set_version (struct tgl_state *TLS, void *extra) {
tgl_peer_t *C = tgl_peer_get (TLS, TGL_MK_CHAT (fetch_int ()));
assert (C && (C->flags & FLAG_CREATED));
C->chat.version = fetch_int ();
C->chat.users_num = fetch_int ();
return 0;
}
static int fetch_comb_binlog_chat_set_admin (struct tgl_state *TLS, void *extra) {
tgl_peer_t *C = tgl_peer_get (TLS, TGL_MK_CHAT (fetch_int ()));
assert (C && (C->flags & FLAG_CREATED));
C->chat.admin_id = fetch_int ();
if (TLS->callback.chat_update) {
TLS->callback.chat_update (TLS, (void *)C, TGL_UPDATE_ADMIN);
}
return 0;
}
static int fetch_comb_binlog_chat_set_participants (struct tgl_state *TLS, void *extra) {
tgl_peer_t *C = tgl_peer_get (TLS, TGL_MK_CHAT (fetch_int ()));
assert (C && (C->flags & FLAG_CREATED));
C->chat.user_list_version = fetch_int ();
if (C->chat.user_list) { tfree (C->chat.user_list, 12 * C->chat.user_list_size); }
C->chat.user_list_size = fetch_int ();
C->chat.user_list = talloc (12 * C->chat.user_list_size);
fetch_ints (C->chat.user_list, 3 * C->chat.user_list_size);
if (TLS->callback.chat_update) {
TLS->callback.chat_update (TLS, (void *)C, TGL_UPDATE_MEMBERS);
}
return 0;
}
static int fetch_comb_binlog_chat_set_full_photo (struct tgl_state *TLS, void *extra) {
tgl_peer_t *C = tgl_peer_get (TLS, TGL_MK_CHAT (fetch_int ()));
assert (C && (C->flags & FLAG_CREATED));
assert (C && (C->flags & FLAG_CREATED));
if (C->flags & FLAG_HAS_PHOTO) {
tgls_free_photo (TLS, &C->chat.photo);
}
tglf_fetch_photo (TLS, &C->chat.photo);
C->flags |= FLAG_HAS_PHOTO;
if (TLS->callback.chat_update) {
TLS->callback.chat_update (TLS, (void *)C, TGL_UPDATE_PHOTO);
}
return 0;
}
static int fetch_comb_binlog_chat_add_participant (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_CHAT (fetch_int ());
tgl_peer_t *_C = tgl_peer_get (TLS, id);
assert (_C && (_C->flags & FLAG_CREATED));
struct tgl_chat *C = &_C->chat;
int version = fetch_int ();
int user = fetch_int ();
int inviter = fetch_int ();
int date = fetch_int ();
assert (C->user_list_version < version);
int i;
for (i = 0; i < C->user_list_size; i++) {
assert (C->user_list[i].user_id != user);
}
C->user_list_size ++;
C->user_list = trealloc (C->user_list, 12 * C->user_list_size - 12, 12 * C->user_list_size);
C->user_list[C->user_list_size - 1].user_id = user;
C->user_list[C->user_list_size - 1].inviter_id = inviter;
C->user_list[C->user_list_size - 1].date = date;
C->user_list_version = version;
if (TLS->callback.chat_update) {
TLS->callback.chat_update (TLS, C, TGL_UPDATE_MEMBERS);
}
return 0;
}
static int fetch_comb_binlog_chat_del_participant (struct tgl_state *TLS, void *extra) {
tgl_peer_id_t id = TGL_MK_CHAT (fetch_int ());
tgl_peer_t *_C = tgl_peer_get (TLS, id);
assert (_C && (_C->flags & FLAG_CREATED));
struct tgl_chat *C = &_C->chat;
int version = fetch_int ();
int user = fetch_int ();
assert (C->user_list_version < version);
int i;
for (i = 0; i < C->user_list_size; i++) {
if (C->user_list[i].user_id == user) {
struct tgl_chat_user t;
t = C->user_list[i];
C->user_list[i] = C->user_list[C->user_list_size - 1];
C->user_list[C->user_list_size - 1] = t;
}
}
assert (C->user_list[C->user_list_size - 1].user_id == user);
C->user_list_size --;
C->user_list = trealloc (C->user_list, 12 * C->user_list_size + 12, 12 * C->user_list_size);
C->user_list_version = version;
if (TLS->callback.chat_update) {
TLS->callback.chat_update (TLS, C, TGL_UPDATE_MEMBERS);
}
return 0;
}
static int fetch_comb_binlog_create_message_text (struct tgl_state *TLS, void *extra) {
long long id = fetch_int ();
struct tgl_message *M = tgl_message_get (TLS, id);
if (!M) {
M = tglm_message_alloc (TLS, id);
} else {
assert (!(M->flags & FLAG_CREATED));
}
M->flags |= FLAG_CREATED;
M->from_id = TGL_MK_USER (fetch_int ());
int t = fetch_int ();
if (t == TGL_PEER_ENCR_CHAT) {
M->flags |= FLAG_ENCRYPTED;
}
M->to_id = tgl_set_peer_id (t, fetch_int ());
M->date = fetch_int ();
M->unread = fetch_int ();
int l = prefetch_strlen ();
M->message = talloc (l + 1);
memcpy (M->message, fetch_str (l), l);
M->message[l] = 0;
M->message_len = l;
if (t == TGL_PEER_ENCR_CHAT) {
M->media.type = tgl_message_media_none;
} else {
M->media.type = tgl_message_media_none;
}
//M->unread = 1;
M->out = tgl_get_peer_id (M->from_id) == TLS->our_id;
tglm_message_insert (TLS, M);
return 0;
}
static int fetch_comb_binlog_send_message_text (struct tgl_state *TLS, void *extra) {
long long id = fetch_long ();
struct tgl_message *M = tgl_message_get (TLS, id);
if (!M) {
M = tglm_message_alloc (TLS, id);
} else {
assert (!(M->flags & FLAG_CREATED));
}
M->flags |= FLAG_CREATED;
M->from_id = TGL_MK_USER (fetch_int ());
int t = fetch_int ();
if (t == TGL_PEER_ENCR_CHAT) {
M->flags |= FLAG_ENCRYPTED;
}
M->to_id = tgl_set_peer_id (t, fetch_int ());
if (t == TGL_PEER_ENCR_CHAT) {
tgl_peer_t *P = tgl_peer_get (TLS, M->to_id);
if (P && P->encr_chat.layer >= 17) {
P->encr_chat.out_seq_no ++;
}
}
M->date = fetch_int ();
int l = prefetch_strlen ();
M->message = talloc (l + 1);
memcpy (M->message, fetch_str (l), l);
M->message[l] = 0;
M->message_len = l;
if (t == TGL_PEER_ENCR_CHAT) {
M->media.type = tgl_message_media_none;
} else {
M->media.type = tgl_message_media_none;
}
M->unread = 1;
M->out = tgl_get_peer_id (M->from_id) == TLS->our_id;
tglm_message_insert (TLS, M);
tglm_message_insert_unsent (TLS, M);
M->flags |= FLAG_PENDING;
return 0;
}
static int fetch_comb_binlog_send_message_action_encr (struct tgl_state *TLS, void *extra) {
long long id = fetch_long ();
struct tgl_message *M = tgl_message_get (TLS, id);
if (!M) {
M = tglm_message_alloc (TLS, id);
} else {
assert (!(M->flags & FLAG_CREATED));
}
M->flags |= FLAG_CREATED | FLAG_ENCRYPTED;
M->from_id = TGL_MK_USER (fetch_int ());
int t = fetch_int ();
M->to_id = tgl_set_peer_id (t, fetch_int ());
M->date = fetch_int ();
M->media.type = tgl_message_media_none;
tglf_fetch_message_action_encrypted (TLS, &M->action);
tgl_peer_t *P = tgl_peer_get (TLS, M->to_id);
if (P) {
if (P->encr_chat.layer >= 17) {
P->encr_chat.out_seq_no ++;
}
}
M->unread = 1;
M->out = tgl_get_peer_id (M->from_id) == TLS->our_id;
M->service = 1;
tglm_message_insert (TLS, M);
tglm_message_insert_unsent (TLS, M);
M->flags |= FLAG_PENDING;
return 0;
}
static int fetch_comb_binlog_create_message_text_fwd (struct tgl_state *TLS, void *extra) {
long long id = fetch_int ();
struct tgl_message *M = tgl_message_get (TLS, id);
if (!M) {
M = tglm_message_alloc (TLS, id);
} else {
assert (!(M->flags & FLAG_CREATED));
}
M->flags |= FLAG_CREATED;
M->from_id = TGL_MK_USER (fetch_int ());
int t = fetch_int ();
if (t == TGL_PEER_ENCR_CHAT) {
M->flags |= FLAG_ENCRYPTED;
}
M->to_id = tgl_set_peer_id (t, fetch_int ());
M->date = fetch_int ();
M->fwd_from_id = TGL_MK_USER (fetch_int ());
M->fwd_date = fetch_int ();
M->unread = fetch_int ();
int l = prefetch_strlen ();
M->message = talloc (l + 1);
memcpy (M->message, fetch_str (l), l);
M->message[l] = 0;
M->message_len = l;
if (t == TGL_PEER_ENCR_CHAT) {
M->media.type = tgl_message_media_none;
} else {
M->media.type = tgl_message_media_none;
}
//M->unread = 1;
M->out = tgl_get_peer_id (M->from_id) == TLS->our_id;
tglm_message_insert (TLS, M);
return 0;
}
static int fetch_comb_binlog_create_message_media (struct tgl_state *TLS, void *extra) {
int id = fetch_int ();
struct tgl_message *M = tgl_message_get (TLS, id);
if (!M) {
M = tglm_message_alloc (TLS, id);
} else {
assert (!(M->flags & FLAG_CREATED));
}
M->flags |= FLAG_CREATED;
M->from_id = TGL_MK_USER (fetch_int ());
int t = fetch_int ();
M->to_id = tgl_set_peer_id (t, fetch_int ());
M->date = fetch_int ();
M->unread = fetch_int ();
int l = prefetch_strlen ();
M->message = talloc (l + 1);
memcpy (M->message, fetch_str (l), l);
M->message[l] = 0;
M->message_len = l;
tglf_fetch_message_media (TLS, &M->media);
//M->unread = 1;
M->out = tgl_get_peer_id (M->from_id) == TLS->our_id;
tglm_message_insert (TLS, M);
return 0;
}
static int fetch_comb_binlog_create_message_media_encr (struct tgl_state *TLS, void *extra) {
long long id = fetch_long ();
struct tgl_message *M = tgl_message_get (TLS, id);
if (!M) {
M = tglm_message_alloc (TLS, id);
} else {
assert (!(M->flags & FLAG_CREATED));
}
M->flags |= FLAG_CREATED | FLAG_ENCRYPTED;
M->from_id = TGL_MK_USER (fetch_int ());
int t = fetch_int ();
M->to_id = tgl_set_peer_id (t, fetch_int ());
M->date = fetch_int ();
int l = prefetch_strlen ();
M->message = talloc (l + 1);
memcpy (M->message, fetch_str (l), l);
M->message[l] = 0;
M->message_len = l;
tglf_fetch_message_media_encrypted (TLS, &M->media);
tglf_fetch_encrypted_message_file (TLS, &M->media);
M->unread = 1;
M->out = tgl_get_peer_id (M->from_id) == TLS->our_id;
tglm_message_insert (TLS, M);
return 0;
}
static int fetch_comb_binlog_create_message_media_encr_pending (struct tgl_state *TLS, void *extra) {
long long id = fetch_long ();
struct tgl_message *M = tgl_message_get (TLS, id);
if (!M) {
M = tglm_message_alloc (TLS, id);
} else {
assert (!(M->flags & FLAG_CREATED));
}
M->flags |= FLAG_CREATED | FLAG_ENCRYPTED;
M->from_id = TGL_MK_USER (fetch_int ());
int t = fetch_int ();
M->to_id = tgl_set_peer_id (t, fetch_int ());
M->date = fetch_int ();
tgl_peer_t *P = tgl_peer_get (TLS, M->to_id);
if (P) {
if (P->encr_chat.layer >= 17) {
P->encr_chat.out_seq_no ++;
}
}
int l = prefetch_strlen ();
M->message = talloc (l + 1);
memcpy (M->message, fetch_str (l), l);
M->message[l] = 0;
M->message_len = l;
tglf_fetch_message_media_encrypted (TLS, &M->media);
M->unread = 1;
M->out = tgl_get_peer_id (M->from_id) == TLS->our_id;
tglm_message_insert (TLS, M);
tglm_message_insert_unsent (TLS, M);
M->flags |= FLAG_PENDING;
return 0;
}
static int fetch_comb_binlog_create_message_media_encr_sent (struct tgl_state *TLS, void *extra) {
long long id = fetch_long ();
struct tgl_message *M = tgl_message_get (TLS, id);
assert (M && (M->flags & FLAG_CREATED));
tglf_fetch_encrypted_message_file (TLS, &M->media);
tglm_message_remove_unsent (TLS, M);
M->flags &= ~FLAG_PENDING;
return 0;
}
static int fetch_comb_binlog_create_message_media_fwd (struct tgl_state *TLS, void *extra) {
int id = fetch_int ();
struct tgl_message *M = tgl_message_get (TLS, id);
if (!M) {
M = tglm_message_alloc (TLS, id);
} else {
assert (!(M->flags & FLAG_CREATED));
}
M->flags |= FLAG_CREATED;
M->from_id = TGL_MK_USER (fetch_int ());
int t = fetch_int ();
M->to_id = tgl_set_peer_id (t, fetch_int ());
M->date = fetch_int ();
M->fwd_from_id = TGL_MK_USER (fetch_int ());
M->fwd_date = fetch_int ();
M->unread = fetch_int ();
int l = prefetch_strlen ();
M->message = talloc (l + 1);
memcpy (M->message, fetch_str (l), l);
M->message[l] = 0;
M->message_len = l;
tglf_fetch_message_media (TLS, &M->media);
//M->unread = 1;
M->out = tgl_get_peer_id (M->from_id) == TLS->our_id;
tglm_message_insert (TLS, M);
return 0;
}
static int fetch_comb_binlog_create_message_service (struct tgl_state *TLS, void *extra) {
int id = fetch_int ();
struct tgl_message *M = tgl_message_get (TLS, id);
if (!M) {
M = tglm_message_alloc (TLS, id);
} else {
assert (!(M->flags & FLAG_CREATED));
}
M->flags |= FLAG_CREATED;
M->from_id = TGL_MK_USER (fetch_int ());
int t = fetch_int ();
M->to_id = tgl_set_peer_id (t, fetch_int ());
M->date = fetch_int ();
M->unread = fetch_int ();
tglf_fetch_message_action (TLS, &M->action);
//M->unread = 1;
M->out = tgl_get_peer_id (M->from_id) == TLS->our_id;
M->service = 1;
tglm_message_insert (TLS, M);
return 0;
}
static int fetch_comb_binlog_create_message_service_encr (struct tgl_state *TLS, void *extra) {
long long id = fetch_long ();
struct tgl_message *M = tgl_message_get (TLS, id);
if (!M) {
M = tglm_message_alloc (TLS, id);
} else {
assert (!(M->flags & FLAG_CREATED));
}
M->flags |= FLAG_CREATED | FLAG_ENCRYPTED;
M->from_id = TGL_MK_USER (fetch_int ());
int t = fetch_int ();
assert (t == TGL_PEER_ENCR_CHAT);
M->to_id = tgl_set_peer_id (t, fetch_int ());
M->date = fetch_int ();
struct tgl_secret_chat *E = (void *)tgl_peer_get (TLS, M->to_id);
assert (E);
tglf_fetch_message_action_encrypted (TLS, &M->action);
M->unread = 1;
M->out = tgl_get_peer_id (M->from_id) == TLS->our_id;
M->service = 1;
if (!M->out && M->action.type == tgl_message_action_notify_layer) {
E->layer = M->action.layer;
}
tglm_message_insert (TLS, M);
return 0;
}
static int fetch_comb_binlog_create_message_service_fwd (struct tgl_state *TLS, void *extra) {
int id = fetch_int ();
struct tgl_message *M = tgl_message_get (TLS, id);
if (!M) {
M = tglm_message_alloc (TLS, id);
} else {
assert (!(M->flags & FLAG_CREATED));
}
M->flags |= FLAG_CREATED;
M->from_id = TGL_MK_USER (fetch_int ());
int t = fetch_int ();
M->to_id = tgl_set_peer_id (t, fetch_int ());
M->date = fetch_int ();
M->fwd_from_id = TGL_MK_USER (fetch_int ());
M->fwd_date = fetch_int ();
M->unread = fetch_int ();
tglf_fetch_message_action (TLS, &M->action);
//M->unread = 1;
M->out = tgl_get_peer_id (M->from_id) == TLS->our_id;
M->service = 1;
tglm_message_insert (TLS, M);
return 0;
}
static int fetch_comb_binlog_message_set_unread_long (struct tgl_state *TLS, void *extra) {
struct tgl_message *M = tgl_message_get (TLS, fetch_long ());
assert (M);
if (M->unread) {
M->unread = 0;
if (TLS->callback.marked_read) {
TLS->callback.marked_read (TLS, 1, &M);
}
}
return 0;
}
static int fetch_comb_binlog_message_set_unread (struct tgl_state *TLS, void *extra) {
struct tgl_message *M = tgl_message_get (TLS, fetch_int ());
assert (M);
if (M->unread) {
M->unread = 0;
if (TLS->callback.marked_read) {
TLS->callback.marked_read (TLS, 1, &M);
}
}
return 0;
}
static int fetch_comb_binlog_set_message_sent (struct tgl_state *TLS, void *extra) {
struct tgl_message *M = tgl_message_get (TLS, fetch_long ());
assert (M);
tglm_message_remove_unsent (TLS, M);
M->flags &= ~FLAG_PENDING;
return 0;
}
static int fetch_comb_binlog_set_msg_id (struct tgl_state *TLS, void *extra) {
struct tgl_message *M = tgl_message_get (TLS, fetch_long ());
assert (M);
if (M->flags & FLAG_PENDING) {
tglm_message_remove_unsent (TLS, M);
M->flags &= ~FLAG_PENDING;
}
tglm_message_remove_tree (TLS, M);
tglm_message_del_peer (TLS, M);
M->id = fetch_int ();
if (tgl_message_get (TLS, M->id)) {
tgls_free_message (TLS, M);
} else {
tglm_message_insert_tree (TLS, M);
tglm_message_add_peer (TLS, M);
}
return 0;
}
static int fetch_comb_binlog_delete_msg (struct tgl_state *TLS, void *extra) {
struct tgl_message *M = tgl_message_get (TLS, fetch_long ());
assert (M);
if (M->flags & FLAG_PENDING) {
tglm_message_remove_unsent (TLS, M);
M->flags &= ~FLAG_PENDING;
}
tglm_message_remove_tree (TLS, M);
tglm_message_del_peer (TLS, M);
tglm_message_del_use (TLS, M);
tgls_free_message (TLS, M);
return 0;
}
static int fetch_comb_binlog_msg_seq_update (struct tgl_state *TLS, void *extra) {
struct tgl_message *M = tgl_message_get (TLS, fetch_long ());
assert (M);
TLS->seq ++;
vlogprintf (E_DEBUG - 1 + 2 * in_replay_log, "seq %d=>%d\n", TLS->seq - 1, TLS->seq);
if (!(M->flags & FLAG_ENCRYPTED)) {
if (TLS->max_msg_id < M->id) {
TLS->max_msg_id = M->id;
}
}
if (TLS->callback.msg_receive) {
TLS->callback.msg_receive (TLS, M);
}
return 0;
}
static int fetch_comb_binlog_msg_update (struct tgl_state *TLS, void *extra) {
struct tgl_message *M = tgl_message_get (TLS, fetch_long ());
if (!M) { return 0; }
assert (M);
if (!(M->flags & FLAG_ENCRYPTED)) {
if (TLS->max_msg_id < M->id) {
TLS->max_msg_id = M->id;
}
}
if (TLS->callback.msg_receive) {
TLS->callback.msg_receive (TLS, M);
}
return 0;
}
static int fetch_comb_binlog_reset_authorization (struct tgl_state *TLS, void *extra) {
int i;
for (i = 0; i <= TLS->max_dc_num; i++) if (TLS->DC_list[i]) {
struct tgl_dc *D = TLS->DC_list[i];
D->flags = 0;
D->state = st_init;
D->auth_key_id = D->temp_auth_key_id = 0;
D->has_auth = 0;
}
TLS->seq = 0;
TLS->qts = 0;
return 0;
}
#define FETCH_COMBINATOR_FUNCTION(NAME) \
case CODE_ ## NAME:\
ok = fetch_comb_ ## NAME (TLS, 0); \
break; \
static void replay_log_event (struct tgl_state *TLS) {
assert (rptr < wptr);
int op = *rptr;
vlogprintf (E_DEBUG, "replay_log_event: log_pos=%lld, op=0x%08x\n", binlog_pos, op);
in_ptr = rptr;
in_end = wptr;
assert (skip_type_any (TYPE_TO_PARAM(binlog_update)) >= 0);
in_end = in_ptr;
in_ptr = rptr;
int ok = -1;
in_ptr ++;
switch (op) {
FETCH_COMBINATOR_FUNCTION (binlog_start)
FETCH_COMBINATOR_FUNCTION (binlog_dc_option)
FETCH_COMBINATOR_FUNCTION (binlog_auth_key)
FETCH_COMBINATOR_FUNCTION (binlog_default_dc)
FETCH_COMBINATOR_FUNCTION (binlog_our_id)
FETCH_COMBINATOR_FUNCTION (binlog_dc_signed)
FETCH_COMBINATOR_FUNCTION (binlog_dc_salt)
FETCH_COMBINATOR_FUNCTION (binlog_set_dh_params)
FETCH_COMBINATOR_FUNCTION (binlog_set_pts)
FETCH_COMBINATOR_FUNCTION (binlog_set_qts)
FETCH_COMBINATOR_FUNCTION (binlog_set_date)
FETCH_COMBINATOR_FUNCTION (binlog_set_seq)
FETCH_COMBINATOR_FUNCTION (binlog_user_add)
FETCH_COMBINATOR_FUNCTION (binlog_user_delete)
FETCH_COMBINATOR_FUNCTION (binlog_user_set_access_hash)
FETCH_COMBINATOR_FUNCTION (binlog_user_set_phone)
FETCH_COMBINATOR_FUNCTION (binlog_user_set_friend)
FETCH_COMBINATOR_FUNCTION (binlog_user_set_full_photo)
FETCH_COMBINATOR_FUNCTION (binlog_user_set_blocked)
FETCH_COMBINATOR_FUNCTION (binlog_user_set_name)
FETCH_COMBINATOR_FUNCTION (binlog_user_set_username)
FETCH_COMBINATOR_FUNCTION (binlog_user_set_photo)
FETCH_COMBINATOR_FUNCTION (binlog_user_set_real_name)
FETCH_COMBINATOR_FUNCTION (binlog_encr_chat_delete)
FETCH_COMBINATOR_FUNCTION (binlog_encr_chat_requested)
FETCH_COMBINATOR_FUNCTION (binlog_encr_chat_set_access_hash)
FETCH_COMBINATOR_FUNCTION (binlog_encr_chat_set_date)
FETCH_COMBINATOR_FUNCTION (binlog_encr_chat_set_ttl)
FETCH_COMBINATOR_FUNCTION (binlog_encr_chat_set_layer)
FETCH_COMBINATOR_FUNCTION (binlog_encr_chat_set_state)
FETCH_COMBINATOR_FUNCTION (binlog_encr_chat_accepted)
FETCH_COMBINATOR_FUNCTION (binlog_encr_chat_set_key)
FETCH_COMBINATOR_FUNCTION (binlog_encr_chat_update_seq)
FETCH_COMBINATOR_FUNCTION (binlog_encr_chat_set_seq)
FETCH_COMBINATOR_FUNCTION (binlog_encr_chat_init)
FETCH_COMBINATOR_FUNCTION (binlog_encr_chat_create)
FETCH_COMBINATOR_FUNCTION (binlog_chat_create)
FETCH_COMBINATOR_FUNCTION (binlog_chat_change_flags)
FETCH_COMBINATOR_FUNCTION (binlog_chat_set_title)
FETCH_COMBINATOR_FUNCTION (binlog_chat_set_photo)
FETCH_COMBINATOR_FUNCTION (binlog_chat_set_date)
FETCH_COMBINATOR_FUNCTION (binlog_chat_set_version)
FETCH_COMBINATOR_FUNCTION (binlog_chat_set_admin)
FETCH_COMBINATOR_FUNCTION (binlog_chat_set_participants)
FETCH_COMBINATOR_FUNCTION (binlog_chat_set_full_photo)
FETCH_COMBINATOR_FUNCTION (binlog_chat_add_participant)
FETCH_COMBINATOR_FUNCTION (binlog_chat_del_participant)
FETCH_COMBINATOR_FUNCTION (binlog_create_message_text)
FETCH_COMBINATOR_FUNCTION (binlog_send_message_text)
FETCH_COMBINATOR_FUNCTION (binlog_send_message_action_encr)
FETCH_COMBINATOR_FUNCTION (binlog_create_message_text_fwd)
FETCH_COMBINATOR_FUNCTION (binlog_create_message_media)
FETCH_COMBINATOR_FUNCTION (binlog_create_message_media_encr)
FETCH_COMBINATOR_FUNCTION (binlog_create_message_media_encr_pending)
FETCH_COMBINATOR_FUNCTION (binlog_create_message_media_encr_sent)
FETCH_COMBINATOR_FUNCTION (binlog_create_message_media_fwd)
FETCH_COMBINATOR_FUNCTION (binlog_create_message_service)
FETCH_COMBINATOR_FUNCTION (binlog_create_message_service_encr)
FETCH_COMBINATOR_FUNCTION (binlog_create_message_service_fwd)
FETCH_COMBINATOR_FUNCTION (binlog_message_set_unread)
FETCH_COMBINATOR_FUNCTION (binlog_message_set_unread_long)
FETCH_COMBINATOR_FUNCTION (binlog_set_message_sent)
FETCH_COMBINATOR_FUNCTION (binlog_set_msg_id)
FETCH_COMBINATOR_FUNCTION (binlog_delete_msg)
FETCH_COMBINATOR_FUNCTION (binlog_msg_seq_update)
FETCH_COMBINATOR_FUNCTION (binlog_msg_update)
FETCH_COMBINATOR_FUNCTION (binlog_reset_authorization)
default:
vlogprintf (E_ERROR, "Unknown op 0x%08x\n", op);
assert (0);
}
assert (ok >= 0);
assert (in_ptr == in_end);
binlog_pos += (in_ptr - rptr) * 4;
rptr = in_ptr;
}
static void create_new_binlog (struct tgl_state *TLS) {
clear_packet ();
//static int s[1000];
//packet_ptr = s;
out_int (CODE_binlog_start);
if (TLS->test_mode) {
out_int (CODE_binlog_dc_option);
out_int (1);
out_string ("");
out_string (TG_SERVER_TEST_1);
out_int (443);
out_int (CODE_binlog_dc_option);
out_int (2);
out_string ("");
out_string (TG_SERVER_TEST_2);
out_int (443);
out_int (CODE_binlog_dc_option);
out_int (3);
out_string ("");
out_string (TG_SERVER_TEST_3);
out_int (443);
out_int (CODE_binlog_default_dc);
out_int (2);
} else {
out_int (CODE_binlog_dc_option);
out_int (1);
out_string ("");
out_string (TG_SERVER_1);
out_int (443);
out_int (CODE_binlog_dc_option);
out_int (2);
out_string ("");
out_string (TG_SERVER_2);
out_int (443);
out_int (CODE_binlog_dc_option);
out_int (3);
out_string ("");
out_string (TG_SERVER_3);
out_int (443);
out_int (CODE_binlog_dc_option);
out_int (4);
out_string ("");
out_string (TG_SERVER_4);
out_int (443);
out_int (CODE_binlog_dc_option);
out_int (5);
out_string ("");
out_string (TG_SERVER_5);
out_int (443);
out_int (CODE_binlog_default_dc);
out_int (2);
}
int fd = open (TLS->binlog_name, O_WRONLY | O_EXCL | O_CREAT, 0600);
if (fd < 0) {
perror ("Write new binlog");
exit (2);
}
assert (write (fd, packet_buffer, (packet_ptr - packet_buffer) * 4) == (packet_ptr - packet_buffer) * 4);
close (fd);
}
void tgl_replay_log (struct tgl_state *TLS) {
if (!TLS->binlog_enabled) { return; }
if (access (TLS->binlog_name, F_OK) < 0) {
printf ("No binlog found. Creating new one\n");
create_new_binlog (TLS);
}
int fd = open (TLS->binlog_name, O_RDONLY);
if (fd < 0) {
perror ("binlog open");
exit (2);
}
int end = 0;
in_replay_log = 1;
while (1) {
if (!end && wptr - rptr < MAX_LOG_EVENT_SIZE / 4) {
if (wptr == rptr) {
wptr = rptr = binlog_buffer;
} else {
int x = wptr - rptr;
memcpy (binlog_buffer, rptr, 4 * x);
wptr -= (rptr - binlog_buffer);
rptr = binlog_buffer;
}
int l = (binlog_buffer + BINLOG_BUFFER_SIZE - wptr) * 4;
int k = read (fd, wptr, l);
if (k < 0) {
perror ("read binlog");
exit (2);
}
assert (!(k & 3));
if (k < l) {
end = 1;
}
wptr += (k / 4);
}
if (wptr == rptr) { break; }
replay_log_event (TLS);
}
in_replay_log = 0;
close (fd);
}
static int b_packet_buffer[PACKET_BUFFER_SIZE];
void tgl_reopen_binlog_for_writing (struct tgl_state *TLS) {
TLS->binlog_fd = open (TLS->binlog_name, O_WRONLY);
if (TLS->binlog_fd < 0) {
perror ("binlog open");
exit (2);
}
assert (lseek (TLS->binlog_fd, binlog_pos, SEEK_SET) == binlog_pos);
if (flock (TLS->binlog_fd, LOCK_EX | LOCK_NB) < 0) {
perror ("get lock");
exit (2);
}
}
static void add_log_event (struct tgl_state *TLS, const int *data, int len) {
vlogprintf (E_DEBUG, "Add log event: magic = 0x%08x, len = %d\n", data[0], len);
assert (!(len & 3));
rptr = (void *)data;
wptr = rptr + (len / 4);
int *in = in_ptr;
int *end = in_end;
replay_log_event (TLS);
if (rptr != wptr) {
vlogprintf (E_ERROR, "Unread %lld ints. Len = %d\n", (long long)(wptr - rptr), len);
assert (rptr == wptr);
}
if (TLS->binlog_enabled) {
assert (TLS->binlog_fd > 0);
assert (write (TLS->binlog_fd, data, len) == len);
}
in_ptr = in;
in_end = end;
}
void bl_do_set_auth_key_id (struct tgl_state *TLS, int num, unsigned char *buf) {
static unsigned char sha1_buffer[20];
SHA1 (buf, 256, sha1_buffer);
long long fingerprint = *(long long *)(sha1_buffer + 12);
int *ev = alloc_log_event (8 + 8 + 256);
ev[0] = CODE_binlog_auth_key;
ev[1] = num;
*(long long *)(ev + 2) = fingerprint;
memcpy (ev + 4, buf, 256);
add_log_event (TLS, ev, 8 + 8 + 256);
}
void bl_do_set_our_id (struct tgl_state *TLS, int id) {
if (TLS->our_id) {
assert (TLS->our_id == id);
return;
}
int *ev = alloc_log_event (8);
ev[0] = CODE_binlog_our_id;
ev[1] = id;
add_log_event (TLS, ev, 8);
//write_auth_file ();
}
void bl_do_user_add (struct tgl_state *TLS, int id, const char *f, int fl, const char *l, int ll, long long access_token, const char *p, int pl, int contact) {
clear_packet ();
out_int (CODE_binlog_user_add);
out_int (id);
out_cstring (f ? f : "", fl);
out_cstring (l ? l : "", ll);
out_long (access_token);
out_cstring (p ? p : "", pl);
out_int (contact);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_user_delete (struct tgl_state *TLS, struct tgl_user *U) {
if (U->flags & FLAG_DELETED) { return; }
int *ev = alloc_log_event (8);
ev[0] = CODE_binlog_user_delete;
ev[1] = tgl_get_peer_id (U->id);
add_log_event (TLS, ev, 8);
}
void bl_do_set_user_profile_photo (struct tgl_state *TLS, struct tgl_user *U, long long photo_id, struct tgl_file_location *big, struct tgl_file_location *small) {
if (photo_id == U->photo_id) { return; }
if (!photo_id) {
int *ev = alloc_log_event (12);
ev[0] = CODE_binlog_user_set_photo;
ev[1] = tgl_get_peer_id (U->id);
ev[2] = CODE_user_profile_photo_empty;
add_log_event (TLS, ev, 12);
} else {
clear_packet ();
out_int (CODE_binlog_user_set_photo);
out_int (tgl_get_peer_id (U->id));
out_int (CODE_user_profile_photo);
out_long (photo_id);
if (small->dc >= 0) {
out_int (CODE_file_location);
out_int (small->dc);
out_long (small->volume);
out_int (small->local_id);
out_long (small->secret);
} else {
out_int (CODE_file_location_unavailable);
out_long (small->volume);
out_int (small->local_id);
out_long (small->secret);
}
if (big->dc >= 0) {
out_int (CODE_file_location);
out_int (big->dc);
out_long (big->volume);
out_int (big->local_id);
out_long (big->secret);
} else {
out_int (CODE_file_location_unavailable);
out_long (big->volume);
out_int (big->local_id);
out_long (big->secret);
}
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
}
void bl_do_user_set_name (struct tgl_state *TLS, struct tgl_user *U, const char *f, int fl, const char *l, int ll) {
if ((U->first_name && (int)strlen (U->first_name) == fl && !strncmp (U->first_name, f, fl)) &&
(U->last_name && (int)strlen (U->last_name) == ll && !strncmp (U->last_name, l, ll))) {
return;
}
clear_packet ();
out_int (CODE_binlog_user_set_name);
out_int (tgl_get_peer_id (U->id));
out_cstring (f, fl);
out_cstring (l, ll);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_user_set_username (struct tgl_state *TLS, struct tgl_user *U, const char *f, int l) {
if ((U->username && (int)strlen (U->username) == l && !strncmp (U->username, f, l)) ||
(!l && !U->username)) {
return;
}
clear_packet ();
out_int (CODE_binlog_user_set_username);
out_int (tgl_get_peer_id (U->id));
out_cstring (f, l);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_user_set_access_hash (struct tgl_state *TLS, struct tgl_user *U, long long access_token) {
if (U->access_hash == access_token) { return; }
int *ev = alloc_log_event (16);
ev[0] = CODE_binlog_user_set_access_hash;
ev[1] = tgl_get_peer_id (U->id);
*(long long *)(ev + 2) = access_token;
add_log_event (TLS, ev, 16);
}
void bl_do_user_set_phone (struct tgl_state *TLS, struct tgl_user *U, const char *p, int pl) {
if (U->phone && (int)strlen (U->phone) == pl && !strncmp (U->phone, p, pl)) {
return;
}
clear_packet ();
out_int (CODE_binlog_user_set_phone);
out_int (tgl_get_peer_id (U->id));
out_cstring (p, pl);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_user_set_friend (struct tgl_state *TLS, struct tgl_user *U, int friend) {
if (friend == ((U->flags & FLAG_USER_CONTACT) != 0)) { return ; }
int *ev = alloc_log_event (12);
ev[0] = CODE_binlog_user_set_friend;
ev[1] = tgl_get_peer_id (U->id);
ev[2] = friend;
add_log_event (TLS, ev, 12);
}
void bl_do_dc_option (struct tgl_state *TLS, int id, int l1, const char *name, int l2, const char *ip, int port) {
struct tgl_dc *DC = TLS->DC_list[id];
if (DC && !strncmp (ip, DC->ip, l2)) { return; }
clear_packet ();
out_int (CODE_binlog_dc_option);
out_int (id);
out_cstring (name, l1);
out_cstring (ip, l2);
out_int (port);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_dc_signed (struct tgl_state *TLS, int id) {
int *ev = alloc_log_event (8);
ev[0] = CODE_binlog_dc_signed;
ev[1] = id;
add_log_event (TLS, ev, 8);
}
void bl_do_set_working_dc (struct tgl_state *TLS, int num) {
int *ev = alloc_log_event (8);
ev[0] = CODE_binlog_default_dc;
ev[1] = num;
add_log_event (TLS, ev, 8);
}
void bl_do_user_set_full_photo (struct tgl_state *TLS, struct tgl_user *U, const int *start, int len) {
if (U->photo.id == *(long long *)(start + 1)) { return; }
int *ev = alloc_log_event (len + 8);
ev[0] = CODE_binlog_user_set_full_photo;
ev[1] = tgl_get_peer_id (U->id);
memcpy (ev + 2, start, len);
add_log_event (TLS, ev, len + 8);
}
void bl_do_user_set_blocked (struct tgl_state *TLS, struct tgl_user *U, int blocked) {
if (U->blocked == blocked) { return; }
int *ev = alloc_log_event (12);
ev[0] = CODE_binlog_user_set_blocked;
ev[1] = tgl_get_peer_id (U->id);
ev[2] = blocked;
add_log_event (TLS, ev, 12);
}
void bl_do_user_set_real_name (struct tgl_state *TLS, struct tgl_user *U, const char *f, int fl, const char *l, int ll) {
if ((U->real_first_name && (int)strlen (U->real_first_name) == fl && !strncmp (U->real_first_name, f, fl)) &&
(U->real_last_name && (int)strlen (U->real_last_name) == ll && !strncmp (U->real_last_name, l, ll))) {
return;
}
clear_packet ();
out_int (CODE_binlog_user_set_real_name);
out_int (tgl_get_peer_id (U->id));
out_cstring (f, fl);
out_cstring (l, ll);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_encr_chat_delete (struct tgl_state *TLS, struct tgl_secret_chat *U) {
if (!(U->flags & FLAG_CREATED) || U->state == sc_deleted || U->state == sc_none) { return; }
int *ev = alloc_log_event (8);
ev[0] = CODE_binlog_encr_chat_delete;
ev[1] = tgl_get_peer_id (U->id);
add_log_event (TLS, ev, 8);
}
void bl_do_encr_chat_requested (struct tgl_state *TLS, struct tgl_secret_chat *U, long long access_hash, int date, int admin_id, int user_id, unsigned char g_key[], unsigned char nonce[]) {
if (U->state != sc_none) { return; }
int *ev = alloc_log_event (540);
ev[0] = CODE_binlog_encr_chat_requested;
ev[1] = tgl_get_peer_id (U->id);
*(long long *)(ev + 2) = access_hash;
ev[4] = date;
ev[5] = admin_id;
ev[6] = user_id;
memcpy (ev + 7, g_key, 256);
memcpy (ev + 7 + 64, nonce, 256);
add_log_event (TLS, ev, 540);
}
void bl_do_encr_chat_set_access_hash (struct tgl_state *TLS, struct tgl_secret_chat *U, long long access_hash) {
if (U->access_hash == access_hash) { return; }
int *ev = alloc_log_event (16);
ev[0] = CODE_binlog_encr_chat_set_access_hash;
ev[1] = tgl_get_peer_id (U->id);
*(long long *)(ev + 2) = access_hash;
add_log_event (TLS, ev, 16);
}
void bl_do_encr_chat_set_date (struct tgl_state *TLS, struct tgl_secret_chat *U, int date) {
if (U->date == date) { return; }
int *ev = alloc_log_event (12);
ev[0] = CODE_binlog_encr_chat_set_date;
ev[1] = tgl_get_peer_id (U->id);
ev[2] = date;
add_log_event (TLS, ev, 12);
}
void bl_do_encr_chat_set_ttl (struct tgl_state *TLS, struct tgl_secret_chat *U, int ttl) {
if (U->ttl == ttl) { return; }
int *ev = alloc_log_event (12);
ev[0] = CODE_binlog_encr_chat_set_ttl;
ev[1] = tgl_get_peer_id (U->id);
ev[2] = ttl;
add_log_event (TLS, ev, 12);
}
void bl_do_encr_chat_set_layer (struct tgl_state *TLS, struct tgl_secret_chat *U, int layer) {
if (U->layer >= layer) { return; }
int *ev = alloc_log_event (12);
ev[0] = CODE_binlog_encr_chat_set_layer;
ev[1] = tgl_get_peer_id (U->id);
ev[2] = layer;
add_log_event (TLS, ev, 12);
}
void bl_do_encr_chat_set_state (struct tgl_state *TLS, struct tgl_secret_chat *U, enum tgl_secret_chat_state state) {
if (U->state == state) { return; }
int *ev = alloc_log_event (12);
ev[0] = CODE_binlog_encr_chat_set_state;
ev[1] = tgl_get_peer_id (U->id);
ev[2] = state;
add_log_event (TLS, ev, 12);
}
void bl_do_encr_chat_accepted (struct tgl_state *TLS, struct tgl_secret_chat *U, const unsigned char g_key[], const unsigned char nonce[], long long key_fingerprint) {
if (U->state != sc_waiting && U->state != sc_request) { return; }
int *ev = alloc_log_event (528);
ev[0] = CODE_binlog_encr_chat_accepted;
ev[1] = tgl_get_peer_id (U->id);
memcpy (ev + 2, g_key, 256);
memcpy (ev + 66, nonce, 256);
*(long long *)(ev + 130) = key_fingerprint;
add_log_event (TLS, ev, 528);
}
void bl_do_encr_chat_create (struct tgl_state *TLS, int id, int user_id, int admin_id, char *name, int name_len) {
clear_packet ();
out_int (CODE_binlog_encr_chat_create);
out_int (id);
out_int (user_id);
out_int (admin_id);
out_cstring (name, name_len);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_encr_chat_set_key (struct tgl_state *TLS, struct tgl_secret_chat *E, unsigned char key[], long long key_fingerprint) {
int *ev = alloc_log_event (272);
ev[0] = CODE_binlog_encr_chat_set_key;
ev[1] = tgl_get_peer_id (E->id);
memcpy (ev + 2, key, 256);
*(long long *)(ev + 66) = key_fingerprint;
add_log_event (TLS, ev, 272);
}
void bl_do_encr_chat_update_seq (struct tgl_state *TLS, struct tgl_secret_chat *E, int in_seq_no, int out_seq_no) {
int *ev = alloc_log_event (16);
ev[0] = CODE_binlog_encr_chat_update_seq;
ev[1] = tgl_get_peer_id (E->id);
ev[2] = in_seq_no;
ev[3] = out_seq_no;
add_log_event (TLS, ev, 16);
}
void bl_do_encr_chat_set_seq (struct tgl_state *TLS, struct tgl_secret_chat *E, int in_seq_no, int last_in_seq_no, int out_seq_no) {
int *ev = alloc_log_event (20);
ev[0] = CODE_binlog_encr_chat_set_seq;
ev[1] = tgl_get_peer_id (E->id);
ev[2] = in_seq_no;
ev[3] = last_in_seq_no;
ev[4] = out_seq_no;
add_log_event (TLS, ev, 20);
}
void bl_do_set_dh_params (struct tgl_state *TLS, int root, unsigned char prime[], int version) {
int *ev = alloc_log_event (268);
ev[0] = CODE_binlog_set_dh_params;
ev[1] = root;
memcpy (ev + 2, prime, 256);
ev[66] = version;
add_log_event (TLS, ev, 268);
}
void bl_do_encr_chat_init (struct tgl_state *TLS, int id, int user_id, unsigned char random[], unsigned char g_a[]) {
int *ev = alloc_log_event (524);
ev[0] = CODE_binlog_encr_chat_init;
ev[1] = id;
ev[2] = user_id;
memcpy (ev + 3, random, 256);
memcpy (ev + 67, g_a, 256);
add_log_event (TLS, ev, 524);
}
void bl_do_set_pts (struct tgl_state *TLS, int pts) {
if (TLS->locks & TGL_LOCK_DIFF) { return; }
if (pts <= TLS->pts) { return; }
int *ev = alloc_log_event (8);
ev[0] = CODE_binlog_set_pts;
ev[1] = pts;
add_log_event (TLS, ev, 8);
}
void bl_do_set_qts (struct tgl_state *TLS, int qts) {
if (TLS->locks & TGL_LOCK_DIFF) { return; }
if (qts <= TLS->qts) { return; }
int *ev = alloc_log_event (8);
ev[0] = CODE_binlog_set_qts;
ev[1] = qts;
add_log_event (TLS, ev, 8);
}
void bl_do_set_date (struct tgl_state *TLS, int date) {
if (TLS->locks & TGL_LOCK_DIFF) { return; }
if (date <= TLS->date) { return; }
int *ev = alloc_log_event (8);
ev[0] = CODE_binlog_set_date;
ev[1] = date;
add_log_event (TLS, ev, 8);
}
void bl_do_set_seq (struct tgl_state *TLS, int seq) {
if (TLS->locks & TGL_LOCK_DIFF) { return; }
if (seq == TLS->seq) { return; }
int *ev = alloc_log_event (8);
ev[0] = CODE_binlog_set_seq;
ev[1] = seq;
add_log_event (TLS, ev, 8);
}
void bl_do_create_chat (struct tgl_state *TLS, struct tgl_chat *C, int y, const char *s, int l, int users_num, int date, int version, struct tgl_file_location *big, struct tgl_file_location *small) {
clear_packet ();
out_int (CODE_binlog_chat_create);
out_int (tgl_get_peer_id (C->id));
out_int (y);
out_cstring (s, l);
out_int (users_num);
out_int (date);
out_int (version);
out_data (big, sizeof (struct tgl_file_location));
out_data (small, sizeof (struct tgl_file_location));
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_chat_forbid (struct tgl_state *TLS, struct tgl_chat *C, int on) {
if (on) {
if (C->flags & FLAG_FORBIDDEN) { return; }
int *ev = alloc_log_event (16);
ev[0] = CODE_binlog_chat_change_flags;
ev[1] = tgl_get_peer_id (C->id);
ev[2] = FLAG_FORBIDDEN;
ev[3] = 0;
add_log_event (TLS, ev, 16);
} else {
if (!(C->flags & FLAG_FORBIDDEN)) { return; }
int *ev = alloc_log_event (16);
ev[0] = CODE_binlog_chat_change_flags;
ev[1] = tgl_get_peer_id (C->id);
ev[2] = 0;
ev[3] = FLAG_FORBIDDEN;
add_log_event (TLS, ev, 16);
}
}
void bl_do_chat_set_title (struct tgl_state *TLS, struct tgl_chat *C, const char *s, int l) {
if (C->title && (int)strlen (C->title) == l && !strncmp (C->title, s, l)) { return; }
clear_packet ();
out_int (CODE_binlog_chat_set_title);
out_int (tgl_get_peer_id (C->id));
out_cstring (s, l);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_chat_set_photo (struct tgl_state *TLS, struct tgl_chat *C, struct tgl_file_location *big, struct tgl_file_location *small) {
if (!memcmp (&C->photo_small, small, sizeof (struct tgl_file_location)) &&
!memcmp (&C->photo_big, big, sizeof (struct tgl_file_location))) { return; }
clear_packet ();
out_int (CODE_binlog_chat_set_photo);
out_int (tgl_get_peer_id (C->id));
out_data (big, sizeof (struct tgl_file_location));
out_data (small, sizeof (struct tgl_file_location));
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_chat_set_date (struct tgl_state *TLS, struct tgl_chat *C, int date) {
if (C->date == date) { return; }
int *ev = alloc_log_event (12);
ev[0] = CODE_binlog_chat_set_date;
ev[1] = tgl_get_peer_id (C->id);
ev[2] = date;
add_log_event (TLS, ev, 12);
}
void bl_do_chat_set_set_in_chat (struct tgl_state *TLS, struct tgl_chat *C, int on) {
if (on) {
if (C->flags & FLAG_CHAT_IN_CHAT) { return; }
int *ev = alloc_log_event (16);
ev[0] = CODE_binlog_chat_change_flags;
ev[1] = tgl_get_peer_id (C->id);
ev[2] = FLAG_CHAT_IN_CHAT;
ev[3] = 0;
add_log_event (TLS, ev, 16);
} else {
if (!(C->flags & FLAG_CHAT_IN_CHAT)) { return; }
int *ev = alloc_log_event (16);
ev[0] = CODE_binlog_chat_change_flags;
ev[1] = tgl_get_peer_id (C->id);
ev[2] = 0;
ev[3] = FLAG_CHAT_IN_CHAT;
add_log_event (TLS, ev, 16);
}
}
void bl_do_chat_set_version (struct tgl_state *TLS, struct tgl_chat *C, int version, int user_num) {
if (C->version >= version) { return; }
int *ev = alloc_log_event (16);
ev[0] = CODE_binlog_chat_set_version;
ev[1] = tgl_get_peer_id (C->id);
ev[2] = version;
ev[3] = user_num;
add_log_event (TLS, ev, 16);
}
void bl_do_chat_set_admin (struct tgl_state *TLS, struct tgl_chat *C, int admin) {
if (C->admin_id == admin) { return; }
int *ev = alloc_log_event (12);
ev[0] = CODE_binlog_chat_set_admin;
ev[1] = tgl_get_peer_id (C->id);
ev[2] = admin;
add_log_event (TLS, ev, 12);
}
void bl_do_chat_set_participants (struct tgl_state *TLS, struct tgl_chat *C, int version, int user_num, struct tgl_chat_user *users) {
if (C->user_list_version >= version) { return; }
int *ev = alloc_log_event (12 * user_num + 16);
ev[0] = CODE_binlog_chat_set_participants;
ev[1] = tgl_get_peer_id (C->id);
ev[2] = version;
ev[3] = user_num;
memcpy (ev + 4, users, 12 * user_num);
add_log_event (TLS, ev, 12 * user_num + 16);
}
void bl_do_chat_set_full_photo (struct tgl_state *TLS, struct tgl_chat *U, const int *start, int len) {
if (U->photo.id == *(long long *)(start + 1)) { return; }
int *ev = alloc_log_event (len + 8);
ev[0] = CODE_binlog_chat_set_full_photo;
ev[1] = tgl_get_peer_id (U->id);
memcpy (ev + 2, start, len);
add_log_event (TLS, ev, len + 8);
}
void bl_do_chat_add_user (struct tgl_state *TLS, struct tgl_chat *C, int version, int user, int inviter, int date) {
if (C->user_list_version >= version || !C->user_list_version) { return; }
int *ev = alloc_log_event (24);
ev[0] = CODE_binlog_chat_add_participant;
ev[1] = tgl_get_peer_id (C->id);
ev[2] = version;
ev[3] = user;
ev[4] = inviter;
ev[5] = date;
add_log_event (TLS, ev, 24);
}
void bl_do_chat_del_user (struct tgl_state *TLS, struct tgl_chat *C, int version, int user) {
if (C->user_list_version >= version || !C->user_list_version) { return; }
int *ev = alloc_log_event (16);
ev[0] = CODE_binlog_chat_del_participant;
ev[1] = tgl_get_peer_id (C->id);
ev[2] = version;
ev[3] = user;
add_log_event (TLS, ev, 16);
}
void bl_do_create_message_text (struct tgl_state *TLS, int msg_id, int from_id, int to_type, int to_id, int date, int unread, int l, const char *s) {
clear_packet ();
out_int (CODE_binlog_create_message_text);
out_int (msg_id);
out_int (from_id);
out_int (to_type);
out_int (to_id);
out_int (date);
out_int (unread);
out_cstring (s, l);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_send_message_text (struct tgl_state *TLS, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s) {
clear_packet ();
out_int (CODE_binlog_send_message_text);
out_long (msg_id);
out_int (from_id);
out_int (to_type);
out_int (to_id);
out_int (date);
out_cstring (s, l);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_send_message_action_encr (struct tgl_state *TLS, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const int *action) {
clear_packet ();
out_int (CODE_binlog_send_message_action_encr);
out_long (msg_id);
out_int (from_id);
out_int (to_type);
out_int (to_id);
out_int (date);
out_ints (action, l);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_create_message_text_fwd (struct tgl_state *TLS, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int unread, int l, const char *s) {
clear_packet ();
out_int (CODE_binlog_create_message_text_fwd);
out_int (msg_id);
out_int (from_id);
out_int (to_type);
out_int (to_id);
out_int (date);
out_int (fwd);
out_int (fwd_date);
out_int (unread);
out_cstring (s, l);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_create_message_media (struct tgl_state *TLS, int msg_id, int from_id, int to_type, int to_id, int date, int unread, int l, const char *s, const int *data, int len) {
clear_packet ();
out_int (CODE_binlog_create_message_media);
out_int (msg_id);
out_int (from_id);
out_int (to_type);
out_int (to_id);
out_int (date);
out_int (unread);
out_cstring (s, l);
out_ints (data, len);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_create_message_media_encr (struct tgl_state *TLS, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len, const int *data2, int len2) {
clear_packet ();
out_int (CODE_binlog_create_message_media_encr);
out_long (msg_id);
out_int (from_id);
out_int (to_type);
out_int (to_id);
out_int (date);
out_cstring (s, l);
out_ints (data, len);
out_ints (data2, len2);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_create_message_media_encr_pending (struct tgl_state *TLS, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len) {
int *s_packet_buffer = packet_buffer;
int *s_packet_ptr = packet_ptr;
packet_buffer = b_packet_buffer;
clear_packet ();
out_int (CODE_binlog_create_message_media_encr_pending);
out_long (msg_id);
out_int (from_id);
out_int (to_type);
out_int (to_id);
out_int (date);
out_cstring (s, l);
out_ints (data, len);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
packet_buffer = s_packet_buffer;
packet_ptr = s_packet_ptr;
}
void bl_do_create_message_media_encr_sent (struct tgl_state *TLS, long long msg_id, const int *data, int len) {
clear_packet ();
out_int (CODE_binlog_create_message_media_encr_sent);
out_long (msg_id);
out_ints (data, len);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_create_message_media_fwd (struct tgl_state *TLS, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int unread, int l, const char *s, const int *data, int len) {
clear_packet ();
out_int (CODE_binlog_create_message_media_fwd);
out_int (msg_id);
out_int (from_id);
out_int (to_type);
out_int (to_id);
out_int (date);
out_int (fwd);
out_int (fwd_date);
out_int (unread);
out_cstring (s, l);
out_ints (data, len);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_create_message_service (struct tgl_state *TLS, int msg_id, int from_id, int to_type, int to_id, int date, int unread, const int *data, int len) {
clear_packet ();
out_int (CODE_binlog_create_message_service);
out_int (msg_id);
out_int (from_id);
out_int (to_type);
out_int (to_id);
out_int (date);
out_int (unread);
out_ints (data, len);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_create_message_service_encr (struct tgl_state *TLS, long long msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len) {
clear_packet ();
out_int (CODE_binlog_create_message_service_encr);
out_long (msg_id);
out_int (from_id);
out_int (to_type);
out_int (to_id);
out_int (date);
out_ints (data, len);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_create_message_service_fwd (struct tgl_state *TLS, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int unread, const int *data, int len) {
clear_packet ();
out_int (CODE_binlog_create_message_service_fwd);
out_int (msg_id);
out_int (from_id);
out_int (to_type);
out_int (to_id);
out_int (date);
out_int (fwd);
out_int (fwd_date);
out_int (unread);
out_ints (data, len);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_set_unread_long (struct tgl_state *TLS, struct tgl_message *M, int unread) {
if (unread || !M->unread) { return; }
clear_packet ();
out_int (CODE_binlog_message_set_unread_long);
out_long (M->id);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_set_unread (struct tgl_state *TLS, struct tgl_message *M, int unread) {
if (M->id != (int)M->id) { bl_do_set_unread_long (TLS, M, unread); }
if (unread || !M->unread) { return; }
clear_packet ();
out_int (CODE_binlog_message_set_unread);
out_int (M->id);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_set_message_sent (struct tgl_state *TLS, struct tgl_message *M) {
if (!(M->flags & FLAG_PENDING)) { return; }
clear_packet ();
out_int (CODE_binlog_set_message_sent);
out_long (M->id);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_set_msg_id (struct tgl_state *TLS, struct tgl_message *M, int id) {
if (M->id == id) { return; }
clear_packet ();
out_int (CODE_binlog_set_msg_id);
out_long (M->id);
out_int (id);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_delete_msg (struct tgl_state *TLS, struct tgl_message *M) {
clear_packet ();
out_int (CODE_binlog_delete_msg);
out_long (M->id);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_msg_seq_update (struct tgl_state *TLS, long long id) {
if (TLS->locks & TGL_LOCK_DIFF) {
return; // We will receive this update in get_difference, that works now
}
clear_packet ();
out_int (CODE_binlog_msg_seq_update);
out_long (id);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_msg_update (struct tgl_state *TLS, long long id) {
clear_packet ();
out_int (CODE_binlog_msg_update);
out_long (id);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
void bl_do_reset_authorization (struct tgl_state *TLS) {
clear_packet ();
out_int (CODE_binlog_reset_authorization);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}
/*void bl_do_add_dc (int id, const char *ip, int l, int port, long long auth_key_id, const char *auth_key) {
clear_packet ();
out_int (CODE_binlog_add_dc);
out_long (id);
out_cstring (ip, l);
out_int (port);
out_long (auth_key_id);
out_ints ((void *)auth_key, 64);
add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}*/
/*
This file is part of tgl-library
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Copyright Vitaly Valtman 2013-2014
*/
#ifndef __BINLOG_H__
#define __BINLOG_H__
//#include "structures.h"
#include "tgl.h"
void bl_do_set_auth_key_id (struct tgl_state *TLS, int num, unsigned char *buf);
void bl_do_dc_option (struct tgl_state *TLS, int id, int l1, const char *name, int l2, const char *ip, int port);
void bl_do_set_our_id (struct tgl_state *TLS, int id);
void bl_do_user_add (struct tgl_state *TLS, int id, const char *f, int fl, const char *l, int ll, long long access_token, const char *p, int pl, int contact);
void bl_do_user_delete (struct tgl_state *TLS, struct tgl_user *U);
void bl_do_set_user_profile_photo (struct tgl_state *TLS, struct tgl_user *U, long long photo_id, struct tgl_file_location *big, struct tgl_file_location *small);
void bl_do_user_set_name (struct tgl_state *TLS, struct tgl_user *U, const char *f, int fl, const char *l, int ll);
void bl_do_user_set_username (struct tgl_state *TLS, struct tgl_user *U, const char *f, int l);
void bl_do_user_set_access_hash (struct tgl_state *TLS, struct tgl_user *U, long long access_token);
void bl_do_user_set_phone (struct tgl_state *TLS, struct tgl_user *U, const char *p, int pl);
void bl_do_user_set_friend (struct tgl_state *TLS, struct tgl_user *U, int friend);
void bl_do_user_set_full_photo (struct tgl_state *TLS, struct tgl_user *U, const int *start, int len);
void bl_do_user_set_blocked (struct tgl_state *TLS, struct tgl_user *U, int blocked);
void bl_do_user_set_real_name (struct tgl_state *TLS, struct tgl_user *U, const char *f, int fl, const char *l, int ll);
void bl_do_encr_chat_delete (struct tgl_state *TLS, struct tgl_secret_chat *U);
void bl_do_encr_chat_requested (struct tgl_state *TLS, struct tgl_secret_chat *U, long long access_hash, int date, int admin_id, int user_id, unsigned char g_key[], unsigned char nonce[]);
void bl_do_encr_chat_create (struct tgl_state *TLS, int id, int user_id, int admin_id, char *name, int name_len);
void bl_do_encr_chat_set_access_hash (struct tgl_state *TLS, struct tgl_secret_chat *U, long long access_hash);
void bl_do_encr_chat_set_date (struct tgl_state *TLS, struct tgl_secret_chat *U, int date);
void bl_do_encr_chat_set_state (struct tgl_state *TLS, struct tgl_secret_chat *U, enum tgl_secret_chat_state state);
void bl_do_encr_chat_set_ttl (struct tgl_state *TLS, struct tgl_secret_chat *U, int ttl);
void bl_do_encr_chat_set_layer (struct tgl_state *TLS, struct tgl_secret_chat *U, int layer);
void bl_do_encr_chat_accepted (struct tgl_state *TLS, struct tgl_secret_chat *U, const unsigned char g_key[], const unsigned char nonce[], long long key_fingerprint);
void bl_do_encr_chat_set_key (struct tgl_state *TLS, struct tgl_secret_chat *E, unsigned char key[], long long key_fingerprint);
void bl_do_encr_chat_init (struct tgl_state *TLS, int id, int user_id, unsigned char random[], unsigned char g_a[]);
void bl_do_encr_chat_update_seq (struct tgl_state *TLS, struct tgl_secret_chat *E, int in_seq_no, int out_seq_no);
void bl_do_encr_chat_set_seq (struct tgl_state *TLS, struct tgl_secret_chat *E, int in_seq_no, int last_in_seq_no, int out_seq_no);
void bl_do_dc_signed (struct tgl_state *TLS, int id);
void bl_do_set_working_dc (struct tgl_state *TLS, int num);
void bl_do_set_dh_params (struct tgl_state *TLS, int root, unsigned char prime[], int version);
void bl_do_set_pts (struct tgl_state *TLS, int pts);
void bl_do_set_qts (struct tgl_state *TLS, int qts);
void bl_do_set_seq (struct tgl_state *TLS, int seq);
void bl_do_set_date (struct tgl_state *TLS, int date);
void bl_do_create_chat (struct tgl_state *TLS, struct tgl_chat *C, int y, const char *s, int l, int users_num, int date, int version, struct tgl_file_location *big, struct tgl_file_location *small);
void bl_do_chat_forbid (struct tgl_state *TLS, struct tgl_chat *C, int on);
void bl_do_chat_set_title (struct tgl_state *TLS, struct tgl_chat *C, const char *s, int l);
void bl_do_chat_set_photo (struct tgl_state *TLS, struct tgl_chat *C, struct tgl_file_location *big, struct tgl_file_location *small);
void bl_do_chat_set_date (struct tgl_state *TLS, struct tgl_chat *C, int date);
void bl_do_chat_set_set_in_chat (struct tgl_state *TLS, struct tgl_chat *C, int on);
void bl_do_chat_set_version (struct tgl_state *TLS, struct tgl_chat *C, int version, int user_num);
void bl_do_chat_set_admin (struct tgl_state *TLS, struct tgl_chat *C, int admin);
void bl_do_chat_set_participants (struct tgl_state *TLS, struct tgl_chat *C, int version, int user_num, struct tgl_chat_user *users);
void bl_do_chat_set_full_photo (struct tgl_state *TLS, struct tgl_chat *U, const int *start, int len);
void bl_do_chat_add_user (struct tgl_state *TLS, struct tgl_chat *C, int version, int user, int inviter, int date);
void bl_do_chat_del_user (struct tgl_state *TLS, struct tgl_chat *C, int version, int user);
void bl_do_create_message_text (struct tgl_state *TLS, int msg_id, int from_id, int to_type, int to_id, int date, int unread, int l, const char *s);
void bl_do_create_message_text_fwd (struct tgl_state *TLS, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int unread, int l, const char *s);
void bl_do_create_message_service (struct tgl_state *TLS, int msg_id, int from_id, int to_type, int to_id, int date, int unread, const int *data, int len);
void bl_do_create_message_service_fwd (struct tgl_state *TLS, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int unread, const int *data, int len);
void bl_do_create_message_media (struct tgl_state *TLS, int msg_id, int from_id, int to_type, int to_id, int date, int unread, int l, const char *s, const int *data, int len);
void bl_do_create_message_media_encr_pending (struct tgl_state *TLS, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len);
void bl_do_create_message_media_encr_sent (struct tgl_state *TLS, long long msg_id, const int *data, int len);
void bl_do_create_message_media_fwd (struct tgl_state *TLS, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int unread, int l, const char *s, const int *data, int len);
void bl_do_create_message_media_encr (struct tgl_state *TLS, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len, const int *data2, int len2);
void bl_do_create_message_service_encr (struct tgl_state *TLS, long long msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len);
void bl_do_send_message_text (struct tgl_state *TLS, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s);
void bl_do_send_message_action_encr (struct tgl_state *TLS, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const int *s);
void bl_do_set_unread (struct tgl_state *TLS, struct tgl_message *M, int unread);
void bl_do_set_message_sent (struct tgl_state *TLS, struct tgl_message *M);
void bl_do_set_msg_id (struct tgl_state *TLS, struct tgl_message *M, int id);
void bl_do_delete_msg (struct tgl_state *TLS, struct tgl_message *M);
void bl_do_msg_seq_update (struct tgl_state *TLS, long long id);
void bl_do_msg_update (struct tgl_state *TLS, long long id);
void bl_do_reset_authorization (struct tgl_state *TLS);
//void bl_do_add_dc (int id, const char *ip, int l, int port, long long auth_key_id, const char *auth_key);
#endif
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdarg.h>
#include <fcntl.h>
#include <assert.h>
#include <string.h>
#include "auto.h"
int *tgl_in_ptr, *tgl_in_end;
int tgl_packet_buffer[0];
int *tgl_packet_ptr;
char *tgl_strdup (char *s) {
return strdup (s);
}
void tgl_out_cstring (const char *str, long len) {}
char *tglf_extf_fetch (struct paramed_type *T);
#define LEN (1 << 28)
static int x[LEN / 4];
int main (int argc, char **argv) {
int i;
int dump_binlog = 0;
while ((i = getopt (argc, argv, "b")) != -1) {
switch (i) {
case 'b':
dump_binlog = 1;
break;
default:
printf ("unknown option '%c'\n", (char)i);
exit (1);
}
}
if (!dump_binlog) {
exit (1);
}
if (optind + 1 != argc) {
exit (1);
}
int fd = open (argv[optind], O_RDONLY);
if (fd < 0) {
perror ("open");
exit (1);
}
int r = read (fd, x, LEN);
if (r <= 0) {
perror ("read");
exit (1);
}
if (r == LEN) {
printf ("Too long file\n");
exit (1);
}
assert (!(r & 3));
tgl_in_ptr = x;
tgl_in_end = x + (r / 4);
while (tgl_in_ptr < tgl_in_end) {
if (dump_binlog) {
char *R = tglf_extf_fetch (TYPE_TO_PARAM(binlog_update));
if (!R) {
printf ("Can not fetch\n");
exit (1);
}
printf ("%s\n", R);
}
}
return 0;
}
/*
This file is part of tgl-libary/tlc
Tgl-library/tlc is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Tgl-library/tlc is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this tgl-library/tlc. If not, see <http://www.gnu.org/licenses/>.
Copyright Vitaly Valtman 2014
It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/)
Copyright 2012-2013 Vkontakte Ltd
2012-2013 Vitaliy Valtman
*/
#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include "tree.h"
#include "tl-parser.h"
#include "crc32.h"
#include "tl-tl.h"
#include "tools.h"
#include "config.h"
extern int verbosity;
extern int schema_version;
extern int output_expressions;
int total_types_num;
int total_constructors_num;
int total_functions_num;
/*char *tstrdup (const char *s) {
assert (s);
char *r = talloc (strlen (s) + 1);
memcpy (r, s, strlen (s) + 1);
return r;
}*/
char curch;
struct parse parse;
struct tree *tree;
struct tree *tree_alloc (void) {
struct tree *T = talloc (sizeof (*T));
assert (T);
memset (T, 0, sizeof (*T));
return T;
}
void tree_add_child (struct tree *P, struct tree *C) {
if (P->nc == P->size) {
void **t = talloc (sizeof (void *) * (++P->size));
memcpy (t, P->c, sizeof (void *) * (P->size - 1));
if (P->c) {
tfree (P->c, sizeof (void *) * (P->size - 1));
}
P->c = (void *)t;
assert (P->c);
}
P->c[P->nc ++] = C;
}
void tree_delete (struct tree *T) {
assert (T);
int i;
for (i = 0; i < T->nc; i++) {
assert (T->c[i]);
tree_delete (T->c[i]);
}
if (T->c) {
tfree (T->c, sizeof (void *) * T->nc);
}
tfree (T, sizeof (*T));
}
void tree_del_child (struct tree *P) {
assert (P->nc);
tree_delete (P->c[--P->nc]);
}
char nextch (void) {
if (parse.pos < parse.len - 1) {
curch = parse.text[++parse.pos];
} else {
curch = 0;
}
if (curch == 10) {
parse.line ++;
parse.line_pos = 0;
} else {
if (curch) {
parse.line_pos ++;
}
}
return curch;
}
struct parse save_parse (void) {
return parse;
}
void load_parse (struct parse _parse) {
parse = _parse;
curch = parse.pos > parse.len ? 0: parse.text[parse.pos] ;
}
int is_whitespace (char c) {
return (c <= 32);
}
int is_uletter (char c) {
return (c >= 'A' && c <= 'Z');
}
int is_lletter (char c) {
return (c >= 'a' && c <= 'z');
}
int is_letter (char c) {
return is_uletter (c) || is_lletter (c);
}
int is_digit (char c) {
return (c >= '0' && c <= '9');
}
int is_hexdigit (char c) {
return is_digit (c) || (c >= 'a' && c <= 'f');
}
int is_ident_char (char c) {
return is_digit (c) || is_letter (c) || c == '_';
}
int last_error_pos;
int last_error_line;
int last_error_line_pos;
char *last_error;
void parse_error (const char *e) {
if (parse.pos > last_error_pos) {
last_error_pos = parse.pos;
last_error_line = parse.line;
last_error_line_pos = parse.line_pos;
if (last_error) {
tfree (last_error, strlen (last_error) + 1);
}
last_error = tstrdup (e);
}
}
void tl_print_parse_error (void) {
fprintf (stderr, "Error near line %d pos %d: `%s`\n", last_error_line + 1, last_error_line_pos + 1, last_error);
}
char *parse_lex (void) {
while (1) {
while (curch && is_whitespace (curch)) { nextch (); }
if (curch == '/' && nextch () == '/') {
while (nextch () != 10);
nextch ();
} else {
break;
}
}
if (!curch) {
parse.lex.len = 0;
parse.lex.type = lex_eof;
return (parse.lex.ptr = 0);
}
char *p = parse.text + parse.pos;
parse.lex.flags = 0;
switch (curch) {
case '-':
if (nextch () != '-' || nextch () != '-') {
parse_error ("Can not parse triple minus");
parse.lex.type = lex_error;
return (parse.lex.ptr = (void *)-1);
} else {
parse.lex.len = 3;
parse.lex.type = lex_triple_minus;
nextch ();
return (parse.lex.ptr = p);
}
case ':':
case ';':
case '(':
case ')':
case '[':
case ']':
case '{':
case '}':
case '=':
case '#':
case '?':
case '%':
case '<':
case '>':
case '+':
case ',':
case '*':
case '_':
case '!':
case '.':
nextch ();
parse.lex.len = 1;
parse.lex.type = lex_char;
return (parse.lex.ptr = p);
case 'a'...'z':
case 'A'...'Z':
parse.lex.flags = 0;
if (is_uletter (curch)) {
while (is_ident_char (nextch ()));
parse.lex.len = parse.text + parse.pos - p;
parse.lex.ptr = p;
if (parse.lex.len == 5 && !memcmp (parse.lex.ptr, "Final", 5)) {
parse.lex.type = lex_final;
} else if (parse.lex.len == 3 && !memcmp (parse.lex.ptr, "New", 3)) {
parse.lex.type = lex_new;
} else if (parse.lex.len == 5 && !memcmp (parse.lex.ptr, "Empty", 5)) {
parse.lex.type = lex_empty;
} else {
parse.lex.type = lex_uc_ident;
}
return (parse.lex.ptr = p);
}
while (is_ident_char (nextch ()));
if (curch == '.' && !is_letter (parse.text[parse.pos + 1])) {
parse.lex.len = parse.text + parse.pos - p;
parse.lex.type = lex_lc_ident;
return (parse.lex.ptr = p);
}
if (curch == '.') {
parse.lex.flags |= 1;
nextch ();
if (is_uletter (curch)) {
while (is_ident_char (nextch ()));
parse.lex.len = parse.text + parse.pos - p;
parse.lex.type = lex_uc_ident;
return (parse.lex.ptr = p);
}
if (is_lletter (curch)) {
while (is_ident_char (nextch ()));
} else {
parse_error ("Expected letter");
parse.lex.type = lex_error;
return (parse.lex.ptr = (void *)-1);
}
}
if (curch == '#') {
parse.lex.flags |= 2;
int i;
int ok = 1;
for (i = 0; i < 8; i++) {
if (!is_hexdigit (nextch())) {
if (curch == ' ' && i >= 5) {
ok = 2;
break;
} else {
parse_error ("Hex digit expected");
parse.lex.type = lex_error;
return (parse.lex.ptr = (void *)-1);
}
}
}
if (ok == 1) {
nextch ();
}
}
parse.lex.len = parse.text + parse.pos - p;
parse.lex.type = lex_lc_ident;
return (parse.lex.ptr = p);
case '0'...'9':
while (is_digit (nextch ()));
parse.lex.len = parse.text + parse.pos - p;
parse.lex.type = lex_num;
return (parse.lex.ptr = p);
default:
parse_error ("Unknown lexem");
parse.lex.type = lex_error;
return (parse.lex.ptr = (void *)-1);
}
}
int expect (char *s) {
if (!parse.lex.ptr || parse.lex.ptr == (void *)-1 || parse.lex.type == lex_error || parse.lex.type == lex_none || parse.lex.len != (int)strlen (s) || memcmp (s, parse.lex.ptr, parse.lex.len)) {
static char buf[1000];
sprintf (buf, "Expected %s", s);
parse_error (buf);
return -1;
} else {
parse_lex ();
}
return 1;
}
struct parse *tl_init_parse_file (const char *fname) {
int fd = open (fname, O_RDONLY);
if (fd < 0) {
fprintf (stderr, "Error %m\n");
assert (0);
return 0;
}
long long size = lseek (fd, 0, SEEK_END);
if (size <= 0) {
fprintf (stderr, "size is %lld. Too small.\n", size);
return 0;
}
static struct parse save;
save.text = talloc (size);
lseek (fd, 0, SEEK_SET);
save.len = read (fd, save.text, size);
assert (save.len == size);
save.pos = 0;
save.line = 0;
save.line_pos = 0;
save.lex.ptr = save.text;
save.lex.len = 0;
save.lex.type = lex_none;
return &save;
}
#define PARSE_INIT(_type) struct parse save = save_parse (); struct tree *T = tree_alloc (); T->type = (_type); T->lex_line = parse.line; T->lex_line_pos = parse.line_pos; struct tree *S __attribute__ ((unused));
#define PARSE_FAIL load_parse (save); tree_delete (T); return 0;
#define PARSE_OK return T;
#define PARSE_TRY_PES(x) if (!(S = x ())) { PARSE_FAIL; } { tree_add_child (T, S); }
#define PARSE_TRY_OPT(x) if ((S = x ())) { tree_add_child (T, S); PARSE_OK }
#define PARSE_TRY(x) S = x ();
#define PARSE_ADD(_type) S = tree_alloc (); S->type = _type; tree_add_child (T, S);
#define EXPECT(s) if (expect (s) < 0) { PARSE_FAIL; }
#define LEX_CHAR(c) (parse.lex.type == lex_char && *parse.lex.ptr == c)
struct tree *parse_args (void);
struct tree *parse_expr (void);
struct tree *parse_boxed_type_ident (void) {
PARSE_INIT (type_boxed_type_ident);
if (parse.lex.type != lex_uc_ident) {
parse_error ("Can not parse boxed type");
PARSE_FAIL;
} else {
T->text = parse.lex.ptr;
T->len = parse.lex.len;
T->flags = parse.lex.flags;
parse_lex ();
PARSE_OK;
}
}
struct tree *parse_full_combinator_id (void) {
PARSE_INIT (type_full_combinator_id);
if (parse.lex.type == lex_lc_ident || LEX_CHAR('_')) {
T->text = parse.lex.ptr;
T->len = parse.lex.len;
T->flags = parse.lex.flags;
parse_lex ();
PARSE_OK;
} else {
parse_error ("Can not parse full combinator id");
PARSE_FAIL;
}
}
struct tree *parse_combinator_id (void) {
PARSE_INIT (type_combinator_id);
if (parse.lex.type == lex_lc_ident && !(parse.lex.flags & 2)) {
T->text = parse.lex.ptr;
T->len = parse.lex.len;
T->flags = parse.lex.flags;
parse_lex ();
PARSE_OK;
} else {
parse_error ("Can not parse combinator id");
PARSE_FAIL;
}
}
struct tree *parse_var_ident (void) {
PARSE_INIT (type_var_ident);
if ((parse.lex.type == lex_lc_ident || parse.lex.type == lex_uc_ident) && !(parse.lex.flags & 3)) {
T->text = parse.lex.ptr;
T->len = parse.lex.len;
T->flags = parse.lex.flags;
parse_lex ();
PARSE_OK;
} else {
parse_error ("Can not parse var ident");
PARSE_FAIL;
}
}
struct tree *parse_var_ident_opt (void) {
PARSE_INIT (type_var_ident_opt);
if ((parse.lex.type == lex_lc_ident || parse.lex.type == lex_uc_ident)&& !(parse.lex.flags & 3)) {
T->text = parse.lex.ptr;
T->len = parse.lex.len;
T->flags = parse.lex.flags;
parse_lex ();
PARSE_OK;
} else if (LEX_CHAR ('_')) {
T->text = parse.lex.ptr;
T->len = parse.lex.len;
T->flags = parse.lex.flags;
parse_lex ();
PARSE_OK;
} else {
parse_error ("Can not parse var ident opt");
PARSE_FAIL;
}
}
struct tree *parse_nat_const (void) {
PARSE_INIT (type_nat_const);
if (parse.lex.type == lex_num) {
T->text = parse.lex.ptr;
T->len = parse.lex.len;
T->flags = parse.lex.flags;
parse_lex ();
PARSE_OK;
} else {
parse_error ("Can not parse nat const");
PARSE_FAIL;
}
}
struct tree *parse_type_ident (void) {
PARSE_INIT (type_type_ident);
if (parse.lex.type == lex_uc_ident && !(parse.lex.flags & 2)) {
T->text = parse.lex.ptr;
T->len = parse.lex.len;
T->flags = parse.lex.flags;
parse_lex ();
PARSE_OK;
} else if (parse.lex.type == lex_lc_ident && !(parse.lex.flags & 2)) {
T->text = parse.lex.ptr;
T->len = parse.lex.len;
T->flags = parse.lex.flags;
parse_lex ();
PARSE_OK;
} else if (LEX_CHAR ('#')) {
T->text = parse.lex.ptr;
T->len = parse.lex.len;
T->flags = parse.lex.flags;
parse_lex ();
PARSE_OK;
} else {
parse_error ("Can not parse type ident");
PARSE_FAIL;
}
}
struct tree *parse_term (void) {
PARSE_INIT (type_term);
while (LEX_CHAR ('%')) {
EXPECT ("%")
PARSE_ADD (type_percent);
}
if (LEX_CHAR ('(')) {
EXPECT ("(");
PARSE_TRY_PES (parse_expr);
EXPECT (")");
PARSE_OK;
}
PARSE_TRY (parse_type_ident);
if (S) {
tree_add_child (T, S);
if (LEX_CHAR ('<')) {
EXPECT ("<");
while (1) {
PARSE_TRY_PES (parse_expr);
if (LEX_CHAR ('>')) { break; }
EXPECT (",");
}
EXPECT (">");
}
PARSE_OK;
}
PARSE_TRY_OPT (parse_type_ident);
PARSE_TRY_OPT (parse_var_ident);
PARSE_TRY_OPT (parse_nat_const);
PARSE_FAIL;
}
struct tree *parse_nat_term (void) {
PARSE_INIT (type_nat_term);
PARSE_TRY_PES (parse_term);
PARSE_OK;
}
struct tree *parse_subexpr (void) {
PARSE_INIT (type_subexpr);
int was_term = 0;
int cc = 0;
while (1) {
PARSE_TRY (parse_nat_const);
if (S) {
tree_add_child (T, S);
} else if (!was_term) {
was_term = 1;
PARSE_TRY (parse_term);
if (S) {
tree_add_child (T, S);
} else {
break;
}
}
cc ++;
if (!LEX_CHAR ('+')) {
break;
}
EXPECT ("+");
}
if (!cc) {
PARSE_FAIL;
} else {
PARSE_OK;
}
}
struct tree *parse_expr (void) {
PARSE_INIT (type_expr);
int cc = 0;
while (1) {
PARSE_TRY (parse_subexpr);
if (S) {
tree_add_child (T, S);
cc ++;
} else {
if (cc < 1) { PARSE_FAIL; }
else { PARSE_OK; }
}
}
}
struct tree *parse_final_empty (void) {
PARSE_INIT (type_final_empty);
EXPECT ("Empty");
PARSE_TRY_PES (parse_boxed_type_ident);
PARSE_OK;
}
struct tree *parse_final_new (void) {
PARSE_INIT (type_final_new);
EXPECT ("New");
PARSE_TRY_PES (parse_boxed_type_ident);
PARSE_OK;
}
struct tree *parse_final_final (void) {
PARSE_INIT (type_final_final);
EXPECT ("Final");
PARSE_TRY_PES (parse_boxed_type_ident);
PARSE_OK;
}
struct tree *parse_partial_comb_app_decl (void) {
PARSE_INIT (type_partial_comb_app_decl);
PARSE_TRY_PES (parse_combinator_id);
while (1) {
PARSE_TRY_PES (parse_subexpr);
if (LEX_CHAR (';')) { break; }
}
PARSE_OK;
}
struct tree *parse_partial_type_app_decl (void) {
PARSE_INIT (type_partial_type_app_decl);
PARSE_TRY_PES (parse_boxed_type_ident);
if (LEX_CHAR ('<')) {
EXPECT ("<");
while (1) {
PARSE_TRY_PES (parse_expr);
if (LEX_CHAR ('>')) { break; }
EXPECT (",");
}
EXPECT (">");
PARSE_OK;
} else {
while (1) {
PARSE_TRY_PES (parse_subexpr);
if (LEX_CHAR (';')) { break; }
}
PARSE_OK;
}
}
struct tree *parse_multiplicity (void) {
PARSE_INIT (type_multiplicity);
PARSE_TRY_PES (parse_nat_term);
PARSE_OK;
}
struct tree *parse_type_term (void) {
PARSE_INIT (type_type_term);
PARSE_TRY_PES (parse_term);
PARSE_OK;
}
struct tree *parse_optional_arg_def (void) {
PARSE_INIT (type_optional_arg_def);
PARSE_TRY_PES (parse_var_ident);
EXPECT (".");
PARSE_TRY_PES (parse_nat_const);
EXPECT ("?");
PARSE_OK;
}
struct tree *parse_args4 (void) {
PARSE_INIT (type_args4);
struct parse so = save_parse ();
PARSE_TRY (parse_optional_arg_def);
if (S) {
tree_add_child (T, S);
} else {
load_parse (so);
}
if (LEX_CHAR ('!')) {
PARSE_ADD (type_exclam);
EXPECT ("!");
}
PARSE_TRY_PES (parse_type_term);
PARSE_OK;
}
struct tree *parse_args3 (void) {
PARSE_INIT (type_args3);
PARSE_TRY_PES (parse_var_ident_opt);
EXPECT (":");
struct parse so = save_parse ();
PARSE_TRY (parse_optional_arg_def);
if (S) {
tree_add_child (T, S);
} else {
load_parse (so);
}
if (LEX_CHAR ('!')) {
PARSE_ADD (type_exclam);
EXPECT ("!");
}
PARSE_TRY_PES (parse_type_term);
PARSE_OK;
}
struct tree *parse_args2 (void) {
PARSE_INIT (type_args2);
PARSE_TRY (parse_var_ident_opt);
if (S && LEX_CHAR (':')) {
tree_add_child (T, S);
EXPECT (":");
} else {
load_parse (save);
}
struct parse so = save_parse ();
PARSE_TRY (parse_optional_arg_def);
if (S) {
tree_add_child (T, S);
} else {
load_parse (so);
}
struct parse save2 = save_parse ();
PARSE_TRY (parse_multiplicity);
if (S && LEX_CHAR ('*')) {
tree_add_child (T, S);
EXPECT ("*");
} else {
load_parse (save2);
}
EXPECT ("[");
while (1) {
if (LEX_CHAR (']')) { break; }
PARSE_TRY_PES (parse_args);
}
EXPECT ("]");
PARSE_OK;
}
struct tree *parse_args1 (void) {
PARSE_INIT (type_args1);
EXPECT ("(");
while (1) {
PARSE_TRY_PES (parse_var_ident_opt);
if (LEX_CHAR(':')) { break; }
}
EXPECT (":");
struct parse so = save_parse ();
PARSE_TRY (parse_optional_arg_def);
if (S) {
tree_add_child (T, S);
} else {
load_parse (so);
}
if (LEX_CHAR ('!')) {
PARSE_ADD (type_exclam);
EXPECT ("!");
}
PARSE_TRY_PES (parse_type_term);
EXPECT (")");
PARSE_OK;
}
struct tree *parse_args (void) {
PARSE_INIT (type_args);
PARSE_TRY_OPT (parse_args1);
PARSE_TRY_OPT (parse_args2);
PARSE_TRY_OPT (parse_args3);
PARSE_TRY_OPT (parse_args4);
PARSE_FAIL;
}
struct tree *parse_opt_args (void) {
PARSE_INIT (type_opt_args);
while (1) {
PARSE_TRY_PES (parse_var_ident);
if (parse.lex.type == lex_char && *parse.lex.ptr == ':') { break;}
}
EXPECT (":");
PARSE_TRY_PES (parse_type_term);
PARSE_OK;
}
struct tree *parse_final_decl (void) {
PARSE_INIT (type_final_decl);
PARSE_TRY_OPT (parse_final_new);
PARSE_TRY_OPT (parse_final_final);
PARSE_TRY_OPT (parse_final_empty);
PARSE_FAIL;
}
struct tree *parse_partial_app_decl (void) {
PARSE_INIT (type_partial_app_decl);
PARSE_TRY_OPT (parse_partial_type_app_decl);
PARSE_TRY_OPT (parse_partial_comb_app_decl);
PARSE_FAIL;
}
struct tree *parse_result_type (void) {
PARSE_INIT (type_result_type);
PARSE_TRY_PES (parse_boxed_type_ident);
if (LEX_CHAR ('<')) {
EXPECT ("<");
while (1) {
PARSE_TRY_PES (parse_expr);
if (LEX_CHAR ('>')) { break; }
EXPECT (",");
}
EXPECT (">");
PARSE_OK;
} else {
while (1) {
if (LEX_CHAR (';')) { PARSE_OK; }
PARSE_TRY_PES (parse_subexpr);
}
}
}
struct tree *parse_combinator_decl (void) {
PARSE_INIT (type_combinator_decl);
PARSE_TRY_PES (parse_full_combinator_id)
while (1) {
if (LEX_CHAR ('{')) {
parse_lex ();
PARSE_TRY_PES (parse_opt_args);
EXPECT ("}");
} else {
break;
}
}
while (1) {
if (LEX_CHAR ('=')) { break; }
PARSE_TRY_PES (parse_args);
}
EXPECT ("=");
PARSE_ADD (type_equals);
PARSE_TRY_PES (parse_result_type);
PARSE_OK;
}
struct tree *parse_builtin_combinator_decl (void) {
PARSE_INIT (type_builtin_combinator_decl);
PARSE_TRY_PES (parse_full_combinator_id)
EXPECT ("?");
EXPECT ("=");
PARSE_TRY_PES (parse_boxed_type_ident);
PARSE_OK;
}
struct tree *parse_declaration (void) {
PARSE_INIT (type_declaration);
PARSE_TRY_OPT (parse_combinator_decl);
PARSE_TRY_OPT (parse_partial_app_decl);
PARSE_TRY_OPT (parse_final_decl);
PARSE_TRY_OPT (parse_builtin_combinator_decl);
PARSE_FAIL;
}
struct tree *parse_constr_declarations (void) {
PARSE_INIT (type_constr_declarations);
if (parse.lex.type == lex_triple_minus || parse.lex.type == lex_eof) { PARSE_OK; }
while (1) {
PARSE_TRY_PES (parse_declaration);
EXPECT (";");
if (parse.lex.type == lex_eof || parse.lex.type == lex_triple_minus) { PARSE_OK; }
}
}
struct tree *parse_fun_declarations (void) {
PARSE_INIT (type_fun_declarations);
if (parse.lex.type == lex_triple_minus || parse.lex.type == lex_eof) { PARSE_OK; }
while (1) {
PARSE_TRY_PES (parse_declaration);
EXPECT (";");
if (parse.lex.type == lex_eof || parse.lex.type == lex_triple_minus) { PARSE_OK; }
}
}
struct tree *parse_program (void) {
PARSE_INIT (type_tl_program);
while (1) {
PARSE_TRY_PES (parse_constr_declarations);
if (parse.lex.type == lex_eof) { PARSE_OK; }
if (parse.lex.type == lex_error || expect ("---") < 0 || expect ("functions") < 0 || expect ("---") < 0) { PARSE_FAIL; }
PARSE_TRY_PES (parse_fun_declarations);
if (parse.lex.type == lex_eof) { PARSE_OK; }
if (parse.lex.type == lex_error || expect ("---") < 0 || expect ("types") < 0 || expect ("---") < 0) { PARSE_FAIL; }
}
}
struct tree *tl_parse_lex (struct parse *_parse) {
assert (_parse);
load_parse (*_parse);
if (parse.lex.type == lex_none) {
parse_lex ();
}
if (parse.lex.type == lex_error) {
return 0;
}
return parse_program ();
}
int mystrcmp2 (const char *b, int len, const char *a) {
int c = strncmp (b, a, len);
return c ? a[len] ? -1 : 0 : c;
}
char *mystrdup (const char *a, int len) {
char *z = talloc (len + 1);
memcpy (z, a, len);
z[len] = 0;
return z;
}
struct tl_program *tl_program_cur;
#define TL_TRY_PES(x) if (!(x)) { return 0; }
#define tl_type_cmp(a,b) (strcmp (a->id, b->id))
DEFINE_TREE (tl_type,struct tl_type *,tl_type_cmp,0)
struct tree_tl_type *tl_type_tree;
DEFINE_TREE (tl_constructor,struct tl_constructor *,tl_type_cmp,0)
struct tree_tl_constructor *tl_constructor_tree;
struct tree_tl_constructor *tl_function_tree;
DEFINE_TREE (tl_var,struct tl_var *,tl_type_cmp,0)
struct tl_var_value {
struct tl_combinator_tree *ptr;
struct tl_combinator_tree *val;
int num_val;
};
#define tl_var_value_cmp(a,b) (((char *)a.ptr) - ((char *)b.ptr))
struct tl_var_value empty;
DEFINE_TREE (var_value, struct tl_var_value, tl_var_value_cmp, empty)
//tree_tl_var_t *tl_var_tree;
DEFINE_TREE (tl_field,char *,strcmp, 0)
//tree_tl_field_t *tl_field_tree;
#define TL_FAIL return 0;
#define TL_INIT(x) struct tl_combinator_tree *x = 0;
#define TL_TRY(f,x) { struct tl_combinator_tree *_t = f; if (!_t) { TL_FAIL;} x = tl_union (x, _t); if (!x) { TL_FAIL; }}
#define TL_ERROR(...) fprintf (stderr, __VA_ARGS__);
#define TL_WARNING(...) fprintf (stderr, __VA_ARGS__);
void tl_set_var_value (struct tree_var_value **T, struct tl_combinator_tree *var, struct tl_combinator_tree *value) {
struct tl_var_value t = {.ptr = var, .val = value, .num_val = 0};
if (tree_lookup_var_value (*T, t).ptr) {
*T = tree_delete_var_value (*T, t);
}
*T = tree_insert_var_value (*T, t, lrand48 ());
}
void tl_set_var_value_num (struct tree_var_value **T, struct tl_combinator_tree *var, struct tl_combinator_tree *value, long long num_value) {
struct tl_var_value t = {.ptr = var, .val = value, .num_val = num_value};
if (tree_lookup_var_value (*T, t).ptr) {
*T = tree_delete_var_value (*T, t);
}
*T = tree_insert_var_value (*T, t, lrand48 ());
}
struct tl_combinator_tree *tl_get_var_value (struct tree_var_value **T, struct tl_combinator_tree *var) {
struct tl_var_value t = {.ptr = var, .val = 0, .num_val = 0};
struct tl_var_value r = tree_lookup_var_value (*T, t);
return r.ptr ? r.val : 0;
}
int tl_get_var_value_num (struct tree_var_value **T, struct tl_combinator_tree *var) {
struct tl_var_value t = {.ptr = var, .val = 0};
struct tl_var_value r = tree_lookup_var_value (*T, t);
return r.ptr ? r.num_val : 0;
}
int namespace_level;
struct tree_tl_var *vars[10];
struct tree_tl_field *fields[10];
struct tl_var *last_num_var[10];
int tl_is_type_name (const char *id, int len) {
if (len == 1 && *id == '#') { return 1;}
int ok = id[0] >= 'A' && id[0] <= 'Z';
int i;
for (i = 0; i < len - 1; i++) if (id[i] == '.') {
ok = id[i + 1] >= 'A' && id[i + 1] <= 'Z';
}
return ok;
}
int tl_add_field (char *id) {
assert (namespace_level < 10);
assert (namespace_level >= 0);
if (tree_lookup_tl_field (fields[namespace_level], id)) {
return 0;
}
fields[namespace_level] = tree_insert_tl_field (fields[namespace_level], id, lrand48 ());
return 1;
}
void tl_clear_fields (void) {
// tree_act_tl_field (fields[namespace_level], (void *)free);
fields[namespace_level] = tree_clear_tl_field (fields[namespace_level]);
}
struct tl_var *tl_add_var (char *id, struct tl_combinator_tree *ptr, int type) {
struct tl_var *v = talloc (sizeof (*v));
v->id = tstrdup (id);
v->type = type;
v->ptr = ptr;
v->flags = 0;
if (tree_lookup_tl_var (vars[namespace_level], v)) {
return 0;
}
vars[namespace_level] = tree_insert_tl_var (vars[namespace_level], v, lrand48 ());
if (type) {
last_num_var[namespace_level] = v;
}
return v;
}
void tl_del_var (struct tl_var *v) {
// free (v->id);
tfree (v, sizeof (*v));
}
void tl_clear_vars (void) {
tree_act_tl_var (vars[namespace_level], tl_del_var);
vars[namespace_level] = tree_clear_tl_var (vars[namespace_level]);
last_num_var[namespace_level] = 0;
}
struct tl_var *tl_get_last_num_var (void) {
return last_num_var[namespace_level];
}
struct tl_var *tl_get_var (char *_id, int len) {
char *id = mystrdup (_id, len);
struct tl_var v = {.id = id};
int i;
for (i = namespace_level; i >= 0; i--) {
struct tl_var *w = tree_lookup_tl_var (vars[i], &v);
if (w) {
tfree (id, len + 1);
return w;
}
}
tfree (id, len + 1);
return 0;
}
void namespace_push (void) {
namespace_level ++;
assert (namespace_level < 10);
tl_clear_vars ();
tl_clear_fields ();
}
void namespace_pop (void) {
namespace_level --;
assert (namespace_level >= 0);
}
struct tl_type *tl_get_type (const char *_id, int len) {
char *id = mystrdup (_id, len);
struct tl_type _t = {.id = id};
struct tl_type *r = tree_lookup_tl_type (tl_type_tree, &_t);
tfree (id, len + 1);
return r;
}
struct tl_type *tl_add_type (const char *_id, int len, int params_num, long long params_types) {
char *id = talloc (len + 1);
memcpy (id, _id, len);
id[len] = 0;
struct tl_type _t = {.id = id};
struct tl_type *_r = 0;
if ((_r = tree_lookup_tl_type (tl_type_tree, &_t))) {
tfree (id, len + 1);
if (params_num >= 0 && (_r->params_num != params_num || _r->params_types != params_types)) {
TL_ERROR ("Wrong params_num or types for type %s\n", _r->id);
return 0;
}
return _r;
}
struct tl_type *t = talloc (sizeof (*t));
t->id = id;
t->print_id = tstrdup (t->id);
int i;
for (i = 0; i < len; i++) if (t->print_id[i] == '.' || t->print_id[i] == '#' || t->print_id[i] == ' ') {
t->print_id[i] = '$';
}
t->name = 0;
t->constructors_num = 0;
t->constructors = 0;
t->flags = 0;
t->real_id = 0;
if (params_num >= 0) {
assert (params_num <= 64);
t->params_num = params_num;
t->params_types = params_types;
} else {
t->flags |= 4;
t->params_num = -1;
}
tl_type_tree = tree_insert_tl_type (tl_type_tree, t, lrand48 ());
total_types_num ++;
return t;
}
void tl_add_type_param (struct tl_type *t, int x) {
assert (t->flags & 4);
assert (t->params_num <= 64);
if (x) {
t->params_types |= (1ull << (t->params_num ++));
} else {
t->params_num ++;
}
}
int tl_type_set_params (struct tl_type *t, int x, long long y) {
if (t->flags & 4) {
t->params_num = x;
t->params_types = y;
t->flags &= ~4;
} else {
if (t->params_num != x || t->params_types != y) {
fprintf (stderr, "Wrong num of params (type %s)\n", t->id);
return 0;
}
}
return 1;
}
void tl_type_finalize (struct tl_type *t) {
t->flags &= ~4;
}
struct tl_constructor *tl_get_constructor (const char *_id, int len) {
char *id = mystrdup (_id, len);
struct tl_constructor _t = {.id = id};
struct tl_constructor *r = tree_lookup_tl_constructor (tl_constructor_tree, &_t);
tfree (id, len + 1);
return r;
}
struct tl_constructor *tl_add_constructor (struct tl_type *a, const char *_id, int len, int force_magic) {
assert (a);
if (a->flags & 1) {
TL_ERROR ("New constructor for type `%s` after final statement\n", a->id);
return 0;
}
int x = 0;
while (x < len && (_id[x] != '#' || force_magic)) { x++; }
char *id = talloc (x + 1);
memcpy (id, _id, x);
id[x] = 0;
unsigned magic = 0;
if (x < len) {
assert (len - x >= 6 && len - x <= 9);
int i;
for (i = 1; i < len - x; i++) {
magic = (magic << 4) + (_id[x + i] <= '9' ? _id[x + i] - '0' : _id[x + i] - 'a' + 10);
}
assert (magic && magic != (unsigned)-1);
}
len = x;
if (*id != '_') {
struct tl_constructor _t = {.id = id};
if (tree_lookup_tl_constructor (tl_constructor_tree, &_t)) {
TL_ERROR ("Duplicate constructor id `%s`\n", id);
tfree (id, len + 1);
return 0;
}
} else {
assert (len == 1);
}
struct tl_constructor *t = talloc (sizeof (*t));
t->type = a;
t->name = magic;
t->id = id;
t->print_id = tstrdup (id);
t->real_id = 0;
int i;
for (i = 0; i < len; i++) if (t->print_id[i] == '.' || t->print_id[i] == '#' || t->print_id[i] == ' ') {
t->print_id[i] = '$';
}
t->left = t->right = 0;
a->constructors = realloc (a->constructors, sizeof (void *) * (a->constructors_num + 1));
assert (a->constructors);
a->constructors[a->constructors_num ++] = t;
if (*id != '_') {
tl_constructor_tree = tree_insert_tl_constructor (tl_constructor_tree, t, lrand48 ());
}
total_constructors_num ++;
a->flags |= FLAG_DEFAULT_CONSTRUCTOR;
return t;
}
struct tl_constructor *tl_get_function (const char *_id, int len) {
char *id = mystrdup (_id, len);
struct tl_constructor _t = {.id = id};
struct tl_constructor *r = tree_lookup_tl_constructor (tl_function_tree, &_t);
tfree (id, len + 1);
return r;
}
struct tl_constructor *tl_add_function (struct tl_type *a, const char *_id, int len, int force_magic) {
// assert (a);
int x = 0;
while (x < len && ((_id[x] != '#') || force_magic)) { x++; }
char *id = talloc (x + 1);
memcpy (id, _id, x);
id[x] = 0;
unsigned magic = 0;
if (x < len) {
assert (len - x >= 6 && len - x <= 9);
int i;
for (i = 1; i < len - x; i++) {
magic = (magic << 4) + (_id[x + i] <= '9' ? _id[x + i] - '0' : _id[x + i] - 'a' + 10);
}
assert (magic && magic != (unsigned)-1);
}
len = x;
struct tl_constructor _t = {.id = id};
if (tree_lookup_tl_constructor (tl_function_tree, &_t)) {
TL_ERROR ("Duplicate function id `%s`\n", id);
tfree (id, len + 1);
return 0;
}
struct tl_constructor *t = talloc (sizeof (*t));
t->type = a;
t->name = magic;
t->id = id;
t->print_id = tstrdup (id);
t->real_id = 0;
int i;
for (i = 0; i < len; i++) if (t->print_id[i] == '.' || t->print_id[i] == '#' || t->print_id[i] == ' ') {
t->print_id[i] = '$';
}
t->left = t->right = 0;
tl_function_tree = tree_insert_tl_constructor (tl_function_tree, t, lrand48 ());
total_functions_num ++;
return t;
}
static char buf[(1 << 20)];
int buf_pos;
struct tl_combinator_tree *alloc_ctree_node (void) {
struct tl_combinator_tree *T = talloc (sizeof (*T));
assert (T);
memset (T, 0, sizeof (*T));
return T;
}
struct tl_combinator_tree *tl_tree_dup (struct tl_combinator_tree *T) {
if (!T) { return 0; }
struct tl_combinator_tree *S = talloc (sizeof (*S));
memcpy (S, T, sizeof (*S));
S->left = tl_tree_dup (T->left);
S->right = tl_tree_dup (T->right);
return S;
}
struct tl_type *tl_tree_get_type (struct tl_combinator_tree *T) {
assert (T->type == type_type);
if (T->act == act_array) { return 0;}
while (T->left) {
T = T->left;
if (T->act == act_array) { return 0;}
assert (T->type == type_type);
}
assert (T->act == act_type || T->act == act_var || T->act == act_array);
return T->act == act_type ? T->data : 0;
}
void tl_tree_set_len (struct tl_combinator_tree *T) {
TL_INIT (H);
H = T;
while (H->left) {
H->left->type_len = H->type_len + 1;
H = H->left;
}
assert (H->type == type_type);
struct tl_type *t = H->data;
assert (t);
assert (H->type_len == t->params_num);
}
void tl_buf_reset (void) {
buf_pos = 0;
}
void tl_buf_add_string (char *s, int len) {
if (len < 0) { len = strlen (s); }
buf[buf_pos ++] = ' ';
memcpy (buf + buf_pos, s, len); buf_pos += len;
buf[buf_pos] = 0;
}
void tl_buf_add_string_nospace (char *s, int len) {
if (len < 0) { len = strlen (s); }
// if (buf_pos) { buf[buf_pos ++] = ' '; }
memcpy (buf + buf_pos, s, len); buf_pos += len;
buf[buf_pos] = 0;
}
void tl_buf_add_string_q (char *s, int len, int x) {
if (x) {
tl_buf_add_string (s, len);
} else {
tl_buf_add_string_nospace (s, len);
}
}
void tl_buf_add_tree (struct tl_combinator_tree *T, int x) {
if (!T) { return; }
assert (T != (void *)-1l && T != (void *)-2l);
switch (T->act) {
case act_question_mark:
tl_buf_add_string_q ("?", -1, x);
return;
case act_type:
if ((T->flags & 1) && !(T->flags & 4)) {
tl_buf_add_string_q ("%", -1, x);
x = 0;
}
if (T->flags & 2) {
tl_buf_add_string_q ((char *)T->data, -1, x);
} else {
struct tl_type *t = T->data;
if (T->flags & 4) {
assert (t->constructors_num == 1);
tl_buf_add_string_q (t->constructors[0]->real_id ? t->constructors[0]->real_id : t->constructors[0]->id, -1, x);
} else {
tl_buf_add_string_q (t->real_id ? t->real_id : t->id, -1, x);
}
}
return;
case act_field:
if (T->data) {
tl_buf_add_string_q ((char *)T->data, -1, x);
x = 0;
tl_buf_add_string_q (":", -1, 0);
}
tl_buf_add_tree (T->left, x);
tl_buf_add_tree (T->right, 1);
return;
case act_union:
tl_buf_add_tree (T->left, x);
tl_buf_add_tree (T->right, 1);
return;
case act_var:
{
if (T->data == (void *)-1l) { return; }
struct tl_combinator_tree *v = T->data;
tl_buf_add_string_q ((char *)v->data, -1, x);
if (T->type == type_num && T->type_flags) {
static char _buf[30];
sprintf (_buf, "+%lld", T->type_flags);
tl_buf_add_string_q (_buf, -1, 0);
}
}
return;
case act_arg:
tl_buf_add_tree (T->left, x);
tl_buf_add_tree (T->right, 1);
return;
case act_array:
if (T->left && !(T->left->flags & 128)) {
tl_buf_add_tree (T->left, x);
x = 0;
tl_buf_add_string_q ("*", -1, x);
}
tl_buf_add_string_q ("[", -1, x);
tl_buf_add_tree (T->right, 1);
tl_buf_add_string_q ("]", -1, 1);
return;
case act_plus:
tl_buf_add_tree (T->left, x);
tl_buf_add_string_q ("+", -1, 0);
tl_buf_add_tree (T->right, 0);
return;
case act_nat_const:
{
static char _buf[30];
snprintf (_buf, 29, "%lld", T->type_flags);
tl_buf_add_string_q (_buf, -1, x);
return;
}
case act_opt_field:
{
struct tl_combinator_tree *v = T->left->data;
tl_buf_add_string_q ((char *)v->data, -1, x);
tl_buf_add_string_q (".", -1, 0);
static char _buf[30];
sprintf (_buf, "%lld", T->left->type_flags);
tl_buf_add_string_q (_buf, -1, 0);
tl_buf_add_string_q ("?", -1, 0);
tl_buf_add_tree (T->right, 0);
return;
}
default:
fprintf (stderr, "%s %s\n", TL_ACT (T->act), TL_TYPE (T->type));
assert (0);
return;
}
}
int tl_count_combinator_name (struct tl_constructor *c) {
assert (c);
tl_buf_reset ();
tl_buf_add_string_nospace (c->real_id ? c->real_id : c->id, -1);
tl_buf_add_tree (c->left, 1);
tl_buf_add_string ("=", -1);
tl_buf_add_tree (c->right, 1);
//fprintf (stderr, "%.*s\n", buf_pos, buf);
if (!c->name) {
c->name = compute_crc32 (buf, buf_pos);
}
return c->name;
}
int tl_print_combinator (struct tl_constructor *c) {
tl_buf_reset ();
tl_buf_add_string_nospace (c->real_id ? c->real_id : c->id, -1);
static char _buf[10];
sprintf (_buf, "#%08x", c->name);
tl_buf_add_string_nospace (_buf, -1);
tl_buf_add_tree (c->left, 1);
tl_buf_add_string ("=", -1);
tl_buf_add_tree (c->right, 1);
if (output_expressions >= 1) {
fprintf (stderr, "%.*s\n", buf_pos, buf);
}
/* if (!c->name) {
c->name = compute_crc32 (buf, buf_pos);
}*/
return c->name;
}
int _tl_finish_subtree (struct tl_combinator_tree *R, int x, long long y) {
assert (R->type == type_type);
assert (R->type_len < 0);
assert (R->act == act_arg || R->act == act_type);
R->type_len = x;
R->type_flags = y;
if (R->act == act_type) {
struct tl_type *t = R->data;
assert (t);
return tl_type_set_params (t, x, y);
}
assert ((R->right->type == type_type && R->right->type_len == 0) || R->right->type == type_num || R->right->type == type_num_value);
return _tl_finish_subtree (R->left, x + 1, y * 2 + (R->right->type == type_num || R->right->type == type_num_value));
}
int tl_finish_subtree (struct tl_combinator_tree *R) {
assert (R);
if (R->type != type_type) {
return 1;
}
if (R->type_len >= 0) {
if (R->type_len > 0) {
TL_ERROR ("Not enough params\n");
return 0;
}
return 1;
}
return _tl_finish_subtree (R, 0, 0);
}
struct tl_combinator_tree *tl_union (struct tl_combinator_tree *L, struct tl_combinator_tree *R) {
if (!L) { return R; }
if (!R) { return L; }
TL_INIT (v);
v = alloc_ctree_node ();
v->left = L;
v->right = R;
switch (L->type) {
case type_num:
if (R->type != type_num_value) {
TL_ERROR ("Union: type mistmatch\n");
return 0;
}
tfree (v, sizeof (*v));
L->type_flags += R->type_flags;
return L;
case type_num_value:
if (R->type != type_num_value && R->type != type_num) {
TL_ERROR ("Union: type mistmatch\n");
return 0;
}
tfree (v, sizeof (*v));
R->type_flags += L->type_flags;
return R;
case type_list_item:
case type_list:
if (R->type != type_list_item) {
TL_ERROR ("Union: type mistmatch\n");
return 0;
}
v->type = type_list;
v->act = act_union;
return v;
case type_type:
if (L->type_len == 0) {
TL_ERROR ("Arguments number exceeds type arity\n");
return 0;
}
if (R->type != type_num && R->type != type_type && R->type != type_num_value) {
TL_ERROR ("Union: type mistmatch\n");
return 0;
}
if (R->type_len < 0) {
if (!tl_finish_subtree (R)) {
return 0;
}
}
if (R->type_len > 0) {
TL_ERROR ("Argument type must have full number of arguments\n");
return 0;
}
if (L->type_len > 0 && ((L->type_flags & 1) != (R->type == type_num || R->type == type_num_value))) {
TL_ERROR ("Argument types mistmatch: L->type_flags = %lld, R->type = %s\n", L->flags, TL_TYPE (R->type));
return 0;
}
v->type = type_type;
v->act = act_arg;
v->type_len = L->type_len > 0 ? L->type_len - 1 : -1;
v->type_flags = L->type_flags >> 1;
return v;
default:
assert (0);
return 0;
}
}
struct tl_combinator_tree *tl_parse_any_term (struct tree *T, int s);
struct tl_combinator_tree *tl_parse_term (struct tree *T, int s) {
assert (T->type == type_term);
int i = 0;
while (i < T->nc && T->c[i]->type == type_percent) { i ++; s ++; }
assert (i < T->nc);
TL_INIT (L);
while (i < T->nc) {
TL_TRY (tl_parse_any_term (T->c[i], s), L);
s = 0;
i ++;
}
return L;
}
struct tl_combinator_tree *tl_parse_type_term (struct tree *T, int s) {
assert (T->type == type_type_term);
assert (T->nc == 1);
struct tl_combinator_tree *Z = tl_parse_term (T->c[0], s);
if (!Z || Z->type != type_type) { if (Z) { TL_ERROR ("type_term: found type %s\n", TL_TYPE (Z->type)); } TL_FAIL; }
return Z;
}
struct tl_combinator_tree *tl_parse_nat_term (struct tree *T, int s) {
assert (T->type == type_nat_term);
assert (T->nc == 1);
struct tl_combinator_tree *Z = tl_parse_term (T->c[0], s);
if (!Z || (Z->type != type_num && Z->type != type_num_value)) { if (Z) { TL_ERROR ("nat_term: found type %s\n", TL_TYPE (Z->type)); }TL_FAIL; }
return Z;
}
struct tl_combinator_tree *tl_parse_subexpr (struct tree *T, int s) {
assert (T->type == type_subexpr);
assert (T->nc >= 1);
int i;
TL_INIT (L);
for (i = 0; i < T->nc; i++) {
TL_TRY (tl_parse_any_term (T->c[i], s), L);
s = 0;
}
return L;
}
struct tl_combinator_tree *tl_parse_expr (struct tree *T, int s) {
assert (T->type == type_expr);
assert (T->nc >= 1);
int i;
TL_INIT (L);
for (i = 0; i < T->nc; i++) {
TL_TRY (tl_parse_subexpr (T->c[i], s), L);
s = 0;
}
return L;
}
struct tl_combinator_tree *tl_parse_nat_const (struct tree *T, int s) {
assert (T->type == type_nat_const);
assert (!T->nc);
if (s > 0) {
TL_ERROR ("Nat const can not preceed with %%\n");
TL_FAIL;
}
assert (T->type == type_nat_const);
assert (!T->nc);
TL_INIT (L);
L = alloc_ctree_node ();
L->act = act_nat_const;
L->type = type_num_value;
int i;
long long x = 0;
for (i = 0; i < T->len; i++) {
x = x * 10 + T->text[i] - '0';
}
L->type_flags = x;
return L;
}
struct tl_combinator_tree *tl_parse_ident (struct tree *T, int s) {
assert (T->type == type_type_ident || T->type == type_var_ident || T->type == type_boxed_type_ident);
assert (!T->nc);
struct tl_var *v = tl_get_var (T->text, T->len);
TL_INIT (L);
if (v) {
L = alloc_ctree_node ();
L->act = act_var;
L->type = v->type ? type_num : type_type;
if (L->type == type_num && s) {
TL_ERROR ("Nat var can not preceed with %%\n");
TL_FAIL;
} else {
if (s) {
L->flags |= 1;
}
}
L->type_len = 0;
L->type_flags = 0;
L->data = v->ptr;
return L;
}
/* if (!mystrcmp2 (T->text, T->len, "#") || !mystrcmp2 (T->text, T->len, "Type")) {
L = alloc_ctree_node ();
L->act = act_type;
L->flags |= 2;
L->data = tl_get_type (T->text, T->len);
assert (L->data);
L->type = type_type;
L->type_len = 0;
L->type_flags = 0;
return L;
}*/
struct tl_constructor *c = tl_get_constructor (T->text, T->len);
if (c) {
assert (c->type);
if (c->type->constructors_num != 1) {
TL_ERROR ("Constructor can be used only if it is the only constructor of the type\n");
return 0;
}
c->type->flags |= 1;
L = alloc_ctree_node ();
L->act = act_type;
L->flags |= 5;
L->data = c->type;
L->type = type_type;
L->type_len = c->type->params_num;
L->type_flags = c->type->params_types;
return L;
}
int x = tl_is_type_name (T->text, T->len);
if (x) {
struct tl_type *t = tl_add_type (T->text, T->len, -1, 0);
L = alloc_ctree_node ();
if (s) {
L->flags |= 1;
t->flags |= 8;
}
L->act = act_type;
L->data = t;
L->type = type_type;
L->type_len = t->params_num;
L->type_flags = t->params_types;
return L;
} else {
TL_ERROR ("Not a type/var ident `%.*s`\n", T->len, T->text);
return 0;
}
}
struct tl_combinator_tree *tl_parse_any_term (struct tree *T, int s) {
switch (T->type) {
case type_type_term:
return tl_parse_type_term (T, s);
case type_nat_term:
return tl_parse_nat_term (T, s);
case type_term:
return tl_parse_term (T, s);
case type_expr:
return tl_parse_expr (T, s);
case type_subexpr:
return tl_parse_subexpr (T, s);
case type_nat_const:
return tl_parse_nat_const (T, s);
case type_type_ident:
case type_var_ident:
return tl_parse_ident (T, s);
default:
fprintf (stderr, "type = %d\n", T->type);
assert (0);
return 0;
}
}
struct tl_combinator_tree *tl_parse_multiplicity (struct tree *T) {
assert (T->type == type_multiplicity);
assert (T->nc == 1);
return tl_parse_nat_term (T->c[0], 0);
}
struct tl_combinator_tree *tl_parse_opt_args (struct tree *T) {
assert (T);
assert (T->type == type_opt_args);
assert (T->nc >= 2);
TL_INIT (R);
TL_TRY (tl_parse_type_term (T->c[T->nc - 1], 0), R);
assert (R->type == type_type && !R->type_len);
assert (tl_finish_subtree (R));
struct tl_type *t = tl_tree_get_type (R);
//assert (t);
int tt = -1;
if (t && !strcmp (t->id, "#")) {
tt = 1;
} else if (t && !strcmp (t->id, "Type")) {
tt = 0;
}
if (tt < 0) {
TL_ERROR ("Optargs can be only of type # or Type\n");
TL_FAIL;
}
int i;
for (i = 0; i < T->nc - 1; i++) {
if (T->c[i]->type != type_var_ident) {
TL_ERROR ("Variable name expected\n");
TL_FAIL;
}
if (T->c[i]->len == 1 && *T->c[i]->text == '_') {
TL_ERROR ("Variables can not be unnamed\n");
TL_FAIL;
}
}
TL_INIT (H);
// for (i = T->nc - 2; i >= (T->nc >= 2 ? 0 : -1); i--) {
for (i = 0; i <= T->nc - 2; i++) {
TL_INIT (S); S = alloc_ctree_node ();
S->left = (i == T->nc - 2) ? R : tl_tree_dup (R) ; S->right = 0;
S->type = type_list_item;
S->type_len = 0;
S->act = act_field;
S->data = i >= 0 ? mystrdup (T->c[i]->text, T->c[i]->len) : 0;
if (tt >= 0) {
assert (S->data);
tl_add_var (S->data, S, tt);
}
S->flags = 33;
H = tl_union (H, S);
}
return H;
}
struct tl_combinator_tree *tl_parse_args (struct tree *T);
struct tl_combinator_tree *tl_parse_args2 (struct tree *T) {
assert (T);
assert (T->type == type_args2);
assert (T->nc >= 1);
TL_INIT (R);
TL_INIT (L);
int x = 0;
char *field_name = 0;
if (T->c[x]->type == type_var_ident_opt || T->c[x]->type == type_var_ident) {
field_name = mystrdup (T->c[x]->text, T->c[x]->len);
if (!tl_add_field (field_name)) {
TL_ERROR ("Duplicate field name %s\n", field_name);
TL_FAIL;
}
x ++;
}
//fprintf (stderr, "%d %d\n", x, T->nc);
if (T->c[x]->type == type_multiplicity) {
L = tl_parse_multiplicity (T->c[x]);
if (!L) { TL_FAIL;}
x ++;
} else {
struct tl_var *v = tl_get_last_num_var ();
if (!v) {
TL_ERROR ("Expected multiplicity or nat var\n");
TL_FAIL;
}
L = alloc_ctree_node ();
L->act = act_var;
L->type = type_num;
L->flags |= 128;
L->type_len = 0;
L->type_flags = 0;
L->data = v->ptr;
((struct tl_combinator_tree *)(v->ptr))->flags |= 256;
}
namespace_push ();
while (x < T->nc) {
TL_TRY (tl_parse_args (T->c[x]), R);
x ++;
}
namespace_pop ();
struct tl_combinator_tree *S = alloc_ctree_node ();
S->type = type_type;
S->type_len = 0;
S->act = act_array;
S->left = L;
S->right = R;
//S->data = field_name;
struct tl_combinator_tree *H = alloc_ctree_node ();
H->type = type_list_item;
H->act = act_field;
H->left = S;
H->right = 0;
H->data = field_name;
H->type_len = 0;
return H;
}
void tl_mark_vars (struct tl_combinator_tree *T);
struct tl_combinator_tree *tl_parse_args134 (struct tree *T) {
assert (T);
assert (T->type == type_args1 || T->type == type_args3 || T->type == type_args4);
assert (T->nc >= 1);
TL_INIT (R);
TL_TRY (tl_parse_type_term (T->c[T->nc - 1], 0), R);
assert (tl_finish_subtree (R));
assert (R->type == type_type && !R->type_len);
struct tl_type *t = tl_tree_get_type (R);
//assert (t);
int tt = -1;
if (t && !strcmp (t->id, "#")) {
tt = 1;
} else if (t && !strcmp (t->id, "Type")) {
tt = 0;
}
/* if (tt >= 0 && T->nc == 1) {
TL_ERROR ("Variables can not be unnamed (type %d)\n", tt);
}*/
int last = T->nc - 2;
int excl = 0;
if (last >= 0 && T->c[last]->type == type_exclam) {
excl ++;
tl_mark_vars (R);
last --;
}
if (last >= 0 && T->c[last]->type == type_optional_arg_def) {
assert (T->c[last]->nc == 2);
TL_INIT (E); E = alloc_ctree_node ();
E->type = type_type;
E->act = act_opt_field;
E->left = tl_parse_ident (T->c[last]->c[0], 0);
int i;
long long x = 0;
for (i = 0; i < T->c[last]->c[1]->len; i++) {
x = x * 10 + T->c[last]->c[1]->text[i] - '0';
}
E->left->type_flags = x;
E->type_flags = R->type_flags;
E->type_len = R->type_len;
E->right = R;
R = E;
last --;
}
int i;
for (i = 0; i < last; i++) {
if (T->c[i]->type != type_var_ident && T->c[i]->type != type_var_ident_opt) {
TL_ERROR ("Variable name expected\n");
TL_FAIL;
}
/* if (tt >= 0 && (T->nc == 1 || (T->c[i]->len == 1 && *T->c[i]->text == '_'))) {
TL_ERROR ("Variables can not be unnamed\n");
TL_FAIL;
}*/
}
TL_INIT (H);
// for (i = T->nc - 2; i >= (T->nc >= 2 ? 0 : -1); i--) {
for (i = (last >= 0 ? 0 : -1); i <= last; i++) {
TL_INIT (S); S = alloc_ctree_node ();
S->left = (i == last) ? R : tl_tree_dup (R) ; S->right = 0;
S->type = type_list_item;
S->type_len = 0;
S->act = act_field;
S->data = i >= 0 ? mystrdup (T->c[i]->text, T->c[i]->len) : 0;
if (excl) {
S->flags |= FLAG_EXCL;
}
if (S->data && (T->c[i]->len >= 2 || *T->c[i]->text != '_')) {
if (!tl_add_field (S->data)) {
TL_ERROR ("Duplicate field name %s\n", (char *)S->data);
TL_FAIL;
}
}
if (tt >= 0) {
//assert (S->data);
char *name = S->data;
if (!name) {
static char s[20];
sprintf (s, "%lld", lrand48 () * (1ll << 32) + lrand48 ());
name = s;
}
struct tl_var *v = tl_add_var (name, S, tt);
if (!v) {TL_FAIL;}
v->flags |= 2;
}
H = tl_union (H, S);
}
return H;
}
struct tl_combinator_tree *tl_parse_args (struct tree *T) {
assert (T->type == type_args);
assert (T->nc == 1);
switch (T->c[0]->type) {
case type_args1:
return tl_parse_args134 (T->c[0]);
case type_args2:
return tl_parse_args2 (T->c[0]);
case type_args3:
return tl_parse_args134 (T->c[0]);
case type_args4:
return tl_parse_args134 (T->c[0]);
default:
assert (0);
return 0;
}
}
void tl_mark_vars (struct tl_combinator_tree *T) {
if (!T) { return; }
if (T->act == act_var) {
char *id = ((struct tl_combinator_tree *)(T->data))->data;
struct tl_var *v = tl_get_var (id, strlen (id));
assert (v);
v->flags |= 1;
}
tl_mark_vars (T->left);
tl_mark_vars (T->right);
}
struct tl_combinator_tree *tl_parse_result_type (struct tree *T) {
assert (T->type == type_result_type);
assert (T->nc >= 1);
assert (T->nc <= 64);
TL_INIT (L);
if (tl_get_var (T->c[0]->text, T->c[0]->len)) {
if (T->nc != 1) {
TL_ERROR ("Variable can not take params\n");
TL_FAIL;
}
L = alloc_ctree_node ();
L->act = act_var;
L->type = type_type;
struct tl_var *v = tl_get_var (T->c[0]->text, T->c[0]->len);
if (v->type) {
TL_ERROR ("Type mistmatch\n");
TL_FAIL;
}
L->data = v->ptr;
// assert (v->ptr);
} else {
L = alloc_ctree_node ();
L->act = act_type;
L->type = type_type;
struct tl_type *t = tl_add_type (T->c[0]->text, T->c[0]->len, -1, 0);
assert (t);
L->type_len = t->params_num;
L->type_flags = t->params_types;
L->data = t;
int i;
for (i = 1; i < T->nc; i++) {
TL_TRY (tl_parse_any_term (T->c[i], 0), L);
assert (L->right);
assert (L->right->type == type_num || L->right->type == type_num_value || (L->right->type == type_type && L->right->type_len == 0));
}
}
if (!tl_finish_subtree (L)) {
TL_FAIL;
}
tl_mark_vars (L);
return L;
}
int __ok;
void tl_var_check_used (struct tl_var *v) {
__ok = __ok && (v->flags & 3);
}
int tl_parse_combinator_decl (struct tree *T, int fun) {
assert (T->type == type_combinator_decl);
assert (T->nc >= 3);
namespace_level = 0;
tl_clear_vars ();
tl_clear_fields ();
TL_INIT (L);
TL_INIT (R);
int i = 1;
while (i < T->nc - 2 && T->c[i]->type == type_opt_args) {
TL_TRY (tl_parse_opt_args (T->c[i]), L);
i++;
}
while (i < T->nc - 2 && T->c[i]->type == type_args) {
TL_TRY (tl_parse_args (T->c[i]), L);
i++;
}
assert (i == T->nc - 2 && T->c[i]->type == type_equals);
i ++;
R = tl_parse_result_type (T->c[i]);
if (!R) { TL_FAIL; }
struct tl_type *t = tl_tree_get_type (R);
if (!fun && !t) {
TL_ERROR ("Only functions can return variables\n");
}
assert (t || fun);
assert (namespace_level == 0);
__ok = 1;
tree_act_tl_var (vars[0], tl_var_check_used);
if (!__ok) {
TL_ERROR ("Not all variables are used in right side\n");
TL_FAIL;
}
if (tl_get_constructor (T->c[0]->text, T->c[0]->len) || tl_get_function (T->c[0]->text, T->c[0]->len)) {
TL_ERROR ("Duplicate combinator id %.*s\n", T->c[0]->len, T->c[0]->text);
return 0;
}
struct tl_constructor *c = !fun ? tl_add_constructor (t, T->c[0]->text, T->c[0]->len, 0) : tl_add_function (t, T->c[0]->text, T->c[0]->len, 0);
if (!c) { TL_FAIL; }
c->left = L;
c->right = R;
if (!c->name) {
tl_count_combinator_name (c);
}
tl_print_combinator (c);
return 1;
}
void change_var_ptrs (struct tl_combinator_tree *O, struct tl_combinator_tree *D, struct tree_var_value **V) {
if (!O || !D) {
assert (!O && !D);
return;
}
if (O->act == act_field) {
struct tl_type *t = tl_tree_get_type (O->left);
if (t && (!strcmp (t->id, "#") || !strcmp (t->id, "Type"))) {
tl_set_var_value (V, O, D);
}
}
if (O->act == act_var) {
assert (D->data == O->data);
D->data = tl_get_var_value (V, O->data);
assert (D->data);
}
change_var_ptrs (O->left, D->left, V);
change_var_ptrs (O->right, D->right, V);
}
struct tl_combinator_tree *change_first_var (struct tl_combinator_tree *O, struct tl_combinator_tree **X, struct tl_combinator_tree *Y) {
if (!O) { return (void *)-2l; };
if (O->act == act_field && !*X) {
struct tl_type *t = tl_tree_get_type (O->left);
if (t && !strcmp (t->id, "#")) {
if (Y->type != type_num && Y->type != type_num_value) {
TL_ERROR ("change_var: Type mistmatch\n");
return 0;
} else {
*X = O;
return (void *)-1l;
}
}
if (t && !strcmp (t->id, "Type")) {
if (Y->type != type_type || Y->type_len != 0) {
TL_ERROR ("change_var: Type mistmatch\n");
return 0;
} else {
*X = O;
return (void *)-1l;
}
}
}
if (O->act == act_var) {
if (O->data == *X) {
struct tl_combinator_tree *R = tl_tree_dup (Y);
if (O->type == type_num || O->type == type_num_value) { R->type_flags += O->type_flags; }
return R;
}
}
struct tl_combinator_tree *t;
t = change_first_var (O->left, X, Y);
if (!t) { return 0;}
if (t == (void *)-1l) {
t = change_first_var (O->right, X, Y);
if (!t) { return 0;}
if (t == (void *)-1l) { return (void *)-1l; }
if (t != (void *)-2l) { return t;}
return (void *)-1l;
}
if (t != (void *)-2l) {
O->left = t;
}
t = change_first_var (O->right, X, Y);
if (!t) { return 0;}
if (t == (void *)-1l) {
return O->left;
}
if (t != (void *)-2l) {
O->right = t;
}
return O;
}
int uniformize (struct tl_combinator_tree *L, struct tl_combinator_tree *R, struct tree_var_value **T);
struct tree_var_value **_T;
int __tok;
void check_nat_val (struct tl_var_value v) {
if (!__tok) { return; }
long long x = v.num_val;
struct tl_combinator_tree *L = v.val;
if (L->type == type_type) { return;}
while (1) {
if (L->type == type_num_value) {
if (x + L->type_flags < 0) {
__tok = 0;
return;
} else {
return;
}
}
assert (L->type == type_num);
x += L->type_flags;
x += tl_get_var_value_num (_T, L->data);
L = tl_get_var_value (_T, L->data);
if (!L) { return;}
}
}
int check_constructors_equal (struct tl_combinator_tree *L, struct tl_combinator_tree *R, struct tree_var_value **T) {
if (!uniformize (L, R, T)) { return 0; }
__tok = 1;
_T = T;
tree_act_var_value (*T, check_nat_val);
return __tok;
}
struct tl_combinator_tree *reduce_type (struct tl_combinator_tree *A, struct tl_type *t) {
assert (A);
if (A->type_len == t->params_num) {
assert (A->type_flags == t->params_types);
A->act = act_type;
A->type = type_type;
A->left = A->right = 0;
A->data = t;
return A;
}
A->left = reduce_type (A->left, t);
return A;
}
struct tl_combinator_tree *change_value_var (struct tl_combinator_tree *O, struct tree_var_value **X) {
if (!O) { return (void *)-2l; };
while (O->act == act_var) {
assert (O->data);
if (!tl_get_var_value (X, O->data)) {
break;
}
if (O->type == type_type) {
O = tl_tree_dup (tl_get_var_value (X, O->data));
} else {
long long n = tl_get_var_value_num (X, O->data);
struct tl_combinator_tree *T = tl_get_var_value (X, O->data);
O->data = T->data;
O->type = T->type;
O->act = T->act;
O->type_flags = O->type_flags + n + T->type_flags;
}
}
if (O->act == act_field) {
if (tl_get_var_value (X, O)) { return (void *)-1l; }
}
struct tl_combinator_tree *t;
t = change_value_var (O->left, X);
if (!t) { return 0;}
if (t == (void *)-1l) {
t = change_value_var (O->right, X);
if (!t) { return 0;}
if (t == (void *)-1l) { return (void *)-1l; }
if (t != (void *)-2l) { return t;}
return (void *)-1l;
}
if (t != (void *)-2l) {
O->left = t;
}
t = change_value_var (O->right, X);
if (!t) { return 0;}
if (t == (void *)-1l) {
return O->left;
}
if (t != (void *)-2l) {
O->right = t;
}
return O;
}
int tl_parse_partial_type_app_decl (struct tree *T) {
assert (T->type == type_partial_type_app_decl);
assert (T->nc >= 1);
assert (T->c[0]->type == type_boxed_type_ident);
struct tl_type *t = tl_get_type (T->c[0]->text, T->c[0]->len);
if (!t) {
TL_ERROR ("Can not make partial app for unknown type\n");
return 0;
}
tl_type_finalize (t);
struct tl_combinator_tree *L = tl_parse_ident (T->c[0], 0);
assert (L);
int i;
tl_buf_reset ();
int cc = T->nc - 1;
for (i = 1; i < T->nc; i++) {
TL_TRY (tl_parse_any_term (T->c[i], 0), L);
tl_buf_add_tree (L->right, 1);
}
while (L->type_len) {
struct tl_combinator_tree *C = alloc_ctree_node ();
C->act = act_var;
C->type = (L->type_flags & 1) ? type_num : type_type;
C->type_len = 0;
C->type_flags = 0;
C->data = (void *)-1l;
L = tl_union (L, C);
if (!L) { return 0; }
}
static char _buf[100000];
snprintf (_buf, 100000, "%s%.*s", t->id, buf_pos, buf);
struct tl_type *nt = tl_add_type (_buf, strlen (_buf), t->params_num - cc, t->params_types >> cc);
assert (nt);
//snprintf (_buf, 100000, "%s #", t->id);
//nt->real_id = strdup (_buf);
for (i = 0; i < t->constructors_num; i++) {
struct tl_constructor *c = t->constructors[i];
struct tree_var_value *V = 0;
TL_INIT (A);
TL_INIT (B);
A = tl_tree_dup (c->left);
B = tl_tree_dup (c->right);
struct tree_var_value *W = 0;
change_var_ptrs (c->left, A, &W);
change_var_ptrs (c->right, B, &W);
if (!check_constructors_equal (B, L, &V)) { continue; }
B = reduce_type (B, nt);
A = change_value_var (A, &V);
if (A == (void *)-1l) { A = 0;}
B = change_value_var (B, &V);
assert (B != (void *)-1l);
snprintf (_buf, 100000, "%s%.*s", c->id, buf_pos, buf);
struct tl_constructor *r = tl_add_constructor (nt, _buf, strlen (_buf), 1);
snprintf (_buf, 100000, "%s", c->id);
r->real_id = tstrdup (_buf);
r->left = A;
r->right = B;
if (!r->name) {
tl_count_combinator_name (r);
}
tl_print_combinator (r);
}
return 1;
}
int tl_parse_partial_comb_app_decl (struct tree *T, int fun) {
assert (T->type == type_partial_comb_app_decl);
struct tl_constructor *c = !fun ? tl_get_constructor (T->c[0]->text, T->c[0]->len) : tl_get_function (T->c[0]->text, T->c[0]->len);
if (!c) {
TL_ERROR ("Can not make partial app for undefined combinator\n");
return 0;
}
//TL_INIT (K);
//static char buf[1000];
//int x = sprintf (buf, "%s", c->id);
TL_INIT (L);
TL_INIT (R);
L = tl_tree_dup (c->left);
R = tl_tree_dup (c->right);
struct tree_var_value *V = 0;
change_var_ptrs (c->left, L, &V);
change_var_ptrs (c->right, R, &V);
V = tree_clear_var_value (V);
int i;
tl_buf_reset ();
for (i = 1; i < T->nc; i++) {
TL_INIT (X);
TL_INIT (Z);
X = tl_parse_any_term (T->c[i], 0);
struct tl_combinator_tree *K = 0;
if (!(Z = change_first_var (L, &K, X))) {
TL_FAIL;
}
L = Z;
if (!K) {
TL_ERROR ("Partial app: not enougth variables (i = %d)\n", i);
TL_FAIL;
}
if (!(Z = change_first_var (R, &K, X))) {
TL_FAIL;
}
assert (Z == R);
tl_buf_add_tree (X, 1);
}
static char _buf[100000];
snprintf (_buf, 100000, "%s%.*s", c->id, buf_pos, buf);
// fprintf (stderr, "Local id: %s\n", _buf);
struct tl_constructor *r = !fun ? tl_add_constructor (c->type, _buf, strlen (_buf), 1) : tl_add_function (c->type, _buf, strlen (_buf), 1);
r->left = L;
r->right = R;
snprintf (_buf, 100000, "%s", c->id);
r->real_id = tstrdup (_buf);
if (!r->name) {
tl_count_combinator_name (r);
}
tl_print_combinator (r);
return 1;
}
int tl_parse_partial_app_decl (struct tree *T, int fun) {
assert (T->type == type_partial_app_decl);
assert (T->nc == 1);
if (T->c[0]->type == type_partial_comb_app_decl) {
return tl_parse_partial_comb_app_decl (T->c[0], fun);
} else {
if (fun) {
TL_ERROR ("Partial type app in functions block\n");
TL_FAIL;
}
return tl_parse_partial_type_app_decl (T->c[0]);
}
}
int tl_parse_final_final (struct tree *T) {
assert (T->type == type_final_final);
assert (T->nc == 1);
struct tl_type *R;
if ((R = tl_get_type (T->c[0]->text, T->c[0]->len))) {
R->flags |= 1;
return 1;
} else {
TL_ERROR ("Final statement for type `%.*s` before declaration\n", T->c[0]->len, T->c[0]->text);
TL_FAIL;
}
}
int tl_parse_final_new (struct tree *T) {
assert (T->type == type_final_new);
assert (T->nc == 1);
if (tl_get_type (T->c[0]->text, T->c[0]->len)) {
TL_ERROR ("New statement: type `%.*s` already declared\n", T->c[0]->len, T->c[0]->text);
TL_FAIL;
} else {
return 1;
}
}
int tl_parse_final_empty (struct tree *T) {
assert (T->type == type_final_empty);
assert (T->nc == 1);
if (tl_get_type (T->c[0]->text, T->c[0]->len)) {
TL_ERROR ("New statement: type `%.*s` already declared\n", T->c[0]->len, T->c[0]->text);
TL_FAIL;
}
struct tl_type *t = tl_add_type (T->c[0]->text, T->c[0]->len, 0, 0);
assert (t);
t->flags |= 1 | FLAG_EMPTY;
return 1;
}
int tl_parse_final_decl (struct tree *T, int fun) {
assert (T->type == type_final_decl);
assert (!fun);
assert (T->nc == 1);
switch (T->c[0]->type) {
case type_final_new:
return tl_parse_final_new (T->c[0]);
case type_final_final:
return tl_parse_final_final (T->c[0]);
case type_final_empty:
return tl_parse_final_empty (T->c[0]);
default:
assert (0);
return 0;
}
}
int tl_parse_builtin_combinator_decl (struct tree *T, int fun) {
if (fun) {
TL_ERROR ("Builtin type can not be described in function block\n");
return -1;
}
assert (T->type == type_builtin_combinator_decl);
assert (T->nc == 2);
assert (T->c[0]->type == type_full_combinator_id);
assert (T->c[1]->type == type_boxed_type_ident);
if ((!mystrcmp2 (T->c[0]->text, T->c[0]->len, "int") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Int")) ||
(!mystrcmp2 (T->c[0]->text, T->c[0]->len, "long") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Long")) ||
(!mystrcmp2 (T->c[0]->text, T->c[0]->len, "double") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Double")) ||
(!mystrcmp2 (T->c[0]->text, T->c[0]->len, "string") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "String"))) {
struct tl_type *t = tl_add_type (T->c[1]->text, T->c[1]->len, 0, 0);
if (!t) {
return 0;
}
struct tl_constructor *c = tl_add_constructor (t, T->c[0]->text, T->c[0]->len, 0);
if (!c) {
return 0;
}
c->left = alloc_ctree_node ();
c->left->act = act_question_mark;
c->left->type = type_list_item;
c->right = alloc_ctree_node ();
c->right->act = act_type;
c->right->data = t;
c->right->type = type_type;
if (!c->name) {
tl_count_combinator_name (c);
}
tl_print_combinator (c);
} else {
TL_ERROR ("Unknown builting type `%.*s`\n", T->c[0]->len, T->c[0]->text);
return 0;
}
return 1;
}
int tl_parse_declaration (struct tree *T, int fun) {
assert (T->type == type_declaration);
assert (T->nc == 1);
switch (T->c[0]->type) {
case type_combinator_decl:
return tl_parse_combinator_decl (T->c[0], fun);
case type_partial_app_decl:
return tl_parse_partial_app_decl (T->c[0], fun);
case type_final_decl:
return tl_parse_final_decl (T->c[0], fun);
case type_builtin_combinator_decl:
return tl_parse_builtin_combinator_decl (T->c[0], fun);
default:
assert (0);
return 0;
}
}
int tl_parse_constr_declarations (struct tree *T) {
assert (T->type == type_constr_declarations);
int i;
for (i = 0; i < T->nc; i++) {
TL_TRY_PES (tl_parse_declaration (T->c[i], 0));
}
return 1;
}
int tl_parse_fun_declarations (struct tree *T) {
assert (T->type == type_fun_declarations);
int i;
for (i = 0; i < T->nc; i++) {
TL_TRY_PES (tl_parse_declaration (T->c[i], 1));
}
return 1;
}
int tl_tree_lookup_value (struct tl_combinator_tree *L, void *var, struct tree_var_value **T) {
if (!L) {
return -1;
}
if (L->act == act_var && L->data == var) {
return 0;
}
if (L->act == act_var) {
struct tl_combinator_tree *E = tl_get_var_value (T, L->data);
if (!E) { return -1;}
else { return tl_tree_lookup_value (E, var, T); }
}
if (tl_tree_lookup_value (L->left, var, T) >= 0) { return 1; }
if (tl_tree_lookup_value (L->right, var, T) >= 0) { return 1; }
return -1;
}
int tl_tree_lookup_value_nat (struct tl_combinator_tree *L, void *var, long long x, struct tree_var_value **T) {
assert (L);
if (L->type == type_num_value) { return -1; }
assert (L->type == type_num);
assert (L->act == act_var);
if (L->data == var) {
return x == L->type_flags ? 0 : 1;
} else {
if (!tl_get_var_value (T, L->data)) {
return -1;
}
return tl_tree_lookup_value_nat (tl_get_var_value (T, L->data), var, x + tl_get_var_value_num (T, L->data), T);
}
}
int uniformize (struct tl_combinator_tree *L, struct tl_combinator_tree *R, struct tree_var_value **T) {
if (!L || !R) {
assert (!L && !R);
return 1;
}
if (R->act == act_var) {
struct tl_combinator_tree *_ = R; R = L; L = _;
}
if (L->type == type_type) {
if (R->type != type_type || L->type_len != R->type_len || L->type_flags != R->type_flags) {
return 0;
}
if (R->data == (void *)-1l || L->data == (void *)-1l) { return 1;}
if (L->act == act_var) {
int x = tl_tree_lookup_value (R, L->data, T);
if (x > 0) {
// if (tl_tree_lookup_value (R, L->data, T) > 0) {
return 0;
}
if (x == 0) {
return 1;
}
struct tl_combinator_tree *E = tl_get_var_value (T, L->data);
if (!E) {
tl_set_var_value (T, L->data, R);
return 1;
} else {
return uniformize (E, R, T);
}
} else {
if (L->act != R->act || L->data != R->data) {
return 0;
}
return uniformize (L->left, R->left, T) && uniformize (L->right, R->right, T);
}
} else {
assert (L->type == type_num || L->type == type_num_value);
if (R->type != type_num && R->type != type_num_value) {
return 0;
}
assert (R->type == type_num || R->type == type_num_value);
if (R->data == (void *)-1l || L->data == (void *)-1l) { return 1;}
long long x = 0;
struct tl_combinator_tree *K = L;
while (1) {
x += K->type_flags;
if (K->type == type_num_value) {
break;
}
if (!tl_get_var_value (T, K->data)) {
int s = tl_tree_lookup_value_nat (R, K->data, K->type_flags, T);
if (s > 0) {
return 0;
}
if (s == 0) {
return 1;
}
/*tl_set_var_value_num (T, K->data, R, -x);
return 1;*/
break;
}
x += tl_get_var_value_num (T, K->data);
K = tl_get_var_value (T, K->data);
}
long long y = 0;
struct tl_combinator_tree *M = R;
while (1) {
y += M->type_flags;
if (M->type == type_num_value) {
break;
}
if (!tl_get_var_value (T, M->data)) {
int s = tl_tree_lookup_value_nat (L, M->data, M->type_flags, T);
if (s > 0) {
return 0;
}
if (s == 0) {
return 1;
}
/*tl_set_var_value_num (T, M->data, L, -y);
return 1;*/
break;
}
y += tl_get_var_value_num (T, M->data);
M = tl_get_var_value (T, M->data);
}
if (K->type == type_num_value && M->type == type_num_value) {
return x == y;
}
if (M->type == type_num_value) {
tl_set_var_value_num (T, K->data, M, -(x - y + M->type_flags));
return 1;
} else if (K->type == type_num_value) {
tl_set_var_value_num (T, M->data, K, -(y - x + K->type_flags));
return 1;
} else {
if (x >= y) {
tl_set_var_value_num (T, K->data, M, -(x - y + M->type_flags));
} else {
tl_set_var_value_num (T, M->data, K, -(y - x + K->type_flags));
}
return 1;
}
}
return 0;
}
void tl_type_check (struct tl_type *t) {
if (!__ok) return;
if (!strcmp (t->id, "#")) { t->name = 0x70659eff; return; }
if (!strcmp (t->id, "Type")) { t->name = 0x2cecf817; return; }
if (t->constructors_num <= 0 && !(t->flags & FLAG_EMPTY)) {
TL_ERROR ("Type %s has no constructors\n", t->id);
__ok = 0;
return;
}
int i, j;
t->name = 0;
for (i = 0; i < t->constructors_num; i++) {
t->name ^= t->constructors[i]->name;
}
for (i = 0; i < t->constructors_num; i++) {
for (j = i + 1; j < t->constructors_num; j++) {
struct tree_var_value *v = 0;
if (check_constructors_equal (t->constructors[i]->right, t->constructors[j]->right, &v)) {
t->flags |= 16;
}
}
}
if ((t->flags & 24) == 24) {
TL_WARNING ("Warning: Type %s has overlapping costructors, but it is used with `%%`\n", t->id);
}
int z = 0;
int sid = 0;
for (i = 0; i < t->constructors_num; i++) if (*t->constructors[i]->id == '_') {
z ++;
sid = i;
}
if (z > 1) {
TL_ERROR ("Type %s has %d default constructors\n", t->id, z);
__ok = 0;
return;
}
if (z == 1 && (t->flags & 8)) {
TL_ERROR ("Type %s has default constructors and used bare\n", t->id);
__ok = 0;
return;
}
if (z) {
struct tl_constructor *c;
c = t->constructors[sid];
t->constructors[sid] = t->constructors[t->constructors_num - 1];
t->constructors[t->constructors_num - 1] = c;
}
}
struct tl_program *tl_parse (struct tree *T) {
assert (T);
assert (T->type == type_tl_program);
int i;
tl_program_cur = talloc (sizeof (*tl_program_cur));
tl_add_type ("#", 1, 0, 0);
tl_add_type ("Type", 4, 0, 0);
for (i = 0; i < T->nc; i++) {
if (T->c[i]->type == type_constr_declarations) { TL_TRY_PES (tl_parse_constr_declarations (T->c[i])); }
else { TL_TRY_PES (tl_parse_fun_declarations (T->c[i])) }
}
__ok = 1;
tree_act_tl_type (tl_type_tree, tl_type_check);
if (!__ok) {
return 0;
}
return tl_program_cur;
}
int __f;
int num = 0;
void wint (int a) {
// printf ("%d ", a);
assert (write (__f, &a, 4) == 4);
}
void wdata (const void *x, int len) {
assert (write (__f, x, len) == len);
}
void wstr (const char *s) {
if (s) {
// printf ("\"%s\" ", s);
if (schema_version < 1) {
wint (strlen (s));
wdata (s, strlen (s));
} else {
int x = strlen (s);
if (x <= 254) {
assert (write (__f, &x, 1) == 1);
} else {
fprintf (stderr, "String is too big...\n");
assert (0);
}
wdata (s, x);
x ++;
int t = 0;
if (x & 3) {
wdata (&t, 4 - (x & 3));
}
}
} else {
// printf ("<none> ");
wint (0);
}
}
void wll (long long a) {
// printf ("%lld ", a);
assert (write (__f, &a, 8) == 8);
}
int count_list_size (struct tl_combinator_tree *T) {
assert (T->type == type_list || T->type == type_list_item);
if (T->type == type_list_item) {
return 1;
} else {
return count_list_size (T->left) + count_list_size (T->right);
}
}
void write_type_flags (long long flags) {
int new_flags = 0;
if (flags & 1) {
new_flags |= FLAG_BARE;
}
if (flags & FLAG_DEFAULT_CONSTRUCTOR) {
new_flags |= FLAG_DEFAULT_CONSTRUCTOR;
}
wint (new_flags);
}
void write_field_flags (long long flags) {
int new_flags = 0;
//fprintf (stderr, "%lld\n", flags);
if (flags & 1) {
new_flags |= FLAG_BARE;
}
if (flags & 32) {
new_flags |= FLAG_OPT_VAR;
}
if (flags & FLAG_EXCL) {
new_flags |= FLAG_EXCL;
}
if (flags & FLAG_OPT_FIELD) {
// new_flags |= FLAG_OPT_FIELD;
new_flags |= 2;
}
if (flags & (1 << 21)) {
new_flags |= 4;
}
wint (new_flags);
}
void write_var_type_flags (long long flags) {
int new_flags = 0;
if (flags & 1) {
new_flags |= FLAG_BARE;
}
if (new_flags & FLAG_BARE) {
TL_ERROR ("Sorry, bare vars are not (yet ?) supported.\n");
assert (!(new_flags & FLAG_BARE));
}
wint (new_flags);
}
void write_tree (struct tl_combinator_tree *T, int extra, struct tree_var_value **v, int *last_var);
void write_args (struct tl_combinator_tree *T, struct tree_var_value **v, int *last_var) {
assert (T->type == type_list || T->type == type_list_item);
if (T->type == type_list) {
assert (T->act == act_union);
assert (T->left);
assert (T->right);
write_args (T->left, v, last_var);
write_args (T->right, v, last_var);
return;
}
if (schema_version == 1) {
wint (TLS_ARG);
} if (schema_version == 2) {
wint (TLS_ARG_V2);
} else {
wint (-3);
}
if (T->act == act_question_mark) {
if (schema_version >= 1) {
assert (0);
} else {
wint (-100);
}
return;
}
if (schema_version >= 1) {
} else {
wint (-99);
}
assert (T->act == act_field);
assert (T->left);
wstr (T->data && strcmp (T->data, "_") ? T->data : 0);
long long f = T->flags;
if (T->left->act == act_opt_field) {
f |= (1 << 20);
}
if (T->left->act == act_type && T->left->data && (!strcmp (((struct tl_type *)T->left->data)->id, "#") || !strcmp (((struct tl_type *)T->left->data)->id, "Type"))) {
write_field_flags (f | (1 << 21));
wint (*last_var);
*last_var = (*last_var) + 1;
tl_set_var_value_num (v, T, 0, (*last_var) - 1);
} else {
write_field_flags (f);
if (schema_version <= 1) {
wint (-1);
}
}
write_tree (T->left, 0, v, last_var);
}
void write_array (struct tl_combinator_tree *T, struct tree_var_value **v, int *last_var) {
if (schema_version == 1) {
wint (TLS_TREE_ARRAY);
} else if (schema_version == 2) {
wint (TLS_ARRAY);
} else {
wint (-8);
}
write_tree (T->left, 0, v, last_var);
write_tree (T->right, 0, v, last_var);
}
void write_type_rec (struct tl_combinator_tree *T, int cc, struct tree_var_value **v, int *last_var) {
if (T->act == act_arg) {
write_type_rec (T->left, cc + 1, v, last_var);
if (schema_version >= 2) {
if (T->right->type == type_num_value || T->right->type == type_num) {
wint (TLS_EXPR_NAT);
} else {
wint (TLS_EXPR_TYPE);
}
}
write_tree (T->right, 0, v, last_var);
} else {
assert (T->act == act_var || T->act == act_type);
if (T->act == act_var) {
assert (!cc);
if (schema_version == 1) {
wint (TLS_TREE_TYPE_VAR);
} else if (schema_version == 2) {
wint (TLS_TYPE_VAR);
} else {
wint (-6);
}
wint (tl_get_var_value_num (v, T->data));
write_var_type_flags (T->flags);
//wint (T->flags);
} else {
if (schema_version == 1) {
wint (TLS_TREE_TYPE);
} else if (schema_version == 2) {
wint (TLS_TYPE_EXPR);
} else {
wint (-7);
}
struct tl_type *t = T->data;
wint (t->name);
write_type_flags (T->flags);
// wint (T->flags);
wint (cc);
// fprintf (stderr, "cc = %d\n", cc);
}
}
}
void write_opt_type (struct tl_combinator_tree *T, struct tree_var_value **v, int *last_var) {
if (schema_version >= 1) {
} else {
wint (-20);
}
wint (tl_get_var_value_num (v, T->left->data));
wint (T->left->type_flags);
// write_tree (T->right, 0, v, last_var);
assert (T);
T = T->right;
switch (T->type) {
case type_type:
if (T->act == act_array) {
write_array (T, v, last_var);
} else if (T->act == act_type || T->act == act_var || T->act == act_arg) {
write_type_rec (T, 0, v, last_var);
} else {
assert (0);
}
break;
default:
assert (0);
}
}
void write_tree (struct tl_combinator_tree *T, int extra, struct tree_var_value **v, int *last_var) {
assert (T);
switch (T->type) {
case type_list_item:
case type_list:
if (schema_version >= 1) {
if (extra) {
wint (schema_version >= 2 ? TLS_COMBINATOR_RIGHT_V2 : TLS_COMBINATOR_RIGHT);
}
} else {
wint (extra ? -1 : -2);
}
wint (count_list_size (T));
write_args (T, v, last_var);
break;
case type_num_value:
wint (schema_version >= 1 ? schema_version >= 2 ? (int)TLS_NAT_CONST : (int)TLS_TREE_NAT_CONST : -4);
if (schema_version >= 2) {
wint (T->type_flags);
} else {
wll (T->type_flags);
}
break;
case type_num:
wint (schema_version >= 1 ? schema_version >= 2 ? (int)TLS_NAT_VAR : (int)TLS_TREE_NAT_VAR : -5);
if (schema_version >= 2) {
wint (T->type_flags);
} else {
wll (T->type_flags);
}
wint (tl_get_var_value_num (v, T->data));
break;
case type_type:
if (T->act == act_array) {
write_array (T, v, last_var);
} else if (T->act == act_type || T->act == act_var || T->act == act_arg) {
write_type_rec (T, 0, v, last_var);
} else {
assert (T->act == act_opt_field);
write_opt_type (T, v, last_var);
}
break;
default:
assert (0);
}
}
void write_type (struct tl_type *t) {
wint (schema_version >= 1 ? TLS_TYPE : 1);
wint (t->name);
wstr (t->id);
wint (t->constructors_num);
wint (t->flags);
wint (t->params_num);
wll (t->params_types);
}
int is_builtin_type (const char *id) {
return !strcmp (id, "int") || !strcmp (id, "long") || !strcmp (id, "double") || !strcmp (id, "string");
}
void write_combinator (struct tl_constructor *c) {
wint (c->name);
wstr (c->id);
wint (c->type ? c->type->name : 0);
struct tree_var_value *T = 0;
int x = 0;
assert (c->right);
if (c->left) {
if (schema_version >= 1 && is_builtin_type (c->id)) {
wint (TLS_COMBINATOR_LEFT_BUILTIN);
} else {
if (schema_version >= 1) {
wint (TLS_COMBINATOR_LEFT);
}
// wint (count_list_size (c->left));
write_tree (c->left, 0, &T, &x);
}
} else {
if (schema_version >= 1) {
wint (TLS_COMBINATOR_LEFT);
wint (0);
} else {
wint (-11);
}
}
if (schema_version >= 1) {
wint (schema_version >= 2 ? TLS_COMBINATOR_RIGHT_V2 : TLS_COMBINATOR_RIGHT);
}
write_tree (c->right, 1, &T, &x);
}
void write_constructor (struct tl_constructor *c) {
wint (schema_version >= 1 ? TLS_COMBINATOR : 2);
write_combinator (c);
}
void write_function (struct tl_constructor *c) {
wint (schema_version >= 1 ? TLS_COMBINATOR : 3);
write_combinator (c);
}
void write_type_constructors (struct tl_type *t) {
int i;
for (i = 0; i < t->constructors_num; i++) {
write_constructor (t->constructors[i]);
}
}
int MAGIC = 0x850230aa;
void write_types (int f) {
__f = f;
if (schema_version == 1) {
wint (TLS_SCHEMA);
} else if (schema_version == 2) {
wint (TLS_SCHEMA_V2);
} else {
wint (MAGIC);
}
if (schema_version >= 1) {
wint (0);
wint (time (0));
}
num = 0;
if (schema_version >= 1) {
wint (total_types_num);
}
tree_act_tl_type (tl_type_tree, write_type);
if (schema_version >= 1) {
wint (total_constructors_num);
}
tree_act_tl_type (tl_type_tree, write_type_constructors);
if (schema_version >= 1) {
wint (total_functions_num);
}
tree_act_tl_constructor (tl_function_tree, write_function);
}
/*
This file is part of tgl-libary/tlc
Tgl-library/tlc is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Tgl-library/tlc is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this tgl-library/tlc. If not, see <http://www.gnu.org/licenses/>.
Copyright Vitaly Valtman 2014
It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/)
Copyright 2012-2013 Vkontakte Ltd
2012-2013 Vitaliy Valtman
*/
#ifndef __TL_PARSER_NEW_H__
#define __TL_PARSER_NEW_H__
enum lex_type {
lex_error,
lex_char,
lex_triple_minus,
lex_uc_ident,
lex_lc_ident,
lex_eof,
lex_final,
lex_new,
lex_none,
lex_num,
lex_empty
};
struct curlex {
char *ptr;
int len;
enum lex_type type;
int flags;
};
struct parse {
char *text;
int pos;
int len;
int line;
int line_pos;
struct curlex lex;
};
enum tree_type {
type_tl_program,
type_fun_declarations,
type_constr_declarations,
type_declaration,
type_combinator_decl,
type_equals,
type_partial_app_decl,
type_final_decl,
type_full_combinator_id,
type_opt_args,
type_args,
type_args1,
type_args2,
type_args3,
type_args4,
type_boxed_type_ident,
type_subexpr,
type_partial_comb_app_decl,
type_partial_type_app_decl,
type_final_new,
type_final_final,
type_final_empty,
// type_type,
type_var_ident,
type_var_ident_opt,
type_multiplicity,
type_type_term,
type_term,
type_percent,
type_result_type,
type_expr,
type_nat_term,
type_combinator_id,
type_nat_const,
type_type_ident,
type_builtin_combinator_decl,
type_exclam,
type_optional_arg_def
};
struct tree {
char *text;
int len;
enum tree_type type;
int lex_line;
int lex_line_pos;
int flags;
int size;
int nc;
struct tree **c;
};
#define TL_ACT(x) (x == act_var ? "act_var" : x == act_field ? "act_field" : x == act_plus ? "act_plus" : x == act_type ? "act_type" : x == act_nat_const ? "act_nat_const" : x == act_array ? "act_array" : x == act_question_mark ? "act_question_mark" : \
x == act_union ? "act_union" : x == act_arg ? "act_arg" : x == act_opt_field ? "act_opt_field" : "act_unknown")
#define TL_TYPE(x) (x == type_num ? "type_num" : x == type_type ? "type_type" : x == type_list_item ? "type_list_item" : x == type_list ? "type_list" : x == type_num_value ? "type_num_value" : "type_unknown")
enum combinator_tree_action {
act_var,
act_field,
act_plus,
act_type,
act_nat_const,
act_array,
act_question_mark,
act_union,
act_arg,
act_opt_field
};
enum combinator_tree_type {
type_num,
type_num_value,
type_type,
type_list_item,
type_list
};
struct tl_combinator_tree {
enum combinator_tree_action act;
struct tl_combinator_tree *left, *right;
char *name;
void *data;
long long flags;
enum combinator_tree_type type;
int type_len;
long long type_flags;
};
struct tl_program {
int types_num;
int functions_num;
int constructors_num;
struct tl_type **types;
struct tl_function **functions;
// struct tl_constuctor **constructors;
};
struct tl_type {
char *id;
char *print_id;
char *real_id;
unsigned name;
int flags;
int params_num;
long long params_types;
int constructors_num;
struct tl_constructor **constructors;
};
struct tl_constructor {
char *id;
char *print_id;
char *real_id;
unsigned name;
struct tl_type *type;
struct tl_combinator_tree *left;
struct tl_combinator_tree *right;
};
struct tl_var {
char *id;
struct tl_combinator_tree *ptr;
int type;
int flags;
};
struct parse *tl_init_parse_file (const char *fname);
struct tree *tl_parse_lex (struct parse *P);
void tl_print_parse_error (void);
struct tl_program *tl_parse (struct tree *T);
void write_types (int f);
#define FLAG_BARE 1
#define FLAG_OPT_VAR (1 << 17)
#define FLAG_EXCL (1 << 18)
#define FLAG_OPT_FIELD (1 << 20)
#define FLAG_IS_VAR (1 << 21)
#define FLAG_DEFAULT_CONSTRUCTOR (1 << 25)
#define FLAG_EMPTY (1 << 10)
#endif
/*
This file is part of VK/KittenPHP-DB-Engine.
VK/KittenPHP-DB-Engine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
VK/KittenPHP-DB-Engine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with VK/KittenPHP-DB-Engine. If not, see <http://www.gnu.org/licenses/>.
This program is released under the GPL with the additional exemption
that compiling, linking, and/or using OpenSSL is allowed.
You are free to remove this exemption from derived works.
Copyright 2012-2013 Vkontakte Ltd
2012-2013 Vitaliy Valtman
*/
#ifndef __TL_TL_H__
#define __TL_TL_H__
#define TLS_SCHEMA 0xf19d9e38
#define TLS_TYPE 0x12eb4386
#define TLS_COMBINATOR 0x5c0a1ed5
#define TLS_COMBINATOR_LEFT_BUILTIN 0xcd211f63
#define TLS_COMBINATOR_LEFT 0x4c12c6d9
#define TLS_COMBINATOR_RIGHT 0xd325b367
#define TLS_ARG 0x46afe232
#define TLS_TREE_NAT_CONST 0xc09f07d7
#define TLS_TREE_NAT_VAR 0x90ea6f58
#define TLS_TREE_TYPE_VAR 0x1caa237a
#define TLS_TREE_ARRAY 0x80479360
#define TLS_TREE_TYPE 0x10f32190
#define TLS_SCHEMA_V2 0x3a2f9be2
#define TLS_COMBINATOR_RIGHT_V2 0x2c064372
#define TLS_ARG_V2 0x29dfe61b
#define TLS_EXPR_TYPE 0xecc9da78
#define TLS_EXPR_NAT 0xdcb49bd8
#define TLS_NAT_CONST 0xdcb49bd8
#define TLS_NAT_VAR 0x4e8a14f0
#define TLS_TYPE_VAR 0x0142ceae
#define TLS_ARRAY 0xd9fb20de
#define TLS_TYPE_EXPR 0xc1863d08
#endif
/*
This file is part of tgl-libary/tlc
Tgl-library/tlc is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Tgl-library/tlc is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this tgl-library/tlc. If not, see <http://www.gnu.org/licenses/>.
Copyright Vitaly Valtman 2014
It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/)
Copyright 2012-2013 Vkontakte Ltd
2012-2013 Vitaliy Valtman
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "tl-parser.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include "config.h"
#include <execinfo.h>
#include <stdarg.h>
int verbosity;
int output_expressions;
int schema_version = 2;
void usage (void) {
printf ("usage: tlc [-v] [-h] <TL-schema-file>\n"
"\tTL compiler\n"
"\t-v\toutput statistical and debug information into stderr\n"
"\t-E\twhenever is possible output to stdout expressions\n"
"\t-e <file>\texport serialized schema to file\n"
"\t-w\t custom version of serialized schema (0 - very old, 1 - old, 2 - current (default))\n"
);
exit (2);
}
int vkext_write (const char *filename) {
int f = open (filename, O_CREAT | O_WRONLY | O_TRUNC, 0640);
assert (f >= 0);
write_types (f);
close (f);
return 0;
}
void logprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
void logprintf (const char *format __attribute__ ((unused)), ...) {
va_list ap;
va_start (ap, format);
vfprintf (stderr, format, ap);
va_end (ap);
}
void hexdump (int *in_ptr, int *in_end) {
int *ptr = in_ptr;
while (ptr < in_end) { printf (" %08x", *(ptr ++)); }
printf ("\n");
}
#ifdef HAVE_EXECINFO_H
void print_backtrace (void) {
void *buffer[255];
const int calls = backtrace (buffer, sizeof (buffer) / sizeof (void *));
backtrace_symbols_fd (buffer, calls, 1);
}
#else
void print_backtrace (void) {
if (write (1, "No libexec. Backtrace disabled\n", 32) < 0) {
// Sad thing
}
}
#endif
void sig_segv_handler (int signum __attribute__ ((unused))) {
if (write (1, "SIGSEGV received\n", 18) < 0) {
// Sad thing
}
print_backtrace ();
exit (EXIT_FAILURE);
}
void sig_abrt_handler (int signum __attribute__ ((unused))) {
if (write (1, "SIGABRT received\n", 18) < 0) {
// Sad thing
}
print_backtrace ();
exit (EXIT_FAILURE);
}
int main (int argc, char **argv) {
signal (SIGSEGV, sig_segv_handler);
signal (SIGABRT, sig_abrt_handler);
int i;
char *vkext_file = 0;
while ((i = getopt (argc, argv, "Ehve:w:")) != -1) {
switch (i) {
case 'E':
output_expressions++;
break;
case 'h':
usage ();
return 2;
case 'e':
vkext_file = optarg;
break;
case 'w':
schema_version = atoi (optarg);
break;
case 'v':
verbosity++;
break;
}
}
if (argc != optind + 1) {
usage ();
}
struct parse *P = tl_init_parse_file (argv[optind]);
if (!P) {
return 0;
}
struct tree *T;
if (!(T = tl_parse_lex (P))) {
fprintf (stderr, "Error in parse:\n");
tl_print_parse_error ();
return 0;
} else {
if (verbosity) {
fprintf (stderr, "Parse ok\n");
}
if (!tl_parse (T)) {
if (verbosity) {
fprintf (stderr, "Fail\n");
}
return 1;
} else {
if (verbosity) {
fprintf (stderr, "Ok\n");
}
}
}
if (vkext_file) {
vkext_write (vkext_file);
}
return 0;
}
/*
This file is part of tgl-library
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Copyright Vitaly Valtman 2013-2014
*/
#ifndef __TREE_H__
#define __TREE_H__
#include <stdio.h>
#include <memory.h>
#include <assert.h>
#include "tools.h"
#pragma pack(push,4)
#define DEFINE_TREE(X_NAME, X_TYPE, X_CMP, X_UNSET) \
struct tree_ ## X_NAME { \
struct tree_ ## X_NAME *left, *right;\
X_TYPE x;\
int y;\
};\
\
static struct tree_ ## X_NAME *new_tree_node_ ## X_NAME (X_TYPE x, int y) {\
struct tree_ ## X_NAME *T = talloc (sizeof (*T));\
T->x = x;\
T->y = y;\
T->left = T->right = 0;\
return T;\
}\
\
static void delete_tree_node_ ## X_NAME (struct tree_ ## X_NAME *T) {\
tfree (T, sizeof (*T));\
}\
\
static void tree_split_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, struct tree_ ## X_NAME **L, struct tree_ ## X_NAME **R) {\
if (!T) {\
*L = *R = 0;\
} else {\
int c = X_CMP (x, T->x);\
if (c < 0) {\
tree_split_ ## X_NAME (T->left, x, L, &T->left);\
*R = T;\
} else {\
tree_split_ ## X_NAME (T->right, x, &T->right, R);\
*L = T;\
}\
}\
}\
\
static struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) __attribute__ ((warn_unused_result,unused));\
static struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) {\
if (!T) {\
return new_tree_node_ ## X_NAME (x, y);\
} else {\
if (y > T->y) {\
struct tree_ ## X_NAME *N = new_tree_node_ ## X_NAME (x, y);\
tree_split_ ## X_NAME (T, x, &N->left, &N->right);\
return N;\
} else {\
int c = X_CMP (x, T->x);\
assert (c);\
if (c < 0) { \
T->left = tree_insert_ ## X_NAME (T->left, x, y);\
} else { \
T->right = tree_insert_ ## X_NAME (T->right, x, y);\
} \
return T; \
}\
}\
}\
\
static struct tree_ ## X_NAME *tree_merge_ ## X_NAME (struct tree_ ## X_NAME *L, struct tree_ ## X_NAME *R) {\
if (!L || !R) {\
return L ? L : R;\
} else {\
if (L->y > R->y) {\
L->right = tree_merge_ ## X_NAME (L->right, R);\
return L;\
} else {\
R->left = tree_merge_ ## X_NAME (L, R->left);\
return R;\
}\
}\
}\
\
static struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) __attribute__ ((warn_unused_result,unused));\
static struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\
assert (T);\
int c = X_CMP (x, T->x);\
if (!c) {\
struct tree_ ## X_NAME *N = tree_merge_ ## X_NAME (T->left, T->right);\
delete_tree_node_ ## X_NAME (T);\
return N;\
} else {\
if (c < 0) { \
T->left = tree_delete_ ## X_NAME (T->left, x); \
} else { \
T->right = tree_delete_ ## X_NAME (T->right, x); \
} \
return T; \
}\
}\
\
static X_TYPE tree_get_min_ ## X_NAME (struct tree_ ## X_NAME *t) __attribute__ ((unused));\
static X_TYPE tree_get_min_ ## X_NAME (struct tree_ ## X_NAME *T) {\
if (!T) { return X_UNSET; } \
while (T->left) { T = T->left; }\
return T->x; \
} \
\
static X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) __attribute__ ((unused));\
static X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\
int c;\
while (T && (c = X_CMP (x, T->x))) {\
T = (c < 0 ? T->left : T->right);\
}\
return T ? T->x : X_UNSET;\
}\
\
static void tree_act_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE)) __attribute__ ((unused));\
static void tree_act_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE)) {\
if (!T) { return; } \
tree_act_ ## X_NAME (T->left, act); \
act (T->x); \
tree_act_ ## X_NAME (T->right, act); \
}\
\
static void tree_act_ex_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE, void *), void *extra) __attribute__ ((unused));\
static void tree_act_ex_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE, void *), void *extra) {\
if (!T) { return; } \
tree_act_ex_ ## X_NAME (T->left, act, extra); \
act (T->x, extra); \
tree_act_ex_ ## X_NAME (T->right, act, extra); \
}\
\
static int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\
static int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) { \
if (!T) { return 0; }\
return 1 + tree_count_ ## X_NAME (T->left) + tree_count_ ## X_NAME (T->right); \
}\
static void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\
static void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) { \
if (!T) { return; }\
if (T->left) { \
assert (T->left->y <= T->y);\
assert (X_CMP (T->left->x, T->x) < 0); \
}\
if (T->right) { \
assert (T->right->y <= T->y);\
assert (X_CMP (T->right->x, T->x) > 0); \
}\
tree_check_ ## X_NAME (T->left); \
tree_check_ ## X_NAME (T->right); \
}\
static struct tree_ ## X_NAME *tree_clear_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\
static struct tree_ ## X_NAME *tree_clear_ ## X_NAME (struct tree_ ## X_NAME *T) { \
if (!T) { return 0; }\
tree_clear_ ## X_NAME (T->left); \
tree_clear_ ## X_NAME (T->right); \
delete_tree_node_ ## X_NAME (T); \
return 0; \
} \
#define int_cmp(a,b) ((a) - (b))
#pragma pack(pop)
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment