home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / jump10.zip / jump.c < prev    next >
C/C++ Source or Header  |  1994-12-14  |  20KB  |  657 lines

  1. #pragma strings(readonly)
  2.  
  3. #define INCL_VIO            // VIO calls
  4. #define INCL_DOSFILEMGR     // File Management
  5. #define INCL_DOSMISC        // Miscellaneous
  6. #define INCL_DOSMODULEMGR   // Module manager
  7. #define INCL_DOSSESMGR      // Session Manager Support
  8. #define INCL_DOSPROCESS     // Process and thread support
  9. #define INCL_DOSQUEUES      // Queues
  10. #define INCL_DOSDATETIME    // Date/Time and Timer support
  11. #define INCL_DOSSEMAPHORES  // Semaphore support
  12. #define INCL_DOSMEMMGR      // Memory Management
  13.  
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <io.h>
  18. #include <os2.h>
  19.  
  20.  
  21. // #define PRELOAD      // if PRELOAD is defined, preloading is compiled
  22.  
  23.  
  24. #ifdef __EMX__
  25.  
  26. #ifndef __OS2_H__       // only if EMX doesn't use IBM's Toolkit:
  27. #define MY_PSZ PCSZ     // EMX prototype of DosScanEnv uses: const PSZ
  28. #endif
  29.  
  30. #ifdef PRELOAD
  31. USHORT _THUNK_FUNCTION (DosQProcStat) (PVOID, USHORT);
  32. void DosQProcStatus (PVOID pBuf, ULONG cbBuf)
  33.   {
  34.     _THUNK_PASCAL_PROLOG (6);
  35.     _THUNK_PASCAL_FLAT (pBuf);
  36.     _THUNK_PASCAL_SHORT (cbBuf);
  37.     _THUNK_PASCAL_CALL (DosQProcStat);
  38.   }
  39. #endif
  40.  
  41. #else                       
  42.  
  43. #define MY_PSZ PSZ      // other compilers' prototype of DosScanEnv: PSZ
  44.  
  45. #ifdef PRELOAD
  46. USHORT APIENTRY16 DosQProcStatus(PVOID pBuf, USHORT cbBuf);
  47. #endif
  48.  
  49. #endif
  50.  
  51. #ifdef PRELOAD
  52. #define PTR(ptr, ofs)  ((void *) ((char *) (ptr) + (ofs)))
  53. #endif
  54.  
  55. #define PIPESIZE 256        // size of the unnamed pipe
  56. #define BUFFERSIZE 0x10000  // size of buffered output
  57. #define PRINT_INTERVAL 32   // output every 32 ms
  58. #define BUFFER1k 1024       // length of 1kb buffer
  59. #define BUFFER4k 4096       // length of 4kb buffer
  60. #define TSTACK 16384        // stack size for thread
  61. #define PRINTPRIO 3         // print thread priority 3 (timecritical)
  62.  
  63. static char *cmdline;       // commandline
  64. static char *ShellPrg;      // command interpreter, i.e. "C:\OS2\CMD.EXE"
  65. static char *ShellArg;      // "/C <commandline>" or parameters from env-var
  66. static BYTE *Buffer;        // output buffer
  67. static BYTE *BufferPos;     // position of next free byte in output buffer
  68. static BYTE *Screen;        // buffer for screen
  69. static int SWidth;          // screen width
  70. static int SHeight;         // screen height
  71. static int SLength;         // length of the screen in bytes (width*height)
  72. static HSEM  OutputSem;     // event semaphore: output screen
  73. static HMTX  BufferSem;     // mutex semaphore: buffer access
  74. static HFILE SaveStdout;    // saved stdout
  75. static HFILE SaveStderr;    // saved stderr
  76. static HFILE hpR;           // read handle of unnamed pipe
  77. static HFILE hpW;           // write handle of unnamed pipe
  78. static HFILE NewStdout;     // new stdout
  79. static HFILE NewStderr;     // new stderr
  80. static HTIMER TimerHandle;  // timer to output screen every x ms
  81. static BOOL ExitThread;     // output thread exits if TRUE
  82. static USHORT row;          // current cursor row
  83. static USHORT col;          // current cursor column
  84. static BOOL NormalMode;     // TRUE: write to stdout; FALSE: jump-scroll
  85.  
  86.  
  87. #ifdef PRELOAD
  88. #pragma pack(1)
  89.  
  90. struct Procstat
  91.   {
  92.   ULONG  summary;       /* global data area                     */
  93.   ULONG  processes;     /* process data area                    */
  94.   ULONG  semaphores;    /* semaphore data area (not used)       */
  95.   ULONG  unknown1;
  96.   ULONG  sharedmemory;  /* shared memory data area (not used)   */
  97.   ULONG  modules;       /* module handle                        */
  98.   ULONG  unknown2;
  99.   ULONG  unknown3;
  100.   };
  101.  
  102. struct Process
  103.   {
  104.   ULONG  type;          /* process: 1                           */
  105.   ULONG  threadlist;    /* -> to 1st thread struct              */
  106.   USHORT pid;           /* process ID                           */
  107.   USHORT ppid;          /* parent process ID                    */
  108.   ULONG  styp;          /* session type                         */
  109.   ULONG  status;        /* process status                       */
  110.   ULONG  sgroup;        /* screen group                         */
  111.   USHORT handle;        /* module handle                        */
  112.   USHORT threads;       /* # of thread control blocks           */
  113.   ULONG  time;
  114.   ULONG  reserved2;
  115.   USHORT sems;          /* # of semaphores used                 */
  116.   USHORT libs;          /* # of libraries                       */
  117.   USHORT mem;           /* # of shared memory handles           */
  118.   USHORT reserved3;
  119.   ULONG  psem;
  120.   ULONG  plib;
  121.   ULONG  pmem;
  122.   };
  123.  
  124. struct Thread
  125.   {
  126.   ULONG  type;          /* Thread: 100                          */
  127.   USHORT tid;           /* Thread ID                            */
  128.   USHORT tsysid;        /* other Thread ID (?)                  */
  129.   ULONG  blockid;       /* id thread is "sleeping" on           */
  130.   ULONG  priority;      /* Thread priority                      */
  131.   ULONG  systime;       /* thread system time                   */
  132.   ULONG  usertime;      /* thread user time                     */
  133.   UCHAR  status;
  134.   UCHAR  unused1;
  135.   USHORT unused2;
  136.   };
  137.  
  138. struct Procstat *procstat;
  139.  
  140. #endif
  141.  
  142.  
  143. //  Error - abort program with an error message
  144. //
  145. //  code:    display specific message if != 0 (input)
  146. //  apicode: display system error message if != 0 (input)
  147.  
  148. static void Error (int code, int apicode)
  149.   {
  150.     switch(code)
  151.       {
  152.         case  0 : break;
  153.         case  1 : printf("JUMP_SHELL, OS2_SHELL and COMSPEC not set\n"); break;
  154.         case  2 : printf("don't redirect JUMP's help!\n"); break;
  155.         case  3 : printf("QueryModuleName (%i): ",apicode); break;
  156.         case  4 : printf("ExecPgm (%i): ",apicode); break;
  157.         case  5 : printf("CreatePipe (%i): ",apicode); break;
  158.         case  6 : printf("Read (%i): ",apicode); break;
  159.         case  7 : printf("StartTimer (%i): ",apicode); break;
  160.         case  8 : printf("CreateEventSem (%i): ",apicode); break;
  161.         case  9 : printf("CreateThread (%i): ",apicode); break;
  162.         case 10 : printf("CreateMutexSem (%i): ",apicode); break;
  163.         case 11 : printf("malloc: not enough memory\n"); break;
  164.         case 12 : printf("RequestMutexSem (%i): ",apicode); break;
  165.         case 13 : printf("ReleaseMutexSem (%i): ",apicode); break;
  166.         case 14 : printf("AllocMem (%i): ",apicode); break;
  167.         case 15 : printf("Close (%i): ",apicode); break;
  168.         case 16 : printf("DupHandle (%i): ",apicode); break;
  169.         case 17 : printf("Write (%i): ",apicode); break;
  170.         case 18 : printf("Close (%i): ",apicode); break;
  171.         default : printf("(unknown code: %i)\n",code);
  172.       }
  173.  
  174.     if (apicode)
  175.       {
  176.         char Msg[BUFFER1k];
  177.         ULONG Msg_Len=0;
  178.         DosGetMessage(NULL,0,Msg,sizeof(Msg),apicode,"OSO001.MSG",&Msg_Len);
  179.         Msg[Msg_Len]='\0';
  180.         printf("%s\n",Msg);
  181.       }
  182.     exit(code);
  183.   }
  184.  
  185.  
  186. //  GetOs2Shell - search environment variables and command line for
  187. //                command interpreter file name and arguments
  188. //
  189. //  direct: parameters from command line (input)
  190. //  *prg:   command interpreter exe file name (output)
  191. //  *arg:   shell arguments (output)
  192.  
  193. static void GetOs2Shell (char *direct, char **prg, char **arg)
  194.   {
  195.     APIRET rc;
  196.     PSZ Os2Shell;
  197.     char *p;
  198.  
  199.     // get environment variable: i.e. "C:\OS2\CMD.EXE /k set prompt="
  200.  
  201.     if (DosScanEnv("JUMP_SHELL",(MY_PSZ *)&Os2Shell))
  202.       if (DosScanEnv("OS2_SHELL",(MY_PSZ *)&Os2Shell))
  203.         if ((rc=DosScanEnv("COMSPEC",(MY_PSZ *)&Os2Shell)))
  204.           Error(1,rc);
  205.  
  206.     // divide EXE file name and parameters:
  207.     // i.e. *prg="C:\OS2\CMD.EXE", *arg="/k set prompt="
  208.  
  209.     if ((*prg=malloc(strlen(Os2Shell)+1))==NULL)
  210.       Error(11,0);
  211.     strcpy(*prg,Os2Shell);
  212.     if ((p=strchr(*prg,' ')))
  213.       {
  214.         *p++='\0';  // terminate EXE file name
  215.         *arg=p;     // next byte: parameters
  216.       }
  217.     else
  218.       *arg=Os2Shell+strlen(Os2Shell);   // no parameters, ptr to "\0"
  219.  
  220.     // if command line parameters exist, use them instead, prepend "/C "
  221.  
  222.     if (direct && direct[0]!='\0')
  223.       {
  224.         if ((*arg=malloc(strlen(direct)+4))==NULL)
  225.           Error(11,0);
  226.         strcpy(*arg,"/C ");
  227.         strcat(*arg,direct);
  228.       }
  229.   }
  230.  
  231.  
  232. //  RedirectOs2Shell - save stdout/stderr, redirect to unnamed pipe
  233. //
  234.  
  235. static void RedirectOs2Shell (void)
  236.   {
  237.     APIRET rc;
  238.  
  239.     SaveStdout=-1;                          // allocate new handle
  240.     if ((rc=DosDupHandle(1,&SaveStdout)))   // SaveStdout: dup of stdout
  241.       Error(16,rc);
  242.     SaveStderr=-1;                          // allocate new handle
  243.     if ((rc=DosDupHandle(2,&SaveStderr)))   // SaveStderr: dup of stderr
  244.       Error(16,rc);
  245.  
  246.     if ((rc=DosCreatePipe(&hpR,&hpW,PIPESIZE)))
  247.       Error(5,rc);
  248.  
  249.     NewStdout=1;                            // stdout handle
  250.     if ((rc=DosDupHandle(hpW,&NewStdout)))  // Write-Pipe is alias of stdout
  251.       Error(16,rc);
  252.     NewStderr=2;                            // stderr handle
  253.     if ((rc=DosDupHandle(hpW,&NewStderr)))  // Write-Pipe is alias of stderr
  254.       Error(16,rc);
  255.   }
  256.  
  257.  
  258. //  RestoreRedirection stdout/stderr are restored
  259.  
  260. static void RestoreRedirection (void)
  261.   {
  262.     APIRET rc;
  263.     if ((rc=DosClose(hpW)))
  264.       Error(15,rc);
  265.     if ((rc=DosDupHandle(SaveStdout,&NewStdout)))   // stdout alias of old one
  266.       Error(16,rc);
  267.     if ((rc=DosDupHandle(SaveStderr,&NewStderr)))   // stderr alias of old one
  268.       Error(16,rc);
  269.   }
  270.  
  271.  
  272. //  EndRedirection - close unneeded file handles
  273.  
  274. static void EndRedirection (void)
  275.   {
  276.     APIRET rc;
  277.  
  278.     if ((rc=DosClose(hpR)))
  279.       Error(18,rc);
  280.     if ((rc=DosClose(SaveStdout)))
  281.       Error(18,rc);
  282.     if ((rc=DosClose(SaveStderr)))
  283.       Error(18,rc);
  284.   }
  285.  
  286.  
  287. //  StartOs2Shell - start command interpreter
  288.  
  289. static void StartOs2Shell (char *prg, char *arg, ULONG exeflags)
  290.   {
  291.     CHAR ObjNameBuf[CCHMAXPATH];
  292.     CHAR ArgPointer[BUFFER4k];
  293.     RESULTCODES ReturnCodes;
  294.     APIRET rc;
  295.  
  296.     // create argument buffer:
  297.     // i.e.  C:\OS2\CMD.EXE\0/C dir\0\0
  298.  
  299.     strcpy(ArgPointer,prg);
  300.     strcpy(ArgPointer+strlen(prg)+1,arg);
  301.     ArgPointer[strlen(prg)+1+strlen(arg)+1]='\0';
  302.  
  303.     if ((rc=DosExecPgm((PUCHAR)&ObjNameBuf,sizeof(ObjNameBuf),exeflags,
  304.                        (PUCHAR)&ArgPointer,NULL,&ReturnCodes,prg)))
  305.       {
  306.         RestoreRedirection();
  307.         EndRedirection();
  308.         Error(4,rc);
  309.       }
  310.   }
  311.  
  312.  
  313. //  ReadScreen - read cursor position and screen contents
  314.  
  315. static void ReadScreen (void)
  316.   {
  317.     USHORT Length=SLength;
  318.     VioReadCharStr((PCH)Screen,&Length,0,0,0);
  319.     VioGetCurPos(&row,&col,0);
  320.   }
  321.  
  322.  
  323. //  WriteScreen - set cursor position and write screen
  324.  
  325. static void WriteScreen (void)
  326.   {
  327.     VioSetCurPos(row,col,0);
  328.     VioWrtCharStr(Screen,SLength,0,0,0);
  329.   }
  330.  
  331.  
  332. static void PrintBuffer (void)
  333.   {
  334.     APIRET rc;
  335.     BYTE *p;
  336.     BYTE *q;
  337.     BYTE c;
  338.     ULONG bw;
  339.  
  340.     if (BufferPos==Buffer)  // exit if nothing to print
  341.       return;
  342.  
  343.     if ((rc=DosRequestMutexSem(BufferSem,SEM_INDEFINITE_WAIT)))
  344.       Error(12,rc);
  345.  
  346.     ReadScreen();   // read the screen
  347.     p=Buffer;       // point to beginning of output buffer
  348.  
  349.     while (p<BufferPos)     // while there are character to process
  350.       switch ((c=*p++))     // c: next character
  351.         {
  352.           case  7 : DosBeep(440,50);                    // BEL: just beep
  353.                     break;
  354.  
  355.           case  8 : if (col>0)                          // BS: backspace
  356.                       Screen[row*SWidth+(--col)]=' ';
  357.                     break;
  358.  
  359.           case  9 : WriteScreen();                      // TAB
  360.                     if ((rc=DosWrite(1,"\t",1,&bw)) || bw!=1)
  361.                       Error(17,rc);
  362.                     ReadScreen();
  363.                     break;
  364.  
  365.           case 10 : row++;                              // LF: line feed
  366.                     if (row>=SHeight)
  367.                       {
  368.                         row--;
  369.                         memcpy(Screen,Screen+SWidth,SLength-SWidth);
  370.                         memset(&Screen[SLength-SWidth],' ',SWidth);
  371.                       }
  372.                     break;
  373.  
  374.           case 13 : col=0;                              // CR: carriage return
  375.                     break;
  376.  
  377.           case 27 :                                     // ESC: ANSI codes
  378.  
  379.                     if (p>=BufferPos)   // premature end of buffer?
  380.                       break;
  381.  
  382.                     if (*p != '[')      // no ESC[ ANSI sequence?
  383.                       break;
  384.  
  385.                     p++;    // p ptr behind ESC[
  386.                     q=p-2;  // q ptr to ESC-sequence
  387.  
  388.                     while (p<BufferPos) // as long as there are more chars
  389.                       {
  390.                         c=*p++;
  391.  
  392.                         if (c=='"' || c=='`' || c=='\'')
  393.                           {
  394.                             while (p<BufferPos && *p!=c)
  395.                               p++;
  396.                             if (p<BufferPos)  // matching '"' found
  397.                               p++;
  398.                           }
  399.                         else
  400.                           if ((c<'0' || c>'9') && c!=';') // command char?
  401.                             break;
  402.                       }
  403.  
  404.                     WriteScreen();
  405.                     if ((rc=DosWrite(1,q,p-q,&bw)) || bw!=p-q)
  406.                       Error(17,rc);
  407.                     ReadScreen();
  408.                     break;
  409.  
  410.           default : Screen[row*SWidth+col]=c;           // other character
  411.                     if (++col>=SWidth)
  412.                       {
  413.                         col=0;
  414.                         row++;
  415.                         if (row>=SHeight)
  416.                           {
  417.                             row--;
  418.                             memcpy(Screen,Screen+SWidth,SLength-SWidth);
  419.                             memset(&Screen[SLength-SWidth],' ',SWidth);
  420.                           }
  421.                       }
  422.         }
  423.  
  424.     WriteScreen();
  425.     BufferPos=Buffer;
  426.  
  427.     if ((rc=DosReleaseMutexSem(BufferSem)))
  428.       Error(13,rc);
  429.   }
  430.  
  431.  
  432. static void InitBuffers (void)
  433.   {
  434.     APIRET rc;
  435.  
  436.     if (NormalMode)
  437.       return;
  438.     if ((Buffer=malloc(BUFFERSIZE))==NULL)
  439.       Error(11,0);
  440.     BufferPos=Buffer;
  441.     if ((rc=DosCreateMutexSem(NULL,&BufferSem,0,FALSE)))
  442.       Error(10,rc);
  443.   }
  444.  
  445.  
  446. static void FlushBuffers (void)
  447.   {
  448.     if (NormalMode)
  449.       return;
  450.     DosStopTimer(TimerHandle);
  451.     ExitThread=TRUE;
  452.     DosPostEventSem((HEV)OutputSem);
  453.     PrintBuffer();
  454.   }
  455.  
  456.  
  457. static void ProcessRedirection (void)
  458.   {
  459.     ULONG br;
  460.  
  461.     do
  462.       {
  463.         APIRET rc;
  464.         char PipeBuffer[PIPESIZE];
  465.  
  466.         if ((rc=DosRead(hpR,(PVOID)&PipeBuffer,PIPESIZE,&br)))
  467.           Error(6,rc);
  468.         if (br)
  469.           if (!NormalMode)
  470.             {
  471.               if ((rc=DosRequestMutexSem(BufferSem,SEM_INDEFINITE_WAIT)))
  472.                 Error(12,rc);
  473.               memcpy(BufferPos,PipeBuffer,br);
  474.               BufferPos+=br;
  475.               if ((rc=DosReleaseMutexSem(BufferSem)))
  476.                 Error(13,rc);
  477.               if (BufferPos-Buffer>BUFFERSIZE-2*PIPESIZE)
  478.                 PrintBuffer();
  479.             }
  480.           else
  481.             {
  482.               ULONG bw;
  483.               if ((rc=DosWrite(1,(PVOID)&PipeBuffer,br,&bw)) || bw!=br)
  484.                 Error(17,rc);
  485.             }
  486.       }
  487.     while (br);
  488.   }
  489.  
  490.  
  491. static void PrintThread (void *dummy)
  492.   {
  493.     ULONG PostCount;
  494.  
  495.     DosSetPriority(PRTYS_THREAD,PRINTPRIO,0,0);
  496.  
  497.     while (!ExitThread)
  498.       {
  499.         DosWaitEventSem((HEV)OutputSem,SEM_INDEFINITE_WAIT);
  500.         DosResetEventSem((HEV)OutputSem,&PostCount);
  501.         PrintBuffer();
  502.       }
  503.   }
  504.  
  505.  
  506. static void InitTimers (void)
  507.   {
  508.     APIRET rc;
  509.     TID tid;
  510.  
  511.     if (NormalMode)
  512.       return;
  513.     if ((rc=DosCreateEventSem(NULL,(PHEV)&OutputSem,DC_SEM_SHARED,FALSE)))
  514.       Error(8,rc);
  515.     if ((rc=DosStartTimer(PRINT_INTERVAL,OutputSem,&TimerHandle)))
  516.       Error(7,rc);
  517.     ExitThread=FALSE;
  518.     if ((rc=DosCreateThread(&tid,(PFNTHREAD)&PrintThread,0,0,TSTACK)))
  519.       Error(9,rc);
  520.   }
  521.  
  522.  
  523. static void InitVideo (void)
  524.   {
  525.     VIOMODEINFO mi;
  526.  
  527.     if (NormalMode)
  528.       return;
  529.     mi.cb=sizeof(VIOMODEINFO);
  530.     VioGetMode(&mi,0);
  531.     SWidth=mi.col;
  532.     SHeight=mi.row;
  533.     SLength=SWidth*SHeight;
  534.     if ((Screen=malloc(SLength))==NULL)
  535.       Error(11,0);
  536.   }
  537.  
  538.  
  539. #ifdef PRELOAD
  540. static BOOL Preloaded (void)
  541.   {
  542.     APIRET rc;
  543.     struct Process *proc;
  544.     UCHAR name[CCHMAXPATH];
  545.  
  546.     if ((rc=DosAllocMem((PPVOID)&procstat,0xF000,
  547.             PAG_COMMIT|OBJ_TILE|PAG_READ|PAG_WRITE)))
  548.       Error(14,rc);
  549.     DosQProcStatus(procstat,0xF000);
  550.  
  551.     for (proc=PTR(procstat->processes,0);  proc->type!=3;
  552.          proc=PTR(proc->threadlist, proc->threads*sizeof(struct Thread)))
  553.       if ( proc->type == 1 &&
  554.            proc->ppid == 0 &&
  555.            proc->sems == 0 &&
  556.            proc->threads == 1 &&
  557.            DosQueryModuleName(proc->handle, sizeof(name), name) == 0 &&
  558.            strlen(name) >= 8 )
  559.         {
  560.           UCHAR *p = &name[strlen(name)-8];
  561.           int i;
  562.           for (i=0; i<=7; i++)
  563.             if (p[i]>='a' && p[i]<='z')
  564.               p[i]-='a'-'A';
  565.           if (strcmp("JUMP.EXE",p)==0)
  566.             return TRUE;
  567.         }
  568.     return FALSE;
  569.   }
  570.  
  571.  
  572. static char *GetLoadPath (void)
  573.   {
  574.     PTIB pptib;
  575.     PPIB pppib;
  576.     char *szPath;
  577.  
  578.     DosGetInfoBlocks(&pptib, &pppib);
  579.     szPath = pppib -> pib_pchenv;
  580.     while (*szPath)
  581.        szPath = (char *) strchr(szPath, 0) + 1;
  582.     return szPath + 1;
  583.   }
  584. #endif
  585.  
  586.  
  587. static void GetCmdLine (int argc, char *argv[], char **cline)
  588.   {
  589.     int i;
  590.  
  591.     if ((*cline=malloc(BUFFER1k))==NULL)
  592.       Error(11,0);
  593.     *cline[0]='\0';
  594.  
  595.     for (i=1; i<argc; i++)
  596.       {
  597.         strcat(*cline,argv[i]);
  598.         strcat(*cline," ");
  599.       }
  600.  
  601.     #ifdef PRELOAD
  602.     if (strcmp(*cline,"/PRELOAD ")==0)
  603.       {
  604.         StartOs2Shell(GetLoadPath(),"",EXEC_LOAD);
  605.         exit(0);
  606.       }
  607.     #endif
  608.  
  609.     if ( strcmp(*cline,"/? ")==0 ||
  610.          strcmp(*cline,"/h ")==0 ||
  611.          strcmp(*cline,"/H ")==0 )
  612.       {
  613.         if (NormalMode)
  614.           Error(2,0);
  615.         InitBuffers();
  616.         InitTimers();
  617.         InitVideo();
  618.         sprintf(Buffer,
  619.           "JUMP 1.0 (c) 1994 by Thomas Opheys, all rights reserved\r\n"
  620.           "jump-scroll output of programs using stdout and stderr\r\n"
  621.           "\r\n"
  622.           "usage: %s <command>\r\n"
  623.           "\r\n"
  624.           "JUMP_SHELL, OS2_SHELL, COMSPEC environment variables are\r\n"
  625.           "used to determine the command interpreter to be started.\r\n"
  626.           "\r\n"
  627.           "please send email to opheys@kirk.fmi.uni-passau.de !\r\n"
  628.         , argv[0]);
  629.         BufferPos=Buffer+strlen(Buffer);
  630.         FlushBuffers();
  631.         exit(0);
  632.       }
  633.   }
  634.  
  635.  
  636. int main (int argc, char *argv[])
  637.   {
  638.     NormalMode=(!isatty(1));
  639.     GetCmdLine(argc,argv,&cmdline);
  640.     #ifdef PRELOAD
  641.     if (!Preloaded())
  642.       StartOs2Shell(GetLoadPath(),"/PRELOAD",EXEC_BACKGROUND);
  643.     #endif
  644.     InitBuffers();
  645.     InitTimers();
  646.     InitVideo();
  647.     GetOs2Shell(cmdline, &ShellPrg, &ShellArg);
  648.     RedirectOs2Shell();
  649.     StartOs2Shell(ShellPrg,ShellArg,EXEC_ASYNC);
  650.     RestoreRedirection();
  651.     ProcessRedirection();
  652.     EndRedirection();
  653.     FlushBuffers();
  654.     return 0;
  655.   }
  656.  
  657.