home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / clipbrd.zip / clipbrd.c next >
C/C++ Source or Header  |  1993-10-23  |  13KB  |  582 lines

  1. #define USE_OS2_TOOLKIT_HEADERS
  2. #define INCL_DOSERRORS
  3. #define INCL_DOSMEMMGR
  4. #define INCL_DOSPROCESS
  5. #define INCL_DOSQUEUES
  6. #define INCL_DOSSESMGR
  7. #define INCL_WINCLIPBOARD
  8. #include <os2.h>
  9.  
  10. #include <assert.h>
  11. #include <getopt.h>
  12. #include <io.h>
  13. #include <stdarg.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include "common.h"
  18.  
  19. #ifdef __GNUC__
  20. #define NEVER_RETURNS void volatile
  21. #else
  22. #define NEVER_RETURNS void
  23. #endif
  24.  
  25. #define ECHODEF         FALSE
  26. #define OPTSTR          "?acehprwx"
  27. #define PAGESIZE        4096
  28. #define PIPESIZE        (sizeof (ULONG))
  29. #define MAX_BUFSIZE     (64 * 1024 * 1024)
  30. #define EOL             ((char) 26)
  31.  
  32.  
  33. typedef enum
  34.         {
  35.           ACTION_NONE,
  36.           ACTION_APPEND,
  37.           ACTION_CLEAR,
  38.           ACTION_EXECUTE,
  39.           ACTION_PREPEND,
  40.           ACTION_READ,
  41.           ACTION_WRITE
  42.         }
  43.         ACTION;
  44.  
  45. typedef struct
  46.         {
  47.           USHORT SessionID;
  48.           USHORT ResultCode;
  49.         }
  50.         TERMINFO;
  51. typedef TERMINFO *PTERMINFO;
  52.  
  53.  
  54. const CHAR szPMClipboardServer [] = "pmclip.exe";
  55. const CHAR szQueueName [] = "\\QUEUES\\SG\\CLIPBOARD";
  56.  
  57. ACTION action        = ACTION_NONE;
  58.  
  59. BOOL   fEcho         = ECHODEF,
  60.        fClipbrdOpen  = FALSE,
  61.        fDataSet      = FALSE,
  62.        fStdinRedir,
  63.        fStdoutRedir;
  64.  
  65.  
  66. char   *myname       = NULL;
  67.  
  68. HAB    hab           = NULLHANDLE;
  69.  
  70. HFILE  hfRead        = NULLHANDLE,
  71.        hfWrite       = NULLHANDLE;
  72.  
  73. PVOID  pBuf          = NULL,
  74.        pShareBuf     = NULL,
  75.        pClipbrdBuf   = NULL;
  76.  
  77. ULONG  ulBufSize     = 0,
  78.        ulClipbrdSize;
  79.  
  80.  
  81. NEVER_RETURNS panic (const char *format, ...)
  82. {
  83.   va_list arg_ptr;
  84.  
  85.   fprintf (stderr, "%s: ", myname);
  86.   va_start (arg_ptr, format);
  87.   vfprintf (stderr, format, arg_ptr);
  88.   va_end (arg_ptr);
  89.   putc ('\n', stderr);
  90.   exit (EXIT_FAILURE);
  91. }
  92.  
  93. void allocate_buf (void)
  94. {
  95.   APIRET rc;
  96.  
  97.   rc = DosAllocMem (&pBuf, MAX_BUFSIZE, PAG_READ | PAG_WRITE);
  98.   if (rc != NO_ERROR)
  99.     panic ("error %lu on DosAllocMem", (unsigned long) rc);
  100. }
  101.  
  102. void allocate_sharebuf (ULONG ulSize)
  103. {
  104.   APIRET rc;
  105.  
  106.   assert (ulBufSize > 0);
  107.  
  108.   rc = DosAllocSharedMem (&pShareBuf,
  109.                           NULL,
  110.                           ulSize,
  111.                           PAG_COMMIT | OBJ_GIVEABLE |
  112.                           PAG_READ   | PAG_WRITE    );
  113.   if (rc != NO_ERROR)
  114.     panic ("error %lu on DosAllocSharedMem", (unsigned long) rc);
  115.  
  116. }
  117.  
  118. void commit_buf (PVOID pBuf, ULONG ulBufSize)
  119. {
  120.   APIRET rc;
  121.  
  122.   rc = DosSetMem (pBuf,
  123.                   ulBufSize,
  124.                   PAG_COMMIT  |
  125.                   PAG_DEFAULT);
  126.   if (rc != NO_ERROR)
  127.     panic ("error %lu on DosSetMem", (unsigned long) rc);
  128. }
  129.  
  130. void read_buf (void)
  131. {
  132.   APIRET rc;
  133.  
  134.   BOOL   fEol          = FALSE;
  135.  
  136.   PVOID  pReadBuf      = pBuf;
  137.  
  138.   ULONG  ulCommitSize  = PAGESIZE,
  139.          ulReadBufSize,
  140.          ulActual;
  141.  
  142.   assert (pBuf != NULL);
  143.  
  144.   commit_buf (pReadBuf, ulCommitSize);
  145.   do
  146.   {
  147.     ulReadBufSize = ulCommitSize;
  148.  
  149.     do
  150.     {
  151.       rc = DosRead (fileno (stdin),
  152.                     pReadBuf,
  153.                     fStdinRedir ? ulReadBufSize : 1,
  154.                     &ulActual);
  155.       if (rc != NO_ERROR)
  156.         panic ("error %lu on DosRead", (unsigned long) rc);
  157.       if (!fStdinRedir)
  158.         fEol = (*((char *) pReadBuf) == EOL);
  159.  
  160.       pReadBuf += ulActual;
  161.       ulBufSize += ulActual;
  162.       ulReadBufSize -= ulActual;
  163.     } while (ulReadBufSize > 0 && ulActual > 0 && !fEol);
  164.  
  165.     if (ulReadBufSize == 0)
  166.     {
  167.       ulCommitSize <<= 1;
  168.       commit_buf (pReadBuf, ulCommitSize);
  169.     }
  170.   } while (ulActual > 0 && !fEol);
  171.  
  172.   if (fEol)
  173.   {
  174.     assert (ulBufSize > 0);
  175.     ulBufSize--;   /* don't want trailing Ctrl-Z */
  176.   }
  177.  
  178.   if (ulBufSize > 0)
  179.   {
  180.     if (fEcho)
  181.     {
  182.       rc = DosWrite (fileno (stdout),
  183.                      pBuf,
  184.                      ulBufSize - 1,   /* excluding end-zero */
  185.                      &ulActual);
  186.       if (rc != NO_ERROR)
  187.         panic ("error %lu on DosWrite", (unsigned long) rc);
  188.       assert (ulActual == ulBufSize - 1);
  189.     }
  190.  
  191.     pReadBuf = pBuf + ulBufSize - 1;
  192.     if (*((char *) pReadBuf) != '\0')
  193.     {
  194.       *((char *) pReadBuf + 1) = '\0';
  195.       ulBufSize++;
  196.     }
  197.   }
  198. }
  199.  
  200. void open_clipbrd ()
  201. {
  202.   if (!fClipbrdOpen)
  203.   {
  204.     fClipbrdOpen = WinOpenClipbrd (hab);
  205.     if (!fClipbrdOpen)
  206.       panic ("error on WinOpenClipbrd");
  207.   }
  208.  
  209.   assert (fClipbrdOpen);
  210. }
  211.  
  212. void set_clipbrd_data (void)
  213. {
  214.   assert (ulBufSize > 0);
  215.  
  216.   open_clipbrd ();
  217.   fDataSet = WinSetClipbrdData (hab, (ULONG) pShareBuf, CF_TEXT, CFI_POINTER);
  218.   if (!fDataSet)
  219.     panic ("error on WinSetClipbrdData");
  220. }
  221.  
  222. void get_clipbrd_data (void)
  223. {
  224.   APIRET      rc;
  225.  
  226.   BYTE        Priority;
  227.  
  228.   CHAR        szArg [16];
  229.  
  230.   HQUEUE      hqQueue;
  231.  
  232.   PID         pid;
  233.  
  234.   PTERMINFO   pTerminationInfo;
  235.  
  236.   REQUESTDATA Request;
  237.  
  238.   STARTDATA   StartData;
  239.  
  240.   ULONG       ulFormat = 0,   /* WinQueryClipbrdFmtInfo seems to return an */
  241.                               /* USHORT, so we'd better initialize it to 0 */
  242.               ulSessionID,
  243.               ulActual;
  244.  
  245.   if (WinQueryClipbrdFmtInfo (hab, CF_TEXT, &ulFormat))
  246.   {
  247.     assert (ulFormat == CFI_POINTER);
  248.  
  249.     rc = DosCreatePipe (&hfRead, &hfWrite, PIPESIZE);
  250.     if (rc != NO_ERROR)
  251.       panic ("error %lu on DosCreatePipe");
  252.  
  253.     rc = DosCreateQueue (&hqQueue, QUE_FIFO | QUE_CONVERT_ADDRESS, szQueueName);
  254.     if (rc != NO_ERROR)
  255.       panic ("error %lu on DosCreateQueue (%s)", rc, szQueueName);
  256.  
  257.     rc = DosAllocSharedMem (&pClipbrdBuf,
  258.                             NULL,
  259.                             MAX_BUFSIZE,
  260.                             OBJ_GETTABLE |
  261.                             PAG_READ     | PAG_WRITE);
  262.     if (rc != NO_ERROR)
  263.       panic ("error %lu on DosAllocSharedMem", (unsigned long) rc);
  264.  
  265.     StartData.Length =      32;
  266.     StartData.Related =     SSF_RELATED_CHILD;
  267.     StartData.FgBg =        SSF_FGBG_BACK;
  268.     StartData.TraceOpt =    SSF_TRACEOPT_NONE;
  269.     StartData.PgmTitle =    NULL;
  270.     StartData.PgmName =     szPMClipboardServer;
  271.     sprintf (szArg, ARG_FORMAT, LO (pClipbrdBuf), HI (pClipbrdBuf),
  272.                                 LO (hfWrite),     HI (hfWrite));
  273.     StartData.PgmInputs =   szArg;
  274.     StartData.TermQ =       szQueueName;
  275.     StartData.Environment = NULL;
  276.     StartData.InheritOpt =  SSF_INHERTOPT_PARENT;
  277.     StartData.SessionType = SSF_TYPE_PM;
  278.     assert (!fClipbrdOpen);
  279.     rc = DosStartSession (&StartData, &ulSessionID, &pid);
  280.     if (rc != NO_ERROR)
  281.       panic ("%s: error %lu on DosStartSession", szPMClipboardServer, rc);
  282.  
  283.     rc = DosReadQueue (hqQueue,
  284.                        &Request,
  285.                        &ulActual,
  286.                        (PPVOID) &pTerminationInfo,
  287.                        0,
  288.                        DCWW_WAIT,
  289.                        &Priority,
  290.                        NULLHANDLE);
  291.     if (rc != NO_ERROR)
  292.       panic ("error %lu on DosReadQueue", rc);
  293.     assert (Request.ulData == 0 &&
  294.             pTerminationInfo != NULL &&
  295.             pTerminationInfo->SessionID == ulSessionID);
  296.  
  297.     if (pTerminationInfo->ResultCode != EXIT_SUCCESS)
  298.     {
  299.       assert (pTerminationInfo->ResultCode == EXIT_FAILURE);
  300.       DosFreeMem (pTerminationInfo);
  301.       panic ("%s: an error occured", szPMClipboardServer);
  302.     }
  303.     DosFreeMem (pTerminationInfo);
  304.  
  305.     rc = DosRead (hfRead, &ulClipbrdSize, sizeof (ulClipbrdSize), &ulActual);
  306.     if (rc != NO_ERROR)
  307.       panic ("error %lu on DosRead from pipe", rc);
  308.     assert (ulActual == sizeof (ulClipbrdSize));
  309.   }
  310.   else
  311.     panic ("no text in clipboard");
  312. }
  313.  
  314. int clipbrd_append (void)
  315. {
  316.   allocate_buf ();
  317.   read_buf ();
  318.   if (ulBufSize > 0)
  319.   {
  320.     get_clipbrd_data ();
  321.     assert (ulClipbrdSize > 0);
  322.  
  323.     allocate_sharebuf (ulClipbrdSize + ulBufSize - 1);
  324.     memcpy (pShareBuf, pClipbrdBuf, ulClipbrdSize);
  325.     assert (*((char *) pShareBuf + ulClipbrdSize - 1) == '\0');
  326.     memcpy (pShareBuf + ulClipbrdSize - 1, pBuf, ulBufSize);
  327.  
  328.     set_clipbrd_data ();
  329.   }
  330.  
  331.   return EXIT_SUCCESS;
  332. }
  333.  
  334. int clipbrd_clear (void)
  335. {
  336.   open_clipbrd ();
  337.   if (!WinEmptyClipbrd (hab))
  338.     panic ("error on WinClearClipbrd");
  339.  
  340.   return EXIT_SUCCESS;
  341. }
  342.  
  343. int clipbrd_prepend (void)
  344. {
  345.   allocate_buf ();
  346.   read_buf ();
  347.   if (ulBufSize > 0)
  348.   {
  349.     get_clipbrd_data ();
  350.     assert (ulClipbrdSize > 0);
  351.  
  352.     allocate_sharebuf (ulBufSize + ulClipbrdSize - 1);
  353.     memcpy (pShareBuf, pBuf, ulBufSize);
  354.     assert (*((char *) pShareBuf + ulBufSize - 1) == '\0');
  355.     memcpy (pShareBuf + ulBufSize - 1, pClipbrdBuf, ulClipbrdSize);
  356.  
  357.     set_clipbrd_data ();
  358.   }
  359.  
  360.   return EXIT_SUCCESS;
  361. }
  362.  
  363. int clipbrd_read (void)
  364. {
  365.   APIRET rc;
  366.  
  367.   ULONG  ulActual;
  368.  
  369.   get_clipbrd_data ();
  370.  
  371.   rc = DosWrite (fileno (stdout),
  372.                  pClipbrdBuf,
  373.                  ulClipbrdSize - 1,   /* excluding end-zero */
  374.                  &ulActual);
  375.   if (rc != NO_ERROR)
  376.     panic ("error %lu on DosWrite", (unsigned long) rc);
  377.   assert (ulActual == ulClipbrdSize - 1);
  378.  
  379.   return EXIT_SUCCESS;
  380. }
  381.  
  382. int clipbrd_execute (void)
  383. {
  384.   if (fEcho)
  385.     clipbrd_read ();
  386.   else
  387.     get_clipbrd_data ();
  388.   return system ((char *) pClipbrdBuf);
  389. }
  390.  
  391. int clipbrd_write (void)
  392. {
  393.   allocate_buf ();
  394.   read_buf ();
  395.   if (ulBufSize > 0)
  396.   {
  397.     allocate_sharebuf (ulBufSize);
  398.     memcpy (pShareBuf, pBuf, ulBufSize);
  399.     set_clipbrd_data ();
  400.   }
  401.   else
  402.     clipbrd_clear ();
  403.  
  404.   return EXIT_SUCCESS;
  405. }
  406.  
  407. VOID APIENTRY exitfunc (VOID)
  408. {
  409.   if (pShareBuf != NULL && !fDataSet)
  410.     DosFreeMem (pShareBuf);
  411.   if (pBuf != NULL)
  412.     DosFreeMem (pBuf);
  413.   if (pClipbrdBuf != NULL)
  414.     DosFreeMem (pClipbrdBuf);
  415.   if (hfWrite != NULLHANDLE)
  416.     DosClose (hfWrite);
  417.   if (hfRead != NULLHANDLE)
  418.     DosClose (hfRead);
  419.   if (fClipbrdOpen)
  420.   {
  421.     assert (hab != NULLHANDLE);
  422.     WinCloseClipbrd (hab);
  423.   }
  424.   if (hab != NULLHANDLE)
  425.     WinTerminate (hab);
  426.  
  427.   DosExitList (EXLST_EXIT, (PFNEXITLIST) exitfunc);
  428. }
  429.  
  430. NEVER_RETURNS usage (void)
  431. {
  432.   printf ("Usage: %s [-<action>] [-e]\n\n"                                \
  433.           "actions:\n"                                                    \
  434.           "  -c  clear clipboard\n"                                       \
  435.           "  -r  copy clipboard to stdout\n"                              \
  436.           "  -w  copy stdin to clipboard\n"                               \
  437.           "  -a  append stdin to clipboard\n"                             \
  438.           "  -p  prepend stdin to clipboard\n"                            \
  439.           "  -x  execute content of clipboard via cmd.exe\n"              \
  440.           "if no action is specified, then if only stdin is redirected, " \
  441.           "-w is supposed,\n"                                             \
  442.           "else if only stdout is redirected, -r is supposed;\n"          \
  443.           "if both are redirected, -we is supposed.\n\n"                  \
  444.           "  -e  echo stdin to stdout (with -w, -a, -p or -x)\n", myname);
  445.   exit (1);
  446. }
  447.  
  448. void guess_action (void)
  449. {
  450.   assert (action == ACTION_NONE);
  451.  
  452.   if (fStdinRedir && fStdoutRedir)
  453.   {
  454.     action = ACTION_WRITE;
  455.     fEcho = TRUE;
  456.   }
  457.   else if (fStdinRedir)
  458.     action = ACTION_WRITE;
  459.   else if (fStdoutRedir)
  460.     action = ACTION_READ;
  461. }
  462.  
  463. void set_action (ACTION a)
  464. {
  465.   if (action != ACTION_NONE)
  466.     usage ();
  467.   action = a;
  468. }
  469.  
  470.  
  471. int main (int argc, char *argv [])
  472. {
  473.   int opt;
  474.  
  475.   myname       = argv [0];
  476.   fStdinRedir  = !isatty (fileno (stdin));
  477.   fStdoutRedir = !isatty (fileno (stdout));
  478.  
  479.   do
  480.   {
  481.     opt = getopt (argc, argv, OPTSTR);
  482.     switch (opt)
  483.     {
  484.       case 'a' :
  485.  
  486.         set_action (ACTION_APPEND);
  487.         break;
  488.  
  489.       case 'c' :
  490.  
  491.         set_action (ACTION_CLEAR);
  492.         break;
  493.  
  494.       case 'e' :
  495.  
  496.         fEcho = !ECHODEF;
  497.         break;
  498.  
  499.       case 'h' :
  500.  
  501.         opt = '?';
  502.         break;
  503.  
  504.       case 'p' :
  505.  
  506.         set_action (ACTION_PREPEND);
  507.         break;
  508.  
  509.       case 'r' :
  510.  
  511.         set_action (ACTION_READ);
  512.         break;
  513.  
  514.       case 'w' :
  515.  
  516.         set_action (ACTION_WRITE);
  517.         break;
  518.  
  519.       case 'x' :
  520.  
  521.         set_action (ACTION_EXECUTE);
  522.         break;
  523.  
  524.       case '?' :
  525.       case EOF :
  526.  
  527.         break;
  528.  
  529.       default :
  530.  
  531.         assert (FALSE);
  532.     }
  533.   } while (opt != '?' && opt != EOF);
  534.  
  535.   if (action == ACTION_NONE)
  536.     guess_action ();
  537.  
  538.   if (action == ACTION_NONE || opt == '?')
  539.     usage ();
  540.   else
  541.   {
  542.     if (NO_ERROR != DosExitList (EXLST_ADD | ROUTINE_ORDER,
  543.                                  (PFNEXITLIST) exitfunc))
  544.       panic ("error on DosExitList");
  545.  
  546.     if (NULLHANDLE == (hab = WinInitialize (0)))
  547.       panic ("error on WiniInitialize");
  548.  
  549.     switch (action)
  550.     {
  551.       case ACTION_APPEND :
  552.  
  553.         return clipbrd_append ();
  554.  
  555.       case ACTION_CLEAR :
  556.  
  557.         return clipbrd_clear ();
  558.  
  559.       case ACTION_EXECUTE :
  560.  
  561.         return clipbrd_execute ();
  562.  
  563.       case ACTION_PREPEND :
  564.  
  565.         return clipbrd_prepend ();
  566.  
  567.       case ACTION_READ :
  568.  
  569.         return clipbrd_read ();
  570.  
  571.       case ACTION_WRITE :
  572.  
  573.         return clipbrd_write ();
  574.  
  575.       default :
  576.  
  577.         assert (FALSE);
  578.         return EXIT_FAILURE;
  579.     }
  580.   }
  581. }
  582.