home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / cvs-1.8.7-src.tgz / tar.out / fsf / cvs / macintosh / ae_if.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  8KB  |  424 lines

  1. /*
  2.  * aeLink.c
  3.  * UNIX environment handling stuff for macos
  4.  *
  5.  * These routines make MacCVS able to accept a standard UNIX command line,
  6.  * environment, output redirection, and startup directory via AppleEvents
  7.  * and redirect all output to AppleEvents, a file, or the SIOUX tty window.
  8.  *
  9.  * Michael Ladwig <mike@twinpeaks.prc.com> --- April 1996
  10.  */
  11. #include "mac_config.h"
  12. #ifdef AE_IO_HANDLERS
  13. #ifdef __POWERPC__
  14. #include <MacHeadersPPC>
  15. #else
  16. #include <MacHeaders68K>
  17. #endif
  18.  
  19. #include <AppleEvents.h>
  20. #include <AERegistry.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <console.h>
  24. #include <sys/fcntl.h>
  25.  
  26. extern char *xmalloc (size_t bytes);
  27.  
  28. enum { outToAE, outToFile };
  29.  
  30. static int        outputMode = outToAE;
  31. static char        tempOutputFileName[256], outputFileName[256];
  32. static int        outputFile;
  33. static int        noLineBuffer;
  34.  
  35. AppleEvent        gResponseEvent            =    {'null', nil};
  36. AppleEvent        gResponseReplyEvent    =    {'null', nil};
  37. AEAddressDesc    gResponseAddress;
  38.  
  39. static char        aeCmdIn = 0;
  40. static char        aeLinkDone = 0;
  41.  
  42. char                **Args;
  43. char                **EnvVars, **EnvVals;
  44. int                ArgC    = 1;
  45. int                EnvC    = 1;
  46.  
  47. char * CopyInfo(Handle info)
  48. {
  49.     if( info )
  50.     {
  51.         char * retarg = xmalloc(GetHandleSize(info) + 1);
  52.     
  53.         if (retarg)
  54.         {
  55.             memcpy(retarg, *info, GetHandleSize(info) );
  56.             retarg[GetHandleSize(info)] = 0;
  57.         }
  58.             
  59.         return retarg;
  60.     }
  61.     else
  62.         return nil;
  63. }
  64.  
  65. void MakeEnvironment(const AppleEvent *event)
  66. {
  67.     AEDesc        args;
  68.     long            i, argCount;
  69.  
  70.     if (AEGetParamDesc(event, 'ENVT', typeAEList, &args) || AECountItems(&args, &argCount) || !argCount)
  71.     {    
  72.         EnvVars[EnvC] = nil;
  73.         EnvVals[EnvC] = nil;
  74.         return;
  75.     }
  76.     
  77.     for (i = 0; i++<argCount;)
  78.     {
  79.         AEKeyword    key;
  80.         AEDesc    arg;
  81.  
  82.         EnvC++;
  83.         
  84.         // Variable
  85.  
  86.         if (!AEGetNthDesc(&args, i, typeChar, &key, &arg))
  87.         {
  88.             HLock(arg.dataHandle);
  89.             EnvVars[EnvC-1] = CopyInfo(arg.dataHandle);
  90.             AEDisposeDesc(&arg);
  91.         }
  92.         
  93.         // Value
  94.  
  95.         i++;
  96.         if (!AEGetNthDesc(&args, i, typeChar, &key, &arg))
  97.         {
  98.             HLock(arg.dataHandle);
  99.             EnvVals[EnvC-1] = CopyInfo(arg.dataHandle);
  100.             AEDisposeDesc(&arg);
  101.         }
  102.     }
  103.     AEDisposeDesc(&args);
  104.  
  105.     EnvVars[EnvC] = nil;
  106.     EnvVals[EnvC] = nil;
  107. }
  108.  
  109. pascal OSErr DoScript(const AppleEvent *event, AppleEvent *reply, long refCon)
  110. {
  111.     OSType        mode;
  112.     DescType        typeCode;
  113.     Size            size;
  114.     AEDesc        args;
  115.     long            i, argCount, addrSize;
  116.     AEDesc        env;
  117.     char            *argString, *anArg, startPWD[1024];
  118.     TargetID        requestAddr;
  119.     DescType        requestAddrType;
  120.     Boolean        flag;
  121.  
  122.     if (AEGetParamDesc(event, '----', typeAEList, &args) || AECountItems(&args, &argCount) || !argCount) 
  123.         return errAEEventFailed;
  124.  
  125.     // Get the address of the requesting app to we can send information back
  126.     
  127.     AEGetAttributePtr(event,
  128.                             keyAddressAttr,
  129.                             typeWildCard, 
  130.                             &requestAddrType,
  131.                             (Ptr) &requestAddr,
  132.                             sizeof(requestAddr),
  133.                             &addrSize);
  134.     AECreateDesc( typeTargetID, &requestAddr, sizeof(requestAddr), &gResponseAddress );
  135.  
  136.     // Pull the command line from the event
  137.     
  138.     for (i = 0; i++<argCount;)
  139.     {
  140.         AEKeyword    key;
  141.         AEDesc    arg;
  142.  
  143.         if (!AEGetNthDesc(&args, i, typeChar, &key, &arg))
  144.         {
  145.             HLock(arg.dataHandle);
  146.             argString = CopyInfo(arg.dataHandle);
  147.             AEDisposeDesc(&arg);
  148.             anArg = strtok( argString, " " );
  149.             Args[ArgC] = anArg;
  150.             ArgC++;
  151.             while( (anArg = strtok(NULL, " ")) != NULL )
  152.             {
  153.                     Args[ArgC] = anArg;
  154.                     ArgC++;
  155.             }
  156.         }
  157.     }
  158.     AEDisposeDesc(&args);
  159.     Args[ArgC] = nil;
  160.  
  161.     // Pull the environment variables from the event
  162.     
  163.     MakeEnvironment( event );
  164.     
  165.     // Figure out what mode should be used to return results
  166.     
  167.     if (AEGetParamPtr(event, 'MODE', typeEnumerated, &typeCode, &mode, 4, &size))
  168.         outputMode = outToAE;
  169.     else
  170.     {
  171.         switch (mode) {
  172.             
  173.             // Batch (return results via Apple Events)
  174.                 
  175.             case 'TOAE':
  176.                 outputMode = outToAE;
  177.                 break;
  178.             
  179.             // File (return results via a file)        
  180.             case 'FILE':
  181.                 outputMode = outToFile;
  182.                 if (AEGetParamPtr(event, 'FILE', typeChar, &typeCode, &outputFileName, sizeof(outputFileName)-1, &size))
  183.                 {
  184.                     outputMode = outToAE;
  185.                     fprintf(stderr, "MacCVS Error: No filename parameter\n" );
  186.                 }
  187.                 else
  188.                 {
  189.                     outputFileName[size] = 0;
  190.                     strcpy( tempOutputFileName, outputFileName );
  191.                     strcat( tempOutputFileName, ".TMP");
  192.                     if( (outputFile = open(tempOutputFileName, O_WRONLY | O_CREAT | O_TRUNC)) == 1 )
  193.                     {
  194.                         outputMode = outToAE;
  195.                         fprintf(stderr, "MacCVS Error: Unable to open '%s'\n", tempOutputFileName);
  196.                     }
  197.                 }
  198.                 break;
  199.         }
  200.     }
  201.     
  202.     // Check to see if there is a starting pathname for this invokation
  203.     
  204.     if ( ! AEGetParamPtr(event, 'SPWD', typeChar, &typeCode, &startPWD, sizeof(startPWD)-1, &size) )
  205.     {
  206.         startPWD[size-1] = 0;
  207.         chdir(startPWD);
  208.     }
  209.     
  210.     // Check to see if we should not line buffer results in AE return mode
  211.     
  212.     if (AEGetParamPtr(event, 'LBUF', typeBoolean, &typeCode, (Ptr) &flag, 1, &size))
  213.         noLineBuffer = 0;
  214.     else
  215.         noLineBuffer = flag;
  216.  
  217.     // All Done
  218.     
  219.     aeLinkDone = 1;
  220.     
  221.     return noErr;
  222. }
  223.  
  224. void GetUnixCommandEnvironment( char *name )
  225. {
  226.     long                timeOutTicks;
  227.     EventRecord        theEvent;
  228.  
  229. #ifdef __POWERPC__
  230.     AEInstallEventHandler( kAEMiscStandards, kAEDoScript, NewAEEventHandlerProc(DoScript), 0, false);
  231. #else
  232.     AEInstallEventHandler( kAEMiscStandards, kAEDoScript, DoScript, 0, false);
  233. #endif
  234.  
  235.     // Allocate some storage for the command line and the environment
  236.     
  237.     Args    = (char **) xmalloc(ArgMax * sizeof(char *));
  238.     EnvVars    = (char **) xmalloc(EnvMax * sizeof(char *));
  239.     EnvVals    = (char **) xmalloc(EnvMax * sizeof(char *));
  240.     
  241.     // Initialize the first arg to the process name
  242.     
  243.     Args[0]    = xmalloc(strlen(name)+1);
  244.     strcpy( Args[0], name );
  245.     
  246.     // Defaults
  247.     
  248.     ArgC = 1;
  249.     EnvC = 0;
  250.     outputMode = outToAE;
  251.     
  252.     // Wait for the command line and environment
  253.     
  254.     timeOutTicks = TickCount() + (60*AE_TIMEOUT_SECONDS);        // Timeout seconds set in maccvs.pch    
  255.     while( (TickCount() < timeOutTicks) && (!aeLinkDone) )
  256.     {        
  257.         if (WaitNextEvent(everyEvent, &theEvent, 60, nil))
  258.         {
  259.             if( ! (SIOUXHandleOneEvent(&theEvent)) )
  260.             {
  261.                 switch (theEvent.what)
  262.                 {
  263.                     case kHighLevelEvent:
  264.                         AEProcessAppleEvent(&theEvent);
  265.                         break;
  266.                 }
  267.             }
  268.         }
  269.     }
  270. }
  271.  
  272. char *
  273. getenv( const char *var )
  274. {
  275.     int    i;
  276.     
  277.     // Look it up in the environment
  278.     
  279.     for( i=0; i<EnvC; i++ )
  280.     {
  281.         if( strcmp(EnvVars[i], var) == 0 ) return( EnvVals[i] );
  282.     }
  283.     
  284.     return NULL;
  285. }
  286.  
  287. /* Free the allocated memory */
  288.  
  289. void CleanUpArgsAndEnv( void )
  290. {
  291.     int    i;
  292.     
  293.     // Clean up the args
  294.     
  295.     for( i=0; i<ArgC; i++ )
  296.         free( Args[i] );
  297.         
  298.     free( Args );
  299.     
  300.     // Clean up the environment
  301.     
  302.     for( i=0; i<EnvC; i++ )
  303.         { free( EnvVars[i] ); free( EnvVals[i] ); }
  304.         
  305.     free( EnvVars );
  306.     free( EnvVals );    
  307. }
  308.  
  309. /*
  310.  * The following blocks of code are related to the redirection of output to
  311.  * AppleEvents.
  312.  */
  313.  
  314. static char        outBuf[AE_OUTBUF_SIZE];
  315. static int        outBufLen = -1;
  316.  
  317. void InitOutBuffer( void )
  318. {
  319.         outBufLen = 0;
  320. }
  321.  
  322. void SendOutBuffer( char outputDone )
  323. {
  324.     if( outBufLen )
  325.     {
  326.         AEPutParamPtr(
  327.             &gResponseEvent,
  328.             keyDirectObject, 
  329.             typeChar,
  330.             outBuf,
  331.             outBufLen);
  332.     }
  333.     if( outputDone )
  334.     {
  335.         AEPutParamPtr(
  336.             &gResponseEvent,
  337.             'DONE', 
  338.             typeChar,
  339.             "DONE",
  340.             4);
  341.     }
  342.     AESend(
  343.         &gResponseEvent,
  344.         &gResponseReplyEvent,
  345.         kAEWaitReply+kAENeverInteract,
  346.         kAENormalPriority,
  347.         kNoTimeOut,
  348.         nil, nil);
  349. }
  350.  
  351. /*
  352.  * The following three routines override the "real thing" from the CW
  353.  * SIOUX library in order to divert output to AppleEvents.
  354.  */
  355.  
  356. short
  357. InstallConsole(short fd)
  358. {
  359.     if (outputMode == outToFile)
  360.     return 0;
  361.  
  362.     AECreateAppleEvent ('MCVS', 'DATA',
  363.             &gResponseAddress,
  364.             kAutoGenerateReturnID,
  365.             kAnyTransactionID, 
  366.             &gResponseEvent);
  367.  
  368.     return 0;
  369. }
  370.  
  371. long WriteCharsToConsole( char *buf, long length )
  372. {
  373.     char        *tCh;
  374.     
  375.     if( outputMode == outToFile )
  376.     {
  377.         write( outputFile, buf, length );
  378.         return length;
  379.     }
  380.     
  381.     if( outBufLen == -1 ) InitOutBuffer();
  382.     
  383.     if( (length + outBufLen) > AE_OUTBUF_SIZE )
  384.     {
  385.         SendOutBuffer( FALSE );
  386.         InitOutBuffer();
  387.     }
  388.     
  389.     for( tCh = buf; tCh < (char *) (buf+length); tCh++ )
  390.     {
  391.         if( *tCh == '\012' ) *tCh = '\015';
  392.         
  393.         outBuf[outBufLen] = *tCh;
  394.         outBufLen++;
  395.     }
  396.     
  397.     if( noLineBuffer && ( *(buf+length) == '\015') )
  398.     {
  399.         SendOutBuffer( FALSE );
  400.         InitOutBuffer();
  401.     }
  402.     
  403.     return length;
  404. }
  405.  
  406. void RemoveConsole( void )
  407. {
  408.     CleanUpArgsAndEnv();
  409.     
  410.     if( outputMode == outToFile )
  411.     {
  412.         close(outputFile);
  413.         if( rename(tempOutputFileName, outputFileName) != 0 )
  414.             SysBeep( 100 );
  415.         return;
  416.     }
  417.     
  418.     SendOutBuffer( TRUE );
  419.  
  420.     AEDisposeDesc( &gResponseEvent );
  421.     AEDisposeDesc( &gResponseAddress );
  422. }
  423. #endif // AE_IO_HANDLERS
  424.