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.