HaikuDepot: notify work status from main window
[haiku.git] / src / tools / opd_to_package_info / opd_to_package_info.cpp
blob104a2847186de9df15d1b59772e8565df3c028af
1 /*
2 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <ctype.h>
8 #include <errno.h>
9 #include <getopt.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
14 #include <Message.h>
15 #include <String.h>
18 enum {
19 FLAG_MANDATORY_FIELD = 0x01,
20 FLAG_LIST_ATTRIBUTE = 0x02,
21 FLAG_DONT_QUOTE = 0x04,
25 extern const char* __progname;
26 const char* kCommandName = __progname;
29 static const char* kUsage =
30 "Usage: %s [ <options> ] <optional package description> "
31 "[ <package info> ]\n"
32 "Converts an .OptionalPackageDescription to a .PackageInfo. If "
33 "<package info>\n"
34 "is not specified, the output is printed to stdout.\n"
35 "Note that the generated .PackageInfo will not be complete. For several\n"
36 "fields an empty string will be used, unless specified via an option.\n"
37 "The \"provides\" and \"requires\" lists will always be empty, though\n"
38 "\n"
39 "Options:\n"
40 " -a <arch> - Use the given architecture string. Default is to "
41 "guess from the file name.\n"
42 " -d <description> - Use the given descripton string. Default is to use\n"
43 " the summary.\n"
44 " -h, --help - Print this usage info.\n"
45 " -p <packager> - Use the given packager string. Default is an empty "
46 "string.\n"
47 " -s <summary> - Use the given summary string. Default is an empty "
48 "string.\n"
49 " -v <version> - Use the given version string. Overrides the version\n"
50 " from the input file.\n"
51 " -V <vendor> - Use the given vendor string. Default is an empty "
52 "string.\n"
56 static void
57 print_usage_and_exit(bool error)
59 fprintf(error ? stderr : stdout, kUsage, kCommandName);
60 exit(error ? 1 : 0);
64 static const char*
65 guess_architecture(const char* name)
67 if (strstr(name, "x86") != NULL) {
68 if (strstr(name, "gcc4") != NULL)
69 return "x86";
71 return "x86_gcc2";
74 return NULL;
78 struct OuputWriter {
79 OuputWriter(FILE* output, const BMessage& package)
81 fOutput(output),
82 fPackage(package)
86 void WriteAttribute(const char* attributeName, const char* fieldName,
87 const char* defaultValue, uint32 flags)
89 if (fieldName != NULL) {
90 int32 count;
91 type_code type;
92 if (fPackage.GetInfo(fieldName, &type, &count) != B_OK) {
93 if ((flags & FLAG_MANDATORY_FIELD) != 0) {
94 fprintf(stderr, "Error: Missing mandatory field \"%s\" in "
95 "input file.\n", fieldName);
96 exit(1);
98 count = 0;
101 if (count > 0) {
102 if (count == 1) {
103 const char* value;
104 fPackage.FindString(fieldName, &value);
105 _WriteSingleElementAttribute(attributeName, value, flags);
106 } else {
107 fprintf(fOutput, "\n%s {\n", attributeName);
109 for (int32 i = 0; i < count; i++) {
110 fprintf(fOutput, "\t");
111 const char* value;
112 fPackage.FindString(fieldName, i, &value);
113 _WriteValue(value, flags);
114 fputc('\n', fOutput);
117 fputs("}\n", fOutput);
120 return;
124 // write the default value
125 if (defaultValue != NULL)
126 _WriteSingleElementAttribute(attributeName, defaultValue, flags);
129 private:
130 void _WriteSingleElementAttribute(const char* attributeName,
131 const char* value, uint32 flags)
133 fputs(attributeName, fOutput);
135 int32 indentation = 16 - (int32)strlen(attributeName);
136 if (indentation > 0)
137 indentation = (indentation + 3) / 4;
138 else
139 indentation = 1;
141 for (int32 i = 0; i < indentation; i++)
142 fputc('\t', fOutput);
144 _WriteValue(value, flags);
145 fputc('\n', fOutput);
148 void _WriteValue(const char* value, uint32 flags)
150 BString escapedValue(value);
152 if ((flags & FLAG_DONT_QUOTE) != 0) {
153 escapedValue.CharacterEscape("\\\"' \t", '\\');
154 fputs(escapedValue.String(), fOutput);
155 } else {
156 escapedValue.CharacterEscape("\\\"", '\\');
157 fprintf(fOutput, "\"%s\"", escapedValue.String());
161 private:
162 FILE* fOutput;
163 const BMessage& fPackage;
168 main(int argc, const char* const* argv)
170 const char* architecture = NULL;
171 const char* version = NULL;
172 const char* summary = "";
173 const char* description = "";
174 const char* packager = "";
175 const char* vendor = "";
177 while (true) {
178 static const struct option kLongOptions[] = {
179 { "help", no_argument, 0, 'h' },
180 { 0, 0, 0, 0 }
183 opterr = 0; // don't print errors
184 int c = getopt_long(argc, (char**)argv, "+ha:d:p:s:v:V:", kLongOptions,
185 NULL);
186 if (c == -1)
187 break;
189 switch (c) {
190 case 'a':
191 architecture = optarg;
192 break;
194 case 'd':
195 description = optarg;
196 break;
198 case 'h':
199 print_usage_and_exit(false);
200 break;
202 case 'p':
203 packager = optarg;
204 break;
206 case 's':
207 summary = optarg;
208 break;
210 case 'v':
211 version = optarg;
212 break;
214 case 'V':
215 vendor = optarg;
216 break;
218 default:
219 print_usage_and_exit(true);
220 break;
224 // One or two argument should remain -- the input file and optionally the
225 // output file.
226 if (optind + 1 != argc && optind + 2 != argc)
227 print_usage_and_exit(true);
229 const char* opdName = argv[optind++];
230 const char* packageInfoName = optind < argc ? argv[optind++] : NULL;
232 // guess architecture from the input file name, if not given
233 if (architecture == NULL) {
234 const char* fileName = strrchr(opdName, '/');
235 if (fileName == NULL)
236 fileName = opdName;
237 else
238 fileName++;
240 // Try to guess from the file name.
241 architecture = guess_architecture(fileName);
243 // If we've got nothing yet, try to guess from the file name.
244 if (architecture == NULL && fileName != opdName)
245 architecture = guess_architecture(opdName);
247 // fallback is "any"
248 if (architecture == NULL)
249 architecture = "any";
252 // open the input
253 FILE* input = fopen(opdName, "r");
254 if (input == NULL) {
255 fprintf(stderr, "Failed to open input file \"%s\": %s\n", opdName,
256 strerror(errno));
257 exit(1);
260 // open the output
261 FILE* output = packageInfoName != NULL
262 ? fopen(packageInfoName, "w+") : stdout;
263 if (output == NULL) {
264 fprintf(stderr, "Failed to open output file \"%s\": %s\n",
265 packageInfoName, strerror(errno));
266 exit(1);
269 // read and parse the input file
270 BMessage package;
271 BString fieldName;
272 BString fieldValue;
273 char lineBuffer[LINE_MAX];
274 bool seenPackageAttribute = false;
276 while (char* line = fgets(lineBuffer, sizeof(lineBuffer), input)) {
277 // chop off line break
278 size_t lineLen = strlen(line);
279 if (lineLen > 0 && line[lineLen - 1] == '\n')
280 line[--lineLen] = '\0';
282 // flush previous field, if a new field begins, otherwise append
283 if (lineLen == 0 || !isspace(line[0])) {
284 // new field -- flush the previous one
285 if (fieldName.Length() > 0) {
286 fieldValue.Trim();
287 package.AddString(fieldName.String(), fieldValue);
288 fieldName = "";
290 } else if (fieldName.Length() > 0) {
291 // append to current field
292 fieldValue += line;
293 continue;
294 } else {
295 // bogus line -- ignore
296 continue;
299 if (lineLen == 0)
300 continue;
302 // parse new field
303 char* colon = strchr(line, ':');
304 if (colon == NULL) {
305 // bogus line -- ignore
306 continue;
309 fieldName.SetTo(line, colon - line);
310 fieldName.Trim();
311 if (fieldName.Length() == 0) {
312 // invalid field name
313 continue;
316 fieldValue = colon + 1;
318 if (fieldName == "Package") {
319 if (seenPackageAttribute) {
320 fprintf(stderr, "Duplicate \"Package\" attribute!\n");
321 exit(1);
324 seenPackageAttribute = true;
328 // write the output
329 OuputWriter writer(output, package);
331 // name
332 writer.WriteAttribute("name", "Package", NULL,
333 FLAG_MANDATORY_FIELD | FLAG_DONT_QUOTE);
335 // version
336 writer.WriteAttribute("version", "Version", version, FLAG_DONT_QUOTE);
338 // architecture
339 fprintf(output, "architecture\t%s\n", architecture);
341 // summary
342 fprintf(output, "summary\t\t\t\"%s\"\n", summary);
344 // description
345 if (description != NULL)
346 fprintf(output, "description\t\t\"%s\"\n", description);
347 else
348 fprintf(output, "description\t\t\"%s\"\n", summary);
350 // packager
351 fprintf(output, "packager\t\t\"%s\"\n", packager);
353 // vendor
354 fprintf(output, "vendor\t\t\t\"%s\"\n", vendor);
356 // copyrights
357 writer.WriteAttribute("copyrights", "Copyright", NULL,
358 FLAG_MANDATORY_FIELD | FLAG_LIST_ATTRIBUTE);
360 // licenses
361 writer.WriteAttribute("licenses", "License", NULL, FLAG_LIST_ATTRIBUTE);
363 // empty provides
364 fprintf(output, "\nprovides {\n}\n");
366 // empty requires
367 fprintf(output, "\nrequires {\n}\n");
369 // URLs
370 writer.WriteAttribute("urls", "URL", NULL, FLAG_LIST_ATTRIBUTE);
372 // source URLs
373 writer.WriteAttribute("source-urls", "SourceURL", NULL,
374 FLAG_LIST_ATTRIBUTE);
376 return 0;