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 int 243 main(int argc, char *argv[]) 244 { 245 BApplication app("application/x-amezei-hey"); 246 247 if (argc < 2) { 248 fprintf(stderr, "hey %s, written by Attila Mezei (attila.mezei@mail.datanet.hu)\n" \ 249 "usage: hey [-s][-o] <app|signature|teamid> [let <specifier> do] <verb> <specifier_1> <of\n" \ 250 " <specifier_n>>* [to <value>] [with name=<value> [and name=<value>]*]\n" \ 251 "where <verb> : DO|GET|SET|COUNT|CREATE|DELETE|GETSUITES|QUIT|SAVE|LOAD|'what'\n" \ 252 " <specifier> : [the] <property_name> [ <index> | name | \"name\" | '\"name\"' ]\n" \ 253 " <index> : int | -int | '['int']' | '['-int']' | '['startint to end']'\n" \ 254 " <value> : \"string\" | <integer> | <float> | bool(value) | int8(value)\n" \ 255 " | int16(value) | int32(value) | float(value) | double(value)\n" \ 256 " | BPoint(x,y) | BRect(l,t,r,b) | rgb_color(r,g,b,a) | file(path)\n" \ 257 "options: -s: silent\n" \ 258 " -o: output result to stdout for easy parsing\n\n", VERSION); 259 // Updated Usage string to reflect "do", "the", bare -index, and '"name"' changes below 260 // -- pfolk@uni.uiuc.edu 1999-11-03 261 262 return 1; 263 } 264 265 int32 argapp = 1; 266 silent = false; 267 output = false; 268 269 // Updated option mechanism --SS 270 for (int i = 0; i < argc; i++) { 271 if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "-S") == 0) { 272 silent = true; 273 argapp++; 274 } 275 if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "-O") == 0) { 276 output = true; 277 argapp++; 278 } 279 } 280 281 // find the application 282 BMessenger the_application; 283 BList team_list; 284 team_id teamid; 285 app_info appinfo; 286 287 teamid = atoi(argv[argapp]); 288 if (teamid > 0) { 289 if (be_roster->GetRunningAppInfo(teamid, &appinfo) != B_OK) 290 return 1; 291 the_application=BMessenger(NULL, teamid); 292 if (!parse(the_application, argc, argv, argapp)) 293 return 0; 294 return 1; 295 } 296 297 be_roster->GetAppList(&team_list); 298 299 for (int32 i = 0; i < team_list.CountItems(); i++) { 300 teamid = (team_id)(addr_t)team_list.ItemAt(i); 301 be_roster->GetRunningAppInfo(teamid, &appinfo); 302 if (strcmp(appinfo.signature, argv[argapp]) == 0) { 303 the_application=BMessenger(appinfo.signature); 304 if (!parse(the_application, argc, argv, argapp)) 305 return 0; 306 } else { 307 if (strcmp(appinfo.ref.name, argv[argapp]) == 0) { 308 the_application = BMessenger(0, teamid); 309 if (!parse(the_application, argc, argv, argapp)) 310 return 0; 311 } 312 } 313 } 314 315 return 1; 316 } 317 318 319 int32 320 HeyInterpreterThreadHook(void* arg) 321 { 322 if (!arg) 323 return 1; 324 325 BMessage environment(*(BMessage*) arg); 326 const char* prompt = "Hey"; 327 if (environment.HasString("prompt")) 328 environment.FindString("prompt", &prompt); 329 printf("%s> ", prompt); 330 331 BMessenger target; 332 if (environment.HasMessenger("Target")) 333 environment.FindMessenger("Target", &target); 334 335 char command[1024]; 336 status_t err; 337 BMessage reply; 338 while (gets(command)) { 339 reply.MakeEmpty(); 340 err = Hey(&target, command, &reply); 341 if (!err) { 342 print_message(&reply); 343 } else { 344 printf("Error!\n"); 345 } 346 printf("%s> ", prompt); 347 } 348 349 return 0; 350 } 351 352 status_t 353 Hey(BMessenger* target, const char* arg, BMessage* reply) 354 { 355 BList argv; // number of tokens is now limited only by memory -- pfolk@uni.uiuc.edu 1999-11-03 356 char* tokens = new char[strlen(arg)*2]; 357 char* currentToken = tokens; 358 int32 tokenNdex = 0; 359 int32 argNdex = 0; 360 bool inquotes = false; 361 362 while (arg[argNdex] != 0) { // for each character in arg 363 if (arg[argNdex] == '\"') 364 inquotes = !inquotes; 365 if (!inquotes && isSpace(arg[argNdex])) { // if the character is white space 366 if (tokenNdex != 0) { // close off currentToken token 367 currentToken[tokenNdex] = 0; 368 argv.AddItem(currentToken); 369 currentToken += tokenNdex + 1; 370 tokenNdex = 0; 371 argNdex++; 372 } else { // just skip the whitespace 373 argNdex++; 374 } 375 } else { // copy char into current token 376 currentToken[tokenNdex] = arg[argNdex]; 377 tokenNdex++; 378 argNdex++; 379 } 380 } 381 382 if (tokenNdex!=0) { // close off currentToken token 383 currentToken[tokenNdex] = 0; 384 argv.AddItem(currentToken); 385 } 386 argv.AddItem(NULL); 387 388 int32 argx = 0; 389 status_t ret = Hey(target, (char **)argv.Items(), &argx, argv.CountItems() - 1, reply); 390 // This used to be "return Hey(...);"---so tokens wasn't delete'd. -- pfolk@uni.uiuc.edu 1999-11-03 391 delete[] tokens; 392 return ret; 393 } 394 395 396 bool 397 isSpace(char c) 398 { 399 switch (c) { 400 case ' ': 401 case '\t': 402 return true; 403 404 default: 405 return false; 406 } 407 } 408 409 410 status_t 411 Hey(BMessenger* target, char* argv[], int32* argx, int32 argc, BMessage* reply) 412 { 413 bool direct_what = false; 414 BMessage the_message; 415 if (strcasecmp(argv[*argx], "let") == 0) { 416 // added "let" -- sander@adamation.com 31may2000 417 BMessage get_target (B_GET_PROPERTY); 418 get_target.AddSpecifier ("Messenger"); 419 // parse the specifiers 420 (*argx)++; 421 status_t result = B_OK; 422 while ((result = add_specifier(&get_target, argv, argx, argc)) == B_OK) 423 ; 424 425 if (result != B_ERROR) { 426 if (!silent) 427 fprintf(stderr, "Bad specifier syntax!\n"); 428 return result; 429 } 430 BMessage msgr; 431 if (target && target->IsValid()) { 432 result = target->SendMessage(&get_target, &msgr); 433 if (result != B_OK) 434 return result; 435 result = msgr.FindMessenger ("result", target); 436 if (result != B_OK) { 437 if (!silent) 438 fprintf(stderr, "Couldn't retrieve the BMessenger!\n"); 439 return result; 440 } 441 } 442 if (!argv[*argx]) { 443 if (!silent) 444 fprintf(stderr, "Syntax error - forgot \"do\"?\n"); 445 return B_ERROR; 446 } 447 } 448 if (strcasecmp(argv[*argx], "do") == 0) { 449 // added "do" -- pfolk@uni.uiuc.edu 1999-11-03 450 the_message.what = B_EXECUTE_PROPERTY; 451 } else if (strcasecmp(argv[*argx], "get") == 0) 452 the_message.what = B_GET_PROPERTY; 453 else if (strcasecmp(argv[*argx], "set") == 0) 454 the_message.what = B_SET_PROPERTY; 455 else if (strcasecmp(argv[*argx], "create") == 0) 456 the_message.what = B_CREATE_PROPERTY; 457 else if (strcasecmp(argv[*argx], "delete") == 0) 458 the_message.what = B_DELETE_PROPERTY; 459 else if (strcasecmp(argv[*argx], "quit") == 0) 460 the_message.what = B_QUIT_REQUESTED; 461 else if (strcasecmp(argv[*argx], "save") == 0) 462 the_message.what = B_SAVE_REQUESTED; 463 else if (strcasecmp(argv[*argx], "load") == 0) 464 the_message.what = B_REFS_RECEIVED; 465 else if (strcasecmp(argv[*argx], "count") == 0) 466 the_message.what = B_COUNT_PROPERTIES; 467 else if (strcasecmp(argv[*argx], "getsuites") == 0) 468 the_message.what = B_GET_SUPPORTED_SUITES; 469 else { 470 switch(strlen(argv[*argx])) { 471 // can be a message constant if 1,2,3 or 4 chars 472 case 1: 473 the_message.what = (int32)argv[*argx][0]; 474 break; 475 case 2: 476 the_message.what = (((int32)argv[*argx][0]) << 8) 477 | (((int32)argv[*argx][1])); 478 break; 479 case 3: 480 the_message.what = (((int32)argv[*argx][0]) << 16) 481 | (((int32)argv[*argx][1]) << 8) 482 | (((int32)argv[*argx][2])); 483 break; 484 case 4: 485 the_message.what = (((int32)argv[*argx][0]) << 24) 486 | (((int32)argv[*argx][1]) << 16) 487 | (((int32)argv[*argx][2]) << 8) 488 | (((int32)argv[*argx][3])); 489 break; 490 default: 491 // maybe this is a user defined command, ask for the supported suites 492 bool found = false; 493 if (target && target->IsValid()) { 494 BMessage reply; 495 if (target->SendMessage(B_GET_SUPPORTED_SUITES, &reply) 496 == B_OK) { 497 // if all goes well, reply contains all kinds of 498 // property infos 499 int32 j = 0; 500 void *voidptr; 501 ssize_t sizefound; 502 BPropertyInfo propinfo; 503 const value_info *vinfo; 504 int32 vinfo_index, vinfo_count; 505 506 // const char *str; 507 // while (rply.FindString("suites", j++, &str) == B_OK) 508 // printf ("Suite %ld: %s\n", j, str); 509 // 510 // j = 0; 511 while (reply.FindData("messages", B_PROPERTY_INFO_TYPE, 512 j++, (const void **)&voidptr, &sizefound) 513 == B_OK && !found) { 514 if (propinfo.Unflatten(B_PROPERTY_INFO_TYPE, 515 (const void *)voidptr, sizefound) == B_OK) { 516 vinfo = propinfo.Values(); 517 vinfo_index = 0; 518 vinfo_count = propinfo.CountValues(); 519 #if TEST_VALUEINFO>0 520 value_info vinfo[10] = { 521 {"Backup", 'back', B_COMMAND_KIND, 522 "This command backs up your hard" 523 " drive."}, 524 {"Abort", 'abor', B_COMMAND_KIND, 525 "Stops the current operation..."}, 526 {"Type Code", 'type', B_TYPE_CODE_KIND, 527 "Type code info..."} 528 }; 529 vinfo_count = 3; 530 #endif 531 532 while (vinfo_index < vinfo_count) { 533 if (strcmp(vinfo[vinfo_index].name, 534 argv[*argx]) == 0) { 535 found = true; 536 the_message.what = 537 vinfo[vinfo_index].value; 538 #if TEST_VALUEINFO>0 539 printf("FOUND COMMAND \"%s\" = %lX\n", 540 vinfo[vinfo_index].name, 541 the_message.what); 542 #endif 543 break; 544 } 545 vinfo_index++; 546 } 547 } 548 } 549 } 550 } 551 552 if (!found) { 553 if (!silent) 554 fprintf(stderr, "Bad verb (\"%s\")\n", argv[*argx]); 555 return -1; 556 } 557 } 558 direct_what = true; 559 } 560 561 status_t result = B_OK; 562 (*argx)++; 563 564 // One exception: Single data item at end of line. 565 if (direct_what && *argx == argc - 1 && argv[*argx] != NULL) 566 add_data(&the_message, argv, argx); 567 else { 568 // parse the specifiers 569 if (the_message.what != B_REFS_RECEIVED) { 570 // LOAD has no specifier 571 while ((result = add_specifier(&the_message, argv, argx, argc)) 572 == B_OK) 573 ; 574 575 if (result != B_ERROR) { 576 if (!silent) 577 fprintf(stderr, "Bad specifier syntax!\n"); 578 return result; 579 } 580 } 581 } 582 583 // if verb is SET or LOAD, there should be a to <value> 584 if ((the_message.what == B_SET_PROPERTY || the_message.what == B_REFS_RECEIVED) && argv[*argx] != NULL) { 585 if (strcasecmp(argv[*argx], "to") == 0) 586 (*argx)++; 587 result = add_data(&the_message, argv, argx); 588 if (result != B_OK) { 589 if (result == B_FILE_NOT_FOUND) { 590 if (!silent) 591 fprintf(stderr, "File not found!\n"); 592 } else if (!silent) 593 fprintf(stderr, "Invalid 'to...' value format!\n"); 594 return result; 595 } 596 } 597 598 add_with(&the_message, argv, argx, argc); 599 600 #if DEBUG_HEY>0 601 fprintf(stderr, "Send "); 602 print_message(&the_message); 603 fprintf(stderr, "\n"); 604 #endif 605 606 if (target && target->IsValid()) { 607 if (reply) 608 result = target->SendMessage(&the_message, reply); 609 else 610 result = target->SendMessage(&the_message); 611 } 612 return result; 613 } 614 615 // There can be a with <name>=<type>() [and <name>=<type> ...] 616 // I treat "and" just the same as "with", it's just to make the script syntax more English-like. 617 status_t 618 add_with(BMessage *to_message, char *argv[], int32 *argx, int32 argc) 619 { 620 status_t result = B_OK; 621 if (*argx < argc - 1 && argv[++(*argx)] != NULL) { 622 // printf ("argv[%ld] = %s\n", *argx, argv[*argx]); 623 if (strcasecmp(argv[*argx], "with") == 0) { 624 // printf ("\"with\" detected!\n"); 625 (*argx)++; 626 bool done = false; 627 do { 628 result = add_data(to_message, argv, argx); 629 if (result != B_OK) { 630 if (result == B_FILE_NOT_FOUND) { 631 if (!silent) 632 fprintf(stderr, "File not found!\n"); 633 } else { 634 if (!silent) 635 fprintf(stderr, "Invalid 'with...' value format!\n"); 636 } 637 return result; 638 } 639 (*argx)++; 640 // printf ("argc = %d, argv[%d] = %s\n", argc, *argx, argv[*argx]); 641 if (*argx < argc - 1 && strcasecmp(argv[*argx], "and") == 0) 642 (*argx)++; 643 else 644 done = true; 645 } while (!done); 646 } 647 } 648 return result; 649 } 650 651 // returns B_OK if successful 652 // B_ERROR if no more specifiers 653 // B_BAD_SCRIPT_SYNTAX if syntax error 654 status_t 655 add_specifier(BMessage *to_message, char *argv[], int32 *argx, int32 argc) 656 { 657 char *property = argv[*argx]; 658 659 if (property == NULL) 660 return B_ERROR; // no more specifiers 661 662 (*argx)++; 663 664 if (strcasecmp(property, "do") == 0) { 665 // Part of the "hey App let Specifier do Verb". 666 return B_ERROR; // no more specifiers 667 } 668 669 if (strcasecmp(property, "to") == 0) { 670 return B_ERROR; 671 // no more specifiers 672 } 673 674 if (strcasecmp(property, "with") == 0) { 675 *argx -= 2; 676 add_with(to_message, argv, argx, argc); 677 return B_ERROR; 678 // no more specifiers 679 } 680 681 if (strcasecmp(property, "of") == 0) { 682 // skip "of", read real property 683 property = argv[*argx]; 684 if (property == NULL) 685 return B_BAD_SCRIPT_SYNTAX; 686 (*argx)++; 687 } 688 689 if (strcasecmp(property, "the") == 0) { 690 // skip "the", read real property -- pfolk@uni.uiuc.edu 1999-11-03 691 property = argv[*argx]; 692 if (property == NULL) 693 return B_BAD_SCRIPT_SYNTAX; 694 (*argx)++; 695 } 696 697 // decide the specifier 698 699 char *specifier = NULL; 700 if (to_message->what == B_CREATE_PROPERTY) { 701 // create is always direct. without this, a "with" would be 702 // taken as a specifier 703 (*argx)--; 704 } else 705 specifier = argv[*argx]; 706 if (specifier == NULL) { 707 // direct specifier 708 to_message->AddSpecifier(property); 709 return B_ERROR; 710 // no more specifiers 711 } 712 713 (*argx)++; 714 715 if (strcasecmp(specifier, "of") == 0) { 716 // direct specifier 717 to_message->AddSpecifier(property); 718 return B_OK; 719 } 720 721 if (strcasecmp(specifier, "to") == 0) { 722 // direct specifier 723 to_message->AddSpecifier(property); 724 return B_ERROR; 725 // no more specifiers 726 } 727 728 729 if (specifier[0] == '[') { 730 // index, reverse index or range 731 char *end; 732 int32 ix1, ix2; 733 if (specifier[1] == '-') { 734 // reverse index 735 ix1 = strtoul(specifier + 2, &end, 10); 736 BMessage revspec(B_REVERSE_INDEX_SPECIFIER); 737 revspec.AddString("property", property); 738 revspec.AddInt32("index", ix1); 739 to_message->AddSpecifier(&revspec); 740 } else { 741 // index or range 742 ix1 = strtoul(specifier + 1, &end, 10); 743 if (end[0] == ']') { 744 // it was an index 745 to_message->AddSpecifier(property, ix1); 746 return B_OK; 747 } else { 748 specifier = argv[*argx]; 749 if (specifier == NULL) { 750 // I was wrong, it was just an index 751 to_message->AddSpecifier(property, ix1); 752 return B_OK; 753 } 754 (*argx)++; 755 if (strcasecmp(specifier, "to") == 0) { 756 specifier = argv[*argx]; 757 if (specifier == NULL) 758 return B_BAD_SCRIPT_SYNTAX; 759 (*argx)++; 760 ix2 = strtoul(specifier, &end, 10); 761 to_message->AddSpecifier(property, ix1, ix2 - ix1 > 0 762 ? ix2 - ix1 : 1); 763 return B_OK; 764 } else 765 return B_BAD_SCRIPT_SYNTAX; 766 } 767 } 768 } else { 769 // name specifier 770 // if it contains only digits, it will be an index... 771 bool index_spec = true; 772 bool reverse = specifier[0] == '-'; 773 // accept bare reverse-index-specs -- pfolk@uni.uiuc.edu 1999-11-03 774 size_t speclen = strlen(specifier); 775 for (int32 i = (reverse ? 1 : 0); i < (int32)speclen; ++i) { 776 if (specifier[i] < '0' || specifier[i] > '9') { 777 index_spec = false; 778 break; 779 } 780 } 781 782 if (index_spec) { 783 if (reverse) { 784 // Copied from above -- pfolk@uni.uiuc.edu 1999-11-03 785 BMessage revspec(B_REVERSE_INDEX_SPECIFIER); 786 revspec.AddString("property", property); 787 revspec.AddInt32("index", atol(specifier + 1)); 788 to_message->AddSpecifier(&revspec); 789 } else 790 to_message->AddSpecifier(property, atol(specifier)); 791 } else { 792 // Allow any name by counting an initial " as a literal-string indicator 793 // -- pfolk@uni.uiuc.edu 1999-11-03 794 if (specifier[0] == '\"') { 795 if (specifier[speclen - 1] == '\"') 796 specifier[speclen - 1] = '\0'; 797 ++specifier; 798 --speclen; 799 } 800 to_message->AddSpecifier(property, specifier); 801 } 802 } 803 804 return B_OK; 805 } 806 807 808 status_t 809 add_data(BMessage *to_message, char *argv[], int32 *argx) 810 { 811 char *valuestring = argv[*argx]; 812 813 if (valuestring == NULL) 814 return B_ERROR; 815 816 // try to interpret it as an integer or float 817 bool contains_only_digits = true; 818 bool is_floating_point = false; 819 for (int32 i = 0; i < (int32)strlen(valuestring); i++) { 820 if (i != 0 || valuestring[i] != '-') { 821 if (valuestring[i] < '0' || valuestring[i] > '9') { 822 if (valuestring[i] == '.') { 823 is_floating_point = true; 824 } else { 825 contains_only_digits = false; 826 break; 827 } 828 } 829 } 830 } 831 //printf("%d %d\n", contains_only_digits,is_floating_point); 832 if (contains_only_digits) { 833 if (is_floating_point) { 834 to_message->AddFloat("data", atof(valuestring)); 835 return B_OK; 836 } else { 837 to_message->AddInt32("data", atol(valuestring)); 838 return B_OK; 839 } 840 } 841 842 // if true or false, it is bool 843 if (strcasecmp(valuestring, "true") == 0) { 844 to_message->AddBool("data", true); 845 return B_OK; 846 } else if (strcasecmp(valuestring, "false") == 0) { 847 to_message->AddBool("data", false); 848 return B_OK; 849 } 850 851 // Add support for "<name>=<type>()" here: 852 // The type is then added under the name "name". 853 854 #define MAX_NAME_LENGTH 128 855 char curname[MAX_NAME_LENGTH]; 856 strcpy (curname, "data"); // This is the default. 857 858 char *s = valuestring; 859 while (*++s && *s != '=') 860 // Look for a '=' character... 861 ; 862 if (*s == '=') { // We found a <name>= 863 *s = 0; 864 strcpy (curname, valuestring); // Use the new <name> 865 valuestring = s + 1; // Reposition the valuestring ptr. 866 } 867 868 // must begin with a type( value ) 869 if (strncasecmp(valuestring, "int8", strlen("int8")) == 0) 870 to_message->AddInt8(curname, atol(valuestring + strlen("int8("))); 871 else if (strncasecmp(valuestring, "int16", strlen("int16")) == 0) 872 to_message->AddInt16(curname, atol(valuestring + strlen("int16("))); 873 else if (strncasecmp(valuestring, "int32", strlen("int32")) == 0) 874 to_message->AddInt32(curname, atol(valuestring + strlen("int32("))); 875 else if (strncasecmp(valuestring, "int64", strlen("int64")) == 0) 876 to_message->AddInt64(curname, atol(valuestring + strlen("int64("))); 877 else if (strncasecmp(valuestring, "bool", strlen("bool")) == 0) { 878 if (strncasecmp(valuestring + strlen("bool("), "true", 4) == 0) 879 to_message->AddBool(curname, true); 880 else if (strncasecmp(valuestring + strlen("bool("), "false", 5) == 0) 881 to_message->AddBool(curname, false); 882 else 883 to_message->AddBool(curname, atol(valuestring + strlen("bool(")) == 0 ? false : true); 884 } else if (strncasecmp(valuestring, "float", strlen("float")) == 0) 885 to_message->AddFloat(curname, atof(valuestring + strlen("float("))); 886 else if (strncasecmp(valuestring, "double", strlen("double")) == 0) 887 to_message->AddDouble(curname, atof(valuestring + strlen("double("))); 888 else if (strncasecmp(valuestring, "BPoint", strlen("BPoint")) == 0) { 889 float x, y; 890 x = atof(valuestring + strlen("BPoint(")); 891 if (strchr(valuestring, ',')) 892 y = atof(strchr(valuestring, ',') + 1); 893 else if (strchr(valuestring, ' ')) 894 y = atof(strchr(valuestring, ' ') + 1); 895 else // bad syntax 896 y = 0.0f; 897 to_message->AddPoint(curname, BPoint(x,y)); 898 } else if (strncasecmp(valuestring, "BRect", strlen("BRect")) == 0) { 899 float l = 0.0f, t = 0.0f, r = 0.0f, b = 0.0f; 900 char *ptr; 901 l = atof(valuestring + strlen("BRect(")); 902 ptr = strchr(valuestring, ','); 903 if (ptr) { 904 t = atof(ptr + 1); 905 ptr = strchr(ptr + 1, ','); 906 if (ptr) { 907 r = atof(ptr + 1); 908 ptr = strchr(ptr + 1, ','); 909 if (ptr) 910 b = atof(ptr + 1); 911 } 912 } 913 914 to_message->AddRect(curname, BRect(l,t,r,b)); 915 } else if (strncasecmp(valuestring, "rgb_color", strlen("rgb_color")) == 0) { 916 rgb_color clr; 917 char *ptr; 918 clr.red = atol(valuestring + strlen("rgb_color(")); 919 ptr = strchr(valuestring, ','); 920 if (ptr) { 921 clr.green = atol(ptr + 1); 922 ptr = strchr(ptr + 1, ','); 923 if (ptr) { 924 clr.blue = atol(ptr + 1); 925 ptr = strchr(ptr + 1, ','); 926 if (ptr) 927 clr.alpha = atol(ptr + 1); 928 } 929 } 930 931 to_message->AddData(curname, B_RGB_COLOR_TYPE, &clr, sizeof(rgb_color)); 932 } else if (strncasecmp(valuestring, "file", strlen("file")) == 0) { 933 entry_ref file_ref; 934 935 // remove the last ] or ) 936 if (valuestring[strlen(valuestring) - 1] == ')' 937 || valuestring[strlen(valuestring) - 1] == ']') 938 valuestring[strlen(valuestring) - 1] = 0; 939 940 if (get_ref_for_path(valuestring + 5, &file_ref) != B_OK) 941 return B_FILE_NOT_FOUND; 942 943 // check if the ref is valid 944 BEntry entry; 945 if (entry.SetTo(&file_ref) != B_OK) 946 return B_FILE_NOT_FOUND; 947 //if(!entry.Exists()) return B_FILE_NOT_FOUND; 948 949 // add both ways, refsreceived needs it as "refs" while scripting needs "data" 950 to_message->AddRef("refs", &file_ref); 951 to_message->AddRef(curname, &file_ref); 952 } else { 953 // it is string 954 // does it begin with a quote? 955 if (valuestring[0] == '\"') { 956 if (valuestring[strlen(valuestring) - 1] == '\"') 957 valuestring[strlen(valuestring) - 1] = 0; 958 to_message->AddString(curname, valuestring + 1); 959 } else 960 to_message->AddString(curname, valuestring); 961 } 962 963 return B_OK; 964 } 965 966 967 void 968 print_message(BMessage *message) 969 { 970 BList textlist; 971 add_message_contents(&textlist, message, 0); 972 973 char *whatString = get_datatype_string(message->what); 974 printf("BMessage(%s):\n", whatString); 975 delete[] whatString; 976 for (int32 i = 0; i < textlist.CountItems(); i++) { 977 printf(" %s\n", (char*)textlist.ItemAt(i)); 978 free(textlist.ItemAt(i)); 979 } 980 } 981 982 983 void 984 add_message_contents(BList *textlist, BMessage *msg, int32 level) 985 { 986 int32 count; 987 int32 i, j; 988 type_code typefound; 989 ssize_t sizefound; 990 #ifdef HAIKU_TARGET_PLATFORM_DANO 991 const char *namefound; 992 #else 993 char *namefound; 994 #endif 995 void *voidptr; 996 BMessage a_message; 997 char *textline, *datatype, *content; 998 999 // go though all message data 1000 count = msg->CountNames(B_ANY_TYPE); 1001 for (i=0; i < count; i++) { 1002 msg->GetInfo(B_ANY_TYPE, i, &namefound, &typefound); 1003 j = 0; 1004 1005 while (msg->FindData(namefound, typefound, j++, (const void **)&voidptr, 1006 &sizefound) == B_OK) { 1007 datatype = get_datatype_string(typefound); 1008 content = format_data(typefound, (char*)voidptr, sizefound); 1009 textline = (char*)malloc(20 + level * 4 + strlen(namefound) 1010 + strlen(datatype) + strlen(content)); 1011 memset(textline, 32, 20 + level * 4); 1012 sprintf(textline + level * 4, "\"%s\" (%s) : %s", namefound, 1013 datatype, content); 1014 textlist->AddItem(textline); 1015 delete[] datatype; 1016 delete[] content; 1017 1018 if (typefound == B_MESSAGE_TYPE) { 1019 msg->FindMessage(namefound, j - 1, &a_message); 1020 add_message_contents(textlist, &a_message, level + 1); 1021 } else if (typefound == B_RAW_TYPE && strcmp(namefound, 1022 "_previous_") == 0) { 1023 if (a_message.Unflatten((const char *)voidptr) == B_OK) 1024 add_message_contents(textlist, &a_message, level + 1); 1025 } 1026 } 1027 } 1028 } 1029 1030 1031 char * 1032 get_datatype_string(int32 type) 1033 { 1034 char *str = new char[128]; 1035 1036 switch (type) { 1037 case B_ANY_TYPE: strcpy(str, "B_ANY_TYPE"); break; 1038 case B_ASCII_TYPE: strcpy(str, "B_ASCII_TYPE"); break; 1039 case B_BOOL_TYPE: strcpy(str, "B_BOOL_TYPE"); break; 1040 case B_CHAR_TYPE: strcpy(str, "B_CHAR_TYPE"); break; 1041 case B_COLOR_8_BIT_TYPE: strcpy(str, "B_COLOR_8_BIT_TYPE"); break; 1042 case B_DOUBLE_TYPE: strcpy(str, "B_DOUBLE_TYPE"); break; 1043 case B_FLOAT_TYPE: strcpy(str, "B_FLOAT_TYPE"); break; 1044 case B_GRAYSCALE_8_BIT_TYPE: strcpy(str, "B_GRAYSCALE_8_BIT_TYPE"); break; 1045 case B_INT64_TYPE: strcpy(str, "B_INT64_TYPE"); break; 1046 case B_INT32_TYPE: strcpy(str, "B_INT32_TYPE"); break; 1047 case B_INT16_TYPE: strcpy(str, "B_INT16_TYPE"); break; 1048 case B_INT8_TYPE: strcpy(str, "B_INT8_TYPE"); break; 1049 case B_MESSAGE_TYPE: strcpy(str, "B_MESSAGE_TYPE"); break; 1050 case B_MESSENGER_TYPE: strcpy(str, "B_MESSENGER_TYPE"); break; 1051 case B_MIME_TYPE: strcpy(str, "B_MIME_TYPE"); break; 1052 case B_MONOCHROME_1_BIT_TYPE: strcpy(str, "B_MONOCHROME_1_BIT_TYPE"); break; 1053 case B_OBJECT_TYPE: strcpy(str, "B_OBJECT_TYPE"); break; 1054 case B_OFF_T_TYPE: strcpy(str, "B_OFF_T_TYPE"); break; 1055 case B_PATTERN_TYPE: strcpy(str, "B_PATTERN_TYPE"); break; 1056 case B_POINTER_TYPE: strcpy(str, "B_POINTER_TYPE"); break; 1057 case B_POINT_TYPE: strcpy(str, "B_POINT_TYPE"); break; 1058 case B_RAW_TYPE: strcpy(str, "B_RAW_TYPE"); break; 1059 case B_RECT_TYPE: strcpy(str, "B_RECT_TYPE"); break; 1060 case B_REF_TYPE: strcpy(str, "B_REF_TYPE"); break; 1061 case B_RGB_32_BIT_TYPE: strcpy(str, "B_RGB_32_BIT_TYPE"); break; 1062 case B_RGB_COLOR_TYPE: strcpy(str, "B_RGB_COLOR_TYPE"); break; 1063 case B_SIZE_T_TYPE: strcpy(str, "B_SIZE_T_TYPE"); break; 1064 case B_SSIZE_T_TYPE: strcpy(str, "B_SSIZE_T_TYPE"); break; 1065 case B_STRING_TYPE: strcpy(str, "B_STRING_TYPE"); break; 1066 case B_TIME_TYPE : strcpy(str, "B_TIME_TYPE"); break; 1067 case B_UINT64_TYPE: strcpy(str, "B_UINT64_TYPE"); break; 1068 case B_UINT32_TYPE: strcpy(str, "B_UINT32_TYPE"); break; 1069 case B_UINT16_TYPE: strcpy(str, "B_UINT16_TYPE"); break; 1070 case B_UINT8_TYPE: strcpy(str, "B_UINT8_TYPE"); break; 1071 case B_PROPERTY_INFO_TYPE: strcpy(str, "B_PROPERTY_INFO_TYPE"); break; 1072 // message constants: 1073 case B_ABOUT_REQUESTED: strcpy(str, "B_ABOUT_REQUESTED"); break; 1074 case B_WINDOW_ACTIVATED: strcpy(str, "B_WINDOW_ACTIVATED"); break; 1075 case B_ARGV_RECEIVED: strcpy(str, "B_ARGV_RECEIVED"); break; 1076 case B_QUIT_REQUESTED: strcpy(str, "B_QUIT_REQUESTED"); break; 1077 case B_CANCEL: strcpy(str, "B_CANCEL"); break; 1078 case B_KEY_DOWN: strcpy(str, "B_KEY_DOWN"); break; 1079 case B_KEY_UP: strcpy(str, "B_KEY_UP"); break; 1080 case B_MINIMIZE: strcpy(str, "B_MINIMIZE"); break; 1081 case B_MOUSE_DOWN: strcpy(str, "B_MOUSE_DOWN"); break; 1082 case B_MOUSE_MOVED: strcpy(str, "B_MOUSE_MOVED"); break; 1083 case B_MOUSE_ENTER_EXIT: strcpy(str, "B_MOUSE_ENTER_EXIT"); break; 1084 case B_MOUSE_UP: strcpy(str, "B_MOUSE_UP"); break; 1085 case B_PULSE: strcpy(str, "B_PULSE"); break; 1086 case B_READY_TO_RUN: strcpy(str, "B_READY_TO_RUN"); break; 1087 case B_REFS_RECEIVED: strcpy(str, "B_REFS_RECEIVED"); break; 1088 case B_SCREEN_CHANGED: strcpy(str, "B_SCREEN_CHANGED"); break; 1089 case B_VALUE_CHANGED: strcpy(str, "B_VALUE_CHANGED"); break; 1090 case B_VIEW_MOVED: strcpy(str, "B_VIEW_MOVED"); break; 1091 case B_VIEW_RESIZED: strcpy(str, "B_VIEW_RESIZED"); break; 1092 case B_WINDOW_MOVED: strcpy(str, "B_WINDOW_MOVED"); break; 1093 case B_WINDOW_RESIZED: strcpy(str, "B_WINDOW_RESIZED"); break; 1094 case B_WORKSPACES_CHANGED: strcpy(str, "B_WORKSPACES_CHANGED"); break; 1095 case B_WORKSPACE_ACTIVATED: strcpy(str, "B_WORKSPACE_ACTIVATED"); break; 1096 case B_ZOOM: strcpy(str, "B_ZOOM"); break; 1097 case _APP_MENU_: strcpy(str, "_APP_MENU_"); break; 1098 case _BROWSER_MENUS_: strcpy(str, "_BROWSER_MENUS_"); break; 1099 case _MENU_EVENT_: strcpy(str, "_MENU_EVENT_"); break; 1100 case _QUIT_: strcpy(str, "_QUIT_"); break; 1101 case _VOLUME_MOUNTED_: strcpy(str, "_VOLUME_MOUNTED_"); break; 1102 case _VOLUME_UNMOUNTED_: strcpy(str, "_VOLUME_UNMOUNTED_"); break; 1103 case _MESSAGE_DROPPED_: strcpy(str, "_MESSAGE_DROPPED_"); break; 1104 case _MENUS_DONE_: strcpy(str, "_MENUS_DONE_"); break; 1105 case _SHOW_DRAG_HANDLES_: strcpy(str, "_SHOW_DRAG_HANDLES_"); break; 1106 case B_SET_PROPERTY: strcpy(str, "B_SET_PROPERTY"); break; 1107 case B_GET_PROPERTY: strcpy(str, "B_GET_PROPERTY"); break; 1108 case B_CREATE_PROPERTY: strcpy(str, "B_CREATE_PROPERTY"); break; 1109 case B_DELETE_PROPERTY: strcpy(str, "B_DELETE_PROPERTY"); break; 1110 case B_COUNT_PROPERTIES: strcpy(str, "B_COUNT_PROPERTIES"); break; 1111 case B_EXECUTE_PROPERTY: strcpy(str, "B_EXECUTE_PROPERTY"); break; 1112 case B_GET_SUPPORTED_SUITES: strcpy(str, "B_GET_SUPPORTED_SUITES"); break; 1113 case B_CUT: strcpy(str, "B_CUT"); break; 1114 case B_COPY: strcpy(str, "B_COPY"); break; 1115 case B_PASTE: strcpy(str, "B_PASTE"); break; 1116 case B_SELECT_ALL: strcpy(str, "B_SELECT_ALL"); break; 1117 case B_SAVE_REQUESTED: strcpy(str, "B_SAVE_REQUESTED"); break; 1118 case B_MESSAGE_NOT_UNDERSTOOD: strcpy(str, "B_MESSAGE_NOT_UNDERSTOOD"); break; 1119 case B_NO_REPLY: strcpy(str, "B_NO_REPLY"); break; 1120 case B_REPLY: strcpy(str, "B_REPLY"); break; 1121 case B_SIMPLE_DATA: strcpy(str, "B_SIMPLE_DATA"); break; 1122 //case B_MIME_DATA : strcpy(str, "B_MIME_DATA"); break; 1123 case B_ARCHIVED_OBJECT: strcpy(str, "B_ARCHIVED_OBJECT"); break; 1124 case B_UPDATE_STATUS_BAR: strcpy(str, "B_UPDATE_STATUS_BAR"); break; 1125 case B_RESET_STATUS_BAR: strcpy(str, "B_RESET_STATUS_BAR"); break; 1126 case B_NODE_MONITOR: strcpy(str, "B_NODE_MONITOR"); break; 1127 case B_QUERY_UPDATE: strcpy(str, "B_QUERY_UPDATE"); break; 1128 case B_BAD_SCRIPT_SYNTAX: strcpy(str, "B_BAD_SCRIPT_SYNTAX"); break; 1129 1130 // specifiers: 1131 case B_NO_SPECIFIER: strcpy(str, "B_NO_SPECIFIER"); break; 1132 case B_DIRECT_SPECIFIER: strcpy(str, "B_DIRECT_SPECIFIER"); break; 1133 case B_INDEX_SPECIFIER: strcpy(str, "B_INDEX_SPECIFIER"); break; 1134 case B_REVERSE_INDEX_SPECIFIER: strcpy(str, "B_REVERSE_INDEX_SPECIFIER"); break; 1135 case B_RANGE_SPECIFIER: strcpy(str, "B_RANGE_SPECIFIER"); break; 1136 case B_REVERSE_RANGE_SPECIFIER: strcpy(str, "B_REVERSE_RANGE_SPECIFIER"); break; 1137 case B_NAME_SPECIFIER: strcpy(str, "B_NAME_SPECIFIER"); break; 1138 1139 case B_ERROR: strcpy(str, "B_ERROR"); break; 1140 1141 default: // unknown 1142 id_to_string(type, str); 1143 break; 1144 } 1145 return str; 1146 } 1147 1148 1149 char * 1150 format_data(int32 type, char *ptr, long size) 1151 { 1152 char idtext[32]; 1153 char *str; 1154 float *fptr; 1155 double *dptr; 1156 entry_ref aref; 1157 BEntry entry; 1158 BPath path; 1159 int64 i64; 1160 int32 i32; 1161 int16 i16; 1162 int8 i8; 1163 uint64 ui64; 1164 uint32 ui32; 1165 uint16 ui16; 1166 uint8 ui8; 1167 BMessage anothermsg; 1168 char *tempstr; 1169 1170 if (size <= 0L) { 1171 str = new char; 1172 *str = 0; 1173 return str; 1174 } 1175 1176 switch (type) { 1177 case B_MIME_TYPE: 1178 case B_ASCII_TYPE: 1179 case B_STRING_TYPE: 1180 if (size > 512) 1181 size = 512; 1182 str = new char[size + 4]; 1183 *str='\"'; 1184 strncpy(str + 1, ptr, size); 1185 strcat(str, "\""); 1186 break; 1187 1188 case B_POINTER_TYPE: 1189 str = new char[64]; 1190 sprintf(str, "%p", *(void**)ptr); 1191 break; 1192 1193 case B_REF_TYPE: 1194 str = new char[1024]; 1195 anothermsg.AddData("myref", B_REF_TYPE, ptr, size); 1196 anothermsg.FindRef("myref", &aref); 1197 if (entry.SetTo(&aref)==B_OK){ 1198 entry.GetPath(&path); 1199 strcpy(str, path.Path()); 1200 } else 1201 strcpy(str, "invalid entry_ref"); 1202 break; 1203 1204 case B_SSIZE_T_TYPE: 1205 case B_INT64_TYPE: 1206 str = new char[64]; 1207 i64 = *(int64*)ptr; 1208 sprintf(str, "%" B_PRId64 " (0x%" B_PRIx64 ")", i64, i64); 1209 break; 1210 1211 case B_SIZE_T_TYPE: 1212 case B_INT32_TYPE: 1213 str = new char[64]; 1214 i32 = *(int32*)ptr; 1215 sprintf(str, "%" B_PRId32 " (0x%08" B_PRId32 ")", i32, i32); 1216 break; 1217 1218 case B_INT16_TYPE: 1219 str = new char[64]; 1220 i16 = *(int16*)ptr; 1221 sprintf(str, "%d (0x%04X)", i16, i16); 1222 break; 1223 1224 case B_CHAR_TYPE: 1225 case B_INT8_TYPE: 1226 str = new char[64]; 1227 i8 = *(int8*)ptr; 1228 sprintf(str, "%d (0x%02X)", i8, i8); 1229 break; 1230 1231 case B_UINT64_TYPE: 1232 str = new char[64]; 1233 ui64 = *(uint64*)ptr; 1234 sprintf(str, "%" B_PRIu64 " (0x%" B_PRIx64 ")", ui64, ui64); 1235 break; 1236 1237 case B_UINT32_TYPE: 1238 str = new char[64]; 1239 ui32 = *(uint32*)ptr; 1240 sprintf(str, "%" B_PRIu32 " (0x%08" B_PRIx32 ")", ui32, ui32); 1241 break; 1242 1243 case B_UINT16_TYPE: 1244 str = new char[64]; 1245 ui16 = *(uint16*)ptr; 1246 sprintf(str, "%u (0x%04X)", ui16, ui16); 1247 break; 1248 1249 case B_UINT8_TYPE: 1250 str = new char[64]; 1251 ui8 = *(uint8*)ptr; 1252 sprintf(str, "%u (0x%02X)", ui8, ui8); 1253 break; 1254 1255 case B_BOOL_TYPE: 1256 str = new char[10]; 1257 if (*ptr) 1258 strcpy(str, "TRUE"); 1259 else 1260 strcpy(str, "FALSE"); 1261 break; 1262 1263 case B_FLOAT_TYPE: 1264 str = new char[40]; 1265 fptr = (float*)ptr; 1266 sprintf(str, "%.3f", *fptr); 1267 break; 1268 1269 case B_DOUBLE_TYPE: 1270 str = new char[40]; 1271 dptr = (double*)ptr; 1272 sprintf(str, "%.3f", *dptr); 1273 break; 1274 1275 case B_RECT_TYPE: 1276 str = new char[200]; 1277 fptr = (float*)ptr; 1278 sprintf(str, "BRect(%.1f, %.1f, %.1f, %.1f)", fptr[0], fptr[1], 1279 fptr[2], fptr[3]); 1280 break; 1281 1282 case B_POINT_TYPE: 1283 str = new char[200]; 1284 fptr = (float*)ptr; 1285 sprintf(str, "BPoint(%.1f, %.1f)", fptr[0], fptr[1]); 1286 break; 1287 1288 case B_RGB_COLOR_TYPE: 1289 str = new char[64]; 1290 sprintf(str, "Red=%u Green=%u Blue=%u Alpha=%u", 1291 ((uint8*)ptr)[0], ((uint8*)ptr)[1], ((uint8*)ptr)[2], 1292 ((uint8*)ptr)[3]); 1293 break; 1294 1295 case B_COLOR_8_BIT_TYPE: 1296 str = new char[size * 6 + 4]; 1297 *str = 0; 1298 for (int32 i = 0; i < min_c(256, size); i++) { 1299 sprintf(idtext, "%u ", ((unsigned char*)ptr)[i]); 1300 strcat(str,idtext); 1301 } 1302 *(str+strlen(str)-2) = 0; 1303 break; 1304 1305 case B_MESSAGE_TYPE: 1306 str = new char[64]; 1307 if (anothermsg.Unflatten((const char *)ptr) == B_OK) { 1308 char *whatString = get_datatype_string(anothermsg.what); 1309 sprintf(str, "what=%s", whatString); 1310 delete[] whatString; 1311 } else 1312 strcpy(str, "error when unflattening"); 1313 break; 1314 1315 case B_PROPERTY_INFO_TYPE: 1316 { 1317 BPropertyInfo propinfo; 1318 if (propinfo.Unflatten(B_PROPERTY_INFO_TYPE, (const void *)ptr, 1319 size) == B_OK) { 1320 str = new char[size * 32]; // an approximation 1321 1322 const property_info *pinfo = propinfo.Properties(); 1323 1324 sprintf(str, "\n property commands " 1325 "specifiers types\n-----------------------------------" 1326 "----------------------------------------------------------------\n"); 1327 for (int32 pinfo_index = 0; pinfo_index < propinfo.CountProperties(); pinfo_index++) { 1328 strcat(str, " " 1329 + (strlen(pinfo[pinfo_index].name) < 16 ? 1330 strlen(pinfo[pinfo_index].name) : 16)); 1331 strcat(str, pinfo[pinfo_index].name); 1332 strcat(str, " "); 1333 char *start = str + strlen(str); 1334 1335 for (int32 i = 0; i < 10 && pinfo[pinfo_index].commands[i]; 1336 i++) { 1337 tempstr = get_datatype_string( 1338 pinfo[pinfo_index].commands[i]); 1339 strcat(str, tempstr); 1340 strcat(str, " "); 1341 delete[] tempstr; 1342 } 1343 1344 // pad the rest with spaces 1345 if (strlen(start) < 36) { 1346 strcat(str, " " 1347 + strlen(start)); 1348 } else 1349 strcat(str, " " ); 1350 1351 for (int32 i = 0; i < 10 && pinfo[pinfo_index].specifiers[i]; i++) { 1352 switch (pinfo[pinfo_index].specifiers[i]) { 1353 case B_NO_SPECIFIER: 1354 strcat(str, "NONE "); 1355 break; 1356 case B_DIRECT_SPECIFIER: 1357 strcat(str, "DIRECT "); 1358 break; 1359 case B_INDEX_SPECIFIER: 1360 strcat(str, "INDEX "); 1361 break; 1362 case B_REVERSE_INDEX_SPECIFIER: 1363 strcat(str, "REV.INDEX "); 1364 break; 1365 case B_RANGE_SPECIFIER: 1366 strcat(str, "RANGE "); 1367 break; 1368 case B_REVERSE_RANGE_SPECIFIER: 1369 strcat(str, "REV.RANGE "); 1370 break; 1371 case B_NAME_SPECIFIER: 1372 strcat(str, "NAME "); 1373 break; 1374 case B_ID_SPECIFIER: 1375 strcat(str, "ID "); 1376 break; 1377 default: 1378 strcat(str, "<NONE> "); 1379 break; 1380 } 1381 } 1382 1383 // pad the rest with spaces 1384 if (strlen(start) < 60) { 1385 strcat(str, " " 1386 " " + strlen(start)); 1387 } else 1388 strcat(str, " "); 1389 for (int32 i = 0; i < 10 1390 && pinfo[pinfo_index].types[i] != 0; i++) { 1391 uint32 type = pinfo[pinfo_index].types[i]; 1392 char str2[6]; 1393 snprintf(str2, sizeof(str2), "%c%c%c%c ", 1394 int(type & 0xFF000000) >> 24, 1395 int(type & 0xFF0000) >> 16, 1396 int(type & 0xFF00) >> 8, 1397 (int)type & 0xFF); 1398 strcat(str, str2); 1399 } 1400 1401 for (int32 i = 0; i < 3; i++) { 1402 for (int32 j = 0; j < 5 1403 && pinfo[pinfo_index].ctypes[i].pairs[j].type 1404 != 0; j++) { 1405 uint32 type = pinfo[pinfo_index].ctypes[i].pairs[j].type; 1406 char str2[strlen(pinfo[pinfo_index].ctypes[i].pairs[j].name) + 8]; 1407 snprintf(str2, sizeof(str2), 1408 "(%s %c%c%c%c)", 1409 pinfo[pinfo_index].ctypes[i].pairs[j].name, 1410 int(type & 0xFF000000) >> 24, 1411 int(type & 0xFF0000) >> 16, 1412 int(type & 0xFF00) >> 8, 1413 (int)type & 0xFF); 1414 strcat(str, str2); 1415 } 1416 } 1417 strcat(str, "\n"); 1418 1419 // is there usage info? 1420 if (pinfo[pinfo_index].usage) { 1421 strcat(str, " Usage: "); 1422 strcat(str, pinfo[pinfo_index].usage); 1423 strcat(str, "\n"); 1424 } 1425 } 1426 1427 1428 // handle value infos.... 1429 const value_info *vinfo = propinfo.Values(); 1430 int32 vinfo_count = propinfo.CountValues(); 1431 #if TEST_VALUEINFO>0 1432 value_info vinfo[10] = { 1433 {"Backup", 'back', B_COMMAND_KIND, 1434 "This command backs up your hard drive."}, 1435 {"Abort", 'abor', B_COMMAND_KIND, 1436 "Stops the current operation..."}, 1437 {"Type Code", 'type', B_TYPE_CODE_KIND, 1438 "Type code info..."} 1439 }; 1440 vinfo_count = 3; 1441 #endif 1442 1443 if (vinfo && vinfo_count > 0) { 1444 sprintf(str + strlen(str), 1445 "\n name value " 1446 " kind\n---------------------------------------------" 1447 "-----------------------------------\n"); 1448 1449 for (int32 vinfo_index = 0; vinfo_index < vinfo_count; 1450 vinfo_index++) { 1451 char *start = str + strlen(str); 1452 strcat(str, " " + (strlen(vinfo[vinfo_index].name) < 16 ? strlen(vinfo[vinfo_index].name) : 16)); 1453 strcat(str, vinfo[vinfo_index].name); 1454 strcat(str, " "); 1455 1456 sprintf(str + strlen(str), "0x%8" B_PRIx32 " (", 1457 vinfo[vinfo_index].value); 1458 id_to_string(vinfo[vinfo_index].value, str + strlen(str)); 1459 strcat(str, ")"); 1460 1461 // pad the rest with spaces 1462 if (strlen(start) < 36 + 19) { 1463 strcat(str, " " 1464 " " + strlen(start)); 1465 } else 1466 strcat(str, " "); 1467 1468 switch (vinfo[vinfo_index].kind) { 1469 case B_COMMAND_KIND: 1470 strcat(str, "COMMAND "); 1471 break; 1472 1473 case B_TYPE_CODE_KIND: 1474 strcat(str, "TYPE CODE "); 1475 break; 1476 1477 default: 1478 strcat(str, "unknown "); 1479 break; 1480 } 1481 1482 strcat(str, "\n"); 1483 1484 // is there usage info? 1485 if (vinfo[vinfo_index].usage) { 1486 strcat(str, " Usage: "); 1487 strcat(str, vinfo[vinfo_index].usage); 1488 strcat(str, "\n"); 1489 } 1490 } 1491 } 1492 } else { 1493 str = new char[64]; 1494 strcpy(str, "error when unflattening"); 1495 } 1496 break; 1497 } 1498 1499 default: 1500 str = new char[min_c(256, size) * 20 + 4]; 1501 *str = 0; 1502 for (int32 i = 0; i < min_c(256, size); i++) { 1503 sprintf(idtext, "0x%02X, ", (uint16)ptr[i]); 1504 strcat(str, idtext); 1505 } 1506 *(str + strlen(str) - 2) = 0; 1507 break; 1508 } 1509 1510 return str; 1511 } 1512 1513 1514 char * 1515 id_to_string(long ID, char *here) 1516 { 1517 uint8 digit0 = (ID>>24)& 255; 1518 uint8 digit1 = (ID>>16)& 255; 1519 uint8 digit2 = (ID>>8) & 255; 1520 uint8 digit3 = (ID) & 255; 1521 bool itsvalid = false; 1522 1523 if (digit0 == 0) { 1524 if (digit1 == 0) { 1525 if (digit2 == 0) { 1526 // 1 digits 1527 itsvalid = is_valid_char(digit3); 1528 sprintf(here, "'%c'", digit3); 1529 } else { 1530 // 2 digits 1531 itsvalid = is_valid_char(digit2) && is_valid_char(digit3); 1532 sprintf(here, "'%c%c'", digit2, digit3); 1533 } 1534 } else { 1535 // 3 digits 1536 itsvalid = is_valid_char(digit1) && is_valid_char(digit2) 1537 && is_valid_char(digit3); 1538 sprintf(here, "'%c%c%c'", digit1, digit2, digit3); 1539 } 1540 } else { 1541 // 4 digits 1542 itsvalid = is_valid_char(digit0) && is_valid_char(digit1) 1543 && is_valid_char(digit2) && is_valid_char(digit3); 1544 sprintf(here, "'%c%c%c%c'", digit0, digit1, digit2, digit3); 1545 } 1546 1547 if (!itsvalid) 1548 sprintf(here, "%ldL", ID); 1549 1550 return here; 1551 } 1552 1553 1554 bool 1555 is_valid_char(uint8 c) 1556 { 1557 return c >= 32 && c < 128; 1558 } 1559 1560