| 1 | #include <stdio.h> |
|---|
| 2 | #include <stdlib.h> |
|---|
| 3 | #include <string.h> |
|---|
| 4 | #include <arbdb.h> |
|---|
| 5 | |
|---|
| 6 | #if defined(DEBUG) |
|---|
| 7 | // #define DUMP |
|---|
| 8 | #endif // DEBUG |
|---|
| 9 | |
|---|
| 10 | static char *filename = 0; |
|---|
| 11 | |
|---|
| 12 | static void error(const char *msg) { |
|---|
| 13 | fprintf(stderr, "%s:1: %s\n", filename, msg); |
|---|
| 14 | } |
|---|
| 15 | |
|---|
| 16 | int main(int argc, char **argv) |
|---|
| 17 | { |
|---|
| 18 | if (argc <= 2) { |
|---|
| 19 | fprintf(stderr,"arb_proto_2_xsub converts GB_prototypes to perl interface\n"); |
|---|
| 20 | fprintf(stderr,"Usage: arb_proto_2_xsub <prototypes.h> <xs-header>\n"); |
|---|
| 21 | fprintf(stderr,"<xs-header> may contain prototypes. Those will not be overwritten!!!\n"); |
|---|
| 22 | return(-1); |
|---|
| 23 | } |
|---|
| 24 | char *data = GB_read_file(filename = argv[1]); |
|---|
| 25 | if (!data){ |
|---|
| 26 | GB_print_error(); |
|---|
| 27 | exit(EXIT_FAILURE); |
|---|
| 28 | } |
|---|
| 29 | |
|---|
| 30 | /* read old version (i.e. ARB.xs.default) |
|---|
| 31 | and put all existing functions to exclude hash */ |
|---|
| 32 | |
|---|
| 33 | char *head = GB_read_file(argv[2]); |
|---|
| 34 | printf("/* This file has been generated from %s */\n\n", argv[2]); |
|---|
| 35 | printf("%s",head); /* inserting the *.xs.default in the output *.xs file*/ |
|---|
| 36 | |
|---|
| 37 | GB_HASH *exclude_hash = GBS_create_hash(1024, GB_MIND_CASE); /*prepare list for excluded functions from xs header*/ |
|---|
| 38 | { |
|---|
| 39 | char *tok; |
|---|
| 40 | /* initializer cond updater */ |
|---|
| 41 | for (tok = strtok(head,"\n");tok;tok = strtok(NULL,"\n")){ |
|---|
| 42 | if ( !strncmp(tok,"P2A_",4) |
|---|
| 43 | || !strncmp(tok,"P2AT_",5)){ /* looks like the if-branch is entered for every token*/ |
|---|
| 44 | char *fn = GBS_string_eval(tok,"(*=",0); |
|---|
| 45 | GBS_write_hash(exclude_hash,fn,1); |
|---|
| 46 | free(fn); |
|---|
| 47 | } |
|---|
| 48 | } |
|---|
| 49 | } |
|---|
| 50 | |
|---|
| 51 | /*parsing of proto.h and replacing substrings*/ |
|---|
| 52 | data = GBS_string_eval(data, |
|---|
| 53 | "\nchar=\nschar" // strdupped char |
|---|
| 54 | ":const =" |
|---|
| 55 | ":GB_CSTR =char \\*" |
|---|
| 56 | ":GB_ERROR =char \\*" |
|---|
| 57 | ":GB_BUFFER =char \\*" |
|---|
| 58 | ":GB_ULONG =long " |
|---|
| 59 | ":enum gb_call_back_type =char \\*" |
|---|
| 60 | ":GB_TYPES =char \\*" |
|---|
| 61 | ":GB_BOOL =int " |
|---|
| 62 | ":GB_CASE =int " |
|---|
| 63 | ":GB_UNDO_TYPE =char \\*" |
|---|
| 64 | ,0); |
|---|
| 65 | |
|---|
| 66 | |
|---|
| 67 | char *tok; |
|---|
| 68 | GBS_strstruct *gb_out = GBS_stropen(100000); |
|---|
| 69 | GBS_strstruct *gbt_out = GBS_stropen(100000); |
|---|
| 70 | bool inComment = false; |
|---|
| 71 | char *type = 0; |
|---|
| 72 | |
|---|
| 73 | for (tok = strtok(data,";\n");tok;tok = strtok(0,";\n")) { |
|---|
| 74 | freeset(type, 0); |
|---|
| 75 | |
|---|
| 76 | #if defined(DEBUG) |
|---|
| 77 | // fprintf(stderr,"tok='%s'\n",tok); |
|---|
| 78 | #endif // DEBUG |
|---|
| 79 | |
|---|
| 80 | // comment handling : |
|---|
| 81 | |
|---|
| 82 | if (inComment) { |
|---|
| 83 | char *cmtEnd = strstr(tok, "*/"); |
|---|
| 84 | if (!cmtEnd) continue; // continued comment -> search on |
|---|
| 85 | |
|---|
| 86 | strcpy(tok, cmtEnd+2); // remove comment |
|---|
| 87 | inComment = false; |
|---|
| 88 | } |
|---|
| 89 | |
|---|
| 90 | arb_assert(!inComment); |
|---|
| 91 | |
|---|
| 92 | for (char *cmtStart = strstr(tok, "/*"); cmtStart; cmtStart = strstr(tok, "/*")) { |
|---|
| 93 | char *cmtEnd = strstr(cmtStart+2, "*/"); |
|---|
| 94 | if (cmtEnd) { |
|---|
| 95 | cmtStart[0] = ' '; |
|---|
| 96 | strcpy(cmtStart+1, cmtEnd+2); |
|---|
| 97 | } |
|---|
| 98 | else { |
|---|
| 99 | inComment = true; |
|---|
| 100 | break; |
|---|
| 101 | } |
|---|
| 102 | } |
|---|
| 103 | |
|---|
| 104 | if (inComment) continue; |
|---|
| 105 | |
|---|
| 106 | while (tok[0] == ' ' || tok[0] == '\t') ++tok; // skip whitespace at beginning of line |
|---|
| 107 | if (!tok[0]) continue; // skip empty lines |
|---|
| 108 | |
|---|
| 109 | #if defined(DEBUG) |
|---|
| 110 | // fprintf(stderr,"noc='%s'\n",tok); |
|---|
| 111 | #endif // DEBUG |
|---|
| 112 | |
|---|
| 113 | if (strpbrk(tok,"#{}")) continue; |
|---|
| 114 | // ignore blocks like: |
|---|
| 115 | // |
|---|
| 116 | //#ifdef __cplusplus |
|---|
| 117 | //extern "C" { |
|---|
| 118 | //#endif |
|---|
| 119 | //#ifdef __cplusplus |
|---|
| 120 | //} |
|---|
| 121 | //#endif |
|---|
| 122 | |
|---|
| 123 | /* exclude some functions because of type problems */ |
|---|
| 124 | if (strstr(tok,"NOT4PERL")) continue; |
|---|
| 125 | if (strstr(tok,"struct")) continue; |
|---|
| 126 | if (strstr(tok,"UINT4 *")) continue; |
|---|
| 127 | if (strstr(tok,"FLOAT *")) continue; |
|---|
| 128 | if (strstr(tok,"...")) continue; |
|---|
| 129 | if (strstr(tok,"GBQUARK")) continue; |
|---|
| 130 | if (strstr(tok,"GB_HASH")) continue; |
|---|
| 131 | if (strstr(tok,"GBT_TREE")) continue; |
|---|
| 132 | if (strstr(tok,"GB_Link_Follower")) continue; |
|---|
| 133 | if (strstr(tok,"GB_alignment_type")) continue; |
|---|
| 134 | if (strstr(tok,"GB_COMPRESSION_MASK")) continue; |
|---|
| 135 | if (strstr(tok,"float *")) continue; |
|---|
| 136 | if (strstr(tok,"**")) continue; |
|---|
| 137 | if (GBS_string_matches(tok,"*(*(*)(*",GB_MIND_CASE)) continue; // no function parameters |
|---|
| 138 | if (strstr(tok,"GB_CB")) continue; // this is a function parameter as well |
|---|
| 139 | |
|---|
| 140 | #if defined(DUMP) |
|---|
| 141 | fprintf(stderr,"Good='%s'\n",tok); |
|---|
| 142 | #endif // DUMP |
|---|
| 143 | |
|---|
| 144 | /* extract function type */ |
|---|
| 145 | char *sp = strchr(tok,' '); |
|---|
| 146 | arb_assert(type == 0); |
|---|
| 147 | { |
|---|
| 148 | // is the expected declaration format "type name(..)" or "type name P_((..))" ?? |
|---|
| 149 | if (!sp) error(GBS_global_string("Space expected in '%s'",tok)); |
|---|
| 150 | while (sp[1] == '*' || sp[1] == ' ') sp++; // function type |
|---|
| 151 | |
|---|
| 152 | // create a copy of the return type |
|---|
| 153 | int c = sp[1]; |
|---|
| 154 | sp[1] = 0; |
|---|
| 155 | type = strdup(tok); |
|---|
| 156 | sp[1] = c; |
|---|
| 157 | |
|---|
| 158 | // remove spaces from return type |
|---|
| 159 | char *t = type; |
|---|
| 160 | char *f = type; |
|---|
| 161 | |
|---|
| 162 | while (*f) { |
|---|
| 163 | if (*f != ' ') *t++ = *f; |
|---|
| 164 | ++f; |
|---|
| 165 | } |
|---|
| 166 | t[0] = 0; |
|---|
| 167 | } |
|---|
| 168 | |
|---|
| 169 | /* check type */ |
|---|
| 170 | GB_BOOL const_char = GB_FALSE; |
|---|
| 171 | GB_BOOL free_flag = GB_FALSE; |
|---|
| 172 | |
|---|
| 173 | if (strcmp(type,"char*") == 0) const_char = GB_TRUE; |
|---|
| 174 | if (strncmp(type,"schar",5) == 0) { |
|---|
| 175 | free_flag = GB_TRUE; |
|---|
| 176 | freedup(type, type+1); |
|---|
| 177 | } |
|---|
| 178 | |
|---|
| 179 | if (strcmp(type,"float") == 0) freedup(type, "double"); |
|---|
| 180 | if (strcmp(type,"GB_alignment_type") == 0) freedup(type, "double"); |
|---|
| 181 | |
|---|
| 182 | tok = sp; |
|---|
| 183 | while (tok[0] == ' ' || tok[0] == '*') ++tok; |
|---|
| 184 | |
|---|
| 185 | char *func_name = 0; |
|---|
| 186 | char *arguments = 0; |
|---|
| 187 | |
|---|
| 188 | char *P_wrapped = strstr(tok, " P_("); |
|---|
| 189 | if (P_wrapped) { |
|---|
| 190 | sp = strchr(tok, ' '); |
|---|
| 191 | if (!sp) error(GBS_global_string("Space expected in '%s'", tok)); |
|---|
| 192 | |
|---|
| 193 | sp[0] = 0; // end function name |
|---|
| 194 | func_name = tok; |
|---|
| 195 | arguments = P_wrapped+5; |
|---|
| 196 | |
|---|
| 197 | char *last_paren = strrchr(arguments, ')'); |
|---|
| 198 | if (!last_paren) error(GBS_global_string("')' expected in '%s'", arguments)); |
|---|
| 199 | |
|---|
| 200 | if (last_paren[-1] == ')') { |
|---|
| 201 | last_paren[-1] = 0; // end arguments |
|---|
| 202 | } |
|---|
| 203 | else { |
|---|
| 204 | error(GBS_global_string("'))' expected in '%s'", P_wrapped)); |
|---|
| 205 | } |
|---|
| 206 | } |
|---|
| 207 | else { |
|---|
| 208 | char *open_paren = strchr(tok, '('); |
|---|
| 209 | if (!open_paren) error(GBS_global_string("'(' expected in '%s'", tok)); |
|---|
| 210 | |
|---|
| 211 | open_paren[0] = 0; |
|---|
| 212 | func_name = tok; |
|---|
| 213 | arguments = open_paren+1; |
|---|
| 214 | |
|---|
| 215 | char *last_paren = strrchr(arguments, ')'); |
|---|
| 216 | if (!last_paren) error(GBS_global_string("')' expected in '%s'", arguments)); |
|---|
| 217 | |
|---|
| 218 | last_paren[0] = 0; |
|---|
| 219 | } |
|---|
| 220 | |
|---|
| 221 | arb_assert(func_name); |
|---|
| 222 | arb_assert(arguments); |
|---|
| 223 | |
|---|
| 224 | #if defined(DUMP) |
|---|
| 225 | fprintf(stderr, "type='%s' func_name='%s' arguments='%s'\n", type, func_name, arguments); |
|---|
| 226 | #endif // DUMP |
|---|
| 227 | |
|---|
| 228 | /* exclude some funtions */ |
|---|
| 229 | |
|---|
| 230 | if (!strcmp(func_name,"GBT_add_data")) continue; |
|---|
| 231 | |
|---|
| 232 | // translate prefixes |
|---|
| 233 | |
|---|
| 234 | GBS_strstruct *out = 0; |
|---|
| 235 | if (!strncmp(func_name,"GB_",3)) out = gb_out; |
|---|
| 236 | if (!strncmp(func_name,"GBT_",4)) out = gbt_out; |
|---|
| 237 | if (!strncmp(func_name,"GEN_",4)) out = gbt_out; |
|---|
| 238 | if (!out) continue; |
|---|
| 239 | |
|---|
| 240 | char *perl_func_name = GBS_string_eval(func_name,"GBT_=P2AT_:GB_=P2A_:GEN_=P2AT_",0); |
|---|
| 241 | if (GBS_read_hash(exclude_hash,perl_func_name)) continue; |
|---|
| 242 | GBS_write_hash(exclude_hash,perl_func_name,1); // don't list functions twice |
|---|
| 243 | |
|---|
| 244 | #if defined(DUMP) |
|---|
| 245 | fprintf(stderr, "-> accepted!\n"); |
|---|
| 246 | #endif // DUMP |
|---|
| 247 | |
|---|
| 248 | char *p; |
|---|
| 249 | GBS_strstruct *params = GBS_stropen(1000); |
|---|
| 250 | GBS_strstruct *args = GBS_stropen(1000); |
|---|
| 251 | for (p=arguments; arguments; arguments=p ){ |
|---|
| 252 | p = strchr(arguments,','); |
|---|
| 253 | if (p) *(p++) = 0; |
|---|
| 254 | if (p && *p == ' ') p++; |
|---|
| 255 | if (strcmp(arguments,"void")){ |
|---|
| 256 | GBS_strcat(params," "); |
|---|
| 257 | GBS_strcat(params,arguments); |
|---|
| 258 | GBS_strcat(params,"\n"); |
|---|
| 259 | char *arp = strrchr(arguments,' '); |
|---|
| 260 | if (arp) { |
|---|
| 261 | arp++; |
|---|
| 262 | if (arp[0] == '*') arp++; |
|---|
| 263 | GBS_strcat(args,","); |
|---|
| 264 | GBS_strcat(args,arp); |
|---|
| 265 | } |
|---|
| 266 | } |
|---|
| 267 | } |
|---|
| 268 | char *sargs = GBS_strclose(args); |
|---|
| 269 | if (sargs[0] == ',') sargs++; |
|---|
| 270 | char *sparams = GBS_strclose(params); |
|---|
| 271 | GBS_strnprintf(out,1000,"%s\n",type); |
|---|
| 272 | GBS_strnprintf(out,1000,"%s(%s)\n%s\n",perl_func_name,sargs,sparams); |
|---|
| 273 | |
|---|
| 274 | if (!strncmp(type,"void",4)){ |
|---|
| 275 | GBS_strnprintf(out,100," PPCODE:\n"); |
|---|
| 276 | GBS_strnprintf(out,1000," %s(%s);\n\n", func_name,sargs); |
|---|
| 277 | }else{ |
|---|
| 278 | GBS_strnprintf(out,100," CODE:\n"); |
|---|
| 279 | if (const_char){ |
|---|
| 280 | GBS_strnprintf(out,1000, " RETVAL = (char *)%s(%s);\n", (char *)func_name,sargs); |
|---|
| 281 | }else if(free_flag){ |
|---|
| 282 | GBS_strnprintf(out,1000, " if (static_pntr) free(static_pntr);\n"); |
|---|
| 283 | GBS_strnprintf(out,1000, " static_pntr = %s(%s);\n", func_name,sargs); |
|---|
| 284 | GBS_strnprintf(out,1000, " RETVAL = static_pntr;\n"); |
|---|
| 285 | }else{ |
|---|
| 286 | GBS_strnprintf(out,1000, " RETVAL = %s(%s);\n", func_name,sargs); |
|---|
| 287 | } |
|---|
| 288 | GBS_strnprintf(out, 1000, " OUTPUT:\n RETVAL\n\n"); |
|---|
| 289 | } |
|---|
| 290 | } |
|---|
| 291 | |
|---|
| 292 | if (inComment) error("Comment until end of file"); |
|---|
| 293 | |
|---|
| 294 | printf("%s",GBS_strclose(gb_out)); |
|---|
| 295 | printf("MODULE = ARB PACKAGE = BIO PREFIX = P2AT_\n\n"); |
|---|
| 296 | printf("%s",GBS_strclose(gbt_out)); |
|---|
| 297 | |
|---|
| 298 | return EXIT_SUCCESS; |
|---|
| 299 | } |
|---|