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 | } |
---|