* Copyright 2010, JΓ©rΓ΄me Duval.
* Copyright 2004-2015, Axel DΓΆrfler, axeld@pinc-software.de.
* Copyright 2002, Sebastian Nozzi.
*
* Distributed under the terms of the MIT license.
*/
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <File.h>
#include <Mime.h>
#include <TypeConstants.h>
#include "addAttr.h"
#define ERR(msg, args...) fprintf(stderr, "%s: " msg, kProgramName, args)
#define ERR_0(msg) fprintf(stderr, "%s: " msg, kProgramName)
static struct option const kLongOptions[] = {
{"help", no_argument, 0, 'h'},
{NULL}
};
extern const char *__progname;
static const char *kProgramName = __progname;
const struct {
type_code type;
const char *name;
} kSupportedTypes[] = {
{B_STRING_TYPE, "string"},
{B_MIME_STRING_TYPE, "mime"},
{B_INT32_TYPE, "int32"},
{B_INT32_TYPE, "int"},
{B_UINT32_TYPE, "uint32"},
{B_UINT32_TYPE, "uint"},
{B_INT64_TYPE, "int64"},
{B_INT64_TYPE, "llong"},
{B_UINT64_TYPE, "uint64"},
{B_UINT64_TYPE, "ullong"},
{B_FLOAT_TYPE, "float"},
{B_DOUBLE_TYPE, "double"},
{B_BOOL_TYPE, "bool"},
{B_TIME_TYPE, "time"},
{B_VECTOR_ICON_TYPE, "icon"},
{B_RAW_TYPE, "raw"},
};
const uint32 kNumSupportedTypes = sizeof(kSupportedTypes)
/ sizeof(kSupportedTypes[0]);
in the command line, this function tries to figure out the
corresponding Be API value.
On success, "result" will contain that value
On failure, B_BAD_VALUE is returned and "result" is not modified
*/
static status_t
typeForString(const char* string, type_code* _result)
{
for (uint32 i = 0; i < kNumSupportedTypes; i++) {
if (!strcmp(string, kSupportedTypes[i].name)) {
*_result = kSupportedTypes[i].type;
return B_OK;
}
}
if (sscanf(string, "%" B_SCNi32, _result) == 1)
return B_OK;
uchar type[4];
if (sscanf(string, "'%c%c%c%c'", &type[0], &type[1], &type[2], &type[3]) == 4) {
*_result = (type[0] << 24) | (type[1] << 16) | (type[2] << 8) | type[3];
return B_OK;
}
return B_BAD_VALUE;
}
void
usage(int returnValue)
{
fprintf(stderr, "usage: %s [-t type|-c code] [ -P ] attr value file1 [file2...]\n"
" or: %s [-f value-from-file] [-t type|-c code] [ -P ] attr file1 [file2...]\n\n"
"\t-P : Don't resolve links\n"
"\tThe '-t' and '-c' options are alternatives; use one or the other.\n"
"\ttype is one of:\n"
"\t\tstring, mime, int, int32, uint32, llong, int64, uint64,\n"
"\t\tfloat, double, bool, icon, time, raw\n"
"\t\tor a numeric value (ie. 0x1234, 42, ...),\n"
"\t\tor an escape-quoted type code, eg. \\'MICN\\'\n"
"\tThe default is \"string\"\n"
"\tcode is a four-char type ID (eg. MICN)\n", kProgramName, kProgramName);
exit(returnValue);
}
void
invalidAttrType(const char* attrTypeName)
{
fprintf(stderr, "%s: attribute type \"%s\" is not valid\n", kProgramName,
attrTypeName);
fprintf(stderr, "\tTry one of: string, mime, int, llong, float, double,\n"
"\t\tbool, icon, time, raw, or a numeric value (ie. 0x1234, 42, ...),\n"
"\t\tor a quoted type code, eg.: \\'MICN\\'\n"
"\t\tOr enter the actual type code with the '-c' option\n");
exit(1);
}
void
invalidTypeCode(const char* attrTypeName)
{
fprintf(stderr, "%s: attribute type code \"%s\" is not valid\n", kProgramName,
attrTypeName);
fprintf(stderr, "\tIt must be exactly four characters\n");
exit(1);
}
void
invalidBoolValue(const char* value)
{
fprintf(stderr, "%s: attribute value \"%s\" is not valid\n", kProgramName,
value);
fprintf(stderr, "\tBool accepts: 0, f, false, disabled, off,\n"
"\t\t1, t, true, enabled, on\n");
exit(1);
}
int
main(int argc, char* argv[])
{
type_code attrType = B_STRING_TYPE;
char* attrValue = NULL;
size_t valueFileLength = 0;
bool resolveLinks = true;
int c;
while ((c = getopt_long(argc, argv, "hf:t:c:P", kLongOptions, NULL)) != -1) {
switch (c) {
case 0:
break;
case 'f':
{
BFile file;
off_t size;
status_t status = file.SetTo(optarg, B_READ_ONLY);
if (status < B_OK) {
ERR("can't read attribute value from file %s: %s\n",
optarg, strerror(status));
return 1;
}
status = file.GetSize(&size);
if (status == B_OK) {
if (size == 0) {
ERR_0("attribute value is empty: 0 bytes\n");
return 1;
}
if (size > 4 * 1024 * 1024) {
ERR("attribute value is too large: %" B_PRIdOFF
" bytes\n", size);
return 1;
}
attrValue = (char*)malloc(size);
if (attrValue != NULL)
status = file.Read(attrValue, size);
else
status = B_NO_MEMORY;
}
if (status < B_OK) {
ERR("can't read attribute value: %s\n", strerror(status));
return 1;
}
valueFileLength = (size_t)size;
break;
}
case 't':
if (typeForString(optarg, &attrType) != B_OK)
invalidAttrType(optarg);
break;
case 'c':
if (strlen(optarg) == 4) {
char code[] = "' '";
strncpy(code + 1, optarg, 4);
if (typeForString(code, &attrType) == B_OK)
break;
}
invalidTypeCode(optarg);
case 'P':
resolveLinks = false;
break;
case 'h':
usage(0);
break;
default:
usage(1);
break;
}
}
if (argc - optind < 1)
usage(1);
const char* attrName = argv[optind++];
if (argc - optind < 1)
usage(1);
if (!valueFileLength)
attrValue = argv[optind++];
if (argc - optind < 1)
usage(1);
int result = 0;
for (; optind < argc; optind++) {
status_t status = addAttr(argv[optind], attrType, attrName, attrValue,
valueFileLength, resolveLinks);
if (status == B_BAD_VALUE && attrType == B_BOOL_TYPE)
invalidBoolValue(attrValue);
if (status != B_OK) {
ERR("can't add attribute to file %s: %s\n", argv[optind],
strerror(status));
result = 1;
}
}
if (valueFileLength)
free(attrValue);
return result;
}