.OPD -> .PackageInfo conversion tool
This commit is contained in:
parent
116852fecb
commit
1bcc0f6e4a
@ -135,6 +135,7 @@ SubInclude HAIKU_TOP src tools hack_coff ;
|
|||||||
SubInclude HAIKU_TOP src tools keymap ;
|
SubInclude HAIKU_TOP src tools keymap ;
|
||||||
SubInclude HAIKU_TOP src tools locale ;
|
SubInclude HAIKU_TOP src tools locale ;
|
||||||
SubInclude HAIKU_TOP src tools makebootable ;
|
SubInclude HAIKU_TOP src tools makebootable ;
|
||||||
|
SubInclude HAIKU_TOP src tools opd_to_package_info ;
|
||||||
SubInclude HAIKU_TOP src tools package ;
|
SubInclude HAIKU_TOP src tools package ;
|
||||||
SubInclude HAIKU_TOP src tools rc ;
|
SubInclude HAIKU_TOP src tools rc ;
|
||||||
SubInclude HAIKU_TOP src tools remote_disk_server ;
|
SubInclude HAIKU_TOP src tools remote_disk_server ;
|
||||||
|
9
src/tools/opd_to_package_info/Jamfile
Normal file
9
src/tools/opd_to_package_info/Jamfile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
SubDir HAIKU_TOP src tools opd_to_package_info ;
|
||||||
|
|
||||||
|
USES_BE_API on <build>opd_to_package_info = true ;
|
||||||
|
|
||||||
|
BuildPlatformMain <build>opd_to_package_info :
|
||||||
|
opd_to_package_info.cpp
|
||||||
|
:
|
||||||
|
$(HOST_LIBBE) $(HOST_LIBSTDC++) $(HOST_LIBSUPC++)
|
||||||
|
;
|
377
src/tools/opd_to_package_info/opd_to_package_info.cpp
Normal file
377
src/tools/opd_to_package_info/opd_to_package_info.cpp
Normal file
@ -0,0 +1,377 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <Message.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FLAG_MANDATORY_FIELD = 0x01,
|
||||||
|
FLAG_LIST_ATTRIBUTE = 0x02,
|
||||||
|
FLAG_DONT_QUOTE = 0x04,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern const char* __progname;
|
||||||
|
const char* kCommandName = __progname;
|
||||||
|
|
||||||
|
|
||||||
|
static const char* kUsage =
|
||||||
|
"Usage: %s [ <options> ] <optional package description> "
|
||||||
|
"[ <package info> ]\n"
|
||||||
|
"Converts an .OptionalPackageDescription to a .PackageInfo. If "
|
||||||
|
"<package info>\n"
|
||||||
|
"is not specified, the output is printed to stdout.\n"
|
||||||
|
"Note that the generated .PackageInfo will not be complete. For several\n"
|
||||||
|
"fields an empty string will be used, unless specified via an option.\n"
|
||||||
|
"The \"provides\" and \"requires\" lists will always be empty, though\n"
|
||||||
|
"\n"
|
||||||
|
"Options:\n"
|
||||||
|
" -a <arch> - Use the given architecture string. Default is to "
|
||||||
|
"guess from the file name.\n"
|
||||||
|
" -d <description> - Use the given descripton string. Default is to use\n"
|
||||||
|
" the summary.\n"
|
||||||
|
" -h, --help - Print this usage info.\n"
|
||||||
|
" -p <packager> - Use the given packager string. Default is an empty "
|
||||||
|
"string.\n"
|
||||||
|
" -s <summary> - Use the given summary string. Default is an empty "
|
||||||
|
"string.\n"
|
||||||
|
" -v <version> - Use the given version string. Overrides the version\n"
|
||||||
|
" from the input file.\n"
|
||||||
|
" -V <vendor> - Use the given vendor string. Default is an empty "
|
||||||
|
"string.\n"
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_usage_and_exit(bool error)
|
||||||
|
{
|
||||||
|
fprintf(error ? stderr : stdout, kUsage, kCommandName);
|
||||||
|
exit(error ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char*
|
||||||
|
guess_architecture(const char* name)
|
||||||
|
{
|
||||||
|
if (strstr(name, "x86") != NULL) {
|
||||||
|
if (strstr(name, "gcc4") != NULL)
|
||||||
|
return "x86";
|
||||||
|
|
||||||
|
return "x86_gcc2";
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct OuputWriter {
|
||||||
|
OuputWriter(FILE* output, const BMessage& package)
|
||||||
|
:
|
||||||
|
fOutput(output),
|
||||||
|
fPackage(package)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteAttribute(const char* attributeName, const char* fieldName,
|
||||||
|
const char* defaultValue, uint32 flags)
|
||||||
|
{
|
||||||
|
if (fieldName != NULL) {
|
||||||
|
int32 count;
|
||||||
|
type_code type;
|
||||||
|
if (fPackage.GetInfo(fieldName, &type, &count) != B_OK) {
|
||||||
|
if ((flags & FLAG_MANDATORY_FIELD) != 0) {
|
||||||
|
fprintf(stderr, "Error: Missing mandatory field \"%s\" in "
|
||||||
|
"input file.\n", fieldName);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
if (count == 1) {
|
||||||
|
const char* value;
|
||||||
|
fPackage.FindString(fieldName, &value);
|
||||||
|
_WriteSingleElementAttribute(attributeName, value, flags);
|
||||||
|
} else {
|
||||||
|
fprintf(fOutput, "\n%s {\n", attributeName);
|
||||||
|
|
||||||
|
for (int32 i = 0; i < count; i++) {
|
||||||
|
fprintf(fOutput, "\t");
|
||||||
|
const char* value;
|
||||||
|
fPackage.FindString(fieldName, i, &value);
|
||||||
|
_WriteValue(value, flags);
|
||||||
|
fputc('\n', fOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("}\n", fOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the default value
|
||||||
|
if (defaultValue != NULL)
|
||||||
|
_WriteSingleElementAttribute(attributeName, defaultValue, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _WriteSingleElementAttribute(const char* attributeName,
|
||||||
|
const char* value, uint32 flags)
|
||||||
|
{
|
||||||
|
fputs(attributeName, fOutput);
|
||||||
|
|
||||||
|
int32 indentation = 16 - (int32)strlen(attributeName);
|
||||||
|
if (indentation > 0)
|
||||||
|
indentation = (indentation + 3) / 4;
|
||||||
|
else
|
||||||
|
indentation = 1;
|
||||||
|
|
||||||
|
for (int32 i = 0; i < indentation; i++)
|
||||||
|
fputc('\t', fOutput);
|
||||||
|
|
||||||
|
_WriteValue(value, flags);
|
||||||
|
fputc('\n', fOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _WriteValue(const char* value, uint32 flags)
|
||||||
|
{
|
||||||
|
BString escapedValue(value);
|
||||||
|
|
||||||
|
if ((flags & FLAG_DONT_QUOTE) != 0) {
|
||||||
|
escapedValue.CharacterEscape("\\\"' \t", '\\');
|
||||||
|
fputs(escapedValue.String(), fOutput);
|
||||||
|
} else {
|
||||||
|
escapedValue.CharacterEscape("\\\"", '\\');
|
||||||
|
fprintf(fOutput, "\"%s\"", escapedValue.String());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FILE* fOutput;
|
||||||
|
const BMessage& fPackage;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, const char* const* argv)
|
||||||
|
{
|
||||||
|
const char* architecture = NULL;
|
||||||
|
const char* version = NULL;
|
||||||
|
const char* summary = "";
|
||||||
|
const char* description = "";
|
||||||
|
const char* packager = "";
|
||||||
|
const char* vendor = "";
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
static const struct option kLongOptions[] = {
|
||||||
|
{ "help", no_argument, 0, 'h' },
|
||||||
|
{ 0, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
opterr = 0; // don't print errors
|
||||||
|
int c = getopt_long(argc, (char**)argv, "+ha:d:p:s:v:V:", kLongOptions,
|
||||||
|
NULL);
|
||||||
|
if (c == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 'a':
|
||||||
|
architecture = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
description = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'h':
|
||||||
|
print_usage_and_exit(false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
packager = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
summary = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'v':
|
||||||
|
version = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'V':
|
||||||
|
vendor = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
print_usage_and_exit(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// One or two argument should remain -- the input file and optionally the
|
||||||
|
// output file.
|
||||||
|
if (optind + 1 != argc && optind + 2 != argc)
|
||||||
|
print_usage_and_exit(true);
|
||||||
|
|
||||||
|
const char* opdName = argv[optind++];
|
||||||
|
const char* packageInfoName = optind < argc ? argv[optind++] : NULL;
|
||||||
|
|
||||||
|
// guess architecture from the input file name, if not given
|
||||||
|
if (architecture == NULL) {
|
||||||
|
const char* fileName = strrchr(opdName, '/');
|
||||||
|
if (fileName == NULL)
|
||||||
|
fileName = opdName;
|
||||||
|
else
|
||||||
|
fileName++;
|
||||||
|
|
||||||
|
// Try to guess from the file name.
|
||||||
|
architecture = guess_architecture(fileName);
|
||||||
|
|
||||||
|
// If we've got nothing yet, try to guess from the file name.
|
||||||
|
if (architecture == NULL && fileName != opdName)
|
||||||
|
architecture = guess_architecture(opdName);
|
||||||
|
|
||||||
|
// fallback is "any"
|
||||||
|
if (architecture == NULL)
|
||||||
|
architecture = "any";
|
||||||
|
}
|
||||||
|
|
||||||
|
// open the input
|
||||||
|
FILE* input = fopen(opdName, "r");
|
||||||
|
if (input == NULL) {
|
||||||
|
fprintf(stderr, "Failed to open input file \"%s\": %s\n", opdName,
|
||||||
|
strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// open the output
|
||||||
|
FILE* output = packageInfoName != NULL
|
||||||
|
? fopen(packageInfoName, "w+") : stdout;
|
||||||
|
if (output == NULL) {
|
||||||
|
fprintf(stderr, "Failed to open output file \"%s\": %s\n",
|
||||||
|
packageInfoName, strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// read and parse the input file
|
||||||
|
BMessage package;
|
||||||
|
BString fieldName;
|
||||||
|
BString fieldValue;
|
||||||
|
char lineBuffer[LINE_MAX];
|
||||||
|
bool seenPackageAttribute = false;
|
||||||
|
|
||||||
|
while (char* line = fgets(lineBuffer, sizeof(lineBuffer), input)) {
|
||||||
|
// chop off line break
|
||||||
|
size_t lineLen = strlen(line);
|
||||||
|
if (lineLen > 0 && line[lineLen - 1] == '\n')
|
||||||
|
line[--lineLen] = '\0';
|
||||||
|
|
||||||
|
// flush previous field, if a new field begins, otherwise append
|
||||||
|
if (lineLen == 0 || !isspace(line[0])) {
|
||||||
|
// new field -- flush the previous one
|
||||||
|
if (fieldName.Length() > 0) {
|
||||||
|
fieldValue.Trim();
|
||||||
|
package.AddString(fieldName.String(), fieldValue);
|
||||||
|
fieldName = "";
|
||||||
|
}
|
||||||
|
} else if (fieldName.Length() > 0) {
|
||||||
|
// append to current field
|
||||||
|
fieldValue += line;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
// bogus line -- ignore
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lineLen == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// parse new field
|
||||||
|
char* colon = strchr(line, ':');
|
||||||
|
if (colon == NULL) {
|
||||||
|
// bogus line -- ignore
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldName.SetTo(line, colon - line);
|
||||||
|
fieldName.Trim();
|
||||||
|
if (fieldName.Length() == 0) {
|
||||||
|
// invalid field name
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldValue = colon + 1;
|
||||||
|
|
||||||
|
if (fieldName == "Package") {
|
||||||
|
if (seenPackageAttribute) {
|
||||||
|
fprintf(stderr, "Duplicate \"Package\" attribute!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
seenPackageAttribute = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the output
|
||||||
|
OuputWriter writer(output, package);
|
||||||
|
|
||||||
|
// name
|
||||||
|
writer.WriteAttribute("name", "Package", NULL,
|
||||||
|
FLAG_MANDATORY_FIELD | FLAG_DONT_QUOTE);
|
||||||
|
|
||||||
|
// version
|
||||||
|
writer.WriteAttribute("version", "Version", version, FLAG_DONT_QUOTE);
|
||||||
|
|
||||||
|
// architecture
|
||||||
|
fprintf(output, "architecture\t%s\n", architecture);
|
||||||
|
|
||||||
|
// summary
|
||||||
|
fprintf(output, "summary\t\t\t\"%s\"\n", summary);
|
||||||
|
|
||||||
|
// description
|
||||||
|
if (description != NULL)
|
||||||
|
fprintf(output, "description\t\t\"%s\"\n", description);
|
||||||
|
else
|
||||||
|
fprintf(output, "description\t\t\"%s\"\n", summary);
|
||||||
|
|
||||||
|
// packager
|
||||||
|
fprintf(output, "packager\t\t\"%s\"\n", packager);
|
||||||
|
|
||||||
|
// vendor
|
||||||
|
fprintf(output, "vendor\t\t\t\"%s\"\n", vendor);
|
||||||
|
|
||||||
|
// copyrights
|
||||||
|
writer.WriteAttribute("copyrights", "Copyright", NULL,
|
||||||
|
FLAG_MANDATORY_FIELD | FLAG_LIST_ATTRIBUTE);
|
||||||
|
|
||||||
|
// licenses
|
||||||
|
writer.WriteAttribute("licenses", "License", NULL, FLAG_LIST_ATTRIBUTE);
|
||||||
|
|
||||||
|
// empty provides
|
||||||
|
fprintf(output, "\nprovides {\n}\n");
|
||||||
|
|
||||||
|
// empty requires
|
||||||
|
fprintf(output, "\nrequires {\n}\n");
|
||||||
|
|
||||||
|
// URLs
|
||||||
|
writer.WriteAttribute("urls", "URL", NULL, FLAG_LIST_ATTRIBUTE);
|
||||||
|
|
||||||
|
// source URLs
|
||||||
|
writer.WriteAttribute("source-urls", "SourceURL", NULL,
|
||||||
|
FLAG_LIST_ATTRIBUTE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user