This is Piper.m in view mode; [Download] [Up]
#import <appkit/appkit.h>
#import <objc/Storage.h>
#import <sys/dir.h>
#import <sys/stat.h>
#import <stdio.h>
#import "Piper.h"
#define SERVICE_FILE "/tmp/PiperService"
#define EXEC_FILE "/tmp/PiperExec"
@implementation Piper
- pasteSelection:(id)pb userData:(const char *)userData error:(char **)msg
/*
* This method returns data to the selection pasteboard.
*/
{
char **pbtypes;
id ret, selPb;
pbtypes = (char **)[pb types];
while (*pbtypes) {
if (*pbtypes == NXAsciiPboardType) { //Plain ASCII text
ret = [pb readType:*pbtypes data:&data length:&length];
type = *pbtypes;
scriptName = userData;
selPb = [Pasteboard newName:NXSelectionPboard];
[self runScript:selPb];
return self;
} else if (*pbtypes == NXFilenamePboardType) { //ASCII file name
ret = [pb readType:*pbtypes data:&data length:&length];
type = *pbtypes;
scriptName = userData;
selPb = [Pasteboard newName:NXSelectionPboard];
[self runScript:selPb];
return self;
}
pbtypes++;
}
/*
* Didn't find one we liked.
*/
NXRunAlertPanel(NULL, "Piper does not recognize pasteboard type",
NULL, NULL, NULL);
return self;
}
- returnSelection:(id)pb userData:(const char *)userData error:(char **)msg
/*
* This method returns data to the callers pasteboard.
*/
{
char **pbtypes;
id ret;
pbtypes = (char **)[pb types];
while (*pbtypes) {
if (*pbtypes == NXAsciiPboardType) { //Plain ASCII text
ret = [pb readType:*pbtypes data:&data length:&length];
type = *pbtypes;
scriptName = userData;
[self runScript:pb];
return self;
} else if (*pbtypes == NXFilenamePboardType) { //ASCII file name
ret = [pb readType:*pbtypes data:&data length:&length];
type = *pbtypes;
scriptName = userData;
[self runScript:pb];
return self;
}
pbtypes++;
}
/*
* Didn't find one we liked.
*/
NXRunAlertPanel(NULL, "Piper does not recognize pasteboard type",
NULL, NULL, NULL);
return self;
}
- appDidInit:sender
{
/*
* Make us the object that service requests (piperMessage) get sent to.
*/
[[NXApp appListener] setServicesDelegate:self];
textView = [scrollView docView];
fontObj = [Font newFont:"Courier" size:14];
[textView setSel:0:0];
[textView setSelFont:fontObj];
clearWindow = 1;
return self;
}
- reloadScripts:sender
/*
* Get the list of scripts from ~/Library/Piper. We then do surgery on
* ourselves to replace the services section thus making the menu
* reflect the list of scripts.
*/
{
char appDir[MAXPATHLEN];
int count = 0, keyFound, returnFound;
char cmd[MAXPATHLEN], fileName[MAXPATHLEN], scriptDirName[MAXPATHLEN];
char scriptFileName[MAXPATHLEN], script[256];
struct stat stats;
char *suffix, option[256], keyOption[256], returnOption[256];
FILE *lspipe, *serviceFile, *optionsFile;
system("rm -f /tmp/PiperService");
strcpy(appDir, NXArgv[0]);
if (appDir[0] == '/') { /* if absolute path */
if (suffix = rindex(appDir,'/'))
*suffix = '\0'; /* remove executable name */
} else {
NXRunAlertPanel(NULL, "Please launch from the Workspace!",
NULL, NULL, NULL);
exit(1);
}
if ((serviceFile = fopen(SERVICE_FILE, "a")) == NULL) {
NXRunAlertPanel(NULL, "Could not open temporary file %s", NULL, NULL,
NULL, SERVICE_FILE);
exit(1);
}
/*
* Get a list of the scripts in ~/Library/Piper
*/
sprintf(scriptDir, "%s/Library/Piper", getenv("HOME"));
if (stat(scriptDir, &stats) < 0) {
NXRunAlertPanel(NULL, "Cannot find scripts directory %s",
NULL, NULL, NULL, scriptDir);
exit(1);
}
sprintf(cmd, "ls %s 2>/dev/null", scriptDir);
if ((lspipe = popen(cmd, "r")) == NULL) {
NXRunAlertPanel(NULL, "Command \"ls %s\" failed",
NULL, NULL, NULL, scriptDir);
exit(1);
}
while (fgets(script, sizeof(script), lspipe) != NULL) {
script[strlen(script)-1] = 0;
sprintf(scriptDirName, "%s/%s", scriptDir, script);
if (stat(scriptDirName, &stats) < 0 || !(stats.st_mode & S_IFDIR)) {
NXRunAlertPanel(NULL, "%s is not a directory!",
NULL, NULL, NULL, scriptDirName);
continue;
}
sprintf(scriptFileName, "%s/script", scriptDirName);
if (stat(scriptFileName, &stats) < 0 || !(stats.st_mode & 0111)) {
NXRunAlertPanel(NULL, "%s does not exist or is not executable",
NULL, NULL, NULL, scriptFileName);
continue;
}
sprintf(fileName, "%s/options", scriptDirName);
keyFound = returnFound = 0;
if ((optionsFile = fopen(fileName, "r")) != NULL) {
while (fgets(option, sizeof(option), optionsFile) != NULL) {
if (!strncmp(option, "Key Equivalent", 14)) {
strcpy(keyOption, option);
keyFound++;
} else if (!strncmp(option, "Return Type", 11)) {
strcpy(returnOption, option);
returnFound++;
} else {
NXRunAlertPanel(NULL, "Option %s not recognized",
NULL, NULL, NULL, option);
}
}
fclose(optionsFile);
}
if (returnFound)
fprintf(serviceFile, "Message: returnSelection\n");
else
fprintf(serviceFile, "Message: pasteSelection\n");
fprintf(serviceFile, "Port: Piper\nMenu Item: Piper/%s\nUser Data: %s\nSend Type: NXAsciiPboardType\nSend Type: NXFilenamePboardType\n", script, script);
if (returnFound)
fprintf(serviceFile, returnOption);
if (keyFound)
fprintf(serviceFile, keyOption);
fprintf(serviceFile, "\n");
count++;
}
pclose(lspipe);
fclose(serviceFile);
if (count == 0) {
NXRunAlertPanel(NULL, "No valid scripts found in %s", NULL, NULL, NULL,
scriptDir);
exit(1);
}
/*
* OK, now we have a new service file, so insert it in the executable.
*/
sprintf(cmd, "segedit %s -r __ICON __services %s -o %s", NXArgv[0],
SERVICE_FILE, EXEC_FILE);
if (system(cmd) != 0) {
NXRunAlertPanel(NULL, "Command %s failed!", NULL, NULL, NULL, cmd);
exit(1);
}
sprintf(cmd, "rm -f %s;mv %s %s;chmod a+x %s", NXArgv[0], EXEC_FILE,
NXArgv[0], NXArgv[0]);
if (system(cmd) != 0) {
NXRunAlertPanel(NULL, "Command %s failed!", NULL, NULL, NULL, cmd);
exit(1);
}
if (system("make_services") != 0) {
NXRunAlertPanel(NULL, "Command make_services failed!", NULL, NULL, NULL);
exit(1);
}
NXRunAlertPanel(NULL, "Reload of scripts complete. Please logout and back in again for changes to take effect.", NULL, NULL, NULL);
exit(0);
return self;
}
- runScript:pb
/*
* Called when one of the Pipes menu buttons is clicked. Run the script.
*/
{
int err, i, outputLen, outputMaxlen, textLength;
char scriptCmd[MAXPATHLEN], *outputData;
const char *paramString;
FILE *pipe;
NXStream *outputStream;
static char outputFile[] = "/tmp/PipeXXXXXX";
struct stat sbuf;
sprintf(scriptDir, "%s/Library/Piper", getenv("HOME"));
sprintf(scriptCmd, "%s/%s/script", scriptDir, scriptName);
stat(scriptCmd, &sbuf);
if (!(sbuf.st_mode & 0111)) {
NXRunAlertPanel(NULL, "No execute permission on %s",
NULL, NULL, NULL, scriptCmd);
exit(1);
}
mktemp(outputFile);
paramString = [parameter stringValueAt:0];
if (type == NXAsciiPboardType) {
/*
* For ascii pasteboard types, we just read the selection
* and pipe it through the given script. The output is collected
* in a temporary file.
*/
sprintf(scriptCmd, "%s/%s/script %s >%s 2>/dev/console", scriptDir,
scriptName, paramString, outputFile);
if ((pipe = popen(scriptCmd, "w")) == NULL) {
NXRunAlertPanel(NULL, "Command \"%s\" failed",
NULL, NULL, NULL, scriptCmd);
exit(1);
}
for (i=0; i<length; i++) {
putc(data[i], pipe);
}
err = pclose(pipe);
if (err != 0) {
NXRunAlertPanel(NULL, "Command \"%s\" returned error code %d",
NULL, NULL, NULL, scriptName, err);
}
} else if (type == NXFilenamePboardType) {
/*
* Selection is a filename. Run the script with the filename
* as the only parameter. Any output is collected in the
* temporary file.
*/
sprintf(scriptCmd, "%s/%s/script %s %s >%s 2>/dev/console",
scriptDir, scriptName, paramString, data, outputFile);
err = system(scriptCmd);
if (err != 0) {
NXRunAlertPanel(NULL, "Command \"%s\" returned error code %d",
NULL, NULL, NULL, scriptName, err);
}
}
if (clearParameter)
[parameter setStringValue:"" at:0];
/*
* Now the fun bit. Any output from the script will be in the temporary
* file outputFile. Map the file in and paste the data out to the
* selection pasteboard.
*/
outputStream = NXMapFile(outputFile, NX_READONLY);
NXGetMemoryBuffer(outputStream, &outputData, &outputLen, &outputMaxlen);
if (outputLen == 0) {
NXCloseMemory(outputStream, NX_FREEBUFFER);
vm_deallocate(task_self(), (int)data, length);
sprintf(scriptCmd, "rm -f %s", outputFile);
system(scriptCmd);
return self;
}
[pb declareTypes:&NXAsciiPboardType num:1 owner:self];
[pb writeType:NXAsciiPboardType data:outputData length:outputLen];
/*
* Output data to our window. If it looks like RTF, interpret it that way.
*/
textLength = [textView textLength];
if (clearWindow)
[textView setSel:0:textLength];
else
[textView setSel:textLength:textLength];
if (!strncmp(outputData, "{\\rtf0", 6))
[textView replaceSelWithRichText:outputStream];
else {
[textView setSelFont:fontObj];
[textView replaceSel:outputData];
}
NXCloseMemory(outputStream, NX_FREEBUFFER);
vm_deallocate(task_self(), (int)data, length);
sprintf(scriptCmd, "rm -f %s", outputFile);
system(scriptCmd);
return self;
}
- setClearParameter:sender
{
clearParameter = !clearParameter;
return self;
}
- setClearWindow:sender
{
clearWindow = !clearWindow;
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.