home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / doscall.zip / doscall.c next >
C/C++ Source or Header  |  2000-10-15  |  6KB  |  176 lines

  1. /*   get stdout, stderr, and rc from DOS session - theory:       */
  2. /*   1: OS/2 side creates two unique inbound named pipes         */
  3. /*   2: OS/2 side creates a start thread and waits for connect   */
  4. /*   3: start thread starts DOS session and terminates           */
  5. /*   4: DOS session opens named pipes as stdout and stderr       */
  6. /*   5: DOS session spawns whatever DOS program and arguments    */
  7. /*   6: OS/2 side copies pipe input to OS/2 stdout and stderr    */
  8. /*   7: DOS program dies, DOS session gets return code           */
  9. /*   8: DOS session writes NUL + rc to stderr and terminates     */
  10. /*   9: OS/2 side finds rc and uses it as its return code        */
  11. /*   0: any OS/2 errors reported on stderr before termination,   */
  12. /*      any DOS spawn errno reported via pipe with error message */
  13.  
  14. #include  <stddef.h>
  15. #include  <stdio.h>
  16. #include  <stdlib.h>
  17. #include  <string.h>
  18. #include  <process.h>
  19. #include  <io.h>
  20. #include  <fcntl.h>
  21. #define   INCL_NOPMAPI
  22. #define   INCL_BASE
  23. #include  <os2.h>
  24.  
  25. #define   STK       8192
  26. #define   NPL       8192
  27. #ifndef   UNUSED
  28. #define   UNUSED(x) (void)(x)
  29. #endif
  30. #define   EMSG( x ) emsg( x, __LINE__ )
  31.  
  32. static    char      PName[] = "\\PIPE\\12345678.DC?";
  33. static    char      OsMsg[ 132 ];
  34. static    char      Stack[ STK *3 ];    /* schild, reader+writer */
  35. static    char      RBuff[ NPL ], WBuff[ NPL ];
  36. static    STARTDATA Start;
  37. static    HPIPE     pipe[ 3 ];
  38. static    char *    name;
  39.  
  40. /* ------------------------------------------------------------- */
  41.  
  42. int  emsg( char *msg, int line )
  43. {
  44.      fprintf( stderr, "\n%s (%s %d)\n", name, __FILE__, line );
  45.      if ( msg   ) fprintf( stderr, "\t%s\n", msg );
  46.      if ( errno ) fprintf( stderr, "\t%s\n", strerror( errno ));
  47.      return EXIT_FAILURE;
  48. }
  49. /* ------------------------------------------------------------- */
  50.  
  51. char * SysMsg( APIRET rc )              /* many error codes not  */
  52. {                                       /* decoded in OSO001.MSG */
  53.      ULONG     ulen = 0;                /* e.g. 294, 309, ...    */
  54.  
  55.      if ( DosGetMessage( 0, 0, OsMsg, sizeof OsMsg,
  56.                          rc, "OSO001.msg", &ulen ))
  57.           sprintf( OsMsg, "system error code %d", rc );
  58.      return OsMsg;
  59. }
  60. /* ------------------------------------------------------------- */
  61.  
  62. void schild( void *arg )
  63. {
  64.      APIRET    rc;  int       n = 0;
  65.      ULONG     x;   UNUSED( arg );
  66.  
  67.      Start.Length        = 32;          /* more requires PM (?)  */
  68.      Start.PgmName       = name;        /* start own DOS stub    */
  69.      Start.PgmInputs     = PName;
  70.      Start.Related       = SSF_RELATED_CHILD;
  71.      Start.FgBg          = SSF_FGBG_BACK;
  72.      Start.InheritOpt    = SSF_INHERTOPT_PARENT;
  73.      Start.SessionType   = SSF_TYPE_VDM;
  74.  
  75.      while ( n < 3 )                    /* check handles 0, 1, 2 */
  76.           if ( DosQueryNPHState( pipe[ n ], &x ))
  77.                DosSleep( 0 );           /* if not yet ready wait */
  78.           else ++n;
  79.  
  80.      rc = DosStartSession( &Start, &x, (PID *) &x );
  81.      if ( rc ) DosExit( EXIT_PROCESS, EMSG( SysMsg( rc )));
  82. }
  83. /* ------------------------------------------------------------- */
  84.  
  85. void reader( void *arg )
  86. {
  87.      int       in = 1 + strlen( RBuff );
  88.      APIRET    rc = DosConnectNPipe( pipe[ 0 ] );
  89.      ULONG     uw;   ;        UNUSED( arg );
  90.  
  91.      if ( ! rc ) rc = DosWrite( pipe[ 0 ], &in,    2, &uw );
  92.      if ( ! rc ) rc = DosWrite( pipe[ 0 ], RBuff, in, &uw );
  93.      if ( rc ) DosExit( EXIT_PROCESS, EMSG( SysMsg( rc )));
  94.  
  95.      if ( ! isatty( 0 )) while ( ! rc )
  96.      {
  97.           in = read( 0, RBuff, sizeof RBuff );
  98.           if ( in <= 0 ) break;
  99.           rc = DosWrite( pipe[ 0 ], RBuff, in, &uw );
  100.      }
  101.  
  102.      DosClose( pipe[ 0 ] );   close( 0 );
  103. }
  104. /* ------------------------------------------------------------- */
  105.  
  106. void writer( void *arg )
  107. {
  108.      APIRET    rc = DosConnectNPipe( pipe[ 1 ]);
  109.      ULONG     uw = 1;        UNUSED( arg );
  110.  
  111.      while ( ! rc && uw )
  112.      {
  113.           rc = DosRead( pipe[ 1 ], WBuff, sizeof WBuff, &uw );
  114.           if ( ! rc && uw != write( 1, WBuff, uw ))
  115.                DosExit( EXIT_PROCESS, EMSG( "output lost" ));
  116.      }
  117.      if ( rc ) DosExit( EXIT_PROCESS, EMSG( SysMsg( rc )));
  118. }
  119. /* ------------------------------------------------------------- */
  120.  
  121. int  rundos( TID w )
  122. {
  123.      APIRET    rc = DosConnectNPipe( pipe[ 2 ]);
  124.      ULONG     uw;                      /* ex[ 0 ] = 0 if DOS rc */
  125.      char      ex[ 3 ];  memset( ex, 11, 3 );
  126.  
  127.      while ( ! rc )
  128.      {
  129.           rc = DosRead( pipe[ 2 ], ex +2, 1, &uw );
  130.           if ( rc || ! uw )   break;
  131.           if ( ! memchr( ex, 0, 3 )) fputc( ex[ 2 ], stderr );
  132.           memmove( ex, ex +1, 2 );
  133.      }
  134.      if ( rc ) return EMSG( SysMsg( rc ));
  135.  
  136.      DosWaitThread( &w, DCWW_WAIT );    /* drain writer() thread */
  137.      if ( ex[ 0 ])                      /* char DOS rc after NUL */
  138.           return EMSG( "DOS return code lost" );
  139.      else return (int)(signed char) ex[ 1 ];
  140. }
  141. /* ------------------------------------------------------------- */
  142.  
  143. int  main( int argc, char * argv[] )
  144. {
  145.      APIRET    rc;  TID       s, r, w;  int       n;
  146.  
  147.      name = argv[ 0 ];
  148.  
  149.      sprintf( Stack, "%8.8x", getpid());
  150.      memcpy( PName + 6, Stack, 8 );
  151.  
  152.      if ( argc < 2 )
  153.           return EMSG( "specify DOS program" );
  154.      if ( sizeof RBuff <= strlen( getcmd( Stack )))
  155.           return EMSG( "too many arguments" );
  156.      strcpy( RBuff, Stack );
  157.  
  158.      for ( n = 0; n < 3; ++n )
  159.      {
  160.           PName[ 17 ] = n + '0';
  161.           if ( n )
  162.                rc = DosCreateNPipe( PName, &pipe[ n ],
  163.                               NP_ACCESS_INBOUND , 1, NPL, 0, 1 );
  164.           else rc = DosCreateNPipe( PName, &pipe[ n ],
  165.                               NP_ACCESS_OUTBOUND, 1, 0, NPL, 1 );
  166.           if ( rc ) return EMSG( SysMsg( rc ));
  167.      }
  168.  
  169.      r = _beginthread( reader, Stack + 0 * STK, STK, NULL );
  170.      w = _beginthread( writer, Stack + 1 * STK, STK, NULL );
  171.      s = _beginthread( schild, Stack + 2 * STK, STK, NULL );
  172.      if ( r == -1 || w == -1 || s == -1 )
  173.           return EMSG( SysMsg( _doserrno ));
  174.      else return rundos( w );
  175. }
  176.