home *** CD-ROM | disk | FTP | other *** search
- #import <defaults/defaults.h> //for NXArgv
- #import <appkit/Application.h> //for NXApp
- #import <appkit/Listener.h> //for void NXUpdateDynamicServices(void)
- #import <appkit/Panel.h> //for NXRunAlertPanel
- #import <appkit/Pasteboard.h>
- #import <libc.h> //for mktemp
- #import <mach/mach.h> //vm_deallocate
- #import <objc/Storage.h>
- #import <stdio.h>
- #import <stdlib.h>
- #import <strings.h> //For strcmp
- #import <sys/dir.h>
- #import <sys/stat.h>
- #import <sys/param.h> //For MAXPATHLEN
- //Maybe not using <appkit/appkit.h> goes faster... But it's a pain spelling
- //all this out. I want a CASE tool from NeXT!
-
- #import "Piper.h"
- @implementation Piper
- -appDidInit:sender{
- // Make us the object that service requests (piperMessage) get sent to.
- [[NXApp appListener] setServicesDelegate:self];
- return self;
- }
- -piperMessage:(id)pb userData:(const char *)userData error:(char **)msg{
- /*var*/
- char **pbtypes,*data,*outputData,
- scriptCmd[MAXPATHLEN];
- int length,err, i, outputLen, outputMaxlen;
- FILE *pipe;
- NXStream *pNXStream;
- static char outputFile[]="/tmp/PipeXXXXXX";
- struct stat sbuf;
- if(!strcmp(userData,"NXUpdateDynamicServices")){
- [self reloadScripts:self];
- return self;
- }
- for(pbtypes=(char **)[pb types];*pbtypes;pbtypes++){
- if( (*pbtypes==NXAsciiPboardType /*Plain ASCII text*/)||
- (*pbtypes==NXFilenamePboardType /*ASCII file name */)){
- [pb readType:*pbtypes data:&data length:&length];
- sprintf(scriptCmd,"%s/script",userData);
- stat(scriptCmd, &sbuf);
- if(!(sbuf.st_mode & 0111)){
- NXRunAlertPanel(NULL,"No execute permission on %s",
- NULL,NULL,NULL, scriptCmd);
- exit(1);
- }
- mktemp(outputFile);
- if(0){
- }else if(*pbtypes==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.
- //I think this should become an NXStream, somehow
- //(needs another thread, hmmm)!!!
- sprintf(scriptCmd,"%s/script >%s 2>/dev/console",
- userData,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);
- if(err=pclose(pipe)){
- NXRunAlertPanel(NULL,"Command \"%s\" returned error code %d",
- NULL,NULL,NULL, userData, err);
- }
- }else if(*pbtypes==NXFilenamePboardType){
- //Selection is a filename. Run the script with the filename
- //as the only parameter. Any output is collected in the
- //temporary file.
- /*var*/ char *pchar;
- while(pchar=data,pchar){
- if(data=index(data,'\t')){ *data=0; data++; }
- sprintf(scriptCmd, "%s/script \"%s\" >%s 2>/dev/console",
- userData, pchar, outputFile);
- if(err=system(scriptCmd)){
- NXRunAlertPanel(NULL,"Command \"%s\" returned error code %d. "
- "Look at Console",
- NULL,NULL,NULL, userData, err);
- }
- }
- }
- //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.
- pNXStream=NXMapFile(outputFile,NX_READONLY);
- NXGetMemoryBuffer(pNXStream, &outputData, &outputLen, &outputMaxlen);
- [pb declareTypes:&NXAsciiPboardType num:1 owner:self];
- [pb writeType:NXAsciiPboardType data:outputData length:outputLen];
- vm_deallocate(task_self(),(int)data,length);
- sprintf(scriptCmd,"rm -f %s",outputFile);
- system(scriptCmd);
- return self;
- }
- }
- //Didn't find one we liked (dropped out of pbtypes list).
- NXRunAlertPanel(NULL,"Piper does not recognize pasteboard type %d",
- NULL,NULL,NULL,*pbtypes);
- return self;
- }
- -reloadScripts:sender{
- /*var*/
- int keyFound,returnFound;
- struct stat stats;
- char option[256],keyOption[256],returnOption[256];
- FILE *lspipe,*serviceFile,*optionsFile;
- /*Make serviceFile your private services cache file.*/{
- /*var*/ char serviceFilePath[MAXPATHLEN];
- sprintf(serviceFilePath,"%s/.NeXT/services/Piper",getenv("HOME"));
- if((serviceFile=fopen(serviceFilePath,"w"))==NULL){
- NXRunAlertPanel(NULL,"Could not open service file %s",
- "Quit",NULL,NULL, serviceFilePath);
- exit(1);
- } //Shouldn't happen.
- }
- /*Make lspipe a pipe filled with script paths.*/{
- /*var*/ char executablePath[MAXPATHLEN],
- cmd [MAXPATHLEN];
- if(NXArgv[0][0]=='/'){
- strcpy(executablePath,NXArgv[0]); *rindex(executablePath,'/')=0;
- }else{
- switch(NXRunAlertPanel( NULL,
- "Please don't use the Update Dynamic Services "
- "command in Piper's menu if it were "
- "launched "
- "from a shell with a partial path if you want "
- "its SampleScripts to be included. "
- "Maybe some programmer will give me a tool "
- "to get the full path using the notion of "
- "current directory or something? "
- "He might then distribute this to the NeXT "
- "programming community…",
- "Quit","Cancel",NULL)){
- case NX_ALERTDEFAULT: [NXApp terminate:self]; //break's not necessary
- case NX_ALERTALTERNATE: return self; //same
- }
- }
- sprintf(cmd,"ls %s/SampleScripts/../SampleScripts 2>/dev/null "
- "| awk '{print \"%s/SampleScripts/\"$0}' 2>/dev/null; "
- "ls /LocalLibrary/Piper/../Piper 2>/dev/null "
- "| awk '{print \"/LocalLibrary/Piper/\"$0}' 2>/dev/null; "
- "ls %s/Library/Piper/../Piper 2>/dev/null "
- "| awk '{print \"%s/Library/Piper/\"$0}' 2>/dev/null",
- executablePath, executablePath,getenv("HOME"),getenv("HOME"));
- if((lspipe=popen(cmd,"r"))==NULL){
- NXRunAlertPanel(NULL,"lspipe could not be opened",
- NULL,NULL,NULL);
- exit(1);
- } //If this happens, it's a bug.
- }
- /*Search for scripts.*/{
- /*var*/ int count; //how many valid ones we found
- char scriptDirPath[MAXPATHLEN],actualScriptPath[MAXPATHLEN];
- for(count=0;
- fgets(scriptDirPath,sizeof(scriptDirPath),lspipe)!=NULL;
- count++){
- scriptDirPath[strlen(scriptDirPath)-1]=0;
- if(stat(scriptDirPath,&stats)<0||!(stats.st_mode&S_IFDIR)){
- NXRunAlertPanel(NULL,"%s is not a directory!",
- NULL,NULL,NULL,scriptDirPath);
- continue;
- }
- sprintf(actualScriptPath,"%s/script",scriptDirPath);
- if(stat(actualScriptPath,&stats)<0||!(stats.st_mode & 0111)){
- NXRunAlertPanel(NULL,"%s does not exist or is not executable",
- NULL,NULL,NULL,actualScriptPath);
- continue;
- }
- fprintf(serviceFile,"Message: piperMessage\n"
- "Port: Piper\n"
- "Menu Item: Piper/%s\n"
- "User Data: %s\n",
- rindex(scriptDirPath,'/')+1,
- scriptDirPath);
- /*Look for options.*/{
- /*var*/ char optionsPath[MAXPATHLEN];
- sprintf(optionsPath,"%s/options",scriptDirPath);
- keyFound=returnFound=0;
- if((optionsFile=fopen(optionsPath,"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 if(!strcmp(option,"Send Type: NXAsciiPboardType\n")){
- fprintf(serviceFile,option);
- }else if(!strcmp(option,"Send Type: NXFilenamePboardType\n")){
- fprintf(serviceFile,option);
- }else{
- NXRunAlertPanel(NULL,"Option\n"
- "%s\n"
- "not recognized in script\n"
- "%s",
- NULL,NULL,NULL,option,scriptDirPath);
- }
- }
- fclose(optionsFile);
- }
- }
- if(returnFound) fprintf(serviceFile,returnOption);
- if(keyFound) fprintf(serviceFile,keyOption);
- /*always*/ fprintf(serviceFile,"\n");
- }
- pclose(lspipe);
- fclose(serviceFile);
- NXUpdateDynamicServices();
- if(!count){
- /*var*/ char somePath[MAXPATHLEN];
- NXRunAlertPanel(NULL,"No valid scripts found",
- NULL,NULL,NULL);
- sprintf(somePath,"%s/.NeXT/services/Piper",getenv("HOME"));
- if(remove(somePath))
- NXRunAlertPanel(NULL,
- "Also, I could not get rid of ``%s''",
- NULL,NULL,NULL,somePath);
- exit(1);
- }
- }
- NXRunAlertPanel(NULL,
- "Relaunch applications in which you want to use new "
- "names, if you haven't got a version (3.0 at least) "
- "in which NeXT fixed this.",
- NULL,NULL,NULL);
- return self;
- }
- @end
-