1#include <debug.h>
2#include <cmdline.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <getopt.h>
6#include <string.h>
7#include <ctype.h>
8
9extern char *optarg;
10extern int optind, opterr, optopt;
11
12static struct option long_options[] = {
13    {"output",  required_argument, 0, 'o'},
14    {"height",  required_argument, 0, 'h'},
15    {"width",   required_argument, 0, 'w'},
16    {"gray",    no_argument,       0, 'g'},
17    {"type",    required_argument, 0, 't'},
18    {"rotate",  required_argument, 0, 'r'},
19    {"verbose", no_argument,       0, 'V'},
20    {"help",    no_argument,       0, 1},
21    {0, 0, 0, 0},
22};
23
24/* This array must parallel long_options[] */
25static const char *descriptions[] = {
26    "output file",
27    "image height in pixels",
28    "image width in pixels",
29    "process the luma plane only",
30    "encode as one of { 'ppm', 'rgb', or 'argb' }",
31    "rotate (90, -90, 180 degrees)",
32    "print verbose output",
33    "print this help screen",
34};
35
36void print_help(const char *name) {
37    fprintf(stdout,
38            "Converts yuv 4:2:0 to rgb24 and generates a PPM file.\n"
39            "invokation:\n"
40            "\t%s infile --height <height> --width <width> --output <outfile> -t <ppm|grb|argb> [ --gray ] [ --rotate <degrees> ] [ --verbose ]\n"
41            "\t%s infile --help\n",
42            name, name);
43    fprintf(stdout, "options:\n");
44    struct option *opt = long_options;
45    const char **desc = descriptions;
46    while (opt->name) {
47        fprintf(stdout, "\t-%c/--%s%s: %s\n",
48                isprint(opt->val) ? opt->val : ' ',
49                opt->name,
50                (opt->has_arg ? " (argument)" : ""),
51                *desc);
52        opt++;
53        desc++;
54    }
55}
56
57int get_options(int argc, char **argv,
58                char **outfile,
59                int *height,
60                int *width,
61                int *gray,
62                char **type,
63                int *rotate,
64                int *verbose) {
65    int c;
66
67    ASSERT(outfile); *outfile = NULL;
68    ASSERT(height); *height = -1;
69    ASSERT(width); *width = -1;
70    ASSERT(gray); *gray = 0;
71    ASSERT(rotate); *rotate = 0;
72    ASSERT(verbose); *verbose = 0;
73    ASSERT(type); *type = NULL;
74
75    while (1) {
76        /* getopt_long stores the option index here. */
77        int option_index = 0;
78
79        c = getopt_long (argc, argv,
80                         "Vgo:h:w:r:t:",
81                         long_options,
82                         &option_index);
83        /* Detect the end of the options. */
84        if (c == -1) break;
85
86        if (isgraph(c)) {
87            INFO ("option -%c with value `%s'\n", c, (optarg ?: "(null)"));
88        }
89
90#define SET_STRING_OPTION(name) do {                                   \
91    ASSERT(optarg);                                                    \
92    (*name) = strdup(optarg);                                          \
93} while(0)
94
95#define SET_INT_OPTION(val) do {                                       \
96    ASSERT(optarg);                                                    \
97	if (strlen(optarg) >= 2 && optarg[0] == '0' && optarg[1] == 'x') { \
98			FAILIF(1 != sscanf(optarg+2, "%x", val),                   \
99				   "Expecting a hexadecimal argument!\n");             \
100	} else {                                                           \
101		FAILIF(1 != sscanf(optarg, "%d", val),                         \
102			   "Expecting a decimal argument!\n");                     \
103	}                                                                  \
104} while(0)
105
106        switch (c) {
107        case 0:
108            /* If this option set a flag, do nothing else now. */
109            if (long_options[option_index].flag != 0)
110                break;
111            INFO ("option %s", long_options[option_index].name);
112            if (optarg)
113                INFO (" with arg %s", optarg);
114            INFO ("\n");
115            break;
116        case 1: print_help(argv[0]); exit(1); break;
117		case 'o':
118			SET_STRING_OPTION(outfile);
119			break;
120		case 't':
121			SET_STRING_OPTION(type);
122			break;
123        case 'h':
124            SET_INT_OPTION(height);
125            break;
126        case 'w':
127            SET_INT_OPTION(width);
128            break;
129        case 'r':
130            SET_INT_OPTION(rotate);
131            break;
132        case 'g': *gray = 1; break;
133        case 'V': *verbose = 1; break;
134        case '?':
135            /* getopt_long already printed an error message. */
136            break;
137
138#undef SET_STRING_OPTION
139#undef SET_INT_OPTION
140
141        default:
142            FAILIF(1, "Unknown option");
143        }
144    }
145
146    return optind;
147}
148