/* -*- mode: c; mode: fold -*- */ /* * Copyright (c) 1992, 1996 John E. Davis (davis@space.mit.edu) * All Rights Reserved. */ #include "config.h" #include "jed-feat.h" /*{{{ #include files */ #include #ifdef HAVE_STDLIB_H # include #endif #include #include "jdmacros.h" #include #include "buffer.h" #include "screen.h" #include "window.h" #include "ins.h" #include "ledit.h" #include "cmds.h" #include "line.h" #include "paste.h" #include "display.h" #include "vterm.h" #include "sysdep.h" #include "text.h" #include "file.h" #include "misc.h" #include "search.h" #include "hooks.h" #include "abbrev.h" #if JED_HAS_SUBPROCESSES # include "jprocess.h" #endif #if JED_HAS_LINE_ATTRIBUTES # include "lineattr.h" #endif /*}}}*/ /*{{{ Global variables */ void (*X_Suspend_Hook)(void); int Blink_Flag = 1; int Indented_Text_Mode = 0; /* if non zero, intent line after wrap */ int Kill_Line_Feature = 1; /* non-zero means kill through eol if bolp */ int Jed_Tab_Default = 8; int Jed_Wrap_Column = 72; int Jed_Suspension_Not_Allowed = 0; int Jed_Use_Tabs = 1; /*}}}*/ /*{{{ Static variables */ static char *Top_Of_Buffer_Error = "Top Of Buffer."; static char *End_Of_Buffer_Error = "End Of Buffer."; /*}}}*/ /*{{{ Static functions */ /* return 1 if line extends beyond the screen */ static int long_line(void) { int p, col; col = Screen_Col; p = Point; Point = CLine->len - 1; if ((*(CLine->data + Point) != '\n') || (CBuf == MiniBuffer)) Point++; if (calculate_column() >= JWindow->width - 1) { Point = p; Screen_Col = col; return(1); } Screen_Col = col; Point = p; return(0); } /* check from point to end of line looking for tabs */ static int tabs_present(void) { unsigned char *p, *pmax; if (!Buffer_Local.tab) return(0); pmax = CLine->data + CLine->len; p = CLine->data + Point; while (p < pmax) if (*p++ == '\t') return(1); return(0); } static int fast_not_ok (unsigned char ch) { return ((Repeat_Factor != NULL) || JWindow->trashed || (ch < 32) || (ch > 126) || Input_Buffer_Len || Suspend_Screen_Update || (Screen_Col >= JWindow->width - 2) || (JWindow->column > 1) || Batch || (CLine->len == 0) || ((CBuf->marks != NULL) && Wants_Attributes) #if JED_HAS_LINE_ATTRIBUTES || ((CLine->next != NULL) && (CLine->next->flags & JED_LINE_HIDDEN)) #endif || input_pending(&Number_Zero) || Executing_Keyboard_Macro || tabs_present() || (Read_This_Character != NULL)); } #if JED_HAS_LINE_ATTRIBUTES static int check_line_attr_no_modify (Line *l) { if (0 == (l->flags & JED_LINE_HIDDEN)) return 0; msg_error ("You cannot edit this hidden line."); return -1; } #endif static int next_visible_lines (int n) { #if JED_HAS_LINE_ATTRIBUTES int dn; int i; i = 0; while (i < n) { Line *l = CLine; dn = 0; do { l = l->next; dn++; } while ((l != NULL) && (l->flags & JED_LINE_HIDDEN)); if (l == NULL) break; CLine = l; LineNum += dn; i++; } if (i) Point = 0; return i; #else return nextline (&n); #endif } static int prev_visible_lines (int n) { #if JED_HAS_LINE_ATTRIBUTES int i, dn; i = 0; while (i < n) { Line *l = CLine; dn = 0; do { l = l->prev; dn++; } while ((l != NULL) && (l->flags & JED_LINE_HIDDEN)); if (l == NULL) break; CLine = l; LineNum -= dn; i++; } if (i) eol (); /* leave point at eol */ return i; #else return prevline (&n); #endif } static int prev_visible_chars (int n) { #if JED_HAS_LINE_ATTRIBUTES push_mark (); n = backwchars (&n); if (n && (CLine->flags & JED_LINE_HIDDEN)) { jed_skip_hidden_lines_backward (&Number_One); if (CLine->flags & JED_LINE_HIDDEN) { pop_mark (&Number_One); return 0; } } pop_mark (&Number_Zero); return n; #else return backwchars (&n); #endif } static int next_visible_chars (int n) { #if JED_HAS_LINE_ATTRIBUTES push_mark (); n = forwchars (&n); if (n && (CLine->flags & JED_LINE_HIDDEN)) { jed_skip_hidden_lines_forward (&Number_One); if (CLine->flags & JED_LINE_HIDDEN) { pop_mark (&Number_One); return 0; } } pop_mark (&Number_Zero); return n; #else return forwchars (&n); #endif } static void check_last_key_function (FVOID_STAR f) { /* For syntax highlighting */ if ((Last_Key_Function != f) && ((Last_Key_Function == (FVOID_STAR) ins_char_cmd) || (Last_Key_Function == (FVOID_STAR) eol_cmd) || (Last_Key_Function == (FVOID_STAR) delete_char_cmd) || (Last_Key_Function == (FVOID_STAR) backward_delete_char_cmd) || (Last_Key_Function == (FVOID_STAR) backward_delete_char_untabify))) register_change(0); } static void next_line_prev_line_helper (int *gcp, int *ret, int dr, FVOID_STAR f) { int gc; check_line(); gc = calculate_column(); if (Cursor_Motion <= 0) Goal_Column = gc; else if (Goal_Column < gc) Goal_Column = gc; *gcp = gc; Cursor_Motion = 2; check_last_key_function (f); *ret = (JWindow->trashed || (CLine == JScreen[JWindow->top + dr - 1].line) #if JED_HAS_LINE_ATTRIBUTES || (CLine->flags & JED_LINE_READONLY) #endif ); } static void eob_bob_error (int f) { char *str; if (CBuf->bob_eob_error_hook != NULL) { SLang_push_integer (f); SLexecute_function (CBuf->bob_eob_error_hook); return; } if (f < 0) str = Top_Of_Buffer_Error; else str = End_Of_Buffer_Error; msg_error (str); } /*}}}*/ /*{{{ interactive insert/delete functions */ /*{{{ Interactive char deletion functions */ int delete_char_cmd (void) { int upd, n; char ch; CHECK_READ_ONLY #if 0 ; #endif #if JED_HAS_LINE_ATTRIBUTES if (check_line_attr_no_modify (CLine)) return 0; #endif if (eobp()) { msg_error(End_Of_Buffer_Error); return(0); } ch = *(CLine->data + Point); if (fast_not_ok ((unsigned char) ch) || long_line () || *tt_Term_Cannot_Insert) { if ((Point == 0) && eolp() #if JED_HAS_LINE_ATTRIBUTES && ((CLine->prev != NULL) && (0 == (CLine->prev->flags & JED_LINE_READONLY))) #endif ) n = 1; else n = 0; /* same effect, update looks better */ n = backwchars(&n); del(); forwchars(&n); upd = 1; } else { upd = ((CBuf->flags & BUFFER_TRASHED) == 0); fast_del(); tt_delete_char (); } return(upd); } int backward_delete_char_cmd() { char ch; int ret; CHECK_READ_ONLY #if 0 ; #endif if (bobp()) { msg_error(Top_Of_Buffer_Error); return(0); } #if JED_HAS_LINE_ATTRIBUTES if (check_line_attr_no_modify (CLine)) return 0; #endif if (bolp()) { #if JED_HAS_LINE_ATTRIBUTES if (check_line_attr_no_modify (CLine->prev)) return 0; #endif backwchars(&Number_One); return delete_char_cmd(); } ch = *(CLine->data + (Point - 1)); if (fast_not_ok ((unsigned char) ch) || long_line () || *tt_Term_Cannot_Insert) { backwchars(&Number_One); del(); return(1); } ret = ((CBuf->flags & BUFFER_TRASHED) == 0); backwchars(&Number_One); tt_putchar('\b'); Screen_Col--; fast_del(); tt_delete_char(); return(ret); } int backward_delete_char_untabify() { unsigned char *p; int n; CHECK_READ_ONLY #if 0 ; #endif #if JED_HAS_LINE_ATTRIBUTES if (check_line_attr_no_modify (CLine)) return 0; #endif p = CLine->data + (Point - 1); if (!Point || (*p != '\t') || !Buffer_Local.tab) return backward_delete_char_cmd(); n = calculate_column() - 1; backwchars(&Number_One); del(); n = n - calculate_column(); ins_char_n_times(' ', n); return(1); } /*}}}*/ /*{{{ newline_and_indent */ int newline_and_indent () { static int in_function; if (in_function) return -1; #if JED_HAS_LINE_ATTRIBUTES if (check_line_attr_no_modify (CLine) || ((CLine->next != NULL) && eolp () && check_line_attr_no_modify (CLine->next))) return 0; #endif if (CBuf->newline_indent_hook != NULL) { in_function = 1; SLexecute_function(CBuf->newline_indent_hook); in_function = 0; return 1; } newline(); indent_line(); return(1); } /*}}}*/ /*{{{ newline */ int newline (void) { CHECK_READ_ONLY #if 0 ; #endif if (CBuf == MiniBuffer) return exit_minibuffer(); insert_string ("\n"); return(1); } int newline_cmd (void) { #if JED_HAS_LINE_ATTRIBUTES if (check_line_attr_no_modify (CLine) || ((CLine->next != NULL) && eolp () && check_line_attr_no_modify (CLine->next))) return 0; #endif return newline (); } /*}}}*/ /*{{{ ins_char_cmd */ int ins_char_cmd (void) { char ch; int wrap = Jed_Wrap_Column; int ret, ll; int do_blink; CHECK_READ_ONLY #if 0 ; #endif #if JED_HAS_LINE_ATTRIBUTES if (check_line_attr_no_modify (CLine)) return 0; #endif ch = (char) SLang_Last_Key_Char; if (ch == '\n') { newline(); return(1); } #if JED_HAS_ABBREVS if (CBuf->flags & ABBREV_MODE) { expand_abbrev (ch); } #endif if ((CBuf->flags & OVERWRITE_MODE) && !eolp()) del(); if (((ch == ' ') || (Point >= wrap)) && (CBuf->modes & WRAP_MODE) && (calculate_column() > wrap)) /* JWindow->width */ { ins(ch); wrap_line(0); /* do not format--- just wrap */ if (Indented_Text_Mode) indent_line (); if (CBuf->wrap_hook != NULL) SLexecute_function(CBuf->wrap_hook); return(1); } do_blink = ((((CBuf->syntax_table != NULL) && ((CBuf->syntax_table->char_syntax[(unsigned char) ch] & CLOSE_DELIM_SYNTAX))) || ((ch == ')') || (ch == '}') || (ch == ']'))) && !input_pending(&Number_Zero)); if ((ch == ' ') || fast_not_ok ((unsigned char) ch) || (CBuf->flags & OVERWRITE_MODE) || (*tt_Term_Cannot_Insert && !eolp()) ) { ins(ch); if (do_blink) blink_match (); return 1; } ret = ((CBuf->flags & BUFFER_TRASHED) == 0) || (User_Prefers_Line_Numbers > 1); if (long_line ()) ll = 1; else ll = 0; ret = ret || ll; /* fast_ins goes first so that screen structure is updated now for following calls to use. */ fast_ins(ch); if (!eolp() || ll) { tt_begin_insert(); tt_putchar(ch); tt_end_insert(); if (ll) register_change(0); } else tt_putchar(ch); Screen_Col++; if (do_blink) blink_match (); return(ret); } /*}}}*/ /*{{{ quoted_insert */ int quoted_insert() { char ch; int lerr = SLang_Error; CHECK_READ_ONLY if (*Error_Buffer || SLKeyBoard_Quit) return(0); if (Repeat_Factor != NULL) { ch = *Repeat_Factor; Repeat_Factor = NULL; } else { SLang_Key_TimeOut_Flag = 1; ch = jed_getkey(); SLang_Key_TimeOut_Flag = 0; } SLang_Error = lerr; /* ^G may set it */ if ((ch == '\n') && (CBuf == MiniBuffer)) { ins('\n'); /* msg_error("Not allowed!"); */ return (1); } SLKeyBoard_Quit = 0; ins_char_n_times(ch, 1); if ((CBuf->syntax_table != NULL) && (CBuf->syntax_table->char_syntax[(unsigned char) ch] & CLOSE_DELIM_SYNTAX) && !input_pending(&Number_Zero)) blink_match (); /* (ch); */ return(1); } /*}}}*/ /*{{{ kill_line */ int kill_line (void) { int n, pnt, flag = 0; CHECK_READ_ONLY if (eobp()) { msg_error(End_Of_Buffer_Error); return(0); } push_mark(); push_spot(); pnt = Point; eol(); n = Point - pnt; if ((!pnt && Kill_Line_Feature) || !n) { /* Either of these (flag =0,1) have the same effect on the buffer. * However, the first sets the mark at the end of the line and moves * the point to the end of the previous line. This way the current * line structure is deleted and the screen update looks better. */ if (!pnt && (CLine->prev != NULL) && (CLine->next != NULL)) { flag = 1; forwchars(&Number_One); } else n += forwchars(&Number_One); } if ((Last_Key_Function == (FVOID_STAR) kill_line) && (Paste_Buffer != NULL)) { copy_region_to_buffer(Paste_Buffer); } else copy_to_pastebuffer(); pop_spot(); if (flag) n += backwchars(&Number_One); generic_deln(&n); if (flag) forwchars(&Number_One); return(1); } /*}}}*/ /*}}}*/ /*{{{ interactive cursor movement functions */ /*{{{ Interactive char/line movement functions */ int previous_line_cmd (void) { int ret, gc; next_line_prev_line_helper (&gc, &ret, 0, (FVOID_STAR) previous_line_cmd); if ((CLine == CBuf->beg) || (1 != prev_visible_lines (1))) { eob_bob_error (-1); return 1; } point_column(Goal_Column); return(ret); } int next_line_cmd (void) { int ret, gc; next_line_prev_line_helper (&gc, &ret, JWindow->rows - 1, (FVOID_STAR) next_line_cmd); if ((CLine == CBuf->end) || (1 != next_visible_lines (1))) { eob_bob_error (1); return 1; } point_column(Goal_Column); return(ret); } int previous_char_cmd (void) { int pnt; Cursor_Motion = 1; pnt = Point - 1; check_last_key_function ((FVOID_STAR) previous_char_cmd); if (1 != prev_visible_chars (1)) { eob_bob_error (-2); return 1; } Goal_Column = calculate_column(); return (pnt == -1) || JWindow->trashed; } int next_char_cmd () { Cursor_Motion = 1; check_last_key_function ((FVOID_STAR) next_char_cmd); if (1 != next_visible_chars (1)) { eob_bob_error (2); return 1; } Goal_Column = calculate_column (); return !Point || JWindow->trashed; /* Point = 0 ==> moved a line */ } /*}}}*/ /*{{{ eol_cmd */ int eol_cmd (void) { eol(); if ((0 == (CBuf->flags & READ_ONLY)) #if JED_HAS_LINE_ATTRIBUTES && (0 == (CLine->flags & JED_LINE_READONLY)) #endif ) trim_whitespace(); return(1); } /*}}}*/ /*{{{ Scrolling/pageup/down functions */ int jed_buffer_visible (char *b) { return buffer_visible (find_buffer(b)); } static void scroll_completion (int dir) { Window_Type *w; if (jed_buffer_visible (Completion_Buffer)) { pop_to_buffer (Completion_Buffer); if (dir > 0) pagedown_cmd (); else pageup_cmd (); while (!IS_MINIBUFFER) other_window (); } else { w = JWindow; other_window(); if (!IS_MINIBUFFER) { if (dir > 0) pagedown_cmd (); else pageup_cmd (); } while (JWindow != w) other_window (); } } int goto_bottom_of_window (void) { int n; n = JWindow->rows - window_line (); return n == next_visible_lines (n); } void goto_top_of_window (void) { int n; n = window_line () - 1; (void) prev_visible_lines (n); } static int Last_Page_Line; static int Last_Page_Point; /* the page up/down commands set cursor_motion to -1 because we do not want to use any goal column information */ int pagedown_cmd() { int col, this_line, this_point; int n; Cursor_Motion = -1; if (IS_MINIBUFFER) { scroll_completion (1); return 1; } if (eobp()) { eob_bob_error (3); return 1; } n = JWindow->rows; if ((CBuf != JWindow->buffer) || (n == 1)) { return next_visible_lines (n); } if (JWindow->trashed) { update (NULL, 0, 0); if (JWindow->trashed) return next_visible_lines (n); } this_line = LineNum; this_point = Point; col = calculate_column (); if (goto_bottom_of_window ()) { recenter (&Number_One); } goto_column1 (&col); if ((Last_Key_Function == (FVOID_STAR) pageup_cmd) && is_line_visible (Last_Page_Line)) { goto_line (&Last_Page_Line); Point = Last_Page_Point; } else if (CLine->next == NULL) eol(); else Point = 0; Last_Page_Line = this_line; Last_Page_Point = this_point; return(1); } int pageup_cmd (void) { int col, this_line, this_point; int n; Cursor_Motion = -1; if (IS_MINIBUFFER) { scroll_completion (-1); return 1; } if (bobp()) { eob_bob_error (-3); return 1; } n = JWindow->rows; if ((CBuf != JWindow->buffer) || (n == 1)) { return prev_visible_lines (n); } if (JWindow->trashed) { update (NULL, 0, 0); if (JWindow->trashed) return prev_visible_lines (n); } this_line = LineNum; this_point = Point; col = calculate_column (); goto_top_of_window (); (void) goto_column1(&col); recenter(&JWindow->rows); if ((Last_Key_Function == (FVOID_STAR) pagedown_cmd) && is_line_visible (Last_Page_Line)) { goto_line (&Last_Page_Line); Point = Last_Page_Point; } else Point = 0; /* something like: Point = point_column(JWindow->column) better? */ Last_Page_Line = this_line; Last_Page_Point = this_point; return(1); } int scroll_right() { if (JWindow->column == 1) return(0); if ((JWindow->column = JWindow->column - JWindow->width / 2) < 1) { JWindow->column = 1; } touch_window(); return(1); } int scroll_left () { JWindow->column = JWindow->column + JWindow->width / 2; touch_window(); return(1); } /*}}}*/ /*}}}*/ /*{{{ Whitespace and Indention functions */ void insert_whitespace(int *n) { int tab = Buffer_Local.tab; int c1, c2, i, k, nspace; if ((nspace = *n) <= 0) return; CHECK_READ_ONLY_VOID c1 = calculate_column() - 1; c2 = c1 + nspace; if (tab && Jed_Use_Tabs) { i = c1 / tab; k = c2 / tab - i; if (k) nspace = c2 - (i + k) * tab; ins_char_n_times('\t', k); } ins_char_n_times(' ', nspace); } /* get indent value of current line, n is the column */ unsigned char *get_current_indent(int *np) { unsigned char *p, *pmax; int tab, n; tab = Buffer_Local.tab; p = CLine->data; pmax = CLine->data + CLine->len; n = 0; while((p < pmax) && ((*p == ' ') || (tab && (*p == '\t')))) { if (*p == '\t') n = tab * (n / tab + 1); else n++; p++; } *np = n; return p; } int trim_whitespace () { register unsigned char *p, *pmax, ch; int n, save_point, len; CHECK_READ_ONLY len = CLine->len; if (len == 0) return(0); save_point = Point; if (Point == len) Point--; /* Note that we save the point before --ing it. This way the comparison made below will effectively restore it if pointing at non whitespace */ p = CLine->data + Point; if (Point && (*p == '\n') && (CBuf != MiniBuffer)) { Point--; p--; } while ((Point > 0) && (((ch = *p) == '\t') || (ch == ' '))) { Point--; p--; } if (save_point != Point) if (!eolp() && ((*p != ' ') && (*p != '\t'))) { Point++; p++; } n = 0; /* this needs to be inlined. Actually for undo, I need del(n)! */ pmax = CLine->data + CLine->len; while ((p < pmax) && ((ch = *p) != '\n') && ((ch == ' ') || (ch == '\t'))) p++, n++; deln(&n); return(1); } /* indent line to column n */ void indent_to(int n) { int m; get_current_indent(&m); if (n != m) { Point = 0; trim_whitespace(); if (n >= 0) insert_whitespace(&n); } } int indent_line () { int n, n1; static int in_function; if (in_function) return -1; if (CBuf->indent_hook != NULL) { in_function = 1; SLexecute_function(CBuf->indent_hook); in_function = 0; return 1; } CHECK_READ_ONLY if (CLine == CBuf->beg) return(0); push_spot(); CLine = CLine->prev; get_current_indent (&n); CLine = CLine->next; indent_to(n); pop_spot(); /* This moves the cursor to the first non whitspace char if we are before it. Otherwise leave it alone */ n1 = calculate_column(); get_current_indent(&n); if (n1 <= n) point_column(n + 1); return 1; } /*}}}*/ /*{{{ goto_column and goto_column1 */ /* goto to column c, returns actual column */ int goto_column1(int *cp) { int c1, c = *cp; if (c <= 0) c = 1; eol(); c1 = calculate_column(); if (c1 > c) { point_column(c); c1 = calculate_column(); } return(c1); } /* move cursor to column c adding spaces if necessary */ void goto_column(int *c) { int c1 = *c; if (c1 <= 0) c1 = 1; c1 = c1 - goto_column1(&c1); insert_whitespace(&c1); } /*}}}*/ /*{{{ skip_whitespace */ /* does not leave current line */ unsigned int skip_whitespace() { unsigned char *p, *pmax; if (CLine->len == 0) return('\n'); p = CLine->data + Point; eol(); pmax = CLine->data + Point; while(p < pmax) { if ((*p != ' ') && (*p != '\t')) break; p++; } Point = (int) (p - CLine->data); if (Point == CLine->len) return '\n'; return(*p); } /*}}}*/ /*{{{ skip_chars1 */ void skip_chars1(char *range, int reverse) { unsigned char lut[256]; unsigned char *p, *pmax; Line *line; int n = 0; SLmake_lut(lut, (unsigned char *) range, (unsigned char) reverse); /* more flexibility is achieved with following line */ if (reverse && lut['\n']) lut['\n'] = 0; line = CLine; while (line != NULL) { CLine = line; p = line->data + Point; pmax = line->data + line->len; while (p < pmax) { if (0 == lut[*p]) { Point = (int)(p - CLine->data); LineNum += n; return; } p++; } Point = 0; line = CLine->next; n++; } eob(); } /*}}}*/ /*{{{ bskip_chars1 */ void bskip_chars1(char *range, int reverse) { unsigned char lut[256]; unsigned char *p; Line *line = CLine; int n = 0; SLmake_lut(lut, (unsigned char *) range, (unsigned char) reverse); /* more flexibility is achieved with following line */ if (reverse && lut['\n']) lut['\n'] = 0; while (1) { if (Point == 0) { if (lut['\n'] == 0) return; if (NULL == (line = CLine->prev)) break; Point = line->len - 1; n++; } CLine = line; p = line->data + (Point - 1); while (p >= line->data) { if (0 == lut[*p]) { Point = 1 + (int)(p - line->data); LineNum -= n; return; } p--; } Point = 0; } bob(); } /*}}}*/ /*{{{ skip_chars */ void skip_chars (char *range) { if (*range == '^') skip_chars1(range + 1, 1); else { if (*range == '\\') range++; skip_chars1(range, 0); } } /*}}}*/ /*{{{ bskip_chars */ void bskip_chars (char *range) { if (*range == '^') bskip_chars1(range + 1, 1); else { if (*range == '\\') range++; bskip_chars1(range, 0); } } /*}}}*/ /*{{{ looking_at */ /* returns < 0 if what is smaller than current thing, 0 if matched, pos otherwise */ int looking_at(char *what) { register unsigned char *p, *pmax; register unsigned char *w = (unsigned char *) what, ch; Line *l = CLine; p = l->data + Point; while (1) { pmax = l->data + l->len; while (((ch = *w) != 0) && (p < pmax)) { #define upcase(ch) (Case_Sensitive ? ch : UPPER_CASE(ch)) if ((upcase(ch) != upcase(*p))) return 0; p++; w++; } if (ch == 0) return 1; l = l->next; if (l == NULL) return 0; p = l->data; } } /*}}}*/ /*{{{ Exiting the editor */ /*{{{ sys_spawn_cmd */ int sys_spawn_cmd (void) { if ((Jed_Secure_Mode) || (Jed_Suspension_Not_Allowed)) { msg_error ("Access to shell denied."); return -1; } if (Batch) { sys_suspend (); return 0; } if (X_Suspend_Hook != NULL) { (*X_Suspend_Hook) (); return (0); } if (-1 == SLang_run_hooks("suspend_hook", 0)) return 0; reset_display(); reset_tty(); sys_suspend(); if (-1 == init_tty()) { exit_error ("Unable to initialize terminal.", 0); } flush_input (); init_display(1); /* cls(); */ (void) SLang_run_hooks("resume_hook", 0); check_buffers(); return(1); } /*}}}*/ /*{{{ quit_jed */ int quit_jed(void) { Buffer *b = CBuf; /* Any buffer marked with AUTO_SAVE_JUST_SAVE flag should be saved * if it has not already been. That is what the flag is for and this * code fragment carries this out. */ do { if ((b->flags & AUTO_SAVE_JUST_SAVE) && (b->flags & BUFFER_TRASHED) && (*b->file)) { while (b->narrow != NULL) widen_buffer(b); auto_save_buffer(b); /* actually, it will save it */ } #if defined(__WIN32__) && JED_HAS_SUBPROCESSES if (b->subprocess) jed_kill_process (b->subprocess - 1); #endif b = b->next; } while (b != CBuf); reset_display(); reset_tty(); #ifdef VMS vms_cancel_exithandler(); #endif #ifdef SLANG_STATS SLang_dump_stats("slang.dat"); #endif #ifdef MALLOC_DEBUG SLmalloc_dump_statistics (); #endif /* SLstring_dump_stats (); */ exit(0); return(1); } /*}}}*/ static int get_y_n_response (char *fmt, char *arg) { char msg [JED_MAX_PATH_LEN + 256]; int ans; if (arg == NULL) { arg = fmt; fmt = "%s"; } sprintf (msg, fmt, arg); jed_vmessage (1, "%s? (y/n)", msg); ans = my_getkey(); message (NULL); if ((ans == 'y') || (ans == 'Y')) return 1; if ((ans == 'n') || (ans == 'N')) return 0; if (SLKeyBoard_Quit) return -1; beep (); return get_yes_no (msg); } /*{{{ save_some_buffers */ /* I should try it like emacs--- if prefix argument, then save all without user intervention */ int save_some_buffers (void) { Buffer *b, *tmp; int ans = 0; int err; b = CBuf; do { if ((b->flags & BUFFER_TRASHED) && (*b->file)) { if (b->flags & AUTO_SAVE_JUST_SAVE) ans = 1; else ans = get_y_n_response ("Buffer %s not saved. Save it", b->name); if (ans == -1) /* warning--- bug here if user edits file at startup and forgets to save it then aborts. */ return -1; if (ans == 1) { tmp = CBuf; switch_to_buffer(b); while (b->narrow != NULL) widen_buffer(b); err = write_file_with_backup(b->dir, b->file); switch_to_buffer(tmp); if (err < 0) return -1; b->flags &= ~BUFFER_TRASHED; /* b->flags |= AUTO_SAVE_BUFFER; */ b->hits = 0; } } b = b->next; } while (b != CBuf); clear_message (); return 1; } /*}}}*/ /*{{{ exit_jed */ int exit_jed (void) { static int in_exit_jed = 0; if (in_exit_jed == 0) { in_exit_jed = 1; if (-1 == SLang_run_hooks("exit_hook", 0)) { in_exit_jed = 0; return 1; } } in_exit_jed = 0; if (SLang_Error) return 0; #if JED_HAS_SUBPROCESSES if (Num_Subprocesses && (1 != get_y_n_response ("Subprocesses exist. Exit anyway", NULL))) return 1; #endif if (save_some_buffers() > 0) quit_jed(); return 1; } /*}}}*/ /*}}}*/