xref: /haiku/src/bin/addattr/main.cpp (revision cda5b8808fd0262f0fac472f6cfa809f846a83cf)
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