Logo Search packages:      
Sourcecode: zile version File versions

main.c

/* Startup functions
   Copyright (c) 1997-2004 Sandro Sigala.  All rights reserved.

   This file is part of Zile.

   Zile is free software; you can redistribute it and/or modify it under
   the terms of the GNU General Public License as published by the Free
   Software Foundation; either version 2, or (at your option) any later
   version.

   Zile is distributed in the hope that it will be useful, but WITHOUT ANY
   WARRANTY; without even the implied warranty of MERCHANTABILITY or
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   for more details.

   You should have received a copy of the GNU General Public License
   along with Zile; see the file COPYING.  If not, write to the Free
   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.  */

/*    $Id: main.c,v 1.50.2.11 2005/02/27 17:43:50 rrt Exp $ */

#include "config.h"

#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <locale.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <signal.h>
#if ALLEGRO
#if HAVE_ALLEGRO_H
#include <allegro.h>
#endif
#endif

#include "alist.h"

#include "zile.h"
#include "extern.h"

#ifndef PATH_MAX
#ifdef _POSIX_PATH_MAX
#define PATH_MAX  _POSIX_PATH_MAX
#else
/* Guess if all else fails */
#define PATH_MAX  254
#endif
#endif

#define ZILE_VERSION_STRING   "Zile " VERSION

/* The current window; the first window in list. */
Window *cur_wp = NULL, *head_wp = NULL;
/* The current buffer; the first buffer in list. */
Buffer *cur_bp = NULL, *head_bp = NULL;

/* The global editor flags. */
int thisflag = 0, lastflag = 0;
/* The universal argument repeat count. */
int last_uniarg = 1;

#if DEBUG
/*
 * This function checks the line list of the specified buffer and
 * appends list informations to the `zile.abort' file if
 * some unexpected corruption is found.
 */
static void check_list(Window *wp)
{
      Line *lp, *prevlp;

      prevlp = wp->bp->limitp;
      for (lp = wp->bp->limitp->next;; lp = lp->next) {
            if (lp->prev != prevlp || prevlp->next != lp) {
                  FILE *f = fopen("zile.abort", "a");
                  fprintf(f, "---------- buffer `%s' corruption\n", wp->bp->name);
                  fprintf(f, "limitp = %p, limitp->prev = %p, limitp->next = %p\n", wp->bp->limitp, wp->bp->limitp->prev, wp->bp->limitp->next);
                  fprintf(f, "prevlp = %p, prevlp->prev = %p, prevlp->next = %p\n", prevlp, prevlp->prev, prevlp->next);
                  fprintf(f, "pointp = %p, pointp->prev = %p, pointp->next = %p\n", wp->bp->pt.p, wp->bp->pt.p->prev, wp->bp->pt.p->next);
                  fprintf(f, "lp = %p, lp->prev = %p, lp->next = %p\n", lp, lp->prev, lp->next);
                  fclose(f);
                  term_close();
                  fprintf(stderr, "\aAborting due to internal buffer structure corruption\n");
                  fprintf(stderr, "\aFor more information read the `zile.abort' file\n");
                  abort();
            }
            if (lp == wp->bp->limitp)
                  break;
            prevlp = lp;
      }
}
#endif /* DEBUG */

static void loop(void)
{
      for (;;) {
                size_t key;

            if (lastflag & FLAG_NEED_RESYNC)
                  resync_redisplay();
#if DEBUG
            check_list(cur_wp);
#endif
                term_redisplay();
                term_refresh();

                thisflag = 0;
            if (lastflag & FLAG_DEFINING_MACRO)
                  thisflag |= FLAG_DEFINING_MACRO;

                key = term_getkey();
                minibuf_clear();
            process_key(key);

            if (thisflag & FLAG_QUIT_ZILE)
                  break;
            if (!(thisflag & FLAG_SET_UNIARG))
                  last_uniarg = 1;

            lastflag = thisflag;
      }
}

static char about_splash_str[] = "\
" ZILE_VERSION_STRING "\n\
\n\
%Copyright (C) 1997-2004 Sandro Sigala <sandro@sigala.it>%\n\
%Copyright (C) 2003-2004 David A. Capello <dacap@users.sourceforge.net>%\n\
%Copyright (C) 2003-2005 Reuben Thomas <rrt@sc3d.org>%\n\
\n\
Type %C-x C-c% to exit Zile.\n\
Type %C-h h% for help; %C-x u% to undo changes.\n\
Type %C-h C-d% for information on getting the latest version.\n\
Type %C-h t% for a tutorial on using Zile.\n\
Type %C-h s% for a sample configuration file.\n\
Type %C-g% at any time to cancel the current operation.\n\
\n\
%C-x% means hold the CTRL key while typing the character %x%.\n\
%M-x% means hold the META or EDIT or ALT key down while typing %x%.\n\
If there is no META, EDIT or ALT key, instead press and release\n\
the ESC key and then type %x%.\n\
Combinations like %C-h h% mean first press %C-h%, then %h%.\n\
";

static char about_minibuf_str[] =
"Welcome to Zile!  For help type `C-h h'";

static void about_screen(void)
{
        int c;

      /* I don't like this hack, but I don't know another way... */
      if (lookup_bool_variable("alternative-bindings")) {
            replace_string(about_splash_str, "C-h", "M-h");
            replace_string(about_minibuf_str, "C-h", "M-h");
      }

        minibuf_write(about_minibuf_str);

        if (!lookup_bool_variable("skip-splash-screen")) {
            show_splash_screen(about_splash_str);
                term_refresh();
                if ((c = term_xgetkey(GETKEY_DELAYED, 20 * 10)) != KBD_NOKEY)
                  term_unget(c);
        }
}

/*
 * Do some sanity checks on the environment.
 */
static void sanity_checks(void)
{
      /*
       * The functions `read_rc_file' and `help_tutorial' rely
       * on a usable `HOME' environment variable.
       */
      if (getenv("HOME") == NULL) {
            fprintf(stderr, "fatal error: please set `HOME' to point to your home-directory\n");
            exit(1);
      }
#ifdef PATH_MAX
      if (strlen(getenv("HOME")) + 12 > PATH_MAX) {
            fprintf(stderr, "fatal error: `HOME' is longer than the longest pathname your system supports\n");
            exit(1);
      }
#endif
}

static void execute_functions(alist al)
{
      char *func;
      for (func = alist_first(al); func != NULL; func = alist_next(al)) {
            term_redisplay();
            if (!execute_function(func, 1))
                  minibuf_error("Function `%s' not defined", func);
            lastflag |= FLAG_NEED_RESYNC;
      }
}

/*
 * Return the number of occurrences of c into s.
 */
static int countchr(const char *s, int c)
{
      int count = 0;
      for (; *s != '\0'; ++s)
            if (*s == c)
                  ++count;
      return count;
}

/*
 * Check the `variable=expression' syntax correctness.
 */
static void check_var_syntax(const char *expr)
{
      if (strlen(expr) < 3 || countchr(expr, '=') != 1 ||
          strchr(expr, '=') == expr ||
          strchr(expr, '=') == expr + strlen(expr) - 1) {
            fprintf(stderr, "zile: invalid `variable=expression' syntax\n");
            exit(1);
      }
}

static void set_variables(alist al)
{
      char *expr;
      for (expr = alist_first(al); expr != NULL; expr = alist_next(al)) {
            char *var = expr;
            char *eq = strchr(expr, '=');
            char *val = eq + 1;
            *eq = '\0';
            fprintf(stderr, "'%s' = '%s'\n", var, val);
            set_variable(var, val);
      }
}

/*
 * Output the program syntax then exit.
 */
static void usage(void)
{
      fprintf(stderr, "usage: zile [-hqV] [-f function] [-v variable=value] [-u rcfile]\n"
                  "          [+number] [file ...]\n");
      exit(1);
}

static void setup_main_screen(int argc)
{
      Buffer *bp, *last_bp = NULL;
      int c = 0;

      for (bp = head_bp; bp; bp = bp->next) {
            /* Last buffer that isn't *scratch*.  */
            if (bp->next && !bp->next->next)
                  last_bp = bp;

            c++;
      }

      /* *scratch* and two files.  */
      if (c == 3) {
            FUNCALL(split_window);
            switch_to_buffer(last_bp);
            FUNCALL(other_window);
      }
      /* More than two files.  */
      else if (c > 3) {
            FUNCALL(list_buffers);
      }
      else {
            if (argc < 1) {
                        undo_nosave = TRUE;
                  insert_string("\
This buffer is for notes you don't want to save.\n\
If you want to create a file, visit that file with C-x C-f,\n\
then enter the text in that file's own buffer.\n\
\n");
                        undo_nosave = FALSE;
                  cur_bp->flags &= ~BFLAG_MODIFIED;
                  resync_redisplay();
            }
      }
}

static void segv_sig_handler(int signo)
{
        (void)signo;
      fprintf(stderr, "Zile crashed.  Please send a bug report to <" PACKAGE_BUGREPORT ">.\r\n");
      zile_exit(2);
}

static void other_sig_handler(int signo)
{
        (void)signo;
      fprintf(stderr, "Zile terminated with signal %d.\r\n", signo);
      zile_exit(2);
}

#ifdef HAVE_SIGACTION
static struct sigaction act; /* For use by signal handlers */

/* What do we do when we catch the suspend signal */
static void suspend_sig_handler(int signal)
{
      /* Clear last line of display, and leave cursor there. */
      term_move(ZILE_LINES - 1, 0);
      term_clrtoeol();
        term_attrset(1, ZILE_NORMAL); /* Make sure we end in normal font */
      term_refresh();
        term_suspend();

        /* Trap SIGHUP and SIGTERM so we can properly deal with them while
           suspended */
        act.sa_handler = other_sig_handler;
        sigaction(SIGHUP, &act, NULL);
        sigaction(SIGTERM, &act, NULL);

        /* We used to re-enable the default SIG_DFL and raise SIGTSTP, but
           then we could be (and were) interrupted in the middle of the call.
           So we do it the mutt way instead */
        kill(0, SIGSTOP);
}

static void signal_init(void);

/* Restore the suspend handler when we come back into the prog */
static void cont_sig_handler(int signal)
{
        term_resume();
        term_full_redisplay(); /* XXX need to call tcsetattr and winch handler */

        /* Simplest just to reinitialise everything. */
        signal_init();
}
#endif

static void signal_init(void)
{
        /* Set up signal handling */
        signal(SIGSEGV, segv_sig_handler);
        signal(SIGHUP, other_sig_handler);
        signal(SIGINT, other_sig_handler);
        signal(SIGQUIT, other_sig_handler);
        signal(SIGTERM, other_sig_handler);

#ifdef HAVE_SIGACTION
      /* If we don't do this, it seems other stuff interrupts the
         suspend handler! Without it, suspending zile under e.g.
         pine or mutt freezes the process. */
      sigfillset(&act.sa_mask);

      act.sa_handler = suspend_sig_handler;
      sigaction(SIGTSTP, &act, NULL);
      act.sa_handler = cont_sig_handler;
      sigaction(SIGCONT, &act, NULL);
#endif
}

int main(int argc, char **argv)
{
      int c;
      int qflag = 0;
      char *uarg = NULL;
      alist fargs = alist_new();
      alist vargs = alist_new();

      while ((c = getopt(argc, argv, "f:hqu:v:V")) != -1)
            switch (c) {
            case 'f':
                  alist_append(fargs, optarg);
                  break;
            case 'q':
                  qflag = 1;
                  break;
            case 'u':
                  uarg = optarg;
                  break;
            case 'v':
                  check_var_syntax(optarg);
                  alist_append(vargs, optarg);
                  break;
            case 'V':
                  fprintf(stderr, ZILE_VERSION_STRING "\n");
                  return 0;
            case '?':
            default:
                  usage();
                  /* NOTREACHED */
            }
      argc -= optind;
      argv += optind;

      sanity_checks();

        signal_init();

        setlocale(LC_ALL, "");

      term_init();

      init_variables();
      if (!qflag)
            read_rc_file(uarg);
      set_variables(vargs);

      /* Create the `*scratch*' buffer and initialize key bindings. */
      create_first_window();
      term_redisplay();
      init_bindings();

      if (argc >= 1)
            while (*argv) {
                  int line = 0;
                  if (**argv == '+')
                        line = atoi(*argv++ + 1);
                  if (*argv)
                        open_file(*argv++, line - 1);
            }
        else
            /*
             * Show the splash screen only if there isn't any file
             * specified on command line and no function was specified
             * with the `-f' flag.
             */
            if (alist_count(fargs) == 0)
                  about_screen();

      setup_main_screen(argc);

      execute_functions(fargs);

      /* Run the main Zile loop. */
      loop();

      /* Clear last line of display, and leave cursor there. */
      term_move(ZILE_LINES - 1, 0);
      term_clrtoeol();
        term_attrset(1, ZILE_NORMAL); /* Make sure we end in normal font */
      term_refresh();

      /* Free all the memory allocated. */
      alist_delete(fargs);
      alist_delete(vargs);
      free_kill_ring();
      free_registers();
      free_search_history();
      free_macros();
      free_windows();
      free_buffers();
      free_bindings();
      free_variables();
      free_minibuf();
      free_rotation_buffers();

      term_close();

      return 0;
}

#ifdef ALLEGRO
END_OF_MAIN()
#endif

Generated by  Doxygen 1.6.0   Back to index