#include "ParseCommandLine.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <Directory.h>
#include <Entry.h>
#include <FindDirectory.h>
#include <List.h>
#include <Path.h>
#include <Roster.h>
#include <String.h>
#include <SupportKit.h>
const char* kTrackerSignature = "application/x-vnd.Be-TRAK";
#define GUNK_CHAR 0x01
static void
GunkSpaces(char* string)
{
bool insideQuote = false;
bool afterBackslash = false;
while (*string != '\0') {
switch(*string) {
case '\"':
if (!afterBackslash) {
insideQuote = !insideQuote;
}
break;
case ' ':
case '\t':
if ((insideQuote)||(afterBackslash))
*string = GUNK_CHAR;
break;
}
afterBackslash = (*string == '\\') ? !afterBackslash : false;
string++;
}
}
static void
RemoveQuotes(char* string)
{
bool afterBackslash = false;
char* endString = strchr(string, '\0');
char* to = string;
while (*string != '\0') {
bool temp = (*string == '\\') ? !afterBackslash : false;
switch(*string) {
case '\"':
case '\\':
if (afterBackslash)
*(to++) = *string;
break;
case 'n':
*(to++) = afterBackslash ? '\n' : *string;
break;
case 't':
*(to++) = afterBackslash ? '\t' : *string;
break;
default:
*(to++) = *string;
}
afterBackslash = temp;
string++;
}
*to = '\0';
if (to < endString) {
*(to + 1) = '\0';
}
}
static bool
IsValidChar(char c)
{
return ((c > ' ')||(c == '\n')||(c == '\t'));
}
static bool
GetNextWord(char** setBegin, char** setEnd)
{
char* next = *setEnd;
while (next++) {
if (*next == '\0') {
return false;
}
else if ((IsValidChar(*next) == false) && (*next != GUNK_CHAR))
*next = '\0';
else {
break;
}
}
*setBegin = next;
while (next++) {
if ((IsValidChar(*next) == false) && (*next != GUNK_CHAR)) {
*next = '\0';
*setEnd = next;
return true;
}
}
return false;
}
static void
UnGunk(char* str)
{
char* temp = str;
while (*temp) {
if (*temp == GUNK_CHAR)
*temp = ' ';
temp++;
}
}
char**
ParseArgvFromString(const char* command, int32& argc)
{
int length = strlen(command);
char* cmd = new char[length + 2];
strcpy(cmd, command);
cmd[length + 1] = '\0';
GunkSpaces(cmd);
RemoveQuotes(cmd);
BList wordlist;
char* beginWord = NULL, *endWord = cmd - 1;
while (GetNextWord(&beginWord, &endWord))
wordlist.AddItem(beginWord);
argc = wordlist.CountItems();
char** argv = new char* [argc + 1];
for (int i = 0; i < argc; i++) {
char* temp = (char*) wordlist.ItemAt(i);
argv[i] = new char[strlen(temp) + 1];
strcpy(argv[i], temp);
UnGunk(argv[i]);
}
argv[argc] = NULL;
delete[] cmd;
return argv;
}
void
FreeArgv(char** argv)
{
if (argv != NULL) {
int i = 0;
while (argv[i] != NULL) {
delete[] argv[i];
i++;
}
}
delete[] argv;
}
char**
CloneArgv(char** argv)
{
int argc = 0;
while (argv[argc] != NULL)
argc++;
char** newArgv = new char* [argc + 1];
for (int i = 0; i < argc; i++) {
newArgv[i] = new char[strlen(argv[i]) + 1];
strcpy(newArgv[i], argv[i]);
}
newArgv[argc] = NULL;
return newArgv;
}
BString
ParseArgvZeroFromString(const char* command)
{
char* array = NULL;
int length = strlen(command);
char* cmd = new char[length + 2];
strcpy(cmd, command);
cmd[length + 1] = '\0';
GunkSpaces(cmd);
RemoveQuotes(cmd);
char* beginWord = NULL, *endWord = cmd - 1;
if (GetNextWord(&beginWord, &endWord)) {
array = new char[strlen(beginWord) + 1];
strcpy(array, beginWord);
UnGunk(array);
}
delete[] cmd;
BString string(array != NULL ? array : "");
delete[] array;
return string;
}
bool
DoStandardEscapes(BString& string)
{
bool escape = false;
escape |= EscapeChars(string, '\\');
escape |= EscapeChars(string, '\"');
escape |= EscapeChars(string, ' ');
escape |= EscapeChars(string, '\t');
return escape;
}
bool
EscapeChars(BString& string, char badChar)
{
if (string.FindFirst(badChar) == -1)
return false;
BString temp;
int stringLen = string.Length();
for (int i = 0; i < stringLen; i++) {
char next = string[i];
if (next == badChar)
temp += '\\';
temp += next;
}
string = temp;
return true;
}
status_t
LaunchCommand(char** argv, int32 argc)
{
BEntry entry(argv[0], true);
if (entry.Exists()) {
BDirectory testDir(&entry);
if (testDir.InitCheck() == B_OK) {
entry_ref ref;
status_t status = entry.GetRef(&ref);
if (status < B_OK)
return status;
BMessenger target(kTrackerSignature);
BMessage message(B_REFS_RECEIVED);
message.AddRef("refs", &ref);
return target.SendMessage(&message);
} else {
entry_ref ref;
if (entry.GetRef(&ref) == B_OK) {
if (argc > 1)
be_roster->Launch(&ref, argc - 1, &argv[1]);
else
be_roster->Launch(&ref);
return B_OK;
}
}
}
return B_ERROR;
}