home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / EDITOR / NVI179B / NVI179B.ZIP / tk / tk_main.c < prev    next >
C/C++ Source or Header  |  1996-09-24  |  9KB  |  424 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[] = "@(#)tk_main.c    8.18 (Berkeley) 9/24/96";
  14. #endif /* not lint */
  15.  
  16. #include <sys/types.h>
  17. #include <sys/queue.h>
  18.  
  19. #include <bitstring.h>
  20. #include <errno.h>
  21. #include <fcntl.h>
  22. #include <signal.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <termios.h>
  27. #include <unistd.h>
  28.  
  29. #include "../common/common.h"
  30. #include "tki.h"
  31. #include "pathnames.h"
  32.  
  33. GS *__global_list;                /* GLOBAL: List of screens. */
  34. sigset_t __sigblockset;                /* GLOBAL: Blocked signals. */
  35.  
  36. static GS    *gs_init __P((char *));
  37. static void     killsig __P((SCR *));
  38. static void     perr __P((char *, char *));
  39. static void     sig_end __P((GS *));
  40. static int     sig_init __P((GS *));
  41. static int     tcl_init __P((GS *));
  42. static void     tcl_err __P((TK_PRIVATE *));
  43.  
  44. /*
  45.  * main --
  46.  *    This is the main loop for the standalone Tcl/Tk editor.
  47.  */
  48. int
  49. main(argc, argv)
  50.     int argc;
  51.     char *argv[];
  52. {
  53.     static int reenter;
  54.     GS *gp;
  55.     TK_PRIVATE *tkp;
  56.     size_t rows, cols;
  57.     int rval;
  58.     char **p_av, **t_av, *script;
  59.  
  60.     /* If loaded at 0 and jumping through a NULL pointer, stop. */
  61.     if (reenter++)
  62.         abort();
  63.  
  64.     /* Create and initialize the global structure. */
  65.     __global_list = gp = gs_init(argv[0]);
  66.  
  67.     /* Initialize Tk/Tcl. */
  68.     if (tcl_init(gp))
  69.         exit (1);
  70.  
  71.     /*
  72.      * Strip out any arguments that the common editor doesn't understand
  73.      * (i.e. the Tk/Tcl arguments).  Search for -i first, it's the Tk/Tcl
  74.      * startup script and needs to be run first.
  75.      *
  76.      * XXX
  77.      * There's no way to portably call getopt twice.
  78.      */
  79.     script = "init.tcl";
  80.     for (p_av = t_av = argv;;) {
  81.         if (*t_av == NULL) {
  82.             *p_av = NULL;
  83.             break;
  84.         }
  85.         if (!strcmp(*t_av, "--")) {
  86.             while ((*p_av++ = *t_av++) != NULL);
  87.             break;
  88.         }
  89.         if (!memcmp(*t_av, "-i", sizeof("-i") - 1)) {
  90.             if (t_av[0][2] != '\0') {
  91.                 script = t_av[0] + 2;
  92.                 ++t_av;
  93.                 --argc;
  94.                 continue;
  95.             }
  96.             if (t_av[1] != NULL) {
  97.                 script = t_av[1];
  98.                 t_av += 2;
  99.                 argc -= 2;
  100.                 continue;
  101.             }
  102.         }
  103.         *p_av++ = *t_av++;
  104.     }
  105.     for (p_av = t_av = argv;;) {
  106.         if (*t_av == NULL) {
  107.             *p_av = NULL;
  108.             break;
  109.         }
  110.         if (!strcmp(*t_av, "--")) {
  111.             while ((*p_av++ = *t_av++) != NULL);
  112.             break;
  113.         }
  114.         if (t_av[1] != NULL &&
  115.            (!memcmp(*t_av, "-background", sizeof("-background") - 1) ||
  116.             !memcmp(*t_av, "-bg", sizeof("-bg") - 1) ||
  117.             !memcmp(*t_av, "-borderwidth", sizeof("-borderwidth") - 1)||
  118.             !memcmp(*t_av, "-bd", sizeof("-bd") - 1) ||
  119.             !memcmp(*t_av, "-foreground", sizeof("-foreground") - 1) ||
  120.             !memcmp(*t_av, "-fg", sizeof("-fg") - 1) ||
  121.             !memcmp(*t_av, "-font", sizeof("-font") - 1))) {
  122.             if (Tcl_VarEval(tkp->interp, ".t configure ",
  123.                 t_av[0], " ", t_av[1], NULL) == TCL_ERROR)
  124.                 tcl_err(tkp);
  125.             t_av += 2;
  126.             argc -= 2;
  127.             continue;
  128.         }
  129.         if (!memcmp(*t_av, "-geometry", sizeof("-geometry") - 1)) {
  130.             if (Tcl_VarEval(tkp->interp, "wm geometry . ",
  131.                 *t_av + sizeof("-geometry") - 1, NULL) == TCL_ERROR)
  132.                 tcl_err(tkp);
  133.             ++t_av;
  134.             --argc;
  135.             continue;
  136.         }
  137.         *p_av++ = *t_av++;
  138.     }
  139.  
  140.     /* Load the initial Tcl/Tk script. */
  141.     tkp = GTKP(gp);
  142.     if (Tcl_EvalFile(tkp->interp, script) == TCL_ERROR)
  143.         tcl_err(tkp);
  144.  
  145.     /* Add the terminal type to the global structure. */
  146.     if ((OG_D_STR(gp, GO_TERM) =
  147.         OG_STR(gp, GO_TERM) = strdup("tkterm")) == NULL)
  148.         perr(gp->progname, NULL);
  149.  
  150.     /* Figure out how big the screen is. */
  151.     if (tk_ssize(NULL, 0, &rows, &cols, NULL))
  152.         exit (1);
  153.  
  154.     /* Add the rows and columns to the global structure. */
  155.     OG_VAL(gp, GO_LINES) = OG_D_VAL(gp, GO_LINES) = rows;
  156.     OG_VAL(gp, GO_COLUMNS) = OG_D_VAL(gp, GO_COLUMNS) = cols;
  157.  
  158.     /* Start catching signals. */
  159.     if (sig_init(gp))
  160.         exit (1);
  161.  
  162.     /* Run ex/vi. */
  163.     rval = editor(gp, argc, argv);
  164.  
  165.     /* Clean up signals. */
  166.     sig_end(gp);
  167.  
  168.     /* Clean up the terminal. */
  169.     (void)tk_quit(gp);
  170.  
  171.     /* If a killer signal arrived, pretend we just got it. */
  172.     if (tkp->killersig) {
  173.         (void)signal(tkp->killersig, SIG_DFL);
  174.         (void)kill(getpid(), tkp->killersig);
  175.         /* NOTREACHED */
  176.     }
  177.  
  178.     /* Free the global and TK private areas. */
  179. #if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
  180.     free(tkp);
  181.     free(gp);
  182. #endif
  183.  
  184.     exit (rval);
  185. }
  186.  
  187. /*
  188.  * gs_init --
  189.  *    Create and partially initialize the GS structure.
  190.  */
  191. static GS *
  192. gs_init(name)
  193.     char *name;
  194. {
  195.     TK_PRIVATE *tkp;
  196.     GS *gp;
  197.     int fd;
  198.     char *p;
  199.  
  200.     /* Figure out what our name is. */
  201.     if ((p = strrchr(name, '/')) != NULL)
  202.         name = p + 1;
  203.  
  204.     /* Allocate the global structure. */
  205.     CALLOC_NOMSG(NULL, gp, GS *, 1, sizeof(GS));
  206.  
  207.     /* Allocate the CL private structure. */
  208.     if (gp != NULL)
  209.         CALLOC_NOMSG(NULL, tkp, TK_PRIVATE *, 1, sizeof(TK_PRIVATE));
  210.     if (gp == NULL || tkp == NULL)
  211.         perr(name, NULL);
  212.     gp->tk_private = tkp;
  213.     TAILQ_INIT(&tkp->evq);
  214.  
  215.     /* Initialize the list of curses functions. */
  216.     gp->scr_addstr = tk_addstr;
  217.     gp->scr_attr = tk_attr;
  218.     gp->scr_baud = tk_baud;
  219.     gp->scr_bell = tk_bell;
  220.     gp->scr_busy = NULL;
  221.     gp->scr_clrtoeol = tk_clrtoeol;
  222.     gp->scr_cursor = tk_cursor;
  223.     gp->scr_deleteln = tk_deleteln;
  224.     gp->scr_event = tk_event;
  225.     gp->scr_ex_adjust = tk_ex_adjust;
  226.     gp->scr_fmap = tk_fmap;
  227.     gp->scr_insertln = tk_insertln;
  228.     gp->scr_keyval = tk_keyval;
  229.     gp->scr_move = tk_move;
  230.     gp->scr_msg = NULL;
  231.     gp->scr_optchange = tk_optchange;
  232.     gp->scr_refresh = tk_refresh;
  233.     gp->scr_rename = tk_rename;
  234.     gp->scr_screen = tk_screen;
  235.     gp->scr_suspend = tk_suspend;
  236.     gp->scr_usage = tk_usage;
  237.  
  238.     /*
  239.      * We expect that if we've lost our controlling terminal that the
  240.      * open() (but not the tcgetattr()) will fail.
  241.      */
  242.     if (isatty(STDIN_FILENO)) {
  243.         if (tcgetattr(STDIN_FILENO, &tkp->orig) == -1)
  244.             goto tcfail;
  245.     } else if ((fd = open(_PATH_TTY, O_RDONLY, 0)) != -1) {
  246.         if (tcgetattr(fd, &tkp->orig) == -1)
  247. tcfail:            perr(name, "tcgetattr");
  248.         (void)close(fd);
  249.     }
  250.  
  251.     gp->progname = name;
  252.     return (gp);
  253. }
  254.  
  255. /*
  256.  *  tcl_init --
  257.  *    Get Tcl/Tk up and running.
  258.  */
  259. static int
  260. tcl_init(gp)
  261.     GS *gp;
  262. {
  263.     TK_PRIVATE *tkp;
  264.  
  265.     tkp = GTKP(gp);
  266.     if ((tkp->interp = Tcl_CreateInterp()) == NULL)
  267.         tcl_err(tkp);
  268.     /* XXX: Tk 4.1 has an incompatible change. */
  269. #if (TK_MAJOR_VERSION == 4) && (TK_MINOR_VERSION == 0)
  270.     if (Tk_CreateMainWindow(tkp->interp, NULL, "vi", "Vi") == NULL)
  271.         tcl_err(tkp);
  272. #endif
  273.     if (Tcl_Init(tkp->interp) == TCL_ERROR)
  274.         tcl_err(tkp);
  275.     if (Tk_Init(tkp->interp) == TCL_ERROR)
  276.         tcl_err(tkp);
  277.  
  278.     /* Shared variables. */
  279.     (void)Tcl_LinkVar(tkp->interp,
  280.         "tk_cursor_row", (char *)&tkp->tk_cursor_row, TCL_LINK_INT);
  281.     (void)Tcl_LinkVar(tkp->interp,
  282.         "tk_cursor_col", (char *)&tkp->tk_cursor_col, TCL_LINK_INT);
  283.     (void)Tcl_LinkVar(tkp->interp,
  284.         "tk_ssize_row", (char *)&tkp->tk_ssize_row, TCL_LINK_INT);
  285.     (void)Tcl_LinkVar(tkp->interp,
  286.         "tk_ssize_col", (char *)&tkp->tk_ssize_col, TCL_LINK_INT);
  287.  
  288.     /* Functions called by Tcl script. */
  289.     Tcl_CreateCommand(tkp->interp, "tk_key", tk_key, tkp, NULL);
  290.     Tcl_CreateCommand(tkp->interp, "tk_op", tk_op, tkp, NULL);
  291.     Tcl_CreateCommand(tkp->interp, "tk_opt_init", tk_opt_init, tkp, NULL);
  292.     Tcl_CreateCommand(tkp->interp, "tk_opt_set", tk_opt_set, tkp, NULL);
  293.     Tcl_CreateCommand(tkp->interp, "tk_version", tk_version, tkp, NULL);
  294.  
  295.     /* Other initialization. */
  296.     if (Tcl_Eval(tkp->interp, "wm geometry . =80x28+0+0") == TCL_ERROR)
  297.         tcl_err(tkp);
  298.     return (0);
  299. }
  300.  
  301. /*
  302.  * tcl_err --
  303.  *    Tcl/Tk error message during initialization.
  304.  */
  305. static void
  306. tcl_err(tkp)
  307.     TK_PRIVATE *tkp;
  308. {
  309.     (void)fprintf(stderr, "%s\n", tkp->interp->result != NULL ?
  310.         tkp->interp->result : "Tcl/Tk: initialization error");
  311.     (void)tk_usage();
  312.     exit (1);
  313. }
  314.  
  315. #define    GLOBAL_TKP \
  316.     TK_PRIVATE *tkp = GTKP(__global_list);
  317. static void
  318. h_hup(signo)
  319.     int signo;
  320. {
  321.     GLOBAL_TKP;
  322.  
  323.     F_SET(tkp, TK_SIGHUP);
  324.     tkp->killersig = SIGHUP;
  325. }
  326.  
  327. static void
  328. h_int(signo)
  329.     int signo;
  330. {
  331.     GLOBAL_TKP;
  332.  
  333.     F_SET(tkp, TK_SIGINT);
  334. }
  335.  
  336. static void
  337. h_term(signo)
  338.     int signo;
  339. {
  340.     GLOBAL_TKP;
  341.  
  342.     F_SET(tkp, TK_SIGTERM);
  343.     tkp->killersig = SIGTERM;
  344. }
  345.  
  346. static void
  347. h_winch(signo)
  348.     int signo;
  349. {
  350.     GLOBAL_TKP;
  351.  
  352.     F_SET(tkp, TK_SIGWINCH);
  353. }
  354. #undef    GLOBAL_TKP
  355.  
  356. /*
  357.  * sig_init --
  358.  *    Initialize signals.
  359.  */
  360. static int
  361. sig_init(gp)
  362.     GS *gp;
  363. {
  364.     TK_PRIVATE *tkp;
  365.     struct sigaction act;
  366.  
  367.     tkp = GTKP(gp);
  368.  
  369.     (void)sigemptyset(&__sigblockset);
  370.  
  371.     /*
  372.      * Use sigaction(2), not signal(3), since we don't always want to
  373.      * restart system calls.  The example is when waiting for a command
  374.      * mode keystroke and SIGWINCH arrives.  Besides, you can't portably
  375.      * restart system calls (thanks, POSIX!).
  376.      */
  377. #define    SETSIG(signal, handler, off) {                    \
  378.     if (sigaddset(&__sigblockset, signal))                \
  379.         goto err;                        \
  380.     act.sa_handler = handler;                    \
  381.     sigemptyset(&act.sa_mask);                    \
  382.     act.sa_flags = 0;                        \
  383.     if (sigaction(signal, &act, &tkp->oact[off]))            \
  384.         goto err;                        \
  385. }
  386. #undef SETSIG
  387.     return (0);
  388.  
  389. err:    perr(gp->progname, NULL);
  390.     return (1);
  391. }
  392.  
  393. /*
  394.  * sig_end --
  395.  *    End signal setup.
  396.  */
  397. static void
  398. sig_end(gp)
  399.     GS *gp;
  400. {
  401.     TK_PRIVATE *tkp;
  402.  
  403.     tkp = GTKP(gp);
  404.     (void)sigaction(SIGHUP, NULL, &tkp->oact[INDX_HUP]);
  405.     (void)sigaction(SIGINT, NULL, &tkp->oact[INDX_INT]);
  406.     (void)sigaction(SIGTERM, NULL, &tkp->oact[INDX_TERM]);
  407.     (void)sigaction(SIGWINCH, NULL, &tkp->oact[INDX_WINCH]);
  408. }
  409.  
  410. /*
  411.  * perr --
  412.  *    Print system error.
  413.  */
  414. static void
  415. perr(name, msg)
  416.     char *name, *msg;
  417. {
  418.     (void)fprintf(stderr, "%s:", name);
  419.     if (msg != NULL)
  420.         (void)fprintf(stderr, "%s:", msg);
  421.     (void)fprintf(stderr, "%s\n", strerror(errno));
  422.     exit(1);
  423. }
  424.