Newsgroups: comp.lang.smalltalk
Path: cantaloupe.srv.cs.cmu.edu!bb3.andrew.cmu.edu!newsfeed.pitt.edu!newsflash.concordia.ca!news.nstn.ca!ott.istar!istar.net!van.istar!west.istar!n1van.istar!van-bc!nntp.portal.ca!news.bc.net!info.ucla.edu!agate!spool.mu.edu!howland.reston.ans.net!blackbush.xlink.net!ins.net!heeg.de!gustav!hmm
From: hmm@gustav (Hans-Martin Mosner)
Subject: Re: Question: Calling a VWorks screen from a running image
Message-ID: <DvAupy.CAC@heeg.de>
Sender: uucp@heeg.de
Organization: Georg Heeg Objektorientierte Systeme, Dortmund, FRG
X-Newsreader: TIN [version 1.2 PL2]
References: <4tb1fq$kdh@atlantis.cc.uwf.edu>
Date: Mon, 29 Jul 1996 10:05:57 GMT
Lines: 286

Ken Pathak (kpathak@news.uwf.edu) wrote:
: Hi there fellow smalltalkers:

: 	Does anyone know how to call (open) a screen from a running image in
: Visual Works?  IOW, can I do this from the command line.  FOr example, if I
: have an application model class called  "AddCustomers".  Now, I can open
: this interface by typing

: AddCustomers open

: in the workspace, and hitting "do it".

: But, if I am on a UNIX box which is running the VWorks server, can I issue
: some kind of command with arguments which will open up a window for my
: AddCustomers (above?)?  

: Any pointers would be *MUCH* appreciated.

: Thanks,

: Ken

You should set up a server in the VW image that listens for commands on a
socket and executes them. Then you need a little C program as the client.
Sound not too difficult, but if you ever have programmed sockets in C,
you know there's a lot of work in front of you...

But... This is your lucky day!

Quite some time ago I did just such a thing for a prototype.
The code is generic and not really long, so I'm including it
here for your viewing pleasure.

Usage:
Load DialogServer.st into VW, adapt the initialize method, and start the server.
Compile ds.c (cc ds.c -o ds)
link ds to command names such as warn, request, launcher, or browser.
execute the commands, see what happens...
(Disclaimer: If you don't like my coding style, the names of the functions/methods,
the scarcity of the comments, my nose, the government, or anything else:
I couldn't care less! This is free software, after all!)

Hans-Martin

=== File: DialogServer.st ===

'From VisualWorks(R), Release 2.5.1 of September 26, 1995 on July 29, 1996 at 11:55:31 am'!



Object subclass: #DialogServer
	instanceVariableNames: 'stream path command args env '
	classVariableNames: 'ServerProcess ServerSocket ServiceRegistry '
	poolDictionaries: ''
	category: 'Dialog Server'!
DialogServer comment:
'This class handles requests from a simple command line interface, executes a matching block in VisualWorks, and returns the result to the calling program.

Instance Variables:
	stream	<Stream>	streaming connection to the calling program
	path	<String>	The command''s working directory
	command	<String>	The command string
	args	<Array of: String>	The arguments to the command
	env	<Dictionary of: String->String>	The environment of the command

Class Variables:
	ServerProcess	<Process>	process listening for connection requests
	ServerSocket	<Socket>	Socket on which requests come in
	ServiceRegistry	<Dictionary of: String->Block>	Mapping from command names to service blocks'!

!DialogServer methodsFor: 'argument parsing'!

stream: aStream 
	| argSize key value action result null |
	stream := aStream.
	
	[null := 0 asCharacter.
	path := stream upTo: null.
	argSize := Integer readFrom: stream.
	stream next.
	command := stream upTo: null.
	args := (1 to: argSize - 1)
				collect: [:i | stream upTo: null].
	env := Dictionary new.
	[stream peek = null]
		whileFalse: 
			[key := stream upTo: $=.
			value := stream upTo: null.
			env at: key put: value].
	action := ServiceRegistry at: command ifAbsent: [].
	InputState default pseudoEvent.
	result := action == nil
				ifTrue: ['Command ' , command printString , ' not registered.']
				ifFalse: [action numArgs = 0
						ifTrue: [action value]
						ifFalse: [action numArgs = 1
								ifTrue: [action value: args]
								ifFalse: [action numArgs = 2
										ifTrue: [action value: args value: path]
										ifFalse: [action
												value: args
												value: path
												value: env]]]].
	stream binary.
	result isInteger ifTrue: [stream nextPut: 0; nextPut: (result bitAnd: 255)].
	result isString
		ifTrue: 
			[stream nextPut: 1 + (result size // 256); nextPut: (result size bitAnd: 255).
			stream text; nextPutAll: result]]
		valueNowOrOnUnwindDo: [stream close]! !

!DialogServer class methodsFor: 'server'!

handle: aStream 
	"Handle aStream in a new process so that multiple requests and errors can be 
	handled."

	[self new stream: aStream] fork!

startServer
	"DialogServer startServer"

	self stopServer.
	ServerSocket := IOAccessor defaultForIPC newTCPserverAtPort: 3451.
	ServerSocket listenFor: 5.
	ServerProcess := [[self handle: ServerSocket accept readAppendStream] repeat] fork!

stopServer
	"DialogServer stopServer"

	ServerProcess notNil
		ifTrue: 
			[ServerProcess terminate.
			ServerProcess := nil].
	ServerSocket notNil
		ifTrue: 
			[ServerSocket close.
			ServerSocket := nil]! !

!DialogServer class methodsFor: 'class initialization'!

initialize
	"DialogServer initialize"

	ServiceRegistry := Dictionary new.
	self registerService: 'warn'
		block: 
			[:args | 
			Dialog warn: (args size = 0
					ifTrue: ['Warning']
					ifFalse: [args first]).
			0].
	self registerService: 'request' block: [:args | Dialog request: (args size >= 1
				ifTrue: [args first]
				ifFalse: ['Question?'])
			initialAnswer: (args size >= 2
					ifTrue: [args at: 2]
					ifFalse: [''])].
	self registerService: 'launcher' block: [VisualLauncher open].
	self registerService: 'browser' block: 
		[:args | 
		| sym class |
		args size = 0
			ifTrue: [Browser open]
			ifFalse: 
				[sym := args first asSymbol.
				(class := Smalltalk at: sym ifAbsent: []) isBehavior
					ifTrue: [Browser newOnClass: class]
					ifFalse: ['No such class.']]]!

registerService: serviceName block: aBlock
	"serviceName is the name of the service as seen from the outside. aBlock can have zero to 3 args:
	1. Array of command arguments
	2. Working Directory string
	3. Environment Dictionary"

	ServiceRegistry at: serviceName put: aBlock! !

DialogServer initialize!

=== File: ds.c ===

/* dialog server interface program
   - establishes a connection to the dialog server
   - sends path, argv and env
   - waits for result
   - waits for connection close
   - prints result
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

FILE *f;

printNum(n)
{
	fprintf(f, "%d%c", n, 0);
}

printStr(s)
char *s;
{
	fprintf(f, "%s%c", s, 0);
}

extern char **environ;
extern void *malloc();

main(argc, argv)
char **argv;
{
	int i, s, result, len;
	struct sockaddr_in sa;
	struct hostent *host;
	unsigned char pathname[MAXPATHLEN], *buffer;
	char **p;

	/* create an address for the dialog manager server */
	sa.sin_family = AF_INET;
	sa.sin_port = 3451;
	host = gethostbyname("localhost");
	sa.sin_addr.s_addr = ((long*)(host->h_addr_list[0]))[0];

	/* create a socket */
	s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (s < 0) {
		perror("socket");
		exit(1);
	}

	/* connect it to the server */
	result = connect(s, &sa, sizeof sa);
	if (result < 0) {
		perror("connect");
		exit(1);
	}

	/* create a stream for communication */
	f = fdopen(s, "w");
	if (f == NULL) {
		perror("fdopen");
		exit(1);
	}

	/* print the working directory name */
	getwd(pathname);
	printStr(pathname);

	/* print the arguments */
	printNum(argc);
	for (i=0; i<argc; i++)
		printStr(argv[i]);

	/* print the environment */
	for (p=environ; *p; p++)
		printStr(*p);
	printStr("");

	/* wait for results */
	fflush(f);
	result = read(s, pathname, 2);
	if (result == 0)
		/* normal EOF */
		exit(0);
	if (pathname[0] == 0)
		/* abnormal; exit status given */
		exit(pathname[1]);
	len = ((pathname[0]-1)<<8) + (pathname[1]);
	buffer = (unsigned char *)malloc(len+1);
	read(s, buffer, len);
	buffer[len] = 0;
	puts(buffer);
}

=== That's it, folks ===
--
+--- Hans-Martin Mosner -------- Senior Smalltalk Guru ---+
| These opinions are entirely ficticious.  Any similarity |
| to real opinions is purely coincidental and unintended. |
+--- <hmm@heeg.de> ------ URL:http://www.heeg.de/~hmm/ ---+
