SCI: Message: Added a few more subfunctions; cleanup.

svn-id: r40529
This commit is contained in:
Walter van Niftrik 2009-05-13 19:03:12 +00:00
parent f0182121f7
commit e35b77e0a7
3 changed files with 194 additions and 130 deletions

View file

@ -722,107 +722,143 @@ reg_t kGetFarText(EngineState *s, int funct_nr, int argc, reg_t *argv) {
return argv[2]; return argv[2];
} }
#define DUMMY_MESSAGE "No MESSAGE support in SCI yet" #define DUMMY_MESSAGE "Message not found!"
static MessageState state; static MessageState state;
enum kMessageFunc {
K_MESSAGE_GET,
K_MESSAGE_NEXT,
K_MESSAGE_SIZE,
K_MESSAGE_REFCOND,
K_MESSAGE_REFVERB,
K_MESSAGE_REFNOUN,
K_MESSAGE_PUSH,
K_MESSAGE_POP,
K_MESSAGE_LASTMESSAGE
};
reg_t kMessage(EngineState *s, int funct_nr, int argc, reg_t *argv) { reg_t kMessage(EngineState *s, int funct_nr, int argc, reg_t *argv) {
MessageTuple tuple; MessageTuple tuple;
int func;
// For earlier version of of this function (GetMessage)
bool isGetMessage = argc == 4;
if (isGetMessage) {
func = K_MESSAGE_GET;
if (argc == 4) {
// Earlier version of of this function (GetMessage)
tuple.noun = UKPV(0); tuple.noun = UKPV(0);
int module = UKPV(1);
tuple.verb = UKPV(2); tuple.verb = UKPV(2);
tuple.cond = 0; tuple.cond = 0;
tuple.seq = 1; tuple.seq = 1;
} else {
func = UKPV(0);
if (state.loadRes(s->resmgr, module, true) && state.getMessage(&tuple)) { if (argc >= 6) {
int len = state.getLength();
char *buffer = kernel_dereference_char_pointer(s, argv[3], len + 1);
if (buffer) {
state.getText(buffer);
return argv[3];
}
}
return NULL_REG;
}
switch (UKPV(0)) {
case 0:
case 2:
case 3:
case 4:
case 5:
tuple.noun = UKPV(2); tuple.noun = UKPV(2);
tuple.verb = UKPV(3); tuple.verb = UKPV(3);
tuple.cond = UKPV(4); tuple.cond = UKPV(4);
tuple.seq = UKPV(5); tuple.seq = UKPV(5);
} }
switch (UKPV(0)) {
case 0 :
if (state.loadRes(s->resmgr, UKPV(1), true) && state.getMessage(&tuple)) {
char *buffer = NULL;
if ((argc == 7) && (argv[6] != NULL_REG))
buffer = kernel_dereference_char_pointer(s, argv[6], state.getLength() + 1);
int talker = state.getTalker();
if (buffer)
state.getText(buffer);
// Talker id
return make_reg(0, talker);
} else {
char *buffer = NULL;
if ((argc == 7) && (argv[6] != NULL_REG))
buffer = kernel_dereference_char_pointer(s, argv[6], strlen(DUMMY_MESSAGE) + 1);
if (buffer)
strcpy(buffer, DUMMY_MESSAGE);
return NULL_REG;
} }
case 1 :
if (state.getNext()) { switch (func) {
case K_MESSAGE_GET:
case K_MESSAGE_NEXT: {
reg_t bufferReg;
char *buffer = NULL; char *buffer = NULL;
const char *str;
reg_t retval;
if ((argc == 2) && (argv[1] != NULL_REG)) if (func == K_MESSAGE_GET) {
buffer = kernel_dereference_char_pointer(s, argv[1], state.getLength() + 1); state.loadRes(s->resmgr, UKPV(1), true);
state.findTuple(tuple);
int talker = state.getTalker(); if (isGetMessage)
bufferReg = (argc == 4 ? argv[3] : NULL_REG);
if (buffer) else
state.getText(buffer); bufferReg = (argc == 7 ? argv[6] : NULL_REG);
// Talker id
return make_reg(0, talker);
} else { } else {
char *buffer = NULL; bufferReg = (argc == 2 ? argv[1] : NULL_REG);
if ((argc == 2) && (argv[1] != NULL_REG))
buffer = kernel_dereference_char_pointer(s, argv[1], strlen(DUMMY_MESSAGE) + 1);
if (buffer)
strcpy(buffer, DUMMY_MESSAGE);
return NULL_REG;
} }
case 2: {
if (state.getMessage()) {
str = state.getText();
if (isGetMessage)
retval = bufferReg;
else
retval = make_reg(0, state.getTalker());
} else {
str = DUMMY_MESSAGE;
retval = NULL_REG;
}
if (!bufferReg.isNull()) {
int len = strlen(str) + 1;
buffer = kernel_dereference_char_pointer(s, bufferReg, len);
if (buffer) {
strcpy(buffer, str);
} else {
warning("Message: buffer "PREG" invalid or too small to hold the following text of %i bytes: '%s'", PRINT_REG(bufferReg), len, str);
// Set buffer to empty string if possible
buffer = kernel_dereference_char_pointer(s, bufferReg, 1);
if (buffer)
*buffer = 0;
}
state.gotoNext();
}
return retval;
}
case K_MESSAGE_SIZE: {
MessageState tempState; MessageState tempState;
if (tempState.loadRes(s->resmgr, UKPV(1), false) && tempState.getMessage(&tuple)) if (tempState.loadRes(s->resmgr, UKPV(1), false) && tempState.findTuple(tuple) && tempState.getMessage())
return make_reg(0, tempState.getLength() + 1); return make_reg(0, strlen(tempState.getText()));
else else
return NULL_REG; return NULL_REG;
} }
case K_MESSAGE_REFCOND:
case K_MESSAGE_REFVERB:
case K_MESSAGE_REFNOUN: {
MessageState tempState;
if (tempState.loadRes(s->resmgr, UKPV(1), false) && tempState.findTuple(tuple)) {
MessageTuple t = tempState.getRefTuple();
switch (func) {
case K_MESSAGE_REFCOND:
return make_reg(0, t.cond);
case K_MESSAGE_REFVERB:
return make_reg(0, t.verb);
case K_MESSAGE_REFNOUN:
return make_reg(0, t.noun);
}
}
return NULL_REG;
}
case K_MESSAGE_LASTMESSAGE: {
MessageTuple msg = state.getLastTuple();
int module = state.getLastModule();
byte *buffer = kernel_dereference_bulk_pointer(s, argv[1], 10);
if (buffer) {
WRITE_LE_UINT16(buffer, module);
WRITE_LE_UINT16(buffer + 2, msg.noun);
WRITE_LE_UINT16(buffer + 4, msg.verb);
WRITE_LE_UINT16(buffer + 6, msg.cond);
WRITE_LE_UINT16(buffer + 8, msg.seq);
} else {
warning("Message: buffer "PREG" invalid or too small to hold the tuple", PRINT_REG(argv[1]));
}
return NULL_REG;
}
default: default:
warning("kMessage subfunction %i invoked (not implemented)", UKPV(0)); warning("Message: subfunction %i invoked (not implemented)", func);
} }
return NULL_REG; return NULL_REG;

View file

@ -28,29 +28,37 @@
namespace Sci { namespace Sci {
void MessageState::parse(IndexRecordCursor *cursor, MessageTuple *t) { MessageTuple MessageState::getTuple() {
t->noun = *(cursor->index_record + 0); MessageTuple t;
t->verb = *(cursor->index_record + 1);
t.noun = *(_engineCursor.index_record + 0);
t.verb = *(_engineCursor.index_record + 1);
if (_version == 2101) { if (_version == 2101) {
t->cond = 0; t.cond = 0;
t->seq = 1; t.seq = 1;
} else { } else {
t->cond = *(cursor->index_record + 2); t.cond = *(_engineCursor.index_record + 2);
t->seq = *(cursor->index_record + 3); t.seq = *(_engineCursor.index_record + 3);
}
} }
void MessageState::parseRef(IndexRecordCursor *cursor, MessageTuple *t) { return t;
if (_version == 2101) {
t->noun = 0;
t->verb = 0;
t->cond = 0;
} else {
t->noun = *(cursor->index_record + 7);
t->verb = *(cursor->index_record + 8);
t->cond = *(cursor->index_record + 9);
} }
t->seq = 1;
MessageTuple MessageState::getRefTuple() {
MessageTuple t;
if (_version == 2101) {
t.noun = 0;
t.verb = 0;
t.cond = 0;
} else {
t.noun = *(_engineCursor.index_record + 7);
t.verb = *(_engineCursor.index_record + 8);
t.cond = *(_engineCursor.index_record + 9);
}
t.seq = 1;
return t;
} }
void MessageState::initCursor() { void MessageState::initCursor() {
@ -67,20 +75,22 @@ void MessageState::advanceCursor(bool increaseSeq) {
_engineCursor.nextSeq++; _engineCursor.nextSeq++;
} }
int MessageState::getMessage(MessageTuple *t) { int MessageState::findTuple(MessageTuple &t) {
if (_module == -1)
return 0;
// Reset the cursor // Reset the cursor
initCursor(); initCursor();
_engineCursor.nextSeq = t->seq; _engineCursor.nextSeq = t.seq;
// Do a linear search for the message // Do a linear search for the message
while (1) { while (1) {
MessageTuple looking_at; MessageTuple looking_at = getTuple();
parse(&_engineCursor, &looking_at);
if (t->noun == looking_at.noun && if (t.noun == looking_at.noun &&
t->verb == looking_at.verb && t.verb == looking_at.verb &&
t->cond == looking_at.cond && t.cond == looking_at.cond &&
t->seq == looking_at.seq) t.seq == looking_at.seq)
break; break;
advanceCursor(false); advanceCursor(false);
@ -90,15 +100,16 @@ int MessageState::getMessage(MessageTuple *t) {
return 0; return 0;
} }
return getNext(); return 1;
} }
int MessageState::getNext() { int MessageState::getMessage() {
if (_module == -1)
return 0;
if (_engineCursor.index != _recordCount) { if (_engineCursor.index != _recordCount) {
MessageTuple mesg; MessageTuple mesg = getTuple();
parse(&_engineCursor, &mesg); MessageTuple ref = getRefTuple();
MessageTuple ref;
parseRef(&_engineCursor, &ref);
if (_engineCursor.nextSeq == mesg.seq) { if (_engineCursor.nextSeq == mesg.seq) {
// We found the right sequence number, check for recursion // We found the right sequence number, check for recursion
@ -107,8 +118,8 @@ int MessageState::getNext() {
// Recursion, advance the current cursor and load the reference // Recursion, advance the current cursor and load the reference
advanceCursor(true); advanceCursor(true);
if (getMessage(&ref)) if (findTuple(ref))
return getNext(); return getMessage();
else { else {
// Reference not found // Reference not found
return 0; return 0;
@ -123,7 +134,7 @@ int MessageState::getNext() {
// We either ran out of records, or found an incorrect sequence number. Go to previous stack frame. // We either ran out of records, or found an incorrect sequence number. Go to previous stack frame.
if (!_cursorStack.empty()) { if (!_cursorStack.empty()) {
_engineCursor = _cursorStack.pop(); _engineCursor = _cursorStack.pop();
return getNext(); return getMessage();
} }
// Stack is empty, no message available // Stack is empty, no message available
@ -134,10 +145,22 @@ int MessageState::getTalker() {
return (_version == 2101) ? -1 : *(_engineCursor.index_record + 4); return (_version == 2101) ? -1 : *(_engineCursor.index_record + 4);
} }
void MessageState::getText(char *buffer) { MessageTuple &MessageState::getLastTuple() {
return _lastReturned;
}
int MessageState::getLastModule() {
return _lastReturnedModule;
}
char *MessageState::getText() {
int offset = READ_LE_UINT16(_engineCursor.index_record + ((_version == 2101) ? 2 : 5)); int offset = READ_LE_UINT16(_engineCursor.index_record + ((_version == 2101) ? 2 : 5));
char *stringptr = (char *)_currentResource->data + offset; return (char *)_currentResource->data + offset;
strcpy(buffer, stringptr); }
void MessageState::gotoNext() {
_lastReturned = getTuple();
_lastReturnedModule = _module;
advanceCursor(true); advanceCursor(true);
} }
@ -148,24 +171,27 @@ int MessageState::getLength() {
} }
int MessageState::loadRes(ResourceManager *resmgr, int module, bool lock) { int MessageState::loadRes(ResourceManager *resmgr, int module, bool lock) {
if (_module == module) if (_locked) {
// We already have a locked resource
if (_module == module) {
// If it's the same resource, we are done
return 1; return 1;
}
// Unlock old resource // Otherwise, free the old resource
if (_module != -1) {
resmgr->unlockResource(_currentResource, _module, kResourceTypeMessage); resmgr->unlockResource(_currentResource, _module, kResourceTypeMessage);
_module = -1; _locked = false;
} }
_currentResource = resmgr->findResource(kResourceTypeMessage, module, lock); _currentResource = resmgr->findResource(kResourceTypeMessage, module, lock);
if (_currentResource == NULL || _currentResource->data == NULL) { if (_currentResource == NULL || _currentResource->data == NULL) {
warning("Message subsystem: failed to load %d.msg", module); warning("Message: failed to load %d.msg", module);
return 0; return 0;
} }
if (lock)
_module = module; _module = module;
_locked = lock;
_version = READ_LE_UINT16(_currentResource->data); _version = READ_LE_UINT16(_currentResource->data);

View file

@ -48,30 +48,32 @@ typedef Common::Stack<IndexRecordCursor> CursorStack;
class MessageState { class MessageState {
public: public:
MessageState() : _module(-1) { } MessageState() : _module(-1), _locked(false) { }
int getMessage(MessageTuple *t); int findTuple(MessageTuple &t);
int getNext(); MessageTuple getTuple();
MessageTuple getRefTuple();
int getMessage();
void gotoNext();
char *getText();
int getTalker(); int getTalker();
int getLength(); int getLength();
void getText(char *buffer); MessageTuple &getLastTuple();
int getLastModule();
int loadRes(ResourceManager *resmgr, int module, bool lock); int loadRes(ResourceManager *resmgr, int module, bool lock);
int isInitialized() { return _initialized; }
void initialize(ResourceManager *resmgr);
void setVersion(int version) { _version = version; }
private: private:
void parse(IndexRecordCursor *cursor, MessageTuple *t);
void parseRef(IndexRecordCursor *cursor, MessageTuple *t);
void initCursor(); void initCursor();
void advanceCursor(bool increaseSeq); void advanceCursor(bool increaseSeq);
int _initialized;
Resource *_currentResource; Resource *_currentResource;
int _module; int _module;
bool _locked;
int _recordCount; int _recordCount;
byte *_indexRecords; byte *_indexRecords;
CursorStack _cursorStack; CursorStack _cursorStack;
IndexRecordCursor _engineCursor; IndexRecordCursor _engineCursor;
MessageTuple _lastReturned;
int _lastReturnedModule;
int _version; int _version;
}; };