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