1 /* -*- Mode: c; c-basic-offset: 2 -*-
2 *
3 * codegen utility - Make C code from Flickr API by reflection
4 *
5 * Copyright (C) 2007-2012, David Beckett http://www.dajobe.org/
6 *
7 * This file is licensed under the following three licenses as alternatives:
8 * 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
9 * 2. GNU General Public License (GPL) V2 or any newer version
10 * 3. Apache License, V2.0 or any newer version
11 *
12 * You may not use this file except in compliance with at least one of
13 * the above three licenses.
14 *
15 * See LICENSE.html or LICENSE.txt at the top of this package for the
16 * complete terms and further detail along with the license texts for
17 * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
18 *
19 *
20 * USAGE: codegen [OPTIONS] flickr.section
21 *
22 */
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdarg.h>
27
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31
32 #ifdef HAVE_STDLIB_H
33 #include <stdlib.h>
34 #endif
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 #ifdef HAVE_ERRNO_H
39 #include <errno.h>
40 #endif
41
42 /* many places for getopt */
43 #ifdef HAVE_GETOPT_H
44 #include <getopt.h>
45 #else
46 #include <flickcurl_getopt.h>
47 #endif
48
49 #include <flickcurl.h>
50
51 #include <flickcurl_cmd.h>
52
53
54
55 #ifdef NEED_OPTIND_DECLARATION
56 extern int optind;
57 extern char *optarg;
58 #endif
59
60
61 const char* program;
62
63 static void
my_message_handler(void * user_data,const char * message)64 my_message_handler(void *user_data, const char *message)
65 {
66 fprintf(stderr, "%s: ERROR: %s\n", program, message);
67 }
68
69
70 #ifdef HAVE_GETOPT_LONG
71 #define HELP_TEXT(short, long, description) " -" short ", --" long " " description
72 #define HELP_TEXT_LONG(long, description) " --" long " " description
73 #define HELP_ARG(short, long) "--" #long
74 #define HELP_PAD "\n "
75 #else
76 #define HELP_TEXT(short, long, description) " -" short " " description
77 #define HELP_TEXT_LONG(long, description)
78 #define HELP_ARG(short, long) "-" #short
79 #define HELP_PAD "\n "
80 #endif
81
82
83 #define GETOPT_STRING "d:hv"
84
85 #ifdef HAVE_GETOPT_LONG
86 static struct option long_options[] =
87 {
88 /* name, has_arg, flag, val */
89 {"delay", 1, 0, 'd'},
90 {"help", 0, 0, 'h'},
91 {"version", 0, 0, 'v'},
92 {NULL, 0, 0, 0}
93 };
94 #endif
95
96 #define IS_INT_ARG(arg) (!strcmp(arg->name, "per_page") || !strcmp(arg->name, "page"))
97 #define IS_OPTIONAL_ARG(arg) (!strcmp(arg->name, "per_page") || !strcmp(arg->name, "page"))
98
99 static const char *title_format_string = "Skeleton code generator utility %s\n";
100
101
102 int
main(int argc,char * argv[])103 main(int argc, char *argv[])
104 {
105 flickcurl *fc = NULL;
106 int rc = 0;
107 int usage = 0;
108 int help = 0;
109 int read_auth = 1;
110 int i;
111 int request_delay= -1;
112 char section[50];
113 size_t section_len;
114 char** methods = NULL;
115
116 flickcurl_init();
117 flickcurl_cmdline_init();
118
119 program = flickcurl_cmdline_basename(argv[0]);
120
121 while (!usage && !help)
122 {
123 int c;
124 #ifdef HAVE_GETOPT_LONG
125 int option_index = 0;
126
127 c = getopt_long (argc, argv, GETOPT_STRING, long_options, &option_index);
128 #else
129 c = getopt (argc, argv, GETOPT_STRING);
130 #endif
131 if (c == -1)
132 break;
133
134 switch (c) {
135 case 0:
136 case '?': /* getopt() - unknown option */
137 usage = 1;
138 break;
139
140 case 'd':
141 if(optarg)
142 request_delay = atoi(optarg);
143 break;
144
145 case 'h':
146 help = 1;
147 break;
148
149 case 'v':
150 fputs(flickcurl_version_string, stdout);
151 fputc('\n', stdout);
152
153 flickcurl_cmdline_finish();
154 exit(0);
155 }
156
157 }
158
159 if(help)
160 goto help;
161
162 if(argc < 2) {
163 fprintf(stderr, "%s: No API section given\n", program);
164 usage = 1;
165 }
166
167 if(usage) {
168 if(usage>1) {
169 fprintf(stderr, title_format_string, flickcurl_version_string);
170 fputs("Flickcurl home page: ", stderr);
171 fputs(flickcurl_home_url_string, stderr);
172 fputc('\n', stderr);
173 fputs(flickcurl_copyright_string, stderr);
174 fputs("\nLicense: ", stderr);
175 fputs(flickcurl_license_string, stderr);
176 fputs("\n\n", stderr);
177 }
178 fprintf(stderr, "Try `%s " HELP_ARG(h, help) "' for more information.\n",
179 program);
180 rc = 1;
181 goto tidy;
182 }
183
184 help:
185 if(help) {
186 printf(title_format_string, flickcurl_version_string);
187 puts("Generate C code from Flickr API by reflection.");
188 printf("Usage: %s [OPTIONS] command args...\n\n", program);
189
190 fputs(flickcurl_copyright_string, stdout);
191 fputs("\nLicense: ", stdout);
192 puts(flickcurl_license_string);
193 fputs("Flickcurl home page: ", stdout);
194 puts(flickcurl_home_url_string);
195
196 fputs("\n", stdout);
197
198 puts(HELP_TEXT("d", "delay DELAY ", "Set delay between requests in milliseconds"));
199 puts(HELP_TEXT("h", "help ", "Print this help, then exit"));
200 puts(HELP_TEXT("v", "version ", "Print the flickcurl version"));
201
202 rc = 0;
203 goto tidy;
204 }
205
206
207 /* Initialise the Flickcurl library */
208 fc = flickcurl_new();
209 if(!fc) {
210 rc = 1;
211 goto tidy;
212 }
213
214 flickcurl_set_error_handler(fc, my_message_handler, NULL);
215
216 if(read_auth && !access((const char*)flickcurl_cmdline_config_path, R_OK)) {
217 if(flickcurl_config_read_ini(fc, flickcurl_cmdline_config_path,
218 flickcurl_cmdline_config_section, fc,
219 flickcurl_config_var_handler)) {
220 rc = 1;
221 goto tidy;
222 }
223 }
224
225 if(request_delay >= 0)
226 flickcurl_set_request_delay(fc, request_delay);
227
228 strcpy(section, "flickr.");
229 strcpy(section+7, argv[1]);
230
231 /* allow old format commands to work */
232 for(i = 0; section[i]; i++) {
233 if(section[i] == '-')
234 section[i] = '.';
235 }
236
237 if(!strncmp(section, "flickr.flickr", 13))
238 strcpy(section, section+7);
239 section_len = strlen(section);
240
241 fprintf(stderr, "%s: section '%s'\n", program, section);
242
243 methods = flickcurl_reflection_getMethods(fc);
244 if(!methods) {
245 fprintf(stderr, "%s: getMethods failed\n", program);
246 rc = 1;
247 goto tidy;
248 }
249
250 fprintf(stdout,
251 "/* -*- Mode: c; c-basic-offset: 2 -*-\n"
252 " *\n"
253 " * %s-api.c - Flickr %s.* API calls\n"
254 " *\n",
255 argv[1], section);
256
257 fprintf(stdout,
258 " * Copyright (C) 2010-2012, David Beckett http://www.dajobe.org/\n"
259 " * \n"
260 " * This file is licensed under the following three licenses as alternatives:\n"
261 " * 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version\n"
262 " * 2. GNU General Public License (GPL) V2 or any newer version\n"
263 " * 3. Apache License, V2.0 or any newer version\n"
264 " * \n"
265 " * You may not use this file except in compliance with at least one of\n"
266 " * the above three licenses.\n"
267 " * \n"
268 " * See LICENSE.html or LICENSE.txt at the top of this package for the\n"
269 " * complete terms and further detail along with the license texts for\n"
270 " * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.\n"
271 " * \n"
272 " */\n"
273 "\n"
274 "#include <stdio.h>\n"
275 "#include <string.h>\n"
276 "#include <stdarg.h>\n"
277 "\n"
278 "#ifdef HAVE_CONFIG_H\n"
279 "#include <config.h>\n"
280 "#endif\n"
281 "\n"
282 "#ifdef HAVE_STDLIB_H\n"
283 "#include <stdlib.h>\n"
284 "#undef HAVE_STDLIB_H\n"
285 "#endif\n"
286 "#ifdef HAVE_UNISTD_H\n"
287 "#include <unistd.h>\n"
288 "#endif\n"
289 "\n"
290 "#include <flickcurl.h>\n"
291 "#include <flickcurl_internal.h>\n"
292 "\n"
293 "\n"
294 );
295
296
297 for(i = 0; methods[i]; i++) {
298 flickcurl_method* method;
299 char* method_name;
300 char function_name[100];
301 int c, j;
302 int is_write = 0;
303
304 if(strncmp(methods[i], section, section_len))
305 continue;
306
307 method = flickcurl_reflection_getMethodInfo(fc, methods[i]);
308 if(!method) {
309 fprintf(stderr, "%s: getMethodInfo(%s) failed\n", program, methods[i]);
310 rc = 1;
311 break;
312 }
313
314 method_name = method->name;
315
316 if(
317 strstr(method_name, ".add") ||
318 strstr(method_name, ".create") ||
319 strstr(method_name, ".delete") ||
320 strstr(method_name, ".edit") ||
321 strstr(method_name, ".remove") ||
322 strstr(method_name, ".set")
323 )
324 is_write = 1;
325
326 strcpy(function_name, "flickcurl_");
327 for(j = 0; (c = methods[i][j+7]); j++) {
328 if(c == '.')
329 c = '_';
330 function_name[j+10] = c;
331 }
332 function_name[j+10] = '\0';
333
334 fprintf(stdout, "/**\n * %s:\n", function_name);
335
336 /* fixed arguments */
337 fprintf(stdout, " * @fc: flickcurl context\n");
338
339 if(method->args_count) {
340 int argi;
341 for(argi = 0; method->args[argi]; argi++) {
342 flickcurl_arg* arg = method->args[argi];
343 if(!strcmp(arg->name, "api_key"))
344 continue;
345
346 fprintf(stdout, " * @%s: %s", arg->name, arg->description);
347 if(arg->optional) {
348 fputs((IS_INT_ARG(arg)? " (or < 0)" : " (or NULL)"), stdout);
349 }
350 fputc('\n', stdout);
351
352 }
353 }
354
355 fprintf(stdout,
356 " * \n"
357 " * %s\n"
358 " *\n"
359 " * Implements %s (%s)\n",
360 method->description, method->name, flickcurl_version_string
361 );
362
363 fprintf(stdout,
364 " * \n"
365 " * Return value: non-0 on failure\n"
366 " **/\n"
367 );
368
369 fprintf(stdout, "int\n%s(flickcurl* fc", function_name);
370 if(method->args_count) {
371 int argi;
372 for(argi = 0; method->args[argi]; argi++) {
373 flickcurl_arg* arg = method->args[argi];
374 if(!strcmp(arg->name, "api_key"))
375 continue;
376
377 if(IS_INT_ARG(arg)) {
378 fprintf(stdout, ", int %s", arg->name);
379 } else {
380 fprintf(stdout, ", const char* %s", arg->name);
381 }
382 }
383 }
384 fprintf(stdout, ")\n{\n");
385
386 fprintf(stdout,
387 " xmlDocPtr doc = NULL;\n"
388 " xmlXPathContextPtr xpathCtx = NULL; \n"
389 " void* result = NULL;\n");
390 if(method->args_count) {
391 int argi;
392 for(argi = 0; method->args[argi]; argi++) {
393 flickcurl_arg* arg = method->args[argi];
394 if(IS_INT_ARG(arg)) {
395 fprintf(stdout,
396 " char %s_str[10];\n",
397 arg->name);
398 }
399 }
400 }
401
402 fputs(
403 "\n"
404 " flickcurl_init_params(fc, 0);\n"
405 "\n",
406 stdout);
407
408
409 if(method->args_count) {
410 int argi;
411 int print_or = 0;
412
413 fprintf(stdout, " if(");
414 for(argi = 0; method->args[argi]; argi++) {
415 flickcurl_arg* arg = method->args[argi];
416 if(!strcmp(arg->name, "api_key"))
417 continue;
418
419 if(!arg->optional) {
420 if(print_or)
421 fprintf(stdout, " || ");
422
423 fprintf(stdout, "!%s", arg->name);
424 print_or = 1;
425 }
426 }
427 fprintf(stdout,
428 ")\n"
429 " return 1;\n"
430 "\n");
431 }
432
433
434 if(method->args_count) {
435 int argi;
436 for(argi = 0; method->args[argi]; argi++) {
437 flickcurl_arg* arg = method->args[argi];
438 if(!strcmp(arg->name, "api_key"))
439 continue;
440
441 if(arg->optional) {
442 if(IS_INT_ARG(arg)) {
443 fprintf(stdout,
444 " if(%s >= 0) {\n"
445 " sprintf(%s_str, \"%%d\", %s);\n"
446 " flickcurl_add_param(fc, \"%s\", %s_str);\n"
447 " }\n",
448 arg->name, arg->name, arg->name, arg->name, arg->name);
449 continue;
450 }
451 fprintf(stdout,
452 " if(%s)\n",
453 arg->name);
454 }
455
456 fprintf(stdout,
457 " flickcurl_add_param(fc, \"%s\", %s);\n",
458 arg->name, arg->name);
459
460 }
461 }
462
463 fprintf(stdout,
464 "\n"
465 " flickcurl_end_params(fc);\n"
466 "\n"
467 " if(flickcurl_prepare(fc, \"%s\"))\n"
468 " goto tidy;\n"
469 "\n",
470 method->name);
471
472 if(is_write)
473 fprintf(stdout,
474 " flickcurl_set_write(fc, 1);\n"
475 " flickcurl_set_data(fc, (void*)\"\", 0);\n"
476 "\n"
477 );
478
479 fprintf(stdout,
480 " doc = flickcurl_invoke(fc);\n"
481 " if(!doc)\n"
482 " goto tidy;\n"
483 "\n"
484 "\n"
485 " xpathCtx = xmlXPathNewContext(doc);\n"
486 " if(!xpathCtx) {\n"
487 " flickcurl_error(fc, \"Failed to create XPath context for document\");\n"
488 " fc->failed = 1;\n"
489 " goto tidy;\n"
490 " }\n"
491 "\n"
492 " result = NULL; /* your code here */\n"
493 "\n"
494 " tidy:\n"
495 " if(xpathCtx)\n"
496 " xmlXPathFreeContext(xpathCtx);\n"
497 "\n"
498 " if(fc->failed)\n"
499 " result = NULL;\n"
500 "\n"
501 " return (result == NULL);\n"
502 "}\n"
503 "\n"
504 "\n");
505
506 flickcurl_free_method(method);
507 }
508
509
510 tidy:
511 if(methods) {
512 for(i = 0; methods[i]; i++)
513 free(methods[i]);
514 free(methods);
515 methods = NULL;
516 }
517
518 if(fc)
519 flickcurl_free(fc);
520
521 flickcurl_finish();
522
523 flickcurl_cmdline_finish();
524
525 return(rc);
526 }
527