This is MessageApp.m in view mode; [Download] [Up]
/* File: MessageApp.m - NextStep Interface to Speaker/Mach messages
*
* By: Christopher Lane
* Symbolic Systems Resources Group
* Knowledge Systems Laboratory
* Stanford University
*
* Date: 11 April 1994
*
* Copyright: 1991, 1993 & 1994 by The Leland Stanford Junior University.
* This program may be distributed without restriction for non-commercial use.
*/
#import "MessageApp.h"
#import "DefaultsTable.h"
#import <c.h>
#import <ctype.h>
#import <sys/dir.h>
#import <netinfo/ni.h>
#import <objc/NXStringTable.h>
#define HELPFILE "Help"
#define PORTSFILE "Ports"
#define MESSAGESFILE "Messages"
#define DEFAULTSFILE "Defaults"
#define TRANSLATIONSFILE "Translations"
#define NETINFODOMAIN "NetInfoDomain"
#define APPLICATIONPATHS "ApplicationPaths"
#define HOSTPATH "HostPath"
#define STATUSKEY "status"
#define NAME (ni_name) "name"
#define PUBLICPORT "public"
#define LOCALHOST "localhost"
#define VERSION __DATE__
#define BUFFERSIZE (MAX(MSG_SIZE_MAX, FILENAME_MAX))
#define EMPTY ""
#define APPSUFFIX ".app"
#define PATHSEPARATOR "/"
#define ARGUMENTSEPARATOR ':'
#define DIRECTORYSEPARATOR ":"
#define STATUSFORMAT "%d (%s)"
#define DESCRIPTIONFORMAT "%s:"
#define streq(s, t) (strcmp(s, t) == 0)
struct argument { void *array[NX_MAXMSGPARAMS]; };
union overlay { struct { void *l, *r; } v; double d; };
typedef enum { DESCRIPTION = 0, TYPE, ARGUMENT } ParamObjects;
int compare(const void *a, const void *b) { return(strcmp(*((char **) a), *((char **) b))); }
@implementation MessageApp
- appDidInit:sender
{
NXStream *stream;
char pathnamebuf[MAXPATHLEN];
bundle = [NXBundle bundleForClass:[self class]];
if ([bundle getPath:pathnamebuf forResource:DEFAULTSFILE ofType:"strings"])
[[[DefaultsTable alloc] initFromFile:pathnamebuf] registerDefaults:[self appName]];
fileTable = [[HashTable alloc] initKeyDesc:@encode(char *)];
if ([bundle getPath:pathnamebuf forResource:TRANSLATIONSFILE ofType:"strings"])
[stringTable readFromFile:pathnamebuf];
[self loadPopUpList:[hostList target] fromNetInfo:getDefault(HOSTPATH)];
[hostList setTitle:LOCALHOST];
[hostField setStringValue:LOCALHOST];
[self loadPopUpList:[applicationList target] fromDirectory:getDefault(APPLICATIONPATHS)];
[applicationList setTitle:NX_WORKSPACEREQUEST];
[applicationField setStringValue:NX_WORKSPACEREQUEST];
if ([bundle getPath:pathnamebuf forResource:PORTSFILE ofType:"strings"]) {
[portTable readFromFile:pathnamebuf];
[self loadPopUpList:[portList target] fromHashTable:portTable];
}
[portList setTitle:PUBLICPORT];
[portField setStringValue:PUBLICPORT];
if ([bundle getPath:pathnamebuf forResource:MESSAGESFILE ofType:"strings"]) {
[messageTable readFromFile:pathnamebuf];
[self loadPopUpList:[messageList target] fromHashTable:messageTable];
}
if ([bundle getPath:pathnamebuf forResource:HELPFILE ofType:"rtf"]) {
if((stream = NXMapFile(pathnamebuf, NX_READONLY)) != NULL) {
[helpScrollView readRichText:stream];
NXCloseMemory(stream, NX_FREEBUFFER);
}
}
[self setMessageFromField:messageField];
[messageWindow makeKeyAndOrderFront:self];
return self;
}
- windowWillClose:sender { return [self terminate:sender]; }
- sendMessage:sender
{
int status;
port_t port;
char buffer[BUFFERSIZE];
struct argument arguments;
id speaker = [self appSpeaker];
const char *s, *host, *application, *portname, *message, *paramTypes;
[statusField setStringValue:EMPTY]; NXPing();
if(streq(host = [hostField stringValue], LOCALHOST)) host = NULL;
application = [applicationField stringValue];
if(streq(portname = [portField stringValue], PUBLICPORT)) port = NXPortFromName(application, host);
else if((s = [portTable valueForStringKey:portname]) != NULL) port = (port_t) atoi((char *) s);
else port = (port_t) [portField intValue];
[speaker setSendPort:port];
paramTypes = [self loadArguments:arguments.array];
message = [messageField stringValue];
if((s = [self getParamTypes:message]) == NULL || !streq(paramTypes, (char *) s))
[self setParamTypes:paramTypes forMessage:message];
status = [speaker selectorRPC:message paramTypes:(char *) paramTypes, arguments];
if(streq(portname, PUBLICPORT)) (void) port_deallocate(task_self(), port);
if((s = [self lookupConstant:status forKey:STATUSKEY]) != NULL) {
(void) sprintf(buffer, STATUSFORMAT, status, (char *) s);
[statusField setStringValue:buffer];
}
else [statusField setIntValue:status];
[self unloadArguments:arguments.array andUpdate:(BOOL) (status == SEND_SUCCESS)];
return self;
}
- (const char *) loadArguments:(void **) array
{
char c, *p;
unsigned int i, j;
union overlay datum;
const char *s, *portname;
static char buffer[NX_MAXMSGPARAMS + 1];
p = buffer;
for(i = 0, j = 0; i < argumentCount && j < NX_MAXMSGPARAMS; i++, j++) {
if((c = *[params[i].type title]) == '\0') break;
switch(c) {
case 'b' : array[j] = (void *) [params[i].argument stringValue];
array[j + 1] = (void *) strlen((char *) array[j]);
j++;
break;
case 'B' : array[j] = (char **) malloc(sizeof(char *));
array[j + 1] = malloc(sizeof(int));
j++;
break;
case 'c' : array[j] = (void *) [params[i].argument stringValue]; break;
case 'C' : array[j] = (char **) malloc(sizeof(char *)); break;
case 'd' : datum.d = [params[i].argument doubleValue];
array[j++] = datum.v.l;
array[j] = datum.v.r;
break;
case 'D' : array[j] = malloc(sizeof(double)); break;
case 'i' : array[j] = (void *) [params[i].argument intValue]; break;
case 'I' : array[j] = malloc(sizeof(int)); break;
case 'r' :
case 's' : if(streq((portname = [params[i].argument stringValue]), PUBLICPORT))
array[j] = (void *) ((c == 'r') ? [[self appSpeaker] sendPort] : [[self appListener] listenPort]);
else if((s = [portTable valueForStringKey:portname]) != NULL) array[j] = (void *) atoi((char *) s);
else array[j] = (void *) [params[i].argument intValue];
break;
case 'R' : case 'S' : array[j] = malloc(sizeof(port_t)); break;
default : break;
}
*p++ = c;
if(isupper(c)) [params[i].argument setStringValue:EMPTY];
}
*p = '\0';
return(buffer);
}
- unloadArguments:(void **) array andUpdate:(BOOL) flag
{
int value;
const char *s;
unsigned int i, j;
char c, buffer[BUFFERSIZE];
for(i = 0, j = 0; i < argumentCount && j < NX_MAXMSGPARAMS; i++, j++) {
if((c = *[params[i].type title]) == '\0') break;
if(flag)
switch(c) {
case 'B' : (void) strncpy(buffer, *((char **) array[j]), *((int *) array[j + 1]));
buffer[*((int *) array[j + 1])] = '\0';
[params[i].argument setStringValue:buffer];
break;
case 'C' : [params[i].argument setStringValue:*((char **) array[j])]; break;
case 'D' : [params[i].argument setDoubleValue:*((double *) array[j])]; break;
case 'I' : [params[i].argument setIntValue:(value = *((int *) array[j]))];
if((s = [self lookupConstant:value forKey:[params[i].description stringValue]]) != NULL) {
(void) sprintf(buffer, STATUSFORMAT, value, s);
[params[i].argument setStringValue:buffer];
}
break;
case 'R' : case 'S' : [params[i].argument setIntValue:*((int *) array[j])]; break;
default : break;
}
switch(c) {
case 'B' : free(array[j]);
case 'b' : case 'd' : j++;
default : if(isupper(c)) free(array[j]); break;
}
}
return self;
}
- setHostField:object { hostField = object; return self; }
- setHostList:object
{
[[[(hostList = object) target] setTarget:self] setAction:@selector(setHostfromMatrix:)];
return self;
}
- setApplicationField:object { applicationField = object; return self; }
- setApplicationList:object
{
[[[(applicationList = object) target] setTarget:self] setAction:@selector(setApplicationfromMatrix:)];
return self;
}
- setPortField:object { portField = object; return self; }
- setPortList:object
{
[[[(portList = object) target] setTarget:self] setAction:@selector(setPortfromMatrix:)];
return self;
}
- setMessageField:object { messageField = object; return self; }
- setMessageList:object
{
[[[(messageList = object) target] setTarget:self] setAction:@selector(setMessagefromMatrix:)];
return self;
}
- loadPopUpList:popUpList fromNetInfo:(const char *) directory
{
ni_id dir;
int i, j = 0;
void *handle;
ni_status status;
ni_namelist *namelist;
ni_entrylist entrylist;
id table = [[HashTable alloc] initKeyDesc:@encode(char *)];
if((status = ni_open(NULL, (ni_name) getDefault(NETINFODOMAIN), &handle)) == NI_OK) {
if((status = ni_pathsearch(handle, &dir, (ni_name) directory)) == NI_OK)
if((status = ni_list(handle, &dir, NAME, &entrylist)) == NI_OK) {
for(i = 0; i < entrylist.ni_entrylist_len; i++)
if((namelist = entrylist.ni_entrylist_val[i].names) != NULL)
// for(j = 0; j < namelist->ni_namelist_len; j++) /* Uncomment line to get aliases */
[table insertKey:(void *) NXCopyStringBuffer(namelist->ni_namelist_val[j]) value:nil];
ni_entrylist_free(&entrylist);
}
ni_free(handle);
}
[self loadPopUpList:popUpList fromHashTable:table];
[[table freeObjects] free];
return self;
}
- loadPopUpList:popUpList fromDirectory:(const char *) directoryList
{
int n;
DIR *dirp;
struct direct *dp;
char *s, *t, *scratch;
id table = [[HashTable alloc] initKeyDesc:@encode(char *)];
s = strtok((scratch = NXCopyStringBuffer(directoryList)), DIRECTORYSEPARATOR);
while(s != NULL) {
if((dirp = opendir(s)) != NULL) {
for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
n = strlen(dp->d_name) - strlen(APPSUFFIX);
if(n > 0 && streq((dp->d_name + n), APPSUFFIX)) {
*((t = NXCopyStringBuffer(dp->d_name)) + n) = '\0';
[table insertKey:(const void *) t value:nil];
}
}
(void) closedir(dirp);
}
s = strtok(NULL, DIRECTORYSEPARATOR);
}
NX_FREE(scratch);
[self loadPopUpList:popUpList fromHashTable:table];
[[table freeObjects] free];
return self;
}
- loadPopUpList:popUpList fromHashTable:hashTable
{
const void *key, *value, **base;
NXHashState state = [hashTable initState];
unsigned int i, count = [hashTable count];
base = calloc((size_t) count, sizeof(const void *));
for(i = 0; [hashTable nextState:&state key:&key value:&value]; i++) base[i] = (const void *) key;
(void) qsort(base, (size_t) count, sizeof(const void *), compare);
for(i = 0; i < count; i++) [popUpList addItem:(const char *) base[i]];
free(base);
return self;
}
- setStatusField:object { statusField = object; return self; }
- setArgumentsBox:object
{
unsigned int i, j, count;
id sublist, list = [[(argumentsBox = object) contentView] subviews];
argumentCount = [list count];
for(i = 0; i < argumentCount; i++) {
count = [(sublist = [[[list objectAt:i] contentView] subviews]) count];
for(j = 0; j < count; j++) {
switch([[sublist objectAt:j] tag]) {
case DESCRIPTION : params[i].description = [sublist objectAt:j]; break;
case TYPE : params[i].type = [sublist objectAt:j];
[[[params[i].type target] setTarget:self] setAction:@selector(setTypeFromMatrix:)];
break;
case ARGUMENT : params[i].argument = [sublist objectAt:j]; break;
default : break;
}
}
}
return self;
}
- setTypeFromMatrix:sender
{
char c;
BOOL isInput;
const char *s;
unsigned int i;
for(i = 0; i < argumentCount; i++) {
if((s = [[params[i].type target] selectedItem]) == NULL || (c = *s) == '\0') continue;
if(!(isInput = (BOOL) islower(c))) [params[i].argument setStringValue:EMPTY];
[[[params[i].argument setSelectable:YES] setEditable:isInput] setBackgroundGray:(isInput) ? NX_WHITE : NX_LTGRAY];
}
return self;
}
- (const char *) getParamTypes:(const char *) name
{
if([messageTable isKey:(const void *) name]) return([messageTable valueForKey:(const void *) name]);
return(NULL);
}
- setParamTypes:(const char *) value forMessage:(const char *) name
{
if([messageTable isKey:(const void *) name])
free([messageTable insertKey:(const void *) name value:(void *) NXCopyStringBuffer(value)]);
else [messageTable insertKey:(const void *) NXCopyStringBuffer(name) value:(void *) NXCopyStringBuffer(value)];
return self;
}
- setButton:button fromField:field
{
id target = [button target];
const char *title = [field stringValue];
[button setTitle:title];
if([target indexOfItem:title] == -1) [target insertItem:title at:0];
return self;
}
- setField:field fromMatrix:matrix
{
[field setStringValue:[[matrix selectedCell] title]];
return self;
}
- setHostFromField:sender { return [self setButton:hostList fromField:sender]; }
- setHostfromMatrix:sender { return [self setField:hostField fromMatrix:sender]; }
- setApplicationFromField:sender { return [self setButton:applicationList fromField:sender]; }
- setApplicationfromMatrix:sender { return [self setField:applicationField fromMatrix:sender]; }
- setPortFromField:sender { return [self setButton:portList fromField:sender]; }
- setPortfromMatrix:sender { return [self setField:portField fromMatrix:sender]; }
- setMessageFromField:sender
{
[self setButton:messageList fromField:sender];
return [self setMessage:[sender stringValue]];
}
- setMessagefromMatrix:sender
{
[self setField:messageField fromMatrix:sender];
return [self setMessage:[[sender selectedCell] title]];
}
- setMessage:(const char *) string
{
BOOL isInput;
unsigned int i, segmentCount = 0;
const char *paramTypes = [self getParamTypes:string];
char *r, *s, *segments[NX_MAXMSGPARAMS], buffer[BUFFERSIZE], *scratch;
[statusField setStringValue:EMPTY];
r = scratch = NXCopyStringBuffer(string);
while((s = index(r, ARGUMENTSEPARATOR)) != NULL) { /* Can't use strtok() due to '::' case! */
segments[segmentCount++] = r;
*s++ = '\0';
r = s;
}
for(i = 0; i < argumentCount; i++) {
if(i < segmentCount) {
(void) sprintf(buffer, DESCRIPTIONFORMAT, segments[i]);
[params[i].description setStringValue:buffer];
if(paramTypes != NULL) {
[params[i].type setEnabled:NO];
if(!(isInput = islower(paramTypes[i])) || paramTypes[i] != *[params[i].type title])
[params[i].argument setStringValue:EMPTY];
[[[params[i].argument setSelectable:YES] setEditable:isInput] setBackgroundGray:(isInput) ? NX_WHITE : NX_LTGRAY];
[params[i].type setTitle:[[[params[i].type target] findCellWithTag:(int) paramTypes[i]] title]];
}
else {
[[params[i].type setTitle:[[[params[i].type target] findCellWithTag:0] title]] setEnabled:YES];
[[[params[i].argument setEditable:YES] setBackgroundGray:NX_WHITE] setStringValue:EMPTY];
}
}
else {
[params[i].description setStringValue:EMPTY];
[[params[i].type setTitle:[[[params[i].type target] findCellWithTag:0] title]] setEnabled:NO];
[[[[params[i].argument setSelectable:NO] setEditable:NO] setBackgroundGray:NX_LTGRAY] setStringValue:EMPTY];
}
}
NX_FREE(scratch);
return self;
}
- (const char *) lookupConstant:(int) value forKey:(const char *) key
{
id table;
const char *file;
char buffer[BUFFERSIZE];
if((file = [stringTable valueForStringKey:key]) != NULL) {
if([fileTable isKey:(const void *) file]) table = (id) [fileTable valueForKey:(const void *) file];
else {
[fileTable insertKey:(const void *) file value:(void *) (table = [[NXStringTable alloc] init])];
if ([bundle getPath:buffer forResource:file ofType:"strings"]) [table readFromFile:buffer];
}
(void) sprintf(buffer, "%d", value);
return([table valueForStringKey:(const char *) buffer]);
}
return(NULL);
}
- setVersion:object { [(version = object) setStringValue:VERSION]; return self; }
- (int) msgVersion:(const char **) aString ok:(int *) flag
{
*aString = [version stringValue];
*flag = YES;
return SEND_SUCCESS;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.