#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <AppKit.h>
#include <Path.h>
#include <SupportDefs.h>
int32 HeyInterpreterThreadHook(void* arg);
status_t Hey(BMessenger* target, const char* arg, BMessage* reply);
bool isSpace(char c);
status_t Hey(BMessenger* target, char* argv[], int32* argx, int32 argc, BMessage* reply);
status_t add_specifier(BMessage *to_message, char *argv[], int32 *argx, int32 argc);
status_t add_data(BMessage *to_message, char *argv[], int32 *argx);
status_t add_with(BMessage *to_message, char *argv[], int32 *argx, int32 argc);
void add_message_contents(BList *textlist, BMessage *msg, int32 level);
char *get_datatype_string(int32 type);
char *format_data(int32 type, char *ptr, long size);
void print_message(BMessage *message);
char *id_to_string(long ID, char *here);
bool is_valid_char(uint8 c);
const char VERSION[] = "v1.2.8";
#define MAX_INPUT_SIZE 1024
#define DEBUG_HEY 0 // 1: prints the script message to be sent to the target application, 0: prints only the reply
#define TEST_VALUEINFO 0
bool silent;
bool output;
status_t
parse(BMessenger& the_application, int argc, char *argv[], int32 argapp)
{
if (!the_application.IsValid()) {
if (!silent)
fprintf(stderr, "Cannot find the application (%s)\n", argv[argapp]);
return B_ERROR;
}
if (argc < 3) {
if (!silent)
fprintf(stderr, "Cannot find the verb!\n");
return B_ERROR;
}
BMessage the_reply;
int32 argx = argapp+1;
status_t err = Hey(&the_application, argv, &argx, argc, &the_reply);
if (err != B_OK) {
if (!silent) {
fprintf(stderr, "Error when sending message to %s!\n",
argv[argapp]);
}
return B_ERROR;
} else {
if (the_reply.what == (uint32)B_MESSAGE_NOT_UNDERSTOOD
|| the_reply.what == (uint32)B_ERROR) {
if (the_reply.HasString("message")) {
if (!silent) {
printf("%s (error 0x%8" B_PRIx32 ")\n",
the_reply.FindString("message"),
the_reply.FindInt32("error"));
}
} else {
if (!silent) {
printf("error 0x%8" B_PRIx32 "\n",
the_reply.FindInt32("error"));
}
}
return 1;
} else {
if (!silent) {
if (output) {
type_code tc;
if (the_reply.GetInfo("result", &tc) == B_OK) {
if (tc == B_INT8_TYPE) {
int8 v;
the_reply.FindInt8("result", &v);
printf("%d\n", v);
} else if (tc == B_INT16_TYPE) {
int16 v;
the_reply.FindInt16("result", &v);
printf("%d\n", v);
} else if (tc == B_INT32_TYPE) {
int32 v;
the_reply.FindInt32("result", &v);
printf("%" B_PRId32 "\n", v);
} else if (tc == B_UINT8_TYPE) {
uint8 v;
the_reply.FindInt8("result", (int8*)&v);
printf("%u\n", v);
} else if (tc == B_UINT16_TYPE) {
uint16 v;
the_reply.FindInt16("result", (int16*)&v);
printf("%u\n", v);
} else if (tc == B_UINT32_TYPE) {
uint32 v;
the_reply.FindInt32("result", (int32*)&v);
printf("%" B_PRIu32 "\n", v);
} else if (tc == B_STRING_TYPE) {
const char* v;
the_reply.FindString("result", &v);
printf("%s\n", v);
} else if (tc == B_FLOAT_TYPE) {
float v;
the_reply.FindFloat("result", &v);
printf("%f\n", v);
} else if (tc == B_DOUBLE_TYPE) {
double v;
the_reply.FindDouble("result", &v);
printf("%f\n", v);
} else if (tc == B_BOOL_TYPE) {
bool v;
the_reply.FindBool("result", &v);
printf("%s\n", v ? "true" : "false");
} else
printf("Unsupported type\n");
}
} else {
printf("Reply ");
print_message(&the_reply);
printf("\n");
}
}
}
}
return B_OK;
}
void
usage(int exitCode)
{
fprintf(exitCode == EXIT_SUCCESS ? stdout : stderr,
"hey %s, written by Attila Mezei (attila.mezei@mail.datanet.hu)\n"
"usage: hey [-s][-o] <app|signature|teamid> [let <specifier> do] <verb> <specifier_1> <of\n"
" <specifier_n>>* [to <value>] [with name=<value> [and name=<value>]*]\n"
"where <verb> : DO|GET|SET|COUNT|CREATE|DELETE|GETSUITES|QUIT|SAVE|LOAD|'what'\n"
" <specifier> : [the] <property_name> [ <index> | name | \"name\" | '\"name\"' ]\n"
" <index> : int | -int | '['int']' | '['-int']' | '['startint to end']'\n"
" <value> : \"string\" | <integer> | <float> | bool(value) | int8(value)\n"
" | int16(value) | int32(value) | float(value) | double(value)\n"
" | BPoint(x,y) | BRect(l,t,r,b) | rgb_color(r,g,b,a) | file(path)\n"
"options: -s: silent\n"
" -o: output result to stdout for easy parsing\n\n", VERSION);
exit(exitCode);
}
int
main(int argc, char *argv[])
{
BApplication app("application/x-amezei-hey");
if (argc < 2)
usage(1);
int32 argapp = 1;
silent = false;
output = false;
for (int i = 0; i < argc; i++) {
if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "-S") == 0) {
silent = true;
argapp++;
} else if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "-O") == 0) {
output = true;
argapp++;
} else if (strcmp(argv[1], "-h") == 0
|| strcmp(argv[1], "--help") == 0)
usage(0);
}
BMessenger the_application;
BList team_list;
team_id teamid;
app_info appinfo;
teamid = atoi(argv[argapp]);
if (teamid > 0) {
if (be_roster->GetRunningAppInfo(teamid, &appinfo) != B_OK)
return 1;
the_application=BMessenger(NULL, teamid);
if (!parse(the_application, argc, argv, argapp))
return 0;
return 1;
}
be_roster->GetAppList(&team_list);
for (int32 i = 0; i < team_list.CountItems(); i++) {
teamid = (team_id)(addr_t)team_list.ItemAt(i);
be_roster->GetRunningAppInfo(teamid, &appinfo);
if (strcmp(appinfo.signature, argv[argapp]) == 0) {
the_application=BMessenger(appinfo.signature);
if (!parse(the_application, argc, argv, argapp))
return 0;
} else {
if (strcmp(appinfo.ref.name, argv[argapp]) == 0) {
the_application = BMessenger(0, teamid);
if (!parse(the_application, argc, argv, argapp))
return 0;
}
}
}
return 1;
}
int32
HeyInterpreterThreadHook(void* arg)
{
if (!arg)
return 1;
BMessage environment(*(BMessage*) arg);
const char* prompt = "Hey";
if (environment.HasString("prompt"))
environment.FindString("prompt", &prompt);
printf("%s> ", prompt);
BMessenger target;
if (environment.HasMessenger("Target"))
environment.FindMessenger("Target", &target);
char command[MAX_INPUT_SIZE];
status_t err;
BMessage reply;
while (fgets(command, sizeof(command), stdin)) {
reply.MakeEmpty();
err = Hey(&target, command, &reply);
if (!err) {
print_message(&reply);
} else {
printf("Error!\n");
}
printf("%s> ", prompt);
}
return 0;
}
status_t
Hey(BMessenger* target, const char* arg, BMessage* reply)
{
BList argv;
char* tokens = new char[strlen(arg) * 2];
char* currentToken = tokens;
int32 tokenNdex = 0;
int32 argNdex = 0;
bool inquotes = false;
while (arg[argNdex] != 0) {
if (arg[argNdex] == '\"')
inquotes = !inquotes;
if (!inquotes && isSpace(arg[argNdex])) {
if (tokenNdex != 0) {
currentToken[tokenNdex] = 0;
argv.AddItem(currentToken);
currentToken += tokenNdex + 1;
tokenNdex = 0;
argNdex++;
} else {
argNdex++;
}
} else {
currentToken[tokenNdex] = arg[argNdex];
tokenNdex++;
argNdex++;
}
}
if (tokenNdex!=0) {
currentToken[tokenNdex] = 0;
argv.AddItem(currentToken);
}
argv.AddItem(NULL);
int32 argx = 0;
status_t ret = Hey(target, (char **)argv.Items(), &argx, argv.CountItems() - 1, reply);
delete[] tokens;
return ret;
}
bool
isSpace(char c)
{
switch (c) {
case ' ':
case '\t':
return true;
default:
return false;
}
}
status_t
Hey(BMessenger* target, char* argv[], int32* argx, int32 argc, BMessage* reply)
{
bool direct_what = false;
BMessage the_message;
if (strcasecmp(argv[*argx], "let") == 0) {
BMessage get_target (B_GET_PROPERTY);
get_target.AddSpecifier ("Messenger");
(*argx)++;
status_t result = B_OK;
while ((result = add_specifier(&get_target, argv, argx, argc)) == B_OK)
;
if (result != B_ERROR) {
if (!silent)
fprintf(stderr, "Bad specifier syntax!\n");
return result;
}
BMessage msgr;
if (target && target->IsValid()) {
result = target->SendMessage(&get_target, &msgr);
if (result != B_OK)
return result;
result = msgr.FindMessenger ("result", target);
if (result != B_OK) {
if (!silent)
fprintf(stderr, "Couldn't retrieve the BMessenger!\n");
return result;
}
}
if (!argv[*argx]) {
if (!silent)
fprintf(stderr, "Syntax error - forgot \"do\"?\n");
return B_ERROR;
}
}
if (strcasecmp(argv[*argx], "do") == 0)
the_message.what = B_EXECUTE_PROPERTY;
else if (strcasecmp(argv[*argx], "get") == 0)
the_message.what = B_GET_PROPERTY;
else if (strcasecmp(argv[*argx], "set") == 0)
the_message.what = B_SET_PROPERTY;
else if (strcasecmp(argv[*argx], "create") == 0)
the_message.what = B_CREATE_PROPERTY;
else if (strcasecmp(argv[*argx], "delete") == 0)
the_message.what = B_DELETE_PROPERTY;
else if (strcasecmp(argv[*argx], "quit") == 0)
the_message.what = B_QUIT_REQUESTED;
else if (strcasecmp(argv[*argx], "save") == 0)
the_message.what = B_SAVE_REQUESTED;
else if (strcasecmp(argv[*argx], "load") == 0)
the_message.what = B_REFS_RECEIVED;
else if (strcasecmp(argv[*argx], "count") == 0)
the_message.what = B_COUNT_PROPERTIES;
else if (strcasecmp(argv[*argx], "getsuites") == 0)
the_message.what = B_GET_SUPPORTED_SUITES;
else {
switch(strlen(argv[*argx])) {
case 1:
the_message.what = (int32)argv[*argx][0];
break;
case 2:
the_message.what = (((int32)argv[*argx][0]) << 8)
| (((int32)argv[*argx][1]));
break;
case 3:
the_message.what = (((int32)argv[*argx][0]) << 16)
| (((int32)argv[*argx][1]) << 8)
| (((int32)argv[*argx][2]));
break;
case 4:
the_message.what = (((int32)argv[*argx][0]) << 24)
| (((int32)argv[*argx][1]) << 16)
| (((int32)argv[*argx][2]) << 8)
| (((int32)argv[*argx][3]));
break;
default:
bool found = false;
if (target && target->IsValid()) {
BMessage reply;
if (target->SendMessage(B_GET_SUPPORTED_SUITES, &reply)
== B_OK) {
int32 j = 0;
void *voidptr;
ssize_t sizefound;
BPropertyInfo propinfo;
const value_info *vinfo;
int32 vinfo_index, vinfo_count;
while (reply.FindData("messages", B_PROPERTY_INFO_TYPE,
j++, (const void **)&voidptr, &sizefound)
== B_OK && !found) {
if (propinfo.Unflatten(B_PROPERTY_INFO_TYPE,
(const void *)voidptr, sizefound) == B_OK) {
vinfo = propinfo.Values();
vinfo_index = 0;
vinfo_count = propinfo.CountValues();
#if TEST_VALUEINFO>0
value_info vinfo[10] = {
{"Backup", 'back', B_COMMAND_KIND,
"This command backs up your hard"
" drive."},
{"Abort", 'abor', B_COMMAND_KIND,
"Stops the current operation..."},
{"Type Code", 'type', B_TYPE_CODE_KIND,
"Type code info..."}
};
vinfo_count = 3;
#endif
while (vinfo_index < vinfo_count) {
if (strcmp(vinfo[vinfo_index].name,
argv[*argx]) == 0) {
found = true;
the_message.what =
vinfo[vinfo_index].value;
#if TEST_VALUEINFO>0
printf("FOUND COMMAND \"%s\" = %lX\n",
vinfo[vinfo_index].name,
the_message.what);
#endif
break;
}
vinfo_index++;
}
}
}
}
}
if (!found) {
if (!silent)
fprintf(stderr, "Bad verb (\"%s\")\n", argv[*argx]);
return -1;
}
}
direct_what = true;
}
status_t result = B_OK;
(*argx)++;
if (direct_what && *argx == argc - 1 && argv[*argx] != NULL)
add_data(&the_message, argv, argx);
else {
if (the_message.what != B_REFS_RECEIVED) {
while ((result = add_specifier(&the_message, argv, argx, argc))
== B_OK)
;
if (result != B_ERROR) {
if (!silent)
fprintf(stderr, "Bad specifier syntax!\n");
return result;
}
}
}
if ((the_message.what == B_SET_PROPERTY || the_message.what == B_REFS_RECEIVED) && argv[*argx] != NULL) {
if (strcasecmp(argv[*argx], "to") == 0)
(*argx)++;
result = add_data(&the_message, argv, argx);
if (result != B_OK) {
if (result == B_ENTRY_NOT_FOUND) {
if (!silent)
fprintf(stderr, "File not found!\n");
} else if (!silent)
fprintf(stderr, "Invalid 'to...' value format!\n");
return result;
}
}
add_with(&the_message, argv, argx, argc);
#if DEBUG_HEY>0
fprintf(stderr, "Send ");
print_message(&the_message);
fprintf(stderr, "\n");
#endif
if (target && target->IsValid()) {
if (reply)
result = target->SendMessage(&the_message, reply);
else
result = target->SendMessage(&the_message);
}
return result;
}
status_t
add_with(BMessage *to_message, char *argv[], int32 *argx, int32 argc)
{
status_t result = B_OK;
if (*argx < argc - 1 && argv[++(*argx)] != NULL) {
if (strcasecmp(argv[*argx], "with") == 0) {
(*argx)++;
bool done = false;
do {
result = add_data(to_message, argv, argx);
if (result != B_OK) {
if (result == B_ENTRY_NOT_FOUND) {
if (!silent)
fprintf(stderr, "File not found!\n");
} else {
if (!silent)
fprintf(stderr, "Invalid 'with...' value format!\n");
}
return result;
}
(*argx)++;
if (*argx < argc - 1 && strcasecmp(argv[*argx], "and") == 0)
(*argx)++;
else
done = true;
} while (!done);
}
}
return result;
}
status_t
add_specifier(BMessage *to_message, char *argv[], int32 *argx, int32 argc)
{
char *property = argv[*argx];
if (property == NULL)
return B_ERROR;
(*argx)++;
if (strcasecmp(property, "do") == 0) {
return B_ERROR;
}
if (strcasecmp(property, "to") == 0) {
return B_ERROR;
}
if (strcasecmp(property, "with") == 0) {
*argx -= 2;
add_with(to_message, argv, argx, argc);
return B_ERROR;
}
if (strcasecmp(property, "of") == 0) {
property = argv[*argx];
if (property == NULL)
return B_BAD_SCRIPT_SYNTAX;
(*argx)++;
}
if (strcasecmp(property, "the") == 0) {
property = argv[*argx];
if (property == NULL)
return B_BAD_SCRIPT_SYNTAX;
(*argx)++;
}
char *specifier = NULL;
if (to_message->what == B_CREATE_PROPERTY) {
(*argx)--;
} else
specifier = argv[*argx];
if (specifier == NULL) {
to_message->AddSpecifier(property);
return B_ERROR;
}
(*argx)++;
if (strcasecmp(specifier, "of") == 0) {
to_message->AddSpecifier(property);
return B_OK;
}
if (strcasecmp(specifier, "to") == 0) {
to_message->AddSpecifier(property);
return B_ERROR;
}
if (specifier[0] == '[') {
char *end;
int32 ix1, ix2;
if (specifier[1] == '-') {
ix1 = strtoul(specifier + 2, &end, 10);
BMessage revspec(B_REVERSE_INDEX_SPECIFIER);
revspec.AddString("property", property);
revspec.AddInt32("index", ix1);
to_message->AddSpecifier(&revspec);
} else {
ix1 = strtoul(specifier + 1, &end, 10);
if (end[0] == ']') {
to_message->AddSpecifier(property, ix1);
return B_OK;
} else {
specifier = argv[*argx];
if (specifier == NULL) {
to_message->AddSpecifier(property, ix1);
return B_OK;
}
(*argx)++;
if (strcasecmp(specifier, "to") == 0) {
specifier = argv[*argx];
if (specifier == NULL)
return B_BAD_SCRIPT_SYNTAX;
(*argx)++;
ix2 = strtoul(specifier, &end, 10);
to_message->AddSpecifier(property, ix1, ix2 - ix1 > 0
? ix2 - ix1 : 1);
return B_OK;
} else
return B_BAD_SCRIPT_SYNTAX;
}
}
} else {
bool index_spec = true;
bool reverse = specifier[0] == '-';
size_t speclen = strlen(specifier);
for (int32 i = (reverse ? 1 : 0); i < (int32)speclen; ++i) {
if (specifier[i] < '0' || specifier[i] > '9') {
index_spec = false;
break;
}
}
if (index_spec) {
if (reverse) {
BMessage revspec(B_REVERSE_INDEX_SPECIFIER);
revspec.AddString("property", property);
revspec.AddInt32("index", atol(specifier + 1));
to_message->AddSpecifier(&revspec);
} else
to_message->AddSpecifier(property, atol(specifier));
} else {
if (specifier[0] == '\"') {
if (specifier[speclen - 1] == '\"')
specifier[speclen - 1] = '\0';
++specifier;
--speclen;
}
to_message->AddSpecifier(property, specifier);
}
}
return B_OK;
}
status_t
add_data(BMessage *to_message, char *argv[], int32 *argx)
{
char *valuestring = argv[*argx];
if (valuestring == NULL)
return B_ERROR;
bool contains_only_digits = true;
bool is_floating_point = false;
for (int32 i = 0; i < (int32)strlen(valuestring); i++) {
if (i != 0 || valuestring[i] != '-') {
if (valuestring[i] < '0' || valuestring[i] > '9') {
if (valuestring[i] == '.') {
is_floating_point = true;
} else {
contains_only_digits = false;
break;
}
}
}
}
if (contains_only_digits) {
if (is_floating_point) {
to_message->AddFloat("data", atof(valuestring));
return B_OK;
} else {
to_message->AddInt32("data", atol(valuestring));
return B_OK;
}
}
if (strcasecmp(valuestring, "true") == 0) {
to_message->AddBool("data", true);
return B_OK;
} else if (strcasecmp(valuestring, "false") == 0) {
to_message->AddBool("data", false);
return B_OK;
}
#define MAX_NAME_LENGTH 128
char curname[MAX_NAME_LENGTH];
strcpy (curname, "data");
char *s = valuestring;
while (*++s && *s != '=')
;
if (*s == '=') {
*s = 0;
strcpy (curname, valuestring);
valuestring = s + 1;
}
if (strncasecmp(valuestring, "int8", strlen("int8")) == 0)
to_message->AddInt8(curname, atol(valuestring + strlen("int8(")));
else if (strncasecmp(valuestring, "int16", strlen("int16")) == 0)
to_message->AddInt16(curname, atol(valuestring + strlen("int16(")));
else if (strncasecmp(valuestring, "int32", strlen("int32")) == 0)
to_message->AddInt32(curname, atol(valuestring + strlen("int32(")));
else if (strncasecmp(valuestring, "int64", strlen("int64")) == 0)
to_message->AddInt64(curname, atol(valuestring + strlen("int64(")));
else if (strncasecmp(valuestring, "bool", strlen("bool")) == 0) {
if (strncasecmp(valuestring + strlen("bool("), "true", 4) == 0)
to_message->AddBool(curname, true);
else if (strncasecmp(valuestring + strlen("bool("), "false", 5) == 0)
to_message->AddBool(curname, false);
else
to_message->AddBool(curname, atol(valuestring + strlen("bool(")) == 0 ? false : true);
} else if (strncasecmp(valuestring, "float", strlen("float")) == 0)
to_message->AddFloat(curname, atof(valuestring + strlen("float(")));
else if (strncasecmp(valuestring, "double", strlen("double")) == 0)
to_message->AddDouble(curname, atof(valuestring + strlen("double(")));
else if (strncasecmp(valuestring, "BPoint", strlen("BPoint")) == 0) {
float x, y;
x = atof(valuestring + strlen("BPoint("));
if (strchr(valuestring, ','))
y = atof(strchr(valuestring, ',') + 1);
else if (strchr(valuestring, ' '))
y = atof(strchr(valuestring, ' ') + 1);
else
y = 0.0f;
to_message->AddPoint(curname, BPoint(x,y));
} else if (strncasecmp(valuestring, "BRect", strlen("BRect")) == 0) {
float l = 0.0f, t = 0.0f, r = 0.0f, b = 0.0f;
char *ptr;
l = atof(valuestring + strlen("BRect("));
ptr = strchr(valuestring, ',');
if (ptr) {
t = atof(ptr + 1);
ptr = strchr(ptr + 1, ',');
if (ptr) {
r = atof(ptr + 1);
ptr = strchr(ptr + 1, ',');
if (ptr)
b = atof(ptr + 1);
}
}
to_message->AddRect(curname, BRect(l,t,r,b));
} else if (strncasecmp(valuestring, "rgb_color", strlen("rgb_color")) == 0) {
rgb_color clr;
char *ptr;
clr.red = atol(valuestring + strlen("rgb_color("));
ptr = strchr(valuestring, ',');
if (ptr) {
clr.green = atol(ptr + 1);
ptr = strchr(ptr + 1, ',');
if (ptr) {
clr.blue = atol(ptr + 1);
ptr = strchr(ptr + 1, ',');
if (ptr)
clr.alpha = atol(ptr + 1);
}
}
to_message->AddData(curname, B_RGB_COLOR_TYPE, &clr, sizeof(rgb_color));
} else if (strncasecmp(valuestring, "file", strlen("file")) == 0) {
entry_ref file_ref;
if (valuestring[strlen(valuestring) - 1] == ')'
|| valuestring[strlen(valuestring) - 1] == ']')
valuestring[strlen(valuestring) - 1] = 0;
if (get_ref_for_path(valuestring + 5, &file_ref) != B_OK)
return B_ENTRY_NOT_FOUND;
BEntry entry;
if (entry.SetTo(&file_ref) != B_OK)
return B_ENTRY_NOT_FOUND;
to_message->AddRef("refs", &file_ref);
to_message->AddRef(curname, &file_ref);
} else {
if (valuestring[0] == '\"') {
if (valuestring[strlen(valuestring) - 1] == '\"')
valuestring[strlen(valuestring) - 1] = 0;
to_message->AddString(curname, valuestring + 1);
} else
to_message->AddString(curname, valuestring);
}
return B_OK;
}
void
print_message(BMessage *message)
{
BList textlist;
add_message_contents(&textlist, message, 0);
char *whatString = get_datatype_string(message->what);
printf("BMessage(%s):\n", whatString);
delete[] whatString;
for (int32 i = 0; i < textlist.CountItems(); i++) {
printf(" %s\n", (char*)textlist.ItemAt(i));
free(textlist.ItemAt(i));
}
}
void
add_message_contents(BList *textlist, BMessage *msg, int32 level)
{
int32 count;
int32 i, j;
type_code typefound;
ssize_t sizefound;
#ifdef HAIKU_TARGET_PLATFORM_DANO
const char *namefound;
#else
char *namefound;
#endif
void *voidptr;
BMessage a_message;
char *textline, *datatype, *content;
count = msg->CountNames(B_ANY_TYPE);
for (i=0; i < count; i++) {
msg->GetInfo(B_ANY_TYPE, i, &namefound, &typefound);
j = 0;
while (msg->FindData(namefound, typefound, j++, (const void **)&voidptr,
&sizefound) == B_OK) {
datatype = get_datatype_string(typefound);
content = format_data(typefound, (char*)voidptr, sizefound);
textline = (char*)malloc(20 + level * 4 + strlen(namefound)
+ strlen(datatype) + strlen(content));
memset(textline, 32, 20 + level * 4);
sprintf(textline + level * 4, "\"%s\" (%s) : %s", namefound,
datatype, content);
textlist->AddItem(textline);
delete[] datatype;
delete[] content;
if (typefound == B_MESSAGE_TYPE) {
msg->FindMessage(namefound, j - 1, &a_message);
add_message_contents(textlist, &a_message, level + 1);
} else if (typefound == B_RAW_TYPE && strcmp(namefound,
"_previous_") == 0) {
if (a_message.Unflatten((const char *)voidptr) == B_OK)
add_message_contents(textlist, &a_message, level + 1);
}
}
}
}
char *
get_datatype_string(int32 type)
{
char *str = new char[128];
switch (type) {
case B_ANY_TYPE: strcpy(str, "B_ANY_TYPE"); break;
case B_ASCII_TYPE: strcpy(str, "B_ASCII_TYPE"); break;
case B_BOOL_TYPE: strcpy(str, "B_BOOL_TYPE"); break;
case B_CHAR_TYPE: strcpy(str, "B_CHAR_TYPE"); break;
case B_COLOR_8_BIT_TYPE: strcpy(str, "B_COLOR_8_BIT_TYPE"); break;
case B_DOUBLE_TYPE: strcpy(str, "B_DOUBLE_TYPE"); break;
case B_FLOAT_TYPE: strcpy(str, "B_FLOAT_TYPE"); break;
case B_GRAYSCALE_8_BIT_TYPE: strcpy(str, "B_GRAYSCALE_8_BIT_TYPE"); break;
case B_INT64_TYPE: strcpy(str, "B_INT64_TYPE"); break;
case B_INT32_TYPE: strcpy(str, "B_INT32_TYPE"); break;
case B_INT16_TYPE: strcpy(str, "B_INT16_TYPE"); break;
case B_INT8_TYPE: strcpy(str, "B_INT8_TYPE"); break;
case B_MESSAGE_TYPE: strcpy(str, "B_MESSAGE_TYPE"); break;
case B_MESSENGER_TYPE: strcpy(str, "B_MESSENGER_TYPE"); break;
case B_MIME_TYPE: strcpy(str, "B_MIME_TYPE"); break;
case B_MONOCHROME_1_BIT_TYPE: strcpy(str, "B_MONOCHROME_1_BIT_TYPE"); break;
case B_OBJECT_TYPE: strcpy(str, "B_OBJECT_TYPE"); break;
case B_OFF_T_TYPE: strcpy(str, "B_OFF_T_TYPE"); break;
case B_PATTERN_TYPE: strcpy(str, "B_PATTERN_TYPE"); break;
case B_POINTER_TYPE: strcpy(str, "B_POINTER_TYPE"); break;
case B_POINT_TYPE: strcpy(str, "B_POINT_TYPE"); break;
case B_RAW_TYPE: strcpy(str, "B_RAW_TYPE"); break;
case B_RECT_TYPE: strcpy(str, "B_RECT_TYPE"); break;
case B_REF_TYPE: strcpy(str, "B_REF_TYPE"); break;
case B_RGB_32_BIT_TYPE: strcpy(str, "B_RGB_32_BIT_TYPE"); break;
case B_RGB_COLOR_TYPE: strcpy(str, "B_RGB_COLOR_TYPE"); break;
case B_SIZE_T_TYPE: strcpy(str, "B_SIZE_T_TYPE"); break;
case B_SSIZE_T_TYPE: strcpy(str, "B_SSIZE_T_TYPE"); break;
case B_STRING_TYPE: strcpy(str, "B_STRING_TYPE"); break;
case B_TIME_TYPE : strcpy(str, "B_TIME_TYPE"); break;
case B_UINT64_TYPE: strcpy(str, "B_UINT64_TYPE"); break;
case B_UINT32_TYPE: strcpy(str, "B_UINT32_TYPE"); break;
case B_UINT16_TYPE: strcpy(str, "B_UINT16_TYPE"); break;
case B_UINT8_TYPE: strcpy(str, "B_UINT8_TYPE"); break;
case B_PROPERTY_INFO_TYPE: strcpy(str, "B_PROPERTY_INFO_TYPE"); break;
case B_ABOUT_REQUESTED: strcpy(str, "B_ABOUT_REQUESTED"); break;
case B_WINDOW_ACTIVATED: strcpy(str, "B_WINDOW_ACTIVATED"); break;
case B_ARGV_RECEIVED: strcpy(str, "B_ARGV_RECEIVED"); break;
case B_QUIT_REQUESTED: strcpy(str, "B_QUIT_REQUESTED"); break;
case B_CANCEL: strcpy(str, "B_CANCEL"); break;
case B_KEY_DOWN: strcpy(str, "B_KEY_DOWN"); break;
case B_KEY_UP: strcpy(str, "B_KEY_UP"); break;
case B_MINIMIZE: strcpy(str, "B_MINIMIZE"); break;
case B_MOUSE_DOWN: strcpy(str, "B_MOUSE_DOWN"); break;
case B_MOUSE_MOVED: strcpy(str, "B_MOUSE_MOVED"); break;
case B_MOUSE_ENTER_EXIT: strcpy(str, "B_MOUSE_ENTER_EXIT"); break;
case B_MOUSE_UP: strcpy(str, "B_MOUSE_UP"); break;
case B_PULSE: strcpy(str, "B_PULSE"); break;
case B_READY_TO_RUN: strcpy(str, "B_READY_TO_RUN"); break;
case B_REFS_RECEIVED: strcpy(str, "B_REFS_RECEIVED"); break;
case B_SCREEN_CHANGED: strcpy(str, "B_SCREEN_CHANGED"); break;
case B_VALUE_CHANGED: strcpy(str, "B_VALUE_CHANGED"); break;
case B_VIEW_MOVED: strcpy(str, "B_VIEW_MOVED"); break;
case B_VIEW_RESIZED: strcpy(str, "B_VIEW_RESIZED"); break;
case B_WINDOW_MOVED: strcpy(str, "B_WINDOW_MOVED"); break;
case B_WINDOW_RESIZED: strcpy(str, "B_WINDOW_RESIZED"); break;
case B_WORKSPACES_CHANGED: strcpy(str, "B_WORKSPACES_CHANGED"); break;
case B_WORKSPACE_ACTIVATED: strcpy(str, "B_WORKSPACE_ACTIVATED"); break;
case B_ZOOM: strcpy(str, "B_ZOOM"); break;
case _APP_MENU_: strcpy(str, "_APP_MENU_"); break;
case _BROWSER_MENUS_: strcpy(str, "_BROWSER_MENUS_"); break;
case _MENU_EVENT_: strcpy(str, "_MENU_EVENT_"); break;
case _QUIT_: strcpy(str, "_QUIT_"); break;
case _VOLUME_MOUNTED_: strcpy(str, "_VOLUME_MOUNTED_"); break;
case _VOLUME_UNMOUNTED_: strcpy(str, "_VOLUME_UNMOUNTED_"); break;
case _MESSAGE_DROPPED_: strcpy(str, "_MESSAGE_DROPPED_"); break;
case _MENUS_DONE_: strcpy(str, "_MENUS_DONE_"); break;
case _SHOW_DRAG_HANDLES_: strcpy(str, "_SHOW_DRAG_HANDLES_"); break;
case B_SET_PROPERTY: strcpy(str, "B_SET_PROPERTY"); break;
case B_GET_PROPERTY: strcpy(str, "B_GET_PROPERTY"); break;
case B_CREATE_PROPERTY: strcpy(str, "B_CREATE_PROPERTY"); break;
case B_DELETE_PROPERTY: strcpy(str, "B_DELETE_PROPERTY"); break;
case B_COUNT_PROPERTIES: strcpy(str, "B_COUNT_PROPERTIES"); break;
case B_EXECUTE_PROPERTY: strcpy(str, "B_EXECUTE_PROPERTY"); break;
case B_GET_SUPPORTED_SUITES: strcpy(str, "B_GET_SUPPORTED_SUITES"); break;
case B_CUT: strcpy(str, "B_CUT"); break;
case B_COPY: strcpy(str, "B_COPY"); break;
case B_PASTE: strcpy(str, "B_PASTE"); break;
case B_SELECT_ALL: strcpy(str, "B_SELECT_ALL"); break;
case B_SAVE_REQUESTED: strcpy(str, "B_SAVE_REQUESTED"); break;
case B_MESSAGE_NOT_UNDERSTOOD: strcpy(str, "B_MESSAGE_NOT_UNDERSTOOD"); break;
case B_NO_REPLY: strcpy(str, "B_NO_REPLY"); break;
case B_REPLY: strcpy(str, "B_REPLY"); break;
case B_SIMPLE_DATA: strcpy(str, "B_SIMPLE_DATA"); break;
case B_ARCHIVED_OBJECT: strcpy(str, "B_ARCHIVED_OBJECT"); break;
case B_UPDATE_STATUS_BAR: strcpy(str, "B_UPDATE_STATUS_BAR"); break;
case B_RESET_STATUS_BAR: strcpy(str, "B_RESET_STATUS_BAR"); break;
case B_NODE_MONITOR: strcpy(str, "B_NODE_MONITOR"); break;
case B_QUERY_UPDATE: strcpy(str, "B_QUERY_UPDATE"); break;
case B_BAD_SCRIPT_SYNTAX: strcpy(str, "B_BAD_SCRIPT_SYNTAX"); break;
case B_NO_SPECIFIER: strcpy(str, "B_NO_SPECIFIER"); break;
case B_DIRECT_SPECIFIER: strcpy(str, "B_DIRECT_SPECIFIER"); break;
case B_INDEX_SPECIFIER: strcpy(str, "B_INDEX_SPECIFIER"); break;
case B_REVERSE_INDEX_SPECIFIER: strcpy(str, "B_REVERSE_INDEX_SPECIFIER"); break;
case B_RANGE_SPECIFIER: strcpy(str, "B_RANGE_SPECIFIER"); break;
case B_REVERSE_RANGE_SPECIFIER: strcpy(str, "B_REVERSE_RANGE_SPECIFIER"); break;
case B_NAME_SPECIFIER: strcpy(str, "B_NAME_SPECIFIER"); break;
case B_ERROR: strcpy(str, "B_ERROR"); break;
default:
id_to_string(type, str);
break;
}
return str;
}
char *
format_data(int32 type, char *ptr, long size)
{
char idtext[32];
char *str;
float *fptr;
double *dptr;
entry_ref aref;
BEntry entry;
BPath path;
int64 i64;
int32 i32;
int16 i16;
int8 i8;
uint64 ui64;
uint32 ui32;
uint16 ui16;
uint8 ui8;
BMessage anothermsg;
char *tempstr;
if (size <= 0L) {
str = new char[1];
*str = 0;
return str;
}
switch (type) {
case B_MIME_TYPE:
case B_ASCII_TYPE:
case B_STRING_TYPE:
if (size > 512)
size = 512;
str = new char[size + 4];
*str='\"';
strncpy(str + 1, ptr, size);
strcat(str, "\"");
break;
case B_POINTER_TYPE:
str = new char[64];
sprintf(str, "%p", *(void**)ptr);
break;
case B_REF_TYPE:
str = new char[1024];
anothermsg.AddData("myref", B_REF_TYPE, ptr, size);
anothermsg.FindRef("myref", &aref);
if (entry.SetTo(&aref)==B_OK){
entry.GetPath(&path);
strcpy(str, path.Path());
} else
strcpy(str, "invalid entry_ref");
break;
case B_SSIZE_T_TYPE:
case B_INT64_TYPE:
str = new char[64];
i64 = *(int64*)ptr;
sprintf(str, "%" B_PRId64 " (0x%" B_PRIx64 ")", i64, i64);
break;
case B_SIZE_T_TYPE:
case B_INT32_TYPE:
str = new char[64];
i32 = *(int32*)ptr;
sprintf(str, "%" B_PRId32 " (0x%08" B_PRId32 ")", i32, i32);
break;
case B_INT16_TYPE:
str = new char[64];
i16 = *(int16*)ptr;
sprintf(str, "%d (0x%04X)", i16, i16);
break;
case B_CHAR_TYPE:
case B_INT8_TYPE:
str = new char[64];
i8 = *(int8*)ptr;
sprintf(str, "%d (0x%02X)", i8, i8);
break;
case B_UINT64_TYPE:
str = new char[64];
ui64 = *(uint64*)ptr;
sprintf(str, "%" B_PRIu64 " (0x%" B_PRIx64 ")", ui64, ui64);
break;
case B_UINT32_TYPE:
str = new char[64];
ui32 = *(uint32*)ptr;
sprintf(str, "%" B_PRIu32 " (0x%08" B_PRIx32 ")", ui32, ui32);
break;
case B_UINT16_TYPE:
str = new char[64];
ui16 = *(uint16*)ptr;
sprintf(str, "%u (0x%04X)", ui16, ui16);
break;
case B_UINT8_TYPE:
str = new char[64];
ui8 = *(uint8*)ptr;
sprintf(str, "%u (0x%02X)", ui8, ui8);
break;
case B_BOOL_TYPE:
str = new char[10];
if (*ptr)
strcpy(str, "TRUE");
else
strcpy(str, "FALSE");
break;
case B_FLOAT_TYPE:
str = new char[40];
fptr = (float*)ptr;
sprintf(str, "%.3f", *fptr);
break;
case B_DOUBLE_TYPE:
str = new char[40];
dptr = (double*)ptr;
sprintf(str, "%.3f", *dptr);
break;
case B_RECT_TYPE:
str = new char[200];
fptr = (float*)ptr;
sprintf(str, "BRect(%.1f, %.1f, %.1f, %.1f)", fptr[0], fptr[1],
fptr[2], fptr[3]);
break;
case B_POINT_TYPE:
str = new char[200];
fptr = (float*)ptr;
sprintf(str, "BPoint(%.1f, %.1f)", fptr[0], fptr[1]);
break;
case B_RGB_COLOR_TYPE:
str = new char[64];
sprintf(str, "Red=%u Green=%u Blue=%u Alpha=%u",
((uint8*)ptr)[0], ((uint8*)ptr)[1], ((uint8*)ptr)[2],
((uint8*)ptr)[3]);
break;
case B_COLOR_8_BIT_TYPE:
str = new char[size * 6 + 4];
*str = 0;
for (int32 i = 0; i < min_c(256, size); i++) {
sprintf(idtext, "%u ", ((unsigned char*)ptr)[i]);
strcat(str,idtext);
}
*(str+strlen(str)-2) = 0;
break;
case B_MESSAGE_TYPE:
str = new char[64];
if (anothermsg.Unflatten((const char *)ptr) == B_OK) {
char *whatString = get_datatype_string(anothermsg.what);
sprintf(str, "what=%s", whatString);
delete[] whatString;
} else
strcpy(str, "error when unflattening");
break;
case B_PROPERTY_INFO_TYPE:
{
BPropertyInfo propinfo;
if (propinfo.Unflatten(B_PROPERTY_INFO_TYPE, (const void *)ptr,
size) == B_OK) {
str = new char[size * 32];
const property_info *pinfo = propinfo.Properties();
sprintf(str, "\n property commands "
"specifiers types\n-----------------------------------"
"----------------------------------------------------------------\n");
for (int32 pinfo_index = 0; pinfo_index < propinfo.CountProperties(); pinfo_index++) {
strcat(str, " "
+ (strlen(pinfo[pinfo_index].name) < 16 ?
strlen(pinfo[pinfo_index].name) : 16));
strcat(str, pinfo[pinfo_index].name);
strcat(str, " ");
char *start = str + strlen(str);
for (int32 i = 0; i < 10 && pinfo[pinfo_index].commands[i];
i++) {
tempstr = get_datatype_string(
pinfo[pinfo_index].commands[i]);
strcat(str, tempstr);
strcat(str, " ");
delete[] tempstr;
}
if (strlen(start) < 36) {
strcat(str, " "
+ strlen(start));
} else
strcat(str, " " );
for (int32 i = 0; i < 10 && pinfo[pinfo_index].specifiers[i]; i++) {
switch (pinfo[pinfo_index].specifiers[i]) {
case B_NO_SPECIFIER:
strcat(str, "NONE ");
break;
case B_DIRECT_SPECIFIER:
strcat(str, "DIRECT ");
break;
case B_INDEX_SPECIFIER:
strcat(str, "INDEX ");
break;
case B_REVERSE_INDEX_SPECIFIER:
strcat(str, "REV.INDEX ");
break;
case B_RANGE_SPECIFIER:
strcat(str, "RANGE ");
break;
case B_REVERSE_RANGE_SPECIFIER:
strcat(str, "REV.RANGE ");
break;
case B_NAME_SPECIFIER:
strcat(str, "NAME ");
break;
case B_ID_SPECIFIER:
strcat(str, "ID ");
break;
default:
strcat(str, "<NONE> ");
break;
}
}
if (strlen(start) < 60) {
strcat(str, " "
" " + strlen(start));
} else
strcat(str, " ");
for (int32 i = 0; i < 10
&& pinfo[pinfo_index].types[i] != 0; i++) {
uint32 type = pinfo[pinfo_index].types[i];
char str2[6];
snprintf(str2, sizeof(str2), "%c%c%c%c ",
int(type & 0xFF000000) >> 24,
int(type & 0xFF0000) >> 16,
int(type & 0xFF00) >> 8,
(int)type & 0xFF);
strcat(str, str2);
}
for (int32 i = 0; i < 3; i++) {
for (int32 j = 0; j < 5
&& pinfo[pinfo_index].ctypes[i].pairs[j].type
!= 0; j++) {
uint32 type = pinfo[pinfo_index].ctypes[i].pairs[j].type;
char str2[strlen(pinfo[pinfo_index].ctypes[i].pairs[j].name) + 8];
snprintf(str2, sizeof(str2),
"(%s %c%c%c%c)",
pinfo[pinfo_index].ctypes[i].pairs[j].name,
int(type & 0xFF000000) >> 24,
int(type & 0xFF0000) >> 16,
int(type & 0xFF00) >> 8,
(int)type & 0xFF);
strcat(str, str2);
}
}
strcat(str, "\n");
if (pinfo[pinfo_index].usage) {
strcat(str, " Usage: ");
strcat(str, pinfo[pinfo_index].usage);
strcat(str, "\n");
}
}
const value_info *vinfo = propinfo.Values();
int32 vinfo_count = propinfo.CountValues();
#if TEST_VALUEINFO>0
value_info vinfo[10] = {
{"Backup", 'back', B_COMMAND_KIND,
"This command backs up your hard drive."},
{"Abort", 'abor', B_COMMAND_KIND,
"Stops the current operation..."},
{"Type Code", 'type', B_TYPE_CODE_KIND,
"Type code info..."}
};
vinfo_count = 3;
#endif
if (vinfo && vinfo_count > 0) {
sprintf(str + strlen(str),
"\n name value "
" kind\n---------------------------------------------"
"-----------------------------------\n");
for (int32 vinfo_index = 0; vinfo_index < vinfo_count;
vinfo_index++) {
char *start = str + strlen(str);
strcat(str, " " + (strlen(vinfo[vinfo_index].name) < 16 ? strlen(vinfo[vinfo_index].name) : 16));
strcat(str, vinfo[vinfo_index].name);
strcat(str, " ");
sprintf(str + strlen(str), "0x%8" B_PRIx32 " (",
vinfo[vinfo_index].value);
id_to_string(vinfo[vinfo_index].value, str + strlen(str));
strcat(str, ")");
if (strlen(start) < 36 + 19) {
strcat(str, " "
" " + strlen(start));
} else
strcat(str, " ");
switch (vinfo[vinfo_index].kind) {
case B_COMMAND_KIND:
strcat(str, "COMMAND ");
break;
case B_TYPE_CODE_KIND:
strcat(str, "TYPE CODE ");
break;
default:
strcat(str, "unknown ");
break;
}
strcat(str, "\n");
if (vinfo[vinfo_index].usage) {
strcat(str, " Usage: ");
strcat(str, vinfo[vinfo_index].usage);
strcat(str, "\n");
}
}
}
} else {
str = new char[64];
strcpy(str, "error when unflattening");
}
break;
}
default:
str = new char[min_c(256, size) * 20 + 4];
*str = 0;
for (int32 i = 0; i < min_c(256, size); i++) {
sprintf(idtext, "0x%02X, ", (uint16)ptr[i]);
strcat(str, idtext);
}
*(str + strlen(str) - 2) = 0;
break;
}
return str;
}
char *
id_to_string(long ID, char *here)
{
uint8 digit0 = (ID>>24)& 255;
uint8 digit1 = (ID>>16)& 255;
uint8 digit2 = (ID>>8) & 255;
uint8 digit3 = (ID) & 255;
bool itsvalid = false;
if (digit0 == 0) {
if (digit1 == 0) {
if (digit2 == 0) {
itsvalid = is_valid_char(digit3);
sprintf(here, "'%c'", digit3);
} else {
itsvalid = is_valid_char(digit2) && is_valid_char(digit3);
sprintf(here, "'%c%c'", digit2, digit3);
}
} else {
itsvalid = is_valid_char(digit1) && is_valid_char(digit2)
&& is_valid_char(digit3);
sprintf(here, "'%c%c%c'", digit1, digit2, digit3);
}
} else {
itsvalid = is_valid_char(digit0) && is_valid_char(digit1)
&& is_valid_char(digit2) && is_valid_char(digit3);
sprintf(here, "'%c%c%c%c'", digit0, digit1, digit2, digit3);
}
if (!itsvalid)
sprintf(here, "%ldL", ID);
return here;
}
bool
is_valid_char(uint8 c)
{
return c >= 32 && c < 128;
}