blob: 35e42603a8230c2c4672e1f5d44fe08799f31853 [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')
175 i = write_file(ret, 1, 0, 0);
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 Ramseyee383db2004-02-06 03:07:10 +0000985 int *verbatim_kbinput; /* Used to hold verbatim input. */
David Lawrence Ramsey805547f2004-04-22 03:41:04 +0000986 size_t verbatim_len; /* Length of verbatim input. */
987 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 Ramseyf4276942003-12-24 03:33:09 +0000990 verbatim_kbinput = get_verbatim_kbinput(edit, &verbatim_len, 1);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000991
992 /* Turn on DISABLE_CURPOS while inserting character(s) and turn it
993 * off afterwards, so that if constant cursor position display is
994 * on, it will be updated properly. */
995 SET(DISABLE_CURPOS);
996 for (i = 0; i < verbatim_len; i++)
David Lawrence Ramsey815cba82004-02-07 03:07:01 +0000997 do_char((char)verbatim_kbinput[i]);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000998 UNSET(DISABLE_CURPOS);
999
1000 free(verbatim_kbinput);
1001
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001002 return 1;
1003}
1004
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001005int do_backspace(void)
1006{
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001007 if (current != fileage || current_x > 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001008 do_left();
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001009 do_delete();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001010 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001011 return 1;
1012}
1013
1014int do_delete(void)
1015{
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001016 assert(current != NULL && current->data != NULL && current_x <=
1017 strlen(current->data));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001018
1019 placewewant = xplustabs();
1020
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001021 if (current->data[current_x] != '\0') {
1022 size_t linelen = strlen(current->data + current_x);
1023
1024 assert(current_x < strlen(current->data));
1025
1026 /* Let's get dangerous. */
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001027 charmove(&current->data[current_x], &current->data[current_x + 1],
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001028 linelen);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001029
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001030 null_at(&current->data, linelen + current_x - 1);
1031#ifndef NANO_SMALL
1032 if (current_x < mark_beginx && mark_beginbuf == current)
1033 mark_beginx--;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001034#endif
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001035 } else if (current != filebot && (current->next != filebot ||
1036 current->data[0] == '\0')) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001037 /* We can delete the line before filebot only if it is blank: it
David Lawrence Ramsey32d19ce2004-05-24 05:05:07 +00001038 * becomes the new magicline then. */
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001039 filestruct *foo = current->next;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001040
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001041 assert(current_x == strlen(current->data));
1042 current->data = charealloc(current->data, current_x +
1043 strlen(foo->data) + 1);
1044 strcpy(current->data + current_x, foo->data);
1045#ifndef NANO_SMALL
1046 if (mark_beginbuf == current->next) {
1047 mark_beginx += current_x;
1048 mark_beginbuf = current;
1049 }
1050#endif
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001051 if (filebot == foo)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001052 filebot = current;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001053
1054 unlink_node(foo);
1055 delete_node(foo);
1056 renumber(current);
1057 totlines--;
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001058 wrap_reset();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001059 } else
1060 return 0;
1061
1062 totsize--;
1063 set_modified();
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001064 edit_refresh();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001065 return 1;
1066}
1067
1068int do_tab(void)
1069{
1070 do_char('\t');
1071 return 1;
1072}
1073
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001074/* Someone hits return *gasp!* */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001075int do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001076{
Chris Allegrettae3167732001-03-18 16:59:34 +00001077 filestruct *newnode;
Chris Allegretta68532c32001-09-17 13:49:33 +00001078 char *tmp;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001079
Chris Allegretta6df90f52002-07-19 01:08:59 +00001080 newnode = make_new_node(current);
1081 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001082 tmp = &current->data[current_x];
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001083
Chris Allegrettaff989832001-09-17 13:48:00 +00001084#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001085 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001086 if (ISSET(AUTOINDENT)) {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001087 int extra = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001088 const char *spc = current->data;
1089
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001090 while (isblank(*spc)) {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001091 extra++;
1092 spc++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001093 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001094 /* If current_x < extra, then we are breaking the line in the
1095 * indentation. Autoindenting should add only current_x
1096 * characters of indentation. */
Chris Allegrettadab017e2002-04-23 10:56:06 +00001097 if (current_x < extra)
1098 extra = current_x;
1099 else
1100 current_x = extra;
1101 totsize += extra;
1102
1103 newnode->data = charalloc(strlen(tmp) + extra + 1);
1104 strncpy(newnode->data, current->data, extra);
1105 strcpy(&newnode->data[extra], tmp);
Chris Allegrettaff989832001-09-17 13:48:00 +00001106 } else
1107#endif
1108 {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001109 current_x = 0;
Chris Allegretta88b09152001-05-17 11:35:43 +00001110 newnode->data = charalloc(strlen(tmp) + 1);
Chris Allegrettae3167732001-03-18 16:59:34 +00001111 strcpy(newnode->data, tmp);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001112 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001113 *tmp = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001114
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001115 if (current->next == NULL)
Chris Allegrettae3167732001-03-18 16:59:34 +00001116 filebot = newnode;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001117 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001118
1119 totsize++;
1120 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001121 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001122 align(&current->data);
1123
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001124 /* The logic here is as follows:
1125 * -> If we are at the bottom of the buffer, we want to recenter
Chris Allegretta88520c92001-05-05 17:45:54 +00001126 * (read: rebuild) the screen and forcibly move the cursor.
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001127 * -> otherwise, we want simply to redraw the screen and update
1128 * where we think the cursor is.
1129 */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001130 if (current_y == editwinrows - 1) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001131#ifndef NANO_SMALL
1132 if (ISSET(SMOOTHSCROLL))
1133 edit_update(current, NONE);
1134 else
1135#endif
1136 edit_update(current, CENTER);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001137 reset_cursor();
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001138 } else {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001139 current_y++;
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001140 edit_refresh();
1141 update_cursor();
1142 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001143
1144 totlines++;
1145 set_modified();
1146
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001147 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001148 return 1;
1149}
1150
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001151#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001152int do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001153{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001154 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001155
Chris Allegretta6df90f52002-07-19 01:08:59 +00001156 /* Skip letters in this word first. */
1157 while (current->data[current_x] != '\0' &&
1158 isalnum((int)current->data[current_x]))
1159 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001160
Chris Allegretta6df90f52002-07-19 01:08:59 +00001161 for (; current != NULL; current = current->next) {
1162 while (current->data[current_x] != '\0' &&
1163 !isalnum((int)current->data[current_x]))
1164 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001165
Chris Allegretta6df90f52002-07-19 01:08:59 +00001166 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001167 break;
1168
Chris Allegretta6df90f52002-07-19 01:08:59 +00001169 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001170 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001171 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001172 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001173
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001174 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001175
David Lawrence Ramseybf3c93e2004-03-13 19:42:58 +00001176 /* Refresh the screen. If current has run off the bottom, this
1177 * call puts it at the center line. */
1178 edit_refresh();
1179
Chris Allegretta6232d662002-05-12 19:52:15 +00001180 return 0;
1181}
1182
Chris Allegretta6df90f52002-07-19 01:08:59 +00001183/* The same thing for backwards. */
1184int do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001185{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001186 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001187
Chris Allegretta6df90f52002-07-19 01:08:59 +00001188 /* Skip letters in this word first. */
1189 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1190 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001191
Chris Allegretta6df90f52002-07-19 01:08:59 +00001192 for (; current != NULL; current = current->prev) {
1193 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1194 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001195
Chris Allegretta6df90f52002-07-19 01:08:59 +00001196 if (current_x >= 0)
1197 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001198
Chris Allegretta6df90f52002-07-19 01:08:59 +00001199 if (current->prev != NULL)
1200 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001201 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001202
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001203 if (current == NULL) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001204 current = fileage;
1205 current_x = 0;
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001206 } else {
1207 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1208 current_x--;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001209 }
1210
Chris Allegretta76e291b2001-10-14 19:05:10 +00001211 placewewant = xplustabs();
1212
David Lawrence Ramseyb6aa4282004-03-14 01:42:17 +00001213 /* Refresh the screen. If current has run off the top, this call
1214 * puts it at the center line. */
1215 edit_refresh();
1216
Chris Allegretta6232d662002-05-12 19:52:15 +00001217 return 0;
1218}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001219
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001220int do_mark(void)
1221{
David Lawrence Ramseyf03c78b2003-09-28 21:26:49 +00001222 TOGGLE(MARK_ISSET);
1223 if (ISSET(MARK_ISSET)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001224 statusbar(_("Mark Set"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001225 mark_beginbuf = current;
1226 mark_beginx = current_x;
1227 } else {
1228 statusbar(_("Mark UNset"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001229 edit_refresh();
1230 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001231 return 1;
1232}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001233#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001234
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001235#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001236void wrap_reset(void)
1237{
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001238 same_line_wrap = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001239}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001240#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001241
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001242#ifndef DISABLE_WRAPPING
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001243/* We wrap the given line. Precondition: we assume the cursor has been
Chris Allegretta6df90f52002-07-19 01:08:59 +00001244 * moved forward since the last typed character. Return value:
1245 * whether we wrapped. */
1246int do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001247{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001248 size_t len = strlen(inptr->data); /* length of the line we wrap */
1249 int i = 0; /* generic loop variable */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001250 int wrap_loc = -1; /* index of inptr->data where we wrap */
1251 int word_back = -1;
1252#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001253 const char *indentation = NULL;
1254 /* indentation to prepend to the new line */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001255 int indent_len = 0; /* strlen(indentation) */
1256#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001257 const char *after_break; /* text after the wrap point */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001258 int after_break_len; /* strlen(after_break) */
1259 int wrapping = 0; /* do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001260 const char *wrap_line = NULL;
1261 /* the next line, minus indentation */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001262 int wrap_line_len = 0; /* strlen(wrap_line) */
1263 char *newline = NULL; /* the line we create */
1264 int new_line_len = 0; /* eventual length of newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001265
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001266/* There are three steps. First, we decide where to wrap. Then, we
1267 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001268
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001269/* Step 1, finding where to wrap. We are going to add a new-line
1270 * after a white-space character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001271 * location of this replacement.
1272 *
1273 * Where should we break the line? We need the last "legal wrap point"
1274 * such that the last word before it ended at or before fill. If there
1275 * is no such point, we settle for the first legal wrap point.
1276 *
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001277 * A "legal wrap point" is a white-space character that is not followed by
1278 * white-space.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001279 *
1280 * If there is no legal wrap point or we found the last character of the
1281 * line, we should return without wrapping.
1282 *
1283 * Note that the initial indentation does not count as a legal wrap
1284 * point if we are going to auto-indent!
1285 *
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001286 * Note that the code below could be optimised, by not calling strnlenpt()
1287 * so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001288
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001289#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001290 if (ISSET(AUTOINDENT))
1291 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001292#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001293 wrap_line = inptr->data + i;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00001294 for (; i < len; i++, wrap_line++) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001295 /* record where the last word ended */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001296 if (!isblank(*wrap_line))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001297 word_back = i;
1298 /* if we have found a "legal wrap point" and the current word
1299 * extends too far, then we stop */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001300 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001301 break;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001302 /* we record the latest "legal wrap point" */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001303 if (word_back != i && !isblank(wrap_line[1]))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001304 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001305 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001306 if (wrap_loc < 0 || i == len)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001307 return 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001308
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001309/* Step 2, making the new wrap line. It will consist of indentation +
1310 * after_break + " " + wrap_line (although indentation and wrap_line are
1311 * conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001312
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001313 /* after_break is the text that will be moved to the next line. */
1314 after_break = inptr->data + wrap_loc + 1;
1315 after_break_len = len - wrap_loc - 1;
1316 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001317
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001318 /* new_line_len will later be increased by the lengths of indentation
1319 * and wrap_line. */
1320 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001321
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001322 /* We prepend the wrapped text to the next line, if the flag is set,
1323 * and there is a next line, and prepending would not make the line
1324 * too long. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001325 if (same_line_wrap && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001326 wrap_line = inptr->next->data;
1327 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001328
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001329 /* +1 for the space between after_break and wrap_line */
1330 if ((new_line_len + 1 + wrap_line_len) <= fill) {
1331 wrapping = 1;
1332 new_line_len += (1 + wrap_line_len);
1333 }
1334 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001335
Chris Allegrettaff989832001-09-17 13:48:00 +00001336#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001337 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001338 /* Indentation comes from the next line if wrapping, else from
1339 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001340 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001341 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001342 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001343 /* The wrap_line text should not duplicate indentation.
1344 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001345 wrap_line += indent_len;
1346 else
1347 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001348 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001349#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001350
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001351 /* Now we allocate the new line and copy into it. */
1352 newline = charalloc(new_line_len + 1); /* +1 for \0 */
1353 *newline = '\0';
1354
1355#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001356 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001357 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001358 newline[indent_len] = '\0';
1359 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001360#endif
1361 strcat(newline, after_break);
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001362 /* We end the old line after wrap_loc. Note this does not eat the
Chris Allegretta81dea022002-09-21 02:19:45 +00001363 * space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001364 null_at(&inptr->data, wrap_loc + 1);
1365 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001366 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001367 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001368 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001369 * in a tab or a space, we don't add a space and decrement
1370 * totsize to account for that. */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001371 if (!isblank(newline[strlen(newline) - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001372 strcat(newline, " ");
1373 else
1374 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001375 strcat(newline, wrap_line);
1376 free(inptr->next->data);
1377 inptr->next->data = newline;
1378 } else {
1379 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001380
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001381 /* In this case, the file size changes by +1 for the new line, and
Chris Allegretta81dea022002-09-21 02:19:45 +00001382 * +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001383#ifndef NANO_SMALL
1384 totsize += indent_len;
1385#endif
1386 totlines++;
1387 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001388 temp->prev = inptr;
1389 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001390 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001391 /* If temp->next is NULL, then temp is the last line of the
1392 * file, so we must set filebot. */
1393 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001394 temp->next->prev = temp;
1395 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001396 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001397 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001398
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001399/* Step 3, clean up. Here we reposition the cursor and mark, and do some
1400 * other sundry things. */
1401
1402 /* later wraps of this line will be prepended to the next line. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001403 same_line_wrap = 1;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001404
1405 /* Each line knows its line number. We recalculate these if we
1406 * inserted a new line. */
1407 if (!wrapping)
1408 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001409
Chris Allegretta6df90f52002-07-19 01:08:59 +00001410 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001411 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001412 current = current->next;
1413 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001414#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001415 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001416#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001417 wrap_loc + 1;
1418 wrap_reset();
1419 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001420 }
1421
Chris Allegretta6df90f52002-07-19 01:08:59 +00001422#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001423 /* If the mark was on this line after the wrap point, we move it down.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001424 * If it was on the next line and we wrapped, we must move it
1425 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001426 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1427 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001428 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001429 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001430 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001431#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001432
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001433 /* Place the cursor. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001434 reset_cursor();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001435
1436 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001437}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001438#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001439
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001440#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001441/* A word is misspelled in the file. Let the user replace it. We
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001442 * return zero if the user cancels. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001443int do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001444{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001445 char *save_search;
1446 char *save_replace;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001447 filestruct *current_save = current;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001448 size_t current_x_save = current_x;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001449 filestruct *edittop_save = edittop;
1450 /* Save where we are. */
1451 int i = 0;
1452 /* The return value. */
1453 int reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001454#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001455 int case_sens_set = ISSET(CASE_SENSITIVE);
1456 int mark_set = ISSET(MARK_ISSET);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001457
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001458 SET(CASE_SENSITIVE);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001459 /* Make sure the marking highlight is off during spell-check. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001460 UNSET(MARK_ISSET);
1461#endif
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001462 /* Make sure spell-check goes forward only. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001463 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001464
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001465 /* Save the current search/replace strings. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001466 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001467 save_search = last_search;
1468 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001469
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001470 /* Set search/replace strings to misspelled word. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001471 last_search = mallocstrcpy(NULL, word);
1472 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001473
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001474 /* Start from the top of the file. */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001475 current = fileage;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001476 current_x = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001477
1478 search_last_line = FALSE;
1479
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001480 /* Find the first whole-word occurrence of word. */
1481 while (findnextstr(TRUE, TRUE, fileage, 0, word, FALSE) != 0)
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001482 if (is_whole_word(current_x, current->data, word)) {
1483 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001484
Chris Allegretta6df90f52002-07-19 01:08:59 +00001485 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001486
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001487 /* Allow the replace word to be corrected. */
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00001488 i = statusq(FALSE, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001489#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001490 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001491#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001492 _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001493
Chris Allegretta6df90f52002-07-19 01:08:59 +00001494 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001495
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001496 if (i != -1 && strcmp(word, answer)) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001497 search_last_line = FALSE;
1498 current_x--;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001499 do_replace_loop(word, current_save, &current_x_save, TRUE);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001500 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001501
1502 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001503 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001504
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001505 /* Restore the search/replace strings. */
1506 free(last_search);
1507 last_search = save_search;
1508 free(last_replace);
1509 last_replace = save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001510
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001511 /* Restore where we were. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001512 current = current_save;
1513 current_x = current_x_save;
1514 edittop = edittop_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001515
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001516 /* Restore search/replace direction. */
Chris Allegretta23b74b22002-01-21 20:32:22 +00001517 if (reverse_search_set)
1518 SET(REVERSE_SEARCH);
1519
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001520#ifndef NANO_SMALL
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001521 if (!case_sens_set)
1522 UNSET(CASE_SENSITIVE);
1523
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001524 /* Restore marking highlight. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001525 if (mark_set)
1526 SET(MARK_ISSET);
1527#endif
1528
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001529 return i != -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001530}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001531
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001532/* Integrated spell checking using 'spell' program. Return value: NULL
1533 * for normal termination, otherwise the error string. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001534const char *do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001535{
Chris Allegretta271e9722000-11-10 18:15:43 +00001536 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001537 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001538 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001539 pid_t pid_spell, pid_sort, pid_uniq;
1540 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001541
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001542 /* Create all three pipes up front. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001543 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1544 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001545
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001546 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001547
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001548 /* A new process to run spell in. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001549 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001550
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001551 /* Child continues (i.e, future spell process). */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001552
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001553 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001554
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001555 /* Replace the standard input with the temp file. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001556 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1557 goto close_pipes_and_exit;
1558
1559 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1560 goto close_pipes_and_exit;
1561
Chris Allegretta271e9722000-11-10 18:15:43 +00001562 close(tempfile_fd);
1563
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001564 /* Send spell's standard output to the pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001565 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1566 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001567
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001568 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001569
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001570 /* Start spell program; we are using PATH. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001571 execlp("spell", "spell", NULL);
1572
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001573 /* Should not be reached, if spell is found. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001574 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001575 }
1576
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001577 /* Parent continues here. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001578 close(spell_fd[1]);
1579
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001580 /* A new process to run sort in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001581 if ((pid_sort = fork()) == 0) {
1582
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001583 /* Child continues (i.e, future spell process). Replace the
1584 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001585 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1586 goto close_pipes_and_exit;
1587
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001588 close(spell_fd[0]);
1589
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001590 /* Send sort's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001591 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1592 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001593
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001594 close(sort_fd[1]);
1595
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001596 /* Start sort program. Use -f to remove mixed case without
1597 * having to have ANOTHER pipe for tr. If this isn't portable,
1598 * let me know. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001599 execlp("sort", "sort", "-f", NULL);
1600
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001601 /* Should not be reached, if sort is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001602 exit(1);
1603 }
1604
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001605 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001606 close(sort_fd[1]);
1607
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001608 /* A new process to run uniq in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001609 if ((pid_uniq = fork()) == 0) {
1610
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001611 /* Child continues (i.e, future uniq process). Replace the
1612 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001613 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1614 goto close_pipes_and_exit;
1615
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001616 close(sort_fd[0]);
1617
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001618 /* Send uniq's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001619 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1620 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001621
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001622 close(uniq_fd[1]);
1623
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001624 /* Start uniq program; we are using PATH. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001625 execlp("uniq", "uniq", NULL);
1626
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001627 /* Should not be reached, if uniq is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001628 exit(1);
1629 }
1630
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001631 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001632 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001633
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001634 /* Child process was not forked successfully. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001635 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1636 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001637 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001638 }
1639
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001640 /* Get system pipe buffer size. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001641 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1642 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001643 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001644 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001645
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001646 /* Read in the returned spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001647 read_buff_read = 0;
1648 read_buff_size = pipe_buff_size + 1;
1649 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001650
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001651 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001652 read_buff_read += bytesread;
1653 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001654 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001655 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001656
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001657 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001658
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001659 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001660 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001661
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001662 /* Process the spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001663 read_buff_word = read_buff_ptr = read_buff;
1664
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001665 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001666
1667 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001668 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001669 if (read_buff_word != read_buff_ptr) {
1670 if (!do_int_spell_fix(read_buff_word)) {
1671 read_buff_word = read_buff_ptr;
1672 break;
1673 }
1674 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001675 read_buff_word = read_buff_ptr + 1;
1676 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001677 read_buff_ptr++;
1678 }
1679
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001680 /* Special case where last word doesn't end with \n or \r. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001681 if (read_buff_word != read_buff_ptr)
1682 do_int_spell_fix(read_buff_word);
1683
Chris Allegretta271e9722000-11-10 18:15:43 +00001684 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001685 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001686 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001687
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001688 /* Process end of spell process. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001689 waitpid(pid_spell, &spell_status, 0);
1690 waitpid(pid_sort, &sort_status, 0);
1691 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001692
Chris Allegretta334a9402002-12-16 04:25:53 +00001693 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1694 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001695
Chris Allegretta334a9402002-12-16 04:25:53 +00001696 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1697 return _("Error invoking \"sort -f\"");
1698
1699 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1700 return _("Error invoking \"uniq\"");
1701
1702 /* Otherwise... */
1703 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001704
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001705 close_pipes_and_exit:
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001706
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001707 /* Don't leak any handles. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001708 close(tempfile_fd);
1709 close(spell_fd[0]);
1710 close(spell_fd[1]);
1711 close(sort_fd[0]);
1712 close(sort_fd[1]);
1713 close(uniq_fd[0]);
1714 close(uniq_fd[1]);
1715 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001716}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001717
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001718/* External spell checking. Return value: NULL for normal termination,
1719 * otherwise the error string. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001720const char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001721{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001722 int alt_spell_status, lineno_cur = current->lineno;
1723 int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001724 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001725 char *ptr;
1726 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001727 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001728#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001729 int mark_set = ISSET(MARK_ISSET);
1730 int mbb_lineno_cur = 0;
1731 /* We're going to close the current file, and open the output of
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001732 * the alternate spell command. The line that mark_beginbuf
1733 * points to will be freed, so we save the line number and
1734 * restore afterwards. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001735
1736 if (mark_set) {
1737 mbb_lineno_cur = mark_beginbuf->lineno;
1738 UNSET(MARK_ISSET);
1739 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001740#endif
1741
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001742 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001743
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001744 /* Set up an argument list to pass execvp(). */
Chris Allegrettae434b452001-01-27 19:25:00 +00001745 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001746 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001747
Chris Allegrettae434b452001-01-27 19:25:00 +00001748 spellargs[0] = strtok(alt_speller, " ");
1749 while ((ptr = strtok(NULL, " ")) != NULL) {
1750 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001751 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00001752 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001753 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001754 spellargs[arglen - 1] = NULL;
1755 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001756 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001757
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001758 /* Start a new process for the alternate speller. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001759 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001760 /* Start alternate spell program; we are using PATH. */
Chris Allegretta169ee842001-01-26 01:57:32 +00001761 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001762
1763 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001764 exit(1);
1765 }
1766
1767 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001768 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001769 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001770
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001771 /* Wait for alternate speller to complete. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001772 wait(&alt_spell_status);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001773
Chris Allegretta334a9402002-12-16 04:25:53 +00001774 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1775 char *altspell_error = NULL;
1776 char *invoke_error = _("Could not invoke \"%s\"");
1777 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1778
1779 altspell_error = charalloc(msglen);
1780 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1781 return altspell_error;
1782 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001783
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001784 refresh();
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001785#ifndef NANO_SMALL
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001786 if (!mark_set) {
1787 /* Only reload the temp file if it isn't a marked selection. */
1788#endif
1789 free_filestruct(fileage);
1790 global_init(1);
1791 open_file(tempfile_name, 0, 1);
1792#ifndef NANO_SMALL
1793 }
1794
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001795 if (mark_set) {
1796 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1797 mark_beginbuf = current;
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001798 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001799 mark_beginx = current_x;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001800 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001801 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001802#endif
1803
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001804 /* Go back to the old position, mark the file as modified, and make
1805 * sure that the titlebar is refreshed. */
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001806 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001807 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001808 clearok(topwin, FALSE);
1809 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001810
Chris Allegretta334a9402002-12-16 04:25:53 +00001811 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001812}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001813
1814int do_spell(void)
1815{
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001816 int i;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001817 char *temp = safe_tempnam(0, "nano.");
1818 const char *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001819
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001820 if (temp == NULL) {
1821 statusbar(_("Could not create temp file: %s"), strerror(errno));
Chris Allegretta271e9722000-11-10 18:15:43 +00001822 return 0;
1823 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001824
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001825#ifndef NANO_SMALL
1826 if (ISSET(MARK_ISSET))
1827 i = write_marked(temp, 1, 0, 0);
1828 else
1829#endif
1830 i = write_file(temp, 1, 0, 0);
1831
1832 if (i == -1) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001833 statusbar(_("Unable to write temp file: %s"), strerror(errno));
Chris Allegrettabef12972002-03-06 03:30:40 +00001834 free(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001835 return 0;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001836 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001837
Chris Allegrettae1f14522001-09-19 03:19:43 +00001838#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001839 /* Update the current open_files entry before spell-checking, in
1840 * case any problems occur. */
Chris Allegretta48b06702002-02-22 04:30:50 +00001841 add_open_file(1);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001842#endif
1843
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001844 spell_msg = alt_speller != NULL ? do_alt_speller(temp) :
1845 do_int_speller(temp);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001846 unlink(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001847 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001848
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001849 if (spell_msg != NULL) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001850 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
1851 strerror(errno));
Chris Allegretta334a9402002-12-16 04:25:53 +00001852 return 0;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001853 } else
1854 statusbar(_("Finished checking spelling"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001855
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001856 return 1;
Chris Allegretta67105eb2000-07-03 03:18:32 +00001857}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001858#endif /* !DISABLE_SPELLER */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001859
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001860#if !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001861/* The "indentation" of a line is the white-space between the quote part
1862 * and the non-white-space of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001863size_t indent_length(const char *line)
1864{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001865 size_t len = 0;
1866
1867 assert(line != NULL);
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001868 while (isblank(*line)) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001869 line++;
1870 len++;
1871 }
1872 return len;
1873}
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001874#endif /* !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001875
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001876#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001877/* justify_format() replaces Tab by Space and multiple spaces by 1
1878 * (except it maintains 2 after a . ! or ?). Note the terminating \0
Chris Allegretta6df90f52002-07-19 01:08:59 +00001879 * counts as a space.
1880 *
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001881 * justify_format() might make line->data shorter, and change the actual
1882 * pointer with null_at().
Chris Allegretta6df90f52002-07-19 01:08:59 +00001883 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001884 * justify_format() will not look at the first skip characters of line.
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001885 * skip should be at most strlen(line->data). The character at
1886 * line[skip + 1] must not be whitespace. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001887void justify_format(filestruct *line, size_t skip)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001888{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001889 const char *punct = ".?!";
1890 const char *brackets = "'\")}]>";
Chris Allegretta6df90f52002-07-19 01:08:59 +00001891 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001892
Chris Allegretta6df90f52002-07-19 01:08:59 +00001893 /* These four asserts are assumptions about the input data. */
1894 assert(line != NULL);
1895 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00001896 assert(skip < strlen(line->data));
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001897 assert(!isblank(line->data[skip]));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001898
Chris Allegretta6df90f52002-07-19 01:08:59 +00001899 back = line->data + skip;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001900 for (front = back; ; front++) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001901 int remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001902 /* Do we want to remove this space? */
1903
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001904 if (*front == '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001905 *front = ' ';
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001906
David Lawrence Ramsey021960d2004-05-13 23:19:01 +00001907 /* These tests are safe since line->data + skip is not a
1908 * space. */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001909 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001910 const char *bob = front - 2;
1911
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001912 remove_space = TRUE;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001913 for (bob = back - 2; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001914 if (strchr(punct, *bob) != NULL) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001915 remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001916 break;
1917 }
1918 if (strchr(brackets, *bob) == NULL)
1919 break;
1920 }
1921 }
1922
1923 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001924 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001925 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001926#ifndef NANO_SMALL
1927 if (mark_beginbuf == line && back - line->data < mark_beginx)
1928 mark_beginx--;
1929#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001930 if (*front == '\0')
1931 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00001932 } else {
1933 *back = *front;
1934 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001935 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001936 if (*front == '\0')
1937 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001938 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001939
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001940 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00001941 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00001942
Chris Allegretta6df90f52002-07-19 01:08:59 +00001943 /* Now back is the new end of line->data. */
1944 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00001945 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001946 null_at(&line->data, back - line->data);
1947#ifndef NANO_SMALL
1948 if (mark_beginbuf == line && back - line->data < mark_beginx)
1949 mark_beginx = back - line->data;
1950#endif
1951 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001952}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001953
1954/* The "quote part" of a line is the largest initial substring matching
1955 * the quote string. This function returns the length of the quote part
1956 * of the given line.
1957 *
1958 * Note that if !HAVE_REGEX_H then we match concatenated copies of
1959 * quotestr. */
1960#ifdef HAVE_REGEX_H
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001961size_t quote_length(const char *line, const regex_t *qreg)
1962{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001963 regmatch_t matches;
1964 int rc = regexec(qreg, line, 1, &matches, 0);
1965
1966 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t) -1)
1967 return 0;
1968 /* matches.rm_so should be 0, since the quote string should start with
1969 * the caret ^. */
1970 return matches.rm_eo;
1971}
1972#else /* !HAVE_REGEX_H */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001973size_t quote_length(const char *line)
1974{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001975 size_t qdepth = 0;
1976 size_t qlen = strlen(quotestr);
1977
1978 /* Compute quote depth level */
1979 while (!strcmp(line + qdepth, quotestr))
1980 qdepth += qlen;
1981 return qdepth;
1982}
1983#endif /* !HAVE_REGEX_H */
1984
Chris Allegretta6df90f52002-07-19 01:08:59 +00001985/* a_line and b_line are lines of text. The quotation part of a_line is
1986 * the first a_quote characters. Check that the quotation part of
1987 * b_line is the same. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00001988int quotes_match(const char *a_line, size_t a_quote, IFREG(const char
1989 *b_line, const regex_t *qreg))
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001990{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001991 /* Here is the assumption about a_quote: */
1992 assert(a_quote == quote_length(IFREG(a_line, qreg)));
Chris Allegrettad865da12002-07-29 23:46:38 +00001993 return a_quote == quote_length(IFREG(b_line, qreg)) &&
Chris Allegretta6df90f52002-07-19 01:08:59 +00001994 !strncmp(a_line, b_line, a_quote);
1995}
1996
1997/* We assume a_line and b_line have no quote part. Then, we return whether
1998 * b_line could follow a_line in a paragraph. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00001999size_t indents_match(const char *a_line, size_t a_indent, const char
2000 *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002001{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002002 assert(a_indent == indent_length(a_line));
2003 assert(b_indent == indent_length(b_line));
2004
2005 return b_indent <= a_indent && !strncmp(a_line, b_line, b_indent);
2006}
2007
2008/* Put the next par_len lines, starting with first_line, in the cut
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002009 * buffer, not allowing them to be concatenated. We assume there are
2010 * enough lines after first_line. We leave copies of the lines in
2011 * place, too. We return the new copy of first_line. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002012filestruct *backup_lines(filestruct *first_line, size_t par_len, size_t
2013 quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002014{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002015 /* We put the original lines, not copies, into the cutbuffer, just
2016 * out of a misguided sense of consistency, so if you uncut, you get
2017 * the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002018 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002019
2020 set_modified();
2021 cutbuffer = NULL;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002022 for (; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002023 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002024
Chris Allegretta908f7702003-01-15 11:18:58 +00002025 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002026 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002027 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002028 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002029 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002030 edittop = bob;
2031#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002032 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002033 mark_beginbuf = bob;
2034#endif
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002035 justify_format(bob, quote_len + indent_length(bob->data + quote_len));
Chris Allegretta6df90f52002-07-19 01:08:59 +00002036
Chris Allegretta908f7702003-01-15 11:18:58 +00002037 assert(alice != NULL && bob != NULL);
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002038 add_to_cutbuffer(alice, FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002039 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002040 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002041 }
2042 return first_line;
2043}
2044
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002045/* Is it possible to break line at or before goal? */
2046int breakable(const char *line, int goal)
2047{
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002048 for (; *line != '\0' && goal >= 0; line++) {
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002049 if (isblank(*line))
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002050 return TRUE;
2051
2052 if (is_cntrl_char(*line) != 0)
2053 goal -= 2;
2054 else
2055 goal -= 1;
2056 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002057 /* If goal is not negative, the whole line (one word) was short
2058 * enough. */
2059 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002060}
2061
Chris Allegretta6df90f52002-07-19 01:08:59 +00002062/* We are trying to break a chunk off line. We find the last space such
2063 * that the display length to there is at most goal + 1. If there is
2064 * no such space, and force is not 0, then we find the first space.
2065 * Anyway, we then take the last space in that group of spaces. The
2066 * terminating '\0' counts as a space. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002067int break_line(const char *line, int goal, int force)
2068{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002069 /* Note that we use int instead of size_t, since goal is at most COLS,
2070 * the screen width, which will always be reasonably small. */
2071 int space_loc = -1;
2072 /* Current tentative return value. Index of the last space we
2073 * found with short enough display width. */
2074 int cur_loc = 0;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002075 /* Current index in line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002076
2077 assert(line != NULL);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002078 for (; *line != '\0' && goal >= 0; line++, cur_loc++) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002079 if (*line == ' ')
2080 space_loc = cur_loc;
2081 assert(*line != '\t');
2082
Chris Allegrettacf287c82002-07-20 13:57:41 +00002083 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002084 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002085 else
2086 goal--;
2087 }
2088 if (goal >= 0)
2089 /* In fact, the whole line displays shorter than goal. */
2090 return cur_loc;
2091 if (space_loc == -1) {
2092 /* No space found short enough. */
2093 if (force)
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002094 for (; *line != '\0'; line++, cur_loc++)
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002095 if (*line == ' ' && *(line + 1) != ' ' && *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002096 return cur_loc;
2097 return -1;
2098 }
2099 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002100 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002101 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2102 *(line - cur_loc + space_loc + 1) == '\0')
2103 space_loc++;
2104 return space_loc;
2105}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002106
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002107/* Search a paragraph. If search_type is JUSTIFY, search for the
2108 * beginning of the current paragraph or, if we're at the end of it, the
2109 * beginning of the next paragraph. If search_type is BEGIN, search for
2110 * the beginning of the current paragraph or, if we're already there,
2111 * the beginning of the previous paragraph. If search_type is END,
2112 * search for the end of the current paragraph or, if we're already
2113 * there, the end of the next paragraph. Afterwards, save the quote
2114 * length, paragraph length, and indentation length in *quote, *par, and
2115 * *indent if they aren't NULL, and refresh the screen if do_refresh is
2116 * TRUE. Return 0 if we found a paragraph, or 1 if there was an error
2117 * or we didn't find a paragraph.
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002118 *
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002119 * To explain the searching algorithm, I first need to define some
Chris Allegretta6df90f52002-07-19 01:08:59 +00002120 * phrases about paragraphs and quotation:
2121 * A line of text consists of a "quote part", followed by an
2122 * "indentation part", followed by text. The functions quote_length()
2123 * and indent_length() calculate these parts.
2124 *
2125 * A line is "part of a paragraph" if it has a part not in the quote
2126 * part or the indentation.
2127 *
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002128 * A line is "the beginning of a paragraph" if it is part of a
2129 * paragraph and
Chris Allegretta6df90f52002-07-19 01:08:59 +00002130 * 1) it is the top line of the file, or
2131 * 2) the line above it is not part of a paragraph, or
2132 * 3) the line above it does not have precisely the same quote
2133 * part, or
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002134 * 4) the indentation of this line is not an initial substring of
2135 * the indentation of the previous line, or
Chris Allegretta6df90f52002-07-19 01:08:59 +00002136 * 5) this line has no quote part and some indentation, and
2137 * AUTOINDENT is not set.
2138 * The reason for number 5) is that if AUTOINDENT is not set, then an
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002139 * indented line is expected to start a paragraph, like in books.
2140 * Thus, nano can justify an indented paragraph only if AUTOINDENT is
2141 * turned on.
Chris Allegretta6df90f52002-07-19 01:08:59 +00002142 *
2143 * A contiguous set of lines is a "paragraph" if each line is part of
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002144 * a paragraph and only the first line is the beginning of a
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002145 * paragraph. */
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002146int do_para_search(justbegend search_type, size_t *quote, size_t *par,
2147 size_t *indent, int do_refresh)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002148{
2149 size_t quote_len;
2150 /* Length of the initial quotation of the paragraph we
2151 * search. */
2152 size_t par_len;
2153 /* Number of lines in that paragraph. */
Robert Siemborski60cd6aa2001-01-21 23:23:48 +00002154
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002155 /* We save this global variable to see if we're where we started
2156 * when searching for the beginning of the paragraph. */
2157 filestruct *current_save = current;
2158
2159 size_t indent_len; /* Generic indentation length. */
2160 filestruct *line; /* Generic line of text. */
2161
2162 static int do_restart = 1;
2163 /* Whether we're restarting when searching for the beginning
2164 * line of the paragraph. */
2165
2166#ifdef HAVE_REGEX_H
2167 regex_t qreg; /* qreg is the compiled quotation regexp. We no
2168 * longer care about quotestr. */
2169 int rc = regcomp(&qreg, quotestr, REG_EXTENDED);
2170
2171 if (rc != 0) {
2172 size_t size = regerror(rc, &qreg, NULL, 0);
2173 char *strerror = charalloc(size);
2174
2175 regerror(rc, &qreg, strerror, size);
2176 statusbar(_("Bad quote string %s: %s"), quotestr, strerror);
2177 free(strerror);
2178 return 1;
2179 }
2180#endif
2181
2182 /* Here is an assumption that is always true anyway. */
2183 assert(current != NULL);
2184
2185 current_x = 0;
2186
2187 restart_para_search:
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002188 /* Here we find the first line of the paragraph to search. If the
2189 * current line is in a paragraph, then we move back to the first
2190 * line. Otherwise, we move to the first line that is in a
2191 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002192 quote_len = quote_length(IFREG(current->data, &qreg));
2193 indent_len = indent_length(current->data + quote_len);
2194
2195 if (current->data[quote_len + indent_len] != '\0') {
2196 /* This line is part of a paragraph. So we must search back to
2197 * the first line of this paragraph. First we check items 1)
2198 * and 3) above. */
2199 while (current->prev != NULL && quotes_match(current->data,
2200 quote_len, IFREG(current->prev->data, &qreg))) {
2201 size_t temp_id_len =
2202 indent_length(current->prev->data + quote_len);
2203 /* The indentation length of the previous line. */
2204
2205 /* Is this line the beginning of a paragraph, according to
2206 * items 2), 5), or 4) above? If so, stop. */
2207 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002208 (quote_len == 0 && indent_len > 0
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002209#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002210 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002211#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002212 ) || !indents_match(current->prev->data + quote_len,
2213 temp_id_len, current->data + quote_len, indent_len))
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002214 break;
2215 indent_len = temp_id_len;
2216 current = current->prev;
2217 current_y--;
2218 }
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002219 } else if (search_type == BEGIN) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002220 /* This line is not part of a paragraph. Move up until we get
2221 * to a non "blank" line, and then move down once. */
2222 do {
2223 /* There is no previous paragraph, so nothing to move to. */
2224 if (current->prev == NULL) {
2225 placewewant = 0;
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002226 if (do_refresh)
2227 edit_refresh();
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002228#ifdef HAVE_REGEX_H
2229 if (!do_restart)
2230 regfree(&qreg);
2231#endif
2232 return 1;
2233 }
2234 current = current->prev;
2235 current_y--;
2236 quote_len = quote_length(IFREG(current->data, &qreg));
2237 indent_len = indent_length(current->data + quote_len);
2238 } while (current->data[quote_len + indent_len] == '\0');
2239 current = current->next;
2240 } else {
2241 /* This line is not part of a paragraph. Move down until we get
2242 * to a non "blank" line. */
2243 do {
2244 /* There is no next paragraph, so nothing to move to. */
2245 if (current->next == NULL) {
2246 placewewant = 0;
2247 if (do_refresh)
2248 edit_refresh();
2249#ifdef HAVE_REGEX_H
2250 regfree(&qreg);
2251#endif
2252 return 1;
2253 }
2254 current = current->next;
2255 current_y++;
2256 quote_len = quote_length(IFREG(current->data, &qreg));
2257 indent_len = indent_length(current->data + quote_len);
2258 } while (current->data[quote_len + indent_len] == '\0');
2259 }
2260
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002261 /* Now current is the first line of the paragraph, and quote_len is
2262 * the quotation length of that line. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002263
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002264 /* Next step, compute par_len, the number of lines in this
2265 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002266 line = current;
2267 par_len = 1;
2268 indent_len = indent_length(line->data + quote_len);
2269
2270 while (line->next != NULL && quotes_match(current->data, quote_len,
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002271 IFREG(line->next->data, &qreg))) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002272 size_t temp_id_len = indent_length(line->next->data + quote_len);
2273
2274 if (!indents_match(line->data + quote_len, indent_len,
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002275 line->next->data + quote_len, temp_id_len) ||
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002276 line->next->data[quote_len + temp_id_len] == '\0' ||
2277 (quote_len == 0 && temp_id_len > 0
2278#ifndef NANO_SMALL
2279 && !ISSET(AUTOINDENT)
2280#endif
2281 ))
2282 break;
2283 indent_len = temp_id_len;
2284 line = line->next;
2285 par_len++;
2286 }
2287
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002288 if (search_type == BEGIN) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002289 /* We're on the same line we started on. Move up until we get
2290 * to a non-"blank" line, restart the search from there until we
2291 * find a line that's part of a paragraph, and search once more
2292 * so that we end up at the beginning of that paragraph. */
2293 if (current != fileage && current == current_save && do_restart) {
2294 while (current->prev != NULL) {
2295 size_t i, j = 0;
2296 current = current->prev;
2297 current_y--;
2298 /* Skip over lines consisting only of spacing
2299 * characters, as searching for the end of the paragraph
2300 * does. */
2301 for (i = 0; current->data[i] != '\0'; i++) {
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002302 if (isblank(current->data[i]))
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002303 j++;
2304 else {
2305 i = 0;
2306 j = 1;
2307 break;
2308 }
2309 }
2310 if (i != j && strlen(current->data) >=
2311 (quote_len + indent_len) &&
2312 current->data[quote_len + indent_len] != '\0') {
2313 do_restart = 0;
2314 break;
2315 }
2316 }
2317 goto restart_para_search;
2318 } else
2319 do_restart = 1;
2320 }
2321
2322#ifdef HAVE_REGEX_H
2323 /* We no longer need to check quotation. */
2324 regfree(&qreg);
2325#endif
2326
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002327 /* Now par_len is the number of lines in this paragraph. We should
2328 * never call quotes_match() or quote_length() again. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002329
2330 /* If we're searching for the end of the paragraph, move down the
2331 * number of lines in the paragraph. */
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002332 if (search_type == END) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002333 for (; par_len > 0; current_y++, par_len--)
2334 current = current->next;
2335 }
2336
2337 /* Refresh the screen if needed. */
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002338 if (do_refresh)
2339 edit_refresh();
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002340
2341 /* Save the values of quote_len, par_len, and indent_len if
2342 * needed. */
2343 if (quote != NULL)
2344 *quote = quote_len;
2345 if (par != NULL)
2346 *par = par_len;
2347 if (indent != NULL)
2348 *indent = indent_len;
2349
2350 return 0;
2351}
2352
2353int do_para_begin(void)
2354{
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002355 return do_para_search(BEGIN, NULL, NULL, NULL, TRUE);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002356}
2357
2358int do_para_end(void)
2359{
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002360 return do_para_search(END, NULL, NULL, NULL, TRUE);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002361}
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002362
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002363/* If full_justify is TRUE, justify the entire file. Otherwise, justify
2364 * the current paragraph. */
2365int do_justify(int full_justify)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002366{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002367 size_t quote_len;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002368 /* Length of the initial quotation of the paragraph we
2369 * justify. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002370 size_t par_len;
2371 /* Number of lines in that paragraph. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002372 filestruct *first_par_line = NULL;
2373 /* Will be the first line of the resulting justified paragraph.
2374 * For restoring after uncut. */
David Lawrence Ramsey36e363f2004-05-17 20:38:00 +00002375 filestruct *last_par_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002376 /* Will be the last line of the result, also for uncut. */
2377 filestruct *cutbuffer_save = cutbuffer;
2378 /* When the paragraph gets modified, all lines from the changed
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002379 * one down are stored in the cutbuffer. We back up the
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002380 * original to restore it later. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002381
2382 /* We save these global variables to be restored if the user
2383 * unjustifies. Note we don't need to save totlines. */
2384 int current_x_save = current_x;
2385 int current_y_save = current_y;
2386 filestruct *current_save = current;
2387 int flags_save = flags;
2388 long totsize_save = totsize;
2389 filestruct *edittop_save = edittop;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002390#ifndef NANO_SMALL
2391 filestruct *mark_beginbuf_save = mark_beginbuf;
2392 int mark_beginx_save = mark_beginx;
2393#endif
2394
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002395 size_t indent_len; /* Generic indentation length. */
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002396 size_t i; /* Generic loop variable. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002397
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002398 /* If we're justifying the entire file, start at the beginning. */
2399 if (full_justify)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002400 current = fileage;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002401
2402 last_par_line = current;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002403
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002404 while (TRUE) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002405
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002406 /* First, search for the beginning of the current paragraph or,
2407 * if we're at the end of it, the beginning of the next
2408 * paragraph. Save the quote length, paragraph length, and
2409 * indentation length and don't refresh the screen yet (since
2410 * we'll do that after we justify). If the search failed and
2411 * we're justifying the whole file, move the last line of the
2412 * text we're justifying to just before the magicline, which is
2413 * where it'll be anyway if we've searched the entire file, and
2414 * break out of the loop; otherwise, refresh the screen and get
2415 * out. */
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002416 if (do_para_search(JUSTIFY, &quote_len, &par_len, &indent_len,
2417 FALSE) != 0) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002418 if (full_justify) {
2419 /* This should be safe in the event of filebot->prev's
2420 * being NULL, since only last_par_line->next is used if
2421 * we eventually unjustify. */
2422 last_par_line = filebot->prev;
2423 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002424 } else {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002425 edit_refresh();
2426 return 0;
2427 }
2428 }
2429
2430 /* Next step, we loop through the lines of this paragraph,
2431 * justifying each one individually. */
2432 for (; par_len > 0; current_y++, par_len--) {
2433 size_t line_len;
2434 size_t display_len;
2435 /* The width of current in screen columns. */
2436 int break_pos;
2437 /* Where we will break the line. */
2438
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002439 indent_len = quote_len + indent_length(current->data +
2440 quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002441
2442 /* justify_format() removes excess spaces from the line, and
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002443 * changes tabs to spaces. After calling it, we call
2444 * backup_lines(), which copies the original paragraph to
2445 * the cutbuffer for unjustification and then calls
2446 * justify_format() on the remaining lines. */
2447 justify_format(current, indent_len);
2448 if (first_par_line == NULL)
2449 first_par_line = backup_lines(current, full_justify ?
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002450 filebot->lineno - current->lineno : par_len, quote_len);
2451
2452 line_len = strlen(current->data);
2453 display_len = strlenpt(current->data);
2454
2455 if (display_len > fill) {
2456 /* The line is too long. Try to wrap it to the next. */
2457 break_pos = break_line(current->data + indent_len,
2458 fill - strnlenpt(current->data, indent_len), TRUE);
2459 if (break_pos == -1 || break_pos + indent_len == line_len)
2460 /* We can't break the line, or don't need to, so
2461 * just go on to the next. */
2462 goto continue_loc;
2463 break_pos += indent_len;
2464 assert(break_pos < line_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002465 if (par_len == 1) {
2466 /* There is no next line in this paragraph. We make
2467 * a new line and copy text after break_pos into
2468 * it. */
2469 splice_node(current, make_new_node(current), current->next);
2470 /* In a non-quoted paragraph, we copy the indent
2471 * only if AUTOINDENT is turned on. */
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002472 if (quote_len == 0
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002473#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002474 && !ISSET(AUTOINDENT)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002475#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002476 )
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002477 indent_len = 0;
2478 current->next->data = charalloc(indent_len + line_len -
2479 break_pos);
2480 strncpy(current->next->data, current->data, indent_len);
2481 strcpy(current->next->data + indent_len,
2482 current->data + break_pos + 1);
2483 assert(strlen(current->next->data) ==
2484 indent_len + line_len - break_pos - 1);
2485 totlines++;
2486 totsize += indent_len;
2487 par_len++;
2488 } else {
2489 size_t next_line_len = strlen(current->next->data);
2490
2491 indent_len = quote_len +
2492 indent_length(current->next->data + quote_len);
2493 current->next->data = charealloc(current->next->data,
2494 next_line_len + line_len - break_pos + 1);
2495
2496 charmove(current->next->data + indent_len + line_len -
2497 break_pos, current->next->data + indent_len,
2498 next_line_len - indent_len + 1);
2499 strcpy(current->next->data + indent_len,
2500 current->data + break_pos + 1);
2501 current->next->data[indent_len + line_len - break_pos - 1]
2502 = ' ';
2503#ifndef NANO_SMALL
2504 if (mark_beginbuf == current->next) {
2505 if (mark_beginx < indent_len)
2506 mark_beginx = indent_len;
2507 mark_beginx += line_len - break_pos;
2508 }
2509#endif
2510 }
2511#ifndef NANO_SMALL
2512 if (mark_beginbuf == current && mark_beginx > break_pos) {
2513 mark_beginbuf = current->next;
2514 mark_beginx -= break_pos + 1 - indent_len;
2515 }
2516#endif
2517 null_at(&current->data, break_pos);
2518 current = current->next;
2519 } else if (display_len < fill && par_len > 1) {
2520 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002521
2522 indent_len = quote_len +
2523 indent_length(current->next->data + quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002524 /* If we can't pull a word from the next line up to this
2525 * one, just go on. */
2526 if (!breakable(current->next->data + indent_len,
2527 fill - display_len - 1))
2528 goto continue_loc;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002529
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002530 break_pos = break_line(current->next->data + indent_len,
2531 fill - display_len - 1, FALSE);
2532 assert(break_pos != -1);
2533
2534 current->data = charealloc(current->data,
2535 line_len + break_pos + 2);
2536 current->data[line_len] = ' ';
2537 strncpy(current->data + line_len + 1,
2538 current->next->data + indent_len, break_pos);
2539 current->data[line_len + break_pos + 1] = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002540#ifndef NANO_SMALL
2541 if (mark_beginbuf == current->next) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002542 if (mark_beginx < indent_len + break_pos) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002543 mark_beginbuf = current;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002544 if (mark_beginx <= indent_len)
2545 mark_beginx = line_len + 1;
2546 else
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002547 mark_beginx = line_len + 1 + mark_beginx -
2548 indent_len;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002549 } else
2550 mark_beginx -= break_pos + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002551 }
2552#endif
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002553 next_line_len = strlen(current->next->data);
2554 if (indent_len + break_pos == next_line_len) {
2555 filestruct *line = current->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002556
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002557 /* Don't destroy edittop! */
2558 if (line == edittop)
2559 edittop = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002560
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002561 unlink_node(line);
2562 delete_node(line);
2563 totlines--;
2564 totsize -= indent_len;
2565 current_y--;
2566 } else {
2567 charmove(current->next->data + indent_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002568 current->next->data + indent_len + break_pos + 1,
2569 next_line_len - break_pos - indent_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002570 null_at(&current->next->data, next_line_len - break_pos);
2571 current = current->next;
2572 }
2573 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002574 continue_loc:
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002575 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002576 current = current->next;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002577
2578 /* If the line we were on before still exists, and it was
2579 * not the last line of the paragraph, add a space to the
David Lawrence Ramsey684e7eb2004-05-20 14:31:15 +00002580 * end of it to replace the one removed or left out by
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002581 * justify_format(). */
2582 if (current->prev != NULL && par_len > 1) {
2583 size_t prev_line_len = strlen(current->prev->data);
2584 current->prev->data = charealloc(current->prev->data,
2585 prev_line_len + 2);
2586 current->prev->data[prev_line_len] = ' ';
2587 current->prev->data[prev_line_len + 1] = '\0';
2588 totsize++;
2589 }
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002590 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002591
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002592 /* We've just justified a paragraph. If we're not justifying the
2593 * entire file, break out of the loop. Otherwise, continue the
2594 * loop so that we justify all the paragraphs in the file. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002595 if (!full_justify)
2596 break;
2597
2598 } /* while (TRUE) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002599
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002600 /* We are now done justifying the paragraph or the file, so clean
2601 * up. totlines, totsize, and current_y have been maintained above.
2602 * Set last_par_line to the new end of the paragraph, update
2603 * fileage, and set current_x. Also, edit_refresh() needs the line
2604 * numbers to be right, so renumber(). */
2605 last_par_line = current->prev;
2606 if (first_par_line->prev == NULL)
2607 fileage = first_par_line;
2608 renumber(first_par_line);
2609
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002610 edit_refresh();
Chris Allegretta6df90f52002-07-19 01:08:59 +00002611
Chris Allegretta9149e612000-11-27 00:23:41 +00002612 statusbar(_("Can now UnJustify!"));
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002613 /* Display the shortcut list with UnJustify. */
Chris Allegretta07798352000-11-27 22:58:23 +00002614 shortcut_init(1);
2615 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002616 reset_cursor();
2617
Chris Allegretta6df90f52002-07-19 01:08:59 +00002618 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002619 * keystroke and return. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002620 {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002621 int meta_key;
2622 i = get_kbinput(edit, &meta_key);
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002623#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002624 /* If it was a mouse click, parse it with do_mouse() and it
2625 * might become the unjustify key. Else give it back to the
2626 * input stream. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002627 if (i == KEY_MOUSE) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002628 do_mouse();
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002629 i = get_kbinput(edit, &meta_key);
2630 }
Chris Allegretta5f071802001-05-06 02:34:31 +00002631#endif
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002632 }
Chris Allegretta5f071802001-05-06 02:34:31 +00002633
David Lawrence Ramseyc91696e2004-01-29 04:16:23 +00002634 if (i != NANO_UNJUSTIFY_KEY && i != NANO_UNJUSTIFY_FKEY) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002635 ungetch(i);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002636 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002637 } else {
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002638 /* Else restore the justify we just did (ungrateful user!). */
2639 filestruct *cutbottom = get_cutbottom();
2640
Chris Allegretta6df90f52002-07-19 01:08:59 +00002641 current = current_save;
2642 current_x = current_x_save;
2643 current_y = current_y_save;
2644 edittop = edittop_save;
Chris Allegrettad022eac2000-11-27 02:50:49 +00002645
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002646 /* Splice the cutbuffer back into the file. */
2647 cutbottom->next = last_par_line->next;
2648 cutbottom->next->prev = cutbottom;
2649 /* The line numbers after the end of the paragraph have been
2650 * changed, so we change them back. */
2651 renumber(cutbottom->next);
2652 if (first_par_line->prev != NULL) {
2653 cutbuffer->prev = first_par_line->prev;
2654 cutbuffer->prev->next = cutbuffer;
2655 } else
2656 fileage = cutbuffer;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002657
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002658 last_par_line->next = NULL;
2659 free_filestruct(first_par_line);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002660
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002661 /* Restore global variables from before the justify. */
2662 totsize = totsize_save;
2663 totlines = filebot->lineno;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002664#ifndef NANO_SMALL
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002665 mark_beginbuf = mark_beginbuf_save;
2666 mark_beginx = mark_beginx_save;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002667#endif
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002668 flags = flags_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002669 if (!ISSET(MODIFIED))
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002670 titlebar(NULL);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002671 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002672 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002673 cutbuffer = cutbuffer_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002674 /* Note that now cutbottom is invalid, but that's okay. */
2675 blank_statusbar();
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002676 /* Display the shortcut list with UnCut. */
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002677 shortcut_init(0);
2678 display_main_list();
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002679
Chris Allegretta6df90f52002-07-19 01:08:59 +00002680 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002681}
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002682
2683int do_justify_void(void)
2684{
2685 return do_justify(FALSE);
2686}
2687
2688int do_full_justify(void)
2689{
2690 return do_justify(TRUE);
2691}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00002692#endif /* !DISABLE_JUSTIFY */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002693
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002694int do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002695{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002696 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002697
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002698 if (!ISSET(MODIFIED)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002699
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002700#ifdef ENABLE_MULTIBUFFER
2701 if (!close_open_file()) {
2702 display_main_list();
2703 return 1;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002704 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002705 else
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002706#endif
David Lawrence Ramseyda141062004-05-25 19:41:11 +00002707 finish();
Chris Allegretta756f2202000-09-01 13:32:47 +00002708 }
2709
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002710 if (ISSET(TEMP_OPT))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002711 i = 1;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002712 else
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002713 i = do_yesno(FALSE, _("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002714
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002715#ifdef DEBUG
2716 dump_buffer(fileage);
2717#endif
2718
2719 if (i == 1) {
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002720 if (do_writeout(TRUE) > 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002721
2722#ifdef ENABLE_MULTIBUFFER
2723 if (!close_open_file()) {
2724 display_main_list();
2725 return 1;
2726 }
2727 else
2728#endif
David Lawrence Ramseyda141062004-05-25 19:41:11 +00002729 finish();
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002730 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002731 } else if (i == 0) {
2732
2733#ifdef ENABLE_MULTIBUFFER
2734 if (!close_open_file()) {
2735 display_main_list();
2736 return 1;
2737 }
2738 else
2739#endif
David Lawrence Ramseyda141062004-05-25 19:41:11 +00002740 finish();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002741 } else
2742 statusbar(_("Cancelled"));
2743
2744 display_main_list();
2745 return 1;
2746}
2747
2748void signal_init(void)
2749{
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002750 /* Trap SIGINT and SIGQUIT because we want them to do useful
2751 * things. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002752 memset(&act, 0, sizeof(struct sigaction));
2753 act.sa_handler = SIG_IGN;
2754 sigaction(SIGINT, &act, NULL);
David Lawrence Ramsey2897d2b2004-01-26 20:56:20 +00002755 sigaction(SIGQUIT, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002756
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002757 /* Trap SIGHUP and SIGTERM because we want to write the file out. */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002758 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002759 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002760 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002761
2762#ifndef NANO_SMALL
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002763 /* Trap SIGWINCH because we want to handle window resizes. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002764 act.sa_handler = handle_sigwinch;
2765 sigaction(SIGWINCH, &act, NULL);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002766 allow_pending_sigwinch(FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002767#endif
2768
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002769 /* Trap normal suspend (^Z) so we can handle it ourselves. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002770 if (!ISSET(SUSPEND)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002771 act.sa_handler = SIG_IGN;
2772 sigaction(SIGTSTP, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002773 } else {
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002774 /* Block all other signals in the suspend and continue handlers.
2775 * If we don't do this, other stuff interrupts them! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002776 sigfillset(&act.sa_mask);
2777
2778 act.sa_handler = do_suspend;
2779 sigaction(SIGTSTP, &act, NULL);
2780
2781 act.sa_handler = do_cont;
2782 sigaction(SIGCONT, &act, NULL);
2783 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002784}
2785
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002786/* Handler for SIGHUP (hangup) and SIGTERM (terminate). */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002787RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002788{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002789 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002790}
2791
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002792/* Handler for SIGTSTP (suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002793RETSIGTYPE do_suspend(int signal)
2794{
2795 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00002796 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002797 fflush(stdout);
2798
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002799 /* Restore the old terminal settings. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002800 tcsetattr(0, TCSANOW, &oldterm);
2801
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002802 /* Trap SIGHUP and SIGTERM so we can properly deal with them while
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002803 * suspended. */
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002804 act.sa_handler = handle_hupterm;
2805 sigaction(SIGHUP, &act, NULL);
2806 sigaction(SIGTERM, &act, NULL);
2807
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002808 /* Do what mutt does: send ourselves a SIGSTOP. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002809 kill(0, SIGSTOP);
2810}
2811
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002812/* Handler for SIGCONT (continue after suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002813RETSIGTYPE do_cont(int signal)
2814{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002815#ifndef NANO_SMALL
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002816 /* Perhaps the user resized the window while we slept. Handle it
2817 * and update the screen in the process. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002818 handle_sigwinch(0);
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002819#else
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002820 /* Just update the screen. */
2821 doupdate();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002822#endif
2823}
2824
2825#ifndef NANO_SMALL
2826void handle_sigwinch(int s)
2827{
2828 const char *tty = ttyname(0);
2829 int fd;
2830 int result = 0;
2831 struct winsize win;
2832
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002833 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002834 return;
2835 fd = open(tty, O_RDWR);
2836 if (fd == -1)
2837 return;
2838 result = ioctl(fd, TIOCGWINSZ, &win);
2839 close(fd);
2840 if (result == -1)
2841 return;
2842
2843 /* Could check whether the COLS or LINES changed, and return
2844 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2845 * variables, and in some cases ncurses has already updated them.
2846 * But not in all cases, argh. */
2847 COLS = win.ws_col;
2848 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002849 editwinrows = LINES - 5 + no_help();
2850 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002851 die_too_small();
2852
2853#ifndef DISABLE_WRAPJUSTIFY
2854 fill = wrap_at;
2855 if (fill <= 0)
2856 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002857 if (fill < 0)
2858 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002859#endif
2860
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002861 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002862 memset(hblank, ' ', COLS);
2863 hblank[COLS] = '\0';
2864
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002865#ifdef USE_SLANG
2866 /* Slang curses emulation brain damage, part 1: If we just do what
2867 * curses does here, it'll only work properly if the resize made the
2868 * window smaller. Do what mutt does: Leave and immediately reenter
2869 * Slang screen management mode. */
2870 SLsmg_reset_smg();
2871 SLsmg_init_smg();
2872#else
2873 /* Do the equivalent of what Minimum Profit does: Leave and
2874 * immediately reenter curses mode. */
2875 endwin();
2876 refresh();
2877#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002878
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002879 /* Do the equivalent of what both mutt and Minimum Profit do:
2880 * Reinitialize all the windows based on the new screen
2881 * dimensions. */
2882 window_init();
2883
2884 /* Redraw the contents of the windows that need it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002885 blank_statusbar();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002886 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002887 total_refresh();
2888
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002889 /* Turn cursor back on for sure. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002890 curs_set(1);
2891
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002892 /* Restore the terminal to its previously saved state. */
2893 resetty();
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002894
2895 /* Jump back to the main loop. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002896 siglongjmp(jmpbuf, 1);
2897}
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002898
2899void allow_pending_sigwinch(int allow)
2900{
2901 sigset_t winch;
2902 sigemptyset(&winch);
2903 sigaddset(&winch, SIGWINCH);
2904 if (allow)
2905 sigprocmask(SIG_UNBLOCK, &winch, NULL);
2906 else
2907 sigprocmask(SIG_BLOCK, &winch, NULL);
2908}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002909#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002910
Chris Allegrettadab017e2002-04-23 10:56:06 +00002911#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002912void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002913{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002914 int enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002915
Chris Allegretta658399a2001-06-14 02:54:22 +00002916 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002917 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002918
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002919 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002920 case TOGGLE_SUSPEND_KEY:
2921 signal_init();
2922 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002923#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00002924 case TOGGLE_MOUSE_KEY:
2925 mouse_init();
2926 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002927#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002928 case TOGGLE_NOHELP_KEY:
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002929 blank_statusbar();
2930 blank_bottombars();
Chris Allegretta2a42af12000-09-12 23:02:49 +00002931 wrefresh(bottomwin);
2932 window_init();
2933 edit_refresh();
2934 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00002935 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00002936 case TOGGLE_DOS_KEY:
2937 UNSET(MAC_FILE);
2938 break;
2939 case TOGGLE_MAC_KEY:
2940 UNSET(DOS_FILE);
2941 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002942#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00002943 case TOGGLE_SYNTAX_KEY:
2944 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002945 break;
2946#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002947 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00002948
Chris Allegretta6df90f52002-07-19 01:08:59 +00002949 /* We are assuming here that shortcut_init() above didn't free and
2950 * reallocate the toggles. */
2951 enabled = ISSET(which->flag);
2952 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
2953 enabled = !enabled;
2954 statusbar("%s %s", which->desc,
2955 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00002956}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002957#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00002958
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002959void disable_signals(void)
2960{
2961 struct termios term;
2962
2963 tcgetattr(0, &term);
2964 term.c_lflag &= ~ISIG;
2965 tcsetattr(0, TCSANOW, &term);
2966}
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002967
2968#ifndef NANO_SMALL
2969void enable_signals(void)
2970{
2971 struct termios term;
2972
2973 tcgetattr(0, &term);
2974 term.c_lflag |= ISIG;
2975 tcsetattr(0, TCSANOW, &term);
2976}
2977#endif
2978
2979void disable_flow_control(void)
2980{
2981 struct termios term;
2982
2983 tcgetattr(0, &term);
2984 term.c_iflag &= ~(IXON|IXOFF);
2985 tcsetattr(0, TCSANOW, &term);
2986}
2987
2988void enable_flow_control(void)
2989{
2990 struct termios term;
2991
2992 tcgetattr(0, &term);
2993 term.c_iflag |= (IXON|IXOFF);
2994 tcsetattr(0, TCSANOW, &term);
2995}
2996
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002997int main(int argc, char *argv[])
2998{
2999 int optchr;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003000 int startline = 0; /* Line to try and start at */
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003001 int modify_control_seq = 0;
Chris Allegretta09fc4302003-01-16 22:16:38 +00003002 int fill_flag_used = 0; /* Was the fill option used? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003003 const shortcut *s;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003004 int keyhandled = 0; /* Have we handled the keystroke yet? */
David Lawrence Ramseyf8ddf312004-01-09 22:38:09 +00003005 int kbinput; /* Input from keyboard */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003006 int meta_key;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003007
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003008#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00003009 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003010#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003011#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003012 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003013 {"help", 0, 0, 'h'},
3014#ifdef ENABLE_MULTIBUFFER
3015 {"multibuffer", 0, 0, 'F'},
3016#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003017#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003018#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003019 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003020#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003021 {"ignorercfiles", 0, 0, 'I'},
3022#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003023#ifndef DISABLE_JUSTIFY
3024 {"quotestr", 1, 0, 'Q'},
3025#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003026#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003027 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003028#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003029 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003030 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003031#ifdef ENABLE_COLOR
3032 {"syntax", 1, 0, 'Y'},
3033#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003034 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003035 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003036 {"nofollow", 0, 0, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003037#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003038 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003039#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003040#ifndef DISABLE_OPERATINGDIR
3041 {"operatingdir", 1, 0, 'o'},
3042#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003043 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003044#ifndef DISABLE_WRAPJUSTIFY
3045 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003046#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003047#ifndef DISABLE_SPELLER
3048 {"speller", 1, 0, 's'},
3049#endif
3050 {"tempfile", 0, 0, 't'},
3051 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003052#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003053 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003054#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003055 {"nohelp", 0, 0, 'x'},
3056 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003057#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003058 {"smarthome", 0, 0, 'A'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003059 {"backup", 0, 0, 'B'},
3060 {"dos", 0, 0, 'D'},
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003061 {"backupdir", 1, 0, 'E'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003062 {"mac", 0, 0, 'M'},
3063 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003064 {"smooth", 0, 0, 'S'},
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003065 {"restricted", 0, 0, 'Z'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003066 {"autoindent", 0, 0, 'i'},
3067 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003068#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003069 {0, 0, 0, 0}
3070 };
3071#endif
3072
Chris Allegretta8bc03b62001-02-09 02:57:52 +00003073#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003074 setlocale(LC_ALL, "");
3075 bindtextdomain(PACKAGE, LOCALEDIR);
3076 textdomain(PACKAGE);
3077#endif
3078
Chris Allegretta7662c862003-01-13 01:35:15 +00003079#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003080 /* if we don't have rcfile support, we're root, and
3081 --disable-wrapping-as-root is used, turn wrapping off */
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003082 if (geteuid() == NANO_ROOT_UID)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003083 SET(NO_WRAP);
3084#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003085
3086#ifdef HAVE_GETOPT_LONG
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003087 while ((optchr = getopt_long(argc, argv, "h?ABDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz",
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00003088 long_options, NULL)) != -1) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00003089#else
3090 while ((optchr =
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003091 getopt(argc, argv, "h?ABDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz")) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003092#endif
3093
3094 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003095
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003096 case 'a':
3097 case 'b':
3098 case 'e':
3099 case 'f':
3100 case 'g':
3101 case 'j':
3102 /* Pico compatibility flags */
3103 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003104#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003105 case 'A':
3106 SET(SMART_HOME);
3107 break;
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003108 case 'B':
3109 SET(BACKUP_FILE);
3110 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003111 case 'D':
3112 SET(DOS_FILE);
3113 break;
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003114 case 'E':
3115 backup_dir = mallocstrcpy(backup_dir, optarg);
3116 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003117#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003118#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003119 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003120 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003121 break;
3122#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003123#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003124#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003125 case 'H':
3126 SET(HISTORYLOG);
3127 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003128#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003129 case 'I':
Chris Allegretta7662c862003-01-13 01:35:15 +00003130 SET(NO_RCFILE);
3131 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003132#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003133#ifndef NANO_SMALL
3134 case 'M':
3135 SET(MAC_FILE);
3136 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003137 case 'N':
3138 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003139 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003140#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003141#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003142 case 'Q':
Chris Allegretta7662c862003-01-13 01:35:15 +00003143 quotestr = mallocstrcpy(quotestr, optarg);
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003144 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003145#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003146#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003147 case 'R':
3148 SET(USE_REGEXP);
3149 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003150#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003151#ifndef NANO_SMALL
3152 case 'S':
3153 SET(SMOOTHSCROLL);
3154 break;
3155#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003156 case 'T':
Chris Allegretta6df90f52002-07-19 01:08:59 +00003157 {
3158 int i;
3159 char *first_error;
3160
Chris Allegretta7662c862003-01-13 01:35:15 +00003161 /* Using strtol() instead of atoi() lets us accept 0
3162 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003163 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003164 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003165 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003166 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003167 tabsize = i;
3168 if (tabsize <= 0) {
3169 fprintf(stderr, _("Tab size is too small for nano...\n"));
3170 exit(1);
3171 }
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003172 }
3173 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003174 case 'V':
3175 version();
3176 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003177#ifdef ENABLE_COLOR
3178 case 'Y':
3179 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3180 break;
3181#endif
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003182 case 'Z':
3183 SET(RESTRICTED);
3184 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003185 case 'c':
3186 SET(CONSTUPDATE);
3187 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003188 case 'd':
3189 SET(REBIND_DELETE);
3190 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003191#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003192 case 'i':
3193 SET(AUTOINDENT);
3194 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003195 case 'k':
3196 SET(CUT_TO_END);
3197 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003198#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003199 case 'l':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003200 SET(NOFOLLOW_SYMLINKS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003201 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003202#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003203 case 'm':
3204 SET(USE_MOUSE);
3205 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003206#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003207#ifndef DISABLE_OPERATINGDIR
3208 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003209 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003210 break;
3211#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003212 case 'p':
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003213 SET(PRESERVE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003214 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003215#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003216 case 'r':
3217 {
3218 int i;
3219 char *first_error;
3220
Chris Allegretta7662c862003-01-13 01:35:15 +00003221 /* Using strtol() instead of atoi() lets us accept 0
3222 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003223 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003224 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003225 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003226 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003227 wrap_at = i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003228 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003229 fill_flag_used = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003230 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003231#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003232#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003233 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003234 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003235 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003236#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003237 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00003238 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003239 break;
3240 case 'v':
3241 SET(VIEW_MODE);
3242 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003243#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003244 case 'w':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003245 SET(NO_WRAP);
3246 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003247#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003248 case 'x':
3249 SET(NO_HELP);
3250 break;
3251 case 'z':
3252 SET(SUSPEND);
3253 break;
3254 default:
3255 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003256 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003257 }
3258
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003259 /* If filename starts with 'r', we use restricted mode. */
3260 if (*(tail(argv[0])) == 'r')
3261 SET(RESTRICTED);
3262
3263 /* If we're using restricted mode, disable suspending, backup files,
3264 * and reading rcfiles. */
3265 if (ISSET(RESTRICTED)) {
3266 UNSET(SUSPEND);
3267 UNSET(BACKUP_FILE);
3268 SET(NO_RCFILE);
3269 }
3270
Chris Allegretta7662c862003-01-13 01:35:15 +00003271/* We've read through the command line options. Now back up the flags
3272 and values that are set, and read the rcfile(s). If the values
3273 haven't changed afterward, restore the backed-up values. */
3274#ifdef ENABLE_NANORC
3275 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003276#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003277 char *operating_dir_cpy = operating_dir;
3278#endif
3279#ifndef DISABLE_WRAPPING
3280 int wrap_at_cpy = wrap_at;
3281#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003282#ifndef NANO_SMALL
3283 char *backup_dir_cpy = backup_dir;
3284#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003285#ifndef DISABLE_JUSTIFY
3286 char *quotestr_cpy = quotestr;
3287#endif
3288#ifndef DISABLE_SPELLER
3289 char *alt_speller_cpy = alt_speller;
3290#endif
3291 int tabsize_cpy = tabsize;
3292 long flags_cpy = flags;
3293
Chris Allegretta5ec68622003-02-05 02:39:34 +00003294#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003295 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003296#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003297#ifndef NANO_SMALL
3298 backup_dir = NULL;
3299#endif
Chris Allegretta5ec68622003-02-05 02:39:34 +00003300#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003301 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003302#endif
3303#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003304 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003305#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003306
3307 do_rcfile();
3308
3309#ifndef DISABLE_OPERATINGDIR
3310 if (operating_dir_cpy != NULL) {
3311 free(operating_dir);
3312 operating_dir = operating_dir_cpy;
3313 }
3314#endif
3315#ifndef DISABLE_WRAPPING
3316 if (fill_flag_used)
3317 wrap_at = wrap_at_cpy;
3318#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003319#ifndef NANO_SMALL
3320 if (backup_dir_cpy != NULL) {
3321 free(backup_dir);
3322 backup_dir = backup_dir_cpy;
3323 }
3324#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003325#ifndef DISABLE_JUSTIFY
3326 if (quotestr_cpy != NULL) {
3327 free(quotestr);
3328 quotestr = quotestr_cpy;
3329 }
3330#endif
3331#ifndef DISABLE_SPELLER
3332 if (alt_speller_cpy != NULL) {
3333 free(alt_speller);
3334 alt_speller = alt_speller_cpy;
3335 }
3336#endif
3337 if (tabsize_cpy > 0)
3338 tabsize = tabsize_cpy;
3339 flags |= flags_cpy;
3340 }
3341#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003342 else if (geteuid() == NANO_ROOT_UID)
Chris Allegretta7662c862003-01-13 01:35:15 +00003343 SET(NO_WRAP);
3344#endif
3345#endif /* ENABLE_NANORC */
3346
Chris Allegrettad8451932003-03-11 03:50:40 +00003347#ifndef NANO_SMALL
3348 history_init();
3349#ifdef ENABLE_NANORC
3350 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3351 load_history();
3352#endif
3353#endif
3354
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003355#ifndef NANO_SMALL
3356 /* Set up the backup directory. This entails making sure it exists
3357 * and is a directory, so that backup files will be saved there. */
3358 init_backup_dir();
3359#endif
3360
Chris Allegretta7662c862003-01-13 01:35:15 +00003361#ifndef DISABLE_OPERATINGDIR
3362 /* Set up the operating directory. This entails chdir()ing there,
3363 so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003364 init_operating_dir();
3365#endif
3366
Chris Allegretta7662c862003-01-13 01:35:15 +00003367#ifndef DISABLE_JUSTIFY
3368 if (quotestr == NULL)
3369#ifdef HAVE_REGEX_H
3370 quotestr = mallocstrcpy(NULL, "^([ \t]*[|>:}#])+");
3371#else
3372 quotestr = mallocstrcpy(NULL, "> ");
3373#endif
3374#endif /* !DISABLE_JUSTIFY */
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003375
Chris Allegretta7662c862003-01-13 01:35:15 +00003376 if (tabsize == -1)
3377 tabsize = 8;
3378
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003379 /* Clear the filename we'll be using */
3380 filename = charalloc(1);
3381 filename[0] = '\0';
3382
Chris Allegretta7662c862003-01-13 01:35:15 +00003383 /* If there's a +LINE flag, it is the first non-option argument. */
3384 if (0 < optind && optind < argc && argv[optind][0] == '+') {
3385 startline = atoi(&argv[optind][1]);
3386 optind++;
3387 }
3388 if (0 < optind && optind < argc)
3389 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003390
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003391 /* See if there's a non-option in argv (first non-option is the
3392 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003393 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003394 /* Look for the +line flag... */
3395 if (argv[optind][0] == '+') {
3396 startline = atoi(&argv[optind][1]);
3397 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003398 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003399 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003400 } else
3401 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003402 }
3403
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003404 /* Back up the old terminal settings so that they can be restored. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003405 tcgetattr(0, &oldterm);
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003406
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003407 /* Curses initialization stuff: Start curses, save the state of the
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003408 * terminal mode, put the terminal in cbreak mode (read one character
3409 * at a time and interpret the special control keys), disable
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003410 * translation of carriage return (^M) into newline (^J) so that we
David Lawrence Ramseyfd462b12004-05-19 15:41:17 +00003411 * can tell the difference between the Enter key and Ctrl-J, and
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003412 * disable echoing of characters as they're typed. Finally, disable
3413 * interpretation of the special control keys, and if we're not in
3414 * preserve mode, disable interpretation of the flow control
3415 * characters too. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003416 initscr();
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003417 cbreak();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003418 nonl();
David Lawrence Ramseyd03216a2004-01-28 18:21:21 +00003419 noecho();
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003420 disable_signals();
3421 if (!ISSET(PRESERVE))
3422 disable_flow_control();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003423
3424#ifndef NANO_SMALL
3425 /* Save the terminal's current state, so that we can restore it
3426 * after a resize. */
3427 savetty();
3428#endif
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003429
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003430 /* Set up the global variables and the shortcuts. */
Chris Allegretta56214c62001-09-27 02:46:53 +00003431 global_init(0);
Chris Allegretta07798352000-11-27 22:58:23 +00003432 shortcut_init(0);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003433
3434 /* Set up the signal handlers. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003435 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003436
3437#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003438 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003439#endif
3440
Chris Allegretta2a42af12000-09-12 23:02:49 +00003441 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003442#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003443 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003444#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003445
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003446#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003447 fprintf(stderr, "Main: bottom win\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003448#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003449 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003450 display_main_list();
3451
3452#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003453 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003454#endif
3455
David Lawrence Ramsey97133f52004-05-14 17:39:19 +00003456 open_file(filename, 0, 0);
Chris Allegretta7662c862003-01-13 01:35:15 +00003457#ifdef ENABLE_MULTIBUFFER
3458 /* If we're using multibuffers and more than one file is specified
3459 on the command line, load them all and switch to the first one
3460 afterward */
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003461 if (optind + 1 < argc) {
3462 int old_multibuffer = ISSET(MULTIBUFFER);
3463 SET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003464 for (optind++; optind < argc; optind++) {
3465 add_open_file(1);
3466 new_file();
3467 filename = mallocstrcpy(filename, argv[optind]);
3468 open_file(filename, 0, 0);
3469 load_file(0);
3470 }
3471 open_nextfile_void();
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003472 if (!old_multibuffer)
3473 UNSET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003474 }
3475#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003476
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003477 titlebar(NULL);
3478
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003479 if (startline > 0)
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003480 do_gotoline(startline, 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003481
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003482#ifndef NANO_SMALL
3483 /* Return here after a SIGWINCH. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003484 sigsetjmp(jmpbuf, 1);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003485#endif
Chris Allegretta08020882001-01-29 23:37:54 +00003486
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003487 /* SHUT UP GCC! */
3488 startline = 0;
3489 fill_flag_used = 0;
3490 keyhandled = 0;
3491
Chris Allegretta7662c862003-01-13 01:35:15 +00003492 /* This variable should be initialized after the sigsetjmp(), so we
3493 can't do Esc-Esc then quickly resize and muck things up. */
Chris Allegretta08020882001-01-29 23:37:54 +00003494 modify_control_seq = 0;
3495
Robert Siemborski6967eec2000-07-08 14:23:32 +00003496 edit_refresh();
3497 reset_cursor();
3498
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00003499 while (TRUE) {
Chris Allegrettad0845df2003-02-13 00:56:57 +00003500 keyhandled = 0;
Chris Allegretta9239d742000-09-06 15:19:18 +00003501
Chris Allegrettad26ab912003-01-28 01:16:47 +00003502 if (ISSET(CONSTUPDATE))
3503 do_cursorpos(1);
3504
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003505#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003506 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003507#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003508
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003509 kbinput = get_kbinput(edit, &meta_key);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003510#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003511 fprintf(stderr, "AHA! %c (%d)\n", kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003512#endif
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003513 if (meta_key == TRUE) {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003514 /* Check for the metaval and miscval defs... */
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003515 for (s = main_list; s != NULL; s = s->next)
David Lawrence Ramsey82138502003-12-24 08:03:54 +00003516 if ((s->metaval != NANO_NO_KEY && kbinput == s->metaval) ||
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003517 (s->miscval != NANO_NO_KEY && kbinput == s->miscval)) {
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003518 if (ISSET(VIEW_MODE) && !s->viewok)
3519 print_view_warning();
3520 else {
3521 if (s->func != do_cut_text)
3522 UNSET(KEEP_CUTBUFFER);
3523 s->func();
3524 }
3525 keyhandled = 1;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003526 }
3527#ifndef NANO_SMALL
3528 if (!keyhandled)
3529 /* And for toggle switches */
3530 for (t = toggles; t != NULL; t = t->next)
3531 if (kbinput == t->val) {
3532 UNSET(KEEP_CUTBUFFER);
3533 do_toggle(t);
3534 keyhandled = 1;
3535 }
3536#endif
3537#ifdef DEBUG
3538 fprintf(stderr, "I got Alt-%c! (%d)\n", kbinput,
3539 kbinput);
3540#endif
3541 }
3542
3543 /* Look through the main shortcut list to see if we've hit a
3544 shortcut key or function key */
3545
3546 if (!keyhandled)
3547#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || !defined(DISABLE_MOUSE)
3548 for (s = currshortcut; s != NULL && !keyhandled; s = s->next) {
3549#else
3550 for (s = main_list; s != NULL && !keyhandled; s = s->next) {
3551#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003552 if ((s->ctrlval != NANO_NO_KEY && kbinput == s->ctrlval) ||
3553 (s->funcval != NANO_NO_KEY && kbinput == s->funcval)) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003554 if (ISSET(VIEW_MODE) && !s->viewok)
3555 print_view_warning();
3556 else {
3557 if (s->func != do_cut_text)
3558 UNSET(KEEP_CUTBUFFER);
3559 s->func();
3560 }
3561 keyhandled = 1;
3562 /* Break out explicitly once we successfully handle
3563 a shortcut */
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003564 break;
3565 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003566 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003567
3568 if (!keyhandled)
3569 UNSET(KEEP_CUTBUFFER);
Chris Allegrettae42df732002-10-15 00:27:55 +00003570
Chris Allegrettae42df732002-10-15 00:27:55 +00003571 /* Don't even think about changing this string */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003572 if (kbinput == NANO_CONTROL_Q)
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003573 statusbar(_("XON ignored, mumble mumble."));
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003574 if (kbinput == NANO_CONTROL_S)
3575 statusbar(_("XOFF ignored, mumble mumble."));
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003576
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003577 /* If we're in raw mode or using Alt-Alt-x, we have to catch
3578 Control-S and Control-Q */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003579 if (kbinput == NANO_CONTROL_Q || kbinput == NANO_CONTROL_S)
Chris Allegretta9239d742000-09-06 15:19:18 +00003580 keyhandled = 1;
3581
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003582 /* Catch ^Z by hand when triggered also */
3583 if (kbinput == NANO_SUSPEND_KEY) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003584 if (ISSET(SUSPEND))
3585 do_suspend(0);
3586 keyhandled = 1;
3587 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003588
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003589 /* Last gasp, stuff that's not in the main lists */
3590 if (!keyhandled)
3591 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003592#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003593 case KEY_MOUSE:
3594 do_mouse();
3595 break;
3596#endif
Chris Allegrettaad3f4782001-10-02 03:54:13 +00003597
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003598 case NANO_CONTROL_3: /* Ctrl-[ (Esc), which should
3599 * have been handled before we
3600 * got here */
3601 case NANO_CONTROL_5: /* Ctrl-] */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003602 break;
3603 default:
3604#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003605 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003606#endif
3607 /* We no longer stop unhandled sequences so that people with
3608 odd character sets can type... */
3609
Chris Allegretta7662c862003-01-13 01:35:15 +00003610 if (ISSET(VIEW_MODE))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003611 print_view_warning();
Chris Allegretta7662c862003-01-13 01:35:15 +00003612 else
3613 do_char(kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003614 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003615
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003616 reset_cursor();
3617 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003618 }
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003619 assert(FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003620}