blob: 6e084bd93af92875fd59217018a0580a1379ea83 [file] [log] [blame]
Chris Allegretta11b00112000-08-06 21:13:45 +00001/* $Id$ */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002/**************************************************************************
3 * nano.c *
4 * *
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +00005 * Copyright (C) 1999-2004 Chris Allegretta *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00006 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
Chris Allegretta3a24f3f2001-10-24 11:33:54 +00008 * the Free Software Foundation; either version 2, or (at your option) *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00009 * any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
19 * *
20 **************************************************************************/
21
Chris Allegretta6efda542001-04-28 18:03:52 +000022#include "config.h"
23
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000024#include <stdio.h>
25#include <stdlib.h>
26#include <stdarg.h>
27#include <signal.h>
28#include <unistd.h>
29#include <string.h>
30#include <fcntl.h>
31#include <sys/stat.h>
32#include <sys/ioctl.h>
33#include <sys/param.h>
Chris Allegretta27eb13f2000-11-05 16:52:21 +000034#include <sys/types.h>
35#include <sys/wait.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000036#include <errno.h>
37#include <ctype.h>
38#include <locale.h>
39#include <limits.h>
Adam Rogoyski77f36de2000-06-07 03:56:54 +000040#include <assert.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000041#include "proto.h"
42#include "nano.h"
43
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000044#ifdef HAVE_TERMIOS_H
45#include <termios.h>
46#endif
47
48#ifdef HAVE_TERMIO_H
49#include <termio.h>
50#endif
51
52#ifdef HAVE_GETOPT_H
53#include <getopt.h>
54#endif
55
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000056#ifndef NANO_SMALL
57#include <setjmp.h>
58#endif
59
Chris Allegretta6fe61492001-05-21 12:56:25 +000060#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +000061static int fill = 0; /* Fill - where to wrap lines, basically */
Chris Allegretta6fe61492001-05-21 12:56:25 +000062#endif
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000063#ifndef DISABLE_WRAPPING
64static int same_line_wrap = 0; /* Whether wrapped text should be
65 prepended to the next line */
66#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +000067
Chris Allegretta6df90f52002-07-19 01:08:59 +000068static struct termios oldterm; /* The user's original term settings */
Chris Allegretta88520c92001-05-05 17:45:54 +000069static struct sigaction act; /* For all our fun signal handlers */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000070
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000071#ifndef NANO_SMALL
Chris Allegretta08020882001-01-29 23:37:54 +000072static sigjmp_buf jmpbuf; /* Used to return to mainloop after SIGWINCH */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000073#endif
Chris Allegretta08020882001-01-29 23:37:54 +000074
David Lawrence Ramseyda141062004-05-25 19:41:11 +000075/* What we do when we're all set to exit. */
76void finish(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000077{
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000078 if (!ISSET(NO_HELP))
79 blank_bottombars();
80 else
81 blank_statusbar();
Chris Allegretta6b58acd2001-04-12 03:01:53 +000082
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000083 wrefresh(bottomwin);
84 endwin();
85
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000086 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000087 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000088
Chris Allegrettad8451932003-03-11 03:50:40 +000089#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
90 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
91 save_history();
92#endif
93
Chris Allegretta6232d662002-05-12 19:52:15 +000094#ifdef DEBUG
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000095 thanks_for_all_the_fish();
Chris Allegretta6232d662002-05-12 19:52:15 +000096#endif
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000097
David Lawrence Ramseyda141062004-05-25 19:41:11 +000098 exit(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000099}
100
101/* Die (gracefully?) */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000102void die(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000103{
104 va_list ap;
105
Chris Allegrettaa0d89972003-02-03 03:32:08 +0000106 endwin();
107 curses_ended = TRUE;
108
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000109 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000110 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000111
Chris Allegretta6df90f52002-07-19 01:08:59 +0000112 va_start(ap, msg);
113 vfprintf(stderr, msg, ap);
114 va_end(ap);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000115
Chris Allegretta32da4562002-01-02 15:12:21 +0000116 /* save the currently loaded file if it's been modified */
117 if (ISSET(MODIFIED))
118 die_save_file(filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000119
Chris Allegretta355fbe52001-07-14 19:32:47 +0000120#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +0000121 /* then save all of the other modified loaded files, if any */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000122 if (open_files != NULL) {
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000123 openfilestruct *tmp;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000124
125 tmp = open_files;
126
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000127 while (open_files->prev != NULL)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000128 open_files = open_files->prev;
129
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000130 while (open_files->next != NULL) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000131
David Lawrence Ramseya3370c42004-04-05 01:08:14 +0000132 /* if we already saved the file above (i.e, if it was the
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000133 currently loaded file), don't save it again */
134 if (tmp != open_files) {
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000135 /* make sure open_files->fileage and fileage, and
136 open_files->filebot and filebot, are in sync; they
137 might not be if lines have been cut from the top or
138 bottom of the file */
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000139 fileage = open_files->fileage;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000140 filebot = open_files->filebot;
Chris Allegretta32da4562002-01-02 15:12:21 +0000141 /* save the file if it's been modified */
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000142 if (open_files->file_flags & MODIFIED)
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000143 die_save_file(open_files->filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000144 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000145 open_files = open_files->next;
146 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000147 }
148#endif
149
Chris Allegretta6df90f52002-07-19 01:08:59 +0000150 exit(1); /* We have a problem: exit w/ errorlevel(1) */
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000151}
152
Chris Allegretta6df90f52002-07-19 01:08:59 +0000153void die_save_file(const char *die_filename)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000154{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000155 char *ret;
Chris Allegretta48b06702002-02-22 04:30:50 +0000156 int i = -1;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000157
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000158 /* No emergency files in restricted mode! */
159 if (ISSET(RESTRICTED))
160 return;
161
Chris Allegretta6df90f52002-07-19 01:08:59 +0000162 /* If we can't save, we have REAL bad problems, but we might as well
163 TRY. */
164 if (die_filename[0] == '\0')
165 ret = get_next_filename("nano.save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000166 else {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000167 char *buf = charalloc(strlen(die_filename) + 6);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000168
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000169 strcpy(buf, die_filename);
170 strcat(buf, ".save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000171 ret = get_next_filename(buf);
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000172 free(buf);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000173 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000174 if (ret[0] != '\0')
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +0000175 i = write_file(ret, TRUE, FALSE, TRUE);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000176
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000177 if (i != -1)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000178 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000179 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000180 fprintf(stderr, _("\nNo %s written (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000181
182 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000183}
184
Chris Allegrettae61e8302001-01-14 05:18:27 +0000185/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000186 * screen is too small. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000187void die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000188{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000189 die(_("Window size is too small for nano...\n"));
Chris Allegrettae61e8302001-01-14 05:18:27 +0000190}
191
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000192void print_view_warning(void)
193{
194 statusbar(_("Key illegal in VIEW mode"));
195}
196
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +0000197/* Initialize global variables -- no better way for now. If
Chris Allegretta6df90f52002-07-19 01:08:59 +0000198 * save_cutbuffer is nonzero, don't set cutbuffer to NULL. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000199void global_init(int save_cutbuffer)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000200{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000201 current_x = 0;
202 current_y = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000203
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000204 editwinrows = LINES - 5 + no_help();
205 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000206 die_too_small();
207
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000208 fileage = NULL;
Chris Allegretta56214c62001-09-27 02:46:53 +0000209 if (!save_cutbuffer)
210 cutbuffer = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000211 current = NULL;
212 edittop = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000213 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000214 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000215 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000216
Chris Allegretta6fe61492001-05-21 12:56:25 +0000217#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000218 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000219 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000220 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000221 if (fill < 0)
222 fill = 0;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000223#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000224
Chris Allegretta88b09152001-05-17 11:35:43 +0000225 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000226 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000227 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000228}
229
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000230void window_init(void)
231{
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000232 editwinrows = LINES - 5 + no_help();
233 if (editwinrows < MIN_EDITOR_ROWS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000234 die_too_small();
235
Chris Allegretta1a128af2003-01-26 04:15:56 +0000236 if (topwin != NULL)
237 delwin(topwin);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000238 if (edit != NULL)
239 delwin(edit);
Chris Allegretta1a128af2003-01-26 04:15:56 +0000240 if (bottomwin != NULL)
241 delwin(bottomwin);
242
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000243 /* Set up the windows. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000244 topwin = newwin(2, COLS, 0, 0);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000245 edit = newwin(editwinrows, COLS, 2, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000246 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
247
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000248 /* Turn the keypad back on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000249 keypad(edit, TRUE);
250 keypad(bottomwin, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000251}
252
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000253#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000254void mouse_init(void)
255{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000256 if (ISSET(USE_MOUSE)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000257 mousemask(BUTTON1_RELEASED, NULL);
258 mouseinterval(50);
259 } else
260 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000261}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000262#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000263
264#ifndef DISABLE_HELP
265/* This function allocates help_text, and stores the help string in it.
266 * help_text should be NULL initially. */
267void help_init(void)
268{
Chris Allegretta908f7702003-01-15 11:18:58 +0000269 size_t allocsize = 1; /* space needed for help_text */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000270 char *ptr = NULL;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000271 const shortcut *s;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000272#ifndef NANO_SMALL
273 const toggle *t;
274#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000275
276 /* First set up the initial help text for the current function */
277 if (currshortcut == whereis_list || currshortcut == replace_list
278 || currshortcut == replace_list_2)
279 ptr = _("Search Command Help Text\n\n "
280 "Enter the words or characters you would like to search "
281 "for, then hit enter. If there is a match for the text you "
282 "entered, the screen will be updated to the location of the "
283 "nearest match for the search string.\n\n "
Chris Allegretta37d594c2003-01-05 22:00:41 +0000284 "The previous search string will be shown in brackets after "
285 "the Search: prompt. Hitting Enter without entering any text "
286 "will perform the previous search.\n\n The following function "
287 "keys are available in Search mode:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000288 else if (currshortcut == goto_list)
289 ptr = _("Go To Line Help Text\n\n "
290 "Enter the line number that you wish to go to and hit "
291 "Enter. If there are fewer lines of text than the "
292 "number you entered, you will be brought to the last line "
293 "of the file.\n\n The following function keys are "
294 "available in Go To Line mode:\n\n");
295 else if (currshortcut == insertfile_list)
296 ptr = _("Insert File Help Text\n\n "
297 "Type in the name of a file to be inserted into the current "
298 "file buffer at the current cursor location.\n\n "
299 "If you have compiled nano with multiple file buffer "
300 "support, and enable multiple buffers with the -F "
301 "or --multibuffer command line flags, the Meta-F toggle, or "
302 "a nanorc file, inserting a file will cause it to be "
303 "loaded into a separate buffer (use Meta-< and > to switch "
304 "between file buffers).\n\n If you need another blank "
305 "buffer, do not enter any filename, or type in a "
306 "nonexistent filename at the prompt and press "
307 "Enter.\n\n The following function keys are "
308 "available in Insert File mode:\n\n");
309 else if (currshortcut == writefile_list)
310 ptr = _("Write File Help Text\n\n "
311 "Type the name that you wish to save the current file "
312 "as and hit Enter to save the file.\n\n If you have "
313 "selected text with Ctrl-^, you will be prompted to "
314 "save only the selected portion to a separate file. To "
315 "reduce the chance of overwriting the current file with "
316 "just a portion of it, the current filename is not the "
317 "default in this mode.\n\n The following function keys "
318 "are available in Write File mode:\n\n");
319#ifndef DISABLE_BROWSER
320 else if (currshortcut == browser_list)
321 ptr = _("File Browser Help Text\n\n "
322 "The file browser is used to visually browse the "
323 "directory structure to select a file for reading "
324 "or writing. You may use the arrow keys or Page Up/"
325 "Down to browse through the files, and S or Enter to "
326 "choose the selected file or enter the selected "
327 "directory. To move up one level, select the directory "
328 "called \"..\" at the top of the file list.\n\n The "
329 "following function keys are available in the file "
330 "browser:\n\n");
331 else if (currshortcut == gotodir_list)
332 ptr = _("Browser Go To Directory Help Text\n\n "
333 "Enter the name of the directory you would like to "
334 "browse to.\n\n If tab completion has not been disabled, "
335 "you can use the TAB key to (attempt to) automatically "
336 "complete the directory name.\n\n The following function "
337 "keys are available in Browser Go To Directory mode:\n\n");
338#endif
Chris Allegretta201f1d92003-02-05 02:51:19 +0000339#ifndef DISABLE_SPELLER
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000340 else if (currshortcut == spell_list)
341 ptr = _("Spell Check Help Text\n\n "
342 "The spell checker checks the spelling of all text "
343 "in the current file. When an unknown word is "
344 "encountered, it is highlighted and a replacement can "
345 "be edited. It will then prompt to replace every "
346 "instance of the given misspelled word in the "
347 "current file.\n\n The following other functions are "
348 "available in Spell Check mode:\n\n");
Chris Allegretta201f1d92003-02-05 02:51:19 +0000349#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000350#ifndef NANO_SMALL
351 else if (currshortcut == extcmd_list)
352 ptr = _("External Command Help Text\n\n "
353 "This menu allows you to insert the output of a command "
354 "run by the shell into the current buffer (or a new "
355 "buffer in multibuffer mode).\n\n The following keys are "
356 "available in this mode:\n\n");
357#endif
358 else /* Default to the main help list */
359 ptr = _(" nano help text\n\n "
360 "The nano editor is designed to emulate the functionality and "
361 "ease-of-use of the UW Pico text editor. There are four main "
362 "sections of the editor: The top line shows the program "
363 "version, the current filename being edited, and whether "
364 "or not the file has been modified. Next is the main editor "
365 "window showing the file being edited. The status line is "
366 "the third line from the bottom and shows important messages. "
367 "The bottom two lines show the most commonly used shortcuts "
368 "in the editor.\n\n "
369 "The notation for shortcuts is as follows: Control-key "
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +0000370 "sequences are notated with a caret (^) symbol and can be "
371 "entered either by using the Control (Ctrl) key or pressing the "
372 "Esc key twice. Escape-key sequences are notated with the Meta "
373 "(M) symbol and can be entered using either the Esc, Alt or "
374 "Meta key depending on your keyboard setup. Also, pressing Esc "
375 "twice and then typing a three-digit number from 000 to 255 "
376 "will enter the character with the corresponding ASCII code. "
377 "The following keystrokes are available in the main editor "
378 "window. Alternative keys are shown in parentheses:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000379
Chris Allegretta908f7702003-01-15 11:18:58 +0000380 allocsize += strlen(ptr);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000381
382 /* The space needed for the shortcut lists, at most COLS characters,
383 * plus '\n'. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000384 allocsize += (COLS + 1) * length_of_list(currshortcut);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000385
386#ifndef NANO_SMALL
387 /* If we're on the main list, we also count the toggle help text.
388 * Each line has "M-%c\t\t\t", which fills 24 columns, plus at most
389 * COLS - 24 characters, plus '\n'.*/
Chris Allegretta3a784062003-02-10 02:32:58 +0000390 if (currshortcut == main_list) {
391 size_t endislen = strlen(_("enable/disable"));
392
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000393 for (t = toggles; t != NULL; t = t->next)
Chris Allegretta3a784062003-02-10 02:32:58 +0000394 allocsize += 8 + strlen(t->desc) + endislen;
395 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000396#endif /* !NANO_SMALL */
397
398 /* help_text has been freed and set to NULL unless the user resized
399 * while in the help screen. */
400 free(help_text);
401
402 /* Allocate space for the help text */
Chris Allegretta908f7702003-01-15 11:18:58 +0000403 help_text = charalloc(allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000404
405 /* Now add the text we want */
406 strcpy(help_text, ptr);
407 ptr = help_text + strlen(help_text);
408
409 /* Now add our shortcut info */
410 for (s = currshortcut; s != NULL; s = s->next) {
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000411 /* true if the character in s->metaval is shown in first column */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000412 int meta_shortcut = 0;
413
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000414 if (s->ctrlval != NANO_NO_KEY) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000415#ifndef NANO_SMALL
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000416 if (s->ctrlval == NANO_HISTORY_KEY)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000417 ptr += sprintf(ptr, "%.2s", _("Up"));
418 else
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000419#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000420 if (s->ctrlval == NANO_CONTROL_SPACE)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000421 ptr += sprintf(ptr, "^%.5s", _("Space"));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000422 else if (s->ctrlval == NANO_CONTROL_8)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000423 ptr += sprintf(ptr, "^?");
424 else
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000425 ptr += sprintf(ptr, "^%c", s->ctrlval + 64);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000426 }
427#ifndef NANO_SMALL
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000428 else if (s->metaval != NANO_NO_KEY) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000429 meta_shortcut = 1;
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000430 if (s->metaval == NANO_ALT_SPACE)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000431 ptr += snprintf(ptr, 8, "M-%.5s", _("Space"));
432 else
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000433 ptr += sprintf(ptr, "M-%c", toupper(s->metaval));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000434 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000435#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000436
437 *(ptr++) = '\t';
438
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000439 if (s->funcval != NANO_NO_KEY)
440 ptr += sprintf(ptr, "(F%d)", s->funcval - KEY_F0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000441
442 *(ptr++) = '\t';
443
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000444 if (!meta_shortcut && s->metaval != NANO_NO_KEY)
445 ptr += sprintf(ptr, "(M-%c)", toupper(s->metaval));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000446 else if (meta_shortcut && s->miscval != NANO_NO_KEY)
447 ptr += sprintf(ptr, "(M-%c)", toupper(s->miscval));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000448
449 *(ptr++) = '\t';
450
451 assert(s->help != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000452 ptr += sprintf(ptr, "%.*s\n", COLS > 24 ? COLS - 24 : 0, s->help);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000453 }
454
455#ifndef NANO_SMALL
456 /* And the toggles... */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000457 if (currshortcut == main_list) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000458 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000459 assert(t->desc != NULL);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000460 ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val), t->desc,
Chris Allegretta3a784062003-02-10 02:32:58 +0000461 _("enable/disable"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000462 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000463 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000464#endif /* !NANO_SMALL */
465
466 /* If all went well, we didn't overwrite the allocated space for
467 help_text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000468 assert(strlen(help_text) < allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000469}
470#endif
471
472/* Create a new filestruct node. Note that we specifically do not set
473 * prevnode->next equal to the new line. */
474filestruct *make_new_node(filestruct *prevnode)
475{
476 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
477
478 newnode->data = NULL;
479 newnode->prev = prevnode;
480 newnode->next = NULL;
481 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
482
483 return newnode;
484}
485
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000486/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000487filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000488{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000489 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000490
Chris Allegretta6df90f52002-07-19 01:08:59 +0000491 assert(src != NULL);
492
Chris Allegretta88b09152001-05-17 11:35:43 +0000493 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000494 dst->next = src->next;
495 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000496 strcpy(dst->data, src->data);
497 dst->lineno = src->lineno;
498
499 return dst;
500}
501
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000502/* Splice a node into an existing filestruct. */
503void splice_node(filestruct *begin, filestruct *newnode, filestruct *end)
504{
505 if (newnode != NULL) {
506 newnode->next = end;
507 newnode->prev = begin;
508 }
509 if (begin != NULL)
510 begin->next = newnode;
511 if (end != NULL)
512 end->prev = newnode;
513}
514
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000515/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000516void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000517{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000518 assert(fileptr != NULL);
519
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000520 if (fileptr->prev != NULL)
521 fileptr->prev->next = fileptr->next;
522
523 if (fileptr->next != NULL)
524 fileptr->next->prev = fileptr->prev;
525}
526
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000527/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000528void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000529{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000530 if (fileptr != NULL) {
531 if (fileptr->data != NULL)
532 free(fileptr->data);
533 free(fileptr);
534 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000535}
536
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000537/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000538filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000539{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000540 filestruct *head; /* copy of src, top of the copied list */
541 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000542
Chris Allegretta6df90f52002-07-19 01:08:59 +0000543 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000544
Chris Allegretta6df90f52002-07-19 01:08:59 +0000545 prev = copy_node(src);
546 prev->prev = NULL;
547 head = prev;
548 src = src->next;
549 while (src != NULL) {
550 prev->next = copy_node(src);
551 prev->next->prev = prev;
552 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000553
Chris Allegretta6df90f52002-07-19 01:08:59 +0000554 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000555 }
556
Chris Allegretta6df90f52002-07-19 01:08:59 +0000557 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000558 return head;
559}
560
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000561/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000562void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000563{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000564 if (src != NULL) {
565 while (src->next != NULL) {
566 src = src->next;
567 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000568#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000569 fprintf(stderr, "%s: free'd a node, YAY!\n", "delete_node()");
Chris Allegretta6df90f52002-07-19 01:08:59 +0000570#endif
571 }
572 delete_node(src);
573#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000574 fprintf(stderr, "%s: free'd last node.\n", "delete_node()");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000575#endif
576 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000577}
578
Chris Allegretta6df90f52002-07-19 01:08:59 +0000579void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000580{
581 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000582 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000583
Chris Allegretta6df90f52002-07-19 01:08:59 +0000584 assert(fileage == NULL || fileage != fileage->next);
585 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000586 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000587}
588
Chris Allegretta6df90f52002-07-19 01:08:59 +0000589void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000590{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000591 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000592 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000593 else {
594 int lineno = fileptr->prev->lineno;
595
596 assert(fileptr != fileptr->next);
597 for (; fileptr != NULL; fileptr = fileptr->next)
598 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000599 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000600}
601
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000602/* Print one usage string to the screen, removes lots of duplicate
Chris Allegretta6df90f52002-07-19 01:08:59 +0000603 * strings to translate and takes out the parts that shouldn't be
604 * translatable (the flag names). */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000605void print1opt(const char *shortflag, const char *longflag,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000606 const char *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000607{
608 printf(" %s\t", shortflag);
609 if (strlen(shortflag) < 8)
610 printf("\t");
611
612#ifdef HAVE_GETOPT_LONG
613 printf("%s\t", longflag);
614 if (strlen(longflag) < 8)
615 printf("\t\t");
616 else if (strlen(longflag) < 16)
617 printf("\t");
618#endif
619
620 printf("%s\n", desc);
621}
622
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000623void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000624{
625#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000626 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
627 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000628#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000629 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
630 printf(_("Option\t\tMeaning\n"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000631#endif /* HAVE_GETOPT_LONG */
632
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000633 print1opt("-h, -?", "--help", _("Show this message"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000634 print1opt(_("+LINE"), "", _("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000635#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +0000636 print1opt("-A", "--smarthome", _("Enable smart home key"));
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000637 print1opt("-B", "--backup", _("Backup existing files on save"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000638 print1opt("-D", "--dos", _("Write file in DOS format"));
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +0000639 print1opt("-E", "--backupdir=[dir]", _("Directory for writing backup files"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000640#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000641#ifdef ENABLE_MULTIBUFFER
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000642 print1opt("-F", "--multibuffer", _("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000643#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000644#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000645#ifndef NANO_SMALL
Chris Allegretta36fec722003-01-22 01:13:25 +0000646 print1opt("-H", "--historylog", _("Log & read search/replace string history"));
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000647#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000648 print1opt("-I", "--ignorercfiles", _("Don't look at nanorc files"));
649#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000650#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000651 print1opt("-M", "--mac", _("Write file in Mac format"));
652 print1opt("-N", "--noconvert", _("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000653#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000654#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000655 print1opt(_("-Q [str]"), _("--quotestr=[str]"), _("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000656#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000657#ifdef HAVE_REGEX_H
658 print1opt("-R", "--regexp", _("Do regular expression searches"));
659#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000660#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000661 print1opt("-S", "--smooth", _("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000662#endif
David Lawrence Ramseya7c93642004-02-25 03:19:29 +0000663 print1opt(_("-T [#cols]"), _("--tabsize=[#cols]"), _("Set width of a tab in cols to #cols"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000664 print1opt("-V", "--version", _("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000665#ifdef ENABLE_COLOR
666 print1opt(_("-Y [str]"), _("--syntax [str]"), _("Syntax definition to use"));
667#endif
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000668 print1opt(_("-Z"), _("--restricted"), _("Restricted mode"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000669 print1opt("-c", "--const", _("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000670#ifndef NANO_SMALL
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000671 print1opt("-d", "--rebinddelete", _("Fix Backspace/Delete confusion problem"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000672 print1opt("-i", "--autoindent", _("Automatically indent new lines"));
673 print1opt("-k", "--cut", _("Let ^K cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000674#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000675 print1opt("-l", "--nofollow", _("Don't follow symbolic links, overwrite"));
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000676#ifndef DISABLE_MOUSE
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000677 print1opt("-m", "--mouse", _("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000678#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000679#ifndef DISABLE_OPERATINGDIR
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000680 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), _("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000681#endif
Jordi Mallacheeb50042003-01-18 22:42:34 +0000682 print1opt("-p", "--preserve", _("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000683#ifndef DISABLE_WRAPJUSTIFY
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000684 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), _("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000685#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000686#ifndef DISABLE_SPELLER
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000687 print1opt(_("-s [prog]"), _("--speller=[prog]"), _("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000688#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000689 print1opt("-t", "--tempfile", _("Auto save on exit, don't prompt"));
690 print1opt("-v", "--view", _("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000691#ifndef DISABLE_WRAPPING
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000692 print1opt("-w", "--nowrap", _("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000693#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000694 print1opt("-x", "--nohelp", _("Don't show help window"));
695 print1opt("-z", "--suspend", _("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000696
697 /* this is a special case */
698 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000699
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000700 exit(0);
701}
702
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000703void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000704{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000705 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000706 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000707 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000708 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000709 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000710
Chris Allegrettae6600372003-01-17 03:39:41 +0000711#ifndef ENABLE_NLS
712 printf(" --disable-nls");
713#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000714#ifdef DEBUG
715 printf(" --enable-debug");
716#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000717#ifdef NANO_EXTRA
718 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000719#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000720#ifdef NANO_SMALL
721 printf(" --enable-tiny");
722#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000723#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000724 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000725#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000726#ifdef DISABLE_HELP
727 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000728#endif
729#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000730 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000731#endif
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000732#ifdef DISABLE_MOUSE
Chris Allegretta84de5522001-04-12 14:51:48 +0000733 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000734#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000735#ifdef DISABLE_OPERATINGDIR
736 printf(" --disable-operatingdir");
737#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000738#ifdef DISABLE_SPELLER
739 printf(" --disable-speller");
740#endif
741#ifdef DISABLE_TABCOMP
742 printf(" --disable-tabcomp");
743#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000744#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000745#ifdef DISABLE_WRAPPING
746 printf(" --disable-wrapping");
747#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000748#ifdef DISABLE_ROOTWRAP
749 printf(" --disable-wrapping-as-root");
750#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000751#ifdef ENABLE_COLOR
752 printf(" --enable-color");
753#endif
754#ifdef ENABLE_MULTIBUFFER
755 printf(" --enable-multibuffer");
756#endif
757#ifdef ENABLE_NANORC
758 printf(" --enable-nanorc");
759#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000760#ifdef USE_SLANG
761 printf(" --with-slang");
762#endif
763 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000764}
765
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000766int no_help(void)
767{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000768 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000769}
770
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000771int nano_disabled_msg(void)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000772{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000773 statusbar(_("Sorry, support for this function has been disabled"));
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000774 return 1;
Chris Allegrettaff269f82000-12-01 18:46:01 +0000775}
776
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000777#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000778static int pid; /* This is the PID of the newly forked process
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000779 * below. It must be global since the signal
780 * handler needs it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000781RETSIGTYPE cancel_fork(int signal)
782{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000783 if (kill(pid, SIGKILL) == -1)
784 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000785}
786
787int open_pipe(const char *command)
788{
789 int fd[2];
790 FILE *f;
791 struct sigaction oldaction, newaction;
792 /* original and temporary handlers for SIGINT */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000793 int cancel_sigs = 0;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000794 /* cancel_sigs == 1 means that sigaction() failed without changing
795 * the signal handlers. cancel_sigs == 2 means the signal handler
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000796 * was changed, but the tcsetattr() didn't succeed.
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000797 *
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000798 * I use this variable since it is important to put things back when
799 * we finish, even if we get errors. */
800
801 /* Make our pipes. */
802
803 if (pipe(fd) == -1) {
804 statusbar(_("Could not pipe"));
805 return 1;
806 }
807
808 /* Fork a child. */
809
810 if ((pid = fork()) == 0) {
811 close(fd[0]);
812 dup2(fd[1], fileno(stdout));
813 dup2(fd[1], fileno(stderr));
814 /* If execl() returns at all, there was an error. */
815
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000816 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000817 exit(0);
818 }
819
820 /* Else continue as parent. */
821
822 close(fd[1]);
823
824 if (pid == -1) {
825 close(fd[0]);
826 statusbar(_("Could not fork"));
827 return 1;
828 }
829
830 /* Before we start reading the forked command's output, we set
831 * things up so that ^C will cancel the new process. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000832
David Lawrence Ramseye608f942004-05-19 16:04:27 +0000833 /* Enable interpretation of the special control keys so that we get
834 * SIGINT when Ctrl-C is pressed. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000835 enable_signals();
836
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000837 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000838 cancel_sigs = 1;
839 nperror("sigaction");
840 } else {
841 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000842 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000843 cancel_sigs = 1;
844 nperror("sigaction");
845 }
846 }
847 /* Note that now oldaction is the previous SIGINT signal handler,
848 * to be restored later. */
849
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000850 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000851 if (f == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000852 nperror("fdopen");
853
854 read_file(f, "stdin", 0);
855 /* if multibuffer mode is on, we could be here in view mode; if so,
856 don't set the modification flag */
857 if (!ISSET(VIEW_MODE))
858 set_modified();
859
860 if (wait(NULL) == -1)
861 nperror("wait");
862
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000863 if (cancel_sigs != 1 && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000864 nperror("sigaction");
865
David Lawrence Ramseye608f942004-05-19 16:04:27 +0000866 /* Disable interpretation of the special control keys so that we can
867 * use Ctrl-C for other things. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000868 disable_signals();
869
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000870 return 0;
871}
David Lawrence Ramseya9cd41c2004-03-05 19:54:58 +0000872#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000873
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000874#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000875void do_mouse(void)
876{
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000877 int mouse_x, mouse_y;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000878
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000879 if (get_mouseinput(&mouse_x, &mouse_y, 1) == 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000880
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000881 /* Click in the edit window to move the cursor, but only when
882 we're not in a subfunction. */
883 if (wenclose(edit, mouse_y, mouse_x) && currshortcut == main_list) {
884 int sameline;
885 /* Did they click on the line with the cursor? If they
886 clicked on the cursor, we set the mark. */
887 size_t xcur;
888 /* The character they clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000889
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000890 /* Subtract out size of topwin. Perhaps we need a constant
891 somewhere? */
892 mouse_y -= 2;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000893
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000894 sameline = (mouse_y == current_y);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000895
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000896 /* Move to where the click occurred. */
897 for (; current_y < mouse_y && current->next != NULL; current_y++)
898 current = current->next;
899 for (; current_y > mouse_y && current->prev != NULL; current_y--)
900 current = current->prev;
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000901
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000902 xcur = actual_x(current->data, get_page_start(xplustabs()) +
903 mouse_x);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000904
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000905 /* Selecting where the cursor is toggles the mark. As does
906 selecting beyond the line length with the cursor at the
907 end of the line. */
908 if (sameline && xcur == current_x) {
909 if (ISSET(VIEW_MODE)) {
910 print_view_warning();
911 return;
912 }
913 do_mark();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000914 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000915
916 current_x = xcur;
917 placewewant = xplustabs();
918 edit_refresh();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000919 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000920 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000921 /* FIXME: If we clicked on a location in the statusbar, the cursor
922 should move to the location we clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000923}
924#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000925
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000926/* The user typed a character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000927void do_char(char ch)
928{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000929 size_t current_len = strlen(current->data);
930#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramsey604caf32004-04-19 02:44:13 +0000931 int refresh = FALSE;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000932 /* Do we have to run edit_refresh(), or can we get away with
933 * update_line()? */
934#endif
935
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000936 if (ch == '\0') /* Null to newline, if needed. */
937 ch = '\n';
938 else if (ch == '\n') { /* Newline to Enter, if needed. */
939 do_enter();
940 return;
941 }
942
943 assert(current != NULL && current->data != NULL);
944
945 /* When a character is inserted on the current magicline, it means
946 * we need a new one! */
David Lawrence Ramseyb9775152004-03-19 02:15:42 +0000947 if (filebot == current)
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000948 new_magicline();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000949
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000950 /* More dangerousness fun =) */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +0000951 current->data = charealloc(current->data, current_len + 2);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000952 assert(current_x <= current_len);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000953 charmove(&current->data[current_x + 1], &current->data[current_x],
954 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000955 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000956 totsize++;
957 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000958
Chris Allegretta6df90f52002-07-19 01:08:59 +0000959#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000960 /* Note that current_x has not yet been incremented. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000961 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000962 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +0000963#endif
964
Chris Allegretta6df90f52002-07-19 01:08:59 +0000965 do_right();
966
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000967#ifndef DISABLE_WRAPPING
Chris Allegrettadffa2072002-07-24 01:02:26 +0000968 if (!ISSET(NO_WRAP) && ch != '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +0000969 refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000970#endif
971
Chris Allegretta6df90f52002-07-19 01:08:59 +0000972#ifdef ENABLE_COLOR
David Lawrence Ramsey760a2dc2004-01-14 06:38:00 +0000973 if (ISSET(COLOR_SYNTAX))
David Lawrence Ramsey604caf32004-04-19 02:44:13 +0000974 refresh = TRUE;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000975#endif
976
977#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
978 if (refresh)
979 edit_refresh();
980#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000981}
982
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000983int do_verbatim_input(void)
984{
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000985 int *v_kbinput = NULL; /* Used to hold verbatim input. */
986 size_t v_len; /* Length of verbatim input. */
David Lawrence Ramsey805547f2004-04-22 03:41:04 +0000987 size_t i;
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000988
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000989 statusbar(_("Verbatim input"));
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000990
991 v_kbinput = get_verbatim_kbinput(edit, v_kbinput, &v_len, TRUE);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000992
993 /* Turn on DISABLE_CURPOS while inserting character(s) and turn it
994 * off afterwards, so that if constant cursor position display is
995 * on, it will be updated properly. */
996 SET(DISABLE_CURPOS);
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000997 for (i = 0; i < v_len; i++)
998 do_char((char)v_kbinput[i]);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000999 UNSET(DISABLE_CURPOS);
1000
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001001 free(v_kbinput);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001002
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001003 return 1;
1004}
1005
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001006int do_backspace(void)
1007{
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001008 if (current != fileage || current_x > 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001009 do_left();
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001010 do_delete();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001011 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001012 return 1;
1013}
1014
1015int do_delete(void)
1016{
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001017 assert(current != NULL && current->data != NULL && current_x <=
1018 strlen(current->data));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001019
1020 placewewant = xplustabs();
1021
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001022 if (current->data[current_x] != '\0') {
1023 size_t linelen = strlen(current->data + current_x);
1024
1025 assert(current_x < strlen(current->data));
1026
1027 /* Let's get dangerous. */
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001028 charmove(&current->data[current_x], &current->data[current_x + 1],
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001029 linelen);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001030
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001031 null_at(&current->data, linelen + current_x - 1);
1032#ifndef NANO_SMALL
1033 if (current_x < mark_beginx && mark_beginbuf == current)
1034 mark_beginx--;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001035#endif
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001036 } else if (current != filebot && (current->next != filebot ||
1037 current->data[0] == '\0')) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001038 /* We can delete the line before filebot only if it is blank: it
David Lawrence Ramsey32d19ce2004-05-24 05:05:07 +00001039 * becomes the new magicline then. */
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001040 filestruct *foo = current->next;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001041
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001042 assert(current_x == strlen(current->data));
1043 current->data = charealloc(current->data, current_x +
1044 strlen(foo->data) + 1);
1045 strcpy(current->data + current_x, foo->data);
1046#ifndef NANO_SMALL
1047 if (mark_beginbuf == current->next) {
1048 mark_beginx += current_x;
1049 mark_beginbuf = current;
1050 }
1051#endif
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001052 if (filebot == foo)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001053 filebot = current;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001054
1055 unlink_node(foo);
1056 delete_node(foo);
1057 renumber(current);
1058 totlines--;
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001059 wrap_reset();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001060 } else
1061 return 0;
1062
1063 totsize--;
1064 set_modified();
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001065 edit_refresh();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001066 return 1;
1067}
1068
1069int do_tab(void)
1070{
1071 do_char('\t');
1072 return 1;
1073}
1074
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001075/* Someone hits return *gasp!* */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001076int do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001077{
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001078 filestruct *newnode = make_new_node(current);
1079 size_t extra = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001080
Chris Allegretta6df90f52002-07-19 01:08:59 +00001081 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001082
Chris Allegrettaff989832001-09-17 13:48:00 +00001083#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001084 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001085 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001086 /* If we are breaking the line in the indentation, the new
1087 * indentation should have only current_x characters, and
1088 * current_x should not change. */
1089 extra = indent_length(current->data);
1090 if (extra > current_x)
Chris Allegrettadab017e2002-04-23 10:56:06 +00001091 extra = current_x;
Chris Allegrettadab017e2002-04-23 10:56:06 +00001092 totsize += extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001093 }
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001094#endif
1095 newnode->data = charalloc(strlen(current->data + current_x) +
1096 extra + 1);
1097 strcpy(&newnode->data[extra], current->data + current_x);
1098#ifndef NANO_SMALL
1099 if (ISSET(AUTOINDENT))
1100 strncpy(newnode->data, current->data, extra);
1101#endif
1102 null_at(&current->data, current_x);
1103#ifndef NANO_SMALL
1104 if (current == mark_beginbuf && current_x < mark_beginx) {
1105 mark_beginbuf = newnode;
1106 mark_beginx += extra - current_x;
1107 }
1108#endif
1109 current_x = extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001110
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001111 if (current == filebot)
Chris Allegrettae3167732001-03-18 16:59:34 +00001112 filebot = newnode;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001113 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001114
1115 totsize++;
1116 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001117 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001118
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001119#ifndef NANO_SMALL
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001120 /* If we're in smooth scrolling mode and we're on the last line of
1121 * the edit window, move edittop down one line so that current is
1122 * onscreen. This prevents edit_refresh() from centering the
1123 * screen. */
1124 if (ISSET(SMOOTHSCROLL) && current_y == editwinrows - 1)
1125 edittop = edittop->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001126#endif
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001127 edit_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001128
1129 totlines++;
1130 set_modified();
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001131 placewewant = xplustabs();
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001132
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001133 return 1;
1134}
1135
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001136#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001137int do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001138{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001139 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001140
Chris Allegretta6df90f52002-07-19 01:08:59 +00001141 /* Skip letters in this word first. */
1142 while (current->data[current_x] != '\0' &&
1143 isalnum((int)current->data[current_x]))
1144 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001145
Chris Allegretta6df90f52002-07-19 01:08:59 +00001146 for (; current != NULL; current = current->next) {
1147 while (current->data[current_x] != '\0' &&
1148 !isalnum((int)current->data[current_x]))
1149 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001150
Chris Allegretta6df90f52002-07-19 01:08:59 +00001151 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001152 break;
1153
Chris Allegretta6df90f52002-07-19 01:08:59 +00001154 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001155 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001156 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001157 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001158
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001159 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001160
David Lawrence Ramseybf3c93e2004-03-13 19:42:58 +00001161 /* Refresh the screen. If current has run off the bottom, this
1162 * call puts it at the center line. */
1163 edit_refresh();
1164
Chris Allegretta6232d662002-05-12 19:52:15 +00001165 return 0;
1166}
1167
Chris Allegretta6df90f52002-07-19 01:08:59 +00001168/* The same thing for backwards. */
1169int do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001170{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001171 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001172
Chris Allegretta6df90f52002-07-19 01:08:59 +00001173 /* Skip letters in this word first. */
1174 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1175 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001176
Chris Allegretta6df90f52002-07-19 01:08:59 +00001177 for (; current != NULL; current = current->prev) {
1178 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1179 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001180
Chris Allegretta6df90f52002-07-19 01:08:59 +00001181 if (current_x >= 0)
1182 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001183
Chris Allegretta6df90f52002-07-19 01:08:59 +00001184 if (current->prev != NULL)
1185 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001186 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001187
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001188 if (current == NULL) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001189 current = fileage;
1190 current_x = 0;
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001191 } else {
1192 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1193 current_x--;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001194 }
1195
Chris Allegretta76e291b2001-10-14 19:05:10 +00001196 placewewant = xplustabs();
1197
David Lawrence Ramseyb6aa4282004-03-14 01:42:17 +00001198 /* Refresh the screen. If current has run off the top, this call
1199 * puts it at the center line. */
1200 edit_refresh();
1201
Chris Allegretta6232d662002-05-12 19:52:15 +00001202 return 0;
1203}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001204
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001205int do_mark(void)
1206{
David Lawrence Ramseyf03c78b2003-09-28 21:26:49 +00001207 TOGGLE(MARK_ISSET);
1208 if (ISSET(MARK_ISSET)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001209 statusbar(_("Mark Set"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001210 mark_beginbuf = current;
1211 mark_beginx = current_x;
1212 } else {
1213 statusbar(_("Mark UNset"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001214 edit_refresh();
1215 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001216 return 1;
1217}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001218#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001219
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001220#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001221void wrap_reset(void)
1222{
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001223 same_line_wrap = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001224}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001225#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001226
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001227#ifndef DISABLE_WRAPPING
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001228/* We wrap the given line. Precondition: we assume the cursor has been
Chris Allegretta6df90f52002-07-19 01:08:59 +00001229 * moved forward since the last typed character. Return value:
1230 * whether we wrapped. */
1231int do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001232{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001233 size_t len = strlen(inptr->data); /* length of the line we wrap */
1234 int i = 0; /* generic loop variable */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001235 int wrap_loc = -1; /* index of inptr->data where we wrap */
1236 int word_back = -1;
1237#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001238 const char *indentation = NULL;
1239 /* indentation to prepend to the new line */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001240 int indent_len = 0; /* strlen(indentation) */
1241#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001242 const char *after_break; /* text after the wrap point */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001243 int after_break_len; /* strlen(after_break) */
1244 int wrapping = 0; /* do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001245 const char *wrap_line = NULL;
1246 /* the next line, minus indentation */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001247 int wrap_line_len = 0; /* strlen(wrap_line) */
1248 char *newline = NULL; /* the line we create */
1249 int new_line_len = 0; /* eventual length of newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001250
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001251/* There are three steps. First, we decide where to wrap. Then, we
1252 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001253
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001254/* Step 1, finding where to wrap. We are going to add a new-line
1255 * after a white-space character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001256 * location of this replacement.
1257 *
1258 * Where should we break the line? We need the last "legal wrap point"
1259 * such that the last word before it ended at or before fill. If there
1260 * is no such point, we settle for the first legal wrap point.
1261 *
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001262 * A "legal wrap point" is a white-space character that is not followed by
1263 * white-space.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001264 *
1265 * If there is no legal wrap point or we found the last character of the
1266 * line, we should return without wrapping.
1267 *
1268 * Note that the initial indentation does not count as a legal wrap
1269 * point if we are going to auto-indent!
1270 *
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001271 * Note that the code below could be optimised, by not calling strnlenpt()
1272 * so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001273
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001274#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001275 if (ISSET(AUTOINDENT))
1276 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001277#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001278 wrap_line = inptr->data + i;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00001279 for (; i < len; i++, wrap_line++) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001280 /* record where the last word ended */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001281 if (!isblank(*wrap_line))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001282 word_back = i;
1283 /* if we have found a "legal wrap point" and the current word
1284 * extends too far, then we stop */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001285 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001286 break;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001287 /* we record the latest "legal wrap point" */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001288 if (word_back != i && !isblank(wrap_line[1]))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001289 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001290 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001291 if (wrap_loc < 0 || i == len)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001292 return 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001293
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001294/* Step 2, making the new wrap line. It will consist of indentation +
1295 * after_break + " " + wrap_line (although indentation and wrap_line are
1296 * conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001297
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001298 /* after_break is the text that will be moved to the next line. */
1299 after_break = inptr->data + wrap_loc + 1;
1300 after_break_len = len - wrap_loc - 1;
1301 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001302
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001303 /* new_line_len will later be increased by the lengths of indentation
1304 * and wrap_line. */
1305 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001306
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001307 /* We prepend the wrapped text to the next line, if the flag is set,
1308 * and there is a next line, and prepending would not make the line
1309 * too long. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001310 if (same_line_wrap && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001311 wrap_line = inptr->next->data;
1312 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001313
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001314 /* +1 for the space between after_break and wrap_line */
1315 if ((new_line_len + 1 + wrap_line_len) <= fill) {
1316 wrapping = 1;
1317 new_line_len += (1 + wrap_line_len);
1318 }
1319 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001320
Chris Allegrettaff989832001-09-17 13:48:00 +00001321#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001322 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001323 /* Indentation comes from the next line if wrapping, else from
1324 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001325 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001326 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001327 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001328 /* The wrap_line text should not duplicate indentation.
1329 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001330 wrap_line += indent_len;
1331 else
1332 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001333 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001334#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001335
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001336 /* Now we allocate the new line and copy into it. */
1337 newline = charalloc(new_line_len + 1); /* +1 for \0 */
1338 *newline = '\0';
1339
1340#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001341 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001342 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001343 newline[indent_len] = '\0';
1344 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001345#endif
1346 strcat(newline, after_break);
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001347 /* We end the old line after wrap_loc. Note this does not eat the
Chris Allegretta81dea022002-09-21 02:19:45 +00001348 * space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001349 null_at(&inptr->data, wrap_loc + 1);
1350 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001351 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001352 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001353 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001354 * in a tab or a space, we don't add a space and decrement
1355 * totsize to account for that. */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001356 if (!isblank(newline[strlen(newline) - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001357 strcat(newline, " ");
1358 else
1359 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001360 strcat(newline, wrap_line);
1361 free(inptr->next->data);
1362 inptr->next->data = newline;
1363 } else {
1364 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001365
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001366 /* In this case, the file size changes by +1 for the new line, and
Chris Allegretta81dea022002-09-21 02:19:45 +00001367 * +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001368#ifndef NANO_SMALL
1369 totsize += indent_len;
1370#endif
1371 totlines++;
1372 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001373 temp->prev = inptr;
1374 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001375 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001376 /* If temp->next is NULL, then temp is the last line of the
1377 * file, so we must set filebot. */
1378 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001379 temp->next->prev = temp;
1380 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001381 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001382 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001383
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001384/* Step 3, clean up. Here we reposition the cursor and mark, and do some
1385 * other sundry things. */
1386
1387 /* later wraps of this line will be prepended to the next line. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001388 same_line_wrap = 1;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001389
1390 /* Each line knows its line number. We recalculate these if we
1391 * inserted a new line. */
1392 if (!wrapping)
1393 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001394
Chris Allegretta6df90f52002-07-19 01:08:59 +00001395 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001396 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001397 current = current->next;
1398 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001399#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001400 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001401#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001402 wrap_loc + 1;
1403 wrap_reset();
1404 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001405 }
1406
Chris Allegretta6df90f52002-07-19 01:08:59 +00001407#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001408 /* If the mark was on this line after the wrap point, we move it down.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001409 * If it was on the next line and we wrapped, we must move it
1410 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001411 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1412 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001413 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001414 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001415 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001416#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001417
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001418 /* Place the cursor. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001419 reset_cursor();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001420
1421 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001422}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001423#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001424
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001425#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001426/* A word is misspelled in the file. Let the user replace it. We
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001427 * return zero if the user cancels. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001428int do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001429{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001430 char *save_search;
1431 char *save_replace;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001432 filestruct *current_save = current;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001433 size_t current_x_save = current_x;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001434 filestruct *edittop_save = edittop;
1435 /* Save where we are. */
1436 int i = 0;
1437 /* The return value. */
1438 int reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001439#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001440 int case_sens_set = ISSET(CASE_SENSITIVE);
1441 int mark_set = ISSET(MARK_ISSET);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001442
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001443 SET(CASE_SENSITIVE);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001444 /* Make sure the marking highlight is off during spell-check. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001445 UNSET(MARK_ISSET);
1446#endif
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001447 /* Make sure spell-check goes forward only. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001448 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001449
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001450 /* Save the current search/replace strings. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001451 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001452 save_search = last_search;
1453 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001454
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001455 /* Set search/replace strings to misspelled word. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001456 last_search = mallocstrcpy(NULL, word);
1457 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001458
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001459 /* Start from the top of the file. */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001460 current = fileage;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001461 current_x = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001462
1463 search_last_line = FALSE;
1464
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001465 /* Find the first whole-word occurrence of word. */
1466 while (findnextstr(TRUE, TRUE, fileage, 0, word, FALSE) != 0)
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001467 if (is_whole_word(current_x, current->data, word)) {
1468 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001469
Chris Allegretta6df90f52002-07-19 01:08:59 +00001470 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001471
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001472 /* Allow the replace word to be corrected. */
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00001473 i = statusq(FALSE, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001474#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001475 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001476#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001477 _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001478
Chris Allegretta6df90f52002-07-19 01:08:59 +00001479 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001480
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001481 if (i != -1 && strcmp(word, answer)) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001482 search_last_line = FALSE;
1483 current_x--;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001484 do_replace_loop(word, current_save, &current_x_save, TRUE);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001485 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001486
1487 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001488 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001489
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001490 /* Restore the search/replace strings. */
1491 free(last_search);
1492 last_search = save_search;
1493 free(last_replace);
1494 last_replace = save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001495
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001496 /* Restore where we were. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001497 current = current_save;
1498 current_x = current_x_save;
1499 edittop = edittop_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001500
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001501 /* Restore search/replace direction. */
Chris Allegretta23b74b22002-01-21 20:32:22 +00001502 if (reverse_search_set)
1503 SET(REVERSE_SEARCH);
1504
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001505#ifndef NANO_SMALL
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001506 if (!case_sens_set)
1507 UNSET(CASE_SENSITIVE);
1508
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001509 /* Restore marking highlight. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001510 if (mark_set)
1511 SET(MARK_ISSET);
1512#endif
1513
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001514 return i != -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001515}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001516
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001517/* Integrated spell checking using 'spell' program. Return value: NULL
1518 * for normal termination, otherwise the error string. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001519const char *do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001520{
Chris Allegretta271e9722000-11-10 18:15:43 +00001521 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001522 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001523 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001524 pid_t pid_spell, pid_sort, pid_uniq;
1525 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001526
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001527 /* Create all three pipes up front. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001528 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1529 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001530
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001531 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001532
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001533 /* A new process to run spell in. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001534 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001535
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001536 /* Child continues (i.e, future spell process). */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001537
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001538 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001539
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001540 /* Replace the standard input with the temp file. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001541 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1542 goto close_pipes_and_exit;
1543
1544 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1545 goto close_pipes_and_exit;
1546
Chris Allegretta271e9722000-11-10 18:15:43 +00001547 close(tempfile_fd);
1548
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001549 /* Send spell's standard output to the pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001550 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1551 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001552
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001553 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001554
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001555 /* Start spell program; we are using PATH. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001556 execlp("spell", "spell", NULL);
1557
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001558 /* Should not be reached, if spell is found. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001559 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001560 }
1561
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001562 /* Parent continues here. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001563 close(spell_fd[1]);
1564
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001565 /* A new process to run sort in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001566 if ((pid_sort = fork()) == 0) {
1567
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001568 /* Child continues (i.e, future spell process). Replace the
1569 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001570 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1571 goto close_pipes_and_exit;
1572
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001573 close(spell_fd[0]);
1574
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001575 /* Send sort's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001576 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1577 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001578
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001579 close(sort_fd[1]);
1580
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001581 /* Start sort program. Use -f to remove mixed case without
1582 * having to have ANOTHER pipe for tr. If this isn't portable,
1583 * let me know. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001584 execlp("sort", "sort", "-f", NULL);
1585
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001586 /* Should not be reached, if sort is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001587 exit(1);
1588 }
1589
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001590 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001591 close(sort_fd[1]);
1592
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001593 /* A new process to run uniq in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001594 if ((pid_uniq = fork()) == 0) {
1595
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001596 /* Child continues (i.e, future uniq process). Replace the
1597 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001598 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1599 goto close_pipes_and_exit;
1600
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001601 close(sort_fd[0]);
1602
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001603 /* Send uniq's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001604 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1605 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001606
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001607 close(uniq_fd[1]);
1608
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001609 /* Start uniq program; we are using PATH. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001610 execlp("uniq", "uniq", NULL);
1611
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001612 /* Should not be reached, if uniq is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001613 exit(1);
1614 }
1615
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001616 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001617 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001618
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001619 /* Child process was not forked successfully. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001620 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1621 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001622 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001623 }
1624
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001625 /* Get system pipe buffer size. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001626 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1627 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001628 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001629 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001630
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001631 /* Read in the returned spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001632 read_buff_read = 0;
1633 read_buff_size = pipe_buff_size + 1;
1634 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001635
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001636 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001637 read_buff_read += bytesread;
1638 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001639 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001640 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001641
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001642 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001643
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001644 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001645 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001646
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001647 /* Process the spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001648 read_buff_word = read_buff_ptr = read_buff;
1649
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001650 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001651
1652 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001653 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001654 if (read_buff_word != read_buff_ptr) {
1655 if (!do_int_spell_fix(read_buff_word)) {
1656 read_buff_word = read_buff_ptr;
1657 break;
1658 }
1659 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001660 read_buff_word = read_buff_ptr + 1;
1661 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001662 read_buff_ptr++;
1663 }
1664
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001665 /* Special case where last word doesn't end with \n or \r. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001666 if (read_buff_word != read_buff_ptr)
1667 do_int_spell_fix(read_buff_word);
1668
Chris Allegretta271e9722000-11-10 18:15:43 +00001669 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001670 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001671 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001672
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001673 /* Process end of spell process. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001674 waitpid(pid_spell, &spell_status, 0);
1675 waitpid(pid_sort, &sort_status, 0);
1676 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001677
Chris Allegretta334a9402002-12-16 04:25:53 +00001678 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1679 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001680
Chris Allegretta334a9402002-12-16 04:25:53 +00001681 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1682 return _("Error invoking \"sort -f\"");
1683
1684 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1685 return _("Error invoking \"uniq\"");
1686
1687 /* Otherwise... */
1688 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001689
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001690 close_pipes_and_exit:
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001691
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001692 /* Don't leak any handles. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001693 close(tempfile_fd);
1694 close(spell_fd[0]);
1695 close(spell_fd[1]);
1696 close(sort_fd[0]);
1697 close(sort_fd[1]);
1698 close(uniq_fd[0]);
1699 close(uniq_fd[1]);
1700 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001701}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001702
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001703/* External spell checking. Return value: NULL for normal termination,
1704 * otherwise the error string. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001705const char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001706{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001707 int alt_spell_status, lineno_cur = current->lineno;
1708 int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001709 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001710 char *ptr;
1711 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001712 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001713#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001714 int mark_set = ISSET(MARK_ISSET);
1715 int mbb_lineno_cur = 0;
1716 /* We're going to close the current file, and open the output of
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001717 * the alternate spell command. The line that mark_beginbuf
1718 * points to will be freed, so we save the line number and
1719 * restore afterwards. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001720
1721 if (mark_set) {
1722 mbb_lineno_cur = mark_beginbuf->lineno;
1723 UNSET(MARK_ISSET);
1724 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001725#endif
1726
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001727 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001728
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001729 /* Set up an argument list to pass execvp(). */
Chris Allegrettae434b452001-01-27 19:25:00 +00001730 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001731 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001732
Chris Allegrettae434b452001-01-27 19:25:00 +00001733 spellargs[0] = strtok(alt_speller, " ");
1734 while ((ptr = strtok(NULL, " ")) != NULL) {
1735 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001736 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00001737 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001738 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001739 spellargs[arglen - 1] = NULL;
1740 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001741 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001742
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001743 /* Start a new process for the alternate speller. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001744 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001745 /* Start alternate spell program; we are using PATH. */
Chris Allegretta169ee842001-01-26 01:57:32 +00001746 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001747
1748 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001749 exit(1);
1750 }
1751
1752 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001753 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001754 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001755
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001756 /* Wait for alternate speller to complete. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001757 wait(&alt_spell_status);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001758
Chris Allegretta334a9402002-12-16 04:25:53 +00001759 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1760 char *altspell_error = NULL;
1761 char *invoke_error = _("Could not invoke \"%s\"");
1762 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1763
1764 altspell_error = charalloc(msglen);
1765 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1766 return altspell_error;
1767 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001768
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001769 refresh();
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001770#ifndef NANO_SMALL
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001771 if (!mark_set) {
1772 /* Only reload the temp file if it isn't a marked selection. */
1773#endif
1774 free_filestruct(fileage);
1775 global_init(1);
1776 open_file(tempfile_name, 0, 1);
1777#ifndef NANO_SMALL
1778 }
1779
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001780 if (mark_set) {
1781 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1782 mark_beginbuf = current;
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001783 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001784 mark_beginx = current_x;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001785 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001786 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001787#endif
1788
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001789 /* Go back to the old position, mark the file as modified, and make
1790 * sure that the titlebar is refreshed. */
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001791 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001792 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001793 clearok(topwin, FALSE);
1794 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001795
Chris Allegretta334a9402002-12-16 04:25:53 +00001796 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001797}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001798
1799int do_spell(void)
1800{
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001801 int i;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001802 char *temp = safe_tempnam(0, "nano.");
1803 const char *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001804
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001805 if (temp == NULL) {
1806 statusbar(_("Could not create temp file: %s"), strerror(errno));
Chris Allegretta271e9722000-11-10 18:15:43 +00001807 return 0;
1808 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001809
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001810#ifndef NANO_SMALL
1811 if (ISSET(MARK_ISSET))
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00001812 i = write_marked(temp, TRUE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001813 else
1814#endif
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00001815 i = write_file(temp, TRUE, FALSE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001816
1817 if (i == -1) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001818 statusbar(_("Unable to write temp file: %s"), strerror(errno));
Chris Allegrettabef12972002-03-06 03:30:40 +00001819 free(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001820 return 0;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001821 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001822
Chris Allegrettae1f14522001-09-19 03:19:43 +00001823#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001824 /* Update the current open_files entry before spell-checking, in
1825 * case any problems occur. */
Chris Allegretta48b06702002-02-22 04:30:50 +00001826 add_open_file(1);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001827#endif
1828
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001829 spell_msg = alt_speller != NULL ? do_alt_speller(temp) :
1830 do_int_speller(temp);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001831 unlink(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001832 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001833
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001834 if (spell_msg != NULL) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001835 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
1836 strerror(errno));
Chris Allegretta334a9402002-12-16 04:25:53 +00001837 return 0;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001838 } else
1839 statusbar(_("Finished checking spelling"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001840
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001841 return 1;
Chris Allegretta67105eb2000-07-03 03:18:32 +00001842}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001843#endif /* !DISABLE_SPELLER */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001844
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001845#if !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001846/* The "indentation" of a line is the white-space between the quote part
1847 * and the non-white-space of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001848size_t indent_length(const char *line)
1849{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001850 size_t len = 0;
1851
1852 assert(line != NULL);
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001853 while (isblank(*line)) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001854 line++;
1855 len++;
1856 }
1857 return len;
1858}
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001859#endif /* !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001860
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001861#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001862/* justify_format() replaces Tab by Space and multiple spaces by 1
1863 * (except it maintains 2 after a . ! or ?). Note the terminating \0
Chris Allegretta6df90f52002-07-19 01:08:59 +00001864 * counts as a space.
1865 *
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001866 * justify_format() might make line->data shorter, and change the actual
1867 * pointer with null_at().
Chris Allegretta6df90f52002-07-19 01:08:59 +00001868 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001869 * justify_format() will not look at the first skip characters of line.
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001870 * skip should be at most strlen(line->data). The character at
1871 * line[skip + 1] must not be whitespace. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001872void justify_format(filestruct *line, size_t skip)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001873{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001874 const char *punct = ".?!";
1875 const char *brackets = "'\")}]>";
Chris Allegretta6df90f52002-07-19 01:08:59 +00001876 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001877
Chris Allegretta6df90f52002-07-19 01:08:59 +00001878 /* These four asserts are assumptions about the input data. */
1879 assert(line != NULL);
1880 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00001881 assert(skip < strlen(line->data));
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001882 assert(!isblank(line->data[skip]));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001883
Chris Allegretta6df90f52002-07-19 01:08:59 +00001884 back = line->data + skip;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001885 for (front = back; ; front++) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001886 int remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001887 /* Do we want to remove this space? */
1888
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001889 if (*front == '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001890 *front = ' ';
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001891
David Lawrence Ramsey021960d2004-05-13 23:19:01 +00001892 /* These tests are safe since line->data + skip is not a
1893 * space. */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001894 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001895 const char *bob = front - 2;
1896
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001897 remove_space = TRUE;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001898 for (bob = back - 2; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001899 if (strchr(punct, *bob) != NULL) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001900 remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001901 break;
1902 }
1903 if (strchr(brackets, *bob) == NULL)
1904 break;
1905 }
1906 }
1907
1908 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001909 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001910 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001911#ifndef NANO_SMALL
1912 if (mark_beginbuf == line && back - line->data < mark_beginx)
1913 mark_beginx--;
1914#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001915 if (*front == '\0')
1916 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00001917 } else {
1918 *back = *front;
1919 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001920 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001921 if (*front == '\0')
1922 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001923 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001924
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001925 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00001926 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00001927
Chris Allegretta6df90f52002-07-19 01:08:59 +00001928 /* Now back is the new end of line->data. */
1929 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00001930 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001931 null_at(&line->data, back - line->data);
1932#ifndef NANO_SMALL
1933 if (mark_beginbuf == line && back - line->data < mark_beginx)
1934 mark_beginx = back - line->data;
1935#endif
1936 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001937}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001938
1939/* The "quote part" of a line is the largest initial substring matching
1940 * the quote string. This function returns the length of the quote part
1941 * of the given line.
1942 *
1943 * Note that if !HAVE_REGEX_H then we match concatenated copies of
1944 * quotestr. */
1945#ifdef HAVE_REGEX_H
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001946size_t quote_length(const char *line, const regex_t *qreg)
1947{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001948 regmatch_t matches;
1949 int rc = regexec(qreg, line, 1, &matches, 0);
1950
1951 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t) -1)
1952 return 0;
1953 /* matches.rm_so should be 0, since the quote string should start with
1954 * the caret ^. */
1955 return matches.rm_eo;
1956}
1957#else /* !HAVE_REGEX_H */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001958size_t quote_length(const char *line)
1959{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001960 size_t qdepth = 0;
1961 size_t qlen = strlen(quotestr);
1962
1963 /* Compute quote depth level */
1964 while (!strcmp(line + qdepth, quotestr))
1965 qdepth += qlen;
1966 return qdepth;
1967}
1968#endif /* !HAVE_REGEX_H */
1969
Chris Allegretta6df90f52002-07-19 01:08:59 +00001970/* a_line and b_line are lines of text. The quotation part of a_line is
1971 * the first a_quote characters. Check that the quotation part of
1972 * b_line is the same. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00001973int quotes_match(const char *a_line, size_t a_quote, IFREG(const char
1974 *b_line, const regex_t *qreg))
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001975{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001976 /* Here is the assumption about a_quote: */
1977 assert(a_quote == quote_length(IFREG(a_line, qreg)));
Chris Allegrettad865da12002-07-29 23:46:38 +00001978 return a_quote == quote_length(IFREG(b_line, qreg)) &&
Chris Allegretta6df90f52002-07-19 01:08:59 +00001979 !strncmp(a_line, b_line, a_quote);
1980}
1981
1982/* We assume a_line and b_line have no quote part. Then, we return whether
1983 * b_line could follow a_line in a paragraph. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00001984size_t indents_match(const char *a_line, size_t a_indent, const char
1985 *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001986{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001987 assert(a_indent == indent_length(a_line));
1988 assert(b_indent == indent_length(b_line));
1989
1990 return b_indent <= a_indent && !strncmp(a_line, b_line, b_indent);
1991}
1992
1993/* Put the next par_len lines, starting with first_line, in the cut
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001994 * buffer, not allowing them to be concatenated. We assume there are
1995 * enough lines after first_line. We leave copies of the lines in
1996 * place, too. We return the new copy of first_line. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00001997filestruct *backup_lines(filestruct *first_line, size_t par_len, size_t
1998 quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001999{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002000 /* We put the original lines, not copies, into the cutbuffer, just
2001 * out of a misguided sense of consistency, so if you uncut, you get
2002 * the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002003 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002004
2005 set_modified();
2006 cutbuffer = NULL;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002007 for (; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002008 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002009
Chris Allegretta908f7702003-01-15 11:18:58 +00002010 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002011 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002012 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002013 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002014 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002015 edittop = bob;
2016#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002017 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002018 mark_beginbuf = bob;
2019#endif
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002020 justify_format(bob, quote_len + indent_length(bob->data + quote_len));
Chris Allegretta6df90f52002-07-19 01:08:59 +00002021
Chris Allegretta908f7702003-01-15 11:18:58 +00002022 assert(alice != NULL && bob != NULL);
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002023 add_to_cutbuffer(alice, FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002024 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002025 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002026 }
2027 return first_line;
2028}
2029
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002030/* Is it possible to break line at or before goal? */
2031int breakable(const char *line, int goal)
2032{
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002033 for (; *line != '\0' && goal >= 0; line++) {
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002034 if (isblank(*line))
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002035 return TRUE;
2036
2037 if (is_cntrl_char(*line) != 0)
2038 goal -= 2;
2039 else
2040 goal -= 1;
2041 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002042 /* If goal is not negative, the whole line (one word) was short
2043 * enough. */
2044 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002045}
2046
Chris Allegretta6df90f52002-07-19 01:08:59 +00002047/* We are trying to break a chunk off line. We find the last space such
2048 * that the display length to there is at most goal + 1. If there is
2049 * no such space, and force is not 0, then we find the first space.
2050 * Anyway, we then take the last space in that group of spaces. The
2051 * terminating '\0' counts as a space. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002052int break_line(const char *line, int goal, int force)
2053{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002054 /* Note that we use int instead of size_t, since goal is at most COLS,
2055 * the screen width, which will always be reasonably small. */
2056 int space_loc = -1;
2057 /* Current tentative return value. Index of the last space we
2058 * found with short enough display width. */
2059 int cur_loc = 0;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002060 /* Current index in line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002061
2062 assert(line != NULL);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002063 for (; *line != '\0' && goal >= 0; line++, cur_loc++) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002064 if (*line == ' ')
2065 space_loc = cur_loc;
2066 assert(*line != '\t');
2067
Chris Allegrettacf287c82002-07-20 13:57:41 +00002068 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002069 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002070 else
2071 goal--;
2072 }
2073 if (goal >= 0)
2074 /* In fact, the whole line displays shorter than goal. */
2075 return cur_loc;
2076 if (space_loc == -1) {
2077 /* No space found short enough. */
2078 if (force)
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002079 for (; *line != '\0'; line++, cur_loc++)
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002080 if (*line == ' ' && *(line + 1) != ' ' && *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002081 return cur_loc;
2082 return -1;
2083 }
2084 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002085 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002086 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2087 *(line - cur_loc + space_loc + 1) == '\0')
2088 space_loc++;
2089 return space_loc;
2090}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002091
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002092/* Search a paragraph. If search_type is JUSTIFY, search for the
2093 * beginning of the current paragraph or, if we're at the end of it, the
2094 * beginning of the next paragraph. If search_type is BEGIN, search for
2095 * the beginning of the current paragraph or, if we're already there,
2096 * the beginning of the previous paragraph. If search_type is END,
2097 * search for the end of the current paragraph or, if we're already
2098 * there, the end of the next paragraph. Afterwards, save the quote
2099 * length, paragraph length, and indentation length in *quote, *par, and
2100 * *indent if they aren't NULL, and refresh the screen if do_refresh is
2101 * TRUE. Return 0 if we found a paragraph, or 1 if there was an error
2102 * or we didn't find a paragraph.
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002103 *
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002104 * To explain the searching algorithm, I first need to define some
Chris Allegretta6df90f52002-07-19 01:08:59 +00002105 * phrases about paragraphs and quotation:
2106 * A line of text consists of a "quote part", followed by an
2107 * "indentation part", followed by text. The functions quote_length()
2108 * and indent_length() calculate these parts.
2109 *
2110 * A line is "part of a paragraph" if it has a part not in the quote
2111 * part or the indentation.
2112 *
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002113 * A line is "the beginning of a paragraph" if it is part of a
2114 * paragraph and
Chris Allegretta6df90f52002-07-19 01:08:59 +00002115 * 1) it is the top line of the file, or
2116 * 2) the line above it is not part of a paragraph, or
2117 * 3) the line above it does not have precisely the same quote
2118 * part, or
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002119 * 4) the indentation of this line is not an initial substring of
2120 * the indentation of the previous line, or
Chris Allegretta6df90f52002-07-19 01:08:59 +00002121 * 5) this line has no quote part and some indentation, and
2122 * AUTOINDENT is not set.
2123 * The reason for number 5) is that if AUTOINDENT is not set, then an
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002124 * indented line is expected to start a paragraph, like in books.
2125 * Thus, nano can justify an indented paragraph only if AUTOINDENT is
2126 * turned on.
Chris Allegretta6df90f52002-07-19 01:08:59 +00002127 *
2128 * A contiguous set of lines is a "paragraph" if each line is part of
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002129 * a paragraph and only the first line is the beginning of a
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002130 * paragraph. */
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002131int do_para_search(justbegend search_type, size_t *quote, size_t *par,
2132 size_t *indent, int do_refresh)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002133{
2134 size_t quote_len;
2135 /* Length of the initial quotation of the paragraph we
2136 * search. */
2137 size_t par_len;
2138 /* Number of lines in that paragraph. */
Robert Siemborski60cd6aa2001-01-21 23:23:48 +00002139
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002140 /* We save this global variable to see if we're where we started
2141 * when searching for the beginning of the paragraph. */
2142 filestruct *current_save = current;
2143
2144 size_t indent_len; /* Generic indentation length. */
2145 filestruct *line; /* Generic line of text. */
2146
2147 static int do_restart = 1;
2148 /* Whether we're restarting when searching for the beginning
2149 * line of the paragraph. */
2150
2151#ifdef HAVE_REGEX_H
2152 regex_t qreg; /* qreg is the compiled quotation regexp. We no
2153 * longer care about quotestr. */
2154 int rc = regcomp(&qreg, quotestr, REG_EXTENDED);
2155
2156 if (rc != 0) {
2157 size_t size = regerror(rc, &qreg, NULL, 0);
2158 char *strerror = charalloc(size);
2159
2160 regerror(rc, &qreg, strerror, size);
2161 statusbar(_("Bad quote string %s: %s"), quotestr, strerror);
2162 free(strerror);
2163 return 1;
2164 }
2165#endif
2166
2167 /* Here is an assumption that is always true anyway. */
2168 assert(current != NULL);
2169
2170 current_x = 0;
2171
2172 restart_para_search:
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002173 /* Here we find the first line of the paragraph to search. If the
2174 * current line is in a paragraph, then we move back to the first
2175 * line. Otherwise, we move to the first line that is in a
2176 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002177 quote_len = quote_length(IFREG(current->data, &qreg));
2178 indent_len = indent_length(current->data + quote_len);
2179
2180 if (current->data[quote_len + indent_len] != '\0') {
2181 /* This line is part of a paragraph. So we must search back to
2182 * the first line of this paragraph. First we check items 1)
2183 * and 3) above. */
2184 while (current->prev != NULL && quotes_match(current->data,
2185 quote_len, IFREG(current->prev->data, &qreg))) {
2186 size_t temp_id_len =
2187 indent_length(current->prev->data + quote_len);
2188 /* The indentation length of the previous line. */
2189
2190 /* Is this line the beginning of a paragraph, according to
2191 * items 2), 5), or 4) above? If so, stop. */
2192 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002193 (quote_len == 0 && indent_len > 0
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002194#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002195 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002196#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002197 ) || !indents_match(current->prev->data + quote_len,
2198 temp_id_len, current->data + quote_len, indent_len))
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002199 break;
2200 indent_len = temp_id_len;
2201 current = current->prev;
2202 current_y--;
2203 }
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002204 } else if (search_type == BEGIN) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002205 /* This line is not part of a paragraph. Move up until we get
2206 * to a non "blank" line, and then move down once. */
2207 do {
2208 /* There is no previous paragraph, so nothing to move to. */
2209 if (current->prev == NULL) {
2210 placewewant = 0;
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002211 if (do_refresh)
2212 edit_refresh();
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002213#ifdef HAVE_REGEX_H
2214 if (!do_restart)
2215 regfree(&qreg);
2216#endif
2217 return 1;
2218 }
2219 current = current->prev;
2220 current_y--;
2221 quote_len = quote_length(IFREG(current->data, &qreg));
2222 indent_len = indent_length(current->data + quote_len);
2223 } while (current->data[quote_len + indent_len] == '\0');
2224 current = current->next;
2225 } else {
2226 /* This line is not part of a paragraph. Move down until we get
2227 * to a non "blank" line. */
2228 do {
2229 /* There is no next paragraph, so nothing to move to. */
2230 if (current->next == NULL) {
2231 placewewant = 0;
2232 if (do_refresh)
2233 edit_refresh();
2234#ifdef HAVE_REGEX_H
2235 regfree(&qreg);
2236#endif
2237 return 1;
2238 }
2239 current = current->next;
2240 current_y++;
2241 quote_len = quote_length(IFREG(current->data, &qreg));
2242 indent_len = indent_length(current->data + quote_len);
2243 } while (current->data[quote_len + indent_len] == '\0');
2244 }
2245
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002246 /* Now current is the first line of the paragraph, and quote_len is
2247 * the quotation length of that line. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002248
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002249 /* Next step, compute par_len, the number of lines in this
2250 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002251 line = current;
2252 par_len = 1;
2253 indent_len = indent_length(line->data + quote_len);
2254
2255 while (line->next != NULL && quotes_match(current->data, quote_len,
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002256 IFREG(line->next->data, &qreg))) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002257 size_t temp_id_len = indent_length(line->next->data + quote_len);
2258
2259 if (!indents_match(line->data + quote_len, indent_len,
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002260 line->next->data + quote_len, temp_id_len) ||
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002261 line->next->data[quote_len + temp_id_len] == '\0' ||
2262 (quote_len == 0 && temp_id_len > 0
2263#ifndef NANO_SMALL
2264 && !ISSET(AUTOINDENT)
2265#endif
2266 ))
2267 break;
2268 indent_len = temp_id_len;
2269 line = line->next;
2270 par_len++;
2271 }
2272
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002273 if (search_type == BEGIN) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002274 /* We're on the same line we started on. Move up until we get
2275 * to a non-"blank" line, restart the search from there until we
2276 * find a line that's part of a paragraph, and search once more
2277 * so that we end up at the beginning of that paragraph. */
2278 if (current != fileage && current == current_save && do_restart) {
2279 while (current->prev != NULL) {
2280 size_t i, j = 0;
2281 current = current->prev;
2282 current_y--;
2283 /* Skip over lines consisting only of spacing
2284 * characters, as searching for the end of the paragraph
2285 * does. */
2286 for (i = 0; current->data[i] != '\0'; i++) {
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002287 if (isblank(current->data[i]))
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002288 j++;
2289 else {
2290 i = 0;
2291 j = 1;
2292 break;
2293 }
2294 }
2295 if (i != j && strlen(current->data) >=
2296 (quote_len + indent_len) &&
2297 current->data[quote_len + indent_len] != '\0') {
2298 do_restart = 0;
2299 break;
2300 }
2301 }
2302 goto restart_para_search;
2303 } else
2304 do_restart = 1;
2305 }
2306
2307#ifdef HAVE_REGEX_H
2308 /* We no longer need to check quotation. */
2309 regfree(&qreg);
2310#endif
2311
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002312 /* Now par_len is the number of lines in this paragraph. We should
2313 * never call quotes_match() or quote_length() again. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002314
2315 /* If we're searching for the end of the paragraph, move down the
2316 * number of lines in the paragraph. */
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002317 if (search_type == END) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002318 for (; par_len > 0; current_y++, par_len--)
2319 current = current->next;
2320 }
2321
2322 /* Refresh the screen if needed. */
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002323 if (do_refresh)
2324 edit_refresh();
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002325
2326 /* Save the values of quote_len, par_len, and indent_len if
2327 * needed. */
2328 if (quote != NULL)
2329 *quote = quote_len;
2330 if (par != NULL)
2331 *par = par_len;
2332 if (indent != NULL)
2333 *indent = indent_len;
2334
2335 return 0;
2336}
2337
2338int do_para_begin(void)
2339{
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002340 return do_para_search(BEGIN, NULL, NULL, NULL, TRUE);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002341}
2342
2343int do_para_end(void)
2344{
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002345 return do_para_search(END, NULL, NULL, NULL, TRUE);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002346}
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002347
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002348/* If full_justify is TRUE, justify the entire file. Otherwise, justify
2349 * the current paragraph. */
2350int do_justify(int full_justify)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002351{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002352 size_t quote_len;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002353 /* Length of the initial quotation of the paragraph we
2354 * justify. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002355 size_t par_len;
2356 /* Number of lines in that paragraph. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002357 filestruct *first_par_line = NULL;
2358 /* Will be the first line of the resulting justified paragraph.
2359 * For restoring after uncut. */
David Lawrence Ramsey36e363f2004-05-17 20:38:00 +00002360 filestruct *last_par_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002361 /* Will be the last line of the result, also for uncut. */
2362 filestruct *cutbuffer_save = cutbuffer;
2363 /* When the paragraph gets modified, all lines from the changed
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002364 * one down are stored in the cutbuffer. We back up the
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002365 * original to restore it later. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002366
2367 /* We save these global variables to be restored if the user
2368 * unjustifies. Note we don't need to save totlines. */
2369 int current_x_save = current_x;
2370 int current_y_save = current_y;
2371 filestruct *current_save = current;
2372 int flags_save = flags;
2373 long totsize_save = totsize;
2374 filestruct *edittop_save = edittop;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002375#ifndef NANO_SMALL
2376 filestruct *mark_beginbuf_save = mark_beginbuf;
2377 int mark_beginx_save = mark_beginx;
2378#endif
2379
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002380 size_t indent_len; /* Generic indentation length. */
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002381 size_t i; /* Generic loop variable. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002382
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002383 /* If we're justifying the entire file, start at the beginning. */
2384 if (full_justify)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002385 current = fileage;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002386
2387 last_par_line = current;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002388
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002389 while (TRUE) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002390
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002391 /* First, search for the beginning of the current paragraph or,
2392 * if we're at the end of it, the beginning of the next
2393 * paragraph. Save the quote length, paragraph length, and
2394 * indentation length and don't refresh the screen yet (since
2395 * we'll do that after we justify). If the search failed and
2396 * we're justifying the whole file, move the last line of the
2397 * text we're justifying to just before the magicline, which is
2398 * where it'll be anyway if we've searched the entire file, and
2399 * break out of the loop; otherwise, refresh the screen and get
2400 * out. */
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002401 if (do_para_search(JUSTIFY, &quote_len, &par_len, &indent_len,
2402 FALSE) != 0) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002403 if (full_justify) {
2404 /* This should be safe in the event of filebot->prev's
2405 * being NULL, since only last_par_line->next is used if
2406 * we eventually unjustify. */
2407 last_par_line = filebot->prev;
2408 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002409 } else {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002410 edit_refresh();
2411 return 0;
2412 }
2413 }
2414
2415 /* Next step, we loop through the lines of this paragraph,
2416 * justifying each one individually. */
2417 for (; par_len > 0; current_y++, par_len--) {
2418 size_t line_len;
2419 size_t display_len;
2420 /* The width of current in screen columns. */
2421 int break_pos;
2422 /* Where we will break the line. */
2423
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002424 indent_len = quote_len + indent_length(current->data +
2425 quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002426
2427 /* justify_format() removes excess spaces from the line, and
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002428 * changes tabs to spaces. After calling it, we call
2429 * backup_lines(), which copies the original paragraph to
2430 * the cutbuffer for unjustification and then calls
2431 * justify_format() on the remaining lines. */
2432 justify_format(current, indent_len);
2433 if (first_par_line == NULL)
2434 first_par_line = backup_lines(current, full_justify ?
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002435 filebot->lineno - current->lineno : par_len, quote_len);
2436
2437 line_len = strlen(current->data);
2438 display_len = strlenpt(current->data);
2439
2440 if (display_len > fill) {
2441 /* The line is too long. Try to wrap it to the next. */
2442 break_pos = break_line(current->data + indent_len,
2443 fill - strnlenpt(current->data, indent_len), TRUE);
2444 if (break_pos == -1 || break_pos + indent_len == line_len)
2445 /* We can't break the line, or don't need to, so
2446 * just go on to the next. */
2447 goto continue_loc;
2448 break_pos += indent_len;
2449 assert(break_pos < line_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002450 if (par_len == 1) {
2451 /* There is no next line in this paragraph. We make
2452 * a new line and copy text after break_pos into
2453 * it. */
2454 splice_node(current, make_new_node(current), current->next);
2455 /* In a non-quoted paragraph, we copy the indent
2456 * only if AUTOINDENT is turned on. */
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002457 if (quote_len == 0
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002458#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002459 && !ISSET(AUTOINDENT)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002460#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002461 )
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002462 indent_len = 0;
2463 current->next->data = charalloc(indent_len + line_len -
2464 break_pos);
2465 strncpy(current->next->data, current->data, indent_len);
2466 strcpy(current->next->data + indent_len,
2467 current->data + break_pos + 1);
2468 assert(strlen(current->next->data) ==
2469 indent_len + line_len - break_pos - 1);
2470 totlines++;
2471 totsize += indent_len;
2472 par_len++;
2473 } else {
2474 size_t next_line_len = strlen(current->next->data);
2475
2476 indent_len = quote_len +
2477 indent_length(current->next->data + quote_len);
2478 current->next->data = charealloc(current->next->data,
2479 next_line_len + line_len - break_pos + 1);
2480
2481 charmove(current->next->data + indent_len + line_len -
2482 break_pos, current->next->data + indent_len,
2483 next_line_len - indent_len + 1);
2484 strcpy(current->next->data + indent_len,
2485 current->data + break_pos + 1);
2486 current->next->data[indent_len + line_len - break_pos - 1]
2487 = ' ';
2488#ifndef NANO_SMALL
2489 if (mark_beginbuf == current->next) {
2490 if (mark_beginx < indent_len)
2491 mark_beginx = indent_len;
2492 mark_beginx += line_len - break_pos;
2493 }
2494#endif
2495 }
2496#ifndef NANO_SMALL
2497 if (mark_beginbuf == current && mark_beginx > break_pos) {
2498 mark_beginbuf = current->next;
2499 mark_beginx -= break_pos + 1 - indent_len;
2500 }
2501#endif
2502 null_at(&current->data, break_pos);
2503 current = current->next;
2504 } else if (display_len < fill && par_len > 1) {
2505 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002506
2507 indent_len = quote_len +
2508 indent_length(current->next->data + quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002509 /* If we can't pull a word from the next line up to this
2510 * one, just go on. */
2511 if (!breakable(current->next->data + indent_len,
2512 fill - display_len - 1))
2513 goto continue_loc;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002514
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002515 break_pos = break_line(current->next->data + indent_len,
2516 fill - display_len - 1, FALSE);
2517 assert(break_pos != -1);
2518
2519 current->data = charealloc(current->data,
2520 line_len + break_pos + 2);
2521 current->data[line_len] = ' ';
2522 strncpy(current->data + line_len + 1,
2523 current->next->data + indent_len, break_pos);
2524 current->data[line_len + break_pos + 1] = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002525#ifndef NANO_SMALL
2526 if (mark_beginbuf == current->next) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002527 if (mark_beginx < indent_len + break_pos) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002528 mark_beginbuf = current;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002529 if (mark_beginx <= indent_len)
2530 mark_beginx = line_len + 1;
2531 else
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002532 mark_beginx = line_len + 1 + mark_beginx -
2533 indent_len;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002534 } else
2535 mark_beginx -= break_pos + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002536 }
2537#endif
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002538 next_line_len = strlen(current->next->data);
2539 if (indent_len + break_pos == next_line_len) {
2540 filestruct *line = current->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002541
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002542 /* Don't destroy edittop! */
2543 if (line == edittop)
2544 edittop = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002545
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002546 unlink_node(line);
2547 delete_node(line);
2548 totlines--;
2549 totsize -= indent_len;
2550 current_y--;
2551 } else {
2552 charmove(current->next->data + indent_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002553 current->next->data + indent_len + break_pos + 1,
2554 next_line_len - break_pos - indent_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002555 null_at(&current->next->data, next_line_len - break_pos);
2556 current = current->next;
2557 }
2558 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002559 continue_loc:
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002560 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002561 current = current->next;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002562
2563 /* If the line we were on before still exists, and it was
2564 * not the last line of the paragraph, add a space to the
David Lawrence Ramsey684e7eb2004-05-20 14:31:15 +00002565 * end of it to replace the one removed or left out by
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002566 * justify_format(). */
2567 if (current->prev != NULL && par_len > 1) {
2568 size_t prev_line_len = strlen(current->prev->data);
2569 current->prev->data = charealloc(current->prev->data,
2570 prev_line_len + 2);
2571 current->prev->data[prev_line_len] = ' ';
2572 current->prev->data[prev_line_len + 1] = '\0';
2573 totsize++;
2574 }
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002575 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002576
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002577 /* We've just justified a paragraph. If we're not justifying the
2578 * entire file, break out of the loop. Otherwise, continue the
2579 * loop so that we justify all the paragraphs in the file. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002580 if (!full_justify)
2581 break;
2582
2583 } /* while (TRUE) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002584
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002585 /* We are now done justifying the paragraph or the file, so clean
2586 * up. totlines, totsize, and current_y have been maintained above.
2587 * Set last_par_line to the new end of the paragraph, update
2588 * fileage, and set current_x. Also, edit_refresh() needs the line
2589 * numbers to be right, so renumber(). */
2590 last_par_line = current->prev;
2591 if (first_par_line->prev == NULL)
2592 fileage = first_par_line;
2593 renumber(first_par_line);
2594
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002595 edit_refresh();
Chris Allegretta6df90f52002-07-19 01:08:59 +00002596
Chris Allegretta9149e612000-11-27 00:23:41 +00002597 statusbar(_("Can now UnJustify!"));
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002598 /* Display the shortcut list with UnJustify. */
Chris Allegretta07798352000-11-27 22:58:23 +00002599 shortcut_init(1);
2600 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002601 reset_cursor();
2602
Chris Allegretta6df90f52002-07-19 01:08:59 +00002603 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002604 * keystroke and return. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002605 {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002606 int meta_key;
2607 i = get_kbinput(edit, &meta_key);
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002608#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002609 /* If it was a mouse click, parse it with do_mouse() and it
2610 * might become the unjustify key. Else give it back to the
2611 * input stream. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002612 if (i == KEY_MOUSE) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002613 do_mouse();
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002614 i = get_kbinput(edit, &meta_key);
2615 }
Chris Allegretta5f071802001-05-06 02:34:31 +00002616#endif
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002617 }
Chris Allegretta5f071802001-05-06 02:34:31 +00002618
David Lawrence Ramseyc91696e2004-01-29 04:16:23 +00002619 if (i != NANO_UNJUSTIFY_KEY && i != NANO_UNJUSTIFY_FKEY) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002620 ungetch(i);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002621 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002622 } else {
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002623 /* Else restore the justify we just did (ungrateful user!). */
2624 filestruct *cutbottom = get_cutbottom();
2625
Chris Allegretta6df90f52002-07-19 01:08:59 +00002626 current = current_save;
2627 current_x = current_x_save;
2628 current_y = current_y_save;
2629 edittop = edittop_save;
Chris Allegrettad022eac2000-11-27 02:50:49 +00002630
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002631 /* Splice the cutbuffer back into the file. */
2632 cutbottom->next = last_par_line->next;
2633 cutbottom->next->prev = cutbottom;
2634 /* The line numbers after the end of the paragraph have been
2635 * changed, so we change them back. */
2636 renumber(cutbottom->next);
2637 if (first_par_line->prev != NULL) {
2638 cutbuffer->prev = first_par_line->prev;
2639 cutbuffer->prev->next = cutbuffer;
2640 } else
2641 fileage = cutbuffer;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002642
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002643 last_par_line->next = NULL;
2644 free_filestruct(first_par_line);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002645
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002646 /* Restore global variables from before the justify. */
2647 totsize = totsize_save;
2648 totlines = filebot->lineno;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002649#ifndef NANO_SMALL
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002650 mark_beginbuf = mark_beginbuf_save;
2651 mark_beginx = mark_beginx_save;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002652#endif
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002653 flags = flags_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002654 if (!ISSET(MODIFIED))
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002655 titlebar(NULL);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002656 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002657 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002658 cutbuffer = cutbuffer_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002659 /* Note that now cutbottom is invalid, but that's okay. */
2660 blank_statusbar();
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002661 /* Display the shortcut list with UnCut. */
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002662 shortcut_init(0);
2663 display_main_list();
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002664
Chris Allegretta6df90f52002-07-19 01:08:59 +00002665 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002666}
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002667
2668int do_justify_void(void)
2669{
2670 return do_justify(FALSE);
2671}
2672
2673int do_full_justify(void)
2674{
2675 return do_justify(TRUE);
2676}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00002677#endif /* !DISABLE_JUSTIFY */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002678
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002679int do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002680{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002681 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002682
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002683 if (!ISSET(MODIFIED)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002684
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002685#ifdef ENABLE_MULTIBUFFER
2686 if (!close_open_file()) {
2687 display_main_list();
2688 return 1;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002689 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002690 else
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002691#endif
David Lawrence Ramseyda141062004-05-25 19:41:11 +00002692 finish();
Chris Allegretta756f2202000-09-01 13:32:47 +00002693 }
2694
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002695 if (ISSET(TEMP_OPT))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002696 i = 1;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002697 else
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002698 i = do_yesno(FALSE, _("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002699
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002700#ifdef DEBUG
2701 dump_buffer(fileage);
2702#endif
2703
2704 if (i == 1) {
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002705 if (do_writeout(TRUE) > 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002706
2707#ifdef ENABLE_MULTIBUFFER
2708 if (!close_open_file()) {
2709 display_main_list();
2710 return 1;
2711 }
2712 else
2713#endif
David Lawrence Ramseyda141062004-05-25 19:41:11 +00002714 finish();
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002715 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002716 } else if (i == 0) {
2717
2718#ifdef ENABLE_MULTIBUFFER
2719 if (!close_open_file()) {
2720 display_main_list();
2721 return 1;
2722 }
2723 else
2724#endif
David Lawrence Ramseyda141062004-05-25 19:41:11 +00002725 finish();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002726 } else
2727 statusbar(_("Cancelled"));
2728
2729 display_main_list();
2730 return 1;
2731}
2732
2733void signal_init(void)
2734{
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002735 /* Trap SIGINT and SIGQUIT because we want them to do useful
2736 * things. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002737 memset(&act, 0, sizeof(struct sigaction));
2738 act.sa_handler = SIG_IGN;
2739 sigaction(SIGINT, &act, NULL);
David Lawrence Ramsey2897d2b2004-01-26 20:56:20 +00002740 sigaction(SIGQUIT, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002741
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002742 /* Trap SIGHUP and SIGTERM because we want to write the file out. */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002743 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002744 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002745 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002746
2747#ifndef NANO_SMALL
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002748 /* Trap SIGWINCH because we want to handle window resizes. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002749 act.sa_handler = handle_sigwinch;
2750 sigaction(SIGWINCH, &act, NULL);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002751 allow_pending_sigwinch(FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002752#endif
2753
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002754 /* Trap normal suspend (^Z) so we can handle it ourselves. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002755 if (!ISSET(SUSPEND)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002756 act.sa_handler = SIG_IGN;
2757 sigaction(SIGTSTP, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002758 } else {
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002759 /* Block all other signals in the suspend and continue handlers.
2760 * If we don't do this, other stuff interrupts them! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002761 sigfillset(&act.sa_mask);
2762
2763 act.sa_handler = do_suspend;
2764 sigaction(SIGTSTP, &act, NULL);
2765
2766 act.sa_handler = do_cont;
2767 sigaction(SIGCONT, &act, NULL);
2768 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002769}
2770
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002771/* Handler for SIGHUP (hangup) and SIGTERM (terminate). */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002772RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002773{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002774 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002775}
2776
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002777/* Handler for SIGTSTP (suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002778RETSIGTYPE do_suspend(int signal)
2779{
2780 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00002781 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002782 fflush(stdout);
2783
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002784 /* Restore the old terminal settings. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002785 tcsetattr(0, TCSANOW, &oldterm);
2786
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002787 /* Trap SIGHUP and SIGTERM so we can properly deal with them while
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002788 * suspended. */
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002789 act.sa_handler = handle_hupterm;
2790 sigaction(SIGHUP, &act, NULL);
2791 sigaction(SIGTERM, &act, NULL);
2792
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002793 /* Do what mutt does: send ourselves a SIGSTOP. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002794 kill(0, SIGSTOP);
2795}
2796
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002797/* Handler for SIGCONT (continue after suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002798RETSIGTYPE do_cont(int signal)
2799{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002800#ifndef NANO_SMALL
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002801 /* Perhaps the user resized the window while we slept. Handle it
2802 * and update the screen in the process. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002803 handle_sigwinch(0);
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002804#else
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002805 /* Just update the screen. */
2806 doupdate();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002807#endif
2808}
2809
2810#ifndef NANO_SMALL
2811void handle_sigwinch(int s)
2812{
2813 const char *tty = ttyname(0);
2814 int fd;
2815 int result = 0;
2816 struct winsize win;
2817
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002818 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002819 return;
2820 fd = open(tty, O_RDWR);
2821 if (fd == -1)
2822 return;
2823 result = ioctl(fd, TIOCGWINSZ, &win);
2824 close(fd);
2825 if (result == -1)
2826 return;
2827
2828 /* Could check whether the COLS or LINES changed, and return
2829 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2830 * variables, and in some cases ncurses has already updated them.
2831 * But not in all cases, argh. */
2832 COLS = win.ws_col;
2833 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002834 editwinrows = LINES - 5 + no_help();
2835 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002836 die_too_small();
2837
2838#ifndef DISABLE_WRAPJUSTIFY
2839 fill = wrap_at;
2840 if (fill <= 0)
2841 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002842 if (fill < 0)
2843 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002844#endif
2845
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002846 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002847 memset(hblank, ' ', COLS);
2848 hblank[COLS] = '\0';
2849
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002850#ifdef USE_SLANG
2851 /* Slang curses emulation brain damage, part 1: If we just do what
2852 * curses does here, it'll only work properly if the resize made the
2853 * window smaller. Do what mutt does: Leave and immediately reenter
2854 * Slang screen management mode. */
2855 SLsmg_reset_smg();
2856 SLsmg_init_smg();
2857#else
2858 /* Do the equivalent of what Minimum Profit does: Leave and
2859 * immediately reenter curses mode. */
2860 endwin();
2861 refresh();
2862#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002863
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002864 /* Do the equivalent of what both mutt and Minimum Profit do:
2865 * Reinitialize all the windows based on the new screen
2866 * dimensions. */
2867 window_init();
2868
2869 /* Redraw the contents of the windows that need it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002870 blank_statusbar();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002871 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002872 total_refresh();
2873
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002874 /* Turn cursor back on for sure. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002875 curs_set(1);
2876
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002877 /* Restore the terminal to its previously saved state. */
2878 resetty();
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002879
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00002880 /* Reset all the input routines that rely on character sequences. */
2881 reset_kbinput();
2882
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002883 /* Jump back to the main loop. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002884 siglongjmp(jmpbuf, 1);
2885}
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002886
2887void allow_pending_sigwinch(int allow)
2888{
2889 sigset_t winch;
2890 sigemptyset(&winch);
2891 sigaddset(&winch, SIGWINCH);
2892 if (allow)
2893 sigprocmask(SIG_UNBLOCK, &winch, NULL);
2894 else
2895 sigprocmask(SIG_BLOCK, &winch, NULL);
2896}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002897#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002898
Chris Allegrettadab017e2002-04-23 10:56:06 +00002899#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002900void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002901{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002902 int enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002903
Chris Allegretta658399a2001-06-14 02:54:22 +00002904 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002905 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002906
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002907 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002908 case TOGGLE_SUSPEND_KEY:
2909 signal_init();
2910 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002911#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00002912 case TOGGLE_MOUSE_KEY:
2913 mouse_init();
2914 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002915#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002916 case TOGGLE_NOHELP_KEY:
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002917 blank_statusbar();
2918 blank_bottombars();
Chris Allegretta2a42af12000-09-12 23:02:49 +00002919 wrefresh(bottomwin);
2920 window_init();
2921 edit_refresh();
2922 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00002923 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00002924 case TOGGLE_DOS_KEY:
2925 UNSET(MAC_FILE);
2926 break;
2927 case TOGGLE_MAC_KEY:
2928 UNSET(DOS_FILE);
2929 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002930#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00002931 case TOGGLE_SYNTAX_KEY:
2932 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002933 break;
2934#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002935 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00002936
Chris Allegretta6df90f52002-07-19 01:08:59 +00002937 /* We are assuming here that shortcut_init() above didn't free and
2938 * reallocate the toggles. */
2939 enabled = ISSET(which->flag);
2940 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
2941 enabled = !enabled;
2942 statusbar("%s %s", which->desc,
2943 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00002944}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002945#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00002946
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002947void disable_signals(void)
2948{
2949 struct termios term;
2950
2951 tcgetattr(0, &term);
2952 term.c_lflag &= ~ISIG;
2953 tcsetattr(0, TCSANOW, &term);
2954}
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002955
2956#ifndef NANO_SMALL
2957void enable_signals(void)
2958{
2959 struct termios term;
2960
2961 tcgetattr(0, &term);
2962 term.c_lflag |= ISIG;
2963 tcsetattr(0, TCSANOW, &term);
2964}
2965#endif
2966
2967void disable_flow_control(void)
2968{
2969 struct termios term;
2970
2971 tcgetattr(0, &term);
2972 term.c_iflag &= ~(IXON|IXOFF);
2973 tcsetattr(0, TCSANOW, &term);
2974}
2975
2976void enable_flow_control(void)
2977{
2978 struct termios term;
2979
2980 tcgetattr(0, &term);
2981 term.c_iflag |= (IXON|IXOFF);
2982 tcsetattr(0, TCSANOW, &term);
2983}
2984
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002985int main(int argc, char *argv[])
2986{
2987 int optchr;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00002988 int startline = 0; /* Line to try and start at */
Chris Allegrettafe1d0722003-02-13 00:52:49 +00002989 int modify_control_seq = 0;
Chris Allegretta09fc4302003-01-16 22:16:38 +00002990 int fill_flag_used = 0; /* Was the fill option used? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002991 const shortcut *s;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00002992 int keyhandled = 0; /* Have we handled the keystroke yet? */
David Lawrence Ramseyf8ddf312004-01-09 22:38:09 +00002993 int kbinput; /* Input from keyboard */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002994 int meta_key;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00002995
Chris Allegretta40ecbad2002-03-06 15:27:44 +00002996#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00002997 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00002998#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002999#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003000 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003001 {"help", 0, 0, 'h'},
3002#ifdef ENABLE_MULTIBUFFER
3003 {"multibuffer", 0, 0, 'F'},
3004#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003005#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003006#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003007 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003008#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003009 {"ignorercfiles", 0, 0, 'I'},
3010#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003011#ifndef DISABLE_JUSTIFY
3012 {"quotestr", 1, 0, 'Q'},
3013#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003014#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003015 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003016#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003017 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003018 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003019#ifdef ENABLE_COLOR
3020 {"syntax", 1, 0, 'Y'},
3021#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003022 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003023 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003024 {"nofollow", 0, 0, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003025#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003026 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003027#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003028#ifndef DISABLE_OPERATINGDIR
3029 {"operatingdir", 1, 0, 'o'},
3030#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003031 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003032#ifndef DISABLE_WRAPJUSTIFY
3033 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003034#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003035#ifndef DISABLE_SPELLER
3036 {"speller", 1, 0, 's'},
3037#endif
3038 {"tempfile", 0, 0, 't'},
3039 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003040#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003041 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003042#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003043 {"nohelp", 0, 0, 'x'},
3044 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003045#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003046 {"smarthome", 0, 0, 'A'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003047 {"backup", 0, 0, 'B'},
3048 {"dos", 0, 0, 'D'},
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003049 {"backupdir", 1, 0, 'E'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003050 {"mac", 0, 0, 'M'},
3051 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003052 {"smooth", 0, 0, 'S'},
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003053 {"restricted", 0, 0, 'Z'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003054 {"autoindent", 0, 0, 'i'},
3055 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003056#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003057 {0, 0, 0, 0}
3058 };
3059#endif
3060
Chris Allegretta8bc03b62001-02-09 02:57:52 +00003061#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003062 setlocale(LC_ALL, "");
3063 bindtextdomain(PACKAGE, LOCALEDIR);
3064 textdomain(PACKAGE);
3065#endif
3066
Chris Allegretta7662c862003-01-13 01:35:15 +00003067#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003068 /* if we don't have rcfile support, we're root, and
3069 --disable-wrapping-as-root is used, turn wrapping off */
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003070 if (geteuid() == NANO_ROOT_UID)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003071 SET(NO_WRAP);
3072#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003073
3074#ifdef HAVE_GETOPT_LONG
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003075 while ((optchr = getopt_long(argc, argv, "h?ABDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz",
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00003076 long_options, NULL)) != -1) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00003077#else
3078 while ((optchr =
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003079 getopt(argc, argv, "h?ABDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz")) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003080#endif
3081
3082 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003083
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003084 case 'a':
3085 case 'b':
3086 case 'e':
3087 case 'f':
3088 case 'g':
3089 case 'j':
3090 /* Pico compatibility flags */
3091 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003092#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003093 case 'A':
3094 SET(SMART_HOME);
3095 break;
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003096 case 'B':
3097 SET(BACKUP_FILE);
3098 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003099 case 'D':
3100 SET(DOS_FILE);
3101 break;
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003102 case 'E':
3103 backup_dir = mallocstrcpy(backup_dir, optarg);
3104 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003105#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003106#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003107 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003108 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003109 break;
3110#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003111#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003112#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003113 case 'H':
3114 SET(HISTORYLOG);
3115 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003116#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003117 case 'I':
Chris Allegretta7662c862003-01-13 01:35:15 +00003118 SET(NO_RCFILE);
3119 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003120#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003121#ifndef NANO_SMALL
3122 case 'M':
3123 SET(MAC_FILE);
3124 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003125 case 'N':
3126 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003127 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003128#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003129#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003130 case 'Q':
Chris Allegretta7662c862003-01-13 01:35:15 +00003131 quotestr = mallocstrcpy(quotestr, optarg);
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003132 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003133#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003134#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003135 case 'R':
3136 SET(USE_REGEXP);
3137 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003138#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003139#ifndef NANO_SMALL
3140 case 'S':
3141 SET(SMOOTHSCROLL);
3142 break;
3143#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003144 case 'T':
Chris Allegretta6df90f52002-07-19 01:08:59 +00003145 {
3146 int i;
3147 char *first_error;
3148
Chris Allegretta7662c862003-01-13 01:35:15 +00003149 /* Using strtol() instead of atoi() lets us accept 0
3150 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003151 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003152 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003153 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003154 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003155 tabsize = i;
3156 if (tabsize <= 0) {
3157 fprintf(stderr, _("Tab size is too small for nano...\n"));
3158 exit(1);
3159 }
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003160 }
3161 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003162 case 'V':
3163 version();
3164 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003165#ifdef ENABLE_COLOR
3166 case 'Y':
3167 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3168 break;
3169#endif
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003170 case 'Z':
3171 SET(RESTRICTED);
3172 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003173 case 'c':
3174 SET(CONSTUPDATE);
3175 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003176 case 'd':
3177 SET(REBIND_DELETE);
3178 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003179#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003180 case 'i':
3181 SET(AUTOINDENT);
3182 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003183 case 'k':
3184 SET(CUT_TO_END);
3185 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003186#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003187 case 'l':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003188 SET(NOFOLLOW_SYMLINKS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003189 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003190#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003191 case 'm':
3192 SET(USE_MOUSE);
3193 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003194#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003195#ifndef DISABLE_OPERATINGDIR
3196 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003197 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003198 break;
3199#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003200 case 'p':
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003201 SET(PRESERVE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003202 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003203#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003204 case 'r':
3205 {
3206 int i;
3207 char *first_error;
3208
Chris Allegretta7662c862003-01-13 01:35:15 +00003209 /* Using strtol() instead of atoi() lets us accept 0
3210 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003211 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003212 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003213 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003214 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003215 wrap_at = i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003216 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003217 fill_flag_used = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003218 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003219#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003220#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003221 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003222 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003223 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003224#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003225 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00003226 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003227 break;
3228 case 'v':
3229 SET(VIEW_MODE);
3230 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003231#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003232 case 'w':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003233 SET(NO_WRAP);
3234 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003235#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003236 case 'x':
3237 SET(NO_HELP);
3238 break;
3239 case 'z':
3240 SET(SUSPEND);
3241 break;
3242 default:
3243 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003244 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003245 }
3246
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003247 /* If filename starts with 'r', we use restricted mode. */
3248 if (*(tail(argv[0])) == 'r')
3249 SET(RESTRICTED);
3250
3251 /* If we're using restricted mode, disable suspending, backup files,
3252 * and reading rcfiles. */
3253 if (ISSET(RESTRICTED)) {
3254 UNSET(SUSPEND);
3255 UNSET(BACKUP_FILE);
3256 SET(NO_RCFILE);
3257 }
3258
Chris Allegretta7662c862003-01-13 01:35:15 +00003259/* We've read through the command line options. Now back up the flags
3260 and values that are set, and read the rcfile(s). If the values
3261 haven't changed afterward, restore the backed-up values. */
3262#ifdef ENABLE_NANORC
3263 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003264#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003265 char *operating_dir_cpy = operating_dir;
3266#endif
3267#ifndef DISABLE_WRAPPING
3268 int wrap_at_cpy = wrap_at;
3269#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003270#ifndef NANO_SMALL
3271 char *backup_dir_cpy = backup_dir;
3272#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003273#ifndef DISABLE_JUSTIFY
3274 char *quotestr_cpy = quotestr;
3275#endif
3276#ifndef DISABLE_SPELLER
3277 char *alt_speller_cpy = alt_speller;
3278#endif
3279 int tabsize_cpy = tabsize;
3280 long flags_cpy = flags;
3281
Chris Allegretta5ec68622003-02-05 02:39:34 +00003282#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003283 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003284#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003285#ifndef NANO_SMALL
3286 backup_dir = NULL;
3287#endif
Chris Allegretta5ec68622003-02-05 02:39:34 +00003288#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003289 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003290#endif
3291#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003292 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003293#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003294
3295 do_rcfile();
3296
3297#ifndef DISABLE_OPERATINGDIR
3298 if (operating_dir_cpy != NULL) {
3299 free(operating_dir);
3300 operating_dir = operating_dir_cpy;
3301 }
3302#endif
3303#ifndef DISABLE_WRAPPING
3304 if (fill_flag_used)
3305 wrap_at = wrap_at_cpy;
3306#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003307#ifndef NANO_SMALL
3308 if (backup_dir_cpy != NULL) {
3309 free(backup_dir);
3310 backup_dir = backup_dir_cpy;
3311 }
3312#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003313#ifndef DISABLE_JUSTIFY
3314 if (quotestr_cpy != NULL) {
3315 free(quotestr);
3316 quotestr = quotestr_cpy;
3317 }
3318#endif
3319#ifndef DISABLE_SPELLER
3320 if (alt_speller_cpy != NULL) {
3321 free(alt_speller);
3322 alt_speller = alt_speller_cpy;
3323 }
3324#endif
3325 if (tabsize_cpy > 0)
3326 tabsize = tabsize_cpy;
3327 flags |= flags_cpy;
3328 }
3329#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003330 else if (geteuid() == NANO_ROOT_UID)
Chris Allegretta7662c862003-01-13 01:35:15 +00003331 SET(NO_WRAP);
3332#endif
3333#endif /* ENABLE_NANORC */
3334
Chris Allegrettad8451932003-03-11 03:50:40 +00003335#ifndef NANO_SMALL
3336 history_init();
3337#ifdef ENABLE_NANORC
3338 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3339 load_history();
3340#endif
3341#endif
3342
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003343#ifndef NANO_SMALL
3344 /* Set up the backup directory. This entails making sure it exists
3345 * and is a directory, so that backup files will be saved there. */
3346 init_backup_dir();
3347#endif
3348
Chris Allegretta7662c862003-01-13 01:35:15 +00003349#ifndef DISABLE_OPERATINGDIR
3350 /* Set up the operating directory. This entails chdir()ing there,
3351 so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003352 init_operating_dir();
3353#endif
3354
Chris Allegretta7662c862003-01-13 01:35:15 +00003355#ifndef DISABLE_JUSTIFY
3356 if (quotestr == NULL)
3357#ifdef HAVE_REGEX_H
3358 quotestr = mallocstrcpy(NULL, "^([ \t]*[|>:}#])+");
3359#else
3360 quotestr = mallocstrcpy(NULL, "> ");
3361#endif
3362#endif /* !DISABLE_JUSTIFY */
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003363
Chris Allegretta7662c862003-01-13 01:35:15 +00003364 if (tabsize == -1)
3365 tabsize = 8;
3366
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003367 /* Clear the filename we'll be using */
3368 filename = charalloc(1);
3369 filename[0] = '\0';
3370
Chris Allegretta7662c862003-01-13 01:35:15 +00003371 /* If there's a +LINE flag, it is the first non-option argument. */
3372 if (0 < optind && optind < argc && argv[optind][0] == '+') {
3373 startline = atoi(&argv[optind][1]);
3374 optind++;
3375 }
3376 if (0 < optind && optind < argc)
3377 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003378
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003379 /* See if there's a non-option in argv (first non-option is the
3380 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003381 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003382 /* Look for the +line flag... */
3383 if (argv[optind][0] == '+') {
3384 startline = atoi(&argv[optind][1]);
3385 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003386 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003387 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003388 } else
3389 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003390 }
3391
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003392 /* Back up the old terminal settings so that they can be restored. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003393 tcgetattr(0, &oldterm);
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003394
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003395 /* Curses initialization stuff: Start curses, save the state of the
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003396 * terminal mode, put the terminal in cbreak mode (read one character
3397 * at a time and interpret the special control keys), disable
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003398 * translation of carriage return (^M) into newline (^J) so that we
David Lawrence Ramseyfd462b12004-05-19 15:41:17 +00003399 * can tell the difference between the Enter key and Ctrl-J, and
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003400 * disable echoing of characters as they're typed. Finally, disable
3401 * interpretation of the special control keys, and if we're not in
3402 * preserve mode, disable interpretation of the flow control
3403 * characters too. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003404 initscr();
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003405 cbreak();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003406 nonl();
David Lawrence Ramseyd03216a2004-01-28 18:21:21 +00003407 noecho();
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003408 disable_signals();
3409 if (!ISSET(PRESERVE))
3410 disable_flow_control();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003411
3412#ifndef NANO_SMALL
3413 /* Save the terminal's current state, so that we can restore it
3414 * after a resize. */
3415 savetty();
3416#endif
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003417
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003418 /* Set up the global variables and the shortcuts. */
Chris Allegretta56214c62001-09-27 02:46:53 +00003419 global_init(0);
Chris Allegretta07798352000-11-27 22:58:23 +00003420 shortcut_init(0);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003421
3422 /* Set up the signal handlers. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003423 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003424
3425#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003426 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003427#endif
3428
Chris Allegretta2a42af12000-09-12 23:02:49 +00003429 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003430#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003431 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003432#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003433
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003434#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003435 fprintf(stderr, "Main: bottom win\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003436#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003437 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003438 display_main_list();
3439
3440#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003441 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003442#endif
3443
David Lawrence Ramsey97133f52004-05-14 17:39:19 +00003444 open_file(filename, 0, 0);
Chris Allegretta7662c862003-01-13 01:35:15 +00003445#ifdef ENABLE_MULTIBUFFER
3446 /* If we're using multibuffers and more than one file is specified
3447 on the command line, load them all and switch to the first one
3448 afterward */
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003449 if (optind + 1 < argc) {
3450 int old_multibuffer = ISSET(MULTIBUFFER);
3451 SET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003452 for (optind++; optind < argc; optind++) {
3453 add_open_file(1);
3454 new_file();
3455 filename = mallocstrcpy(filename, argv[optind]);
3456 open_file(filename, 0, 0);
3457 load_file(0);
3458 }
3459 open_nextfile_void();
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003460 if (!old_multibuffer)
3461 UNSET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003462 }
3463#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003464
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003465 titlebar(NULL);
3466
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003467 if (startline > 0)
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003468 do_gotoline(startline, 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003469
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003470#ifndef NANO_SMALL
3471 /* Return here after a SIGWINCH. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003472 sigsetjmp(jmpbuf, 1);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003473#endif
Chris Allegretta08020882001-01-29 23:37:54 +00003474
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003475 /* SHUT UP GCC! */
3476 startline = 0;
3477 fill_flag_used = 0;
3478 keyhandled = 0;
3479
Chris Allegretta7662c862003-01-13 01:35:15 +00003480 /* This variable should be initialized after the sigsetjmp(), so we
3481 can't do Esc-Esc then quickly resize and muck things up. */
Chris Allegretta08020882001-01-29 23:37:54 +00003482 modify_control_seq = 0;
3483
Robert Siemborski6967eec2000-07-08 14:23:32 +00003484 edit_refresh();
3485 reset_cursor();
3486
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00003487 while (TRUE) {
Chris Allegrettad0845df2003-02-13 00:56:57 +00003488 keyhandled = 0;
Chris Allegretta9239d742000-09-06 15:19:18 +00003489
Chris Allegrettad26ab912003-01-28 01:16:47 +00003490 if (ISSET(CONSTUPDATE))
3491 do_cursorpos(1);
3492
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003493#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003494 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003495#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003496
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003497 kbinput = get_kbinput(edit, &meta_key);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003498#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003499 fprintf(stderr, "AHA! %c (%d)\n", kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003500#endif
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003501 if (meta_key == TRUE) {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003502 /* Check for the metaval and miscval defs... */
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003503 for (s = main_list; s != NULL; s = s->next)
David Lawrence Ramsey82138502003-12-24 08:03:54 +00003504 if ((s->metaval != NANO_NO_KEY && kbinput == s->metaval) ||
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003505 (s->miscval != NANO_NO_KEY && kbinput == s->miscval)) {
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003506 if (ISSET(VIEW_MODE) && !s->viewok)
3507 print_view_warning();
3508 else {
3509 if (s->func != do_cut_text)
3510 UNSET(KEEP_CUTBUFFER);
3511 s->func();
3512 }
3513 keyhandled = 1;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003514 }
3515#ifndef NANO_SMALL
3516 if (!keyhandled)
3517 /* And for toggle switches */
3518 for (t = toggles; t != NULL; t = t->next)
3519 if (kbinput == t->val) {
3520 UNSET(KEEP_CUTBUFFER);
3521 do_toggle(t);
3522 keyhandled = 1;
3523 }
3524#endif
3525#ifdef DEBUG
3526 fprintf(stderr, "I got Alt-%c! (%d)\n", kbinput,
3527 kbinput);
3528#endif
3529 }
3530
3531 /* Look through the main shortcut list to see if we've hit a
3532 shortcut key or function key */
3533
3534 if (!keyhandled)
3535#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || !defined(DISABLE_MOUSE)
3536 for (s = currshortcut; s != NULL && !keyhandled; s = s->next) {
3537#else
3538 for (s = main_list; s != NULL && !keyhandled; s = s->next) {
3539#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003540 if ((s->ctrlval != NANO_NO_KEY && kbinput == s->ctrlval) ||
3541 (s->funcval != NANO_NO_KEY && kbinput == s->funcval)) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003542 if (ISSET(VIEW_MODE) && !s->viewok)
3543 print_view_warning();
3544 else {
3545 if (s->func != do_cut_text)
3546 UNSET(KEEP_CUTBUFFER);
3547 s->func();
3548 }
3549 keyhandled = 1;
3550 /* Break out explicitly once we successfully handle
3551 a shortcut */
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003552 break;
3553 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003554 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003555
3556 if (!keyhandled)
3557 UNSET(KEEP_CUTBUFFER);
Chris Allegrettae42df732002-10-15 00:27:55 +00003558
Chris Allegrettae42df732002-10-15 00:27:55 +00003559 /* Don't even think about changing this string */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003560 if (kbinput == NANO_CONTROL_Q)
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003561 statusbar(_("XON ignored, mumble mumble."));
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003562 if (kbinput == NANO_CONTROL_S)
3563 statusbar(_("XOFF ignored, mumble mumble."));
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003564
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003565 /* If we're in raw mode or using Alt-Alt-x, we have to catch
3566 Control-S and Control-Q */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003567 if (kbinput == NANO_CONTROL_Q || kbinput == NANO_CONTROL_S)
Chris Allegretta9239d742000-09-06 15:19:18 +00003568 keyhandled = 1;
3569
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003570 /* Catch ^Z by hand when triggered also */
3571 if (kbinput == NANO_SUSPEND_KEY) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003572 if (ISSET(SUSPEND))
3573 do_suspend(0);
3574 keyhandled = 1;
3575 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003576
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003577 /* Last gasp, stuff that's not in the main lists */
3578 if (!keyhandled)
3579 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003580#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003581 case KEY_MOUSE:
3582 do_mouse();
3583 break;
3584#endif
Chris Allegrettaad3f4782001-10-02 03:54:13 +00003585
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003586 case NANO_CONTROL_3: /* Ctrl-[ (Esc), which should
3587 * have been handled before we
3588 * got here */
3589 case NANO_CONTROL_5: /* Ctrl-] */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003590 break;
3591 default:
3592#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003593 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003594#endif
3595 /* We no longer stop unhandled sequences so that people with
3596 odd character sets can type... */
3597
Chris Allegretta7662c862003-01-13 01:35:15 +00003598 if (ISSET(VIEW_MODE))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003599 print_view_warning();
Chris Allegretta7662c862003-01-13 01:35:15 +00003600 else
3601 do_char(kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003602 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003603
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003604 reset_cursor();
3605 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003606 }
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003607 assert(FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003608}