1 /* 2 * Copyright 2004-2006, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2002, Sebastian Nozzi. 4 * 5 * Distributed under the terms of the MIT license. 6 */ 7 8 9 #include "addAttr.h" 10 11 #include <File.h> 12 #include <Mime.h> 13 #include <TypeConstants.h> 14 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 19 20 // supported types (if you add any, make sure that writeAttr() handles them properly) 21 22 const struct { 23 type_code type; 24 const char *name; 25 } kSupportedTypes[] = { 26 {B_STRING_TYPE, "string"}, 27 {B_MIME_STRING_TYPE, "mime"}, 28 29 {B_INT32_TYPE, "int32"}, 30 {B_INT32_TYPE, "int"}, 31 {B_UINT32_TYPE, "uint32"}, 32 {B_UINT32_TYPE, "uint"}, 33 34 {B_INT64_TYPE, "int64"}, 35 {B_INT64_TYPE, "llong"}, 36 {B_UINT64_TYPE, "uint64"}, 37 {B_UINT64_TYPE, "ullong"}, 38 39 {B_FLOAT_TYPE, "float"}, 40 {B_DOUBLE_TYPE, "double"}, 41 42 {B_BOOL_TYPE, "bool"}, 43 44 {B_RAW_TYPE, "raw"}, 45 }; 46 const uint32 kNumSupportedTypes = sizeof(kSupportedTypes) / sizeof(kSupportedTypes[0]); 47 48 char *gProgramName; 49 50 51 /** For the given string that the user specifies as attribute type 52 * in the command line, this function tries to figure out the 53 * corresponding Be API value. 54 * 55 * On success, "result" will contain that value 56 * On failure, B_BAD_VALUE is returned and "result" is not modified 57 */ 58 59 static status_t 60 typeForString(const char *string, type_code *_result) 61 { 62 for (uint32 i = 0; i < kNumSupportedTypes; i++) { 63 if (!strcmp(string, kSupportedTypes[i].name)) { 64 *_result = kSupportedTypes[i].type; 65 return B_OK; 66 } 67 } 68 69 // type didn't show up - in this case, we parse the string 70 // as number and use it directly as type code 71 72 if (sscanf(string, "%lu", _result) == 1) 73 return B_OK; 74 75 uchar type[4]; 76 if (sscanf(string, "'%c%c%c%c'", &type[0], &type[1], &type[2], &type[3]) == 4) { 77 *_result = (type[0] << 24) | (type[1] << 16) | (type[2] << 8) | type[3]; 78 return B_OK; 79 } 80 81 return B_BAD_VALUE; 82 } 83 84 85 void 86 usage(int returnValue) 87 { 88 fprintf(stderr, "usage: %s [-t type] attr value file1 [file2...]\n" 89 " or: %s [-f value-from-file] [-t type] attr file1 [file2...]\n\n" 90 "\tType is one of:\n" 91 "\t\tstring, mime, int, llong, float, double, bool, raw\n" 92 "\t\tor a numeric value (ie. 0x1234, 42, 'ABCD', ...)\n" 93 "\tThe default is \"string\"\n", gProgramName, gProgramName); 94 95 exit(returnValue); 96 } 97 98 99 void 100 assertArgument(int i, int argc) 101 { 102 if (i >= argc) 103 usage(1); 104 } 105 106 107 void 108 invalidAttrType(const char *attrTypeName) 109 { 110 fprintf(stderr, "%s: attribute type \"%s\" is not valid\n", gProgramName, attrTypeName); 111 fprintf(stderr, "\tTry one of: string, mime, int, llong, float, double,\n"); 112 fprintf(stderr, "\t\tbool, raw, or a numeric value (ie. 0x1234, 42, 'ABCD', ...)\n"); 113 114 exit(1); 115 } 116 117 118 void 119 invalidBoolValue(const char *value) 120 { 121 fprintf(stderr, "%s: attribute value \"%s\" is not valid\n", gProgramName, value); 122 fprintf(stderr, "\tBool accepts: 0, f, false, disabled, off,\n"); 123 fprintf(stderr, "\t\t1, t, true, enabled, on\n"); 124 125 exit(1); 126 } 127 128 129 int 130 main(int argc, char *argv[]) 131 { 132 gProgramName = strrchr(argv[0], '/'); 133 if (gProgramName == NULL) 134 gProgramName = argv[0]; 135 else 136 gProgramName++; 137 138 assertArgument(1, argc); 139 if (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) 140 usage(0); 141 142 type_code attrType = B_STRING_TYPE; 143 144 char *attrValue = NULL; 145 size_t valueFileLength = 0; 146 int32 i = 1; 147 148 if (!strcmp(argv[i], "-f")) { 149 // retrieve attribute value from file 150 BFile file; 151 off_t size; 152 assertArgument(i, argc); 153 status_t status = file.SetTo(argv[i + 1], B_READ_ONLY); 154 if (status < B_OK) { 155 fprintf(stderr, "%s: can't read attribute value from file %s: %s\n", 156 gProgramName, argv[i], strerror(status)); 157 158 return 1; 159 } 160 161 status = file.GetSize(&size); 162 if (status == B_OK) { 163 if (size > 4 * 1024 * 1024) { 164 fprintf(stderr, "%s: attribute value is too large: %Ld bytes\n", 165 gProgramName, size); 166 167 return 1; 168 } 169 attrValue = (char *)malloc(size); 170 if (attrValue != NULL) 171 status = file.Read(attrValue, size); 172 else 173 status = B_NO_MEMORY; 174 } 175 176 if (status < B_OK) { 177 fprintf(stderr, "%s: can't read attribute value: %s\n", 178 gProgramName, strerror(status)); 179 180 return 1; 181 } 182 183 valueFileLength = (size_t)size; 184 i += 2; 185 } 186 187 assertArgument(i, argc); 188 if (!strcmp(argv[i], "-t")) { 189 // Get the attribute type 190 assertArgument(i, argc); 191 if (typeForString(argv[i + 1], &attrType) != B_OK) 192 invalidAttrType(argv[i + 1]); 193 194 i += 2; 195 } 196 197 assertArgument(i, argc); 198 const char *attrName = argv[i++]; 199 200 assertArgument(i, argc); 201 if (!valueFileLength) 202 attrValue = argv[i++]; 203 204 // no files specified? 205 assertArgument(i, argc); 206 207 // Now that we gathered all the information proceed 208 // to add the attribute to the file(s) 209 210 int result = 0; 211 212 for (; i < argc; i++) { 213 status_t status = addAttr(argv[i], attrType, attrName, attrValue, 214 valueFileLength); 215 216 // special case for bool types 217 if (status == B_BAD_VALUE && attrType == B_BOOL_TYPE) 218 invalidBoolValue(attrValue); 219 220 if (status != B_OK) { 221 fprintf(stderr, "%s: can't add attribute to file %s: %s\n", 222 gProgramName, argv[i], strerror(status)); 223 224 // proceed files, but return an error at the end 225 result = 1; 226 } 227 } 228 229 if (valueFileLength) 230 free(attrValue); 231 232 return result; 233 } 234 235