/* | ee (easy editor) | | An easy to use, simple screen oriented editor. | | written by Hugh Mahon | | | Copyright (c) 2009, Hugh Mahon | All rights reserved. | | Redistribution and use in source and binary forms, with or without | modification, are permitted provided that the following conditions | are met: | | * Redistributions of source code must retain the above copyright | notice, this list of conditions and the following disclaimer. | * Redistributions in binary form must reproduce the above | copyright notice, this list of conditions and the following | disclaimer in the documentation and/or other materials provided | with the distribution. | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | POSSIBILITY OF SUCH DAMAGE. | | -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- | | This editor was purposely developed to be simple, both in | interface and implementation. This editor was developed to | address a specific audience: the user who is new to computers | (especially UNIX). | | ee is not aimed at technical users; for that reason more | complex features were intentionally left out. In addition, | ee is intended to be compiled by people with little computer | experience, which means that it needs to be small, relatively | simple in implementation, and portable. | | This software and documentation contains | proprietary information which is protected by | copyright. All rights are reserved. | | $Header: /home/hugh/sources/old_ae/RCS/ee.c,v 1.102 2009/02/17 03:22:50 hugh Exp hugh $ | */ #include __FBSDID("$FreeBSD$"); char *ee_copyright_message = "Copyright (c) 1986, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 2009 Hugh Mahon "; #include "ee_version.h" char *version = "@(#) ee, version " EE_VERSION " $Revision: 1.102 $"; #ifdef NCURSE #include "new_curse.h" #elif HAS_NCURSES #include #else #include #endif #ifdef HAS_CTYPE #include #endif #include #include #include #include #include #include #include #ifdef HAS_SYS_WAIT #include #endif #ifdef HAS_STDLIB #include #endif #ifdef HAS_STDARG #include #endif #ifdef HAS_UNISTD #include #endif #ifndef NO_CATGETS #include #include nl_catd catalog; #else #define catgetlocal(a, b) (b) #endif /* NO_CATGETS */ #ifndef SIGCHLD #define SIGCHLD SIGCLD #endif #define TAB 9 #define max(a, b) (a > b ? a : b) #define min(a, b) (a < b ? a : b) /* | defines for type of data to show in info window */ #define CONTROL_KEYS 1 #define COMMANDS 2 struct text { unsigned char *line; /* line of characters */ int line_number; /* line number */ int line_length; /* actual number of characters in the line */ int max_length; /* maximum number of characters the line handles */ struct text *next_line; /* next line of text */ struct text *prev_line; /* previous line of text */ }; struct text *first_line; /* first line of current buffer */ struct text *dlt_line; /* structure for info on deleted line */ struct text *curr_line; /* current line cursor is on */ struct text *tmp_line; /* temporary line pointer */ struct text *srch_line; /* temporary pointer for search routine */ struct files { /* structure to store names of files to be edited*/ unsigned char *name; /* name of file */ struct files *next_name; }; struct files *top_of_stack = NULL; int d_wrd_len; /* length of deleted word */ int position; /* offset in bytes from begin of line */ int scr_pos; /* horizontal position */ int scr_vert; /* vertical position on screen */ int scr_horz; /* horizontal position on screen */ int absolute_lin; /* number of lines from top */ int tmp_vert, tmp_horz; int input_file; /* indicate to read input file */ int recv_file; /* indicate reading a file */ int edit; /* continue executing while true */ int gold; /* 'gold' function key pressed */ int fildes; /* file descriptor */ int case_sen; /* case sensitive search flag */ int last_line; /* last line for text display */ int last_col; /* last column for text display */ int horiz_offset = 0; /* offset from left edge of text */ int clear_com_win; /* flag to indicate com_win needs clearing */ int text_changes = FALSE; /* indicate changes have been made to text */ int get_fd; /* file descriptor for reading a file */ int info_window = TRUE; /* flag to indicate if help window visible */ int info_type = CONTROL_KEYS; /* flag to indicate type of info to display */ int expand_tabs = TRUE; /* flag for expanding tabs */ int right_margin = 0; /* the right margin */ int observ_margins = TRUE; /* flag for whether margins are observed */ int shell_fork; int temp_stdin; /* temporary storage for stdin */ int temp_stdout; /* temp storage for stdout descriptor */ int temp_stderr; /* temp storage for stderr descriptor */ int pipe_out[2]; /* pipe file desc for output */ int pipe_in[2]; /* pipe file descriptors for input */ int out_pipe; /* flag that info is piped out */ int in_pipe; /* flag that info is piped in */ int formatted = FALSE; /* flag indicating paragraph formatted */ int auto_format = FALSE; /* flag for auto_format mode */ int restricted = FALSE; /* flag to indicate restricted mode */ int nohighlight = FALSE; /* turns off highlighting */ int eightbit = TRUE; /* eight bit character flag */ int local_LINES = 0; /* copy of LINES, to detect when win resizes */ int local_COLS = 0; /* copy of COLS, to detect when win resizes */ int curses_initialized = FALSE; /* flag indicating if curses has been started*/ int emacs_keys_mode = FALSE; /* mode for if emacs key binings are used */ int ee_chinese = FALSE; /* allows handling of multi-byte characters */ /* by checking for high bit in a byte the */ /* code recognizes a two-byte character */ /* sequence */ unsigned char *point; /* points to current position in line */ unsigned char *srch_str; /* pointer for search string */ unsigned char *u_srch_str; /* pointer to non-case sensitive search */ unsigned char *srch_1; /* pointer to start of suspect string */ unsigned char *srch_2; /* pointer to next character of string */ unsigned char *srch_3; unsigned char *in_file_name = NULL; /* name of input file */ char *tmp_file; /* temporary file name */ unsigned char *d_char; /* deleted character */ unsigned char *d_word; /* deleted word */ unsigned char *d_line; /* deleted line */ char in_string[513]; /* buffer for reading a file */ unsigned char *print_command = (unsigned char *)"lpr"; /* string to use for the print command */ unsigned char *start_at_line = NULL; /* move to this line at start of session*/ int in; /* input character */ FILE *temp_fp; /* temporary file pointer */ FILE *bit_bucket; /* file pointer to /dev/null */ char *table[] = { "^@", "^A", "^B", "^C", "^D", "^E", "^F", "^G", "^H", "\t", "^J", "^K", "^L", "^M", "^N", "^O", "^P", "^Q", "^R", "^S", "^T", "^U", "^V", "^W", "^X", "^Y", "^Z", "^[", "^\\", "^]", "^^", "^_" }; WINDOW *com_win; WINDOW *text_win; WINDOW *help_win; WINDOW *info_win; #if defined(__STDC__) || defined(__cplusplus) #define P_(s) s #else #define P_(s) () #endif /* | The following structure allows menu items to be flexibly declared. | The first item is the string describing the selection, the second | is the address of the procedure to call when the item is selected, | and the third is the argument for the procedure. | | For those systems with i18n, the string should be accompanied by a | catalog number. The 'int *' should be replaced with 'void *' on | systems with that type. | | The first menu item will be the title of the menu, with NULL | parameters for the procedure and argument, followed by the menu items. | | If the procedure value is NULL, the menu item is displayed, but no | procedure is called when the item is selected. The number of the | item will be returned. If the third (argument) parameter is -1, no | argument is given to the procedure when it is called. */ struct menu_entries { char *item_string; int (*procedure)P_((struct menu_entries *)); struct menu_entries *ptr_argument; int (*iprocedure)P_((int)); void (*nprocedure)P_((void)); int argument; }; int main P_((int argc, char *argv[])); unsigned char *resiz_line P_((int factor, struct text *rline, int rpos)); void insert P_((int character)); void delete P_((int disp)); void scanline P_((unsigned char *pos)); int tabshift P_((int temp_int)); int out_char P_((WINDOW *window, int character, int column)); int len_char P_((int character, int column)); void draw_line P_((int vertical, int horiz, unsigned char *ptr, int t_pos, int length)); void insert_line P_((int disp)); struct text *txtalloc P_((void)); struct files *name_alloc P_((void)); unsigned char *next_word P_((unsigned char *string)); void prev_word P_((void)); void control P_((void)); void emacs_control P_((void)); void bottom P_((void)); void top P_((void)); void nextline P_((void)); void prevline P_((void)); void left P_((int disp)); void right P_((int disp)); void find_pos P_((void)); void up P_((void)); void down P_((void)); void function_key P_((void)); void print_buffer P_((void)); void command_prompt P_((void)); void command P_((char *cmd_str1)); int scan P_((char *line, int offset, int column)); char *get_string P_((char *prompt, int advance)); int compare P_((char *string1, char *string2, int sensitive)); void goto_line P_((char *cmd_str)); void midscreen P_((int line, unsigned char *pnt)); void get_options P_((int numargs, char *arguments[])); void check_fp P_((void)); void get_file P_((char *file_name)); void get_line P_((int length, unsigned char *in_string, int *append)); void draw_screen P_((void)); void finish P_((void)); int quit P_((int noverify)); void edit_abort P_((int arg)); void delete_text P_((void)); int write_file P_((char *file_name, int warn_if_exists)); int search P_((int display_message)); void search_prompt P_((void)); void del_char P_((void)); void undel_char P_((void)); void del_word P_((void)); void undel_word P_((void)); void del_line P_((void)); void undel_line P_((void)); void adv_word P_((void)); void move_rel P_((char *direction, int lines)); void eol P_((void)); void bol P_((void)); void adv_line P_((void)); void sh_command P_((char *string)); void set_up_term P_((void)); void resize_check P_((void)); int menu_op P_((struct menu_entries *)); void paint_menu P_((struct menu_entries menu_list[], int max_width, int max_height, int list_size, int top_offset, WINDOW *menu_win, int off_start, int vert_size)); void help P_((void)); void paint_info_win P_((void)); void no_info_window P_((void)); void create_info_window P_((void)); int file_op P_((int arg)); void shell_op P_((void)); void leave_op P_((void)); void redraw P_((void)); int Blank_Line P_((struct text *test_line)); void Format P_((void)); void ee_init P_((void)); void dump_ee_conf P_((void)); void echo_string P_((char *string)); void spell_op P_((void)); void ispell_op P_((void)); int first_word_len P_((struct text *test_line)); void Auto_Format P_((void)); void modes_op P_((void)); char *is_in_string P_((char *string, char *substring)); char *resolve_name P_((char *name)); int restrict_mode P_((void)); int unique_test P_((char *string, char *list[])); void strings_init P_((void)); #undef P_ /* | allocate space here for the strings that will be in the menu */ struct menu_entries modes_menu[] = { {"", NULL, NULL, NULL, NULL, 0}, /* title */ {"", NULL, NULL, NULL, NULL, -1}, /* 1. tabs to spaces */ {"", NULL, NULL, NULL, NULL, -1}, /* 2. case sensitive search*/ {"", NULL, NULL, NULL, NULL, -1}, /* 3. margins observed */ {"", NULL, NULL, NULL, NULL, -1}, /* 4. auto-paragraph */ {"", NULL, NULL, NULL, NULL, -1}, /* 5. eightbit characters*/ {"", NULL, NULL, NULL, NULL, -1}, /* 6. info window */ {"", NULL, NULL, NULL, NULL, -1}, /* 7. emacs key bindings*/ {"", NULL, NULL, NULL, NULL, -1}, /* 8. right margin */ {"", NULL, NULL, NULL, NULL, -1}, /* 9. chinese text */ {"", NULL, NULL, NULL, dump_ee_conf, -1}, /* 10. save editor config */ {NULL, NULL, NULL, NULL, NULL, -1} /* terminator */ }; char *mode_strings[11]; #define NUM_MODES_ITEMS 10 struct menu_entries config_dump_menu[] = { {"", NULL, NULL, NULL, NULL, 0}, {"", NULL, NULL, NULL, NULL, -1}, {"", NULL, NULL, NULL, NULL, -1}, {NULL, NULL, NULL, NULL, NULL, -1} }; struct menu_entries leave_menu[] = { {"", NULL, NULL, NULL, NULL, -1}, {"", NULL, NULL, NULL, finish, -1}, {"", NULL, NULL, quit, NULL, TRUE}, {NULL, NULL, NULL, NULL, NULL, -1} }; #define READ_FILE 1 #define WRITE_FILE 2 #define SAVE_FILE 3 struct menu_entries file_menu[] = { {"", NULL, NULL, NULL, NULL, -1}, {"", NULL, NULL, file_op, NULL, READ_FILE}, {"", NULL, NULL, file_op, NULL, WRITE_FILE}, {"", NULL, NULL, file_op, NULL, SAVE_FILE}, {"", NULL, NULL, NULL, print_buffer, -1}, {NULL, NULL, NULL, NULL, NULL, -1} }; struct menu_entries search_menu[] = { {"", NULL, NULL, NULL, NULL, 0}, {"", NULL, NULL, NULL, search_prompt, -1}, {"", NULL, NULL, search, NULL, TRUE}, {NULL, NULL, NULL, NULL, NULL, -1} }; struct menu_entries spell_menu[] = { {"", NULL, NULL, NULL, NULL, -1}, {"", NULL, NULL, NULL, spell_op, -1}, {"", NULL, NULL, NULL, ispell_op, -1}, {NULL, NULL, NULL, NULL, NULL, -1} }; struct menu_entries misc_menu[] = { {"", NULL, NULL, NULL, NULL, -1}, {"", NULL, NULL, NULL, Format, -1}, {"", NULL, NULL, NULL, shell_op, -1}, {"", menu_op, spell_menu, NULL, NULL, -1}, {NULL, NULL, NULL, NULL, NULL, -1} }; struct menu_entries main_menu[] = { {"", NULL, NULL, NULL, NULL, -1}, {"", NULL, NULL, NULL, leave_op, -1}, {"", NULL, NULL, NULL, help, -1}, {"", menu_op, file_menu, NULL, NULL, -1}, {"", NULL, NULL, NULL, redraw, -1}, {"", NULL, NULL, NULL, modes_op, -1}, {"", menu_op, search_menu, NULL, NULL, -1}, {"", menu_op, misc_menu, NULL, NULL, -1}, {NULL, NULL, NULL, NULL, NULL, -1} }; char *help_text[23]; char *control_keys[5]; char *emacs_help_text[22]; char *emacs_control_keys[5]; char *command_strings[5]; char *commands[32]; char *init_strings[22]; #define MENU_WARN 1 #define max_alpha_char 36 /* | Declarations for strings for localization */ char *com_win_message; /* to be shown in com_win if no info window */ char *no_file_string; char *ascii_code_str; char *printer_msg_str; char *command_str; char *file_write_prompt_str; char *file_read_prompt_str; char *char_str; char *unkn_cmd_str; char *non_unique_cmd_msg; char *line_num_str; char *line_len_str; char *current_file_str; char *usage0; char *usage1; char *usage2; char *usage3; char *usage4; char *file_is_dir_msg; char *new_file_msg; char *cant_open_msg; char *open_file_msg; char *file_read_fin_msg; char *reading_file_msg; char *read_only_msg; char *file_read_lines_msg; char *save_file_name_prompt; char *file_not_saved_msg; char *changes_made_prompt; char *yes_char; char *file_exists_prompt; char *create_file_fail_msg; char *writing_file_msg; char *file_written_msg; char *searching_msg; char *str_not_found_msg; char *search_prompt_str; char *exec_err_msg; char *continue_msg; char *menu_cancel_msg; char *menu_size_err_msg; char *press_any_key_msg; char *shell_prompt; char *formatting_msg; char *shell_echo_msg; char *spell_in_prog_msg; char *margin_prompt; char *restricted_msg; char *ON; char *OFF; char *HELP; char *WRITE; char *READ; char *LINE; char *FILE_str; char *CHARACTER; char *REDRAW; char *RESEQUENCE; char *AUTHOR; char *VERSION; char *CASE; char *NOCASE; char *EXPAND; char *NOEXPAND; char *Exit_string; char *QUIT_string; char *INFO; char *NOINFO; char *MARGINS; char *NOMARGINS; char *AUTOFORMAT; char *NOAUTOFORMAT; char *Echo; char *PRINTCOMMAND; char *RIGHTMARGIN; char *HIGHLIGHT; char *NOHIGHLIGHT; char *EIGHTBIT; char *NOEIGHTBIT; char *EMACS_string; char *NOEMACS_string; char *conf_dump_err_msg; char *conf_dump_success_msg; char *conf_not_saved_msg; char *ree_no_file_msg; char *cancel_string; char *menu_too_lrg_msg; char *more_above_str, *more_below_str; char *separator = "==============================================================================="; char *chinese_cmd, *nochinese_cmd; #ifndef __STDC__ #ifndef HAS_STDLIB extern char *malloc(); extern char *realloc(); extern char *getenv(); FILE *fopen(); /* declaration for open function */ #endif /* HAS_STDLIB */ #endif /* __STDC__ */ int main(argc, argv) /* beginning of main program */ int argc; char *argv[]; { int counter; for (counter = 1; counter < 24; counter++) signal(counter, SIG_IGN); signal(SIGCHLD, SIG_DFL); signal(SIGSEGV, SIG_DFL); signal(SIGINT, edit_abort); d_char = malloc(3); /* provide a buffer for multi-byte chars */ d_word = malloc(150); *d_word = '\0'; d_line = NULL; dlt_line = txtalloc(); dlt_line->line = d_line; dlt_line->line_length = 0; curr_line = first_line = txtalloc(); curr_line->line = point = malloc(10); curr_line->line_length = 1; curr_line->max_length = 10; curr_line->prev_line = NULL; curr_line->next_line = NULL; curr_line->line_number = 1; srch_str = NULL; u_srch_str = NULL; position = 1; scr_pos =0; scr_vert = 0; scr_horz = 0; absolute_lin = 1; bit_bucket = fopen("/dev/null", "w"); edit = TRUE; gold = case_sen = FALSE; shell_fork = TRUE; strings_init(); ee_init(); if (argc > 0 ) get_options(argc, argv); set_up_term(); if (right_margin == 0) right_margin = COLS - 1; if (top_of_stack == NULL) { if (restrict_mode()) { wmove(com_win, 0, 0); werase(com_win); wprintw(com_win, ree_no_file_msg); wrefresh(com_win); edit_abort(0); } wprintw(com_win, no_file_string); wrefresh(com_win); } else check_fp(); clear_com_win = TRUE; counter = 0; while(edit) { /* | display line and column information */ if (info_window) { if (!nohighlight) wstandout(info_win); wmove(info_win, 5, 0); wprintw(info_win, separator); wmove(info_win, 5, 5); wprintw(info_win, "line %d col %d lines from top %d ", curr_line->line_number, scr_horz, absolute_lin); wstandend(info_win); wrefresh(info_win); } wrefresh(text_win); in = wgetch(text_win); if (in == -1) exit(0); /* without this exit ee will go into an infinite loop if the network session detaches */ resize_check(); if (clear_com_win) { clear_com_win = FALSE; wmove(com_win, 0, 0); werase(com_win); if (!info_window) { wprintw(com_win, "%s", com_win_message); } wrefresh(com_win); } if (in > 255) function_key(); else if ((in == '\10') || (in == 127)) { in = 8; /* make sure key is set to backspace */ delete(TRUE); } else if ((in > 31) || (in == 9)) insert(in); else if ((in >= 0) && (in <= 31)) { if (emacs_keys_mode) emacs_control(); else control(); } } return(0); } unsigned char * resiz_line(factor, rline, rpos) /* resize the line to length + factor*/ int factor; /* resize factor */ struct text *rline; /* position in line */ int rpos; { unsigned char *rpoint; int resiz_var; rline->max_length += factor; rpoint = rline->line = realloc(rline->line, rline->max_length ); for (resiz_var = 1 ; (resiz_var < rpos) ; resiz_var++) rpoint++; return(rpoint); } void insert(character) /* insert character into line */ int character; /* new character */ { int counter; int value; unsigned char *temp; /* temporary pointer */ unsigned char *temp2; /* temporary pointer */ if ((character == '\011') && (expand_tabs)) { counter = len_char('\011', scr_horz); for (; counter > 0; counter--) insert(' '); if (auto_format) Auto_Format(); return; } text_changes = TRUE; if ((curr_line->max_length - curr_line->line_length) < 5) point = resiz_line(10, curr_line, position); curr_line->line_length++; temp = point; counter = position; while (counter < curr_line->line_length) /* find end of line */ { counter++; temp++; } temp++; /* increase length of line by one */ while (point < temp) { temp2=temp - 1; *temp= *temp2; /* shift characters over by one */ temp--; } *point = character; /* insert new character */ wclrtoeol(text_win); if (((character >= 0) && (character < ' ')) || (character >= 127)) /* check for TAB character*/ { scr_pos = scr_horz += out_char(text_win, character, scr_horz); point++; position++; } else { waddch(text_win, character); scr_pos = ++scr_horz; point++; position ++; } if ((observ_margins) && (right_margin < scr_pos)) { counter = position; while (scr_pos > right_margin) prev_word(); if (scr_pos == 0) { while (position < counter) right(TRUE); } else { counter -= position; insert_line(TRUE); for (value = 0; value < counter; value++) right(TRUE); } } if ((scr_horz - horiz_offset) > last_col) { horiz_offset += 8; midscreen(scr_vert, point); } if ((auto_format) && (character == ' ') && (!formatted)) Auto_Format(); else if ((character != ' ') && (character != '\t')) formatted = FALSE; draw_line(scr_vert, scr_horz, point, position, curr_line->line_length); } void delete(disp) /* delete character */ int disp; { unsigned char *tp; unsigned char *temp2; struct text *temp_buff; int temp_vert; int temp_pos; int del_width = 1; if (point != curr_line->line) /* if not at beginning of line */ { text_changes = TRUE; temp2 = tp = point; if ((ee_chinese) && (position >= 2) && (*(point - 2) > 127)) { del_width = 2; } tp -= del_width; point -= del_width; position -= del_width; temp_pos = position; curr_line->line_length -= del_width; if ((*tp < ' ') || (*tp >= 127)) /* check for TAB */ scanline(tp); else scr_horz -= del_width; scr_pos = scr_horz; if (in == 8) { if (del_width == 1) *d_char = *point; /* save deleted character */ else { d_char[0] = *point; d_char[1] = *(point + 1); } d_char[del_width] = '\0'; } while (temp_pos <= curr_line->line_length) { temp_pos++; *tp = *temp2; tp++; temp2++; } if (scr_horz < horiz_offset) { horiz_offset -= 8; midscreen(scr_vert, point); } } else if (curr_line->prev_line != NULL) { absolute_lin--; text_changes = TRUE; left(disp); /* go to previous line */ temp_buff = curr_line->next_line; point = resiz_line(temp_buff->line_length, curr_line, position); if (temp_buff->next_line != NULL) temp_buff->next_line->prev_line = curr_line; curr_line->next_line = temp_buff->next_line; temp2 = temp_buff->line; if (in == 8) { d_char[0] = '\n'; d_char[1] = '\0'; } tp = point; temp_pos = 1; while (temp_pos < temp_buff->line_length) { curr_line->line_length++; temp_pos++; *tp = *temp2; tp++; temp2++; } *tp = '\0'; free(temp_buff->line); free(temp_buff); temp_buff = curr_line; temp_vert = scr_vert; scr_pos = scr_horz; if (scr_vert < last_line) { wmove(text_win, scr_vert + 1, 0); wdeleteln(text_win); } while ((temp_buff != NULL) && (temp_vert < last_line)) { temp_buff = temp_buff->next_line; temp_vert++; } if ((temp_vert == last_line) && (temp_buff != NULL)) { tp = temp_buff->line; wmove(text_win, last_line,0); wclrtobot(text_win); draw_line(last_line, 0, tp, 1, temp_buff->line_length); wmove(text_win, scr_vert, (scr_horz - horiz_offset)); } } draw_line(scr_vert, scr_horz, point, position, curr_line->line_length); formatted = FALSE; } void scanline(pos) /* find the proper horizontal position for the pointer */ unsigned char *pos; { int temp; unsigned char *ptr; ptr = curr_line->line; temp = 0; while (ptr < pos) { if (*ptr <= 8) temp += 2; else if (*ptr == 9) temp += tabshift(temp); else if ((*ptr >= 10) && (*ptr <= 31)) temp += 2; else if ((*ptr >= 32) && (*ptr < 127)) temp++; else if (*ptr == 127) temp += 2; else if (!eightbit) temp += 5; else temp++; ptr++; } scr_horz = temp; if ((scr_horz - horiz_offset) > last_col) { horiz_offset = (scr_horz - (scr_horz % 8)) - (COLS - 8); midscreen(scr_vert, point); } else if (scr_horz < horiz_offset) { horiz_offset = max(0, (scr_horz - (scr_horz % 8))); midscreen(scr_vert, point); } } int tabshift(temp_int) /* give the number of spaces to shift */ int temp_int; { int leftover; leftover = ((temp_int + 1) % 8); if (leftover == 0) return (1); else return (9 - leftover); } int out_char(window, character, column) /* output non-printing character */ WINDOW *window; char character; int column; { int i1, i2; char *string; char string2[8]; if (character == TAB) { i1 = tabshift(column); for (i2 = 0; (i2 < i1) && (((column+i2+1)-horiz_offset) < last_col); i2++) { waddch(window, ' '); } return(i1); } else if ((character >= '\0') && (character < ' ')) { string = table[(int) character]; } else if ((character < 0) || (character >= 127)) { if (character == 127) string = "^?"; else if (!eightbit) { sprintf(string2, "<%d>", (character < 0) ? (character + 256) : character); string = string2; } else { waddch(window, (char)character ); return(1); } } else { waddch(window, (char)character); return(1); } for (i2 = 0; (string[i2] != '\0') && (((column+i2+1)-horiz_offset) < last_col); i2++) waddch(window, string[i2]); return(strlen(string)); } int len_char(character, column) /* return the length of the character */ char character; int column; /* the column must be known to provide spacing for tabs */ { int length; if (character == '\t') length = tabshift(column); else if ((character >= 0) && (character < 32)) length = 2; else if ((character >= 32) && (character <= 126)) length = 1; else if (character == 127) length = 2; else if (((character > 126) || (character < 0)) && (!eightbit)) length = 5; else length = 1; return(length); } void draw_line(vertical, horiz, ptr, t_pos, length) /* redraw line from current position */ int vertical; /* current vertical position on screen */ int horiz; /* current horizontal position on screen */ unsigned char *ptr; /* pointer to line */ int t_pos; /* current position (offset in bytes) from bol */ int length; /* length (in bytes) of line */ { int d; /* partial length of special or tab char to display */ unsigned char *temp; /* temporary pointer to position in line */ int abs_column; /* offset in screen units from begin of line */ int column; /* horizontal position on screen */ int row; /* vertical position on screen */ int posit; /* temporary position indicator within line */ abs_column = horiz; column = horiz - horiz_offset; row = vertical; temp = ptr; d = 0; posit = t_pos; if (column < 0) { wmove(text_win, row, 0); wclrtoeol(text_win); } while (column < 0) { d = len_char(*temp, abs_column); abs_column += d; column += d; posit++; temp++; } wmove(text_win, row, column); wclrtoeol(text_win); while ((posit < length) && (column <= last_col)) { if ((*temp < 32) || (*temp >= 127)) { column += len_char(*temp, abs_column); abs_column += out_char(text_win, *temp, abs_column); } else { abs_column++; column++; waddch(text_win, *temp); } posit++; temp++; } if (column < last_col) wclrtoeol(text_win); wmove(text_win, vertical, (horiz - horiz_offset)); } void insert_line(disp) /* insert new line */ int disp; { int temp_pos; int temp_pos2; unsigned char *temp; unsigned char *extra; struct text *temp_nod; text_changes = TRUE; wmove(text_win, scr_vert, (scr_horz - horiz_offset)); wclrtoeol(text_win); temp_nod= txtalloc(); temp_nod->line = extra= malloc(10); temp_nod->line_length = 1; temp_nod->max_length = 10; temp_nod->line_number = curr_line->line_number + 1; temp_nod->next_line = curr_line->next_line; if (temp_nod->next_line != NULL) temp_nod->next_line->prev_line = temp_nod; temp_nod->prev_line = curr_line; curr_line->next_line = temp_nod; temp_pos2 = position; temp = point; if (temp_pos2 < curr_line->line_length) { temp_pos = 1; while (temp_pos2 < curr_line->line_length) { if ((temp_nod->max_length - temp_nod->line_length)< 5) extra = resiz_line(10, temp_nod, temp_pos); temp_nod->line_length++; temp_pos++; temp_pos2++; *extra= *temp; extra++; temp++; } temp=point; *temp = '\0'; temp = resiz_line((1 - temp_nod->line_length), curr_line, position); curr_line->line_length = 1 + temp - curr_line->line; } curr_line->line_length = position; absolute_lin++; curr_line = temp_nod; *extra = '\0'; position = 1; point= curr_line->line; if (disp) { if (scr_vert < last_line) { scr_vert++; wclrtoeol(text_win); wmove(text_win, scr_vert, 0); winsertln(text_win); } else { wmove(text_win, 0,0); wdeleteln(text_win); wmove(text_win, last_line,0); wclrtobot(text_win); } scr_pos = scr_horz = 0; if (horiz_offset) { horiz_offset = 0; midscreen(scr_vert, point); } draw_line(scr_vert, scr_horz, point, position, curr_line->line_length); } } struct text *txtalloc() /* allocate space for line structure */ { return((struct text *) malloc(sizeof( struct text))); } struct files *name_alloc() /* allocate space for file name list node */ { return((struct files *) malloc(sizeof( struct files))); } unsigned char *next_word(string) /* move to next word in string */ unsigned char *string; { while ((*string != '\0') && ((*string != 32) && (*string != 9))) string++; while ((*string != '\0') && ((*string == 32) || (*string == 9))) string++; return(string); } void prev_word() /* move to start of previous word in text */ { if (position != 1) { if ((position != 1) && ((point[-1] == ' ') || (point[-1] == '\t'))) { /* if at the start of a word */ while ((position != 1) && ((*point != ' ') && (*point != '\t'))) left(TRUE); } while ((position != 1) && ((*point == ' ') || (*point == '\t'))) left(TRUE); while ((position != 1) && ((*point != ' ') && (*point != '\t'))) left(TRUE); if ((position != 1) && ((*point == ' ') || (*point == '\t'))) right(TRUE); } else left(TRUE); } void control() /* use control for commands */ { char *string; if (in == 1) /* control a */ { string = get_string(ascii_code_str, TRUE); if (*string != '\0') { in = atoi(string); wmove(text_win, scr_vert, (scr_horz - horiz_offset)); insert(in); } free(string); } else if (in == 2) /* control b */ bottom(); else if (in == 3) /* control c */ { command_prompt(); } else if (in == 4) /* control d */ down(); else if (in == 5) /* control e */ search_prompt(); else if (in == 6) /* control f */ undel_char(); else if (in == 7) /* control g */ bol(); else if (in == 8) /* control h */ delete(TRUE); else if (in == 9) /* control i */ ; else if (in == 10) /* control j */ insert_line(TRUE); else if (in == 11) /* control k */ del_char(); else if (in == 12) /* control l */ left(TRUE); else if (in == 13) /* control m */ insert_line(TRUE); else if (in == 14) /* control n */ move_rel("d", max(5, (last_line - 5))); else if (in == 15) /* control o */ eol(); else if (in == 16) /* control p */ move_rel("u", max(5, (last_line - 5))); else if (in == 17) /* control q */ ; else if (in == 18) /* control r */ right(TRUE); else if (in == 19) /* control s */ ; else if (in == 20) /* control t */ top(); else if (in == 21) /* control u */ up(); else if (in == 22) /* control v */ undel_word(); else if (in == 23) /* control w */ del_word(); else if (in == 24) /* control x */ search(TRUE); else if (in == 25) /* control y */ del_line(); else if (in == 26) /* control z */ undel_line(); else if (in == 27) /* control [ (escape) */ { menu_op(main_menu); } } /* | Emacs control-key bindings */ void emacs_control() { char *string; if (in == 1) /* control a */ bol(); else if (in == 2) /* control b */ left(TRUE); else if (in == 3) /* control c */ { command_prompt(); } else if (in == 4) /* control d */ del_char(); else if (in == 5) /* control e */ eol(); else if (in == 6) /* control f */ right(TRUE); else if (in == 7) /* control g */ move_rel("u", max(5, (last_line - 5))); else if (in == 8) /* control h */ delete(TRUE); else if (in == 9) /* control i */ ; else if (in == 10) /* control j */ undel_char(); else if (in == 11) /* control k */ del_line(); else if (in == 12) /* control l */ undel_line(); else if (in == 13) /* control m */ insert_line(TRUE); else if (in == 14) /* control n */ down(); else if (in == 15) /* control o */ { string = get_string(ascii_code_str, TRUE); if (*string != '\0') { in = atoi(string); wmove(text_win, scr_vert, (scr_horz - horiz_offset)); insert(in); } free(string); } else if (in == 16) /* control p */ up(); else if (in == 17) /* control q */ ; else if (in == 18) /* control r */ undel_word(); else if (in == 19) /* control s */ ; else if (in == 20) /* control t */ top(); else if (in == 21) /* control u */ bottom(); else if (in == 22) /* control v */ move_rel("d", max(5, (last_line - 5))); else if (in == 23) /* control w */ del_word(); else if (in == 24) /* control x */ search(TRUE); else if (in == 25) /* control y */ search_prompt(); else if (in == 26) /* control z */ adv_word(); else if (in == 27) /* control [ (escape) */ { menu_op(main_menu); } } void bottom() /* go to bottom of file */ { while (curr_line->next_line != NULL) { curr_line = curr_line->next_line; absolute_lin++; } point = curr_line->line; if (horiz_offset) horiz_offset = 0; position = 1; midscreen(last_line, point); scr_pos = scr_horz; } void top() /* go to top of file */ { while (curr_line->prev_line != NULL) { curr_line = curr_line->prev_line; absolute_lin--; } point = curr_line->line; if (horiz_offset) horiz_offset = 0; position = 1; midscreen(0, point); scr_pos = scr_horz; } void nextline() /* move pointers to start of next line */ { curr_line = curr_line->next_line; absolute_lin++; point = curr_line->line; position = 1; if (scr_vert == last_line) { wmove(text_win, 0,0); wdeleteln(text_win); wmove(text_win, last_line,0); wclrtobot(text_win); draw_line(last_line,0,point,1,curr_line->line_length); } else scr_vert++; } void prevline() /* move pointers to start of previous line*/ { curr_line = curr_line->prev_line; absolute_lin--; point = curr_line->line; position = 1; if (scr_vert == 0) { winsertln(text_win); draw_line(0,0,point,1,curr_line->line_length); } else scr_vert--; while (position < curr_line->line_length) { position++; point++; } } void left(disp) /* move left one character */ int disp; { if (point != curr_line->line) /* if not at begin of line */ { if ((ee_chinese) && (position >= 2) && (*(point - 2) > 127)) { point--; position--; } point--; position--; scanline(point); wmove(text_win, scr_vert, (scr_horz - horiz_offset)); scr_pos = scr_horz; } else if (curr_line->prev_line != NULL) { if (!disp) { absolute_lin--; curr_line = curr_line->prev_line; point = curr_line->line + curr_line->line_length; position = curr_line->line_length; return; } position = 1; prevline(); scanline(point); scr_pos = scr_horz; wmove(text_win, scr_vert, (scr_horz - horiz_offset)); } } void right(disp) /* move right one character */ int disp; { if (position < curr_line->line_length) { if ((ee_chinese) && (*point > 127) && ((curr_line->line_length - position) >= 2)) { point++; position++; } point++; position++; scanline(point); wmove(text_win, scr_vert, (scr_horz - horiz_offset)); scr_pos = scr_horz; } else if (curr_line->next_line != NULL) { if (!disp) { absolute_lin++; curr_line = curr_line->next_line; point = curr_line->line; position = 1; return; } nextline(); scr_pos = scr_horz = 0; if (horiz_offset) { horiz_offset = 0; midscreen(scr_vert, point); } wmove(text_win, scr_vert, (scr_horz - horiz_offset)); position = 1; } } void find_pos() /* move to the same column as on other line */ { scr_horz = 0; position = 1; while ((scr_horz < scr_pos) && (position < curr_line->line_length)) { if (*point == 9) scr_horz += tabshift(scr_horz); else if (*point < ' ') scr_horz += 2; else if ((ee_chinese) && (*point > 127) && ((curr_line->line_length - position) >= 2)) { scr_horz += 2; point++; position++; } else scr_horz++; position++; point++; } if ((scr_horz - horiz_offset) > last_col) { horiz_offset = (scr_horz - (scr_horz % 8)) - (COLS - 8); midscreen(scr_vert, point); } else if (scr_horz < horiz_offset) { horiz_offset = max(0, (scr_horz - (scr_horz % 8))); midscreen(scr_vert, point); } wmove(text_win, scr_vert, (scr_horz - horiz_offset)); } void up() /* move up one line */ { if (curr_line->prev_line != NULL) { prevline(); point = curr_line->line; find_pos(); } } void down() /* move down one line */ { if (curr_line->next_line != NULL) { nextline(); find_pos(); } } void function_key() /* process function key */ { if (in == KEY_LEFT) left(TRUE); else if (in == KEY_RIGHT) right(TRUE); else if (in == KEY_HOME) bol(); else if (in == KEY_END) eol(); else if (in == KEY_UP) up(); else if (in == KEY_DOWN) down(); else if (in == KEY_NPAGE) move_rel("d", max( 5, (last_line - 5))); else if (in == KEY_PPAGE) move_rel("u", max(5, (last_line - 5))); else if (in == KEY_DL) del_line(); else if (in == KEY_DC) del_char(); else if (in == KEY_BACKSPACE) delete(TRUE); else if (in == KEY_IL) { /* insert a line before current line */ insert_line(TRUE); left(TRUE); } else if (in == KEY_F(1)) gold = !gold; else if (in == KEY_F(2)) { if (gold) { gold = FALSE; undel_line(); } else undel_char(); } else if (in == KEY_F(3)) { if (gold) { gold = FALSE; undel_word(); } else del_word(); } else if (in == KEY_F(4)) { if (gold) { gold = FALSE; paint_info_win(); midscreen(scr_vert, point); } else adv_word(); } else if (in == KEY_F(5)) { if (gold) { gold = FALSE; search_prompt(); } else search(TRUE); } else if (in == KEY_F(6)) { if (gold) { gold = FALSE; bottom(); } else top(); } else if (in == KEY_F(7)) { if (gold) { gold = FALSE; eol(); } else bol(); } else if (in == KEY_F(8)) { if (gold) { gold = FALSE; command_prompt(); } else adv_line(); } } void print_buffer() { char buffer[256]; sprintf(buffer, ">!%s", print_command); wmove(com_win, 0, 0); wclrtoeol(com_win); wprintw(com_win, printer_msg_str, print_command); wrefresh(com_win); command(buffer); } void command_prompt() { char *cmd_str; int result; info_type = COMMANDS; paint_info_win(); cmd_str = get_string(command_str, TRUE); if ((result = unique_test(cmd_str, commands)) != 1) { werase(com_win); wmove(com_win, 0, 0); if (result == 0) wprintw(com_win, unkn_cmd_str, cmd_str); else wprintw(com_win, non_unique_cmd_msg); wrefresh(com_win); info_type = CONTROL_KEYS; paint_info_win(); if (cmd_str != NULL) free(cmd_str); return; } command(cmd_str); wrefresh(com_win); wmove(text_win, scr_vert, (scr_horz - horiz_offset)); info_type = CONTROL_KEYS; paint_info_win(); if (cmd_str != NULL) free(cmd_str); } void command(cmd_str1) /* process commands from keyboard */ char *cmd_str1; { char *cmd_str2 = NULL; char *cmd_str = cmd_str1; clear_com_win = TRUE; if (compare(cmd_str, HELP, FALSE)) help(); else if (compare(cmd_str, WRITE, FALSE)) { if (restrict_mode()) { return; } cmd_str = next_word(cmd_str); if (*cmd_str == '\0') { cmd_str = cmd_str2 = get_string(file_write_prompt_str, TRUE); } tmp_file = resolve_name(cmd_str); write_file(tmp_file, 1); if (tmp_file != cmd_str) free(tmp_file); } else if (compare(cmd_str, READ, FALSE)) { if (restrict_mode()) { return; } cmd_str = next_word(cmd_str); if (*cmd_str == '\0') { cmd_str = cmd_str2 = get_string(file_read_prompt_str, TRUE); } tmp_file = cmd_str; recv_file = TRUE; tmp_file = resolve_name(cmd_str); check_fp(); if (tmp_file != cmd_str) free(tmp_file); } else if (compare(cmd_str, LINE, FALSE)) { wmove(com_win, 0, 0); wclrtoeol(com_win); wprintw(com_win, line_num_str, curr_line->line_number); wprintw(com_win, line_len_str, curr_line->line_length); } else if (compare(cmd_str, FILE_str, FALSE)) { wmove(com_win, 0, 0); wclrtoeol(com_win); if (in_file_name == NULL) wprintw(com_win, no_file_string); else wprintw(com_win, current_file_str, in_file_name); } else if ((*cmd_str >= '0') && (*cmd_str <= '9')) goto_line(cmd_str); else if (compare(cmd_str, CHARACTER, FALSE)) { wmove(com_win, 0, 0); wclrtoeol(com_win); wprintw(com_win, char_str, *point); } else if (compare(cmd_str, REDRAW, FALSE)) redraw(); else if (compare(cmd_str, RESEQUENCE, FALSE)) { tmp_line = first_line->next_line; while (tmp_line != NULL) { tmp_line->line_number = tmp_line->prev_line->line_number + 1; tmp_line = tmp_line->next_line; } } else if (compare(cmd_str, AUTHOR, FALSE)) { wmove(com_win, 0, 0); wclrtoeol(com_win); wprintw(com_win, "written by Hugh Mahon"); } else if (compare(cmd_str, VERSION, FALSE)) { wmove(com_win, 0, 0); wclrtoeol(com_win); wprintw(com_win, "%s", version); } else if (compare(cmd_str, CASE, FALSE)) case_sen = TRUE; else if (compare(cmd_str, NOCASE, FALSE)) case_sen = FALSE; else if (compare(cmd_str, EXPAND, FALSE)) expand_tabs = TRUE; else if (compare(cmd_str, NOEXPAND, FALSE)) expand_tabs = FALSE; else if (compare(cmd_str, Exit_string, FALSE)) finish(); else if (compare(cmd_str, chinese_cmd, FALSE)) { ee_chinese = TRUE; #ifdef NCURSE nc_setattrib(A_NC_BIG5); #endif /* NCURSE */ } else if (compare(cmd_str, nochinese_cmd, FALSE)) { ee_chinese = FALSE; #ifdef NCURSE nc_clearattrib(A_NC_BIG5); #endif /* NCURSE */ } else if (compare(cmd_str, QUIT_string, FALSE)) quit(0); else if (*cmd_str == '!') { cmd_str++; if ((*cmd_str == ' ') || (*cmd_str == 9)) cmd_str = next_word(cmd_str); sh_command(cmd_str); } else if ((*cmd_str == '<') && (!in_pipe)) { in_pipe = TRUE; shell_fork = FALSE; cmd_str++; if ((*cmd_str == ' ') || (*cmd_str == '\t')) cmd_str = next_word(cmd_str); command(cmd_str); in_pipe = FALSE; shell_fork = TRUE; } else if ((*cmd_str == '>') && (!out_pipe)) { out_pipe = TRUE; cmd_str++; if ((*cmd_str == ' ') || (*cmd_str == '\t')) cmd_str = next_word(cmd_str); command(cmd_str); out_pipe = FALSE; } else { wmove(com_win, 0, 0); wclrtoeol(com_win); wprintw(com_win, unkn_cmd_str, cmd_str); } if (cmd_str2 != NULL) free(cmd_str2); } int scan(line, offset, column) /* determine horizontal position for get_string */ char *line; int offset; int column; { char *stemp; int i; int j; stemp = line; i = 0; j = column; while (i < offset) { i++; j += len_char(*stemp, j); stemp++; } return(j); } char * get_string(prompt, advance) /* read string from input on command line */ char *prompt; /* string containing user prompt message */ int advance; /* if true, skip leading spaces and tabs */ { char *string; char *tmp_string; char *nam_str; char *g_point; int tmp_int; int g_horz, g_position, g_pos; int esc_flag; g_point = tmp_string = malloc(512); wmove(com_win,0,0); wclrtoeol(com_win); waddstr(com_win, prompt); wrefresh(com_win); nam_str = tmp_string; clear_com_win = TRUE; g_horz = g_position = scan(prompt, strlen(prompt), 0); g_pos = 0; do { esc_flag = FALSE; in = wgetch(com_win); if (in == -1) exit(0); if (((in == 8) || (in == 127) || (in == KEY_BACKSPACE)) && (g_pos > 0)) { tmp_int = g_horz; g_pos--; g_horz = scan(g_point, g_pos, g_position); tmp_int = tmp_int - g_horz; for (; 0 < tmp_int; tmp_int--) { if ((g_horz+tmp_int) < (last_col - 1)) { waddch(com_win, '\010'); waddch(com_win, ' '); waddch(com_win, '\010'); } } nam_str--; } else if ((in != 8) && (in != 127) && (in != '\n') && (in != '\r') && (in < 256)) { if (in == '\026') /* control-v, accept next character verbatim */ { /* allows entry of ^m, ^j, and ^h */ esc_flag = TRUE; in = wgetch(com_win); if (in == -1) exit(0); } *nam_str = in; g_pos++; if (((in < ' ') || (in > 126)) && (g_horz < (last_col - 1))) g_horz += out_char(com_win, in, g_horz); else { g_horz++; if (g_horz < (last_col - 1)) waddch(com_win, in); } nam_str++; } wrefresh(com_win); if (esc_flag) in = '\0'; } while ((in != '\n') && (in != '\r')); *nam_str = '\0'; nam_str = tmp_string; if (((*nam_str == ' ') || (*nam_str == 9)) && (advance)) nam_str = next_word(nam_str); string = malloc(strlen(nam_str) + 1); strcpy(string, nam_str); free(tmp_string); wrefresh(com_win); return(string); } int compare(string1, string2, sensitive) /* compare two strings */ char *string1; char *string2; int sensitive; { char *strng1; char *strng2; int tmp; int equal; strng1 = string1; strng2 = string2; tmp = 0; if ((strng1 == NULL) || (strng2 == NULL) || (*strng1 == '\0') || (*strng2 == '\0')) return(FALSE); equal = TRUE; while (equal) { if (sensitive) { if (*strng1 != *strng2) equal = FALSE; } else { if (toupper(*strng1) != toupper(*strng2)) equal = FALSE; } strng1++; strng2++; if ((*strng1 == '\0') || (*strng2 == '\0') || (*strng1 == ' ') || (*strng2 == ' ')) break; tmp++; } return(equal); } void goto_line(cmd_str) char *cmd_str; { int number; int i; char *ptr; char *direction = NULL; struct text *t_line; ptr = cmd_str; i= 0; while ((*ptr >='0') && (*ptr <= '9')) { i= i * 10 + (*ptr - '0'); ptr++; } number = i; i = 0; t_line = curr_line; while ((t_line->line_number > number) && (t_line->prev_line != NULL)) { i++; t_line = t_line->prev_line; direction = "u"; } while ((t_line->line_number < number) && (t_line->next_line != NULL)) { i++; direction = "d"; t_line = t_line->next_line; } if ((i < 30) && (i > 0)) { move_rel(direction, i); } else { if (!strcmp(direction, "d")) { absolute_lin += i; } else { absolute_lin -= i; } curr_line = t_line; point = curr_line->line; position = 1; midscreen((last_line / 2), point); scr_pos = scr_horz; } wmove(com_win, 0, 0); wclrtoeol(com_win); wprintw(com_win, line_num_str, curr_line->line_number); wmove(text_win, scr_vert, (scr_horz - horiz_offset)); } void midscreen(line, pnt) /* put current line in middle of screen */ int line; unsigned char *pnt; { struct text *mid_line; int i; line = min(line, last_line); mid_line = curr_line; for (i = 0; ((i < line) && (curr_line->prev_line != NULL)); i++) curr_line = curr_line->prev_line; scr_vert = scr_horz = 0; wmove(text_win, 0, 0); draw_screen(); scr_vert = i; curr_line = mid_line; scanline(pnt); wmove(text_win, scr_vert, (scr_horz - horiz_offset)); } void get_options(numargs, arguments) /* get arguments from command line */ int numargs; char *arguments[]; { char *buff; int count; struct files *temp_names = NULL; char *name; char *ptr; int no_more_opts = FALSE; /* | see if editor was invoked as 'ree' (restricted mode) */ if (!(name = strrchr(arguments[0], '/'))) name = arguments[0]; else name++; if (!strcmp(name, "ree")) restricted = TRUE; top_of_stack = NULL; input_file = FALSE; recv_file = FALSE; count = 1; while ((count < numargs)&& (!no_more_opts)) { buff = arguments[count]; if (!strcmp("-i", buff)) { info_window = FALSE; } else if (!strcmp("-e", buff)) { expand_tabs = FALSE; } else if (!strcmp("-h", buff)) { nohighlight = TRUE; } else if (!strcmp("-?", buff)) { fprintf(stderr, usage0, arguments[0]); fprintf(stderr, usage1); fprintf(stderr, usage2); fprintf(stderr, usage3); fprintf(stderr, usage4); exit(1); } else if ((*buff == '+') && (start_at_line == NULL)) { buff++; start_at_line = buff; } else if (!(strcmp("--", buff))) no_more_opts = TRUE; else { count--; no_more_opts = TRUE; } count++; } while (count < numargs) { buff = arguments[count]; if (top_of_stack == NULL) { temp_names = top_of_stack = name_alloc(); } else { temp_names->next_name = name_alloc(); temp_names = temp_names->next_name; } ptr = temp_names->name = malloc(strlen(buff) + 1); while (*buff != '\0') { *ptr = *buff; buff++; ptr++; } *ptr = '\0'; temp_names->next_name = NULL; input_file = TRUE; recv_file = TRUE; count++; } } void check_fp() /* open or close files according to flags */ { int line_num; int temp; struct stat buf; clear_com_win = TRUE; tmp_vert = scr_vert; tmp_horz = scr_horz; tmp_line = curr_line; if (input_file) { in_file_name = tmp_file = top_of_stack->name; top_of_stack = top_of_stack->next_name; } temp = stat(tmp_file, &buf); buf.st_mode &= ~07777; if ((temp != -1) && (buf.st_mode != 0100000) && (buf.st_mode != 0)) { wprintw(com_win, file_is_dir_msg, tmp_file); wrefresh(com_win); if (input_file) { quit(0); return; } else return; } if ((get_fd = open(tmp_file, O_RDONLY)) == -1) { wmove(com_win, 0, 0); wclrtoeol(com_win); if (input_file) wprintw(com_win, new_file_msg, tmp_file); else wprintw(com_win, cant_open_msg, tmp_file); wrefresh(com_win); wmove(text_win, scr_vert, (scr_horz - horiz_offset)); wrefresh(text_win); recv_file = FALSE; input_file = FALSE; return; } else get_file(tmp_file); recv_file = FALSE; line_num = curr_line->line_number; scr_vert = tmp_vert; scr_horz = tmp_horz; if (input_file) curr_line= first_line; else curr_line = tmp_line; point = curr_line->line; draw_screen(); if (input_file) { input_file = FALSE; if (start_at_line != NULL) { line_num = atoi(start_at_line) - 1; move_rel("d", line_num); line_num = 0; start_at_line = NULL; } } else { wmove(com_win, 0, 0); wclrtoeol(com_win); text_changes = TRUE; if ((tmp_file != NULL) && (*tmp_file != '\0')) wprintw(com_win, file_read_fin_msg, tmp_file); } wrefresh(com_win); wmove(text_win, scr_vert, (scr_horz - horiz_offset)); wrefresh(text_win); } void get_file(file_name) /* read specified file into current buffer */ char *file_name; { int can_read; /* file has at least one character */ int length; /* length of line read by read */ int append; /* should text be appended to current line */ struct text *temp_line; char ro_flag = FALSE; if (recv_file) /* if reading a file */ { wmove(com_win, 0, 0); wclrtoeol(com_win); wprintw(com_win, reading_file_msg, file_name); if (access(file_name, 2)) /* check permission to write */ { if ((errno == ENOTDIR) || (errno == EACCES) || (errno == EROFS) || (errno == ETXTBSY) || (errno == EFAULT)) { wprintw(com_win, read_only_msg); ro_flag = TRUE; } } wrefresh(com_win); } if (curr_line->line_length > 1) /* if current line is not blank */ { insert_line(FALSE); left(FALSE); append = FALSE; } else append = TRUE; can_read = FALSE; /* test if file has any characters */ while (((length = read(get_fd, in_string, 512)) != 0) && (length != -1)) { can_read = TRUE; /* if set file has at least 1 character */ get_line(length, in_string, &append); } if ((can_read) && (curr_line->line_length == 1)) { temp_line = curr_line->prev_line; temp_line->next_line = curr_line->next_line; if (temp_line->next_line != NULL) temp_line->next_line->prev_line = temp_line; if (curr_line->line != NULL) free(curr_line->line); free(curr_line); curr_line = temp_line; } if (input_file) /* if this is the file to be edited display number of lines */ { wmove(com_win, 0, 0); wclrtoeol(com_win); wprintw(com_win, file_read_lines_msg, in_file_name, curr_line->line_number); if (ro_flag) wprintw(com_win, read_only_msg); wrefresh(com_win); } else if (can_read) /* not input_file and file is non-zero size */ text_changes = TRUE; if (recv_file) /* if reading a file */ { in = EOF; } } void get_line(length, in_string, append) /* read string and split into lines */ int length; /* length of string read by read */ unsigned char *in_string; /* string read by read */ int *append; /* TRUE if must append more text to end of current line */ { unsigned char *str1; unsigned char *str2; int num; /* offset from start of string */ int char_count; /* length of new line (or added portion */ int temp_counter; /* temporary counter value */ struct text *tline; /* temporary pointer to new line */ int first_time; /* if TRUE, the first time through the loop */ str2 = in_string; num = 0; first_time = TRUE; while (num < length) { if (!first_time) { if (num < length) { str2++; num++; } } else first_time = FALSE; str1 = str2; char_count = 1; /* find end of line */ while ((*str2 != '\n') && (num < length)) { str2++; num++; char_count++; } if (!(*append)) /* if not append to current line, insert new one */ { tline = txtalloc(); /* allocate data structure for next line */ tline->line_number = curr_line->line_number + 1; tline->next_line = curr_line->next_line; tline->prev_line = curr_line; curr_line->next_line = tline; if (tline->next_line != NULL) tline->next_line->prev_line = tline; curr_line = tline; curr_line->line = point = (unsigned char *) malloc(char_count); curr_line->line_length = char_count; curr_line->max_length = char_count; } else { point = resiz_line(char_count, curr_line, curr_line->line_length); curr_line->line_length += (char_count - 1); } for (temp_counter = 1; temp_counter < char_count; temp_counter++) { *point = *str1; point++; str1++; } *point = '\0'; *append = FALSE; if ((num == length) && (*str2 != '\n')) *append = TRUE; } } void draw_screen() /* redraw the screen from current postion */ { struct text *temp_line; unsigned char *line_out; int temp_vert; temp_line = curr_line; temp_vert = scr_vert; wclrtobot(text_win); while ((temp_line != NULL) && (temp_vert <= last_line)) { line_out = temp_line->line; draw_line(temp_vert, 0, line_out, 1, temp_line->line_length); temp_vert++; temp_line = temp_line->next_line; } wmove(text_win, temp_vert, 0); wmove(text_win, scr_vert, (scr_horz - horiz_offset)); } void finish() /* prepare to exit edit session */ { char *file_name = in_file_name; /* | changes made here should be reflected in the 'save' | portion of file_op() */ if ((file_name == NULL) || (*file_name == '\0')) file_name = get_string(save_file_name_prompt, TRUE); if ((file_name == NULL) || (*file_name == '\0')) { wmove(com_win, 0, 0); wprintw(com_win, file_not_saved_msg); wclrtoeol(com_win); wrefresh(com_win); clear_com_win = TRUE; return; } tmp_file = resolve_name(file_name); if (tmp_file != file_name) { free(file_name); file_name = tmp_file; } if (write_file(file_name, 1)) { text_changes = FALSE; quit(0); } } int quit(noverify) /* exit editor */ int noverify; { char *ans; touchwin(text_win); wrefresh(text_win); if ((text_changes) && (!noverify)) { ans = get_string(changes_made_prompt, TRUE); if (toupper(*ans) == toupper(*yes_char)) text_changes = FALSE; else return(0); free(ans); } if (top_of_stack == NULL) { if (info_window) wrefresh(info_win); wrefresh(com_win); resetty(); endwin(); putchar('\n'); exit(0); } else { delete_text(); recv_file = TRUE; input_file = TRUE; check_fp(); } return(0); } void edit_abort(arg) int arg; { wrefresh(com_win); resetty(); endwin(); putchar('\n'); exit(1); } void delete_text() { while (curr_line->next_line != NULL) curr_line = curr_line->next_line; while (curr_line != first_line) { free(curr_line->line); curr_line = curr_line->prev_line; absolute_lin--; free(curr_line->next_line); } curr_line->next_line = NULL; *curr_line->line = '\0'; curr_line->line_length = 1; curr_line->line_number = 1; point = curr_line->line; scr_pos = scr_vert = scr_horz = 0; position = 1; } int write_file(file_name, warn_if_exists) char *file_name; int warn_if_exists; { char cr; char *tmp_point; struct text *out_line; int lines, charac; int temp_pos; int write_flag = TRUE; charac = lines = 0; if (warn_if_exists && ((in_file_name == NULL) || strcmp(in_file_name, file_name))) { if ((temp_fp = fopen(file_name, "r"))) { tmp_point = get_string(file_exists_prompt, TRUE); if (toupper(*tmp_point) == toupper(*yes_char)) write_flag = TRUE; else write_flag = FALSE; fclose(temp_fp); free(tmp_point); } } clear_com_win = TRUE; if (write_flag) { if ((temp_fp = fopen(file_name, "w")) == NULL) { clear_com_win = TRUE; wmove(com_win,0,0); wclrtoeol(com_win); wprintw(com_win, create_file_fail_msg, file_name); wrefresh(com_win); return(FALSE); } else { wmove(com_win,0,0); wclrtoeol(com_win); wprintw(com_win, writing_file_msg, file_name); wrefresh(com_win); cr = '\n'; out_line = first_line; while (out_line != NULL) { temp_pos = 1; tmp_point= out_line->line; while (temp_pos < out_line->line_length) { putc(*tmp_point, temp_fp); tmp_point++; temp_pos++; } charac += out_line->line_length; out_line = out_line->next_line; putc(cr, temp_fp); lines++; } fclose(temp_fp); wmove(com_win,0,0); wclrtoeol(com_win); wprintw(com_win, file_written_msg, file_name, lines, charac); wrefresh(com_win); return(TRUE); } } else return(FALSE); } int search(display_message) /* search for string in srch_str */ int display_message; { int lines_moved; int iter; int found; if ((srch_str == NULL) || (*srch_str == '\0')) return(FALSE); if (display_message) { wmove(com_win, 0, 0); wclrtoeol(com_win); wprintw(com_win, searching_msg); wrefresh(com_win); clear_com_win = TRUE; } lines_moved = 0; found = FALSE; srch_line = curr_line; srch_1 = point; if (position < curr_line->line_length) srch_1++; iter = position + 1; while ((!found) && (srch_line != NULL)) { while ((iter < srch_line->line_length) && (!found)) { srch_2 = srch_1; if (case_sen) /* if case sensitive */ { srch_3 = srch_str; while ((*srch_2 == *srch_3) && (*srch_3 != '\0')) { found = TRUE; srch_2++; srch_3++; } /* end while */ } else /* if not case sensitive */ { srch_3 = u_srch_str; while ((toupper(*srch_2) == *srch_3) && (*srch_3 != '\0')) { found = TRUE; srch_2++; srch_3++; } } /* end else */ if (!((*srch_3 == '\0') && (found))) { found = FALSE; if (iter < srch_line->line_length) srch_1++; iter++; } } if (!found) { srch_line = srch_line->next_line; if (srch_line != NULL) srch_1 = srch_line->line; iter = 1; lines_moved++; } } if (found) { if (display_message) { wmove(com_win, 0, 0); wclrtoeol(com_win); wrefresh(com_win); } if (lines_moved == 0) { while (position < iter) right(TRUE); } else { if (lines_moved < 30) { move_rel("d", lines_moved); while (position < iter) right(TRUE); } else { absolute_lin += lines_moved; curr_line = srch_line; point = srch_1; position = iter; scanline(point); scr_pos = scr_horz; midscreen((last_line / 2), point); } } } else { if (display_message) { wmove(com_win, 0, 0); wclrtoeol(com_win); wprintw(com_win, str_not_found_msg, srch_str); wrefresh(com_win); } wmove(text_win, scr_vert,(scr_horz - horiz_offset)); } return(found); } void search_prompt() /* prompt and read search string (srch_str) */ { if (srch_str != NULL) free(srch_str); if ((u_srch_str != NULL) && (*u_srch_str != '\0')) free(u_srch_str); srch_str = get_string(search_prompt_str, FALSE); gold = FALSE; srch_3 = srch_str; srch_1 = u_srch_str = malloc(strlen(srch_str) + 1); while (*srch_3 != '\0') { *srch_1 = toupper(*srch_3); srch_1++; srch_3++; } *srch_1 = '\0'; search(TRUE); } void del_char() /* delete current character */ { in = 8; /* backspace */ if (position < curr_line->line_length) /* if not end of line */ { if ((ee_chinese) && (*point > 127) && ((curr_line->line_length - position) >= 2)) { point++; position++; } position++; point++; scanline(point); delete(TRUE); } else { right(FALSE); delete(FALSE); } } void undel_char() /* undelete last deleted character */ { if (d_char[0] == '\n') /* insert line if last del_char deleted eol */ insert_line(TRUE); else { in = d_char[0]; insert(in); if (d_char[1] != '\0') { in = d_char[1]; insert(in); } } } void del_word() /* delete word in front of cursor */ { int tposit; int difference; unsigned char *d_word2; unsigned char *d_word3; unsigned char tmp_char[3]; if (d_word != NULL) free(d_word); d_word = malloc(curr_line->line_length); tmp_char[0] = d_char[0]; tmp_char[1] = d_char[1]; tmp_char[2] = d_char[2]; d_word3 = point; d_word2 = d_word; tposit = position; while ((tposit < curr_line->line_length) && ((*d_word3 != ' ') && (*d_word3 != '\t'))) { tposit++; *d_word2 = *d_word3; d_word2++; d_word3++; } while ((tposit < curr_line->line_length) && ((*d_word3 == ' ') || (*d_word3 == '\t'))) { tposit++; *d_word2 = *d_word3; d_word2++; d_word3++; } *d_word2 = '\0'; d_wrd_len = difference = d_word2 - d_word; d_word2 = point; while (tposit < curr_line->line_length) { tposit++; *d_word2 = *d_word3; d_word2++; d_word3++; } curr_line->line_length -= difference; *d_word2 = '\0'; draw_line(scr_vert, scr_horz,point,position,curr_line->line_length); d_char[0] = tmp_char[0]; d_char[1] = tmp_char[1]; d_char[2] = tmp_char[2]; text_changes = TRUE; formatted = FALSE; } void undel_word() /* undelete last deleted word */ { int temp; int tposit; unsigned char *tmp_old_ptr; unsigned char *tmp_space; unsigned char *tmp_ptr; unsigned char *d_word_ptr; /* | resize line to handle undeleted word */ if ((curr_line->max_length - (curr_line->line_length + d_wrd_len)) < 5) point = resiz_line(d_wrd_len, curr_line, position); tmp_ptr = tmp_space = malloc(curr_line->line_length + d_wrd_len); d_word_ptr = d_word; temp = 1; /* | copy d_word contents into temp space */ while (temp <= d_wrd_len) { temp++; *tmp_ptr = *d_word_ptr; tmp_ptr++; d_word_ptr++; } tmp_old_ptr = point; tposit = position; /* | copy contents of line from curent position to eol into | temp space */ while (tposit < curr_line->line_length) { temp++; tposit++; *tmp_ptr = *tmp_old_ptr; tmp_ptr++; tmp_old_ptr++; } curr_line->line_length += d_wrd_len; tmp_old_ptr = point; *tmp_ptr = '\0'; tmp_ptr = tmp_space; tposit = 1; /* | now copy contents from temp space back to original line */ while (tposit < temp) { tposit++; *tmp_old_ptr = *tmp_ptr; tmp_ptr++; tmp_old_ptr++; } *tmp_old_ptr = '\0'; free(tmp_space); draw_line(scr_vert, scr_horz, point, position, curr_line->line_length); } void del_line() /* delete from cursor to end of line */ { unsigned char *dl1; unsigned char *dl2; int tposit; if (d_line != NULL) free(d_line); d_line = malloc(curr_line->line_length); dl1 = d_line; dl2 = point; tposit = position; while (tposit < curr_line->line_length) { *dl1 = *dl2; dl1++; dl2++; tposit++; } dlt_line->line_length = 1 + tposit - position; *dl1 = '\0'; *point = '\0'; curr_line->line_length = position; wclrtoeol(text_win); if (curr_line->next_line != NULL) { right(FALSE); delete(FALSE); } text_changes = TRUE; } void undel_line() /* undelete last deleted line */ { unsigned char *ud1; unsigned char *ud2; int tposit; if (dlt_line->line_length == 0) return; insert_line(TRUE); left(TRUE); point = resiz_line(dlt_line->line_length, curr_line, position); curr_line->line_length += dlt_line->line_length - 1; ud1 = point; ud2 = d_line; tposit = 1; while (tposit < dlt_line->line_length) { tposit++; *ud1 = *ud2; ud1++; ud2++; } *ud1 = '\0'; draw_line(scr_vert, scr_horz,point,position,curr_line->line_length); } void adv_word() /* advance to next word */ { while ((position < curr_line->line_length) && ((*point != 32) && (*point != 9))) right(TRUE); while ((position < curr_line->line_length) && ((*point == 32) || (*point == 9))) right(TRUE); } void move_rel(direction, lines) /* move relative to current line */ char *direction; int lines; { int i; char *tmp; if (*direction == 'u') { scr_pos = 0; while (position > 1) left(TRUE); for (i = 0; i < lines; i++) { up(); } if ((last_line > 5) && ( scr_vert < 4)) { tmp = point; tmp_line = curr_line; for (i= 0;(i<5)&&(curr_line->prev_line != NULL); i++) { up(); } scr_vert = scr_vert + i; curr_line = tmp_line; absolute_lin += i; point = tmp; scanline(point); } } else { if ((position != 1) && (curr_line->next_line != NULL)) { nextline(); scr_pos = scr_horz = 0; if (horiz_offset) { horiz_offset = 0; midscreen(scr_vert, point); } } else adv_line(); for (i = 1; i < lines; i++) { down(); } if ((last_line > 10) && (scr_vert > (last_line - 5))) { tmp = point; tmp_line = curr_line; for (i=0; (i<5) && (curr_line->next_line != NULL); i++) { down(); } absolute_lin -= i; scr_vert = scr_vert - i; curr_line = tmp_line; point = tmp; scanline(point); } } wmove(text_win, scr_vert, (scr_horz - horiz_offset)); } void eol() /* go to end of line */ { if (position < curr_line->line_length) { while (position < curr_line->line_length) right(TRUE); } else if (curr_line->next_line != NULL) { right(TRUE); while (position < curr_line->line_length) right(TRUE); } } void bol() /* move to beginning of line */ { if (point != curr_line->line) { while (point != curr_line->line) left(TRUE); } else if (curr_line->prev_line != NULL) { scr_pos = 0; up(); } } void adv_line() /* advance to beginning of next line */ { if ((point != curr_line->line) || (scr_pos > 0)) { while (position < curr_line->line_length) right(TRUE); right(TRUE); } else if (curr_line->next_line != NULL) { scr_pos = 0; down(); } } void from_top() { struct text *tmpline = first_line; int x = 1; while ((tmpline != NULL) && (tmpline != curr_line)) { x++; tmpline = tmpline->next_line; } absolute_lin = x; } void sh_command(string) /* execute shell command */ char *string; /* string containing user command */ { char *temp_point; char *last_slash; char *path; /* directory path to executable */ int parent; /* zero if child, child's pid if parent */ int value; int return_val; struct text *line_holder; if (restrict_mode()) { return; } if (!(path = getenv("SHELL"))) path = "/bin/sh"; last_slash = temp_point = path; while (*temp_point != '\0') { if (*temp_point == '/') last_slash = ++temp_point; else temp_point++; } /* | if in_pipe is true, then output of the shell operation will be | read by the editor, and curses doesn't need to be turned off */ if (!in_pipe) { keypad(com_win, FALSE); keypad(text_win, FALSE); echo(); nl(); noraw(); resetty(); #ifndef NCURSE endwin(); #endif } if (in_pipe) { pipe(pipe_in); /* create a pipe */ parent = fork(); if (!parent) /* if the child */ { /* | child process which will fork and exec shell command (if shell output is | to be read by editor) */ in_pipe = FALSE; /* | redirect stdout to pipe */ temp_stdout = dup(1); close(1); dup(pipe_in[1]); /* | redirect stderr to pipe */ temp_stderr = dup(2); close(2); dup(pipe_in[1]); close(pipe_in[1]); /* | child will now continue down 'if (!in_pipe)' | path below */ } else /* if the parent */ { /* | prepare editor to read from the pipe */ signal(SIGCHLD, SIG_IGN); line_holder = curr_line; tmp_vert = scr_vert; close(pipe_in[1]); get_fd = pipe_in[0]; get_file(""); close(pipe_in[0]); scr_vert = tmp_vert; scr_horz = scr_pos = 0; position = 1; curr_line = line_holder; from_top(); point = curr_line->line; out_pipe = FALSE; signal(SIGCHLD, SIG_DFL); /* | since flag "in_pipe" is still TRUE, the path which waits for the child | process to die will be avoided. | (the pipe is closed, no more output can be expected) */ } } if (!in_pipe) { signal(SIGINT, SIG_IGN); if (out_pipe) { pipe(pipe_out); } /* | fork process which will exec command */ parent = fork(); if (!parent) /* if the child */ { if (shell_fork) putchar('\n'); if (out_pipe) { /* | prepare the child process (soon to exec a shell command) to read from the | pipe (which will be output from the editor's buffer) */ close(0); dup(pipe_out[0]); close(pipe_out[0]); close(pipe_out[1]); } for (value = 1; value < 24; value++) signal(value, SIG_DFL); execl(path, last_slash, "-c", string, NULL); fprintf(stderr, exec_err_msg, path); exit(-1); } else /* if the parent */ { if (out_pipe) { /* | output the contents of the buffer to the pipe (to be read by the | process forked and exec'd above as stdin) */ close(pipe_out[0]); line_holder = first_line; while (line_holder != NULL) { write(pipe_out[1], line_holder->line, (line_holder->line_length-1)); write(pipe_out[1], "\n", 1); line_holder = line_holder->next_line; } close(pipe_out[1]); out_pipe = FALSE; } do { return_val = wait((int *) 0); } while ((return_val != parent) && (return_val != -1)); /* | if this process is actually the child of the editor, exit. Here's how it | works: | The editor forks a process. If output must be sent to the command to be | exec'd another process is forked, and that process (the child's child) | will exec the command. In this case, "shell_fork" will be FALSE. If no | output is to be performed to the shell command, "shell_fork" will be TRUE. | If this is the editor process, shell_fork will be true, otherwise this is | the child of the edit process. */ if (!shell_fork) exit(0); } signal(SIGINT, edit_abort); } if (shell_fork) { printf(continue_msg); fflush(stdout); while ((in = getchar()) != '\n') ; } if (!in_pipe) { fixterm(); noecho(); nonl(); raw(); keypad(text_win, TRUE); keypad(com_win, TRUE); if (info_window) clearok(info_win, TRUE); } redraw(); } void set_up_term() /* set up the terminal for operating with ae */ { if (!curses_initialized) { initscr(); savetty(); noecho(); raw(); nonl(); curses_initialized = TRUE; } if (((LINES > 15) && (COLS >= 80)) && info_window) last_line = LINES - 8; else { info_window = FALSE; last_line = LINES - 2; } idlok(stdscr, TRUE); com_win = newwin(1, COLS, (LINES - 1), 0); keypad(com_win, TRUE); idlok(com_win, TRUE); wrefresh(com_win); if (!info_window) text_win = newwin((LINES - 1), COLS, 0, 0); else text_win = newwin((LINES - 7), COLS, 6, 0); keypad(text_win, TRUE); idlok(text_win, TRUE); wrefresh(text_win); help_win = newwin((LINES - 1), COLS, 0, 0); keypad(help_win, TRUE); idlok(help_win, TRUE); if (info_window) { info_type = CONTROL_KEYS; info_win = newwin(6, COLS, 0, 0); werase(info_win); paint_info_win(); } last_col = COLS - 1; local_LINES = LINES; local_COLS = COLS; #ifdef NCURSE if (ee_chinese) nc_setattrib(A_NC_BIG5); #endif /* NCURSE */ } void resize_check() { if ((LINES == local_LINES) && (COLS == local_COLS)) return; if (info_window) delwin(info_win); delwin(text_win); delwin(com_win); delwin(help_win); set_up_term(); redraw(); wrefresh(text_win); } static char item_alpha[] = "abcdefghijklmnopqrstuvwxyz0123456789 "; int menu_op(menu_list) struct menu_entries menu_list[]; { WINDOW *temp_win; int max_width, max_height; int x_off, y_off; int counter; int length; int input; int temp; int list_size; int top_offset; /* offset from top where menu items start */ int vert_pos; /* vertical position */ int vert_size; /* vertical size for menu list item display */ int off_start = 1; /* offset from start of menu items to start display */ /* | determine number and width of menu items */ list_size = 1; while (menu_list[list_size + 1].item_string != NULL) list_size++; max_width = 0; for (counter = 0; counter <= list_size; counter++) { if ((length = strlen(menu_list[counter].item_string)) > max_width) max_width = length; } max_width += 3; max_width = max(max_width, strlen(menu_cancel_msg)); max_width = max(max_width, max(strlen(more_above_str), strlen(more_below_str))); max_width += 6; /* | make sure that window is large enough to handle menu | if not, print error message and return to calling function */ if (max_width > COLS) { wmove(com_win, 0, 0); werase(com_win); wprintw(com_win, menu_too_lrg_msg); wrefresh(com_win); clear_com_win = TRUE; return(0); } top_offset = 0; if (list_size > LINES) { max_height = LINES; if (max_height > 11) vert_size = max_height - 8; else vert_size = max_height; } else { vert_size = list_size; max_height = list_size; } if (LINES >= (vert_size + 8)) { if (menu_list[0].argument != MENU_WARN) max_height = vert_size + 8; else max_height = vert_size + 7; top_offset = 4; } x_off = (COLS - max_width) / 2; y_off = (LINES - max_height - 1) / 2; temp_win = newwin(max_height, max_width, y_off, x_off); keypad(temp_win, TRUE); paint_menu(menu_list, max_width, max_height, list_size, top_offset, temp_win, off_start, vert_size); counter = 1; vert_pos = 0; do { if (off_start > 2) wmove(temp_win, (1 + counter + top_offset - off_start), 3); else wmove(temp_win, (counter + top_offset - off_start), 3); wrefresh(temp_win); in = wgetch(temp_win); input = in; if (input == -1) exit(0); if (((tolower(input) >= 'a') && (tolower(input) <= 'z')) || ((input >= '0') && (input <= '9'))) { if ((tolower(input) >= 'a') && (tolower(input) <= 'z')) { temp = 1 + tolower(input) - 'a'; } else if ((input >= '0') && (input <= '9')) { temp = (2 + 'z' - 'a') + (input - '0'); } if (temp <= list_size) { input = '\n'; counter = temp; } } else { switch (input) { case ' ': /* space */ case '\004': /* ^d, down */ case KEY_RIGHT: case KEY_DOWN: counter++; if (counter > list_size) counter = 1; break; case '\010': /* ^h, backspace*/ case '\025': /* ^u, up */ case 127: /* ^?, delete */ case KEY_BACKSPACE: case KEY_LEFT: case KEY_UP: counter--; if (counter == 0) counter = list_size; break; case '\033': /* escape key */ if (menu_list[0].argument != MENU_WARN) counter = 0; break; case '\014': /* ^l */ case '\022': /* ^r, redraw */ paint_menu(menu_list, max_width, max_height, list_size, top_offset, temp_win, off_start, vert_size); break; default: break; } } if (((list_size - off_start) >= (vert_size - 1)) && (counter > (off_start + vert_size - 3)) && (off_start > 1)) { if (counter == list_size) off_start = (list_size - vert_size) + 2; else off_start++; paint_menu(menu_list, max_width, max_height, list_size, top_offset, temp_win, off_start, vert_size); } else if ((list_size != vert_size) && (counter > (off_start + vert_size - 2))) { if (counter == list_size) off_start = 2 + (list_size - vert_size); else if (off_start == 1) off_start = 3; else off_start++; paint_menu(menu_list, max_width, max_height, list_size, top_offset, temp_win, off_start, vert_size); } else if (counter < off_start) { if (counter <= 2) off_start = 1; else off_start = counter; paint_menu(menu_list, max_width, max_height, list_size, top_offset, temp_win, off_start, vert_size); } } while ((input != '\r') && (input != '\n') && (counter != 0)); werase(temp_win); wrefresh(temp_win); delwin(temp_win); if ((menu_list[counter].procedure != NULL) || (menu_list[counter].iprocedure != NULL) || (menu_list[counter].nprocedure != NULL)) { if (menu_list[counter].argument != -1) (*menu_list[counter].iprocedure)(menu_list[counter].argument); else if (menu_list[counter].ptr_argument != NULL) (*menu_list[counter].procedure)(menu_list[counter].ptr_argument); else (*menu_list[counter].nprocedure)(); } if (info_window) paint_info_win(); redraw(); return(counter); } void paint_menu(menu_list, max_width, max_height, list_size, top_offset, menu_win, off_start, vert_size) struct menu_entries menu_list[]; int max_width, max_height, list_size, top_offset; WINDOW *menu_win; int off_start, vert_size; { int counter, temp_int; werase(menu_win); /* | output top and bottom portions of menu box only if window | large enough */ if (max_height > vert_size) { wmove(menu_win, 1, 1); if (!nohighlight) wstandout(menu_win); waddch(menu_win, '+'); for (counter = 0; counter < (max_width - 4); counter++) waddch(menu_win, '-'); waddch(menu_win, '+'); wmove(menu_win, (max_height - 2), 1); waddch(menu_win, '+'); for (counter = 0; counter < (max_width - 4); counter++) waddch(menu_win, '-'); waddch(menu_win, '+'); wstandend(menu_win); wmove(menu_win, 2, 3); waddstr(menu_win, menu_list[0].item_string); wmove(menu_win, (max_height - 3), 3); if (menu_list[0].argument != MENU_WARN) waddstr(menu_win, menu_cancel_msg); } if (!nohighlight) wstandout(menu_win); for (counter = 0; counter < (vert_size + top_offset); counter++) { if (top_offset == 4) { temp_int = counter + 2; } else temp_int = counter; wmove(menu_win, temp_int, 1); waddch(menu_win, '|'); wmove(menu_win, temp_int, (max_width - 2)); waddch(menu_win, '|'); } wstandend(menu_win); if (list_size > vert_size) { if (off_start >= 3) { temp_int = 1; wmove(menu_win, top_offset, 3); waddstr(menu_win, more_above_str); } else temp_int = 0; for (counter = off_start; ((temp_int + counter - off_start) < (vert_size - 1)); counter++) { wmove(menu_win, (top_offset + temp_int + (counter - off_start)), 3); if (list_size > 1) wprintw(menu_win, "%c) ", item_alpha[min((counter - 1), max_alpha_char)]); waddstr(menu_win, menu_list[counter].item_string); } wmove(menu_win, (top_offset + (vert_size - 1)), 3); if (counter == list_size) { if (list_size > 1) wprintw(menu_win, "%c) ", item_alpha[min((counter - 1), max_alpha_char)]); wprintw(menu_win, menu_list[counter].item_string); } else wprintw(menu_win, more_below_str); } else { for (counter = 1; counter <= list_size; counter++) { wmove(menu_win, (top_offset + counter - 1), 3); if (list_size > 1) wprintw(menu_win, "%c) ", item_alpha[min((counter - 1), max_alpha_char)]); waddstr(menu_win, menu_list[counter].item_string); } } } void help() { int counter; werase(help_win); clearok(help_win, TRUE); for (counter = 0; counter < 22; counter++) { wmove(help_win, counter, 0); waddstr(help_win, (emacs_keys_mode) ? emacs_help_text[counter] : help_text[counter]); } wrefresh(help_win); werase(com_win); wmove(com_win, 0, 0); wprintw(com_win, press_any_key_msg); wrefresh(com_win); counter = wgetch(com_win); if (counter == -1) exit(0); werase(com_win); wmove(com_win, 0, 0); werase(help_win); wrefresh(help_win); wrefresh(com_win); redraw(); } void paint_info_win() { int counter; if (!info_window) return; werase(info_win); for (counter = 0; counter < 5; counter++) { wmove(info_win, counter, 0); wclrtoeol(info_win); if (info_type == CONTROL_KEYS) waddstr(info_win, (emacs_keys_mode) ? emacs_control_keys[counter] : control_keys[counter]); else if (info_type == COMMANDS) waddstr(info_win, command_strings[counter]); } wmove(info_win, 5, 0); if (!nohighlight) wstandout(info_win); waddstr(info_win, separator); wstandend(info_win); wrefresh(info_win); } void no_info_window() { if (!info_window) return; delwin(info_win); delwin(text_win); info_window = FALSE; last_line = LINES - 2; text_win = newwin((LINES - 1), COLS, 0, 0); keypad(text_win, TRUE); idlok(text_win, TRUE); clearok(text_win, TRUE); midscreen(scr_vert, point); wrefresh(text_win); clear_com_win = TRUE; } void create_info_window() { if (info_window) return; last_line = LINES - 8; delwin(text_win); text_win = newwin((LINES - 7), COLS, 6, 0); keypad(text_win, TRUE); idlok(text_win, TRUE); werase(text_win); info_window = TRUE; info_win = newwin(6, COLS, 0, 0); werase(info_win); info_type = CONTROL_KEYS; midscreen(min(scr_vert, last_line), point); clearok(info_win, TRUE); paint_info_win(); wrefresh(text_win); clear_com_win = TRUE; } int file_op(arg) int arg; { char *string; int flag; if (restrict_mode()) { return(0); } if (arg == READ_FILE) { string = get_string(file_read_prompt_str, TRUE); recv_file = TRUE; tmp_file = resolve_name(string); check_fp(); if (tmp_file != string) free(tmp_file); free(string); } else if (arg == WRITE_FILE) { string = get_string(file_write_prompt_str, TRUE); tmp_file = resolve_name(string); write_file(tmp_file, 1); if (tmp_file != string) free(tmp_file); free(string); } else if (arg == SAVE_FILE) { /* | changes made here should be reflected in finish() */ if (in_file_name) flag = TRUE; else flag = FALSE; string = in_file_name; if ((string == NULL) || (*string == '\0')) string = get_string(save_file_name_prompt, TRUE); if ((string == NULL) || (*string == '\0')) { wmove(com_win, 0, 0); wprintw(com_win, file_not_saved_msg); wclrtoeol(com_win); wrefresh(com_win); clear_com_win = TRUE; return(0); } if (!flag) { tmp_file = resolve_name(string); if (tmp_file != string) { free(string); string = tmp_file; } } if (write_file(string, 1)) { in_file_name = string; text_changes = FALSE; } else if (!flag) free(string); } return(0); } void shell_op() { char *string; if (((string = get_string(shell_prompt, TRUE)) != NULL) && (*string != '\0')) { sh_command(string); free(string); } } void leave_op() { if (text_changes) { menu_op(leave_menu); } else quit(TRUE); } void redraw() { if (info_window) { clearok(info_win, TRUE); paint_info_win(); } else clearok(text_win, TRUE); midscreen(scr_vert, point); } /* | The following routines will "format" a paragraph (as defined by a | block of text with blank lines before and after the block). */ int Blank_Line(test_line) /* test if line has any non-space characters */ struct text *test_line; { unsigned char *line; int length; if (test_line == NULL) return(TRUE); length = 1; line = test_line->line; /* | To handle troff/nroff documents, consider a line with a | period ('.') in the first column to be blank. To handle mail | messages with included text, consider a line with a '>' blank. */ if ((*line == '.') || (*line == '>')) return(TRUE); while (((*line == ' ') || (*line == '\t')) && (length < test_line->line_length)) { length++; line++; } if (length != test_line->line_length) return(FALSE); else return(TRUE); } void Format() /* format the paragraph according to set margins */ { int string_count; int offset; int temp_case; int status; int tmp_af; int counter; unsigned char *line; unsigned char *tmp_srchstr; unsigned char *temp1, *temp2; unsigned char *temp_dword; unsigned char temp_d_char[3]; temp_d_char[0] = d_char[0]; temp_d_char[1] = d_char[1]; temp_d_char[2] = d_char[2]; /* | if observ_margins is not set, or the current line is blank, | do not format the current paragraph */ if ((!observ_margins) || (Blank_Line(curr_line))) return; /* | save the currently set flags, and clear them */ wmove(com_win, 0, 0); wclrtoeol(com_win); wprintw(com_win, formatting_msg); wrefresh(com_win); /* | get current position in paragraph, so after formatting, the cursor | will be in the same relative position */ tmp_af = auto_format; auto_format = FALSE; offset = position; if (position != 1) prev_word(); temp_dword = d_word; d_word = NULL; temp_case = case_sen; case_sen = TRUE; tmp_srchstr = srch_str; temp2 = srch_str = (unsigned char *) malloc(1 + curr_line->line_length - position); if ((*point == ' ') || (*point == '\t')) adv_word(); offset -= position; counter = position; line = temp1 = point; while ((*temp1 != '\0') && (*temp1 != ' ') && (*temp1 != '\t') && (counter < curr_line->line_length)) { *temp2 = *temp1; temp2++; temp1++; counter++; } *temp2 = '\0'; if (position != 1) bol(); while (!Blank_Line(curr_line->prev_line)) bol(); string_count = 0; status = TRUE; while ((line != point) && (status)) { status = search(FALSE); string_count++; } wmove(com_win, 0, 0); wclrtoeol(com_win); wprintw(com_win, formatting_msg); wrefresh(com_win); /* | now get back to the start of the paragraph to start formatting */ if (position != 1) bol(); while (!Blank_Line(curr_line->prev_line)) bol(); observ_margins = FALSE; /* | Start going through lines, putting spaces at end of lines if they do | not already exist. Append lines together to get one long line, and | eliminate spacing at begin of lines. */ while (!Blank_Line(curr_line->next_line)) { eol(); left(TRUE); if (*point != ' ') { right(TRUE); insert(' '); } else right(TRUE); del_char(); if ((*point == ' ') || (*point == '\t')) del_word(); } /* | Now there is one long line. Eliminate extra spaces within the line | after the first word (so as not to blow away any indenting the user | may have put in). */ bol(); adv_word(); while (position < curr_line->line_length) { if ((*point == ' ') && (*(point + 1) == ' ')) del_char(); else right(TRUE); } /* | Now make sure there are two spaces after a '.'. */ bol(); while (position < curr_line->line_length) { if ((*point == '.') && (*(point + 1) == ' ')) { right(TRUE); insert(' '); insert(' '); while (*point == ' ') del_char(); } right(TRUE); } observ_margins = TRUE; bol(); wmove(com_win, 0, 0); wclrtoeol(com_win); wprintw(com_win, formatting_msg); wrefresh(com_win); /* | create lines between margins */ while (position < curr_line->line_length) { while ((scr_pos < right_margin) && (position < curr_line->line_length)) right(TRUE); if (position < curr_line->line_length) { prev_word(); if (position == 1) adv_word(); insert_line(TRUE); } } /* | go back to begin of paragraph, put cursor back to original position */ bol(); while (!Blank_Line(curr_line->prev_line)) bol(); /* | find word cursor was in */ while ((status) && (string_count > 0)) { search(FALSE); string_count--; } /* | offset the cursor to where it was before from the start of the word */ while (offset > 0) { offset--; right(TRUE); } /* | reset flags and strings to what they were before formatting */ if (d_word != NULL) free(d_word); d_word = temp_dword; case_sen = temp_case; free(srch_str); srch_str = tmp_srchstr; d_char[0] = temp_d_char[0]; d_char[1] = temp_d_char[1]; d_char[2] = temp_d_char[2]; auto_format = tmp_af; midscreen(scr_vert, point); werase(com_win); wrefresh(com_win); } unsigned char *init_name[3] = { "/usr/share/misc/init.ee", NULL, ".init.ee" }; void ee_init() /* check for init file and read it if it exists */ { FILE *init_file; unsigned char *string; unsigned char *str1; unsigned char *str2; char *home; int counter; int temp_int; string = getenv("HOME"); if (string == NULL) string = "/tmp"; str1 = home = malloc(strlen(string)+10); strcpy(home, string); strcat(home, "/.init.ee"); init_name[1] = home; string = malloc(512); for (counter = 0; counter < 3; counter++) { if (!(access(init_name[counter], 4))) { init_file = fopen(init_name[counter], "r"); while ((str2 = fgets(string, 512, init_file)) != NULL) { str1 = str2 = string; while (*str2 != '\n') str2++; *str2 = '\0'; if (unique_test(string, init_strings) != 1) continue; if (compare(str1, CASE, FALSE)) case_sen = TRUE; else if (compare(str1, NOCASE, FALSE)) case_sen = FALSE; else if (compare(str1, EXPAND, FALSE)) expand_tabs = TRUE; else if (compare(str1, NOEXPAND, FALSE)) expand_tabs = FALSE; else if (compare(str1, INFO, FALSE)) info_window = TRUE; else if (compare(str1, NOINFO, FALSE)) info_window = FALSE; else if (compare(str1, MARGINS, FALSE)) observ_margins = TRUE; else if (compare(str1, NOMARGINS, FALSE)) observ_margins = FALSE; else if (compare(str1, AUTOFORMAT, FALSE)) { auto_format = TRUE; observ_margins = TRUE; } else if (compare(str1, NOAUTOFORMAT, FALSE)) auto_format = FALSE; else if (compare(str1, Echo, FALSE)) { str1 = next_word(str1); if (*str1 != '\0') echo_string(str1); } else if (compare(str1, PRINTCOMMAND, FALSE)) { str1 = next_word(str1); print_command = malloc(strlen(str1)+1); strcpy(print_command, str1); } else if (compare(str1, RIGHTMARGIN, FALSE)) { str1 = next_word(str1); if ((*str1 >= '0') && (*str1 <= '9')) { temp_int = atoi(str1); if (temp_int > 0) right_margin = temp_int; } } else if (compare(str1, HIGHLIGHT, FALSE)) nohighlight = FALSE; else if (compare(str1, NOHIGHLIGHT, FALSE)) nohighlight = TRUE; else if (compare(str1, EIGHTBIT, FALSE)) eightbit = TRUE; else if (compare(str1, NOEIGHTBIT, FALSE)) { eightbit = FALSE; ee_chinese = FALSE; } else if (compare(str1, EMACS_string, FALSE)) emacs_keys_mode = TRUE; else if (compare(str1, NOEMACS_string, FALSE)) emacs_keys_mode = FALSE; else if (compare(str1, chinese_cmd, FALSE)) { ee_chinese = TRUE; eightbit = TRUE; } else if (compare(str1, nochinese_cmd, FALSE)) ee_chinese = FALSE; } fclose(init_file); } } free(string); free(home); string = getenv("LANG"); if (string != NULL) { if (strcmp(string, "zh_TW.big5") == 0) { ee_chinese = TRUE; eightbit = TRUE; } } } /* | Save current configuration to .init.ee file in the current directory. */ void dump_ee_conf() { FILE *init_file; FILE *old_init_file = NULL; char *file_name = ".init.ee"; char *home_dir = "~/.init.ee"; char buffer[512]; struct stat buf; char *string; int length; int option = 0; if (restrict_mode()) { return; } option = menu_op(config_dump_menu); werase(com_win); wmove(com_win, 0, 0); if (option == 0) { wprintw(com_win, conf_not_saved_msg); wrefresh(com_win); return; } else if (option == 2) file_name = resolve_name(home_dir); /* | If a .init.ee file exists, move it to .init.ee.old. */ if (stat(file_name, &buf) != -1) { sprintf(buffer, "%s.old", file_name); unlink(buffer); link(file_name, buffer); unlink(file_name); old_init_file = fopen(buffer, "r"); } init_file = fopen(file_name, "w"); if (init_file == NULL) { wprintw(com_win, conf_dump_err_msg); wrefresh(com_win); return; } if (old_init_file != NULL) { /* | Copy non-configuration info into new .init.ee file. */ while ((string = fgets(buffer, 512, old_init_file)) != NULL) { length = strlen(string); string[length - 1] = '\0'; if (unique_test(string, init_strings) == 1) { if (compare(string, Echo, FALSE)) { fprintf(init_file, "%s\n", string); } } else fprintf(init_file, "%s\n", string); } fclose(old_init_file); } fprintf(init_file, "%s\n", case_sen ? CASE : NOCASE); fprintf(init_file, "%s\n", expand_tabs ? EXPAND : NOEXPAND); fprintf(init_file, "%s\n", info_window ? INFO : NOINFO ); fprintf(init_file, "%s\n", observ_margins ? MARGINS : NOMARGINS ); fprintf(init_file, "%s\n", auto_format ? AUTOFORMAT : NOAUTOFORMAT ); fprintf(init_file, "%s %s\n", PRINTCOMMAND, print_command); fprintf(init_file, "%s %d\n", RIGHTMARGIN, right_margin); fprintf(init_file, "%s\n", nohighlight ? NOHIGHLIGHT : HIGHLIGHT ); fprintf(init_file, "%s\n", eightbit ? EIGHTBIT : NOEIGHTBIT ); fprintf(init_file, "%s\n", emacs_keys_mode ? EMACS_string : NOEMACS_string ); fprintf(init_file, "%s\n", ee_chinese ? chinese_cmd : nochinese_cmd ); fclose(init_file); wprintw(com_win, conf_dump_success_msg, file_name); wrefresh(com_win); if ((option == 2) && (file_name != home_dir)) { free(file_name); } } void echo_string(string) /* echo the given string */ char *string; { char *temp; int Counter; temp = string; while (*temp != '\0') { if (*temp == '\\') { temp++; if (*temp == 'n') putchar('\n'); else if (*temp == 't') putchar('\t'); else if (*temp == 'b') putchar('\b'); else if (*temp == 'r') putchar('\r'); else if (*temp == 'f') putchar('\f'); else if ((*temp == 'e') || (*temp == 'E')) putchar('\033'); /* escape */ else if (*temp == '\\') putchar('\\'); else if (*temp == '\'') putchar('\''); else if ((*temp >= '0') && (*temp <= '9')) { Counter = 0; while ((*temp >= '0') && (*temp <= '9')) { Counter = (8 * Counter) + (*temp - '0'); temp++; } putchar(Counter); temp--; } temp++; } else { putchar(*temp); temp++; } } fflush(stdout); } void spell_op() /* check spelling of words in the editor */ { if (restrict_mode()) { return; } top(); /* go to top of file */ insert_line(FALSE); /* create two blank lines */ insert_line(FALSE); top(); command(shell_echo_msg); adv_line(); wmove(com_win, 0, 0); wprintw(com_win, spell_in_prog_msg); wrefresh(com_win); command("<>!spell"); /* send contents of buffer to command 'spell' and read the results back into the editor */ } void ispell_op() { char template[128], *name; char string[256]; int fd; if (restrict_mode()) { return; } (void)sprintf(template, "/tmp/ee.XXXXXXXX"); fd = mkstemp(template); if (fd < 0) { wmove(com_win, 0, 0); wprintw(com_win, create_file_fail_msg, name); wrefresh(com_win); return; } close(fd); if (write_file(name, 0)) { sprintf(string, "ispell %s", name); sh_command(string); delete_text(); tmp_file = name; recv_file = TRUE; check_fp(); unlink(name); } } int first_word_len(test_line) struct text *test_line; { int counter; unsigned char *pnt; if (test_line == NULL) return(0); pnt = test_line->line; if ((pnt == NULL) || (*pnt == '\0') || (*pnt == '.') || (*pnt == '>')) return(0); if ((*pnt == ' ') || (*pnt == '\t')) { pnt = next_word(pnt); } if (*pnt == '\0') return(0); counter = 0; while ((*pnt != '\0') && ((*pnt != ' ') && (*pnt != '\t'))) { pnt++; counter++; } while ((*pnt != '\0') && ((*pnt == ' ') || (*pnt == '\t'))) { pnt++; counter++; } return(counter); } void Auto_Format() /* format the paragraph according to set margins */ { int string_count; int offset; int temp_case; int word_len; int temp_dwl; int tmp_d_line_length; int leave_loop = FALSE; int status; int counter; char not_blank; unsigned char *line; unsigned char *tmp_srchstr; unsigned char *temp1, *temp2; unsigned char *temp_dword; unsigned char temp_d_char[3]; unsigned char *tmp_d_line; temp_d_char[0] = d_char[0]; temp_d_char[1] = d_char[1]; temp_d_char[2] = d_char[2]; /* | if observ_margins is not set, or the current line is blank, | do not format the current paragraph */ if ((!observ_margins) || (Blank_Line(curr_line))) return; /* | get current position in paragraph, so after formatting, the cursor | will be in the same relative position */ tmp_d_line = d_line; tmp_d_line_length = dlt_line->line_length; d_line = NULL; auto_format = FALSE; offset = position; if ((position != 1) && ((*point == ' ') || (*point == '\t') || (position == curr_line->line_length) || (*point == '\0'))) prev_word(); temp_dword = d_word; temp_dwl = d_wrd_len; d_wrd_len = 0; d_word = NULL; temp_case = case_sen; case_sen = TRUE; tmp_srchstr = srch_str; temp2 = srch_str = (unsigned char *) malloc(1 + curr_line->line_length - position); if ((*point == ' ') || (*point == '\t')) adv_word(); offset -= position; counter = position; line = temp1 = point; while ((*temp1 != '\0') && (*temp1 != ' ') && (*temp1 != '\t') && (counter < curr_line->line_length)) { *temp2 = *temp1; temp2++; temp1++; counter++; } *temp2 = '\0'; if (position != 1) bol(); while (!Blank_Line(curr_line->prev_line)) bol(); string_count = 0; status = TRUE; while ((line != point) && (status)) { status = search(FALSE); string_count++; } /* | now get back to the start of the paragraph to start checking */ if (position != 1) bol(); while (!Blank_Line(curr_line->prev_line)) bol(); /* | Start going through lines, putting spaces at end of lines if they do | not already exist. Check line length, and move words to the next line | if they cross the margin. Then get words from the next line if they | will fit in before the margin. */ counter = 0; while (!leave_loop) { if (position != curr_line->line_length) eol(); left(TRUE); if (*point != ' ') { right(TRUE); insert(' '); } else right(TRUE); not_blank = FALSE; /* | fill line if first word on next line will fit | in the line without crossing the margin */ while ((curr_line->next_line != NULL) && ((word_len = first_word_len(curr_line->next_line)) > 0) && ((scr_pos + word_len) < right_margin)) { adv_line(); if ((*point == ' ') || (*point == '\t')) adv_word(); del_word(); if (position != 1) bol(); /* | We know this line was not blank before, so | make sure that it doesn't have one of the | leading characters that indicate the line | should not be modified. | | We also know that this character should not | be left as the first character of this line. */ if ((Blank_Line(curr_line)) && (curr_line->line[0] != '.') && (curr_line->line[0] != '>')) { del_line(); not_blank = FALSE; } else not_blank = TRUE; /* | go to end of previous line */ left(TRUE); undel_word(); eol(); /* | make sure there's a space at the end of the line */ left(TRUE); if (*point != ' ') { right(TRUE); insert(' '); } else right(TRUE); } /* | make sure line does not cross right margin */ while (right_margin <= scr_pos) { prev_word(); if (position != 1) { del_word(); if (Blank_Line(curr_line->next_line)) insert_line(TRUE); else adv_line(); if ((*point == ' ') || (*point == '\t')) adv_word(); undel_word(); not_blank = TRUE; if (position != 1) bol(); left(TRUE); } } if ((!Blank_Line(curr_line->next_line)) || (not_blank)) { adv_line(); counter++; } else leave_loop = TRUE; } /* | go back to begin of paragraph, put cursor back to original position */ if (position != 1) bol(); while ((counter-- > 0) || (!Blank_Line(curr_line->prev_line))) bol(); /* | find word cursor was in */ status = TRUE; while ((status) && (string_count > 0)) { status = search(FALSE); string_count--; } /* | offset the cursor to where it was before from the start of the word */ while (offset > 0) { offset--; right(TRUE); } if ((string_count > 0) && (offset < 0)) { while (offset < 0) { offset++; left(TRUE); } } /* | reset flags and strings to what they were before formatting */ if (d_word != NULL) free(d_word); d_word = temp_dword; d_wrd_len = temp_dwl; case_sen = temp_case; free(srch_str); srch_str = tmp_srchstr; d_char[0] = temp_d_char[0]; d_char[1] = temp_d_char[1]; d_char[2] = temp_d_char[2]; auto_format = TRUE; dlt_line->line_length = tmp_d_line_length; d_line = tmp_d_line; formatted = TRUE; midscreen(scr_vert, point); } void modes_op() { int ret_value; int counter; char *string; do { sprintf(modes_menu[1].item_string, "%s %s", mode_strings[1], (expand_tabs ? ON : OFF)); sprintf(modes_menu[2].item_string, "%s %s", mode_strings[2], (case_sen ? ON : OFF)); sprintf(modes_menu[3].item_string, "%s %s", mode_strings[3], (observ_margins ? ON : OFF)); sprintf(modes_menu[4].item_string, "%s %s", mode_strings[4], (auto_format ? ON : OFF)); sprintf(modes_menu[5].item_string, "%s %s", mode_strings[5], (eightbit ? ON : OFF)); sprintf(modes_menu[6].item_string, "%s %s", mode_strings[6], (info_window ? ON : OFF)); sprintf(modes_menu[7].item_string, "%s %s", mode_strings[7], (emacs_keys_mode ? ON : OFF)); sprintf(modes_menu[8].item_string, "%s %d", mode_strings[8], right_margin); sprintf(modes_menu[9].item_string, "%s %s", mode_strings[9], (ee_chinese ? ON : OFF)); ret_value = menu_op(modes_menu); switch (ret_value) { case 1: expand_tabs = !expand_tabs; break; case 2: case_sen = !case_sen; break; case 3: observ_margins = !observ_margins; break; case 4: auto_format = !auto_format; if (auto_format) observ_margins = TRUE; break; case 5: eightbit = !eightbit; if (!eightbit) ee_chinese = FALSE; #ifdef NCURSE if (ee_chinese) nc_setattrib(A_NC_BIG5); else nc_clearattrib(A_NC_BIG5); #endif /* NCURSE */ redraw(); wnoutrefresh(text_win); break; case 6: if (info_window) no_info_window(); else create_info_window(); break; case 7: emacs_keys_mode = !emacs_keys_mode; if (info_window) paint_info_win(); break; case 8: string = get_string(margin_prompt, TRUE); if (string != NULL) { counter = atoi(string); if (counter > 0) right_margin = counter; free(string); } break; case 9: ee_chinese = !ee_chinese; if (ee_chinese != FALSE) eightbit = TRUE; #ifdef NCURSE if (ee_chinese) nc_setattrib(A_NC_BIG5); else nc_clearattrib(A_NC_BIG5); #endif /* NCURSE */ redraw(); break; default: break; } } while (ret_value != 0); } char * is_in_string(string, substring) /* a strchr() look-alike for systems without strchr() */ char * string, *substring; { char *full, *sub; for (sub = substring; (sub != NULL) && (*sub != '\0'); sub++) { for (full = string; (full != NULL) && (*full != '\0'); full++) { if (*sub == *full) return(full); } } return(NULL); } /* | handle names of the form "~/file", "~user/file", | "$HOME/foo", "~/$FOO", etc. */ char * resolve_name(name) char *name; { char long_buffer[1024]; char short_buffer[128]; char *buffer; char *slash; char *tmp; char *start_of_var; int offset; int index; int counter; struct passwd *user; if (name[0] == '~') { if (name[1] == '/') { index = getuid(); user = (struct passwd *) getpwuid(index); slash = name + 1; } else { slash = strchr(name, '/'); if (slash == NULL) return(name); *slash = '\0'; user = (struct passwd *) getpwnam((name + 1)); *slash = '/'; } if (user == NULL) { return(name); } buffer = malloc(strlen(user->pw_dir) + strlen(slash) + 1); strcpy(buffer, user->pw_dir); strcat(buffer, slash); } else buffer = name; if (is_in_string(buffer, "$")) { tmp = buffer; index = 0; while ((*tmp != '\0') && (index < 1024)) { while ((*tmp != '\0') && (*tmp != '$') && (index < 1024)) { long_buffer[index] = *tmp; tmp++; index++; } if ((*tmp == '$') && (index < 1024)) { counter = 0; start_of_var = tmp; tmp++; if (*tmp == '{') /* } */ /* bracketed variable name */ { tmp++; /* { */ while ((*tmp != '\0') && (*tmp != '}') && (counter < 128)) { short_buffer[counter] = *tmp; counter++; tmp++; } /* { */ if (*tmp == '}') tmp++; } else { while ((*tmp != '\0') && (*tmp != '/') && (*tmp != '$') && (counter < 128)) { short_buffer[counter] = *tmp; counter++; tmp++; } } short_buffer[counter] = '\0'; if ((slash = getenv(short_buffer)) != NULL) { offset = strlen(slash); if ((offset + index) < 1024) strcpy(&long_buffer[index], slash); index += offset; } else { while ((start_of_var != tmp) && (index < 1024)) { long_buffer[index] = *start_of_var; start_of_var++; index++; } } } } if (index == 1024) return(buffer); else long_buffer[index] = '\0'; if (name != buffer) free(buffer); buffer = malloc(index + 1); strcpy(buffer, long_buffer); } return(buffer); } int restrict_mode() { if (!restricted) return(FALSE); wmove(com_win, 0, 0); wprintw(com_win, restricted_msg); wclrtoeol(com_win); wrefresh(com_win); clear_com_win = TRUE; return(TRUE); } /* | The following routine tests the input string against the list of | strings, to determine if the string is a unique match with one of the | valid values. */ int unique_test(string, list) char *string; char *list[]; { int counter; int num_match; int result; num_match = 0; counter = 0; while (list[counter] != NULL) { result = compare(string, list[counter], FALSE); if (result) num_match++; counter++; } return(num_match); } #ifndef NO_CATGETS /* | Get the catalog entry, and if it got it from the catalog, | make a copy, since the buffer will be overwritten by the | next call to catgets(). */ char * catgetlocal(number, string) int number; char *string; { char *temp1; char *temp2; temp1 = catgets(catalog, 1, number, string); if (temp1 != string) { temp2 = malloc(strlen(temp1) + 1); strcpy(temp2, temp1); temp1 = temp2; } return(temp1); } #endif /* NO_CATGETS */ /* | The following is to allow for using message catalogs which allow | the software to be 'localized', that is, to use different languages | all with the same binary. For more information, see your system | documentation, or the X/Open Internationalization Guide. */ void strings_init() { int counter; #ifndef NO_CATGETS setlocale(LC_ALL, ""); catalog = catopen("ee", NL_CAT_LOCALE); #endif /* NO_CATGETS */ modes_menu[0].item_string = catgetlocal( 1, "modes menu"); mode_strings[1] = catgetlocal( 2, "tabs to spaces "); mode_strings[2] = catgetlocal( 3, "case sensitive search"); mode_strings[3] = catgetlocal( 4, "margins observed "); mode_strings[4] = catgetlocal( 5, "auto-paragraph format"); mode_strings[5] = catgetlocal( 6, "eightbit characters "); mode_strings[6] = catgetlocal( 7, "info window "); mode_strings[8] = catgetlocal( 8, "right margin "); leave_menu[0].item_string = catgetlocal( 9, "leave menu"); leave_menu[1].item_string = catgetlocal( 10, "save changes"); leave_menu[2].item_string = catgetlocal( 11, "no save"); file_menu[0].item_string = catgetlocal( 12, "file menu"); file_menu[1].item_string = catgetlocal( 13, "read a file"); file_menu[2].item_string = catgetlocal( 14, "write a file"); file_menu[3].item_string = catgetlocal( 15, "save file"); file_menu[4].item_string = catgetlocal( 16, "print editor contents"); search_menu[0].item_string = catgetlocal( 17, "search menu"); search_menu[1].item_string = catgetlocal( 18, "search for ..."); search_menu[2].item_string = catgetlocal( 19, "search"); spell_menu[0].item_string = catgetlocal( 20, "spell menu"); spell_menu[1].item_string = catgetlocal( 21, "use 'spell'"); spell_menu[2].item_string = catgetlocal( 22, "use 'ispell'"); misc_menu[0].item_string = catgetlocal( 23, "miscellaneous menu"); misc_menu[1].item_string = catgetlocal( 24, "format paragraph"); misc_menu[2].item_string = catgetlocal( 25, "shell command"); misc_menu[3].item_string = catgetlocal( 26, "check spelling"); main_menu[0].item_string = catgetlocal( 27, "main menu"); main_menu[1].item_string = catgetlocal( 28, "leave editor"); main_menu[2].item_string = catgetlocal( 29, "help"); main_menu[3].item_string = catgetlocal( 30, "file operations"); main_menu[4].item_string = catgetlocal( 31, "redraw screen"); main_menu[5].item_string = catgetlocal( 32, "settings"); main_menu[6].item_string = catgetlocal( 33, "search"); main_menu[7].item_string = catgetlocal( 34, "miscellaneous"); help_text[0] = catgetlocal( 35, "Control keys: "); help_text[1] = catgetlocal( 36, "^a ascii code ^i tab ^r right "); help_text[2] = catgetlocal( 37, "^b bottom of text ^j newline ^t top of text "); help_text[3] = catgetlocal( 38, "^c command ^k delete char ^u up "); help_text[4] = catgetlocal( 39, "^d down ^l left ^v undelete word "); help_text[5] = catgetlocal( 40, "^e search prompt ^m newline ^w delete word "); help_text[6] = catgetlocal( 41, "^f undelete char ^n next page ^x search "); help_text[7] = catgetlocal( 42, "^g begin of line ^o end of line ^y delete line "); help_text[8] = catgetlocal( 43, "^h backspace ^p prev page ^z undelete line "); help_text[9] = catgetlocal( 44, "^[ (escape) menu ESC-Enter: exit ee "); help_text[10] = catgetlocal( 45, " "); help_text[11] = catgetlocal( 46, "Commands: "); help_text[12] = catgetlocal( 47, "help : get this info file : print file name "); help_text[13] = catgetlocal( 48, "read : read a file char : ascii code of char "); help_text[14] = catgetlocal( 49, "write : write a file case : case sensitive search "); help_text[15] = catgetlocal( 50, "exit : leave and save nocase : case insensitive search "); help_text[16] = catgetlocal( 51, "quit : leave, no save !cmd : execute \"cmd\" in shell "); help_text[17] = catgetlocal( 52, "line : display line # 0-9 : go to line \"#\" "); help_text[18] = catgetlocal( 53, "expand : expand tabs noexpand: do not expand tabs "); help_text[19] = catgetlocal( 54, " "); help_text[20] = catgetlocal( 55, " ee [+#] [-i] [-e] [-h] [file(s)] "); help_text[21] = catgetlocal( 56, "+# :go to line # -i :no info window -e : don't expand tabs -h :no highlight"); control_keys[0] = catgetlocal( 57, "^[ (escape) menu ^e search prompt ^y delete line ^u up ^p prev page "); control_keys[1] = catgetlocal( 58, "^a ascii code ^x search ^z undelete line ^d down ^n next page "); control_keys[2] = catgetlocal( 59, "^b bottom of text ^g begin of line ^w delete word ^l left "); control_keys[3] = catgetlocal( 60, "^t top of text ^o end of line ^v undelete word ^r right "); control_keys[4] = catgetlocal( 61, "^c command ^k delete char ^f undelete char ESC-Enter: exit ee "); command_strings[0] = catgetlocal( 62, "help : get help info |file : print file name |line : print line # "); command_strings[1] = catgetlocal( 63, "read : read a file |char : ascii code of char |0-9 : go to line \"#\""); command_strings[2] = catgetlocal( 64, "write: write a file |case : case sensitive search |exit : leave and save "); command_strings[3] = catgetlocal( 65, "!cmd : shell \"cmd\" |nocase: ignore case in search |quit : leave, no save"); command_strings[4] = catgetlocal( 66, "expand: expand tabs |noexpand: do not expand tabs "); com_win_message = catgetlocal( 67, " press Escape (^[) for menu"); no_file_string = catgetlocal( 68, "no file"); ascii_code_str = catgetlocal( 69, "ascii code: "); printer_msg_str = catgetlocal( 70, "sending contents of buffer to \"%s\" "); command_str = catgetlocal( 71, "command: "); file_write_prompt_str = catgetlocal( 72, "name of file to write: "); file_read_prompt_str = catgetlocal( 73, "name of file to read: "); char_str = catgetlocal( 74, "character = %d"); unkn_cmd_str = catgetlocal( 75, "unknown command \"%s\""); non_unique_cmd_msg = catgetlocal( 76, "entered command is not unique"); line_num_str = catgetlocal( 77, "line %d "); line_len_str = catgetlocal( 78, "length = %d"); current_file_str = catgetlocal( 79, "current file is \"%s\" "); usage0 = catgetlocal( 80, "usage: %s [-i] [-e] [-h] [+line_number] [file(s)]\n"); usage1 = catgetlocal( 81, " -i turn off info window\n"); usage2 = catgetlocal( 82, " -e do not convert tabs to spaces\n"); usage3 = catgetlocal( 83, " -h do not use highlighting\n"); file_is_dir_msg = catgetlocal( 84, "file \"%s\" is a directory"); new_file_msg = catgetlocal( 85, "new file \"%s\""); cant_open_msg = catgetlocal( 86, "can't open \"%s\""); open_file_msg = catgetlocal( 87, "file \"%s\", %d lines"); file_read_fin_msg = catgetlocal( 88, "finished reading file \"%s\""); reading_file_msg = catgetlocal( 89, "reading file \"%s\""); read_only_msg = catgetlocal( 90, ", read only"); file_read_lines_msg = catgetlocal( 91, "file \"%s\", %d lines"); save_file_name_prompt = catgetlocal( 92, "enter name of file: "); file_not_saved_msg = catgetlocal( 93, "no filename entered: file not saved"); changes_made_prompt = catgetlocal( 94, "changes have been made, are you sure? (y/n [n]) "); yes_char = catgetlocal( 95, "y"); file_exists_prompt = catgetlocal( 96, "file already exists, overwrite? (y/n) [n] "); create_file_fail_msg = catgetlocal( 97, "unable to create file \"%s\""); writing_file_msg = catgetlocal( 98, "writing file \"%s\""); file_written_msg = catgetlocal( 99, "\"%s\" %d lines, %d characters"); searching_msg = catgetlocal( 100, " ...searching"); str_not_found_msg = catgetlocal( 101, "string \"%s\" not found"); search_prompt_str = catgetlocal( 102, "search for: "); exec_err_msg = catgetlocal( 103, "could not exec %s\n"); continue_msg = catgetlocal( 104, "press return to continue "); menu_cancel_msg = catgetlocal( 105, "press Esc to cancel"); menu_size_err_msg = catgetlocal( 106, "menu too large for window"); press_any_key_msg = catgetlocal( 107, "press any key to continue "); shell_prompt = catgetlocal( 108, "shell command: "); formatting_msg = catgetlocal( 109, "...formatting paragraph..."); shell_echo_msg = catgetlocal( 110, ""; commands[17] = "!"; commands[18] = "0"; commands[19] = "1"; commands[20] = "2"; commands[21] = "3"; commands[22] = "4"; commands[23] = "5"; commands[24] = "6"; commands[25] = "7"; commands[26] = "8"; commands[27] = "9"; commands[28] = CHARACTER; commands[29] = chinese_cmd; commands[30] = nochinese_cmd; commands[31] = NULL; init_strings[0] = CASE; init_strings[1] = NOCASE; init_strings[2] = EXPAND; init_strings[3] = NOEXPAND; init_strings[4] = INFO; init_strings[5] = NOINFO; init_strings[6] = MARGINS; init_strings[7] = NOMARGINS; init_strings[8] = AUTOFORMAT; init_strings[9] = NOAUTOFORMAT; init_strings[10] = Echo; init_strings[11] = PRINTCOMMAND; init_strings[12] = RIGHTMARGIN; init_strings[13] = HIGHLIGHT; init_strings[14] = NOHIGHLIGHT; init_strings[15] = EIGHTBIT; init_strings[16] = NOEIGHTBIT; init_strings[17] = EMACS_string; init_strings[18] = NOEMACS_string; init_strings[19] = chinese_cmd; init_strings[20] = nochinese_cmd; init_strings[21] = NULL; /* | allocate space for strings here for settings menu */ for (counter = 1; counter < NUM_MODES_ITEMS; counter++) { modes_menu[counter].item_string = malloc(80); } #ifndef NO_CATGETS catclose(catalog); #endif /* NO_CATGETS */ }