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