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. 16 // 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[...]". 24 // 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). 37 // 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 46 // 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... 55 // 56 // You can also use the application defined commands (as the verb) with hey: 57 // hey MyBackupApp Backup "Maui" 58 // 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). 65 // 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. 68 // 69 // Also, the archive name is now Y2K compliant =) 70 // 71 // 1.2.3: new option: -s for silent processing (no reply or errors printed) AM 72 // 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) 76 // 77 // 1.2.1: compiled for x86, R4 with minor modifications at BPropertyInfo 78 // 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. 84 // 85 // Detailed printout of B_PROPERTY_INFO in BMessages. Better than BPropertyInfo::PrintToStream(). 86 // Also prints usage info for a property if defined. 87 // 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 90 // 91 // The range specifier sent to the target was 1 greater than it should've been. Fixed. 92 // 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>. 96 // 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 100 // 101 //v1.0.0 First public release 102 103 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> 111 112 int32 HeyInterpreterThreadHook(void* arg); 113 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); 126 127 const char VERSION[] = "v1.2.8"; 128 129 #define DEBUG_HEY 0 // 1: prints the script message to be sent to the target application, 0: prints only the reply 130 131 132 // test, these should be zero for normal operation 133 #define TEST_VALUEINFO 0 134 135 136 // flag for silent mode 137 bool silent; 138 // flag for stdout mode 139 bool output; 140 141 status_t 142 parse(BMessenger& the_application, int argc, char *argv[], int32 argapp) 143 { 144 if (!the_application.IsValid()) { 145 if (!silent) 146 fprintf(stderr, "Cannot find the application (%s)\n", argv[argapp]); 147 return B_ERROR; 148 } 149 150 if (argc < 3) { 151 if (!silent) 152 fprintf(stderr, "Cannot find the verb!\n"); 153 return B_ERROR; 154 } 155 156 157 BMessage the_reply; 158 int32 argx = argapp+1; 159 status_t err = Hey(&the_application, argv, &argx, argc, &the_reply); 160 161 if (err != B_OK) { 162 if (!silent) { 163 fprintf(stderr, "Error when sending message to %s!\n", 164 argv[argapp]); 165 } 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")); 175 } 176 } else { 177 if (!silent) { 178 printf("error 0x%8" B_PRIx32 "\n", 179 the_reply.FindInt32("error")); 180 } 181 } 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"); 230 } 231 } else { 232 printf("Reply "); 233 print_message(&the_reply); 234 printf("\n"); 235 } 236 } 237 } 238 } 239 return B_OK; 240 } 241 242 243 void 244 usage(int exitCode) 245 { 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); 259 } 260 261 262 int 263 main(int argc, char *argv[]) 264 { 265 BApplication app("application/x-amezei-hey"); 266 267 if (argc < 2) 268 usage(1); 269 270 int32 argapp = 1; 271 silent = false; 272 output = false; 273 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); 285 } 286 287 // find the application 288 BMessenger the_application; 289 BList team_list; 290 team_id teamid; 291 app_info appinfo; 292 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; 301 } 302 303 be_roster->GetAppList(&team_list); 304 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; 317 } 318 } 319 } 320 321 return 1; 322 } 323 324 325 int32 326 HeyInterpreterThreadHook(void* arg) 327 { 328 if (!arg) 329 return 1; 330 331 BMessage environment(*(BMessage*) arg); 332 const char* prompt = "Hey"; 333 if (environment.HasString("prompt")) 334 environment.FindString("prompt", &prompt); 335 printf("%s> ", prompt); 336 337 BMessenger target; 338 if (environment.HasMessenger("Target")) 339 environment.FindMessenger("Target", &target); 340 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"); 351 } 352 printf("%s> ", prompt); 353 } 354 355 return 0; 356 } 357 358 status_t 359 Hey(BMessenger* target, const char* arg, BMessage* reply) 360 { 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; 368 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++; 381 } 382 } else { // copy char into current token 383 currentToken[tokenNdex] = arg[argNdex]; 384 tokenNdex++; 385 argNdex++; 386 } 387 } 388 389 if (tokenNdex!=0) { // close off currentToken token 390 currentToken[tokenNdex] = 0; 391 argv.AddItem(currentToken); 392 } 393 argv.AddItem(NULL); 394 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; 400 } 401 402 403 bool 404 isSpace(char c) 405 { 406 switch (c) { 407 case ' ': 408 case '\t': 409 return true; 410 411 default: 412 return false; 413 } 414 } 415 416 417 status_t 418 Hey(BMessenger* target, char* argv[], int32* argx, int32 argc, BMessage* reply) 419 { 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) 429 ; 430 431 if (result != B_ERROR) { 432 if (!silent) 433 fprintf(stderr, "Bad specifier syntax!\n"); 434 return result; 435 } 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; 446 } 447 } 448 if (!argv[*argx]) { 449 if (!silent) 450 fprintf(stderr, "Syntax error - forgot \"do\"?\n"); 451 return B_ERROR; 452 } 453 } 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; 510 511 // const char *str; 512 // while (rply.FindString("suites", j++, &str) == B_OK) 513 // printf ("Suite %ld: %s\n", j, str); 514 // 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..."} 533 }; 534 vinfo_count = 3; 535 #endif 536 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; 549 } 550 vinfo_index++; 551 } 552 } 553 } 554 } 555 } 556 557 if (!found) { 558 if (!silent) 559 fprintf(stderr, "Bad verb (\"%s\")\n", argv[*argx]); 560 return -1; 561 } 562 } 563 direct_what = true; 564 } 565 566 status_t result = B_OK; 567 (*argx)++; 568 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) 578 ; 579 580 if (result != B_ERROR) { 581 if (!silent) 582 fprintf(stderr, "Bad specifier syntax!\n"); 583 return result; 584 } 585 } 586 } 587 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; 600 } 601 } 602 603 add_with(&the_message, argv, argx, argc); 604 605 #if DEBUG_HEY>0 606 fprintf(stderr, "Send "); 607 print_message(&the_message); 608 fprintf(stderr, "\n"); 609 #endif 610 611 if (target && target->IsValid()) { 612 if (reply) 613 result = target->SendMessage(&the_message, reply); 614 else 615 result = target->SendMessage(&the_message); 616 } 617 return result; 618 } 619 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) 624 { 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"); 641 } 642 return result; 643 } 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); 651 } 652 } 653 return result; 654 } 655 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) 661 { 662 char *property = argv[*argx]; 663 664 if (property == NULL) 665 return B_ERROR; // no more specifiers 666 667 (*argx)++; 668 669 if (strcasecmp(property, "do") == 0) { 670 // Part of the "hey App let Specifier do Verb". 671 return B_ERROR; // no more specifiers 672 } 673 674 if (strcasecmp(property, "to") == 0) { 675 return B_ERROR; 676 // no more specifiers 677 } 678 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 684 } 685 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)++; 692 } 693 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)++; 700 } 701 702 // decide the specifier 703 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 716 } 717 718 (*argx)++; 719 720 if (strcasecmp(specifier, "of") == 0) { 721 // direct specifier 722 to_message->AddSpecifier(property); 723 return B_OK; 724 } 725 726 if (strcasecmp(specifier, "to") == 0) { 727 // direct specifier 728 to_message->AddSpecifier(property); 729 return B_ERROR; 730 // no more specifiers 731 } 732 733 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; 758 } 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; 771 } 772 } 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; 784 } 785 } 786 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; 804 } 805 to_message->AddSpecifier(property, specifier); 806 } 807 } 808 809 return B_OK; 810 } 811 812 813 status_t 814 add_data(BMessage *to_message, char *argv[], int32 *argx) 815 { 816 char *valuestring = argv[*argx]; 817 818 if (valuestring == NULL) 819 return B_ERROR; 820 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; 832 } 833 } 834 } 835 } 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; 844 } 845 } 846 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; 854 } 855 856 // Add support for "<name>=<type>()" here: 857 // The type is then added under the name "name". 858 859 #define MAX_NAME_LENGTH 128 860 char curname[MAX_NAME_LENGTH]; 861 strcpy (curname, "data"); // This is the default. 862 863 char *s = valuestring; 864 while (*++s && *s != '=') 865 // Look for a '=' character... 866 ; 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. 871 } 872 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); 916 } 917 } 918 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); 933 } 934 } 935 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; 939 940 // remove the last ] or ) 941 if (valuestring[strlen(valuestring) - 1] == ')' 942 || valuestring[strlen(valuestring) - 1] == ']') 943 valuestring[strlen(valuestring) - 1] = 0; 944 945 if (get_ref_for_path(valuestring + 5, &file_ref) != B_OK) 946 return B_FILE_NOT_FOUND; 947 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; 953 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); 966 } 967 968 return B_OK; 969 } 970 971 972 void 973 print_message(BMessage *message) 974 { 975 BList textlist; 976 add_message_contents(&textlist, message, 0); 977 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)); 984 } 985 } 986 987 988 void 989 add_message_contents(BList *textlist, BMessage *msg, int32 level) 990 { 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; 1003 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; 1009 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; 1022 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); 1030 } 1031 } 1032 } 1033 } 1034 1035 1036 char * 1037 get_datatype_string(int32 type) 1038 { 1039 char *str = new char[128]; 1040 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; 1134 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; 1143 1144 case B_ERROR: strcpy(str, "B_ERROR"); break; 1145 1146 default: // unknown 1147 id_to_string(type, str); 1148 break; 1149 } 1150 return str; 1151 } 1152 1153 1154 char * 1155 format_data(int32 type, char *ptr, long size) 1156 { 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; 1174 1175 if (size <= 0L) { 1176 str = new char[1]; 1177 *str = 0; 1178 return str; 1179 } 1180 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; 1192 1193 case B_POINTER_TYPE: 1194 str = new char[64]; 1195 sprintf(str, "%p", *(void**)ptr); 1196 break; 1197 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; 1208 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; 1215 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; 1222 1223 case B_INT16_TYPE: 1224 str = new char[64]; 1225 i16 = *(int16*)ptr; 1226 sprintf(str, "%d (0x%04X)", i16, i16); 1227 break; 1228 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; 1235 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; 1241 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; 1247 1248 case B_UINT16_TYPE: 1249 str = new char[64]; 1250 ui16 = *(uint16*)ptr; 1251 sprintf(str, "%u (0x%04X)", ui16, ui16); 1252 break; 1253 1254 case B_UINT8_TYPE: 1255 str = new char[64]; 1256 ui8 = *(uint8*)ptr; 1257 sprintf(str, "%u (0x%02X)", ui8, ui8); 1258 break; 1259 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; 1267 1268 case B_FLOAT_TYPE: 1269 str = new char[40]; 1270 fptr = (float*)ptr; 1271 sprintf(str, "%.3f", *fptr); 1272 break; 1273 1274 case B_DOUBLE_TYPE: 1275 str = new char[40]; 1276 dptr = (double*)ptr; 1277 sprintf(str, "%.3f", *dptr); 1278 break; 1279 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; 1286 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; 1292 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; 1299 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); 1306 } 1307 *(str+strlen(str)-2) = 0; 1308 break; 1309 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; 1319 1320 case B_PROPERTY_INFO_TYPE: 1321 { 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 1326 1327 const property_info *pinfo = propinfo.Properties(); 1328 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); 1339 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; 1347 } 1348 1349 // pad the rest with spaces 1350 if (strlen(start) < 36) { 1351 strcat(str, " " 1352 + strlen(start)); 1353 } else 1354 strcat(str, " " ); 1355 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; 1385 } 1386 } 1387 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); 1404 } 1405 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); 1420 } 1421 } 1422 strcat(str, "\n"); 1423 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"); 1429 } 1430 } 1431 1432 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..."} 1444 }; 1445 vinfo_count = 3; 1446 #endif 1447 1448 if (vinfo && vinfo_count > 0) { 1449 sprintf(str + strlen(str), 1450 "\n name value " 1451 " kind\n---------------------------------------------" 1452 "-----------------------------------\n"); 1453 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, " "); 1460 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, ")"); 1465 1466 // pad the rest with spaces 1467 if (strlen(start) < 36 + 19) { 1468 strcat(str, " " 1469 " " + strlen(start)); 1470 } else 1471 strcat(str, " "); 1472 1473 switch (vinfo[vinfo_index].kind) { 1474 case B_COMMAND_KIND: 1475 strcat(str, "COMMAND "); 1476 break; 1477 1478 case B_TYPE_CODE_KIND: 1479 strcat(str, "TYPE CODE "); 1480 break; 1481 1482 default: 1483 strcat(str, "unknown "); 1484 break; 1485 } 1486 1487 strcat(str, "\n"); 1488 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"); 1494 } 1495 } 1496 } 1497 } else { 1498 str = new char[64]; 1499 strcpy(str, "error when unflattening"); 1500 } 1501 break; 1502 } 1503 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); 1510 } 1511 *(str + strlen(str) - 2) = 0; 1512 break; 1513 } 1514 1515 return str; 1516 } 1517 1518 1519 char * 1520 id_to_string(long ID, char *here) 1521 { 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; 1527 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); 1538 } 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); 1544 } 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); 1550 } 1551 1552 if (!itsvalid) 1553 sprintf(here, "%ldL", ID); 1554 1555 return here; 1556 } 1557 1558 1559 bool 1560 is_valid_char(uint8 c) 1561 { 1562 return c >= 32 && c < 128; 1563 } 1564 1565