home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / EDITOR / NVI179B / NVI179B.ZIP / cl / cl_main.c < prev    next >
C/C++ Source or Header  |  1997-06-29  |  12KB  |  583 lines

  1. /*-
  2.  * Copyright (c) 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  * Copyright (c) 1993, 1994, 1995, 1996
  5.  *    Keith Bostic.  All rights reserved.
  6.  *
  7.  * See the LICENSE file for redistribution information.
  8.  */
  9.  
  10. #include "config.h"
  11.  
  12. #ifndef lint
  13. static const char sccsid[] = "@(#)cl_main.c    10.36 (Berkeley) 10/14/96";
  14. #endif /* not lint */
  15.  
  16. #include <sys/types.h>
  17. #include <sys/queue.h>
  18.  
  19. #include <bitstring.h>
  20. #include <curses.h>
  21. #include <errno.h>
  22. #include <fcntl.h>
  23. #include <signal.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <termios.h>
  28. #include <unistd.h>
  29.  
  30. #include "../common/common.h"
  31. #ifdef RUNNING_IP
  32. #include "../ip/ip.h"
  33. #endif
  34. #include "cl.h"
  35. #include "pathnames.h"
  36.  
  37. #ifdef __EMX__
  38. #define INCL_DOSPROCESS
  39. #define INCL_MOU
  40. #include <os2.h>
  41. #endif
  42.  
  43. GS *__global_list;                /* GLOBAL: List of screens. */
  44. sigset_t __sigblockset;                /* GLOBAL: Blocked signals. */
  45.  
  46. static void       cl_func_std __P((GS *));
  47. static CL_PRIVATE *cl_init __P((GS *));
  48. static GS      *gs_init __P((char *));
  49. static void       perr __P((char *, char *));
  50. static int       setsig __P((int, struct sigaction *, void (*)(int)));
  51. static void       sig_end __P((GS *));
  52. static void       term_init __P((char *, char *));
  53. #ifdef __EMX__
  54. #ifdef EMX_MOUSE
  55. static void       mou_proc __P((void *));
  56. #endif
  57. #endif
  58.  
  59. /*
  60.  * main --
  61.  *    This is the main loop for the standalone curses editor.
  62.  */
  63. int
  64. main(argc, argv)
  65.     int argc;
  66.     char *argv[];
  67. {
  68.     static int reenter;
  69.     CL_PRIVATE *clp;
  70.     GS *gp;
  71.     size_t rows, cols;
  72.     int rval;
  73.     char *ip_arg, **p_av, **t_av, *ttype;
  74.  
  75.     /* If loaded at 0 and jumping through a NULL pointer, stop. */
  76.     if (reenter++)
  77.         abort();
  78.  
  79. #ifdef __EMX__
  80.     _wildcard(&argc, &argv);
  81. #endif
  82.     /* Create and initialize the global structure. */
  83.     __global_list = gp = gs_init(argv[0]);
  84.  
  85.     /*
  86.      * Strip out any arguments that vi isn't going to understand.  There's
  87.      * no way to portably call getopt twice, so arguments parsed here must
  88.      * be removed from the argument list.
  89.      */
  90. #ifdef RUNNING_IP
  91.     ip_arg = NULL;
  92.     for (p_av = t_av = argv;;) {
  93.         if (*t_av == NULL) {
  94.             *p_av = NULL;
  95.             break;
  96.         }
  97.         if (!strcmp(*t_av, "--")) {
  98.             while ((*p_av++ = *t_av++) != NULL);
  99.             break;
  100.         }
  101.         if (!memcmp(*t_av, "-I", sizeof("-I") - 1)) {
  102.             if (t_av[0][2] != '\0') {
  103.                 ip_arg = t_av[0] + 2;
  104.                 ++t_av;
  105.                 --argc;
  106.                 continue;
  107.             }
  108.             if (t_av[1] != NULL) {
  109.                 ip_arg = t_av[1];
  110.                 t_av += 2;
  111.                 argc -= 2;
  112.                 continue;
  113.             }
  114.         }
  115.         *p_av++ = *t_av++;
  116.     }
  117.  
  118.     /*
  119.      * If we're being called as an editor library, we're done here, we
  120.      * get loaded with the curses screen, we don't share much code.
  121.      */
  122.     if (ip_arg != NULL)
  123.         exit (ip_main(argc, argv, gp, ip_arg));
  124. #else
  125.     ip_arg = argv[0];
  126. #endif
  127.         
  128.     /* Create and initialize the CL_PRIVATE structure. */
  129.     clp = cl_init(gp);
  130.  
  131.     /*
  132.      * Initialize the terminal information.
  133.      *
  134.      * We have to know what terminal it is from the start, since we may
  135.      * have to use termcap/terminfo to find out how big the screen is.
  136.      */
  137.     if ((ttype = getenv("TERM")) == NULL)
  138.         ttype = "unknown";
  139.     term_init(gp->progname, ttype);
  140.  
  141.     /* Add the terminal type to the global structure. */
  142.     if ((OG_D_STR(gp, GO_TERM) =
  143.         OG_STR(gp, GO_TERM) = strdup(ttype)) == NULL)
  144.         perr(gp->progname, NULL);
  145.  
  146.     /* Figure out how big the screen is. */
  147.     if (cl_ssize(NULL, 0, &rows, &cols, NULL))
  148.         exit (1);
  149.  
  150.     /* Add the rows and columns to the global structure. */
  151.     OG_VAL(gp, GO_LINES) = OG_D_VAL(gp, GO_LINES) = rows;
  152.     OG_VAL(gp, GO_COLUMNS) = OG_D_VAL(gp, GO_COLUMNS) = cols;
  153.  
  154.     /* Ex wants stdout to be buffered. */
  155.     (void)setvbuf(stdout, NULL, _IOFBF, 0);
  156.  
  157.     /* Start catching signals. */
  158.     if (sig_init(gp, NULL))
  159.         exit (1);
  160.  
  161.     /* Run ex/vi. */
  162.     rval = editor(gp, argc, argv);
  163.  
  164.     /* Clean up signals. */
  165.     sig_end(gp);
  166.  
  167.     /* Clean up the terminal. */
  168.     (void)cl_quit(gp);
  169.  
  170.     /*
  171.      * XXX
  172.      * Reset the O_MESG option.
  173.      */
  174.     if (clp->tgw != TGW_UNKNOWN)
  175.         (void)cl_omesg(NULL, clp, clp->tgw == TGW_SET);
  176.  
  177.     /*
  178.      * XXX
  179.      * Reset the X11 xterm icon/window name.
  180.      */
  181. #if VI_DOSISH
  182.     /* this is invalid in Unix version, note... */
  183.     (void)cl_rename(0, 0, 0);
  184. #else
  185.     if (F_ISSET(clp, CL_RENAME)) {
  186.         (void)printf(XTERM_RENAME, ttype);
  187.         (void)fflush(stdout);
  188.     }
  189. #endif
  190.  
  191.     /* If a killer signal arrived, pretend we just got it. */
  192.     if (clp->killersig) {
  193.         (void)signal(clp->killersig, SIG_DFL);
  194.         (void)kill(getpid(), clp->killersig);
  195.         /* NOTREACHED */
  196.     }
  197.  
  198.     /* Free the global and CL private areas. */
  199. #if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
  200.     free(clp);
  201.     free(gp);
  202. #endif
  203.  
  204.     exit (rval);
  205. }
  206.  
  207. /*
  208.  * gs_init --
  209.  *    Create and partially initialize the GS structure.
  210.  */
  211. static GS *
  212. gs_init(name)
  213.     char *name;
  214. {
  215.     CL_PRIVATE *clp;
  216.     GS *gp;
  217.     char *p;
  218.  
  219.     /* Figure out what our name is. */
  220.     if ((p = strrchr(name, '/')) != NULL)
  221.         name = p + 1;
  222.  
  223.     /* Allocate the global structure. */
  224.     CALLOC_NOMSG(NULL, gp, GS *, 1, sizeof(GS));
  225.     if (gp == NULL)
  226.         perr(name, NULL);
  227.  
  228.  
  229.     gp->progname = name;
  230.     return (gp);
  231. }
  232.  
  233. /*
  234.  * cl_init --
  235.  *    Create and partially initialize the CL structure.
  236.  */
  237. static CL_PRIVATE *
  238. cl_init(gp)
  239.     GS *gp;
  240. {
  241.     CL_PRIVATE *clp;
  242.     int fd;
  243.  
  244.     /* Allocate the CL private structure. */
  245.     CALLOC_NOMSG(NULL, clp, CL_PRIVATE *, 1, sizeof(CL_PRIVATE));
  246.     if (clp == NULL)
  247.         perr(gp->progname, NULL);
  248.     gp->cl_private = clp;
  249.  
  250.     /*
  251.      * Set the CL_STDIN_TTY flag.  It's purpose is to avoid setting
  252.      * and resetting the tty if the input isn't from there.  We also
  253.      * use the same test to determine if we're running a script or
  254.      * not.
  255.      */
  256.     if (isatty(STDIN_FILENO))
  257.         F_SET(clp, CL_STDIN_TTY);
  258.     else
  259.         F_SET(gp, G_SCRIPTED);
  260.  
  261.     /*
  262.      * We expect that if we've lost our controlling terminal that the
  263.      * open() (but not the tcgetattr()) will fail.
  264.      */
  265. #ifdef __EMX__
  266. #ifdef EMX_MOUSE
  267.     clp->mou_pipe = -1;
  268.     clp->mou_thr = 0;
  269. #endif
  270. #ifdef EMX_CURSOR
  271.     clp->cs1 = -1;
  272. #endif
  273. #endif
  274.     if (F_ISSET(clp, CL_STDIN_TTY)) {
  275.         if (tcgetattr(STDIN_FILENO, &clp->orig) == -1)
  276.             goto tcfail;
  277. #ifdef __EMX__
  278. #ifdef EMX_MOUSE
  279.         /*
  280.          * Start a thread to handle mouse input.  We do not display
  281.          * a mouse pointer; we just accept mouse events and change
  282.          * them into strings of vi commands.
  283.          */
  284.         if (_emx_env & 0x200)
  285.         {
  286.             int pi[2];
  287.  
  288.             if (pipe(pi) != -1)
  289.             {
  290.             clp->mou_pipe = pi[0];
  291.             if ((clp->mou_thr = _beginthread(mou_proc, 0, 24576,
  292.                             (void *) pi[1])) == -1)
  293.             {
  294.                 close(pi[0]);
  295.                 close(pi[1]);
  296.                 clp->mou_pipe = -1;
  297.             }
  298.             }
  299.         }
  300. #endif
  301. #endif
  302.     } else if ((fd = open(_PATH_TTY, O_RDONLY, 0)) != -1) {
  303.         if (tcgetattr(fd, &clp->orig) == -1) {
  304. tcfail:            perr(gp->progname, "tcgetattr");
  305.             exit (1);
  306.         }
  307.         (void)close(fd);
  308.     }
  309.  
  310.     /* Initialize the list of curses functions. */
  311.     cl_func_std(gp);
  312.  
  313.     return (clp);
  314. }
  315.  
  316. /*
  317.  * term_init --
  318.  *    Initialize terminal information.
  319.  */
  320. static void
  321. term_init(name, ttype)
  322.     char *name, *ttype;
  323. {
  324.     int err;
  325.  
  326.     /* Set up the terminal database information. */
  327.     setupterm(ttype, STDOUT_FILENO, &err);
  328.     switch (err) {
  329.     case -1:
  330.         (void)fprintf(stderr,
  331.             "%s: No terminal database found\n", name);
  332.         exit (1);
  333.     case 0:
  334.         (void)fprintf(stderr,
  335.             "%s: %s: unknown terminal type\n", name, ttype);
  336.         exit (1);
  337.     }
  338. }
  339.  
  340. #define    GLOBAL_CLP \
  341.     CL_PRIVATE *clp = GCLP(__global_list);
  342. static void
  343. h_hup(signo)
  344.     int signo;
  345. {
  346.     GLOBAL_CLP;
  347.  
  348.     F_SET(clp, CL_SIGHUP);
  349.     clp->killersig = SIGHUP;
  350. }
  351.  
  352. static void
  353. h_int(signo)
  354.     int signo;
  355. {
  356.     GLOBAL_CLP;
  357.  
  358.     F_SET(clp, CL_SIGINT);
  359. }
  360.  
  361. static void
  362. h_term(signo)
  363.     int signo;
  364. {
  365.     GLOBAL_CLP;
  366.  
  367.     F_SET(clp, CL_SIGTERM);
  368.     clp->killersig = SIGTERM;
  369. }
  370.  
  371. static void
  372. h_winch(signo)
  373.     int signo;
  374. {
  375.     GLOBAL_CLP;
  376.  
  377.     F_SET(clp, CL_SIGWINCH);
  378. }
  379. #undef    GLOBAL_CLP
  380.  
  381. /*
  382.  * sig_init --
  383.  *    Initialize signals.
  384.  *
  385.  * PUBLIC: int sig_init __P((GS *, SCR *));
  386.  */
  387. int
  388. sig_init(gp, sp)
  389.     GS *gp;
  390.     SCR *sp;
  391. {
  392.     CL_PRIVATE *clp;
  393.  
  394.     clp = GCLP(gp);
  395.  
  396.     if (sp == NULL) {
  397.         (void)sigemptyset(&__sigblockset);
  398.         if (sigaddset(&__sigblockset, SIGHUP) ||
  399.             setsig(SIGHUP, &clp->oact[INDX_HUP], h_hup) ||
  400.             sigaddset(&__sigblockset, SIGINT) ||
  401.             setsig(SIGINT, &clp->oact[INDX_INT], h_int) ||
  402.             sigaddset(&__sigblockset, SIGTERM) ||
  403.             setsig(SIGTERM, &clp->oact[INDX_TERM], h_term)
  404. #ifdef SIGWINCH
  405.             ||
  406.             sigaddset(&__sigblockset, SIGWINCH) ||
  407.             setsig(SIGWINCH, &clp->oact[INDX_WINCH], h_winch)
  408. #endif
  409.             ) {
  410.             perr(gp->progname, NULL);
  411.             return (1);
  412.         }
  413.     } else
  414.         if (setsig(SIGHUP, NULL, h_hup) ||
  415.             setsig(SIGINT, NULL, h_int) ||
  416.             setsig(SIGTERM, NULL, h_term)
  417. #ifdef SIGWINCH
  418.             ||
  419.             setsig(SIGWINCH, NULL, h_winch)
  420. #endif
  421.             ) {
  422.             msgq(sp, M_SYSERR, "signal-reset");
  423.         }
  424.     return (0);
  425. }
  426.  
  427. /*
  428.  * setsig --
  429.  *    Set a signal handler.
  430.  */
  431. static int
  432. setsig(signo, oactp, handler)
  433.     int signo;
  434.     struct sigaction *oactp;
  435.     void (*handler) __P((int));
  436. {
  437.     struct sigaction act;
  438.  
  439.     /*
  440.      * Use sigaction(2), not signal(3), since we don't always want to
  441.      * restart system calls.  The example is when waiting for a command
  442.      * mode keystroke and SIGWINCH arrives.  Besides, you can't portably
  443.      * restart system calls (thanks, POSIX!).  On the other hand, you
  444.      * can't portably NOT restart system calls (thanks, Sun!).  SunOS
  445.      * used SA_INTERRUPT as their extension to NOT restart read calls.
  446.      * We sure hope nobody else used it for anything else.  Mom told me
  447.      * there'd be days like this.  She just never told me that there'd
  448.      * be so many.
  449.      */
  450.     act.sa_handler = handler;
  451.     sigemptyset(&act.sa_mask);
  452.  
  453. #ifdef SA_INTERRUPT
  454.     act.sa_flags = SA_INTERRUPT;
  455. #else
  456.     act.sa_flags = 0;
  457. #endif
  458.     return (sigaction(signo, &act, oactp));
  459. }
  460.  
  461. /*
  462.  * sig_end --
  463.  *    End signal setup.
  464.  */
  465. static void
  466. sig_end(gp)
  467.     GS *gp;
  468. {
  469.     CL_PRIVATE *clp;
  470.  
  471.     clp = GCLP(gp);
  472.     (void)sigaction(SIGHUP, NULL, &clp->oact[INDX_HUP]);
  473.     (void)sigaction(SIGINT, NULL, &clp->oact[INDX_INT]);
  474.     (void)sigaction(SIGTERM, NULL, &clp->oact[INDX_TERM]);
  475. #ifdef SIGWINCH
  476.     (void)sigaction(SIGWINCH, NULL, &clp->oact[INDX_WINCH]);
  477. #endif
  478. }
  479.  
  480. /*
  481.  * cl_func_std --
  482.  *    Initialize the standard curses functions.
  483.  */
  484. static void
  485. cl_func_std(gp)
  486.     GS *gp;
  487. {
  488.     gp->scr_addstr = cl_addstr;
  489.     gp->scr_attr = cl_attr;
  490.     gp->scr_baud = cl_baud;
  491.     gp->scr_bell = cl_bell;
  492.     gp->scr_busy = NULL;
  493.     gp->scr_clrtoeol = cl_clrtoeol;
  494.     gp->scr_cursor = cl_cursor;
  495.     gp->scr_deleteln = cl_deleteln;
  496.     gp->scr_event = cl_event;
  497.     gp->scr_ex_adjust = cl_ex_adjust;
  498.     gp->scr_fmap = cl_fmap;
  499.     gp->scr_insertln = cl_insertln;
  500.     gp->scr_keyval = cl_keyval;
  501.     gp->scr_move = cl_move;
  502.     gp->scr_msg = NULL;
  503.     gp->scr_optchange = cl_optchange;
  504.     gp->scr_refresh = cl_refresh;
  505.     gp->scr_rename = cl_rename;
  506.     gp->scr_screen = cl_screen;
  507.     gp->scr_suspend = cl_suspend;
  508.     gp->scr_usage = cl_usage;
  509. }
  510.  
  511. /*
  512.  * perr --
  513.  *    Print system error.
  514.  */
  515. static void
  516. perr(name, msg)
  517.     char *name, *msg;
  518. {
  519.     (void)fprintf(stderr, "%s:", name);
  520.     if (msg != NULL)
  521.         (void)fprintf(stderr, "%s:", msg);
  522.     (void)fprintf(stderr, "%s\n", strerror(errno));
  523.     exit(1);
  524. }
  525.  
  526. #ifdef __EMX__
  527. #ifdef EMX_MOUSE
  528. /*
  529.  * mou_proc --
  530.  *    Process mouse events from a VDM.
  531.  *    OS/2 only.
  532.  */
  533. static void
  534. mou_proc(arg)
  535.     void *arg;
  536. {
  537.     int fd = (int) arg;
  538.     MOUEVENTINFO ev;
  539.     struct msev mev;
  540.     USHORT msk, rc;
  541.     HMOU hm;
  542.  
  543.     if ((rc = MouOpen((PSZ) 0, &hm)) != 0)
  544.     {
  545.     close(fd);
  546.     _endthread();
  547.     }
  548.     msk = MOUSE_BN1_DOWN | MOUSE_BN2_DOWN | MOUSE_BN3_DOWN;
  549.     if ((rc = MouSetEventMask(&msk, hm)) != 0)
  550.     {
  551.     MouClose(hm);
  552.     close(fd);
  553.     _endthread();
  554.     }
  555.     msk = 0; /* system draws pointer, return position in pels */
  556.     if ((rc = MouSetDevStatus(&msk, hm)) != 0)
  557.     {
  558.     MouClose(hm);
  559.     close(fd);
  560.     _endthread();
  561.     }
  562.     msk = MOU_WAIT;
  563.     while ((rc = MouReadEventQue(&ev, &msk, hm)) == 0)
  564.     {
  565.     if (!ev.fs)
  566.         continue;    /* we only want mouse-down events */
  567.     mev.button = 0;
  568.     if (ev.fs & MOUSE_BN1_DOWN)
  569.         mev.button |= MEV_B1;
  570.     if (ev.fs & MOUSE_BN2_DOWN)
  571.         mev.button |= MEV_B2;
  572.     if (ev.fs & MOUSE_BN3_DOWN)
  573.         mev.button |= MEV_B3;
  574.     mev.x = ev.col;
  575.     mev.y = ev.row;
  576.     write(fd, &mev, sizeof mev);
  577.     }
  578.     MouClose(hm);
  579.     close(fd);
  580. }
  581. #endif
  582. #endif
  583.