v4k-git-backup/tools/labs/meta_info.c

293 lines
9.3 KiB
C

//#define META_DEMO
#include "fwk.h"
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdio.h>
static
char *reformat(const char *text, const char *blacklist, const char *separator) {
char **list = strsplit(text, blacklist);
char *joint = strjoin(list, separator);
return joint;
}
const char *c_symbols = "{},>&/+=;:"; // "(){}[].,><&*/+=;:!~";
const char *c_symbols_extra = "{},>&/+=;:[]()"; // "(){}[].,><&*/+=;:!~";
const char *c_keywords[] = { "const","long","signed","unsigned","typedef" }; int num_keywords = 4;
typedef struct meta {
const char *name;
const char *tags;
} meta;
meta metas[2048] = {
/*00*/ {"typedef", ""},
/*01*/ {"enum", ""},
/*02*/ {"struct", ""},
/*03*/ {"function", ""},
/*04*/ {"bool", "default 0"},
/*05*/ {"false", "default 0 bits 1"},
/*06*/ {"true", "default 1 bits 1"},
/*07*/ {"char", "default 0 bits 8"},
/*08*/ {"int", "default 0"},
/*09*/ {"float", "default 0 bits 32"},
/*10*/ {"double", "default 0 bits 64"},
/*11*/ {"int8_t", "default 0 bits 8"},
/*12*/ {"int16_t", "default 0 bits 16"},
/*13*/ {"int32_t", "default 0 bits 32"},
/*14*/ {"int64_t", "default 0 bits 64"},
/*15*/ {"uint8_t", "default 0 bits 8 signed 0"},
/*16*/ {"uint16_t", "default 0 bits 16 signed 0"},
/*17*/ {"uint32_t", "default 0 bits 32 signed 0"},
/*18*/ {"uint64_t", "default 0 bits 64 signed 0"},
};
int meta_count = 19;
const char *meta_last_name = 0;
const char *meta_last_struct = 0;
meta* meta_find(const char *name) {
for( int i = 0; i < meta_count; ++i ) {
if( 0 == strcmp(name, metas[i].name) ) return &metas[i];
}
return 0;
}
meta* meta_add(const char *name, const char *subtype, const char *tags ) {
{ meta *t = meta_find(name); if( t ) return t; }
if( meta_count >= 2048 ) return 0;
meta t = { STRDUP(name), reformat(STRDUP(tags), " ", " ") };
metas[meta_count] = t;
meta_last_struct = !strcmp(subtype, "struct") ? name : meta_last_struct;
meta_last_name = !strcmp(subtype, "struct") || !strcmp(subtype, "enum") || !strcmp(subtype, "typedef") ? name : subtype;
return &metas[meta_count++];
}
char* meta_find_value(const char *name, const char *prop) {
meta *t = meta_find(name);
if( !t ) return 0;
char *found = strstr(t->tags, prop);
if( !found ) return 0;
static char copy[256] = {0}; // @fixme
strcpy(copy, found + strlen(prop) + 1);
for(int i=0; copy[i]; ++i) if(copy[i]==' ') { copy[i] = 0; break; }
return copy;
}
void meta_inspectf(FILE *fp) {
if( fp ) {
char buf[255+1];
while(fgets(buf, 255, fp)) {
char *mark = strstr(buf, "//""M");
if( !mark ) continue;
char *tags = mark + 3;
// must reset last_struct
if( strstr(buf, "typedef") ) {
meta_last_struct = 0; // typedef is a special case
}
// remove symbols
for( int i = 0; buf[i]; ++i ) {
// symbols off
if(strchr(&buf[i] < tags ? c_symbols : c_symbols_extra, buf[i])) { buf[i] = ' '; continue; }
}
// remove leading whitespaces
char *spc = buf;
while( spc && spc[0] && spc[0] <= 32 ) ++spc;
// remove trailing linefeeds and whitespaces
int len = strlen(buf);
while( len > 0 && buf[len-1] <= 32 ) buf[--len] = 0;
// split buffer into left|right buffers
char *left = spc, *right = tags; right[-1] = 0;
// remove left keywords
for( int i = 0; left[i]; ++i ) {
for(int j = 0; j < sizeof(c_keywords)/sizeof(0[c_keywords]); ++j) {
int kb = strlen(left+i);
int kl = strlen(c_keywords[j]);
if( kl <= kb && !memcmp(left+i, c_keywords[j], kl) ) {
memset(left+i, ' ', kl);
i += kl;
break;
}
}
}
// debug
// printf("%s <--> %s\n", left, right);
// add type
const char *meta_name = 0;
const char *meta_t = 0;
const char *meta_val = "";
array(char *) tokens = strsplit(left, " \t");
if(1) for( int i = 0, end = array_count(tokens); i < end; ++i ) {
/**/ if( strstr(tokens[i],"enum") ) meta_last_name = 0, meta_last_struct = 0, meta_t = "enum";
else if( strstr(tokens[i],"struct") ) meta_last_name = 0, meta_last_struct = 0, meta_t = "struct";
else if( strstr(tokens[i],"typedef") ) meta_last_name = 0, meta_last_struct = 0, meta_t = "typedef"; // trimmed. never happens
else if( strchr(tokens[i],'(') ) meta_last_name = 0, meta_last_struct = 0, meta_name = tokens[i], meta_t = "function";
else if( !meta_name ) meta_name = tokens[i];
else if( !meta_t ) meta_t = tokens[i];
}
if( meta_find(meta_name) ) {
const char *swap = meta_name;
meta_name = meta_t;
meta_t = swap;
}
// if !meta_find defer(meta_eval) && emit(warning) && keep(iterating);
bool is_pointer = strstr(meta_name, "*");
meta_name = (char *)reformat(meta_name, "*", "");
char *found_sqr = strstr(meta_name, "[");
int array_len = found_sqr ? atoi(found_sqr+1) : 0;
if( found_sqr ) *found_sqr = 0;
bool is_number = false;
char conv[32] = {0};
double dbl = atof(meta_t);
if(!is_number) { sprintf(conv, "%f", dbl); is_number = !strcmp(conv, meta_t); }
if(!is_number) { sprintf(conv, "%.f", dbl); is_number = !strcmp(conv, meta_t); }
if(is_number) {
meta_val = meta_t;
meta_t = meta_last_name;
}
char hints[256] = {0}, *p = hints;
if( 1 ) p += sprintf(p, "type %s ", meta_t);
if( is_pointer || array_len ) p += sprintf(p, "pointer %d ", 1);
if( array_len ) p += sprintf(p, "count %d ", array_len);
if( 1 ) p += sprintf(p, "%s ", tags);
if( meta_last_struct ) p += sprintf(p, "struct %s ", meta_last_struct);
if( meta_val[0] ) p += sprintf(p, "default %s ", meta_val);
meta_val = hints;
// inherited tags (from super type) at the very end, so overriden tags can be found at first place
if( meta_find(meta_t) )
p += sprintf(p, "%s ", meta_find(meta_t)->tags );
if( !meta_find(meta_name) ) {
meta_add(meta_name, meta_t, meta_val);
meta *t = meta_find(meta_name);
//printf("%s,%s\n", t->name, t->tags);
}
}
// clean state
meta_last_name = 0;
meta_last_struct = 0;
}
}
bool meta_save(FILE *fp) {
if( fp )
for( int i = 0; i < meta_count; ++i ) {
meta *t = &metas[i];
fprintf(fp, "%s %s\n", t->name, t->tags);
}
return !!fp;
}
bool meta_load(FILE *fp) {
if( fp ) {
meta_count = 0;
meta_last_name = 0;
meta_last_struct = 0;
char buf[2048+1];
while(fgets(buf, 2048, fp)) {
int bl = strlen(buf); while( bl && buf[bl] <= 32) buf[bl--] = 0;
char id[128];
sscanf(buf, "%s", id);
metas[ meta_count ].name = strdup(id);
metas[ meta_count ].tags = strdup(buf+strlen(id)+1);
++meta_count;
}
}
return !!fp;
}
void meta_inspect(const char *name) {
FILE *fp = fopen(name, "rb");
if( !fp ) return;
meta_inspectf(fp);
fclose(fp);
}
bool meta_savefile(const char *name) {
FILE *fp = fopen(name, "wb");
if( !fp ) return false;
meta_save(fp); fclose(fp);
return true;
}
bool meta_loadfile(const char *name) {
FILE *fp = fopen(name, "rb");
if( !fp ) return false;
meta_load(fp); fclose(fp);
return true;
}
#ifdef META_DEMO
#pragma once
typedef int my_array[8]; //M
typedef const char *string; //M
typedef enum Fruit { //M bits:8
Banana = -1, //M
Orange = 42 //M
} Fruit;
struct myObject { //M version:100
Fruit meal; //M default:Banana
int32_t hitpoints; //M default:100 zigzag:yes
float shininess; //M default:+3.5e2 min:0 max:1 fixed:yes
string text; //M default:"DEMO"
bool visible; //M bits:1 deprecated:1 version:001
char test; //M serialize:off
};
int print(int); //M const:true
typedef int dummy; //M extra=separators allowed(too)
int main(int argc, const char **argv) {
#ifndef NDEBUG
unlink(__FILE__ ".meta");
#endif
if( meta_loadfile(__FILE__ ".meta") ) {
puts("Loaded .meta file");
} else {
puts("Cannot read .meta file. regenerating...");
meta_inspect(__FILE__);
puts("Saving .meta file...");
meta_savefile(__FILE__ ".meta");
}
meta_save( stdout );
puts(meta_find_value("Orange", "type"));
puts(meta_find_value("Orange", "bits"));
puts(meta_find_value("Orange", "default"));
puts(meta_find_value("visible", "type"));
puts(meta_find_value("shininess", "fixed"));
}
#define main main__
#endif