17abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#include <debug.h> 27abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#include <cmdline.h> 37abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#include <stdio.h> 47abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#include <stdlib.h> 57abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#include <getopt.h> 67abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#include <string.h> 77abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#include <ctype.h> 87abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev 97abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchevextern char *optarg; 107abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchevextern int optind, opterr, optopt; 117abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev 127abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchevstatic struct option long_options[] = { 137abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev {"output", required_argument, 0, 'o'}, 147abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev {"height", required_argument, 0, 'h'}, 157abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev {"width", required_argument, 0, 'w'}, 167abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev {"gray", no_argument, 0, 'g'}, 177abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev {"type", required_argument, 0, 't'}, 187abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev {"rotate", required_argument, 0, 'r'}, 197abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev {"verbose", no_argument, 0, 'V'}, 207abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev {"help", no_argument, 0, 1}, 217abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev {0, 0, 0, 0}, 227abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev}; 237abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev 247abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev/* This array must parallel long_options[] */ 257abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchevstatic const char *descriptions[] = { 267abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev "output file", 277abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev "image height in pixels", 287abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev "image width in pixels", 297abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev "process the luma plane only", 307abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev "encode as one of { 'ppm', 'rgb', or 'argb' }", 317abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev "rotate (90, -90, 180 degrees)", 327abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev "print verbose output", 337abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev "print this help screen", 347abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev}; 357abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev 367abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchevvoid print_help(const char *name) { 377abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev fprintf(stdout, 387abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev "Converts yuv 4:2:0 to rgb24 and generates a PPM file.\n" 397abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev "invokation:\n" 407abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev "\t%s infile --height <height> --width <width> --output <outfile> -t <ppm|grb|argb> [ --gray ] [ --rotate <degrees> ] [ --verbose ]\n" 417abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev "\t%s infile --help\n", 427abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev name, name); 437abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev fprintf(stdout, "options:\n"); 447abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev struct option *opt = long_options; 457abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev const char **desc = descriptions; 467abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev while (opt->name) { 477abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev fprintf(stdout, "\t-%c/--%s%s: %s\n", 487abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev isprint(opt->val) ? opt->val : ' ', 497abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev opt->name, 507abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev (opt->has_arg ? " (argument)" : ""), 517abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev *desc); 527abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev opt++; 537abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev desc++; 547abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev } 557abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev} 567abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev 577abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchevint get_options(int argc, char **argv, 587abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev char **outfile, 597abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev int *height, 607abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev int *width, 617abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev int *gray, 627abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev char **type, 637abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev int *rotate, 647abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev int *verbose) { 657abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev int c; 667abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev 677abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev ASSERT(outfile); *outfile = NULL; 687abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev ASSERT(height); *height = -1; 697abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev ASSERT(width); *width = -1; 707abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev ASSERT(gray); *gray = 0; 717abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev ASSERT(rotate); *rotate = 0; 727abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev ASSERT(verbose); *verbose = 0; 737abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev ASSERT(type); *type = NULL; 747abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev 757abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev while (1) { 767abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev /* getopt_long stores the option index here. */ 777abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev int option_index = 0; 787abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev 797abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev c = getopt_long (argc, argv, 807abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev "Vgo:h:w:r:t:", 817abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev long_options, 827abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev &option_index); 837abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev /* Detect the end of the options. */ 847abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev if (c == -1) break; 857abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev 867abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev if (isgraph(c)) { 877abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev INFO ("option -%c with value `%s'\n", c, (optarg ?: "(null)")); 887abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev } 897abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev 907abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#define SET_STRING_OPTION(name) do { \ 917abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev ASSERT(optarg); \ 927abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev (*name) = strdup(optarg); \ 937abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev} while(0) 947abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev 957abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#define SET_INT_OPTION(val) do { \ 967abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev ASSERT(optarg); \ 977abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev if (strlen(optarg) >= 2 && optarg[0] == '0' && optarg[1] == 'x') { \ 987abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev FAILIF(1 != sscanf(optarg+2, "%x", val), \ 997abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev "Expecting a hexadecimal argument!\n"); \ 1007abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev } else { \ 1017abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev FAILIF(1 != sscanf(optarg, "%d", val), \ 1027abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev "Expecting a decimal argument!\n"); \ 1037abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev } \ 1047abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev} while(0) 1057abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev 1067abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev switch (c) { 1077abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev case 0: 1087abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev /* If this option set a flag, do nothing else now. */ 1097abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev if (long_options[option_index].flag != 0) 1107abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev break; 1117abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev INFO ("option %s", long_options[option_index].name); 1127abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev if (optarg) 1137abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev INFO (" with arg %s", optarg); 1147abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev INFO ("\n"); 1157abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev break; 1167abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev case 1: print_help(argv[0]); exit(1); break; 1177abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev case 'o': 1187abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev SET_STRING_OPTION(outfile); 1197abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev break; 1207abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev case 't': 1217abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev SET_STRING_OPTION(type); 1227abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev break; 1237abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev case 'h': 1247abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev SET_INT_OPTION(height); 1257abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev break; 1267abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev case 'w': 1277abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev SET_INT_OPTION(width); 1287abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev break; 1297abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev case 'r': 1307abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev SET_INT_OPTION(rotate); 1317abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev break; 1327abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev case 'g': *gray = 1; break; 1337abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev case 'V': *verbose = 1; break; 1347abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev case '?': 1357abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev /* getopt_long already printed an error message. */ 1367abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev break; 1377abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev 1387abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#undef SET_STRING_OPTION 1397abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#undef SET_INT_OPTION 1407abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev 1417abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev default: 1427abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev FAILIF(1, "Unknown option"); 1437abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev } 1447abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev } 1457abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev 1467abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev return optind; 1477abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev} 148