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