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