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