assembler: Add support for raw output format
[b43-tools.git] / assembler / args.c
1 /*
2  *   Copyright (C) 2006-2007  Michael Buesch <mb@bu3sch.de>
3  *
4  *   This program is free software; you can redistribute it and/or modify
5  *   it under the terms of the GNU General Public License version 2
6  *   as published by the Free Software Foundation.
7  *
8  *   This program is distributed in the hope that it will be useful,
9  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *   GNU General Public License for more details.
12  */
13
14 #include "args.h"
15 #include "main.h"
16 #include "util.h"
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23
24
25 int _debug;
26 bool arg_print_sizes;
27 const char *initvals_fn_extension = ".initvals";
28 static const char *real_infile_name;
29 enum fwformat output_format = FMT_B43;
30
31
32 #define ARG_MATCH               0
33 #define ARG_NOMATCH             1
34 #define ARG_ERROR               -1
35
36 static int do_cmp_arg(char **argv, int *pos,
37                       const char *template,
38                       int allow_merged,
39                       const char **param)
40 {
41         char *arg;
42         char *next_arg;
43         size_t arg_len, template_len;
44
45         arg = argv[*pos];
46         next_arg = argv[*pos + 1];
47         arg_len = strlen(arg);
48         template_len = strlen(template);
49
50         if (param) {
51                 /* Maybe we have a merged parameter here.
52                  * A merged parameter is "-pfoobar" for example.
53                  */
54                 if (allow_merged && arg_len > template_len) {
55                         if (memcmp(arg, template, template_len) == 0) {
56                                 *param = arg + template_len;
57                                 return ARG_MATCH;
58                         }
59                         return ARG_NOMATCH;
60                 } else if (arg_len != template_len)
61                         return ARG_NOMATCH;
62                 *param = next_arg;
63         }
64         if (strcmp(arg, template) == 0) {
65                 if (param) {
66                         /* Skip the parameter on the next iteration. */
67                         (*pos)++;
68                         if (*param == NULL) {
69                                 fprintf(stderr, "%s needs a parameter\n", arg);
70                                 return ARG_ERROR;
71                         }
72                 }
73                 return ARG_MATCH;
74         }
75
76         return ARG_NOMATCH;
77 }
78
79 /* Simple and lean command line argument parsing. */
80 static int cmp_arg(char **argv, int *pos,
81                    const char *long_template,
82                    const char *short_template,
83                    const char **param)
84 {
85         int err;
86
87         if (long_template) {
88                 err = do_cmp_arg(argv, pos, long_template, 0, param);
89                 if (err == ARG_MATCH || err == ARG_ERROR)
90                         return err;
91         }
92         err = ARG_NOMATCH;
93         if (short_template)
94                 err = do_cmp_arg(argv, pos, short_template, 1, param);
95         return err;
96 }
97
98 static void usage(int argc, char **argv)
99 {
100         printf("Usage: %s INPUT_FILE OUTPUT_FILE [OPTIONS]\n", argv[0]);
101         printf("  -f|--format FMT     Output file format. FMT must be one of:\n");
102         printf("                      raw-le32, raw-be32, b43\n");
103         printf("  -d|--debug          Print verbose debugging info\n");
104         printf("                      Repeat for more verbose debugging\n");
105         printf("  -s|--psize          Print the size of the code after assembling\n");
106         printf("  -e|--ivalext EXT    Filename extension for the initvals\n");
107         printf("  -h|--help           Print this help\n");
108 }
109
110 int parse_args(int argc, char **argv)
111 {
112         int i;
113         int res;
114         const char *param;
115
116         if (argc < 3)
117                 goto out_usage;
118         infile_name = argv[1];
119         outfile_name = argv[2];
120
121         for (i = 3; i < argc; i++) {
122                 if ((res = cmp_arg(argv, &i, "--help", "-h", NULL)) == ARG_MATCH) {
123                         usage(argc, argv);
124                         return 1;
125                 } else if ((res = cmp_arg(argv, &i, "--format", "-f", &param)) == ARG_MATCH) {
126                         if (strcasecmp(param, "raw-le32") == 0)
127                                 output_format = FMT_RAW_LE32;
128                         else if (strcasecmp(param, "raw-be32") == 0)
129                                 output_format = FMT_RAW_BE32;
130                         else if (strcasecmp(param, "b43") == 0)
131                                 output_format = FMT_B43;
132                         else {
133                                 fprintf(stderr, "Invalid -f|--format\n\n");
134                                 goto out_usage;
135                         }
136                 } else if ((res = cmp_arg(argv, &i, "--debug", "-d", NULL)) == ARG_MATCH) {
137                         _debug++;
138                 } else if ((res = cmp_arg(argv, &i, "--psize", "-s", NULL)) == ARG_MATCH) {
139                         arg_print_sizes = 1;
140                 } else if ((res = cmp_arg(argv, &i, "--ivalext", "-e", &initvals_fn_extension)) == ARG_MATCH) {
141                         /* initvals_fn_extension is set to the extension. */
142                 } else if ((res = cmp_arg(argv, &i, "--__real_infile", NULL, &real_infile_name)) == ARG_MATCH) {
143                         /* real_infile_name is set. */
144                 } else {
145                         fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
146                         goto out_usage;
147                 }
148         }
149         if (!real_infile_name)
150                 real_infile_name = infile_name;
151         if (strcmp(real_infile_name, outfile_name) == 0) {
152                 fprintf(stderr, "Error: INPUT and OUTPUT filename must not be the same\n");
153                 goto out_usage;
154         }
155
156         return 0;
157 out_usage:
158         usage(argc, argv);
159         return -1;
160 }
161
162 int open_input_file(void)
163 {
164         int fd;
165         int err;
166
167         if (strcmp(infile_name, "-") == 0) {
168                 /* infile == stdin */
169                 fd = STDIN_FILENO;
170         } else {
171                 fd = open(infile_name, O_RDONLY);
172                 if (fd < 0) {
173                         fprintf(stderr, "Could not open INPUT_FILE %s\n",
174                                 infile_name);
175                         return -1;
176                 }
177                 err = dup2(fd, STDIN_FILENO);
178                 if (err) {
179                         fprintf(stderr, "Could not dup INPUT_FILE %s "
180                                 "to STDIN\n", infile_name);
181                         close(fd);
182                         return -1;
183                 }
184         }
185         infile.fd = fd;
186
187         return 0;
188 }
189
190 void close_input_file(void)
191 {
192         if (strcmp(infile_name, "-") != 0)
193                 close(infile.fd);
194 }