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, "%lu", _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] attr value file1 [file2...]\n" 90 " or: %s [-f value-from-file] [-t type] attr file1 [file2...]\n\n" 91 "\tType is one of:\n" 92 "\t\tstring, mime, int, llong, float, double, bool, raw\n" 93 "\t\tor a numeric value (ie. 0x1234, 42, 'ABCD', ...)\n" 94 "\tThe default is \"string\"\n", gProgramName, gProgramName); 95 96 exit(returnValue); 97 } 98 99 100 void 101 assertArgument(int i, int argc) 102 { 103 if (i >= argc) 104 usage(1); 105 } 106 107 108 void 109 invalidAttrType(const char *attrTypeName) 110 { 111 fprintf(stderr, "%s: attribute type \"%s\" is not valid\n", gProgramName, 112 attrTypeName); 113 fprintf(stderr, "\tTry one of: string, mime, int, llong, float, double,\n"); 114 fprintf(stderr, "\t\tbool, raw, or a numeric value (ie. 0x1234, 42, 'ABCD'" 115 ", ...)\n"); 116 117 exit(1); 118 } 119 120 121 void 122 invalidBoolValue(const char *value) 123 { 124 fprintf(stderr, "%s: attribute value \"%s\" is not valid\n", gProgramName, 125 value); 126 fprintf(stderr, "\tBool accepts: 0, f, false, disabled, off,\n"); 127 fprintf(stderr, "\t\t1, t, true, enabled, on\n"); 128 129 exit(1); 130 } 131 132 133 int 134 main(int argc, char *argv[]) 135 { 136 gProgramName = strrchr(argv[0], '/'); 137 if (gProgramName == NULL) 138 gProgramName = argv[0]; 139 else 140 gProgramName++; 141 142 assertArgument(1, argc); 143 if (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) 144 usage(0); 145 146 type_code attrType = B_STRING_TYPE; 147 148 char *attrValue = NULL; 149 size_t valueFileLength = 0; 150 int32 i = 1; 151 152 if (!strcmp(argv[i], "-f")) { 153 // retrieve attribute value from file 154 BFile file; 155 off_t size; 156 assertArgument(i, argc); 157 status_t status = file.SetTo(argv[i + 1], B_READ_ONLY); 158 if (status < B_OK) { 159 fprintf(stderr, "%s: can't read attribute value from file %s: %s\n", 160 gProgramName, argv[i], strerror(status)); 161 162 return 1; 163 } 164 165 status = file.GetSize(&size); 166 if (status == B_OK) { 167 if (size == 0) { 168 fprintf(stderr, "%s: attribute value is empty: 0 bytes\n", 169 gProgramName); 170 171 return 1; 172 } 173 if (size > 4 * 1024 * 1024) { 174 fprintf(stderr, "%s: attribute value is too large: %Ld bytes\n", 175 gProgramName, size); 176 177 return 1; 178 } 179 attrValue = (char *)malloc(size); 180 if (attrValue != NULL) 181 status = file.Read(attrValue, size); 182 else 183 status = B_NO_MEMORY; 184 } 185 186 if (status < B_OK) { 187 fprintf(stderr, "%s: can't read attribute value: %s\n", 188 gProgramName, strerror(status)); 189 190 return 1; 191 } 192 193 valueFileLength = (size_t)size; 194 i += 2; 195 } 196 197 assertArgument(i, argc); 198 if (!strcmp(argv[i], "-t")) { 199 // Get the attribute type 200 assertArgument(i, argc); 201 if (typeForString(argv[i + 1], &attrType) != B_OK) 202 invalidAttrType(argv[i + 1]); 203 204 i += 2; 205 } 206 207 assertArgument(i, argc); 208 const char *attrName = argv[i++]; 209 210 assertArgument(i, argc); 211 if (!valueFileLength) 212 attrValue = argv[i++]; 213 214 // no files specified? 215 assertArgument(i, argc); 216 217 // Now that we gathered all the information proceed 218 // to add the attribute to the file(s) 219 220 int result = 0; 221 222 for (; i < argc; i++) { 223 status_t status = addAttr(argv[i], attrType, attrName, attrValue, 224 valueFileLength); 225 226 // special case for bool types 227 if (status == B_BAD_VALUE && attrType == B_BOOL_TYPE) 228 invalidBoolValue(attrValue); 229 230 if (status != B_OK) { 231 fprintf(stderr, "%s: can't add attribute to file %s: %s\n", 232 gProgramName, argv[i], strerror(status)); 233 234 // proceed files, but return an error at the end 235 result = 1; 236 } 237 } 238 239 if (valueFileLength) 240 free(attrValue); 241 242 return result; 243 } 244 245