diff --git a/Documentation/yab-Commands b/Documentation/yab-Commands index f90b5f8..ae7ba42 100644 --- a/Documentation/yab-Commands +++ b/Documentation/yab-Commands @@ -18,8 +18,9 @@ ATTRIBUTE CLEAR Name$, Filename$ Value$ = ATTRIBUTE GET$ Name$, Filename$ Get the string value of the attribute Name$ for file Filename$. Returns "true" or "false" for "Bool" type attributes. - If Name$="", returns a list of attribute names and their types separated by " | ". returns "Unsupported" for types that are not valid for yab. - it name$ and filenbame$ both = "", returns the current program path and filename + If Name$="", returns a list of attribute names and their types separated + by " | ". returns "Unsupported" for types that are not valid for yab. + If Name$ and Filename$ both = "", returns the current program directory. Value = ATTRIBUTE GET Name$, Filename$ Get the number value of the attribute Name$ for file Filename$. diff --git a/README.md b/README.md index c96e1da..37904bc 100644 --- a/README.md +++ b/README.md @@ -24,4 +24,6 @@ This will insure that the BuildFactory is refreshed with the current version. LICENSE: Artistic License -- Create your own stand-alone binaries with yab under any license you want. AUTHOR: jan__64 -yab homepage: http://yab.orgfree.com/ \ No newline at end of file +yab homepage: http://yab.orgfree.com/ + +yab forum: http://yab-talk.forumotion.com/ \ No newline at end of file diff --git a/src/YAB.rdef.rsrc b/src/YAB.rdef.rsrc index b78cbdd..e56c03a 100644 Binary files a/src/YAB.rdef.rsrc and b/src/YAB.rdef.rsrc differ diff --git a/src/YabInterface.cpp b/src/YabInterface.cpp index a9dc250..d5dc0cb 100644 --- a/src/YabInterface.cpp +++ b/src/YabInterface.cpp @@ -9220,6 +9220,8 @@ const char* YabInterface::AttributeGet1(const char* name, const char* filename) if (tempname.Length() >0) ErrorGen("Attribute file not found!"); BString appdir = mainFileName; + int32 i = appdir.FindLast("/"); + appdir.Truncate(i); return appdir; } diff --git a/src/resattr b/src/resattr deleted file mode 100755 index 36f7fc9..0000000 Binary files a/src/resattr and /dev/null differ diff --git a/src/resattr.cpp b/src/resattr.cpp new file mode 100644 index 0000000..ec02f48 --- /dev/null +++ b/src/resattr.cpp @@ -0,0 +1,313 @@ +// resattr.cpp + +#include +#include +#include + +#include +#include +#include +#include + +// usage +static const char *kUsage = +"Usage: %s [ ] -o [ ... ]\n" +"\n" +"Reads resources from zero or more input files and adds them as attributes\n" +"to the specified output file, or (in reverse mode) reads attributes from\n" +"zero or more input files and adds them as resources to the specified output\n" +"file. If not existent the output file is created as an empty file.\n" +"\n" +"Options:\n" +" -h, --help - Print this text.\n" +" -o - Specifies the output file.\n" +" -O, --overwrite - Overwrite existing attributes. regardless of whether\n" +" an attribute does already exist, it is always written\n" +" when a respective resource is encountered in an input\n" +" file. The last input file specifying the attribute\n" +" wins. If the options is not given, already existing\n" +" attributes remain untouched. Otherwise the first input\n" +" file specifying an attribute wins.\n" +" -r, --reverse - Reverse mode: Reads attributes from input files and\n" +" writes resources. A unique resource ID is assigned to\n" +" each attribute, so there will be no conflicts if two\n" +" input files feature the same attribute.\n" +; + +// command line args +static int sArgc; +static const char *const *sArgv; + +// print_usage +void +print_usage(bool error) +{ + // get nice program name + const char *programName = (sArgc > 0 ? sArgv[0] : "resattr"); + if (const char *lastSlash = strrchr(programName, '/')) + programName = lastSlash + 1; + + // print usage + fprintf((error ? stderr : stdout), kUsage, programName); +} + +// print_usage_and_exit +static +void +print_usage_and_exit(bool error) +{ + print_usage(error); + exit(error ? 1 : 0); +} + +// next_arg +static +const char* +next_arg(int argc, const char* const* argv, int& argi, bool dontFail = false) +{ + if (argi + 1 >= argc) { + if (dontFail) + return NULL; + print_usage_and_exit(true); + } + + return argv[++argi]; +} + +// write_attributes +static +void +write_attributes(BNode &out, const char *inFileName, BResources &resources, + bool overwrite) +{ + // iterate through the resources + type_code type; + int32 id; + const char *name; + size_t size; + for (int resIndex = 0; + resources.GetResourceInfo(resIndex, &type, &id, &name, &size); + resIndex++) { + // if we shall not overwrite attributes, we skip the attribute, if it + // already exists + attr_info attrInfo; + if (!overwrite && out.GetAttrInfo(name, &attrInfo) == B_OK) + continue; + + // get the resource + const void *data = resources.LoadResource(type, id, &size); + if (!data && size > 0) { + // should not happen + fprintf(stderr, "Failed to get resource `%s', type: %" B_PRIx32 + ", id: %" B_PRId32 " from input file `%s'\n", name, type, id, + inFileName); + exit(1); + } + + // construct a name, if the resource doesn't have one + char nameBuffer[32]; + if (!name) { + sprintf(nameBuffer, "unnamed_%d\n", resIndex); + name = nameBuffer; + } + + // write the attribute + ssize_t bytesWritten = out.WriteAttr(name, type, 0LL, data, size); + if (bytesWritten < 0) { + fprintf(stderr, "Failed to write attribute `%s' to output file: " + "%s\n", name, strerror(bytesWritten)); + } + } +} + +// write_resources +static +void +write_resources(BResources &resources, const char *inFileName, BNode &in, + int32 &resID) +{ + // iterate through the attributes + char name[B_ATTR_NAME_LENGTH]; + while (in.GetNextAttrName(name) == B_OK) { + // get attribute info + attr_info attrInfo; + status_t error = in.GetAttrInfo(name, &attrInfo); + if (error != B_OK) { + fprintf(stderr, "Failed to get info for attribute `%s' of input " + "file `%s': %s\n", name, inFileName, strerror(error)); + exit(1); + } + + // read attribute + char *data = new char[attrInfo.size]; + ssize_t bytesRead = in.ReadAttr(name, attrInfo.type, 0LL, data, + attrInfo.size); + if (bytesRead < 0) { + fprintf(stderr, "Failed to read attribute `%s' of input " + "file `%s': %s\n", name, inFileName, strerror(bytesRead)); + delete[] data; + exit(1); + } + + // find unique ID + const char *existingName; + size_t existingSize; + while (resources.GetResourceInfo(attrInfo.type, resID, &existingName, + &existingSize)) { + resID++; + } + + // write resource + error = resources.AddResource(attrInfo.type, resID++, data, + attrInfo.size, name); + if (error != B_OK) { + fprintf(stderr, "Failed to write resource `%s' to output " + "file: %s\n", name, strerror(error)); + } + delete[] data; + } +} + +// resources_to_attributes +static +void +resources_to_attributes(const char *outputFile, const char **inputFiles, + int inputFileCount, bool overwrite) +{ + // create output file, if it doesn't exist + if (!BEntry(outputFile).Exists()) { + BFile createdOut; + status_t error = createdOut.SetTo(outputFile, + B_READ_WRITE | B_CREATE_FILE); + if (error != B_OK) { + fprintf(stderr, "Failed to create output file `%s': %s\n", + outputFile, strerror(error)); + exit(1); + } + } + + // open output file + BNode out; + status_t error = out.SetTo(outputFile); + if (error != B_OK) { + fprintf(stderr, "Failed to open output file `%s': %s\n", outputFile, + strerror(error)); + exit(1); + } + + // iterate through the input files + for (int i = 0; i < inputFileCount; i++) { + // open input file + BFile in; + error = in.SetTo(inputFiles[i], B_READ_ONLY); + if (error != B_OK) { + fprintf(stderr, "Failed to open input file `%s': %s\n", + inputFiles[i], strerror(error)); + exit(1); + } + + // open resources + BResources resources; + error = resources.SetTo(&in, false); + if (error != B_OK) { + fprintf(stderr, "Failed to read resources of input file `%s': %s\n", + inputFiles[i], strerror(error)); + exit(1); + } + + // add the attributes + write_attributes(out, inputFiles[i], resources, overwrite); + } +} + +// resources_to_attributes +static +void +attributes_to_resources(const char *outputFile, const char **inputFiles, + int inputFileCount) +{ + // open output file + BFile out; + status_t error = out.SetTo(outputFile, B_READ_WRITE | B_CREATE_FILE); + if (error != B_OK) { + fprintf(stderr, "Failed to open output file `%s': %s\n", outputFile, + strerror(error)); + exit(1); + } + + // init output resources + BResources resources; + error = resources.SetTo(&out, false); + if (error != B_OK) { + fprintf(stderr, "Failed to init resources of output file `%s': %s\n", + outputFile, strerror(error)); + exit(1); + } + + int32 resID = 0; + + // iterate through the input files + for (int i = 0; i < inputFileCount; i++) { + // open input file + BNode in; + error = in.SetTo(inputFiles[i]); + if (error != B_OK) { + fprintf(stderr, "Failed to open input file `%s': %s\n", + inputFiles[i], strerror(error)); + exit(1); + } + + // add the resources + + write_resources(resources, inputFiles[i], in, resID); + } +} + +// main +int +main(int argc, const char *const *argv) +{ + sArgc = argc; + sArgv = argv; + + // parameters + const char *outputFile = NULL; + bool overwrite = false; + bool reverse = false; + const char **inputFiles = new const char*[argc]; + int inputFileCount = 0; + + // parse arguments + for (int argi = 1; argi < argc; argi++) { + const char *arg = argv[argi]; + if (arg[0] == '-') { + if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) { + print_usage_and_exit(false); + } else if (strcmp(arg, "-o") == 0) { + outputFile = next_arg(argc, argv, argi); + } else if (strcmp(arg, "-O") == 0) { + overwrite = true; + } else if (strcmp(arg, "-r") == 0 + || strcmp(arg, "--reverse") == 0) { + reverse = true; + } else { + print_usage_and_exit(true); + } + } else { + inputFiles[inputFileCount++] = arg; + } + } + + // check parameters + if (!outputFile) + print_usage_and_exit(true); + + if (reverse) { + attributes_to_resources(outputFile, inputFiles, inputFileCount); + } else { + resources_to_attributes(outputFile, inputFiles, inputFileCount, + overwrite); + } + + return 0; +} diff --git a/src/resattrMakefile b/src/resattrMakefile new file mode 100644 index 0000000..9c9320d --- /dev/null +++ b/src/resattrMakefile @@ -0,0 +1,27 @@ +NAME= resattr +TYPE= APP +SRCS= resattr.cpp +RSRCS= +LIBS= /boot/develop/lib/x86/libroot.so /boot/develop/lib/x86/libbe.so +LIBPATHS= +SYSTEM_INCLUDE_PATHS= /boot/develop/headers/be /boot/develop/headers/cpp /boot/develop/headers/posix /boot/home/config/include +LOCAL_INCLUDE_PATHS= +OPTIMIZE=NONE +# specify any preprocessor symbols to be defined. The symbols will not +# have their values set automatically; you must supply the value (if any) +# to use. For example, setting DEFINES to "DEBUG=1" will cause the +# compiler option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" +# would pass "-DDEBUG" on the compiler's command line. +DEFINES= +# specify special warning levels +# if unspecified default warnings will be used +# NONE = supress all warnings +# ALL = enable all warnings +WARNINGS = +# Build with debugging symbols if set to TRUE +SYMBOLS= +COMPILER_FLAGS= +LINKER_FLAGS= + +## include the makefile-engine +include $(BUILDHOME)/etc/makefile-engine