tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / bin / hey.cpp
blobd736808a1972bf9d24bd75201071ff40f48838b8
1 // hey
2 // a small scripting utility
3 // written by Attila Mezei (attila.mezei@mail.datanet.hu)
4 // contributions by Sander Stoks, Peter Folk, Chris Herborth, Marco Nelissen, Scott Lindsey and others
5 //
6 // public domain, use it at your own risk
7 //
8 // 1.2.8: (Sander Stoks): Added command-line option -o which will output the "result" value
9 // in the reply message to stdout, so you can use it in shell scripting more easily:
10 // "hey Becasso get AspectRatio of Canvas 0"
11 // outputs
12 // Reply BMessage(B_REPLY):
13 // "result" (B_DOUBLE_TYPE) : 0.600
14 // but "hey -o Becasso get AspectRatio of Canvas 0"
15 // outputs 0.600000 directly.
17 // 1.2.7: by Sander Stoks: Made a fork since I don't think Attila still supports "hey", and
18 // because the latest version on BeBits seems to be 1.2.4.
19 // Changes w.r.t. 1.2.6: When an application returns an error on a message, hey now
20 // keeps iterating over applications with the same signature. This is useful because,
21 // for instance, Terminal starts as a new process for each instance, so it previously
22 // wouldn't work to move a specific Terminal window using hey. You can now say
23 // "hey Terminal set Frame of Window foo to BRect[...]".
25 // 1.2.6: syntax extended by Sander Stoks <sander@stoks.nl to allow:
26 // "hey Application let Specifier do ..."
27 // allowing you to send messages directly to other handlers than the app itself.
28 // In cooperation with the new Application defined commands (note that some
29 // Be classes, e.g. BWindow, publish commands as well) this allows, for example:
30 // "hey NetPositive let Window 0 do MoveBy BPoint[10,10]"
31 // Note that this is partly redundant, since
32 // "hey NetPositive let Window 0 do get Title"
33 // duplicates "hey NetPositive get Title of Window 0"
34 // But with the old system,
35 // "hey NetPositive MoveBy of Window 0 with data=BPoint[10,10]"
36 // couldn't work ("MoveBy" is not defined by the Application itself).
38 // 1.2.5: value_info is supported in BPropertyInfo. This means when you send GETSUITES (B_GET_SUPPORTED_SUITES)
39 // the value info is printed after the property infos, like this:
40 // "messages" (B_PROPERTY_INFO_TYPE) :
41 // property commands specifiers
42 // --------------------------------------------------------------------------------
43 // Suites B_GET_PROPERTY DIRECT
44 // Messenger B_GET_PROPERTY DIRECT
45 // InternalName B_GET_PROPERTY DIRECT
47 // name value kind
48 // --------------------------------------------------------------------------------
49 // Backup 0x6261636B ('back') COMMAND
50 // Usage: This command backs up your hard drive.
51 // Abort 0x61626F72 ('abor') COMMAND
52 // Usage: Stops the current operation...
53 // Type Code 0x74797065 ('type') TYPE CODE
54 // Usage: Type code info...
56 // You can also use the application defined commands (as the verb) with hey:
57 // hey MyBackupApp Backup "Maui"
59 // 1.2.4: the syntax is extended by Peter Folk <pfolk@uni.uiuc.edu> to contain:
60 // do the x of y -3 of z '"1"'
61 // I.e. "do" => B_EXECUTE_PROPERTY, optional "the" makes direct specifiers
62 // more like english, bare reverse-index-specifiers are now handled, and
63 // named specifiers can contain only digits by quoting it (but make sure the
64 // shell passed the quotes through).
66 // Hey(target,const char*,reply) was previously limited to 100 tokens. It
67 // now uses a vector<> so it's only limited by available memory.
69 // Also, the archive name is now Y2K compliant =)
71 // 1.2.3: new option: -s for silent processing (no reply or errors printed) AM
73 // 1.2.2: Fixes by Marco Nelissen (marcone@xs4all.nl)
74 // - fixed parsing of negative numbers
75 // - fixed "with" syntax, which was broken (after a create, "with" would be taken as a specifier)
77 // 1.2.1: compiled for x86, R4 with minor modifications at BPropertyInfo
79 // 1.2.0: the syntax is extended by Sander Stoks (sander@adamation.com) to contain
80 // with name=<value> [and name=<value> [...]]
81 // at the end of the command which will add additional data to the scripting message. E.g:
82 // hey Becasso create Canvas with name=MyCanvas and size=BRect(100,100,300,300)
83 // Also a small interpreter is included.
85 // Detailed printout of B_PROPERTY_INFO in BMessages. Better than BPropertyInfo::PrintToStream().
86 // Also prints usage info for a property if defined.
88 // 1.1.1: minor change from chrish@qnx.com to return -1 if an error is
89 // sent back in the reply message; also added B_COUNT_PROPERTIES support
91 // The range specifier sent to the target was 1 greater than it should've been. Fixed.
93 // 'hey' made the assumption that the first thread in a team will be the
94 // application thread (and therefore have the application's name).
95 // This was not always the case. Fix from Scott Lindsey <wombat@gobe.com>.
97 //v1.1.0: Flattened BPropertyInfo is printed if found in the reply of B_GET_SUPPORTED_SUITES
98 // 1,2,3 and 4 character message constant is supported (e.g. '1', '12', '123', '1234')
99 // Alpha is sent with rgb_color
101 //v1.0.0 First public release
104 #include <stdio.h>
105 #include <stdlib.h>
106 #include <string.h>
107 #include <strings.h>
108 #include <AppKit.h>
109 #include <Path.h>
110 #include <SupportDefs.h>
112 int32 HeyInterpreterThreadHook(void* arg);
114 status_t Hey(BMessenger* target, const char* arg, BMessage* reply);
115 bool isSpace(char c);
116 status_t Hey(BMessenger* target, char* argv[], int32* argx, int32 argc, BMessage* reply);
117 status_t add_specifier(BMessage *to_message, char *argv[], int32 *argx, int32 argc);
118 status_t add_data(BMessage *to_message, char *argv[], int32 *argx);
119 status_t add_with(BMessage *to_message, char *argv[], int32 *argx, int32 argc);
120 void add_message_contents(BList *textlist, BMessage *msg, int32 level);
121 char *get_datatype_string(int32 type);
122 char *format_data(int32 type, char *ptr, long size);
123 void print_message(BMessage *message);
124 char *id_to_string(long ID, char *here);
125 bool is_valid_char(uint8 c);
127 const char VERSION[] = "v1.2.8";
129 #define DEBUG_HEY 0 // 1: prints the script message to be sent to the target application, 0: prints only the reply
132 // test, these should be zero for normal operation
133 #define TEST_VALUEINFO 0
136 // flag for silent mode
137 bool silent;
138 // flag for stdout mode
139 bool output;
141 status_t
142 parse(BMessenger& the_application, int argc, char *argv[], int32 argapp)
144 if (!the_application.IsValid()) {
145 if (!silent)
146 fprintf(stderr, "Cannot find the application (%s)\n", argv[argapp]);
147 return B_ERROR;
150 if (argc < 3) {
151 if (!silent)
152 fprintf(stderr, "Cannot find the verb!\n");
153 return B_ERROR;
157 BMessage the_reply;
158 int32 argx = argapp+1;
159 status_t err = Hey(&the_application, argv, &argx, argc, &the_reply);
161 if (err != B_OK) {
162 if (!silent) {
163 fprintf(stderr, "Error when sending message to %s!\n",
164 argv[argapp]);
166 return B_ERROR;
167 } else {
168 if (the_reply.what == (uint32)B_MESSAGE_NOT_UNDERSTOOD
169 || the_reply.what == (uint32)B_ERROR) { // I do it myself
170 if (the_reply.HasString("message")) {
171 if (!silent) {
172 printf("%s (error 0x%8" B_PRIx32 ")\n",
173 the_reply.FindString("message"),
174 the_reply.FindInt32("error"));
176 } else {
177 if (!silent) {
178 printf("error 0x%8" B_PRIx32 "\n",
179 the_reply.FindInt32("error"));
182 return 1;
183 } else {
184 if (!silent) {
185 if (output) {
186 type_code tc;
187 if (the_reply.GetInfo("result", &tc) == B_OK) {
188 if (tc == B_INT8_TYPE) {
189 int8 v;
190 the_reply.FindInt8("result", &v);
191 printf("%d\n", v);
192 } else if (tc == B_INT16_TYPE) {
193 int16 v;
194 the_reply.FindInt16("result", &v);
195 printf("%d\n", v);
196 } else if (tc == B_INT32_TYPE) {
197 int32 v;
198 the_reply.FindInt32("result", &v);
199 printf("%" B_PRId32 "\n", v);
200 } else if (tc == B_UINT8_TYPE) {
201 uint8 v;
202 the_reply.FindInt8("result", (int8*)&v);
203 printf("%u\n", v);
204 } else if (tc == B_UINT16_TYPE) {
205 uint16 v;
206 the_reply.FindInt16("result", (int16*)&v);
207 printf("%u\n", v);
208 } else if (tc == B_UINT32_TYPE) {
209 uint32 v;
210 the_reply.FindInt32("result", (int32*)&v);
211 printf("%" B_PRIu32 "\n", v);
212 } else if (tc == B_STRING_TYPE) {
213 const char* v;
214 the_reply.FindString("result", &v);
215 printf("%s\n", v);
216 } else if (tc == B_FLOAT_TYPE) {
217 float v;
218 the_reply.FindFloat("result", &v);
219 printf("%f\n", v);
220 } else if (tc == B_DOUBLE_TYPE) {
221 double v;
222 the_reply.FindDouble("result", &v);
223 printf("%f\n", v);
224 } else if (tc == B_BOOL_TYPE) {
225 bool v;
226 the_reply.FindBool("result", &v);
227 printf("%s\n", v ? "true" : "false");
228 } else
229 printf("Unsupported type\n");
231 } else {
232 printf("Reply ");
233 print_message(&the_reply);
234 printf("\n");
239 return B_OK;
243 void
244 usage(int exitCode)
246 fprintf(exitCode == EXIT_SUCCESS ? stdout : stderr,
247 "hey %s, written by Attila Mezei (attila.mezei@mail.datanet.hu)\n"
248 "usage: hey [-s][-o] <app|signature|teamid> [let <specifier> do] <verb> <specifier_1> <of\n"
249 " <specifier_n>>* [to <value>] [with name=<value> [and name=<value>]*]\n"
250 "where <verb> : DO|GET|SET|COUNT|CREATE|DELETE|GETSUITES|QUIT|SAVE|LOAD|'what'\n"
251 " <specifier> : [the] <property_name> [ <index> | name | \"name\" | '\"name\"' ]\n"
252 " <index> : int | -int | '['int']' | '['-int']' | '['startint to end']'\n"
253 " <value> : \"string\" | <integer> | <float> | bool(value) | int8(value)\n"
254 " | int16(value) | int32(value) | float(value) | double(value)\n"
255 " | BPoint(x,y) | BRect(l,t,r,b) | rgb_color(r,g,b,a) | file(path)\n"
256 "options: -s: silent\n"
257 " -o: output result to stdout for easy parsing\n\n", VERSION);
258 exit(exitCode);
263 main(int argc, char *argv[])
265 BApplication app("application/x-amezei-hey");
267 if (argc < 2)
268 usage(1);
270 int32 argapp = 1;
271 silent = false;
272 output = false;
274 // Updated option mechanism
275 for (int i = 0; i < argc; i++) {
276 if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "-S") == 0) {
277 silent = true;
278 argapp++;
279 } else if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "-O") == 0) {
280 output = true;
281 argapp++;
282 } else if (strcmp(argv[1], "-h") == 0
283 || strcmp(argv[1], "--help") == 0)
284 usage(0);
287 // find the application
288 BMessenger the_application;
289 BList team_list;
290 team_id teamid;
291 app_info appinfo;
293 teamid = atoi(argv[argapp]);
294 if (teamid > 0) {
295 if (be_roster->GetRunningAppInfo(teamid, &appinfo) != B_OK)
296 return 1;
297 the_application=BMessenger(NULL, teamid);
298 if (!parse(the_application, argc, argv, argapp))
299 return 0;
300 return 1;
303 be_roster->GetAppList(&team_list);
305 for (int32 i = 0; i < team_list.CountItems(); i++) {
306 teamid = (team_id)(addr_t)team_list.ItemAt(i);
307 be_roster->GetRunningAppInfo(teamid, &appinfo);
308 if (strcmp(appinfo.signature, argv[argapp]) == 0) {
309 the_application=BMessenger(appinfo.signature);
310 if (!parse(the_application, argc, argv, argapp))
311 return 0;
312 } else {
313 if (strcmp(appinfo.ref.name, argv[argapp]) == 0) {
314 the_application = BMessenger(0, teamid);
315 if (!parse(the_application, argc, argv, argapp))
316 return 0;
321 return 1;
325 int32
326 HeyInterpreterThreadHook(void* arg)
328 if (!arg)
329 return 1;
331 BMessage environment(*(BMessage*) arg);
332 const char* prompt = "Hey";
333 if (environment.HasString("prompt"))
334 environment.FindString("prompt", &prompt);
335 printf("%s> ", prompt);
337 BMessenger target;
338 if (environment.HasMessenger("Target"))
339 environment.FindMessenger("Target", &target);
341 char command[1024];
342 status_t err;
343 BMessage reply;
344 while (gets(command)) {
345 reply.MakeEmpty();
346 err = Hey(&target, command, &reply);
347 if (!err) {
348 print_message(&reply);
349 } else {
350 printf("Error!\n");
352 printf("%s> ", prompt);
355 return 0;
358 status_t
359 Hey(BMessenger* target, const char* arg, BMessage* reply)
361 BList argv;
362 char* tokens = new char[strlen(arg) * 2];
363 // number of tokens is limited only by memory
364 char* currentToken = tokens;
365 int32 tokenNdex = 0;
366 int32 argNdex = 0;
367 bool inquotes = false;
369 while (arg[argNdex] != 0) { // for each character in arg
370 if (arg[argNdex] == '\"')
371 inquotes = !inquotes;
372 if (!inquotes && isSpace(arg[argNdex])) { // if the character is white space
373 if (tokenNdex != 0) { // close off currentToken token
374 currentToken[tokenNdex] = 0;
375 argv.AddItem(currentToken);
376 currentToken += tokenNdex + 1;
377 tokenNdex = 0;
378 argNdex++;
379 } else { // just skip the whitespace
380 argNdex++;
382 } else { // copy char into current token
383 currentToken[tokenNdex] = arg[argNdex];
384 tokenNdex++;
385 argNdex++;
389 if (tokenNdex!=0) { // close off currentToken token
390 currentToken[tokenNdex] = 0;
391 argv.AddItem(currentToken);
393 argv.AddItem(NULL);
395 int32 argx = 0;
396 status_t ret = Hey(target, (char **)argv.Items(), &argx, argv.CountItems() - 1, reply);
397 // This used to be "return Hey(...);"---so tokens wasn't delete'd.
398 delete[] tokens;
399 return ret;
403 bool
404 isSpace(char c)
406 switch (c) {
407 case ' ':
408 case '\t':
409 return true;
411 default:
412 return false;
417 status_t
418 Hey(BMessenger* target, char* argv[], int32* argx, int32 argc, BMessage* reply)
420 bool direct_what = false;
421 BMessage the_message;
422 if (strcasecmp(argv[*argx], "let") == 0) {
423 BMessage get_target (B_GET_PROPERTY);
424 get_target.AddSpecifier ("Messenger");
425 // parse the specifiers
426 (*argx)++;
427 status_t result = B_OK;
428 while ((result = add_specifier(&get_target, argv, argx, argc)) == B_OK)
431 if (result != B_ERROR) {
432 if (!silent)
433 fprintf(stderr, "Bad specifier syntax!\n");
434 return result;
436 BMessage msgr;
437 if (target && target->IsValid()) {
438 result = target->SendMessage(&get_target, &msgr);
439 if (result != B_OK)
440 return result;
441 result = msgr.FindMessenger ("result", target);
442 if (result != B_OK) {
443 if (!silent)
444 fprintf(stderr, "Couldn't retrieve the BMessenger!\n");
445 return result;
448 if (!argv[*argx]) {
449 if (!silent)
450 fprintf(stderr, "Syntax error - forgot \"do\"?\n");
451 return B_ERROR;
454 if (strcasecmp(argv[*argx], "do") == 0)
455 the_message.what = B_EXECUTE_PROPERTY;
456 else if (strcasecmp(argv[*argx], "get") == 0)
457 the_message.what = B_GET_PROPERTY;
458 else if (strcasecmp(argv[*argx], "set") == 0)
459 the_message.what = B_SET_PROPERTY;
460 else if (strcasecmp(argv[*argx], "create") == 0)
461 the_message.what = B_CREATE_PROPERTY;
462 else if (strcasecmp(argv[*argx], "delete") == 0)
463 the_message.what = B_DELETE_PROPERTY;
464 else if (strcasecmp(argv[*argx], "quit") == 0)
465 the_message.what = B_QUIT_REQUESTED;
466 else if (strcasecmp(argv[*argx], "save") == 0)
467 the_message.what = B_SAVE_REQUESTED;
468 else if (strcasecmp(argv[*argx], "load") == 0)
469 the_message.what = B_REFS_RECEIVED;
470 else if (strcasecmp(argv[*argx], "count") == 0)
471 the_message.what = B_COUNT_PROPERTIES;
472 else if (strcasecmp(argv[*argx], "getsuites") == 0)
473 the_message.what = B_GET_SUPPORTED_SUITES;
474 else {
475 switch(strlen(argv[*argx])) {
476 // can be a message constant if 1,2,3 or 4 chars
477 case 1:
478 the_message.what = (int32)argv[*argx][0];
479 break;
480 case 2:
481 the_message.what = (((int32)argv[*argx][0]) << 8)
482 | (((int32)argv[*argx][1]));
483 break;
484 case 3:
485 the_message.what = (((int32)argv[*argx][0]) << 16)
486 | (((int32)argv[*argx][1]) << 8)
487 | (((int32)argv[*argx][2]));
488 break;
489 case 4:
490 the_message.what = (((int32)argv[*argx][0]) << 24)
491 | (((int32)argv[*argx][1]) << 16)
492 | (((int32)argv[*argx][2]) << 8)
493 | (((int32)argv[*argx][3]));
494 break;
495 default:
496 // maybe this is a user defined command, ask for the supported suites
497 bool found = false;
498 if (target && target->IsValid()) {
499 BMessage reply;
500 if (target->SendMessage(B_GET_SUPPORTED_SUITES, &reply)
501 == B_OK) {
502 // if all goes well, reply contains all kinds of
503 // property infos
504 int32 j = 0;
505 void *voidptr;
506 ssize_t sizefound;
507 BPropertyInfo propinfo;
508 const value_info *vinfo;
509 int32 vinfo_index, vinfo_count;
511 // const char *str;
512 // while (rply.FindString("suites", j++, &str) == B_OK)
513 // printf ("Suite %ld: %s\n", j, str);
515 // j = 0;
516 while (reply.FindData("messages", B_PROPERTY_INFO_TYPE,
517 j++, (const void **)&voidptr, &sizefound)
518 == B_OK && !found) {
519 if (propinfo.Unflatten(B_PROPERTY_INFO_TYPE,
520 (const void *)voidptr, sizefound) == B_OK) {
521 vinfo = propinfo.Values();
522 vinfo_index = 0;
523 vinfo_count = propinfo.CountValues();
524 #if TEST_VALUEINFO>0
525 value_info vinfo[10] = {
526 {"Backup", 'back', B_COMMAND_KIND,
527 "This command backs up your hard"
528 " drive."},
529 {"Abort", 'abor', B_COMMAND_KIND,
530 "Stops the current operation..."},
531 {"Type Code", 'type', B_TYPE_CODE_KIND,
532 "Type code info..."}
534 vinfo_count = 3;
535 #endif
537 while (vinfo_index < vinfo_count) {
538 if (strcmp(vinfo[vinfo_index].name,
539 argv[*argx]) == 0) {
540 found = true;
541 the_message.what =
542 vinfo[vinfo_index].value;
543 #if TEST_VALUEINFO>0
544 printf("FOUND COMMAND \"%s\" = %lX\n",
545 vinfo[vinfo_index].name,
546 the_message.what);
547 #endif
548 break;
550 vinfo_index++;
557 if (!found) {
558 if (!silent)
559 fprintf(stderr, "Bad verb (\"%s\")\n", argv[*argx]);
560 return -1;
563 direct_what = true;
566 status_t result = B_OK;
567 (*argx)++;
569 // One exception: Single data item at end of line.
570 if (direct_what && *argx == argc - 1 && argv[*argx] != NULL)
571 add_data(&the_message, argv, argx);
572 else {
573 // parse the specifiers
574 if (the_message.what != B_REFS_RECEIVED) {
575 // LOAD has no specifier
576 while ((result = add_specifier(&the_message, argv, argx, argc))
577 == B_OK)
580 if (result != B_ERROR) {
581 if (!silent)
582 fprintf(stderr, "Bad specifier syntax!\n");
583 return result;
588 // if verb is SET or LOAD, there should be a to <value>
589 if ((the_message.what == B_SET_PROPERTY || the_message.what == B_REFS_RECEIVED) && argv[*argx] != NULL) {
590 if (strcasecmp(argv[*argx], "to") == 0)
591 (*argx)++;
592 result = add_data(&the_message, argv, argx);
593 if (result != B_OK) {
594 if (result == B_FILE_NOT_FOUND) {
595 if (!silent)
596 fprintf(stderr, "File not found!\n");
597 } else if (!silent)
598 fprintf(stderr, "Invalid 'to...' value format!\n");
599 return result;
603 add_with(&the_message, argv, argx, argc);
605 #if DEBUG_HEY>0
606 fprintf(stderr, "Send ");
607 print_message(&the_message);
608 fprintf(stderr, "\n");
609 #endif
611 if (target && target->IsValid()) {
612 if (reply)
613 result = target->SendMessage(&the_message, reply);
614 else
615 result = target->SendMessage(&the_message);
617 return result;
620 // There can be a with <name>=<type>() [and <name>=<type> ...]
621 // I treat "and" just the same as "with", it's just to make the script syntax more English-like.
622 status_t
623 add_with(BMessage *to_message, char *argv[], int32 *argx, int32 argc)
625 status_t result = B_OK;
626 if (*argx < argc - 1 && argv[++(*argx)] != NULL) {
627 // printf ("argv[%ld] = %s\n", *argx, argv[*argx]);
628 if (strcasecmp(argv[*argx], "with") == 0) {
629 // printf ("\"with\" detected!\n");
630 (*argx)++;
631 bool done = false;
632 do {
633 result = add_data(to_message, argv, argx);
634 if (result != B_OK) {
635 if (result == B_FILE_NOT_FOUND) {
636 if (!silent)
637 fprintf(stderr, "File not found!\n");
638 } else {
639 if (!silent)
640 fprintf(stderr, "Invalid 'with...' value format!\n");
642 return result;
644 (*argx)++;
645 // printf ("argc = %d, argv[%d] = %s\n", argc, *argx, argv[*argx]);
646 if (*argx < argc - 1 && strcasecmp(argv[*argx], "and") == 0)
647 (*argx)++;
648 else
649 done = true;
650 } while (!done);
653 return result;
656 // returns B_OK if successful
657 // B_ERROR if no more specifiers
658 // B_BAD_SCRIPT_SYNTAX if syntax error
659 status_t
660 add_specifier(BMessage *to_message, char *argv[], int32 *argx, int32 argc)
662 char *property = argv[*argx];
664 if (property == NULL)
665 return B_ERROR; // no more specifiers
667 (*argx)++;
669 if (strcasecmp(property, "do") == 0) {
670 // Part of the "hey App let Specifier do Verb".
671 return B_ERROR; // no more specifiers
674 if (strcasecmp(property, "to") == 0) {
675 return B_ERROR;
676 // no more specifiers
679 if (strcasecmp(property, "with") == 0) {
680 *argx -= 2;
681 add_with(to_message, argv, argx, argc);
682 return B_ERROR;
683 // no more specifiers
686 if (strcasecmp(property, "of") == 0) {
687 // skip "of", read real property
688 property = argv[*argx];
689 if (property == NULL)
690 return B_BAD_SCRIPT_SYNTAX;
691 (*argx)++;
694 if (strcasecmp(property, "the") == 0) {
695 // skip "the", read real property
696 property = argv[*argx];
697 if (property == NULL)
698 return B_BAD_SCRIPT_SYNTAX;
699 (*argx)++;
702 // decide the specifier
704 char *specifier = NULL;
705 if (to_message->what == B_CREATE_PROPERTY) {
706 // create is always direct. without this, a "with" would be
707 // taken as a specifier
708 (*argx)--;
709 } else
710 specifier = argv[*argx];
711 if (specifier == NULL) {
712 // direct specifier
713 to_message->AddSpecifier(property);
714 return B_ERROR;
715 // no more specifiers
718 (*argx)++;
720 if (strcasecmp(specifier, "of") == 0) {
721 // direct specifier
722 to_message->AddSpecifier(property);
723 return B_OK;
726 if (strcasecmp(specifier, "to") == 0) {
727 // direct specifier
728 to_message->AddSpecifier(property);
729 return B_ERROR;
730 // no more specifiers
734 if (specifier[0] == '[') {
735 // index, reverse index or range
736 char *end;
737 int32 ix1, ix2;
738 if (specifier[1] == '-') {
739 // reverse index
740 ix1 = strtoul(specifier + 2, &end, 10);
741 BMessage revspec(B_REVERSE_INDEX_SPECIFIER);
742 revspec.AddString("property", property);
743 revspec.AddInt32("index", ix1);
744 to_message->AddSpecifier(&revspec);
745 } else {
746 // index or range
747 ix1 = strtoul(specifier + 1, &end, 10);
748 if (end[0] == ']') {
749 // it was an index
750 to_message->AddSpecifier(property, ix1);
751 return B_OK;
752 } else {
753 specifier = argv[*argx];
754 if (specifier == NULL) {
755 // I was wrong, it was just an index
756 to_message->AddSpecifier(property, ix1);
757 return B_OK;
759 (*argx)++;
760 if (strcasecmp(specifier, "to") == 0) {
761 specifier = argv[*argx];
762 if (specifier == NULL)
763 return B_BAD_SCRIPT_SYNTAX;
764 (*argx)++;
765 ix2 = strtoul(specifier, &end, 10);
766 to_message->AddSpecifier(property, ix1, ix2 - ix1 > 0
767 ? ix2 - ix1 : 1);
768 return B_OK;
769 } else
770 return B_BAD_SCRIPT_SYNTAX;
773 } else {
774 // name specifier
775 // if it contains only digits, it will be an index...
776 bool index_spec = true;
777 bool reverse = specifier[0] == '-';
778 // accept bare reverse-index-specs
779 size_t speclen = strlen(specifier);
780 for (int32 i = (reverse ? 1 : 0); i < (int32)speclen; ++i) {
781 if (specifier[i] < '0' || specifier[i] > '9') {
782 index_spec = false;
783 break;
787 if (index_spec) {
788 if (reverse) {
789 // Copied from above
790 BMessage revspec(B_REVERSE_INDEX_SPECIFIER);
791 revspec.AddString("property", property);
792 revspec.AddInt32("index", atol(specifier + 1));
793 to_message->AddSpecifier(&revspec);
794 } else
795 to_message->AddSpecifier(property, atol(specifier));
796 } else {
797 // Allow any name by counting an initial " as a literal-string
798 // indicator
799 if (specifier[0] == '\"') {
800 if (specifier[speclen - 1] == '\"')
801 specifier[speclen - 1] = '\0';
802 ++specifier;
803 --speclen;
805 to_message->AddSpecifier(property, specifier);
809 return B_OK;
813 status_t
814 add_data(BMessage *to_message, char *argv[], int32 *argx)
816 char *valuestring = argv[*argx];
818 if (valuestring == NULL)
819 return B_ERROR;
821 // try to interpret it as an integer or float
822 bool contains_only_digits = true;
823 bool is_floating_point = false;
824 for (int32 i = 0; i < (int32)strlen(valuestring); i++) {
825 if (i != 0 || valuestring[i] != '-') {
826 if (valuestring[i] < '0' || valuestring[i] > '9') {
827 if (valuestring[i] == '.') {
828 is_floating_point = true;
829 } else {
830 contains_only_digits = false;
831 break;
836 //printf("%d %d\n", contains_only_digits,is_floating_point);
837 if (contains_only_digits) {
838 if (is_floating_point) {
839 to_message->AddFloat("data", atof(valuestring));
840 return B_OK;
841 } else {
842 to_message->AddInt32("data", atol(valuestring));
843 return B_OK;
847 // if true or false, it is bool
848 if (strcasecmp(valuestring, "true") == 0) {
849 to_message->AddBool("data", true);
850 return B_OK;
851 } else if (strcasecmp(valuestring, "false") == 0) {
852 to_message->AddBool("data", false);
853 return B_OK;
856 // Add support for "<name>=<type>()" here:
857 // The type is then added under the name "name".
859 #define MAX_NAME_LENGTH 128
860 char curname[MAX_NAME_LENGTH];
861 strcpy (curname, "data"); // This is the default.
863 char *s = valuestring;
864 while (*++s && *s != '=')
865 // Look for a '=' character...
867 if (*s == '=') { // We found a <name>=
868 *s = 0;
869 strcpy (curname, valuestring); // Use the new <name>
870 valuestring = s + 1; // Reposition the valuestring ptr.
873 // must begin with a type( value )
874 if (strncasecmp(valuestring, "int8", strlen("int8")) == 0)
875 to_message->AddInt8(curname, atol(valuestring + strlen("int8(")));
876 else if (strncasecmp(valuestring, "int16", strlen("int16")) == 0)
877 to_message->AddInt16(curname, atol(valuestring + strlen("int16(")));
878 else if (strncasecmp(valuestring, "int32", strlen("int32")) == 0)
879 to_message->AddInt32(curname, atol(valuestring + strlen("int32(")));
880 else if (strncasecmp(valuestring, "int64", strlen("int64")) == 0)
881 to_message->AddInt64(curname, atol(valuestring + strlen("int64(")));
882 else if (strncasecmp(valuestring, "bool", strlen("bool")) == 0) {
883 if (strncasecmp(valuestring + strlen("bool("), "true", 4) == 0)
884 to_message->AddBool(curname, true);
885 else if (strncasecmp(valuestring + strlen("bool("), "false", 5) == 0)
886 to_message->AddBool(curname, false);
887 else
888 to_message->AddBool(curname, atol(valuestring + strlen("bool(")) == 0 ? false : true);
889 } else if (strncasecmp(valuestring, "float", strlen("float")) == 0)
890 to_message->AddFloat(curname, atof(valuestring + strlen("float(")));
891 else if (strncasecmp(valuestring, "double", strlen("double")) == 0)
892 to_message->AddDouble(curname, atof(valuestring + strlen("double(")));
893 else if (strncasecmp(valuestring, "BPoint", strlen("BPoint")) == 0) {
894 float x, y;
895 x = atof(valuestring + strlen("BPoint("));
896 if (strchr(valuestring, ','))
897 y = atof(strchr(valuestring, ',') + 1);
898 else if (strchr(valuestring, ' '))
899 y = atof(strchr(valuestring, ' ') + 1);
900 else // bad syntax
901 y = 0.0f;
902 to_message->AddPoint(curname, BPoint(x,y));
903 } else if (strncasecmp(valuestring, "BRect", strlen("BRect")) == 0) {
904 float l = 0.0f, t = 0.0f, r = 0.0f, b = 0.0f;
905 char *ptr;
906 l = atof(valuestring + strlen("BRect("));
907 ptr = strchr(valuestring, ',');
908 if (ptr) {
909 t = atof(ptr + 1);
910 ptr = strchr(ptr + 1, ',');
911 if (ptr) {
912 r = atof(ptr + 1);
913 ptr = strchr(ptr + 1, ',');
914 if (ptr)
915 b = atof(ptr + 1);
919 to_message->AddRect(curname, BRect(l,t,r,b));
920 } else if (strncasecmp(valuestring, "rgb_color", strlen("rgb_color")) == 0) {
921 rgb_color clr;
922 char *ptr;
923 clr.red = atol(valuestring + strlen("rgb_color("));
924 ptr = strchr(valuestring, ',');
925 if (ptr) {
926 clr.green = atol(ptr + 1);
927 ptr = strchr(ptr + 1, ',');
928 if (ptr) {
929 clr.blue = atol(ptr + 1);
930 ptr = strchr(ptr + 1, ',');
931 if (ptr)
932 clr.alpha = atol(ptr + 1);
936 to_message->AddData(curname, B_RGB_COLOR_TYPE, &clr, sizeof(rgb_color));
937 } else if (strncasecmp(valuestring, "file", strlen("file")) == 0) {
938 entry_ref file_ref;
940 // remove the last ] or )
941 if (valuestring[strlen(valuestring) - 1] == ')'
942 || valuestring[strlen(valuestring) - 1] == ']')
943 valuestring[strlen(valuestring) - 1] = 0;
945 if (get_ref_for_path(valuestring + 5, &file_ref) != B_OK)
946 return B_FILE_NOT_FOUND;
948 // check if the ref is valid
949 BEntry entry;
950 if (entry.SetTo(&file_ref) != B_OK)
951 return B_FILE_NOT_FOUND;
952 //if(!entry.Exists()) return B_FILE_NOT_FOUND;
954 // add both ways, refsreceived needs it as "refs" while scripting needs "data"
955 to_message->AddRef("refs", &file_ref);
956 to_message->AddRef(curname, &file_ref);
957 } else {
958 // it is string
959 // does it begin with a quote?
960 if (valuestring[0] == '\"') {
961 if (valuestring[strlen(valuestring) - 1] == '\"')
962 valuestring[strlen(valuestring) - 1] = 0;
963 to_message->AddString(curname, valuestring + 1);
964 } else
965 to_message->AddString(curname, valuestring);
968 return B_OK;
972 void
973 print_message(BMessage *message)
975 BList textlist;
976 add_message_contents(&textlist, message, 0);
978 char *whatString = get_datatype_string(message->what);
979 printf("BMessage(%s):\n", whatString);
980 delete[] whatString;
981 for (int32 i = 0; i < textlist.CountItems(); i++) {
982 printf(" %s\n", (char*)textlist.ItemAt(i));
983 free(textlist.ItemAt(i));
988 void
989 add_message_contents(BList *textlist, BMessage *msg, int32 level)
991 int32 count;
992 int32 i, j;
993 type_code typefound;
994 ssize_t sizefound;
995 #ifdef HAIKU_TARGET_PLATFORM_DANO
996 const char *namefound;
997 #else
998 char *namefound;
999 #endif
1000 void *voidptr;
1001 BMessage a_message;
1002 char *textline, *datatype, *content;
1004 // go though all message data
1005 count = msg->CountNames(B_ANY_TYPE);
1006 for (i=0; i < count; i++) {
1007 msg->GetInfo(B_ANY_TYPE, i, &namefound, &typefound);
1008 j = 0;
1010 while (msg->FindData(namefound, typefound, j++, (const void **)&voidptr,
1011 &sizefound) == B_OK) {
1012 datatype = get_datatype_string(typefound);
1013 content = format_data(typefound, (char*)voidptr, sizefound);
1014 textline = (char*)malloc(20 + level * 4 + strlen(namefound)
1015 + strlen(datatype) + strlen(content));
1016 memset(textline, 32, 20 + level * 4);
1017 sprintf(textline + level * 4, "\"%s\" (%s) : %s", namefound,
1018 datatype, content);
1019 textlist->AddItem(textline);
1020 delete[] datatype;
1021 delete[] content;
1023 if (typefound == B_MESSAGE_TYPE) {
1024 msg->FindMessage(namefound, j - 1, &a_message);
1025 add_message_contents(textlist, &a_message, level + 1);
1026 } else if (typefound == B_RAW_TYPE && strcmp(namefound,
1027 "_previous_") == 0) {
1028 if (a_message.Unflatten((const char *)voidptr) == B_OK)
1029 add_message_contents(textlist, &a_message, level + 1);
1036 char *
1037 get_datatype_string(int32 type)
1039 char *str = new char[128];
1041 switch (type) {
1042 case B_ANY_TYPE: strcpy(str, "B_ANY_TYPE"); break;
1043 case B_ASCII_TYPE: strcpy(str, "B_ASCII_TYPE"); break;
1044 case B_BOOL_TYPE: strcpy(str, "B_BOOL_TYPE"); break;
1045 case B_CHAR_TYPE: strcpy(str, "B_CHAR_TYPE"); break;
1046 case B_COLOR_8_BIT_TYPE: strcpy(str, "B_COLOR_8_BIT_TYPE"); break;
1047 case B_DOUBLE_TYPE: strcpy(str, "B_DOUBLE_TYPE"); break;
1048 case B_FLOAT_TYPE: strcpy(str, "B_FLOAT_TYPE"); break;
1049 case B_GRAYSCALE_8_BIT_TYPE: strcpy(str, "B_GRAYSCALE_8_BIT_TYPE"); break;
1050 case B_INT64_TYPE: strcpy(str, "B_INT64_TYPE"); break;
1051 case B_INT32_TYPE: strcpy(str, "B_INT32_TYPE"); break;
1052 case B_INT16_TYPE: strcpy(str, "B_INT16_TYPE"); break;
1053 case B_INT8_TYPE: strcpy(str, "B_INT8_TYPE"); break;
1054 case B_MESSAGE_TYPE: strcpy(str, "B_MESSAGE_TYPE"); break;
1055 case B_MESSENGER_TYPE: strcpy(str, "B_MESSENGER_TYPE"); break;
1056 case B_MIME_TYPE: strcpy(str, "B_MIME_TYPE"); break;
1057 case B_MONOCHROME_1_BIT_TYPE: strcpy(str, "B_MONOCHROME_1_BIT_TYPE"); break;
1058 case B_OBJECT_TYPE: strcpy(str, "B_OBJECT_TYPE"); break;
1059 case B_OFF_T_TYPE: strcpy(str, "B_OFF_T_TYPE"); break;
1060 case B_PATTERN_TYPE: strcpy(str, "B_PATTERN_TYPE"); break;
1061 case B_POINTER_TYPE: strcpy(str, "B_POINTER_TYPE"); break;
1062 case B_POINT_TYPE: strcpy(str, "B_POINT_TYPE"); break;
1063 case B_RAW_TYPE: strcpy(str, "B_RAW_TYPE"); break;
1064 case B_RECT_TYPE: strcpy(str, "B_RECT_TYPE"); break;
1065 case B_REF_TYPE: strcpy(str, "B_REF_TYPE"); break;
1066 case B_RGB_32_BIT_TYPE: strcpy(str, "B_RGB_32_BIT_TYPE"); break;
1067 case B_RGB_COLOR_TYPE: strcpy(str, "B_RGB_COLOR_TYPE"); break;
1068 case B_SIZE_T_TYPE: strcpy(str, "B_SIZE_T_TYPE"); break;
1069 case B_SSIZE_T_TYPE: strcpy(str, "B_SSIZE_T_TYPE"); break;
1070 case B_STRING_TYPE: strcpy(str, "B_STRING_TYPE"); break;
1071 case B_TIME_TYPE : strcpy(str, "B_TIME_TYPE"); break;
1072 case B_UINT64_TYPE: strcpy(str, "B_UINT64_TYPE"); break;
1073 case B_UINT32_TYPE: strcpy(str, "B_UINT32_TYPE"); break;
1074 case B_UINT16_TYPE: strcpy(str, "B_UINT16_TYPE"); break;
1075 case B_UINT8_TYPE: strcpy(str, "B_UINT8_TYPE"); break;
1076 case B_PROPERTY_INFO_TYPE: strcpy(str, "B_PROPERTY_INFO_TYPE"); break;
1077 // message constants:
1078 case B_ABOUT_REQUESTED: strcpy(str, "B_ABOUT_REQUESTED"); break;
1079 case B_WINDOW_ACTIVATED: strcpy(str, "B_WINDOW_ACTIVATED"); break;
1080 case B_ARGV_RECEIVED: strcpy(str, "B_ARGV_RECEIVED"); break;
1081 case B_QUIT_REQUESTED: strcpy(str, "B_QUIT_REQUESTED"); break;
1082 case B_CANCEL: strcpy(str, "B_CANCEL"); break;
1083 case B_KEY_DOWN: strcpy(str, "B_KEY_DOWN"); break;
1084 case B_KEY_UP: strcpy(str, "B_KEY_UP"); break;
1085 case B_MINIMIZE: strcpy(str, "B_MINIMIZE"); break;
1086 case B_MOUSE_DOWN: strcpy(str, "B_MOUSE_DOWN"); break;
1087 case B_MOUSE_MOVED: strcpy(str, "B_MOUSE_MOVED"); break;
1088 case B_MOUSE_ENTER_EXIT: strcpy(str, "B_MOUSE_ENTER_EXIT"); break;
1089 case B_MOUSE_UP: strcpy(str, "B_MOUSE_UP"); break;
1090 case B_PULSE: strcpy(str, "B_PULSE"); break;
1091 case B_READY_TO_RUN: strcpy(str, "B_READY_TO_RUN"); break;
1092 case B_REFS_RECEIVED: strcpy(str, "B_REFS_RECEIVED"); break;
1093 case B_SCREEN_CHANGED: strcpy(str, "B_SCREEN_CHANGED"); break;
1094 case B_VALUE_CHANGED: strcpy(str, "B_VALUE_CHANGED"); break;
1095 case B_VIEW_MOVED: strcpy(str, "B_VIEW_MOVED"); break;
1096 case B_VIEW_RESIZED: strcpy(str, "B_VIEW_RESIZED"); break;
1097 case B_WINDOW_MOVED: strcpy(str, "B_WINDOW_MOVED"); break;
1098 case B_WINDOW_RESIZED: strcpy(str, "B_WINDOW_RESIZED"); break;
1099 case B_WORKSPACES_CHANGED: strcpy(str, "B_WORKSPACES_CHANGED"); break;
1100 case B_WORKSPACE_ACTIVATED: strcpy(str, "B_WORKSPACE_ACTIVATED"); break;
1101 case B_ZOOM: strcpy(str, "B_ZOOM"); break;
1102 case _APP_MENU_: strcpy(str, "_APP_MENU_"); break;
1103 case _BROWSER_MENUS_: strcpy(str, "_BROWSER_MENUS_"); break;
1104 case _MENU_EVENT_: strcpy(str, "_MENU_EVENT_"); break;
1105 case _QUIT_: strcpy(str, "_QUIT_"); break;
1106 case _VOLUME_MOUNTED_: strcpy(str, "_VOLUME_MOUNTED_"); break;
1107 case _VOLUME_UNMOUNTED_: strcpy(str, "_VOLUME_UNMOUNTED_"); break;
1108 case _MESSAGE_DROPPED_: strcpy(str, "_MESSAGE_DROPPED_"); break;
1109 case _MENUS_DONE_: strcpy(str, "_MENUS_DONE_"); break;
1110 case _SHOW_DRAG_HANDLES_: strcpy(str, "_SHOW_DRAG_HANDLES_"); break;
1111 case B_SET_PROPERTY: strcpy(str, "B_SET_PROPERTY"); break;
1112 case B_GET_PROPERTY: strcpy(str, "B_GET_PROPERTY"); break;
1113 case B_CREATE_PROPERTY: strcpy(str, "B_CREATE_PROPERTY"); break;
1114 case B_DELETE_PROPERTY: strcpy(str, "B_DELETE_PROPERTY"); break;
1115 case B_COUNT_PROPERTIES: strcpy(str, "B_COUNT_PROPERTIES"); break;
1116 case B_EXECUTE_PROPERTY: strcpy(str, "B_EXECUTE_PROPERTY"); break;
1117 case B_GET_SUPPORTED_SUITES: strcpy(str, "B_GET_SUPPORTED_SUITES"); break;
1118 case B_CUT: strcpy(str, "B_CUT"); break;
1119 case B_COPY: strcpy(str, "B_COPY"); break;
1120 case B_PASTE: strcpy(str, "B_PASTE"); break;
1121 case B_SELECT_ALL: strcpy(str, "B_SELECT_ALL"); break;
1122 case B_SAVE_REQUESTED: strcpy(str, "B_SAVE_REQUESTED"); break;
1123 case B_MESSAGE_NOT_UNDERSTOOD: strcpy(str, "B_MESSAGE_NOT_UNDERSTOOD"); break;
1124 case B_NO_REPLY: strcpy(str, "B_NO_REPLY"); break;
1125 case B_REPLY: strcpy(str, "B_REPLY"); break;
1126 case B_SIMPLE_DATA: strcpy(str, "B_SIMPLE_DATA"); break;
1127 //case B_MIME_DATA : strcpy(str, "B_MIME_DATA"); break;
1128 case B_ARCHIVED_OBJECT: strcpy(str, "B_ARCHIVED_OBJECT"); break;
1129 case B_UPDATE_STATUS_BAR: strcpy(str, "B_UPDATE_STATUS_BAR"); break;
1130 case B_RESET_STATUS_BAR: strcpy(str, "B_RESET_STATUS_BAR"); break;
1131 case B_NODE_MONITOR: strcpy(str, "B_NODE_MONITOR"); break;
1132 case B_QUERY_UPDATE: strcpy(str, "B_QUERY_UPDATE"); break;
1133 case B_BAD_SCRIPT_SYNTAX: strcpy(str, "B_BAD_SCRIPT_SYNTAX"); break;
1135 // specifiers:
1136 case B_NO_SPECIFIER: strcpy(str, "B_NO_SPECIFIER"); break;
1137 case B_DIRECT_SPECIFIER: strcpy(str, "B_DIRECT_SPECIFIER"); break;
1138 case B_INDEX_SPECIFIER: strcpy(str, "B_INDEX_SPECIFIER"); break;
1139 case B_REVERSE_INDEX_SPECIFIER: strcpy(str, "B_REVERSE_INDEX_SPECIFIER"); break;
1140 case B_RANGE_SPECIFIER: strcpy(str, "B_RANGE_SPECIFIER"); break;
1141 case B_REVERSE_RANGE_SPECIFIER: strcpy(str, "B_REVERSE_RANGE_SPECIFIER"); break;
1142 case B_NAME_SPECIFIER: strcpy(str, "B_NAME_SPECIFIER"); break;
1144 case B_ERROR: strcpy(str, "B_ERROR"); break;
1146 default: // unknown
1147 id_to_string(type, str);
1148 break;
1150 return str;
1154 char *
1155 format_data(int32 type, char *ptr, long size)
1157 char idtext[32];
1158 char *str;
1159 float *fptr;
1160 double *dptr;
1161 entry_ref aref;
1162 BEntry entry;
1163 BPath path;
1164 int64 i64;
1165 int32 i32;
1166 int16 i16;
1167 int8 i8;
1168 uint64 ui64;
1169 uint32 ui32;
1170 uint16 ui16;
1171 uint8 ui8;
1172 BMessage anothermsg;
1173 char *tempstr;
1175 if (size <= 0L) {
1176 str = new char[1];
1177 *str = 0;
1178 return str;
1181 switch (type) {
1182 case B_MIME_TYPE:
1183 case B_ASCII_TYPE:
1184 case B_STRING_TYPE:
1185 if (size > 512)
1186 size = 512;
1187 str = new char[size + 4];
1188 *str='\"';
1189 strncpy(str + 1, ptr, size);
1190 strcat(str, "\"");
1191 break;
1193 case B_POINTER_TYPE:
1194 str = new char[64];
1195 sprintf(str, "%p", *(void**)ptr);
1196 break;
1198 case B_REF_TYPE:
1199 str = new char[1024];
1200 anothermsg.AddData("myref", B_REF_TYPE, ptr, size);
1201 anothermsg.FindRef("myref", &aref);
1202 if (entry.SetTo(&aref)==B_OK){
1203 entry.GetPath(&path);
1204 strcpy(str, path.Path());
1205 } else
1206 strcpy(str, "invalid entry_ref");
1207 break;
1209 case B_SSIZE_T_TYPE:
1210 case B_INT64_TYPE:
1211 str = new char[64];
1212 i64 = *(int64*)ptr;
1213 sprintf(str, "%" B_PRId64 " (0x%" B_PRIx64 ")", i64, i64);
1214 break;
1216 case B_SIZE_T_TYPE:
1217 case B_INT32_TYPE:
1218 str = new char[64];
1219 i32 = *(int32*)ptr;
1220 sprintf(str, "%" B_PRId32 " (0x%08" B_PRId32 ")", i32, i32);
1221 break;
1223 case B_INT16_TYPE:
1224 str = new char[64];
1225 i16 = *(int16*)ptr;
1226 sprintf(str, "%d (0x%04X)", i16, i16);
1227 break;
1229 case B_CHAR_TYPE:
1230 case B_INT8_TYPE:
1231 str = new char[64];
1232 i8 = *(int8*)ptr;
1233 sprintf(str, "%d (0x%02X)", i8, i8);
1234 break;
1236 case B_UINT64_TYPE:
1237 str = new char[64];
1238 ui64 = *(uint64*)ptr;
1239 sprintf(str, "%" B_PRIu64 " (0x%" B_PRIx64 ")", ui64, ui64);
1240 break;
1242 case B_UINT32_TYPE:
1243 str = new char[64];
1244 ui32 = *(uint32*)ptr;
1245 sprintf(str, "%" B_PRIu32 " (0x%08" B_PRIx32 ")", ui32, ui32);
1246 break;
1248 case B_UINT16_TYPE:
1249 str = new char[64];
1250 ui16 = *(uint16*)ptr;
1251 sprintf(str, "%u (0x%04X)", ui16, ui16);
1252 break;
1254 case B_UINT8_TYPE:
1255 str = new char[64];
1256 ui8 = *(uint8*)ptr;
1257 sprintf(str, "%u (0x%02X)", ui8, ui8);
1258 break;
1260 case B_BOOL_TYPE:
1261 str = new char[10];
1262 if (*ptr)
1263 strcpy(str, "TRUE");
1264 else
1265 strcpy(str, "FALSE");
1266 break;
1268 case B_FLOAT_TYPE:
1269 str = new char[40];
1270 fptr = (float*)ptr;
1271 sprintf(str, "%.3f", *fptr);
1272 break;
1274 case B_DOUBLE_TYPE:
1275 str = new char[40];
1276 dptr = (double*)ptr;
1277 sprintf(str, "%.3f", *dptr);
1278 break;
1280 case B_RECT_TYPE:
1281 str = new char[200];
1282 fptr = (float*)ptr;
1283 sprintf(str, "BRect(%.1f, %.1f, %.1f, %.1f)", fptr[0], fptr[1],
1284 fptr[2], fptr[3]);
1285 break;
1287 case B_POINT_TYPE:
1288 str = new char[200];
1289 fptr = (float*)ptr;
1290 sprintf(str, "BPoint(%.1f, %.1f)", fptr[0], fptr[1]);
1291 break;
1293 case B_RGB_COLOR_TYPE:
1294 str = new char[64];
1295 sprintf(str, "Red=%u Green=%u Blue=%u Alpha=%u",
1296 ((uint8*)ptr)[0], ((uint8*)ptr)[1], ((uint8*)ptr)[2],
1297 ((uint8*)ptr)[3]);
1298 break;
1300 case B_COLOR_8_BIT_TYPE:
1301 str = new char[size * 6 + 4];
1302 *str = 0;
1303 for (int32 i = 0; i < min_c(256, size); i++) {
1304 sprintf(idtext, "%u ", ((unsigned char*)ptr)[i]);
1305 strcat(str,idtext);
1307 *(str+strlen(str)-2) = 0;
1308 break;
1310 case B_MESSAGE_TYPE:
1311 str = new char[64];
1312 if (anothermsg.Unflatten((const char *)ptr) == B_OK) {
1313 char *whatString = get_datatype_string(anothermsg.what);
1314 sprintf(str, "what=%s", whatString);
1315 delete[] whatString;
1316 } else
1317 strcpy(str, "error when unflattening");
1318 break;
1320 case B_PROPERTY_INFO_TYPE:
1322 BPropertyInfo propinfo;
1323 if (propinfo.Unflatten(B_PROPERTY_INFO_TYPE, (const void *)ptr,
1324 size) == B_OK) {
1325 str = new char[size * 32]; // an approximation
1327 const property_info *pinfo = propinfo.Properties();
1329 sprintf(str, "\n property commands "
1330 "specifiers types\n-----------------------------------"
1331 "----------------------------------------------------------------\n");
1332 for (int32 pinfo_index = 0; pinfo_index < propinfo.CountProperties(); pinfo_index++) {
1333 strcat(str, " "
1334 + (strlen(pinfo[pinfo_index].name) < 16 ?
1335 strlen(pinfo[pinfo_index].name) : 16));
1336 strcat(str, pinfo[pinfo_index].name);
1337 strcat(str, " ");
1338 char *start = str + strlen(str);
1340 for (int32 i = 0; i < 10 && pinfo[pinfo_index].commands[i];
1341 i++) {
1342 tempstr = get_datatype_string(
1343 pinfo[pinfo_index].commands[i]);
1344 strcat(str, tempstr);
1345 strcat(str, " ");
1346 delete[] tempstr;
1349 // pad the rest with spaces
1350 if (strlen(start) < 36) {
1351 strcat(str, " "
1352 + strlen(start));
1353 } else
1354 strcat(str, " " );
1356 for (int32 i = 0; i < 10 && pinfo[pinfo_index].specifiers[i]; i++) {
1357 switch (pinfo[pinfo_index].specifiers[i]) {
1358 case B_NO_SPECIFIER:
1359 strcat(str, "NONE ");
1360 break;
1361 case B_DIRECT_SPECIFIER:
1362 strcat(str, "DIRECT ");
1363 break;
1364 case B_INDEX_SPECIFIER:
1365 strcat(str, "INDEX ");
1366 break;
1367 case B_REVERSE_INDEX_SPECIFIER:
1368 strcat(str, "REV.INDEX ");
1369 break;
1370 case B_RANGE_SPECIFIER:
1371 strcat(str, "RANGE ");
1372 break;
1373 case B_REVERSE_RANGE_SPECIFIER:
1374 strcat(str, "REV.RANGE ");
1375 break;
1376 case B_NAME_SPECIFIER:
1377 strcat(str, "NAME ");
1378 break;
1379 case B_ID_SPECIFIER:
1380 strcat(str, "ID ");
1381 break;
1382 default:
1383 strcat(str, "<NONE> ");
1384 break;
1388 // pad the rest with spaces
1389 if (strlen(start) < 60) {
1390 strcat(str, " "
1391 " " + strlen(start));
1392 } else
1393 strcat(str, " ");
1394 for (int32 i = 0; i < 10
1395 && pinfo[pinfo_index].types[i] != 0; i++) {
1396 uint32 type = pinfo[pinfo_index].types[i];
1397 char str2[6];
1398 snprintf(str2, sizeof(str2), "%c%c%c%c ",
1399 int(type & 0xFF000000) >> 24,
1400 int(type & 0xFF0000) >> 16,
1401 int(type & 0xFF00) >> 8,
1402 (int)type & 0xFF);
1403 strcat(str, str2);
1406 for (int32 i = 0; i < 3; i++) {
1407 for (int32 j = 0; j < 5
1408 && pinfo[pinfo_index].ctypes[i].pairs[j].type
1409 != 0; j++) {
1410 uint32 type = pinfo[pinfo_index].ctypes[i].pairs[j].type;
1411 char str2[strlen(pinfo[pinfo_index].ctypes[i].pairs[j].name) + 8];
1412 snprintf(str2, sizeof(str2),
1413 "(%s %c%c%c%c)",
1414 pinfo[pinfo_index].ctypes[i].pairs[j].name,
1415 int(type & 0xFF000000) >> 24,
1416 int(type & 0xFF0000) >> 16,
1417 int(type & 0xFF00) >> 8,
1418 (int)type & 0xFF);
1419 strcat(str, str2);
1422 strcat(str, "\n");
1424 // is there usage info?
1425 if (pinfo[pinfo_index].usage) {
1426 strcat(str, " Usage: ");
1427 strcat(str, pinfo[pinfo_index].usage);
1428 strcat(str, "\n");
1433 // handle value infos....
1434 const value_info *vinfo = propinfo.Values();
1435 int32 vinfo_count = propinfo.CountValues();
1436 #if TEST_VALUEINFO>0
1437 value_info vinfo[10] = {
1438 {"Backup", 'back', B_COMMAND_KIND,
1439 "This command backs up your hard drive."},
1440 {"Abort", 'abor', B_COMMAND_KIND,
1441 "Stops the current operation..."},
1442 {"Type Code", 'type', B_TYPE_CODE_KIND,
1443 "Type code info..."}
1445 vinfo_count = 3;
1446 #endif
1448 if (vinfo && vinfo_count > 0) {
1449 sprintf(str + strlen(str),
1450 "\n name value "
1451 " kind\n---------------------------------------------"
1452 "-----------------------------------\n");
1454 for (int32 vinfo_index = 0; vinfo_index < vinfo_count;
1455 vinfo_index++) {
1456 char *start = str + strlen(str);
1457 strcat(str, " " + (strlen(vinfo[vinfo_index].name) < 16 ? strlen(vinfo[vinfo_index].name) : 16));
1458 strcat(str, vinfo[vinfo_index].name);
1459 strcat(str, " ");
1461 sprintf(str + strlen(str), "0x%8" B_PRIx32 " (",
1462 vinfo[vinfo_index].value);
1463 id_to_string(vinfo[vinfo_index].value, str + strlen(str));
1464 strcat(str, ")");
1466 // pad the rest with spaces
1467 if (strlen(start) < 36 + 19) {
1468 strcat(str, " "
1469 " " + strlen(start));
1470 } else
1471 strcat(str, " ");
1473 switch (vinfo[vinfo_index].kind) {
1474 case B_COMMAND_KIND:
1475 strcat(str, "COMMAND ");
1476 break;
1478 case B_TYPE_CODE_KIND:
1479 strcat(str, "TYPE CODE ");
1480 break;
1482 default:
1483 strcat(str, "unknown ");
1484 break;
1487 strcat(str, "\n");
1489 // is there usage info?
1490 if (vinfo[vinfo_index].usage) {
1491 strcat(str, " Usage: ");
1492 strcat(str, vinfo[vinfo_index].usage);
1493 strcat(str, "\n");
1497 } else {
1498 str = new char[64];
1499 strcpy(str, "error when unflattening");
1501 break;
1504 default:
1505 str = new char[min_c(256, size) * 20 + 4];
1506 *str = 0;
1507 for (int32 i = 0; i < min_c(256, size); i++) {
1508 sprintf(idtext, "0x%02X, ", (uint16)ptr[i]);
1509 strcat(str, idtext);
1511 *(str + strlen(str) - 2) = 0;
1512 break;
1515 return str;
1519 char *
1520 id_to_string(long ID, char *here)
1522 uint8 digit0 = (ID>>24)& 255;
1523 uint8 digit1 = (ID>>16)& 255;
1524 uint8 digit2 = (ID>>8) & 255;
1525 uint8 digit3 = (ID) & 255;
1526 bool itsvalid = false;
1528 if (digit0 == 0) {
1529 if (digit1 == 0) {
1530 if (digit2 == 0) {
1531 // 1 digits
1532 itsvalid = is_valid_char(digit3);
1533 sprintf(here, "'%c'", digit3);
1534 } else {
1535 // 2 digits
1536 itsvalid = is_valid_char(digit2) && is_valid_char(digit3);
1537 sprintf(here, "'%c%c'", digit2, digit3);
1539 } else {
1540 // 3 digits
1541 itsvalid = is_valid_char(digit1) && is_valid_char(digit2)
1542 && is_valid_char(digit3);
1543 sprintf(here, "'%c%c%c'", digit1, digit2, digit3);
1545 } else {
1546 // 4 digits
1547 itsvalid = is_valid_char(digit0) && is_valid_char(digit1)
1548 && is_valid_char(digit2) && is_valid_char(digit3);
1549 sprintf(here, "'%c%c%c%c'", digit0, digit1, digit2, digit3);
1552 if (!itsvalid)
1553 sprintf(here, "%ldL", ID);
1555 return here;
1559 bool
1560 is_valid_char(uint8 c)
1562 return c >= 32 && c < 128;