5e9c37e00a59dd85eab34ec0b6da7c817212844a
[src/app-framework-binder.git] / src / devtools / genskel.c
1 /*
2  * Copyright (C) 2016-2019 "IoT.bzh"
3  * Author José Bollo <jose.bollo@iot.bzh>
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 /*
18  * This simple program expands the object { "$ref": "#/path/to/a/target" }
19  *
20  * For example:
21  *
22  *  {
23  *    "type":{
24  *      "a": "int",
25  *      "b": { "$ref": "#/type/a" }
26  *    }
27  *  }
28  *
29  * will be exapanded to
30  *
31  *  {
32  *    "type":{
33  *      "a": "int",
34  *      "b": "int"
35  *    }
36  *  }
37  *
38  * Invocation:   program  [file|-]...
39  *
40  * without arguments, it reads the input.
41  */
42
43 #define _GNU_SOURCE
44 #include <string.h>
45 #include <stdio.h>
46 #include <unistd.h>
47 #include <ctype.h>
48
49 #include <json-c/json.h>
50
51 #define T(x)   ((x) && *(x))
52 #define oom(x) do{if(!(x)){fprintf(stderr,"out of memory\n");exit(1);}}while(0)
53
54 /**
55  * records path to the expanded node
56  */
57 struct path
58 {
59         struct json_object *object;     /**< node being expanded */
60         struct path *upper;             /**< link to upper expanded nodes */
61 };
62
63 /**
64  * root of the JSON being parsed
65  */
66 int version = 3;
67 struct json_object *root = NULL;
68 struct json_object *d_perms = NULL;
69 struct json_object *a_perms = NULL;
70 const char *preinit = NULL;
71 const char *init = NULL;
72 const char *onevent = NULL;
73 const char *api = NULL;
74 const char *scope = NULL;
75 const char *prefix = NULL;
76 const char *postfix = NULL;
77 const char *provideclass = NULL;
78 const char *requireclass = NULL;
79 const char *requireapi = NULL;
80 char *capi = NULL;
81 int priv = -1;
82 int noconc = -1;
83 int cpp = 0;
84
85 /**
86  * Search for a reference of type "#/a/b/c" in the
87  * parsed JSON object (root)
88  */
89 struct json_object *search(const char *path)
90 {
91         char *d;
92         struct json_object *i;
93
94         /* does it match #/ at the beginning? */
95         if (path[0] != '#' || (path[0] && path[1] != '/'))
96                 return NULL;
97
98         /* search from root to target */
99         i = root;
100         d = strdupa(path+2);
101         d = strtok(d, "/");
102         while(i && d) {
103                 if (!json_object_object_get_ex(i, d, &i))
104                         return NULL;
105                 d = strtok(NULL, "/");
106         }
107         return i;
108 }
109
110 /**
111  * Expands the node designated by path and returns its expanded form
112  */
113 struct json_object *expand_$ref(struct path path)
114 {
115         struct path *p;
116         struct json_object *o, *x;
117         int n, i;
118         struct json_object_iterator ji, jn;
119
120         /* expansion depends of the type of the node */
121         switch (json_object_get_type(path.object)) {
122         case json_type_object:
123                 /* for object, look if it contains a property "$ref" */
124                 if (json_object_object_get_ex(path.object, "$ref", &o)) {
125                         /* yes, reference, try to substitute its target */
126                         if (!json_object_is_type(o, json_type_string)) {
127                                 fprintf(stderr, "found a $ref not being string. Is: %s\n", json_object_get_string(o));
128                                 exit(1);
129                         }
130                         x = search(json_object_get_string(o));
131                         if (!x) {
132                                 fprintf(stderr, "$ref not found. Was: %s\n", json_object_get_string(o));
133                                 exit(1);
134                         }
135                         p = &path;
136                         while(p) {
137                                 if (x == p->object) {
138                                         fprintf(stderr, "$ref recursive. Was: %s\n", json_object_get_string(o));
139                                         exit(1);
140                                 }
141                                 p = p->upper;
142                         }
143                         /* cool found, return a new instance of the target */
144                         return json_object_get(x);
145                 }
146                 /* no, expand the values */
147                 ji = json_object_iter_begin(path.object);
148                 jn = json_object_iter_end(path.object);
149                 while (!json_object_iter_equal(&ji, &jn)) {
150                         o = json_object_iter_peek_value(&ji);
151                         x = expand_$ref((struct path){ .object = o, .upper = &path });
152                         if (x != o)
153                                 json_object_object_add(path.object, json_object_iter_peek_name(&ji), x);
154                         json_object_iter_next(&ji);
155                 }
156                 break;
157         case json_type_array:
158                 /* expand the values of arrays */
159                 i = 0;
160                 n = (int)json_object_array_length(path.object);
161                 while (i != n) {
162                         o = json_object_array_get_idx(path.object, i);
163                         x = expand_$ref((struct path){ .object = o, .upper = &path });
164                         if (x != o)
165                                 json_object_array_put_idx(path.object, i, x);
166                         i++;
167                 }
168                 break;
169         default:
170                 /* otherwise no expansion */
171                 break;
172         }
173
174         /* return the given node */
175         return path.object;
176 }
177
178 /* create c name by replacing non alpha numeric characters with underscores */
179 char *cify(const char *str)
180 {
181         char *r = strdup(str);
182         int i = 0;
183         while (r && r[i]) {
184                 if (!isalnum(r[i]))
185                         r[i] = '_';
186                 i++;
187         }
188         return r;
189 }
190
191 /* format the specification as a C string */
192 char *make_info(const char *text, int split)
193 {
194         const char *a, *b;
195         char *desc, c, buf[3];
196         size_t len;
197         int i, pos, e;
198
199         /* estimated length */
200         a = b = text;
201         len = 1;
202         while((c = *b++)) {
203                 len += 1 + ('"' == c);
204         }
205
206         len += 7 * (1 + len / 72);
207         desc = malloc(len);
208         oom(desc);
209
210         len = pos = 0;
211         if (!split)
212                 desc[len++] = '"';
213         b = a;
214         while((c = *b++)) {
215                 if (c == '"') {
216                         buf[0] = '\\';
217                         buf[1] = '"';
218                         buf[2] = 0;
219                 }
220                 else if (c == '\\') {
221                         switch ((c = *b++)) {
222                         case 0:
223                                 b--;
224                                 break;
225                         case '/':
226                                 buf[0] = '/';
227                                 buf[1] = 0;
228                                 break;
229                         default:
230                                 buf[0] = '\\';
231                                 buf[1] = c;
232                                 buf[2] = 0;
233                                 break;
234                         }
235                 }
236                 else {
237                         buf[0] = c;
238                         buf[1] = 0;
239                 }
240                 i = e = 0;
241                 while (buf[i]) {
242                         if (split) {
243                                 if (pos >= 77 && !e) {
244                                         desc[len++] = '"';
245                                         desc[len++] = '\n';
246                                         pos = 0;
247                                 }
248                                 if (pos == 0) {
249                                         desc[len++] = ' ';
250                                         desc[len++] = ' ';
251                                         desc[len++] = ' ';
252                                         desc[len++] = ' ';
253                                         desc[len++] = '"';
254                                         pos = 5;
255                                 }
256                         }
257                         c = buf[i++];
258                         desc[len++] = c;
259                         e = !e && c == '\\';
260                         pos++;
261                 }
262         }
263         desc[len++] = '"';
264         if (split)
265                 desc[len++] = '\n';
266         desc[len] = 0;
267         return desc;
268 }
269
270 /* make the description of the object */
271 char *make_desc(struct json_object *o)
272 {
273         return make_info(json_object_to_json_string_ext(o, 0), 1);
274 }
275
276 /* get the permission odescription if set */
277 struct json_object *permissions_of_verb(struct json_object *obj)
278 {
279         struct json_object *x, *y;
280
281         if (json_object_object_get_ex(obj, "x-permissions", &x))
282                 return x;
283
284         if (json_object_object_get_ex(obj, "get", &x))
285                 if (json_object_object_get_ex(x, "x-permissions", &y))
286                         return y;
287
288         return NULL;
289 }
290
291 /* output the array of permissions */
292 void print_perms()
293 {
294         int i, n;
295         const char *fmtstr = cpp ? "\t%s" : "\t{ %s }";
296
297         n = a_perms ? (int)json_object_array_length(a_perms) : 0;
298         if (n) {
299                 printf("static const struct afb_auth _afb_auths_%s[] = {\n" , capi);
300                 i = 0;
301                 while (i < n) {
302                         printf(fmtstr, json_object_get_string(json_object_array_get_idx(a_perms, i)));
303                         printf(",\n"+(++i == n));
304                 }
305                 printf("};\n\n");
306         }
307 }
308
309 /*
310  * search in the global object 'd_perm' the computed representation
311  * of the permission described either by 'obj' or 'desc'
312  */
313 struct json_object *new_perm(struct json_object *obj, const char *desc)
314 {
315         const char *tag;
316         char *b;
317         struct json_object *x, *y;
318
319         tag = obj ? json_object_to_json_string_ext(obj, 0) : desc;
320         if (!json_object_object_get_ex(d_perms, tag, &y)) {
321
322                 /* creates the d_perms dico and the a_perms array */
323                 if (!d_perms) {
324                         d_perms = json_object_new_object();
325                         a_perms = json_object_new_array();
326                 }
327
328                 /* creates the reference in the structure */
329                 asprintf(&b, "&_afb_auths_%s[%d]", capi, (int)json_object_array_length(a_perms));
330                 x = json_object_new_string(desc);
331                 y = json_object_new_string(b);
332                 json_object_array_add(a_perms, x);
333                 json_object_object_add(d_perms, tag, y);
334                 free(b);
335         }
336         return y;
337 }
338
339 struct json_object *decl_perm(struct json_object *obj);
340
341 enum optype { And, Or };
342
343 /* recursive declare and/or permissions */
344 struct json_object *decl_perm_a(enum optype op, struct json_object *obj)
345 {
346         int i, n;
347         char *a;
348         const char *opstr, *fmtstr;
349         struct json_object *x, *y;
350
351         if (cpp) {
352                 fmtstr = "afb::auth_%s(%s, %s)";
353                 opstr = op==And ? "and" : "or";
354         } else {
355                 fmtstr = ".type = afb_auth_%s, .first = %s, .next = %s";
356                 opstr = op==And ? "And" : "Or";
357         }
358         x = NULL;
359         i = n = obj ? (int)json_object_array_length(obj) : 0;
360         while (i) {
361                 y = decl_perm(json_object_array_get_idx(obj, --i));
362                 if (!y)
363                         ;
364                 else if (!x)
365                         x = y;
366                 else if (x != y) {
367                         asprintf(&a, fmtstr, opstr, json_object_get_string(y), json_object_get_string(x));
368                         x = new_perm(NULL, a);
369                         free(a);
370                 }
371         }
372         return x;
373 }
374
375 /* declare the permission for obj */
376 struct json_object *decl_perm(struct json_object *obj)
377 {
378         char *a;
379         const char *fmt;
380         struct json_object *x, *y;
381
382         if (json_object_object_get_ex(d_perms, json_object_to_json_string_ext(obj, 0), &x))
383                 return x;
384
385         if (json_object_object_get_ex(obj, "permission", &x)) {
386                 if (cpp)
387                         fmt = "afb::auth_permission(\"%s\")";
388                 else
389                         fmt = ".type = afb_auth_Permission, .text = \"%s\"";
390                 asprintf(&a, fmt, json_object_get_string(x));
391                 y = new_perm(obj, a);
392                 free(a);
393         }
394         else if (json_object_object_get_ex(obj, "anyOf", &x)) {
395                 y = decl_perm_a(Or, x);
396         }
397         else if (json_object_object_get_ex(obj, "allOf", &x)) {
398                 y = decl_perm_a(And, x);
399         }
400         else if (json_object_object_get_ex(obj, "not", &x)) {
401                 x = decl_perm(x);
402                 if (cpp)
403                         fmt = "afb::auth_not(%s)";
404                 else
405                         fmt = ".type = afb_auth_Not, .first = %s";
406                 asprintf(&a, fmt, json_object_get_string(x));
407                 y = new_perm(obj, a);
408                 free(a);
409         }
410         else if (json_object_object_get_ex(obj, "LOA", &x))
411                 y = NULL;
412         else if (json_object_object_get_ex(obj, "session", &x))
413                 y = NULL;
414         else
415                 y = NULL;
416
417         return y;
418 }
419
420 void declare_permissions(const char *name, struct json_object *obj)
421 {
422         struct json_object *p;
423
424         p = permissions_of_verb(obj);
425         if (p)
426                 decl_perm(p);
427 }
428
429
430 #define SESSION_CLOSE  0x000001
431 #define SESSION_RENEW  0x000010
432 #define SESSION_CHECK  0x000100
433 #define SESSION_LOA_1  0x001000
434 #define SESSION_LOA_2  0x011000
435 #define SESSION_LOA_3  0x111000
436 #define SESSION_MASK   0x111111
437
438
439 int get_session(struct json_object *obj);
440
441 int get_session_a(int and, struct json_object *obj)
442 {
443         int i, n, x, y;
444
445         n = obj ? (int)json_object_array_length(obj) : 0;
446         if (n == 0)
447                 return 0;
448
449         i = n;
450         x = get_session(json_object_array_get_idx(obj, --i));
451         while (i) {
452                 y = get_session(json_object_array_get_idx(obj, --i));
453                 if (and)
454                         x &= y;
455                 else
456                         x |= y;
457         }
458         return x;
459 }
460
461 int get_session(struct json_object *obj)
462 {
463         int y;
464         const char *a;
465         struct json_object *x;
466
467         y = 0;
468         if (json_object_object_get_ex(obj, "anyOf", &x)) {
469                 y = get_session_a(1, x);
470         }
471         else if (json_object_object_get_ex(obj, "allOf", &x)) {
472                 y = get_session_a(0, x);
473         }
474         else if (json_object_object_get_ex(obj, "not", &x)) {
475                 y = ~get_session(x) & SESSION_MASK;
476         }
477         else if (json_object_object_get_ex(obj, "LOA", &x)) {
478                 switch (json_object_get_int(x)) {
479                 case 3: y = SESSION_LOA_3; break;
480                 case 2: y = SESSION_LOA_2; break;
481                 case 1: y = SESSION_LOA_1; break;
482                 default: break;
483                 }
484         }
485         else if (json_object_object_get_ex(obj, "session", &x)) {
486                 a = json_object_get_string(x);
487                 if (!strcmp(a, "check"))
488                         y = SESSION_CHECK;
489                 else if (!strcmp(a, "close"))
490                         y = SESSION_CLOSE;
491         }
492         else if (json_object_object_get_ex(obj, "token", &x)) {
493                 a = json_object_get_string(x);
494                 if (!strcmp(a, "refresh"))
495                         y = SESSION_RENEW;
496         }
497
498         return y;
499 }
500
501 void print_session(struct json_object *p)
502 {
503         int s, c, l;
504
505         s = p ? get_session(p) : 0;
506         c = 1;
507         if (s & SESSION_CHECK) {
508                 printf("%s", "|AFB_SESSION_CHECK" + c);
509                 c = 0;
510         }
511         if (s & SESSION_LOA_3 & ~SESSION_LOA_2)
512                 l = 3;
513         else if (s & SESSION_LOA_2 & ~SESSION_LOA_1)
514                 l = 2;
515         else if (s & SESSION_LOA_1)
516                 l = 1;
517         else
518                 l = 0;
519         if (l) {
520                 printf("%s%d", "|AFB_SESSION_LOA_" + c, l);
521                 c = 0;
522         }
523         if (s & SESSION_CLOSE) {
524                 printf("%s", "|AFB_SESSION_CLOSE" + c);
525                 c = 0;
526         }
527         if (s & SESSION_RENEW) {
528                 printf("%s", "|AFB_SESSION_REFRESH" + c);
529                 c = 0;
530         }
531         if (c)
532                 printf("AFB_SESSION_NONE");
533 }
534
535 void print_verb(const char *name)
536 {
537         printf("%s%s%s" , prefix, name, postfix);
538 }
539
540 void print_declare_verb(const char *name, struct json_object *obj)
541 {
542         if (T(scope))
543                 printf("%s ", scope);
544         printf("void ");
545         print_verb(name);
546         printf("(afb_req_t req);\n");
547 }
548
549 void print_struct_verb(const char *name, struct json_object *obj)
550 {
551         struct json_object *p, *i;
552         const char *info;
553
554         info = NULL;
555         if (json_object_object_get_ex(obj, "description", &i))
556                 info = json_object_get_string(i);
557
558         p = permissions_of_verb(obj);
559         printf(
560                 "    {\n"
561                 "        .verb = \"%s\",\n"
562                 "        .callback = "
563                 , name
564         );
565         print_verb(name);
566         printf(
567                 ",\n"
568                 "        .auth = %s,\n"
569                 "        .info = %s,\n"
570                 , p && decl_perm(p) ? json_object_get_string(decl_perm(p)) : "NULL"
571                 , info ? make_info(info, 0) : "NULL"
572         );
573         if (version == 3)
574                 printf(
575                         "        .vcbdata = NULL,\n"
576                 );
577         printf(
578                 "        .session = "
579         );
580         print_session(p);
581         if (version == 3)
582                 printf(
583                         ",\n"
584                         "        .glob = 0"
585                 );
586         printf(
587                 "\n"
588                 "    },\n"
589         );
590 }
591
592 void enum_verbs(void (*func)(const char *name, struct json_object *obj))
593 {
594         struct json_object_iterator ji, jn;
595         struct json_object *paths, *obj;
596         const char *name;
597
598         /* search the verbs */
599         paths = search("#/paths");
600         if (!paths)
601                 return;
602
603         /* list the verbs and sort it */
604         ji = json_object_iter_begin(paths);
605         jn = json_object_iter_end(paths);
606         while (!json_object_iter_equal(&ji, &jn)) {
607                 name = json_object_iter_peek_name(&ji);
608                 obj = json_object_iter_peek_value(&ji);
609                 name += (*name == '/');
610                 func(name, obj);
611                 json_object_iter_next(&ji);
612         }
613 }
614
615 void getvarbool(int *var, const char *path, int defval)
616 {
617         struct json_object *o;
618
619         if (*var != 0 && *var != 1) {
620                 o = search(path);
621                 if (o && json_object_is_type(o, json_type_boolean))
622                         *var = json_object_get_boolean(o);
623                 else
624                         *var = !!defval;
625         }
626 }
627
628 void getvar(const char **var, const char *path, const char *defval)
629 {
630         struct json_object *o;
631
632         if (!*var) {
633                 o = search(path);
634                 if (o && json_object_is_type(o, json_type_string))
635                         *var = json_object_get_string(o);
636                 else
637                         *var = defval;
638         }
639 }
640
641 /**
642  * process a file and prints its expansion on stdout
643  */
644 void process(char *filename)
645 {
646         char *desc;
647         const char *info;
648
649         /* translate - */
650         if (!strcmp(filename, "-"))
651                 filename = "/dev/stdin";
652
653         /* check access */
654         if (access(filename, R_OK)) {
655                 fprintf(stderr, "can't access file %s\n", filename);
656                 exit(1);
657         }
658
659         /* read the file */
660         root = json_object_from_file(filename);
661         if (!root) {
662                 fprintf(stderr, "reading file %s produced null\n", filename);
663                 exit(1);
664         }
665
666         /* create the description */
667         desc = make_desc(root);
668
669         /* expand references */
670         root = expand_$ref((struct path){ .object = root, .upper = NULL });
671
672         /* get some names */
673         getvar(&api, "#/info/x-binding-c-generator/api", NULL);
674         getvar(&preinit, "#/info/x-binding-c-generator/preinit", NULL);
675         getvar(&init, "#/info/x-binding-c-generator/init", NULL);
676         getvar(&onevent, "#/info/x-binding-c-generator/onevent", NULL);
677         getvar(&scope, "#/info/x-binding-c-generator/scope", "static");
678         getvar(&prefix, "#/info/x-binding-c-generator/prefix", "afb_verb_");
679         getvar(&postfix, "#/info/x-binding-c-generator/postfix", "_cb");
680         getvar(&provideclass, "#/info/x-binding-c-generator/provide-class", NULL);
681         getvar(&requireclass, "#/info/x-binding-c-generator/require-class", NULL);
682         getvar(&requireapi, "#/info/x-binding-c-generator/require-api", NULL);
683         getvarbool(&priv, "#/info/x-binding-c-generator/private", 0);
684         getvarbool(&noconc, "#/info/x-binding-c-generator/noconcurrency", 0);
685         getvar(&api, "#/info/title", "?");
686         info = NULL;
687         getvar(&info, "#/info/description", NULL);
688         capi = cify(api);
689
690         /* get the API name */
691         printf(
692                 "\n"
693                 "static const char _afb_description_%s[] =\n"
694                 "%s"
695                 ";\n"
696                 "\n"
697                 , capi, desc
698         );
699         enum_verbs(declare_permissions);
700         print_perms();
701         enum_verbs(print_declare_verb);
702         printf(
703                 "\n"
704                 "static const struct afb_verb_v%d _afb_verbs_%s[] = {\n"
705                 , version, capi
706         );
707         enum_verbs(print_struct_verb);
708         printf(
709                 "    {\n"
710                 "        .verb = NULL,\n"
711                 "        .callback = NULL,\n"
712                 "        .auth = NULL,\n"
713                 "        .info = NULL,\n"
714         );
715         if (version == 3)
716                 printf(
717                         "        .vcbdata = NULL,\n"
718                 );
719         printf(
720                 "        .session = 0"
721         );
722         if (version == 3)
723                 printf(
724                         ",\n"
725                         "        .glob = 0"
726                 );
727         printf(
728                 "\n"
729                 "       }\n"
730                 "};\n"
731         );
732
733         if (T(preinit) || T(init) || T(onevent)) {
734                 printf("\n");
735                 if (T(preinit)) {
736                         if (T(scope)) printf("%s ", scope);
737                         printf("int %s(%s);\n", preinit, version==3 ? "afb_api_t api" : "");
738                 }
739                 if (T(init)) {
740                         if (T(scope)) printf("%s ", scope);
741                         printf("int %s(%s);\n", init, version==3 ? "afb_api_t api" : "");
742                 }
743                 if (T(onevent)) {
744                         if (T(scope)) printf("%s ", scope);
745                         printf("void %s(%sconst char *event, struct json_object *object);\n",
746                                         onevent, version==3 ? "afb_api_t api, " : "");
747                 }
748         }
749
750         printf(
751                 "\n"
752                 "%sconst struct afb_binding_v%d %s%s = {\n"
753                 "    .api = \"%s\",\n"
754                 "    .specification = _afb_description_%s,\n"
755                 "    .info = %s,\n"
756                 "    .verbs = _afb_verbs_%s,\n"
757                 "    .preinit = %s,\n"
758                 "    .init = %s,\n"
759                 "    .onevent = %s,\n"
760                 , priv ? "static " : ""
761                 , version
762                 , priv ? "_afb_binding_" : version==3 ? "afbBindingV3" : "afbBindingV2"
763                 , priv ? capi : ""
764                 , api
765                 , capi
766                 , info ? make_info(info, 0) : "NULL"
767                 , capi
768                 , T(preinit) ? preinit : "NULL"
769                 , T(init) ? init : "NULL"
770                 , T(onevent) ? onevent : "NULL"
771         );
772
773
774         if (version == 3)
775                 printf(
776                         "    .userdata = NULL,\n"
777                         "    .provide_class = %s%s%s,\n"
778                         "    .require_class = %s%s%s,\n"
779                         "    .require_api = %s%s%s,\n"
780                         , T(provideclass) ? "\"" : "", T(provideclass) ? provideclass : "NULL", T(provideclass) ? "\"" : ""
781                         , T(requireclass) ? "\"" : "", T(requireclass) ? requireclass : "NULL", T(requireclass) ? "\"" : ""
782                         , T(requireapi) ? "\"" : "", T(requireapi) ? requireapi : "NULL", T(requireapi) ? "\"" : ""
783                 );
784
785
786         printf(
787                 "    .noconcurrency = %d\n"
788                 "};\n"
789                 "\n"
790                 , !!noconc
791         );
792
793         /* clean up */
794         json_object_put(root);
795         free(desc);
796 }
797
798 /** process the list of files or stdin if none */
799 int main(int ac, char **av)
800 {
801         int r, w;
802         av++;
803
804         r = w = 0;
805         while (av[r]) {
806                 if (!(strcmp(av[r], "-x") && strcmp(av[r], "--cpp"))) {
807                         cpp = 1;
808                         r++;
809                 } else if (!strcmp(av[r], "-2")) {
810                         version = 2;
811                         r++;
812                 } else if (!strcmp(av[r], "-3")) {
813                         version = 3;
814                         r++;
815                 } else {
816                         av[w++] = av[r++];
817                 }
818         }
819         av[w] = NULL;
820         if (!*av)
821                 process("-");
822         else {
823                 do { process(*av++); } while(*av);
824         }
825         return 0;
826 }
827