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.