home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume1 / torch / part03 / textmode.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-28  |  9.5 KB  |  415 lines

  1. /*
  2. Copyright 1988 Torch Computers Ltd.
  3.  
  4. Permission to use, copy, modify, and otherwise generally do what you like
  5. with this software is hereby granted provided that the above copyright notice
  6. appears in all copies.
  7.  
  8. Torch disclaims all warranties implied or expressed with regard to this
  9. software.  In no event shall Torch be liable for any damages arising from
  10. this use of software.
  11. */
  12.  
  13. /********************************************************
  14. *                            *
  15. *  Title   Yorn, Gs and Alert                *
  16. *                            *
  17. *  File       : textmode.c                    *
  18. *  Author  : Gary Henderson                *
  19. *  Date       : 26th Sep 1988.                *
  20. *  Purpose : Terminal versions of above programs, in     *
  21. *            connection to server cannot be opened.     *
  22. *                            *
  23. *********************************************************/
  24.  
  25. /*------Include files-----------------------------------*/
  26.  
  27. #include <stdio.h>
  28. #include <signal.h>
  29. #include <errno.h>
  30.  
  31. #if defined(SYSV) || defined(UNISOFTV)
  32. #include <termio.h>
  33. #endif SYSV
  34.  
  35. #ifdef BSD
  36. #include <sgtty.h>
  37. #include <setjmp.h>
  38. #endif BSD
  39.  
  40. /*------Forward delarations-----------------------------*/
  41.  
  42. /*------Constants and macros----------------------------*/
  43.  
  44. /*------Exported variables/functions--------------------*/
  45.  
  46. /*------Imported variables/functions--------------------*/
  47.  
  48. extern int is_gs;
  49. extern int cols, lines;
  50. extern char * progname;
  51. extern int errno;
  52. extern int timeout;
  53. extern void Usage ();
  54.  
  55. /*------Static variables--------------------------------*/
  56.  
  57. static int size_args, title_arg, seconds_arg;
  58.  
  59. static int set = -1;
  60.  
  61. #ifdef SYSV
  62. static int (*old_sig[SIGPWR + 1])();
  63. static struct termio term_settings, term;
  64. #endif SYSV
  65.  
  66. #ifdef UNISOFTV
  67. static int (*old_sig[SIGIO + 1])();
  68. static struct termio term_settings, term;
  69. #endif UNISOFTV
  70.  
  71. #ifdef BSD
  72. static int (*old_sig[SIGUSR2 + 1])();
  73. static struct sgttyb term_settings, term;
  74. static jmp_buf env;
  75. #endif BSD
  76.  
  77. static struct options {
  78.     char * name;
  79.     int args;
  80.     int * addr;
  81. } opts[] = {
  82.     {"-z", 0, 0},
  83.     {"-r", 2, &size_args},
  84.     {"-n", 1, &title_arg},
  85.     {"-t", 1, &seconds_arg},
  86.     {"-display", 1, 0},
  87.     {"-font", 1, 0},
  88.     {"-fn", 1, 0},
  89.     {"-fg", 1, 0},
  90.     {"-bg", 1, 0},
  91. };
  92.  
  93. static int AlarmCall ();
  94. static int alarm_gone_off = 0;
  95. static int ResetTerm ();
  96.  
  97. /*
  98.                             *****************
  99.                             *        *
  100.                             *   TEXTMODE    *
  101.                             *        *
  102.                             *****************
  103. -------------------------------------------------------------------------
  104. | Hmmm, the connection to the X server could not be made.  Just to be    |
  105. | nice, give the user a terminal version of the program he/she asked for|
  106. | (useful if the utility is in a Unix start up shell script and the     |
  107. | the server failed to start up for some reason).                       |
  108. -------------------------------------------------------------------------
  109. */
  110. TextMode (argc, argv)
  111. int argc;
  112. char ** argv;
  113. {
  114.     register struct options * parse;
  115.     int max_arg = 1;
  116.     int i, j;
  117.     char c;
  118.  
  119.     /* Parse options (the toolkit can't parse them without a connection to
  120.        the server */
  121.     
  122.     for (i = 1; i < argc; i++)
  123.         for (j = 0, parse = opts; j < sizeof (opts) / sizeof (opts[0]); 
  124.                                                             j++, parse++)
  125.         if (strcmp (parse->name, argv[i]) == 0)
  126.         {
  127.             if (i + parse->args >= argc)
  128.             Usage ();
  129.  
  130.         if (i + parse->args + 1 >= max_arg)
  131.             max_arg = i + parse->args + 1;
  132.  
  133.         if (parse->addr)
  134.             *(parse->addr) = i + 1;
  135.  
  136.         i += parse->args;
  137.  
  138.         break;
  139.         }
  140.  
  141.     if ((is_gs && argc - max_arg < 1) || (!is_gs && argc - max_arg < 2))
  142.         Usage ();
  143.  
  144.     if (is_gs)
  145.     {
  146.     /* We are called 'gs', so act like gs.  Print out the title and 
  147.        the message... */
  148.     if (title_arg)
  149.         (void) fprintf (stderr, "\t%s\n", argv[title_arg]);
  150.  
  151.     for (i = max_arg; i < argc; i++)
  152.         (void) fprintf (stderr, "%s ", argv[i]);
  153.  
  154.     (void) fprintf (stderr, "\n");
  155.  
  156.     /* ...find out if a timeout is required... */
  157.     
  158.     if (!seconds_arg || sscanf (argv[seconds_arg], "%d", &timeout) != 1 ||
  159.         timeout < 1)
  160.         timeout = 0;
  161.         
  162.     /* ...and the size of the reply from the user. */
  163.     
  164.     if (size_args)
  165.     {
  166.         if (sscanf (argv[size_args], "%d", &cols) != 1 ||
  167.             sscanf (argv[size_args + 1], "%d", &lines) != 1)
  168.  
  169.             cols = lines = 0;
  170.     }
  171.     else
  172.         cols = lines = 0;
  173.  
  174.     if (cols * lines <= 0)
  175.     {
  176.         /* Negative or zero length reply required from user.  If there's
  177.            a timeout wait for it to go off, otherwise... */
  178.         if (timeout)
  179.         {
  180.             (void) signal (SIGALRM, AlarmCall);
  181.             (void) alarm ((unsigned int) timeout);
  182.             
  183.         while (!alarm_gone_off)
  184.             pause ();
  185.         }
  186.         else
  187.         {
  188.             /* ...ask the user to press RETURN */
  189.         
  190.         (void) fprintf (stderr, "(Press RETURN to continue)");
  191.         (void) fflush (stderr);
  192.             
  193.         do
  194.             {
  195.             } while (((j = read (0, &c, 1)) == -1 && errno == EINTR) ||
  196.                      (j == 1 && c != '\n')); 
  197.         }
  198.         
  199.         exit (0);
  200.     }
  201.     
  202.     /* A positive length reply is required from the user, ask for one... */
  203.  
  204.     i = 0;
  205.  
  206.     (void) fprintf (stderr, "(Please type in your reply and press RETURN)\n\
  207. \nEnter> ");
  208.     (void) fflush (stderr);
  209.     
  210.     /* ...set a timer going if a timeout is required... */
  211.     
  212.     if (timeout)
  213.     {
  214.         (void) signal (SIGALRM, AlarmCall);
  215.         (void) alarm ((unsigned int) timeout);
  216.     }
  217.     
  218. #ifdef BSD
  219.         if (setjmp (env) == 0)
  220.     {
  221. #endif BSD
  222.         /* ...and read in the reply and send it to stdout. */
  223.     
  224.     do
  225.     {
  226.         do
  227.         {
  228.             } while (!alarm_gone_off && ((j = read (0, &c, 1)) == -1 && 
  229.                                                         errno == EINTR));
  230.         if (j == 1 && i++ < cols * lines && c != '\n')
  231.             (void) putchar (c);
  232.  
  233.     } while (j == 1 && c != '\n' && !alarm_gone_off);
  234. #ifdef BSD
  235.     }
  236. #endif BSD    
  237.  
  238.     if (i)
  239.         (void) printf ("\n");
  240.         
  241.     exit (0);
  242.     }
  243.  
  244.     /* Yorn or alert.  Print out the message... */
  245.     
  246.     (void) printf ("\t%s\n", argv[max_arg]);
  247.     
  248.     for (i = max_arg + 1; i < argc; i++)
  249.         (void) printf ("%s ", argv[i]);
  250.  
  251.     if (strcmp ("alert", progname) == 0)
  252.     {
  253.         /* ...if we are alert, ask the user to press RETURN when he/she has
  254.        read the message... */
  255.        
  256.     (void) printf ("\07\n(Press RETURN to continue) ");
  257.         
  258.     (void) fflush (stdout);
  259.     
  260.     do
  261.     {
  262.     } while (((j = read (0, &c, 1)) == -1 && errno == EINTR) ||
  263.                  (j == 1 && c != '\n')); 
  264.  
  265.     exit (0);
  266.     }
  267.     else
  268.     {
  269.         /* ...otherwise must be yorn.  Trap most signals (so the terminal state
  270.        can be reset before we get killed off)... */
  271.        
  272.     (void) printf ("(y/n) ");
  273.  
  274.     (void) fflush (stdout);
  275.     
  276.     for (i = SIGHUP; i < SIGALRM; i++)
  277.         old_sig[i] = signal (i, ResetTerm);
  278.  
  279. #ifdef SYSV
  280.         for (i = SIGTERM; i <= SIGPWR; i++)
  281.         old_sig[i] = signal (i, ResetTerm);
  282. #endif SYSV
  283.  
  284. #ifdef UNISOFTV
  285.         for (i = SIGTERM; i <= SIGIO; i++)
  286.         old_sig[i] = signal (i, ResetTerm);
  287. #endif UNISOFTV
  288.  
  289.     /* ...fiddle the terminal to give one key press at a time and convert
  290.        upper-case to lower-case... */
  291.  
  292. #if defined(SYSV) || defined(UNISOFTV)
  293.     if ((set = ioctl (0, TCGETA, &term_settings)) == 0)
  294.     {
  295. #ifdef UNISOFTV
  296.         blt ((char *) &term, (char *) &term_settings, 
  297.                                                 sizeof (struct termio));
  298. #else
  299.         (void) memcpy ((char *) &term, (char *) &term_settings, 
  300.                                                 sizeof (struct termio));
  301. #endif UNISOFTV
  302.  
  303.         term.c_lflag &= ~ICANON;
  304.         term.c_iflag |= IUCLC;
  305.         
  306.         term.c_cc[4] = 1;
  307.         term.c_cc[5] = 255;
  308.  
  309.         (void) ioctl (0, TCSETA, &term);
  310.     }
  311. #endif SYSV
  312.  
  313. #ifdef BSD
  314.     for (i = SIGTERM; i <= SIGUSR2; i++)
  315.         old_sig[i] = signal (i, ResetTerm);
  316.         
  317.     if ((set = ioctl (0, TIOCGETP, &term_settings)) == 0)
  318.     {
  319.         bcopy ((char *) &term_settings, (char *) &term, 
  320.                                                 sizeof (struct sgttyb));
  321.         term.sg_flags |= CBREAK | LCASE;
  322.  
  323.         (void) ioctl (0, TIOCSETP, &term);
  324.     }
  325. #endif BSD
  326.  
  327.     /* ...wait for a 'y' or and 'n' to be typed... */
  328.     do
  329.     {
  330.     } while (((j = read (0, &c, 1)) == -1 && errno == EINTR) ||
  331.             (j == 1 && c != 'y' && c != 'n'));
  332.  
  333.     /* ...reset the terminal state... */
  334.     
  335.     if (set == 0)
  336.     {
  337. #if defined(SYSV) || defined(UNISOFTV)
  338.         (void) ioctl (0, TCSETA, &term_settings);
  339. #endif SYSV
  340.  
  341. #ifdef BSD
  342.         (void) ioctl (0, TIOCSETN, &term_settings);
  343. #endif BSD
  344.     }
  345.  
  346.     (void) printf ("\n");
  347.     
  348.     /* ...and return 0 or 1 to the calling program depending on which
  349.        key was pressed (return 2 on some sort of error) */
  350.        
  351.     if (c == 'y')
  352.         exit (0);
  353.         else
  354.         if (c == 'n')
  355.             exit (1);
  356.         else
  357.             exit (2);
  358.     }
  359. }
  360.  
  361. /*
  362.                             *****************
  363.                             *        *
  364.                             *   ALARMCALL    *
  365.                             *        *
  366.                             *****************
  367. -------------------------------------------------------------------------
  368. | SIGALRM signal handler.  Used to add a timeout facility to gs.        |
  369. -------------------------------------------------------------------------
  370. */
  371.  
  372. static int AlarmCall ()
  373. {
  374.     alarm_gone_off = 1;
  375.  
  376. #ifdef BSD
  377.     if (env)
  378.         longjmp (env, 1);
  379. #endif BSD    
  380. }
  381.  
  382. /*
  383.                             *****************
  384.                             *        *
  385.                             *  RESETTERM    *
  386.                             *        *
  387.                             *****************
  388. -------------------------------------------------------------------------
  389. | Handler for every other type of signal (that is catchable).  If the     |
  390. | terminal state has been fiddled with, reset it then reset the signal    |
  391. | to its default state and send the signal again.                       |
  392. | Note: The code will work correctly for signals that don't kill the    |
  393.         process (may fix it one day, but it's only a minor problem).    |
  394. -------------------------------------------------------------------------
  395. */
  396.  
  397. static int ResetTerm (sig)
  398. int sig;
  399. {
  400.     if (set == 0)
  401.     {
  402. #if defined(SYSV) || defined(UNISOFTV)
  403.     (void) ioctl (0, TCSETA, &term_settings);
  404. #endif SYSV
  405.  
  406. #ifdef BSD
  407.     (void) ioctl (0, TIOCSETP, &term_settings);
  408. #endif BSD
  409.     }
  410.  
  411.     (void) signal (sig, old_sig[sig]);
  412.  
  413.     (void) kill (getpid (), sig);
  414. }
  415.