clients/screenshooter: Fix taking screenshot on multiple outputs
[src/agl-compositor.git] / shared / option-parser.c
1 /*
2  * Copyright © 2012 Kristian Høgsberg
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25
26 #include <stdbool.h>
27 #include <stdlib.h>
28 #include <stdint.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <errno.h>
33
34 #include <libweston/config-parser.h>
35 #include "shared/string-helpers.h"
36
37 static bool
38 handle_option(const struct weston_option *option, char *value)
39 {
40         char* p;
41
42         switch (option->type) {
43         case WESTON_OPTION_INTEGER:
44                 if (!safe_strtoint(value, option->data))
45                         return false;
46                 return true;
47         case WESTON_OPTION_UNSIGNED_INTEGER:
48                 errno = 0;
49                 * (uint32_t *) option->data = strtoul(value, &p, 10);
50                 if (errno != 0 || p == value || *p != '\0')
51                         return false;
52                 return true;
53         case WESTON_OPTION_STRING:
54                 * (char **) option->data = strdup(value);
55                 return true;
56         default:
57                 assert(0);
58                 return false;
59         }
60 }
61
62 static bool
63 long_option(const struct weston_option *options, int count, char *arg)
64 {
65         int k, len;
66
67         for (k = 0; k < count; k++) {
68                 if (!options[k].name)
69                         continue;
70
71                 len = strlen(options[k].name);
72                 if (strncmp(options[k].name, arg + 2, len) != 0)
73                         continue;
74
75                 if (options[k].type == WESTON_OPTION_BOOLEAN) {
76                         if (!arg[len + 2]) {
77                                 * (int32_t *) options[k].data = 1;
78
79                                 return true;
80                         }
81                 } else if (arg[len+2] == '=') {
82                         return handle_option(options + k, arg + len + 3);
83                 }
84         }
85
86         return false;
87 }
88
89 static bool
90 long_option_with_arg(const struct weston_option *options, int count, char *arg,
91                      char *param)
92 {
93         int k, len;
94
95         for (k = 0; k < count; k++) {
96                 if (!options[k].name)
97                         continue;
98
99                 len = strlen(options[k].name);
100                 if (strncmp(options[k].name, arg + 2, len) != 0)
101                         continue;
102
103                 /* Since long_option() should handle all booleans, we should
104                  * never reach this
105                  */
106                 assert(options[k].type != WESTON_OPTION_BOOLEAN);
107
108                 return handle_option(options + k, param);
109         }
110
111         return false;
112 }
113
114 static bool
115 short_option(const struct weston_option *options, int count, char *arg)
116 {
117         int k;
118
119         if (!arg[1])
120                 return false;
121
122         for (k = 0; k < count; k++) {
123                 if (options[k].short_name != arg[1])
124                         continue;
125
126                 if (options[k].type == WESTON_OPTION_BOOLEAN) {
127                         if (!arg[2]) {
128                                 * (int32_t *) options[k].data = 1;
129
130                                 return true;
131                         }
132                 } else if (arg[2]) {
133                         return handle_option(options + k, arg + 2);
134                 } else {
135                         return false;
136                 }
137         }
138
139         return false;
140 }
141
142 static bool
143 short_option_with_arg(const struct weston_option *options, int count, char *arg, char *param)
144 {
145         int k;
146
147         if (!arg[1])
148                 return false;
149
150         for (k = 0; k < count; k++) {
151                 if (options[k].short_name != arg[1])
152                         continue;
153
154                 if (options[k].type == WESTON_OPTION_BOOLEAN)
155                         continue;
156
157                 return handle_option(options + k, param);
158         }
159
160         return false;
161 }
162
163 int
164 parse_options(const struct weston_option *options,
165               int count, int *argc, char *argv[])
166 {
167         int i, j;
168
169         for (i = 1, j = 1; i < *argc; i++) {
170                 if (argv[i][0] == '-') {
171                         if (argv[i][1] == '-') {
172                                 /* Long option, e.g. --foo or --foo=bar */
173                                 if (long_option(options, count, argv[i]))
174                                         continue;
175
176                                 /* ...also handle --foo bar */
177                                 if (i + 1 < *argc &&
178                                     long_option_with_arg(options, count,
179                                                          argv[i], argv[i+1])) {
180                                         i++;
181                                         continue;
182                                 }
183                         } else {
184                                 /* Short option, e.g -f or -f42 */
185                                 if (short_option(options, count, argv[i]))
186                                         continue;
187
188                                 /* ...also handle -f 42 */
189                                 if (i+1 < *argc &&
190                                     short_option_with_arg(options, count, argv[i], argv[i+1])) {
191                                         i++;
192                                         continue;
193                                 }
194                         }
195                 }
196                 argv[j++] = argv[i];
197         }
198         argv[j] = NULL;
199         *argc = j;
200
201         return j;
202 }