blob: 3729829301d3fc020c9a769cf435196c8db8dd75 [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
David Lawrence Ramsey85529b32004-06-22 15:38:47 +000064static int same_line_wrap = FALSE; /* Whether wrapped text should
65 be prepended to the next
66 line */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000067#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +000068
Chris Allegretta6df90f52002-07-19 01:08:59 +000069static struct termios oldterm; /* The user's original term settings */
Chris Allegretta88520c92001-05-05 17:45:54 +000070static struct sigaction act; /* For all our fun signal handlers */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000071
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000072#ifndef NANO_SMALL
David Lawrence Ramsey85529b32004-06-22 15:38:47 +000073static sigjmp_buf jmpbuf; /* Used to return to mainloop after
74 SIGWINCH */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000075#endif
Chris Allegretta08020882001-01-29 23:37:54 +000076
David Lawrence Ramseyda141062004-05-25 19:41:11 +000077/* What we do when we're all set to exit. */
78void finish(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000079{
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000080 if (!ISSET(NO_HELP))
81 blank_bottombars();
82 else
83 blank_statusbar();
Chris Allegretta6b58acd2001-04-12 03:01:53 +000084
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000085 wrefresh(bottomwin);
86 endwin();
87
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000088 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000089 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000090
Chris Allegrettad8451932003-03-11 03:50:40 +000091#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
92 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
93 save_history();
94#endif
95
Chris Allegretta6232d662002-05-12 19:52:15 +000096#ifdef DEBUG
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000097 thanks_for_all_the_fish();
Chris Allegretta6232d662002-05-12 19:52:15 +000098#endif
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000099
David Lawrence Ramseyda141062004-05-25 19:41:11 +0000100 exit(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000101}
102
103/* Die (gracefully?) */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000104void die(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000105{
106 va_list ap;
107
Chris Allegrettaa0d89972003-02-03 03:32:08 +0000108 endwin();
109 curses_ended = TRUE;
110
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000111 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000112 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000113
Chris Allegretta6df90f52002-07-19 01:08:59 +0000114 va_start(ap, msg);
115 vfprintf(stderr, msg, ap);
116 va_end(ap);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000117
Chris Allegretta32da4562002-01-02 15:12:21 +0000118 /* save the currently loaded file if it's been modified */
119 if (ISSET(MODIFIED))
120 die_save_file(filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000121
Chris Allegretta355fbe52001-07-14 19:32:47 +0000122#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +0000123 /* then save all of the other modified loaded files, if any */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000124 if (open_files != NULL) {
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000125 openfilestruct *tmp;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000126
127 tmp = open_files;
128
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000129 while (open_files->prev != NULL)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000130 open_files = open_files->prev;
131
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000132 while (open_files->next != NULL) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000133
David Lawrence Ramseya3370c42004-04-05 01:08:14 +0000134 /* if we already saved the file above (i.e, if it was the
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000135 currently loaded file), don't save it again */
136 if (tmp != open_files) {
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000137 /* make sure open_files->fileage and fileage, and
138 open_files->filebot and filebot, are in sync; they
139 might not be if lines have been cut from the top or
140 bottom of the file */
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000141 fileage = open_files->fileage;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000142 filebot = open_files->filebot;
Chris Allegretta32da4562002-01-02 15:12:21 +0000143 /* save the file if it's been modified */
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000144 if (open_files->file_flags & MODIFIED)
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000145 die_save_file(open_files->filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000146 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000147 open_files = open_files->next;
148 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000149 }
150#endif
151
Chris Allegretta6df90f52002-07-19 01:08:59 +0000152 exit(1); /* We have a problem: exit w/ errorlevel(1) */
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000153}
154
Chris Allegretta6df90f52002-07-19 01:08:59 +0000155void die_save_file(const char *die_filename)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000156{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000157 char *ret;
Chris Allegretta48b06702002-02-22 04:30:50 +0000158 int i = -1;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000159
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +0000160 /* If we're using restricted mode, don't write any emergency backup
161 * files, since that would allow reading from or writing to files
162 * not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000163 if (ISSET(RESTRICTED))
164 return;
165
Chris Allegretta6df90f52002-07-19 01:08:59 +0000166 /* If we can't save, we have REAL bad problems, but we might as well
167 TRY. */
168 if (die_filename[0] == '\0')
169 ret = get_next_filename("nano.save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000170 else {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000171 char *buf = charalloc(strlen(die_filename) + 6);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000172
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000173 strcpy(buf, die_filename);
174 strcat(buf, ".save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000175 ret = get_next_filename(buf);
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000176 free(buf);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000177 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000178 if (ret[0] != '\0')
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +0000179 i = write_file(ret, TRUE, FALSE, TRUE);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000180
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000181 if (i != -1)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000182 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000183 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000184 fprintf(stderr, _("\nNo %s written (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000185
186 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000187}
188
Chris Allegrettae61e8302001-01-14 05:18:27 +0000189/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000190 * screen is too small. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000191void die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000192{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000193 die(_("Window size is too small for nano...\n"));
Chris Allegrettae61e8302001-01-14 05:18:27 +0000194}
195
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000196void print_view_warning(void)
197{
198 statusbar(_("Key illegal in VIEW mode"));
199}
200
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +0000201/* Initialize global variables -- no better way for now. If
Chris Allegretta6df90f52002-07-19 01:08:59 +0000202 * save_cutbuffer is nonzero, don't set cutbuffer to NULL. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000203void global_init(int save_cutbuffer)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000204{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000205 current_x = 0;
206 current_y = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000207
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000208 editwinrows = LINES - 5 + no_help();
209 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000210 die_too_small();
211
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000212 fileage = NULL;
Chris Allegretta56214c62001-09-27 02:46:53 +0000213 if (!save_cutbuffer)
214 cutbuffer = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000215 current = NULL;
216 edittop = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000217 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000218 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000219 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000220
Chris Allegretta6fe61492001-05-21 12:56:25 +0000221#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000222 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000223 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000224 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000225 if (fill < 0)
226 fill = 0;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000227#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000228
Chris Allegretta88b09152001-05-17 11:35:43 +0000229 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000230 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000231 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000232}
233
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000234void window_init(void)
235{
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000236 editwinrows = LINES - 5 + no_help();
237 if (editwinrows < MIN_EDITOR_ROWS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000238 die_too_small();
239
Chris Allegretta1a128af2003-01-26 04:15:56 +0000240 if (topwin != NULL)
241 delwin(topwin);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000242 if (edit != NULL)
243 delwin(edit);
Chris Allegretta1a128af2003-01-26 04:15:56 +0000244 if (bottomwin != NULL)
245 delwin(bottomwin);
246
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000247 /* Set up the windows. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000248 topwin = newwin(2, COLS, 0, 0);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000249 edit = newwin(editwinrows, COLS, 2, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000250 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
251
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000252 /* Turn the keypad back on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000253 keypad(edit, TRUE);
254 keypad(bottomwin, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000255}
256
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000257#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000258void mouse_init(void)
259{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000260 if (ISSET(USE_MOUSE)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000261 mousemask(BUTTON1_RELEASED, NULL);
262 mouseinterval(50);
263 } else
264 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000265}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000266#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000267
268#ifndef DISABLE_HELP
269/* This function allocates help_text, and stores the help string in it.
270 * help_text should be NULL initially. */
271void help_init(void)
272{
Chris Allegretta908f7702003-01-15 11:18:58 +0000273 size_t allocsize = 1; /* space needed for help_text */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000274 char *ptr = NULL;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000275 const shortcut *s;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000276#ifndef NANO_SMALL
277 const toggle *t;
278#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000279
280 /* First set up the initial help text for the current function */
281 if (currshortcut == whereis_list || currshortcut == replace_list
282 || currshortcut == replace_list_2)
283 ptr = _("Search Command Help Text\n\n "
284 "Enter the words or characters you would like to search "
285 "for, then hit enter. If there is a match for the text you "
286 "entered, the screen will be updated to the location of the "
287 "nearest match for the search string.\n\n "
Chris Allegretta37d594c2003-01-05 22:00:41 +0000288 "The previous search string will be shown in brackets after "
289 "the Search: prompt. Hitting Enter without entering any text "
290 "will perform the previous search.\n\n The following function "
291 "keys are available in Search mode:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000292 else if (currshortcut == goto_list)
293 ptr = _("Go To Line Help Text\n\n "
294 "Enter the line number that you wish to go to and hit "
295 "Enter. If there are fewer lines of text than the "
296 "number you entered, you will be brought to the last line "
297 "of the file.\n\n The following function keys are "
298 "available in Go To Line mode:\n\n");
299 else if (currshortcut == insertfile_list)
300 ptr = _("Insert File Help Text\n\n "
301 "Type in the name of a file to be inserted into the current "
302 "file buffer at the current cursor location.\n\n "
303 "If you have compiled nano with multiple file buffer "
304 "support, and enable multiple buffers with the -F "
305 "or --multibuffer command line flags, the Meta-F toggle, or "
306 "a nanorc file, inserting a file will cause it to be "
307 "loaded into a separate buffer (use Meta-< and > to switch "
308 "between file buffers).\n\n If you need another blank "
309 "buffer, do not enter any filename, or type in a "
310 "nonexistent filename at the prompt and press "
311 "Enter.\n\n The following function keys are "
312 "available in Insert File mode:\n\n");
313 else if (currshortcut == writefile_list)
314 ptr = _("Write File Help Text\n\n "
315 "Type the name that you wish to save the current file "
316 "as and hit Enter to save the file.\n\n If you have "
317 "selected text with Ctrl-^, you will be prompted to "
318 "save only the selected portion to a separate file. To "
319 "reduce the chance of overwriting the current file with "
320 "just a portion of it, the current filename is not the "
321 "default in this mode.\n\n The following function keys "
322 "are available in Write File mode:\n\n");
323#ifndef DISABLE_BROWSER
324 else if (currshortcut == browser_list)
325 ptr = _("File Browser Help Text\n\n "
326 "The file browser is used to visually browse the "
327 "directory structure to select a file for reading "
328 "or writing. You may use the arrow keys or Page Up/"
329 "Down to browse through the files, and S or Enter to "
330 "choose the selected file or enter the selected "
331 "directory. To move up one level, select the directory "
332 "called \"..\" at the top of the file list.\n\n The "
333 "following function keys are available in the file "
334 "browser:\n\n");
335 else if (currshortcut == gotodir_list)
336 ptr = _("Browser Go To Directory Help Text\n\n "
337 "Enter the name of the directory you would like to "
338 "browse to.\n\n If tab completion has not been disabled, "
339 "you can use the TAB key to (attempt to) automatically "
340 "complete the directory name.\n\n The following function "
341 "keys are available in Browser Go To Directory mode:\n\n");
342#endif
Chris Allegretta201f1d92003-02-05 02:51:19 +0000343#ifndef DISABLE_SPELLER
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000344 else if (currshortcut == spell_list)
345 ptr = _("Spell Check Help Text\n\n "
346 "The spell checker checks the spelling of all text "
347 "in the current file. When an unknown word is "
348 "encountered, it is highlighted and a replacement can "
349 "be edited. It will then prompt to replace every "
350 "instance of the given misspelled word in the "
351 "current file.\n\n The following other functions are "
352 "available in Spell Check mode:\n\n");
Chris Allegretta201f1d92003-02-05 02:51:19 +0000353#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000354#ifndef NANO_SMALL
355 else if (currshortcut == extcmd_list)
356 ptr = _("External Command Help Text\n\n "
357 "This menu allows you to insert the output of a command "
358 "run by the shell into the current buffer (or a new "
359 "buffer in multibuffer mode).\n\n The following keys are "
360 "available in this mode:\n\n");
361#endif
362 else /* Default to the main help list */
363 ptr = _(" nano help text\n\n "
364 "The nano editor is designed to emulate the functionality and "
365 "ease-of-use of the UW Pico text editor. There are four main "
366 "sections of the editor: The top line shows the program "
367 "version, the current filename being edited, and whether "
368 "or not the file has been modified. Next is the main editor "
369 "window showing the file being edited. The status line is "
370 "the third line from the bottom and shows important messages. "
371 "The bottom two lines show the most commonly used shortcuts "
372 "in the editor.\n\n "
373 "The notation for shortcuts is as follows: Control-key "
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +0000374 "sequences are notated with a caret (^) symbol and can be "
375 "entered either by using the Control (Ctrl) key or pressing the "
376 "Esc key twice. Escape-key sequences are notated with the Meta "
377 "(M) symbol and can be entered using either the Esc, Alt or "
378 "Meta key depending on your keyboard setup. Also, pressing Esc "
379 "twice and then typing a three-digit number from 000 to 255 "
380 "will enter the character with the corresponding ASCII code. "
381 "The following keystrokes are available in the main editor "
382 "window. Alternative keys are shown in parentheses:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000383
Chris Allegretta908f7702003-01-15 11:18:58 +0000384 allocsize += strlen(ptr);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000385
386 /* The space needed for the shortcut lists, at most COLS characters,
387 * plus '\n'. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000388 allocsize += (COLS + 1) * length_of_list(currshortcut);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000389
390#ifndef NANO_SMALL
391 /* If we're on the main list, we also count the toggle help text.
392 * Each line has "M-%c\t\t\t", which fills 24 columns, plus at most
393 * COLS - 24 characters, plus '\n'.*/
Chris Allegretta3a784062003-02-10 02:32:58 +0000394 if (currshortcut == main_list) {
395 size_t endislen = strlen(_("enable/disable"));
396
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000397 for (t = toggles; t != NULL; t = t->next)
Chris Allegretta3a784062003-02-10 02:32:58 +0000398 allocsize += 8 + strlen(t->desc) + endislen;
399 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000400#endif /* !NANO_SMALL */
401
402 /* help_text has been freed and set to NULL unless the user resized
403 * while in the help screen. */
404 free(help_text);
405
406 /* Allocate space for the help text */
Chris Allegretta908f7702003-01-15 11:18:58 +0000407 help_text = charalloc(allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000408
409 /* Now add the text we want */
410 strcpy(help_text, ptr);
411 ptr = help_text + strlen(help_text);
412
413 /* Now add our shortcut info */
414 for (s = currshortcut; s != NULL; s = s->next) {
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000415 /* true if the character in s->metaval is shown in first column */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +0000416 int meta_shortcut = FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000417
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000418 if (s->ctrlval != NANO_NO_KEY) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000419#ifndef NANO_SMALL
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000420 if (s->ctrlval == NANO_HISTORY_KEY)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000421 ptr += sprintf(ptr, "%.2s", _("Up"));
422 else
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000423#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000424 if (s->ctrlval == NANO_CONTROL_SPACE)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000425 ptr += sprintf(ptr, "^%.5s", _("Space"));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000426 else if (s->ctrlval == NANO_CONTROL_8)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000427 ptr += sprintf(ptr, "^?");
428 else
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000429 ptr += sprintf(ptr, "^%c", s->ctrlval + 64);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000430 }
431#ifndef NANO_SMALL
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000432 else if (s->metaval != NANO_NO_KEY) {
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +0000433 meta_shortcut = TRUE;
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000434 if (s->metaval == NANO_ALT_SPACE)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000435 ptr += snprintf(ptr, 8, "M-%.5s", _("Space"));
436 else
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000437 ptr += sprintf(ptr, "M-%c", toupper(s->metaval));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000438 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000439#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000440
441 *(ptr++) = '\t';
442
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000443 if (s->funcval != NANO_NO_KEY)
444 ptr += sprintf(ptr, "(F%d)", s->funcval - KEY_F0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000445
446 *(ptr++) = '\t';
447
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000448 if (!meta_shortcut && s->metaval != NANO_NO_KEY)
449 ptr += sprintf(ptr, "(M-%c)", toupper(s->metaval));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000450 else if (meta_shortcut && s->miscval != NANO_NO_KEY)
451 ptr += sprintf(ptr, "(M-%c)", toupper(s->miscval));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000452
453 *(ptr++) = '\t';
454
455 assert(s->help != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000456 ptr += sprintf(ptr, "%.*s\n", COLS > 24 ? COLS - 24 : 0, s->help);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000457 }
458
459#ifndef NANO_SMALL
460 /* And the toggles... */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000461 if (currshortcut == main_list) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000462 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000463 assert(t->desc != NULL);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000464 ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val), t->desc,
Chris Allegretta3a784062003-02-10 02:32:58 +0000465 _("enable/disable"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000466 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000467 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000468#endif /* !NANO_SMALL */
469
470 /* If all went well, we didn't overwrite the allocated space for
471 help_text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000472 assert(strlen(help_text) < allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000473}
474#endif
475
476/* Create a new filestruct node. Note that we specifically do not set
477 * prevnode->next equal to the new line. */
478filestruct *make_new_node(filestruct *prevnode)
479{
480 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
481
482 newnode->data = NULL;
483 newnode->prev = prevnode;
484 newnode->next = NULL;
485 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
486
487 return newnode;
488}
489
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000490/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000491filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000492{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000493 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000494
Chris Allegretta6df90f52002-07-19 01:08:59 +0000495 assert(src != NULL);
496
Chris Allegretta88b09152001-05-17 11:35:43 +0000497 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000498 dst->next = src->next;
499 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000500 strcpy(dst->data, src->data);
501 dst->lineno = src->lineno;
502
503 return dst;
504}
505
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000506/* Splice a node into an existing filestruct. */
507void splice_node(filestruct *begin, filestruct *newnode, filestruct *end)
508{
509 if (newnode != NULL) {
510 newnode->next = end;
511 newnode->prev = begin;
512 }
513 if (begin != NULL)
514 begin->next = newnode;
515 if (end != NULL)
516 end->prev = newnode;
517}
518
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000519/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000520void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000521{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000522 assert(fileptr != NULL);
523
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000524 if (fileptr->prev != NULL)
525 fileptr->prev->next = fileptr->next;
526
527 if (fileptr->next != NULL)
528 fileptr->next->prev = fileptr->prev;
529}
530
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000531/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000532void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000533{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000534 if (fileptr != NULL) {
535 if (fileptr->data != NULL)
536 free(fileptr->data);
537 free(fileptr);
538 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000539}
540
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000541/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000542filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000543{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000544 filestruct *head; /* copy of src, top of the copied list */
545 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000546
Chris Allegretta6df90f52002-07-19 01:08:59 +0000547 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000548
Chris Allegretta6df90f52002-07-19 01:08:59 +0000549 prev = copy_node(src);
550 prev->prev = NULL;
551 head = prev;
552 src = src->next;
553 while (src != NULL) {
554 prev->next = copy_node(src);
555 prev->next->prev = prev;
556 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000557
Chris Allegretta6df90f52002-07-19 01:08:59 +0000558 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000559 }
560
Chris Allegretta6df90f52002-07-19 01:08:59 +0000561 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000562 return head;
563}
564
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000565/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000566void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000567{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000568 if (src != NULL) {
569 while (src->next != NULL) {
570 src = src->next;
571 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000572#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000573 fprintf(stderr, "%s: free'd a node, YAY!\n", "delete_node()");
Chris Allegretta6df90f52002-07-19 01:08:59 +0000574#endif
575 }
576 delete_node(src);
577#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000578 fprintf(stderr, "%s: free'd last node.\n", "delete_node()");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000579#endif
580 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000581}
582
Chris Allegretta6df90f52002-07-19 01:08:59 +0000583void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000584{
585 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000586 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000587
Chris Allegretta6df90f52002-07-19 01:08:59 +0000588 assert(fileage == NULL || fileage != fileage->next);
589 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000590 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000591}
592
Chris Allegretta6df90f52002-07-19 01:08:59 +0000593void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000594{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000595 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000596 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000597 else {
598 int lineno = fileptr->prev->lineno;
599
600 assert(fileptr != fileptr->next);
601 for (; fileptr != NULL; fileptr = fileptr->next)
602 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000603 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000604}
605
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000606/* Print one usage string to the screen, removes lots of duplicate
Chris Allegretta6df90f52002-07-19 01:08:59 +0000607 * strings to translate and takes out the parts that shouldn't be
608 * translatable (the flag names). */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000609void print1opt(const char *shortflag, const char *longflag,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000610 const char *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000611{
612 printf(" %s\t", shortflag);
613 if (strlen(shortflag) < 8)
614 printf("\t");
615
616#ifdef HAVE_GETOPT_LONG
617 printf("%s\t", longflag);
618 if (strlen(longflag) < 8)
619 printf("\t\t");
620 else if (strlen(longflag) < 16)
621 printf("\t");
622#endif
623
624 printf("%s\n", desc);
625}
626
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000627void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000628{
629#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000630 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
631 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000632#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000633 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
634 printf(_("Option\t\tMeaning\n"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000635#endif /* HAVE_GETOPT_LONG */
636
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000637 print1opt("-h, -?", "--help", _("Show this message"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000638 print1opt(_("+LINE"), "", _("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000639#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +0000640 print1opt("-A", "--smarthome", _("Enable smart home key"));
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000641 print1opt("-B", "--backup", _("Backup existing files on save"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000642 print1opt("-D", "--dos", _("Write file in DOS format"));
David Lawrence Ramsey45251372004-06-09 08:36:46 +0000643 print1opt(_("-E [dir]"), _("--backupdir=[dir]"), _("Directory for writing backup files"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000644#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000645#ifdef ENABLE_MULTIBUFFER
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000646 print1opt("-F", "--multibuffer", _("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000647#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000648#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000649#ifndef NANO_SMALL
Chris Allegretta36fec722003-01-22 01:13:25 +0000650 print1opt("-H", "--historylog", _("Log & read search/replace string history"));
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000651#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000652 print1opt("-I", "--ignorercfiles", _("Don't look at nanorc files"));
653#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000654#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000655 print1opt("-M", "--mac", _("Write file in Mac format"));
656 print1opt("-N", "--noconvert", _("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000657#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000658#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000659 print1opt(_("-Q [str]"), _("--quotestr=[str]"), _("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000660#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000661#ifdef HAVE_REGEX_H
662 print1opt("-R", "--regexp", _("Do regular expression searches"));
663#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000664#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000665 print1opt("-S", "--smooth", _("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000666#endif
David Lawrence Ramseya7c93642004-02-25 03:19:29 +0000667 print1opt(_("-T [#cols]"), _("--tabsize=[#cols]"), _("Set width of a tab in cols to #cols"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000668 print1opt("-V", "--version", _("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000669#ifdef ENABLE_COLOR
670 print1opt(_("-Y [str]"), _("--syntax [str]"), _("Syntax definition to use"));
671#endif
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000672 print1opt(_("-Z"), _("--restricted"), _("Restricted mode"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000673 print1opt("-c", "--const", _("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000674#ifndef NANO_SMALL
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000675 print1opt("-d", "--rebinddelete", _("Fix Backspace/Delete confusion problem"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000676 print1opt("-i", "--autoindent", _("Automatically indent new lines"));
677 print1opt("-k", "--cut", _("Let ^K cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000678#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000679 print1opt("-l", "--nofollow", _("Don't follow symbolic links, overwrite"));
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000680#ifndef DISABLE_MOUSE
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000681 print1opt("-m", "--mouse", _("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000682#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000683#ifndef DISABLE_OPERATINGDIR
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000684 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), _("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000685#endif
Jordi Mallacheeb50042003-01-18 22:42:34 +0000686 print1opt("-p", "--preserve", _("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000687#ifndef DISABLE_WRAPJUSTIFY
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000688 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), _("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000689#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000690#ifndef DISABLE_SPELLER
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000691 print1opt(_("-s [prog]"), _("--speller=[prog]"), _("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000692#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000693 print1opt("-t", "--tempfile", _("Auto save on exit, don't prompt"));
694 print1opt("-v", "--view", _("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000695#ifndef DISABLE_WRAPPING
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000696 print1opt("-w", "--nowrap", _("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000697#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000698 print1opt("-x", "--nohelp", _("Don't show help window"));
699 print1opt("-z", "--suspend", _("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000700
701 /* this is a special case */
702 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000703
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000704 exit(0);
705}
706
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000707void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000708{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000709 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000710 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000711 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000712 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000713 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000714
Chris Allegrettae6600372003-01-17 03:39:41 +0000715#ifndef ENABLE_NLS
716 printf(" --disable-nls");
717#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000718#ifdef DEBUG
719 printf(" --enable-debug");
720#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000721#ifdef NANO_EXTRA
722 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000723#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000724#ifdef NANO_SMALL
725 printf(" --enable-tiny");
726#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000727#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000728 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000729#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000730#ifdef DISABLE_HELP
731 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000732#endif
733#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000734 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000735#endif
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000736#ifdef DISABLE_MOUSE
Chris Allegretta84de5522001-04-12 14:51:48 +0000737 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000738#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000739#ifdef DISABLE_OPERATINGDIR
740 printf(" --disable-operatingdir");
741#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000742#ifdef DISABLE_SPELLER
743 printf(" --disable-speller");
744#endif
745#ifdef DISABLE_TABCOMP
746 printf(" --disable-tabcomp");
747#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000748#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000749#ifdef DISABLE_WRAPPING
750 printf(" --disable-wrapping");
751#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000752#ifdef DISABLE_ROOTWRAP
753 printf(" --disable-wrapping-as-root");
754#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000755#ifdef ENABLE_COLOR
756 printf(" --enable-color");
757#endif
758#ifdef ENABLE_MULTIBUFFER
759 printf(" --enable-multibuffer");
760#endif
761#ifdef ENABLE_NANORC
762 printf(" --enable-nanorc");
763#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000764#ifdef USE_SLANG
765 printf(" --with-slang");
766#endif
767 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000768}
769
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000770int no_help(void)
771{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000772 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000773}
774
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000775void nano_disabled_msg(void)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000776{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000777 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000778}
779
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000780#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000781static int pid; /* This is the PID of the newly forked process
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000782 * below. It must be global since the signal
783 * handler needs it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000784RETSIGTYPE cancel_fork(int signal)
785{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000786 if (kill(pid, SIGKILL) == -1)
787 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000788}
789
790int open_pipe(const char *command)
791{
792 int fd[2];
793 FILE *f;
794 struct sigaction oldaction, newaction;
795 /* original and temporary handlers for SIGINT */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000796 int cancel_sigs = 0;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000797 /* cancel_sigs == 1 means that sigaction() failed without changing
798 * the signal handlers. cancel_sigs == 2 means the signal handler
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000799 * was changed, but the tcsetattr() didn't succeed.
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000800 *
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000801 * I use this variable since it is important to put things back when
802 * we finish, even if we get errors. */
803
804 /* Make our pipes. */
805
806 if (pipe(fd) == -1) {
807 statusbar(_("Could not pipe"));
808 return 1;
809 }
810
811 /* Fork a child. */
812
813 if ((pid = fork()) == 0) {
814 close(fd[0]);
815 dup2(fd[1], fileno(stdout));
816 dup2(fd[1], fileno(stderr));
817 /* If execl() returns at all, there was an error. */
818
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000819 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000820 exit(0);
821 }
822
823 /* Else continue as parent. */
824
825 close(fd[1]);
826
827 if (pid == -1) {
828 close(fd[0]);
829 statusbar(_("Could not fork"));
830 return 1;
831 }
832
833 /* Before we start reading the forked command's output, we set
834 * things up so that ^C will cancel the new process. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000835
David Lawrence Ramseye608f942004-05-19 16:04:27 +0000836 /* Enable interpretation of the special control keys so that we get
837 * SIGINT when Ctrl-C is pressed. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000838 enable_signals();
839
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000840 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000841 cancel_sigs = 1;
842 nperror("sigaction");
843 } else {
844 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000845 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000846 cancel_sigs = 1;
847 nperror("sigaction");
848 }
849 }
850 /* Note that now oldaction is the previous SIGINT signal handler,
851 * to be restored later. */
852
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000853 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000854 if (f == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000855 nperror("fdopen");
856
857 read_file(f, "stdin", 0);
858 /* if multibuffer mode is on, we could be here in view mode; if so,
859 don't set the modification flag */
860 if (!ISSET(VIEW_MODE))
861 set_modified();
862
863 if (wait(NULL) == -1)
864 nperror("wait");
865
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000866 if (cancel_sigs != 1 && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000867 nperror("sigaction");
868
David Lawrence Ramseye608f942004-05-19 16:04:27 +0000869 /* Disable interpretation of the special control keys so that we can
870 * use Ctrl-C for other things. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000871 disable_signals();
872
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000873 return 0;
874}
David Lawrence Ramseya9cd41c2004-03-05 19:54:58 +0000875#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000876
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000877#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000878void do_mouse(void)
879{
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000880 int mouse_x, mouse_y;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000881
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +0000882 if (get_mouseinput(&mouse_x, &mouse_y, TRUE) == FALSE) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000883 /* Click in the edit window to move the cursor, but only when
884 we're not in a subfunction. */
885 if (wenclose(edit, mouse_y, mouse_x) && currshortcut == main_list) {
886 int sameline;
887 /* Did they click on the line with the cursor? If they
888 clicked on the cursor, we set the mark. */
889 size_t xcur;
890 /* The character they clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000891
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000892 /* Subtract out size of topwin. Perhaps we need a constant
893 somewhere? */
894 mouse_y -= 2;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000895
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000896 sameline = (mouse_y == current_y);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000897
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000898 /* Move to where the click occurred. */
899 for (; current_y < mouse_y && current->next != NULL; current_y++)
900 current = current->next;
901 for (; current_y > mouse_y && current->prev != NULL; current_y--)
902 current = current->prev;
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000903
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000904 xcur = actual_x(current->data, get_page_start(xplustabs()) +
905 mouse_x);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000906
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +0000907 /* Selecting where the cursor is toggles the mark, as does
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000908 selecting beyond the line length with the cursor at the
909 end of the line. */
910 if (sameline && xcur == current_x) {
911 if (ISSET(VIEW_MODE)) {
912 print_view_warning();
913 return;
914 }
915 do_mark();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000916 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000917
918 current_x = xcur;
919 placewewant = xplustabs();
920 edit_refresh();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000921 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000922 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000923 /* FIXME: If we clicked on a location in the statusbar, the cursor
924 should move to the location we clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000925}
926#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000927
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000928/* The user typed a character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000929void do_char(char ch)
930{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000931 size_t current_len = strlen(current->data);
932#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000933 int do_refresh = FALSE;
934 /* Do we have to call edit_refresh(), or can we get away with
Chris Allegretta6df90f52002-07-19 01:08:59 +0000935 * update_line()? */
936#endif
937
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000938 if (ch == '\0') /* Null to newline, if needed. */
939 ch = '\n';
940 else if (ch == '\n') { /* Newline to Enter, if needed. */
941 do_enter();
942 return;
943 }
944
945 assert(current != NULL && current->data != NULL);
946
947 /* When a character is inserted on the current magicline, it means
948 * we need a new one! */
David Lawrence Ramseyb9775152004-03-19 02:15:42 +0000949 if (filebot == current)
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000950 new_magicline();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000951
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000952 /* More dangerousness fun =) */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +0000953 current->data = charealloc(current->data, current_len + 2);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000954 assert(current_x <= current_len);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000955 charmove(&current->data[current_x + 1], &current->data[current_x],
956 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000957 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000958 totsize++;
959 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000960
Chris Allegretta6df90f52002-07-19 01:08:59 +0000961#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000962 /* Note that current_x has not yet been incremented. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000963 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000964 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +0000965#endif
966
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000967 do_right(FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000968
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000969#ifndef DISABLE_WRAPPING
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000970 /* If we're wrapping text, we need to call edit_refresh(). */
Chris Allegrettadffa2072002-07-24 01:02:26 +0000971 if (!ISSET(NO_WRAP) && ch != '\t')
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000972 do_refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000973#endif
974
Chris Allegretta6df90f52002-07-19 01:08:59 +0000975#ifdef ENABLE_COLOR
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000976 /* If color syntaxes are turned on, we need to call
977 * edit_refresh(). */
David Lawrence Ramsey760a2dc2004-01-14 06:38:00 +0000978 if (ISSET(COLOR_SYNTAX))
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000979 do_refresh = TRUE;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000980#endif
981
982#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000983 if (do_refresh)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000984 edit_refresh();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000985 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000986#endif
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000987 update_line(current, current_x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000988}
989
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000990void do_verbatim_input(void)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000991{
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000992 int *v_kbinput = NULL; /* Used to hold verbatim input. */
993 size_t v_len; /* Length of verbatim input. */
David Lawrence Ramsey805547f2004-04-22 03:41:04 +0000994 size_t i;
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000995
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000996 statusbar(_("Verbatim input"));
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000997
998 v_kbinput = get_verbatim_kbinput(edit, v_kbinput, &v_len, TRUE);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000999
1000 /* Turn on DISABLE_CURPOS while inserting character(s) and turn it
1001 * off afterwards, so that if constant cursor position display is
1002 * on, it will be updated properly. */
1003 SET(DISABLE_CURPOS);
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001004 for (i = 0; i < v_len; i++)
1005 do_char((char)v_kbinput[i]);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001006 UNSET(DISABLE_CURPOS);
1007
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001008 free(v_kbinput);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001009}
1010
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001011void do_backspace(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001012{
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001013 if (current != fileage || current_x > 0) {
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001014 do_left(FALSE);
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001015 do_delete();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001016 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001017}
1018
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001019void do_delete(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001020{
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001021 int do_refresh = FALSE;
1022 /* Do we have to call edit_refresh(), or can we get away with
1023 * update_line()? */
1024
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001025 assert(current != NULL && current->data != NULL && current_x <=
1026 strlen(current->data));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001027
1028 placewewant = xplustabs();
1029
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001030 if (current->data[current_x] != '\0') {
1031 size_t linelen = strlen(current->data + current_x);
1032
1033 assert(current_x < strlen(current->data));
1034
1035 /* Let's get dangerous. */
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001036 charmove(&current->data[current_x], &current->data[current_x + 1],
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001037 linelen);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001038
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001039 null_at(&current->data, linelen + current_x - 1);
1040#ifndef NANO_SMALL
1041 if (current_x < mark_beginx && mark_beginbuf == current)
1042 mark_beginx--;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001043#endif
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001044 } else if (current != filebot && (current->next != filebot ||
1045 current->data[0] == '\0')) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001046 /* We can delete the line before filebot only if it is blank: it
David Lawrence Ramsey32d19ce2004-05-24 05:05:07 +00001047 * becomes the new magicline then. */
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001048 filestruct *foo = current->next;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001049
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001050 assert(current_x == strlen(current->data));
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001051
1052 /* If we're deleting at the end of a line, we need to call
1053 * edit_refresh(). */
1054 if (current->data[current_x] == '\0')
1055 do_refresh = TRUE;
1056
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001057 current->data = charealloc(current->data, current_x +
1058 strlen(foo->data) + 1);
1059 strcpy(current->data + current_x, foo->data);
1060#ifndef NANO_SMALL
1061 if (mark_beginbuf == current->next) {
1062 mark_beginx += current_x;
1063 mark_beginbuf = current;
1064 }
1065#endif
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001066 if (filebot == foo)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001067 filebot = current;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001068
1069 unlink_node(foo);
1070 delete_node(foo);
1071 renumber(current);
1072 totlines--;
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001073 wrap_reset();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001074 } else
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001075 return;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001076
1077 totsize--;
1078 set_modified();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001079
1080#ifdef ENABLE_COLOR
1081 /* If color syntaxes are turned on, we need to call
1082 * edit_refresh(). */
1083 if (ISSET(COLOR_SYNTAX))
1084 do_refresh = TRUE;
1085#endif
1086
1087 if (do_refresh)
1088 edit_refresh();
1089 else
1090 update_line(current, current_x);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001091}
1092
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001093void do_tab(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001094{
1095 do_char('\t');
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001096}
1097
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001098/* Someone hits return *gasp!* */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001099void do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001100{
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001101 filestruct *newnode = make_new_node(current);
1102 size_t extra = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001103
Chris Allegretta6df90f52002-07-19 01:08:59 +00001104 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001105
Chris Allegrettaff989832001-09-17 13:48:00 +00001106#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001107 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001108 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001109 /* If we are breaking the line in the indentation, the new
1110 * indentation should have only current_x characters, and
1111 * current_x should not change. */
1112 extra = indent_length(current->data);
1113 if (extra > current_x)
Chris Allegrettadab017e2002-04-23 10:56:06 +00001114 extra = current_x;
Chris Allegrettadab017e2002-04-23 10:56:06 +00001115 totsize += extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001116 }
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001117#endif
1118 newnode->data = charalloc(strlen(current->data + current_x) +
1119 extra + 1);
1120 strcpy(&newnode->data[extra], current->data + current_x);
1121#ifndef NANO_SMALL
1122 if (ISSET(AUTOINDENT))
1123 strncpy(newnode->data, current->data, extra);
1124#endif
1125 null_at(&current->data, current_x);
1126#ifndef NANO_SMALL
1127 if (current == mark_beginbuf && current_x < mark_beginx) {
1128 mark_beginbuf = newnode;
1129 mark_beginx += extra - current_x;
1130 }
1131#endif
1132 current_x = extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001133
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001134 if (current == filebot)
Chris Allegrettae3167732001-03-18 16:59:34 +00001135 filebot = newnode;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001136 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001137
1138 totsize++;
1139 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001140 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001141
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001142#ifndef NANO_SMALL
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001143 /* If we're in smooth scrolling mode and we're on the last line of
1144 * the edit window, move edittop down one line so that current is
1145 * onscreen. This prevents edit_refresh() from centering the
1146 * screen. */
1147 if (ISSET(SMOOTHSCROLL) && current_y == editwinrows - 1)
1148 edittop = edittop->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001149#endif
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001150 edit_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001151
1152 totlines++;
1153 set_modified();
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001154 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001155}
1156
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001157#ifndef NANO_SMALL
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001158void do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001159{
David Lawrence Ramseyc21790d2004-05-30 03:19:52 +00001160 int old_pww = placewewant;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001161 const filestruct *current_save = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001162 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001163
Chris Allegretta6df90f52002-07-19 01:08:59 +00001164 /* Skip letters in this word first. */
1165 while (current->data[current_x] != '\0' &&
1166 isalnum((int)current->data[current_x]))
1167 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001168
Chris Allegretta6df90f52002-07-19 01:08:59 +00001169 for (; current != NULL; current = current->next) {
1170 while (current->data[current_x] != '\0' &&
1171 !isalnum((int)current->data[current_x]))
1172 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001173
Chris Allegretta6df90f52002-07-19 01:08:59 +00001174 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001175 break;
1176
Chris Allegretta6df90f52002-07-19 01:08:59 +00001177 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001178 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001179 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001180 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001181
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001182 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001183
David Lawrence Ramseybf3c93e2004-03-13 19:42:58 +00001184 /* Refresh the screen. If current has run off the bottom, this
1185 * call puts it at the center line. */
David Lawrence Ramseyc21790d2004-05-30 03:19:52 +00001186 edit_redraw(current_save, old_pww);
Chris Allegretta6232d662002-05-12 19:52:15 +00001187}
1188
Chris Allegretta6df90f52002-07-19 01:08:59 +00001189/* The same thing for backwards. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001190void do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001191{
David Lawrence Ramseyc21790d2004-05-30 03:19:52 +00001192 int old_pww = placewewant;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001193 const filestruct *current_save = current;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001194 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001195
Chris Allegretta6df90f52002-07-19 01:08:59 +00001196 /* Skip letters in this word first. */
1197 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1198 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001199
Chris Allegretta6df90f52002-07-19 01:08:59 +00001200 for (; current != NULL; current = current->prev) {
1201 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1202 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001203
Chris Allegretta6df90f52002-07-19 01:08:59 +00001204 if (current_x >= 0)
1205 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001206
Chris Allegretta6df90f52002-07-19 01:08:59 +00001207 if (current->prev != NULL)
1208 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001209 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001210
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001211 if (current == NULL) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001212 current = fileage;
1213 current_x = 0;
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001214 } else {
1215 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1216 current_x--;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001217 }
1218
Chris Allegretta76e291b2001-10-14 19:05:10 +00001219 placewewant = xplustabs();
1220
David Lawrence Ramseyb6aa4282004-03-14 01:42:17 +00001221 /* Refresh the screen. If current has run off the top, this call
1222 * puts it at the center line. */
David Lawrence Ramseyc21790d2004-05-30 03:19:52 +00001223 edit_redraw(current_save, old_pww);
Chris Allegretta6232d662002-05-12 19:52:15 +00001224}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001225
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001226void do_mark(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001227{
David Lawrence Ramseyf03c78b2003-09-28 21:26:49 +00001228 TOGGLE(MARK_ISSET);
1229 if (ISSET(MARK_ISSET)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001230 statusbar(_("Mark Set"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001231 mark_beginbuf = current;
1232 mark_beginx = current_x;
1233 } else {
1234 statusbar(_("Mark UNset"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001235 edit_refresh();
1236 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001237}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001238#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001239
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001240#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001241void wrap_reset(void)
1242{
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001243 same_line_wrap = FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001244}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001245#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001246
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001247#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001248/* We wrap the given line. Precondition: we assume the cursor has been
1249 * moved forward since the last typed character. Return value: whether
1250 * we wrapped. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001251int do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001252{
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001253 size_t len = strlen(inptr->data);
1254 /* Length of the line we wrap. */
1255 size_t i = 0;
1256 /* Generic loop variable. */
1257 int wrap_loc = -1;
1258 /* Index of inptr->data where we wrap. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001259 int word_back = -1;
1260#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001261 const char *indentation = NULL;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001262 /* Indentation to prepend to the new line. */
1263 size_t indent_len = 0; /* strlen(indentation) */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001264#endif
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001265 const char *after_break; /* Text after the wrap point. */
1266 size_t after_break_len; /* strlen(after_break) */
1267 int wrapping = FALSE; /* Do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001268 const char *wrap_line = NULL;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001269 /* The next line, minus indentation */
1270 size_t wrap_line_len = 0; /* strlen(wrap_line) */
1271 char *newline = NULL; /* The line we create. */
1272 size_t new_line_len = 0; /* Eventual length of newline. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001273
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001274/* There are three steps. First, we decide where to wrap. Then, we
1275 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001276
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001277/* Step 1, finding where to wrap. We are going to add a new-line
David Lawrence Ramsey89bb9372004-05-29 16:47:52 +00001278 * after a whitespace character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001279 * location of this replacement.
1280 *
1281 * Where should we break the line? We need the last "legal wrap point"
1282 * such that the last word before it ended at or before fill. If there
1283 * is no such point, we settle for the first legal wrap point.
1284 *
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001285 * A "legal wrap point" is a whitespace character that is not followed
1286 * by whitespace.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001287 *
1288 * If there is no legal wrap point or we found the last character of the
1289 * line, we should return without wrapping.
1290 *
1291 * Note that the initial indentation does not count as a legal wrap
1292 * point if we are going to auto-indent!
1293 *
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001294 * Note that the code below could be optimized, by not calling
1295 * strnlenpt() so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001296
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001297#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001298 if (ISSET(AUTOINDENT))
1299 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001300#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001301 wrap_line = inptr->data + i;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00001302 for (; i < len; i++, wrap_line++) {
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001303 /* Record where the last word ended. */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001304 if (!isblank(*wrap_line))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001305 word_back = i;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001306 /* If we have found a "legal wrap point" and the current word
1307 * extends too far, then we stop. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001308 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001309 break;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001310 /* We record the latest "legal wrap point". */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001311 if (word_back != i && !isblank(wrap_line[1]))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001312 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001313 }
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001314 if (i == len)
1315 return FALSE;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001316
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001317 /* Step 2, making the new wrap line. It will consist of indentation
1318 * + after_break + " " + wrap_line (although indentation and
1319 * wrap_line are conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001320
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001321 /* after_break is the text that will be moved to the next line. */
1322 after_break = inptr->data + wrap_loc + 1;
1323 after_break_len = len - wrap_loc - 1;
1324 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001325
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001326 /* new_line_len will later be increased by the lengths of indentation
1327 * and wrap_line. */
1328 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001329
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001330 /* We prepend the wrapped text to the next line, if the flag is set,
1331 * and there is a next line, and prepending would not make the line
1332 * too long. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001333 if (same_line_wrap && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001334 wrap_line = inptr->next->data;
1335 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001336
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001337 /* +1 for the space between after_break and wrap_line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001338 if ((new_line_len + 1 + wrap_line_len) <= fill) {
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001339 wrapping = TRUE;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001340 new_line_len += (1 + wrap_line_len);
1341 }
1342 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001343
Chris Allegrettaff989832001-09-17 13:48:00 +00001344#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001345 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001346 /* Indentation comes from the next line if wrapping, else from
1347 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001348 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001349 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001350 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001351 /* The wrap_line text should not duplicate indentation.
1352 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001353 wrap_line += indent_len;
1354 else
1355 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001356 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001357#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001358
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001359 /* Now we allocate the new line and copy into it. */
1360 newline = charalloc(new_line_len + 1); /* +1 for \0 */
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001361 new_line_len = 0;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001362 *newline = '\0';
1363
1364#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001365 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001366 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001367 newline[indent_len] = '\0';
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001368 new_line_len = indent_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001369 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001370#endif
1371 strcat(newline, after_break);
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001372 new_line_len += after_break_len;
1373 /* We end the old line after wrap_loc. Note that this does not eat
1374 * the space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001375 null_at(&inptr->data, wrap_loc + 1);
1376 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001377 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001378 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001379 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001380 * in a tab or a space, we don't add a space and decrement
1381 * totsize to account for that. */
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001382 if (!isblank(newline[new_line_len - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001383 strcat(newline, " ");
1384 else
1385 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001386 strcat(newline, wrap_line);
1387 free(inptr->next->data);
1388 inptr->next->data = newline;
1389 } else {
1390 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001391
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001392 /* In this case, the file size changes by +1 for the new line,
1393 * and +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001394#ifndef NANO_SMALL
1395 totsize += indent_len;
1396#endif
1397 totlines++;
1398 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001399 temp->prev = inptr;
1400 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001401 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001402 /* If temp->next is NULL, then temp is the last line of the
1403 * file, so we must set filebot. */
1404 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001405 temp->next->prev = temp;
1406 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001407 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001408 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001409
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001410 /* Step 3, clean up. Here we reposition the cursor and mark, and do
1411 * some other sundry things. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001412
1413 /* later wraps of this line will be prepended to the next line. */
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001414 same_line_wrap = TRUE;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001415
1416 /* Each line knows its line number. We recalculate these if we
1417 * inserted a new line. */
1418 if (!wrapping)
1419 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001420
Chris Allegretta6df90f52002-07-19 01:08:59 +00001421 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001422 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001423 current = current->next;
1424 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001425#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001426 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001427#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001428 wrap_loc + 1;
1429 wrap_reset();
1430 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001431 }
1432
Chris Allegretta6df90f52002-07-19 01:08:59 +00001433#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001434 /* If the mark was on this line after the wrap point, we move it down.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001435 * If it was on the next line and we wrapped, we must move it
1436 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001437 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1438 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001439 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001440 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001441 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001442#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001443
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001444 return TRUE;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001445}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001446#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001447
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001448#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001449/* A word is misspelled in the file. Let the user replace it. We
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001450 * return zero if the user cancels. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001451int do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001452{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001453 char *save_search;
1454 char *save_replace;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001455 size_t current_x_save = current_x;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001456 filestruct *current_save = current;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001457 filestruct *edittop_save = edittop;
1458 /* Save where we are. */
1459 int i = 0;
1460 /* The return value. */
1461 int reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001462#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001463 int case_sens_set = ISSET(CASE_SENSITIVE);
1464 int mark_set = ISSET(MARK_ISSET);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001465
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001466 SET(CASE_SENSITIVE);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001467 /* Make sure the marking highlight is off during spell-check. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001468 UNSET(MARK_ISSET);
1469#endif
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001470 /* Make sure spell-check goes forward only. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001471 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001472
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001473 /* Save the current search/replace strings. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001474 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001475 save_search = last_search;
1476 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001477
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001478 /* Set search/replace strings to misspelled word. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001479 last_search = mallocstrcpy(NULL, word);
1480 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001481
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001482 /* Start from the top of the file. */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001483 current = fileage;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001484 current_x = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001485
1486 search_last_line = FALSE;
1487
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001488 /* Find the first whole-word occurrence of word. */
1489 while (findnextstr(TRUE, TRUE, fileage, 0, word, FALSE) != 0)
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001490 if (is_whole_word(current_x, current->data, word)) {
1491 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001492
Chris Allegretta6df90f52002-07-19 01:08:59 +00001493 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001494
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001495 /* Allow the replace word to be corrected. */
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00001496 i = statusq(FALSE, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001497#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001498 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001499#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001500 _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001501
Chris Allegretta6df90f52002-07-19 01:08:59 +00001502 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001503
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001504 if (i != -1 && strcmp(word, answer)) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001505 search_last_line = FALSE;
1506 current_x--;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001507 do_replace_loop(word, current_save, &current_x_save, TRUE);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001508 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001509
1510 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001511 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001512
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001513 /* Restore the search/replace strings. */
1514 free(last_search);
1515 last_search = save_search;
1516 free(last_replace);
1517 last_replace = save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001518
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001519 /* Restore where we were. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001520 current = current_save;
1521 current_x = current_x_save;
1522 edittop = edittop_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001523
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001524 /* Restore search/replace direction. */
Chris Allegretta23b74b22002-01-21 20:32:22 +00001525 if (reverse_search_set)
1526 SET(REVERSE_SEARCH);
1527
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001528#ifndef NANO_SMALL
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001529 if (!case_sens_set)
1530 UNSET(CASE_SENSITIVE);
1531
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001532 /* Restore marking highlight. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001533 if (mark_set)
1534 SET(MARK_ISSET);
1535#endif
1536
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001537 return i != -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001538}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001539
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001540/* Integrated spell checking using 'spell' program. Return value: NULL
1541 * for normal termination, otherwise the error string. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001542const char *do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001543{
Chris Allegretta271e9722000-11-10 18:15:43 +00001544 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001545 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001546 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001547 pid_t pid_spell, pid_sort, pid_uniq;
1548 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001549
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001550 /* Create all three pipes up front. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001551 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1552 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001553
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001554 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001555
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001556 /* A new process to run spell in. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001557 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001558
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001559 /* Child continues (i.e, future spell process). */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001560
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001561 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001562
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001563 /* Replace the standard input with the temp file. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001564 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1565 goto close_pipes_and_exit;
1566
1567 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1568 goto close_pipes_and_exit;
1569
Chris Allegretta271e9722000-11-10 18:15:43 +00001570 close(tempfile_fd);
1571
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001572 /* Send spell's standard output to the pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001573 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1574 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001575
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001576 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001577
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001578 /* Start spell program; we are using PATH. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001579 execlp("spell", "spell", NULL);
1580
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001581 /* Should not be reached, if spell is found. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001582 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001583 }
1584
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001585 /* Parent continues here. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001586 close(spell_fd[1]);
1587
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001588 /* A new process to run sort in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001589 if ((pid_sort = fork()) == 0) {
1590
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001591 /* Child continues (i.e, future spell process). Replace the
1592 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001593 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1594 goto close_pipes_and_exit;
1595
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001596 close(spell_fd[0]);
1597
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001598 /* Send sort's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001599 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1600 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001601
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001602 close(sort_fd[1]);
1603
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001604 /* Start sort program. Use -f to remove mixed case without
1605 * having to have ANOTHER pipe for tr. If this isn't portable,
1606 * let me know. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001607 execlp("sort", "sort", "-f", NULL);
1608
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001609 /* Should not be reached, if sort is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001610 exit(1);
1611 }
1612
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001613 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001614 close(sort_fd[1]);
1615
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001616 /* A new process to run uniq in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001617 if ((pid_uniq = fork()) == 0) {
1618
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001619 /* Child continues (i.e, future uniq process). Replace the
1620 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001621 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1622 goto close_pipes_and_exit;
1623
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001624 close(sort_fd[0]);
1625
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001626 /* Send uniq's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001627 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1628 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001629
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001630 close(uniq_fd[1]);
1631
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001632 /* Start uniq program; we are using PATH. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001633 execlp("uniq", "uniq", NULL);
1634
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001635 /* Should not be reached, if uniq is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001636 exit(1);
1637 }
1638
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001639 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001640 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001641
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001642 /* Child process was not forked successfully. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001643 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1644 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001645 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001646 }
1647
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001648 /* Get system pipe buffer size. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001649 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1650 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001651 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001652 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001653
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001654 /* Read in the returned spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001655 read_buff_read = 0;
1656 read_buff_size = pipe_buff_size + 1;
1657 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001658
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001659 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001660 read_buff_read += bytesread;
1661 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001662 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001663 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001664
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001665 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001666
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001667 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001668 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001669
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001670 /* Process the spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001671 read_buff_word = read_buff_ptr = read_buff;
1672
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001673 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001674
1675 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001676 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001677 if (read_buff_word != read_buff_ptr) {
1678 if (!do_int_spell_fix(read_buff_word)) {
1679 read_buff_word = read_buff_ptr;
1680 break;
1681 }
1682 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001683 read_buff_word = read_buff_ptr + 1;
1684 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001685 read_buff_ptr++;
1686 }
1687
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001688 /* Special case where last word doesn't end with \n or \r. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001689 if (read_buff_word != read_buff_ptr)
1690 do_int_spell_fix(read_buff_word);
1691
Chris Allegretta271e9722000-11-10 18:15:43 +00001692 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001693 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001694 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001695
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001696 /* Process end of spell process. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001697 waitpid(pid_spell, &spell_status, 0);
1698 waitpid(pid_sort, &sort_status, 0);
1699 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001700
Chris Allegretta334a9402002-12-16 04:25:53 +00001701 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1702 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001703
Chris Allegretta334a9402002-12-16 04:25:53 +00001704 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1705 return _("Error invoking \"sort -f\"");
1706
1707 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1708 return _("Error invoking \"uniq\"");
1709
1710 /* Otherwise... */
1711 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001712
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001713 close_pipes_and_exit:
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001714
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001715 /* Don't leak any handles. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001716 close(tempfile_fd);
1717 close(spell_fd[0]);
1718 close(spell_fd[1]);
1719 close(sort_fd[0]);
1720 close(sort_fd[1]);
1721 close(uniq_fd[0]);
1722 close(uniq_fd[1]);
1723 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001724}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001725
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001726/* External spell checking. Return value: NULL for normal termination,
1727 * otherwise the error string. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001728const char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001729{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001730 int alt_spell_status, lineno_cur = current->lineno;
1731 int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001732 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001733 char *ptr;
1734 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001735 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001736#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001737 int mark_set = ISSET(MARK_ISSET);
1738 int mbb_lineno_cur = 0;
1739 /* We're going to close the current file, and open the output of
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001740 * the alternate spell command. The line that mark_beginbuf
1741 * points to will be freed, so we save the line number and
1742 * restore afterwards. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001743
1744 if (mark_set) {
1745 mbb_lineno_cur = mark_beginbuf->lineno;
1746 UNSET(MARK_ISSET);
1747 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001748#endif
1749
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001750 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001751
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001752 /* Set up an argument list to pass execvp(). */
Chris Allegrettae434b452001-01-27 19:25:00 +00001753 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001754 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001755
Chris Allegrettae434b452001-01-27 19:25:00 +00001756 spellargs[0] = strtok(alt_speller, " ");
1757 while ((ptr = strtok(NULL, " ")) != NULL) {
1758 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001759 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00001760 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001761 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001762 spellargs[arglen - 1] = NULL;
1763 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001764 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001765
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001766 /* Start a new process for the alternate speller. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001767 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001768 /* Start alternate spell program; we are using PATH. */
Chris Allegretta169ee842001-01-26 01:57:32 +00001769 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001770
1771 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001772 exit(1);
1773 }
1774
1775 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001776 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001777 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001778
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001779 /* Wait for alternate speller to complete. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001780 wait(&alt_spell_status);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001781
Chris Allegretta334a9402002-12-16 04:25:53 +00001782 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1783 char *altspell_error = NULL;
1784 char *invoke_error = _("Could not invoke \"%s\"");
1785 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1786
1787 altspell_error = charalloc(msglen);
1788 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1789 return altspell_error;
1790 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001791
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001792 refresh();
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001793#ifndef NANO_SMALL
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001794 if (!mark_set) {
1795 /* Only reload the temp file if it isn't a marked selection. */
1796#endif
1797 free_filestruct(fileage);
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00001798 global_init(TRUE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001799 open_file(tempfile_name, 0, 1);
1800#ifndef NANO_SMALL
1801 }
1802
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001803 if (mark_set) {
1804 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1805 mark_beginbuf = current;
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001806 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001807 mark_beginx = current_x;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001808 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001809 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001810#endif
1811
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001812 /* Go back to the old position, mark the file as modified, and make
1813 * sure that the titlebar is refreshed. */
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001814 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001815 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001816 clearok(topwin, FALSE);
1817 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001818
Chris Allegretta334a9402002-12-16 04:25:53 +00001819 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001820}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001821
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001822void do_spell(void)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001823{
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001824 int i;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001825 char *temp = safe_tempnam(0, "nano.");
1826 const char *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001827
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001828 if (temp == NULL) {
1829 statusbar(_("Could not create temp file: %s"), strerror(errno));
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001830 return;
Chris Allegretta271e9722000-11-10 18:15:43 +00001831 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001832
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001833#ifndef NANO_SMALL
1834 if (ISSET(MARK_ISSET))
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00001835 i = write_marked(temp, TRUE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001836 else
1837#endif
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00001838 i = write_file(temp, TRUE, FALSE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001839
1840 if (i == -1) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001841 statusbar(_("Unable to write temp file: %s"), strerror(errno));
Chris Allegrettabef12972002-03-06 03:30:40 +00001842 free(temp);
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001843 return;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001844 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001845
Chris Allegrettae1f14522001-09-19 03:19:43 +00001846#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001847 /* Update the current open_files entry before spell-checking, in
1848 * case any problems occur. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001849 add_open_file(TRUE);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001850#endif
1851
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001852 spell_msg = alt_speller != NULL ? do_alt_speller(temp) :
1853 do_int_speller(temp);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001854 unlink(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001855 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001856
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001857 if (spell_msg != NULL) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001858 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
1859 strerror(errno));
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001860 return;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001861 } else
1862 statusbar(_("Finished checking spelling"));
Chris Allegretta67105eb2000-07-03 03:18:32 +00001863}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001864#endif /* !DISABLE_SPELLER */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001865
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001866#if !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001867/* The "indentation" of a line is the whitespace between the quote part
1868 * and the non-whitespace of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001869size_t indent_length(const char *line)
1870{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001871 size_t len = 0;
1872
1873 assert(line != NULL);
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001874 while (isblank(*line)) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001875 line++;
1876 len++;
1877 }
1878 return len;
1879}
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001880#endif /* !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001881
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001882#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001883/* justify_format() replaces Tab by Space and multiple spaces by 1
1884 * (except it maintains 2 after a . ! or ?). Note the terminating \0
Chris Allegretta6df90f52002-07-19 01:08:59 +00001885 * counts as a space.
1886 *
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001887 * justify_format() might make line->data shorter, and change the actual
1888 * pointer with null_at().
Chris Allegretta6df90f52002-07-19 01:08:59 +00001889 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001890 * justify_format() will not look at the first skip characters of line.
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001891 * skip should be at most strlen(line->data). The character at
1892 * line[skip + 1] must not be whitespace. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001893void justify_format(filestruct *line, size_t skip)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001894{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001895 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001896
Chris Allegretta6df90f52002-07-19 01:08:59 +00001897 /* These four asserts are assumptions about the input data. */
1898 assert(line != NULL);
1899 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00001900 assert(skip < strlen(line->data));
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001901 assert(!isblank(line->data[skip]));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001902
Chris Allegretta6df90f52002-07-19 01:08:59 +00001903 back = line->data + skip;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001904 for (front = back; ; front++) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001905 int remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001906 /* Do we want to remove this space? */
1907
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001908 if (*front == '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001909 *front = ' ';
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001910
David Lawrence Ramsey021960d2004-05-13 23:19:01 +00001911 /* These tests are safe since line->data + skip is not a
1912 * space. */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001913 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001914 const char *bob = front - 2;
1915
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001916 remove_space = TRUE;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001917 for (bob = back - 2; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001918 if (strchr(punct, *bob) != NULL) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001919 remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001920 break;
1921 }
1922 if (strchr(brackets, *bob) == NULL)
1923 break;
1924 }
1925 }
1926
1927 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001928 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001929 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001930#ifndef NANO_SMALL
1931 if (mark_beginbuf == line && back - line->data < mark_beginx)
1932 mark_beginx--;
1933#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001934 if (*front == '\0')
1935 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00001936 } else {
1937 *back = *front;
1938 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001939 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001940 if (*front == '\0')
1941 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001942 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001943
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001944 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00001945 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00001946
Chris Allegretta6df90f52002-07-19 01:08:59 +00001947 /* Now back is the new end of line->data. */
1948 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00001949 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001950 null_at(&line->data, back - line->data);
1951#ifndef NANO_SMALL
1952 if (mark_beginbuf == line && back - line->data < mark_beginx)
1953 mark_beginx = back - line->data;
1954#endif
1955 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001956}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001957
1958/* The "quote part" of a line is the largest initial substring matching
1959 * the quote string. This function returns the length of the quote part
1960 * of the given line.
1961 *
1962 * Note that if !HAVE_REGEX_H then we match concatenated copies of
1963 * quotestr. */
1964#ifdef HAVE_REGEX_H
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001965size_t quote_length(const char *line, const regex_t *qreg)
1966{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001967 regmatch_t matches;
1968 int rc = regexec(qreg, line, 1, &matches, 0);
1969
1970 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t) -1)
1971 return 0;
1972 /* matches.rm_so should be 0, since the quote string should start with
1973 * the caret ^. */
1974 return matches.rm_eo;
1975}
1976#else /* !HAVE_REGEX_H */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001977size_t quote_length(const char *line)
1978{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001979 size_t qdepth = 0;
1980 size_t qlen = strlen(quotestr);
1981
1982 /* Compute quote depth level */
1983 while (!strcmp(line + qdepth, quotestr))
1984 qdepth += qlen;
1985 return qdepth;
1986}
1987#endif /* !HAVE_REGEX_H */
1988
Chris Allegretta6df90f52002-07-19 01:08:59 +00001989/* a_line and b_line are lines of text. The quotation part of a_line is
1990 * the first a_quote characters. Check that the quotation part of
1991 * b_line is the same. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00001992int quotes_match(const char *a_line, size_t a_quote, IFREG(const char
1993 *b_line, const regex_t *qreg))
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001994{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001995 /* Here is the assumption about a_quote: */
1996 assert(a_quote == quote_length(IFREG(a_line, qreg)));
Chris Allegrettad865da12002-07-29 23:46:38 +00001997 return a_quote == quote_length(IFREG(b_line, qreg)) &&
Chris Allegretta6df90f52002-07-19 01:08:59 +00001998 !strncmp(a_line, b_line, a_quote);
1999}
2000
2001/* We assume a_line and b_line have no quote part. Then, we return whether
2002 * b_line could follow a_line in a paragraph. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002003size_t indents_match(const char *a_line, size_t a_indent, const char
2004 *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002005{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002006 assert(a_indent == indent_length(a_line));
2007 assert(b_indent == indent_length(b_line));
2008
2009 return b_indent <= a_indent && !strncmp(a_line, b_line, b_indent);
2010}
2011
2012/* Put the next par_len lines, starting with first_line, in the cut
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002013 * buffer, not allowing them to be concatenated. We assume there are
2014 * enough lines after first_line. We leave copies of the lines in
2015 * place, too. We return the new copy of first_line. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002016filestruct *backup_lines(filestruct *first_line, size_t par_len, size_t
2017 quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002018{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002019 /* We put the original lines, not copies, into the cutbuffer, just
2020 * out of a misguided sense of consistency, so if you uncut, you get
2021 * the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002022 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002023
2024 set_modified();
2025 cutbuffer = NULL;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002026 for (; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002027 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002028
Chris Allegretta908f7702003-01-15 11:18:58 +00002029 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002030 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002031 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002032 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002033 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002034 edittop = bob;
2035#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002036 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002037 mark_beginbuf = bob;
2038#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002039
Chris Allegretta908f7702003-01-15 11:18:58 +00002040 assert(alice != NULL && bob != NULL);
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002041 add_to_cutbuffer(alice, FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002042 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002043 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002044 }
2045 return first_line;
2046}
2047
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002048/* Is it possible to break line at or before goal? */
2049int breakable(const char *line, int goal)
2050{
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002051 for (; *line != '\0' && goal >= 0; line++) {
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002052 if (isblank(*line))
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002053 return TRUE;
2054
2055 if (is_cntrl_char(*line) != 0)
2056 goal -= 2;
2057 else
2058 goal -= 1;
2059 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002060 /* If goal is not negative, the whole line (one word) was short
2061 * enough. */
2062 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002063}
2064
Chris Allegretta6df90f52002-07-19 01:08:59 +00002065/* We are trying to break a chunk off line. We find the last space such
2066 * that the display length to there is at most goal + 1. If there is
2067 * no such space, and force is not 0, then we find the first space.
2068 * Anyway, we then take the last space in that group of spaces. The
2069 * terminating '\0' counts as a space. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002070int break_line(const char *line, int goal, int force)
2071{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002072 /* Note that we use int instead of size_t, since goal is at most COLS,
2073 * the screen width, which will always be reasonably small. */
2074 int space_loc = -1;
2075 /* Current tentative return value. Index of the last space we
2076 * found with short enough display width. */
2077 int cur_loc = 0;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002078 /* Current index in line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002079
2080 assert(line != NULL);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002081 for (; *line != '\0' && goal >= 0; line++, cur_loc++) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002082 if (*line == ' ')
2083 space_loc = cur_loc;
2084 assert(*line != '\t');
2085
Chris Allegrettacf287c82002-07-20 13:57:41 +00002086 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002087 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002088 else
2089 goal--;
2090 }
2091 if (goal >= 0)
2092 /* In fact, the whole line displays shorter than goal. */
2093 return cur_loc;
2094 if (space_loc == -1) {
2095 /* No space found short enough. */
2096 if (force)
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002097 for (; *line != '\0'; line++, cur_loc++)
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002098 if (*line == ' ' && *(line + 1) != ' ' && *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002099 return cur_loc;
2100 return -1;
2101 }
2102 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002103 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002104 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2105 *(line - cur_loc + space_loc + 1) == '\0')
2106 space_loc++;
2107 return space_loc;
2108}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002109
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002110/* Search a paragraph. If search_type is JUSTIFY, search for the
2111 * beginning of the current paragraph or, if we're at the end of it, the
2112 * beginning of the next paragraph. If search_type is BEGIN, search for
2113 * the beginning of the current paragraph or, if we're already there,
2114 * the beginning of the previous paragraph. If search_type is END,
2115 * search for the end of the current paragraph or, if we're already
2116 * there, the end of the next paragraph. Afterwards, save the quote
2117 * length, paragraph length, and indentation length in *quote, *par, and
2118 * *indent if they aren't NULL, and refresh the screen if do_refresh is
2119 * TRUE. Return 0 if we found a paragraph, or 1 if there was an error
2120 * or we didn't find a paragraph.
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002121 *
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002122 * To explain the searching algorithm, I first need to define some
Chris Allegretta6df90f52002-07-19 01:08:59 +00002123 * phrases about paragraphs and quotation:
2124 * A line of text consists of a "quote part", followed by an
2125 * "indentation part", followed by text. The functions quote_length()
2126 * and indent_length() calculate these parts.
2127 *
2128 * A line is "part of a paragraph" if it has a part not in the quote
2129 * part or the indentation.
2130 *
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002131 * A line is "the beginning of a paragraph" if it is part of a
2132 * paragraph and
Chris Allegretta6df90f52002-07-19 01:08:59 +00002133 * 1) it is the top line of the file, or
2134 * 2) the line above it is not part of a paragraph, or
2135 * 3) the line above it does not have precisely the same quote
2136 * part, or
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002137 * 4) the indentation of this line is not an initial substring of
2138 * the indentation of the previous line, or
Chris Allegretta6df90f52002-07-19 01:08:59 +00002139 * 5) this line has no quote part and some indentation, and
2140 * AUTOINDENT is not set.
2141 * The reason for number 5) is that if AUTOINDENT is not set, then an
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002142 * indented line is expected to start a paragraph, like in books.
2143 * Thus, nano can justify an indented paragraph only if AUTOINDENT is
2144 * turned on.
Chris Allegretta6df90f52002-07-19 01:08:59 +00002145 *
2146 * A contiguous set of lines is a "paragraph" if each line is part of
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002147 * a paragraph and only the first line is the beginning of a
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002148 * paragraph. */
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002149int do_para_search(justbegend search_type, size_t *quote, size_t *par,
2150 size_t *indent, int do_refresh)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002151{
David Lawrence Ramseyc21790d2004-05-30 03:19:52 +00002152 int old_pww = placewewant;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002153 const filestruct *current_save = current;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002154 size_t quote_len;
2155 /* Length of the initial quotation of the paragraph we
2156 * search. */
2157 size_t par_len;
2158 /* Number of lines in that paragraph. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002159 size_t indent_len;
2160 /* Generic indentation length. */
2161 filestruct *line;
2162 /* Generic line of text. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002163
2164#ifdef HAVE_REGEX_H
2165 regex_t qreg; /* qreg is the compiled quotation regexp. We no
2166 * longer care about quotestr. */
2167 int rc = regcomp(&qreg, quotestr, REG_EXTENDED);
2168
2169 if (rc != 0) {
2170 size_t size = regerror(rc, &qreg, NULL, 0);
2171 char *strerror = charalloc(size);
2172
2173 regerror(rc, &qreg, strerror, size);
2174 statusbar(_("Bad quote string %s: %s"), quotestr, strerror);
2175 free(strerror);
2176 return 1;
2177 }
2178#endif
2179
2180 /* Here is an assumption that is always true anyway. */
2181 assert(current != NULL);
2182
2183 current_x = 0;
2184
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002185 quote_len = quote_length(IFREG(current->data, &qreg));
2186 indent_len = indent_length(current->data + quote_len);
2187
David Lawrence Ramseydbde9d72004-06-27 00:54:08 +00002188 /* Here we find the last or first line of the paragraph to search.
2189 * If the current line is in a paragraph, then we move back to the
2190 * first line of the paragraph. Otherwise, we move to the last or
2191 * first line that is in a paragraph. */
2192 start_para_search:
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002193 if (current->data[quote_len + indent_len] != '\0') {
2194 /* This line is part of a paragraph. So we must search back to
2195 * the first line of this paragraph. First we check items 1)
2196 * and 3) above. */
2197 while (current->prev != NULL && quotes_match(current->data,
2198 quote_len, IFREG(current->prev->data, &qreg))) {
2199 size_t temp_id_len =
2200 indent_length(current->prev->data + quote_len);
2201 /* The indentation length of the previous line. */
2202
2203 /* Is this line the beginning of a paragraph, according to
2204 * items 2), 5), or 4) above? If so, stop. */
2205 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002206 (quote_len == 0 && indent_len > 0
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002207#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002208 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002209#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002210 ) || !indents_match(current->prev->data + quote_len,
2211 temp_id_len, current->data + quote_len, indent_len))
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002212 break;
2213 indent_len = temp_id_len;
2214 current = current->prev;
2215 current_y--;
2216 }
David Lawrence Ramseydbde9d72004-06-27 00:54:08 +00002217
2218 /* If we're searching for the beginning of the paragraph,
2219 * we're not on the first line of the file, and we're on the
2220 * same line we started on, move up one line and search
2221 * again, so that we end up on the first line of the previous
2222 * paragraph. */
2223 if (search_type == BEGIN && current->prev != NULL &&
2224 current == current_save) {
2225 current = current->prev;
2226 current_y--;
2227 goto start_para_search;
2228 }
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002229 } else if (search_type == BEGIN) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002230 /* This line is not part of a paragraph. Move up until we get
David Lawrence Ramseydbde9d72004-06-27 00:54:08 +00002231 * to a non "blank" line. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002232 do {
2233 /* There is no previous paragraph, so nothing to move to. */
2234 if (current->prev == NULL) {
2235 placewewant = 0;
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002236 if (do_refresh)
David Lawrence Ramseyc21790d2004-05-30 03:19:52 +00002237 edit_redraw(current_save, old_pww);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002238#ifdef HAVE_REGEX_H
David Lawrence Ramseydbde9d72004-06-27 00:54:08 +00002239 regfree(&qreg);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002240#endif
2241 return 1;
2242 }
2243 current = current->prev;
2244 current_y--;
2245 quote_len = quote_length(IFREG(current->data, &qreg));
2246 indent_len = indent_length(current->data + quote_len);
2247 } while (current->data[quote_len + indent_len] == '\0');
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002248 } else {
2249 /* This line is not part of a paragraph. Move down until we get
2250 * to a non "blank" line. */
2251 do {
2252 /* There is no next paragraph, so nothing to move to. */
2253 if (current->next == NULL) {
2254 placewewant = 0;
2255 if (do_refresh)
David Lawrence Ramseyc21790d2004-05-30 03:19:52 +00002256 edit_redraw(current_save, old_pww);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002257#ifdef HAVE_REGEX_H
2258 regfree(&qreg);
2259#endif
2260 return 1;
2261 }
2262 current = current->next;
2263 current_y++;
2264 quote_len = quote_length(IFREG(current->data, &qreg));
2265 indent_len = indent_length(current->data + quote_len);
2266 } while (current->data[quote_len + indent_len] == '\0');
2267 }
2268
David Lawrence Ramseydbde9d72004-06-27 00:54:08 +00002269 /* Now current is the last line in the paragraph if we're searching
2270 * for the beginning of it or the first line of the paragraph
2271 * otherwise, and quote_len is the quotation length of that line. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002272
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002273 /* Next step, compute par_len, the number of lines in this
2274 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002275 line = current;
2276 par_len = 1;
2277 indent_len = indent_length(line->data + quote_len);
2278
David Lawrence Ramseydbde9d72004-06-27 00:54:08 +00002279 if (search_type == BEGIN) {
2280 while (line->prev != NULL && quotes_match(current->data,
2281 quote_len, IFREG(line->prev->data, &qreg))) {
2282 size_t temp_id_len = indent_length(line->prev->data +
2283 quote_len);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002284
David Lawrence Ramseydbde9d72004-06-27 00:54:08 +00002285 if (!indents_match(line->data + quote_len, indent_len,
2286 line->prev->data + quote_len, temp_id_len) ||
2287 line->prev->data[quote_len + temp_id_len] == '\0' ||
2288 (quote_len == 0 && temp_id_len > 0
2289#ifndef NANO_SMALL
2290 && !ISSET(AUTOINDENT)
2291#endif
2292 ))
2293 break;
2294 indent_len = temp_id_len;
2295 line = line->prev;
2296 par_len++;
2297 }
2298 } else {
2299 while (line->next != NULL && quotes_match(current->data,
2300 quote_len, IFREG(line->next->data, &qreg))) {
2301 size_t temp_id_len = indent_length(line->next->data +
2302 quote_len);
2303
2304 if (!indents_match(line->data + quote_len, indent_len,
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002305 line->next->data + quote_len, temp_id_len) ||
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002306 line->next->data[quote_len + temp_id_len] == '\0' ||
2307 (quote_len == 0 && temp_id_len > 0
2308#ifndef NANO_SMALL
David Lawrence Ramseydbde9d72004-06-27 00:54:08 +00002309 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002310#endif
2311 ))
David Lawrence Ramseydbde9d72004-06-27 00:54:08 +00002312 break;
2313 indent_len = temp_id_len;
2314 line = line->next;
2315 par_len++;
2316 }
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002317 }
2318
2319#ifdef HAVE_REGEX_H
2320 /* We no longer need to check quotation. */
2321 regfree(&qreg);
2322#endif
2323
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002324 /* Now par_len is the number of lines in this paragraph. We should
2325 * never call quotes_match() or quote_length() again. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002326
David Lawrence Ramseydbde9d72004-06-27 00:54:08 +00002327 /* If we're searching for the beginning of the paragraph, move up
2328 * the number of lines in the paragraph minus one, since we want to
2329 * end up on the first line of the paragraph. If we're searching
2330 * for the end of the paragraph, move down the number of lines in
2331 * the paragraph, since we want to end up on the line after the
2332 * last line of the paragraph. */
2333 if (search_type == BEGIN) {
2334 for (; par_len > 1; current_y--, par_len--)
2335 current = current->prev;
2336 } else if (search_type == END) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002337 for (; par_len > 0; current_y++, par_len--)
2338 current = current->next;
2339 }
2340
2341 /* Refresh the screen if needed. */
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002342 if (do_refresh)
David Lawrence Ramseyc21790d2004-05-30 03:19:52 +00002343 edit_redraw(current_save, old_pww);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002344
2345 /* Save the values of quote_len, par_len, and indent_len if
2346 * needed. */
2347 if (quote != NULL)
2348 *quote = quote_len;
2349 if (par != NULL)
2350 *par = par_len;
2351 if (indent != NULL)
2352 *indent = indent_len;
2353
2354 return 0;
2355}
2356
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002357void do_para_begin(void)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002358{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002359 do_para_search(BEGIN, NULL, NULL, NULL, TRUE);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002360}
2361
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002362void do_para_end(void)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002363{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002364 do_para_search(END, NULL, NULL, NULL, TRUE);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002365}
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002366
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002367/* If full_justify is TRUE, justify the entire file. Otherwise, justify
2368 * the current paragraph. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002369void do_justify(int full_justify)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002370{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002371 size_t quote_len;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002372 /* Length of the initial quotation of the paragraph we
2373 * justify. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002374 size_t par_len;
2375 /* Number of lines in that paragraph. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002376 filestruct *first_par_line = NULL;
2377 /* Will be the first line of the resulting justified paragraph.
2378 * For restoring after uncut. */
David Lawrence Ramsey36e363f2004-05-17 20:38:00 +00002379 filestruct *last_par_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002380 /* Will be the last line of the result, also for uncut. */
2381 filestruct *cutbuffer_save = cutbuffer;
2382 /* When the paragraph gets modified, all lines from the changed
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002383 * one down are stored in the cutbuffer. We back up the
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002384 * original to restore it later. */
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002385 int allow_respacing;
2386 /* Whether we should change the spacing at the end of a line
2387 * after justifying it. This should be TRUE whenever we move
2388 * to the next line after justifying the current line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002389
2390 /* We save these global variables to be restored if the user
2391 * unjustifies. Note we don't need to save totlines. */
2392 int current_x_save = current_x;
2393 int current_y_save = current_y;
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00002394 long flags_save = flags;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002395 long totsize_save = totsize;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002396 filestruct *current_save = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002397 filestruct *edittop_save = edittop;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002398#ifndef NANO_SMALL
2399 filestruct *mark_beginbuf_save = mark_beginbuf;
2400 int mark_beginx_save = mark_beginx;
2401#endif
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002402 int kbinput;
2403 int meta_key;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002404
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002405 size_t indent_len; /* Generic indentation length. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002406
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002407 /* If we're justifying the entire file, start at the beginning. */
2408 if (full_justify)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002409 current = fileage;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002410
2411 last_par_line = current;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002412
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002413 while (TRUE) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002414 /* First, search for the beginning of the current paragraph or,
2415 * if we're at the end of it, the beginning of the next
2416 * paragraph. Save the quote length, paragraph length, and
2417 * indentation length and don't refresh the screen yet (since
2418 * we'll do that after we justify). If the search failed and
2419 * we're justifying the whole file, move the last line of the
2420 * text we're justifying to just before the magicline, which is
2421 * where it'll be anyway if we've searched the entire file, and
2422 * break out of the loop; otherwise, refresh the screen and get
2423 * out. */
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002424 if (do_para_search(JUSTIFY, &quote_len, &par_len, &indent_len,
2425 FALSE) != 0) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002426 if (full_justify) {
2427 /* This should be safe in the event of filebot->prev's
2428 * being NULL, since only last_par_line->next is used if
2429 * we eventually unjustify. */
2430 last_par_line = filebot->prev;
2431 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002432 } else {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002433 edit_refresh();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002434 return;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002435 }
2436 }
2437
2438 /* Next step, we loop through the lines of this paragraph,
2439 * justifying each one individually. */
2440 for (; par_len > 0; current_y++, par_len--) {
2441 size_t line_len;
2442 size_t display_len;
2443 /* The width of current in screen columns. */
2444 int break_pos;
2445 /* Where we will break the line. */
2446
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002447 /* We'll be moving to the next line after justifying the
2448 * current line in almost all cases, so allow changing the
2449 * spacing at the ends of justified lines by default. */
2450 allow_respacing = TRUE;
2451
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002452 indent_len = quote_len + indent_length(current->data +
2453 quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002454
David Lawrence Ramsey91bc83a2004-06-25 01:52:10 +00002455 /* If we haven't already done it, copy the original
2456 * paragraph to the cutbuffer for unjustification. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002457 if (first_par_line == NULL)
2458 first_par_line = backup_lines(current, full_justify ?
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002459 filebot->lineno - current->lineno : par_len, quote_len);
2460
David Lawrence Ramsey91bc83a2004-06-25 01:52:10 +00002461 /* Now we call justify_format() on the current line of the
2462 * paragraph, which will remove excess spaces from it and
2463 * change tabs to spaces. */
2464 justify_format(current, quote_len +
2465 indent_length(current->data + quote_len));
2466
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002467 line_len = strlen(current->data);
2468 display_len = strlenpt(current->data);
2469
2470 if (display_len > fill) {
2471 /* The line is too long. Try to wrap it to the next. */
2472 break_pos = break_line(current->data + indent_len,
2473 fill - strnlenpt(current->data, indent_len), TRUE);
2474 if (break_pos == -1 || break_pos + indent_len == line_len)
2475 /* We can't break the line, or don't need to, so
2476 * just go on to the next. */
2477 goto continue_loc;
2478 break_pos += indent_len;
2479 assert(break_pos < line_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002480 if (par_len == 1) {
2481 /* There is no next line in this paragraph. We make
2482 * a new line and copy text after break_pos into
2483 * it. */
2484 splice_node(current, make_new_node(current), current->next);
2485 /* In a non-quoted paragraph, we copy the indent
2486 * only if AUTOINDENT is turned on. */
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002487 if (quote_len == 0
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002488#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002489 && !ISSET(AUTOINDENT)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002490#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002491 )
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002492 indent_len = 0;
2493 current->next->data = charalloc(indent_len + line_len -
2494 break_pos);
2495 strncpy(current->next->data, current->data, indent_len);
2496 strcpy(current->next->data + indent_len,
2497 current->data + break_pos + 1);
2498 assert(strlen(current->next->data) ==
2499 indent_len + line_len - break_pos - 1);
2500 totlines++;
2501 totsize += indent_len;
2502 par_len++;
2503 } else {
2504 size_t next_line_len = strlen(current->next->data);
2505
2506 indent_len = quote_len +
2507 indent_length(current->next->data + quote_len);
2508 current->next->data = charealloc(current->next->data,
2509 next_line_len + line_len - break_pos + 1);
2510
2511 charmove(current->next->data + indent_len + line_len -
2512 break_pos, current->next->data + indent_len,
2513 next_line_len - indent_len + 1);
2514 strcpy(current->next->data + indent_len,
2515 current->data + break_pos + 1);
David Lawrence Ramsey537a8802004-06-24 22:39:24 +00002516 current->next->data[indent_len + line_len -
2517 break_pos - 1] = ' ';
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002518#ifndef NANO_SMALL
2519 if (mark_beginbuf == current->next) {
2520 if (mark_beginx < indent_len)
2521 mark_beginx = indent_len;
2522 mark_beginx += line_len - break_pos;
2523 }
2524#endif
2525 }
2526#ifndef NANO_SMALL
2527 if (mark_beginbuf == current && mark_beginx > break_pos) {
2528 mark_beginbuf = current->next;
2529 mark_beginx -= break_pos + 1 - indent_len;
2530 }
2531#endif
2532 null_at(&current->data, break_pos);
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002533
2534 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002535 current = current->next;
2536 } else if (display_len < fill && par_len > 1) {
2537 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002538
2539 indent_len = quote_len +
2540 indent_length(current->next->data + quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002541 /* If we can't pull a word from the next line up to this
2542 * one, just go on. */
2543 if (!breakable(current->next->data + indent_len,
2544 fill - display_len - 1))
2545 goto continue_loc;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002546
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002547 break_pos = break_line(current->next->data + indent_len,
2548 fill - display_len - 1, FALSE);
2549 assert(break_pos != -1);
2550
2551 current->data = charealloc(current->data,
2552 line_len + break_pos + 2);
2553 current->data[line_len] = ' ';
2554 strncpy(current->data + line_len + 1,
2555 current->next->data + indent_len, break_pos);
2556 current->data[line_len + break_pos + 1] = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002557#ifndef NANO_SMALL
2558 if (mark_beginbuf == current->next) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002559 if (mark_beginx < indent_len + break_pos) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002560 mark_beginbuf = current;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002561 if (mark_beginx <= indent_len)
2562 mark_beginx = line_len + 1;
2563 else
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002564 mark_beginx = line_len + 1 + mark_beginx -
2565 indent_len;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002566 } else
2567 mark_beginx -= break_pos + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002568 }
2569#endif
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002570 next_line_len = strlen(current->next->data);
2571 if (indent_len + break_pos == next_line_len) {
2572 filestruct *line = current->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002573
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002574 /* Don't destroy edittop! */
2575 if (line == edittop)
2576 edittop = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002577
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002578 unlink_node(line);
2579 delete_node(line);
2580 totlines--;
2581 totsize -= indent_len;
2582 current_y--;
David Lawrence Ramsey01a6bf42004-07-03 05:23:19 +00002583
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002584 /* Don't go to the next line. Accordingly, don't
2585 * allow changing the spacing at the end of the
David Lawrence Ramsey309fbcb2004-07-03 14:34:03 +00002586 * previous justified line, so that we don't end up
2587 * doing it more than once on the same line. */
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002588 allow_respacing = FALSE;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002589 } else {
2590 charmove(current->next->data + indent_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002591 current->next->data + indent_len + break_pos + 1,
2592 next_line_len - break_pos - indent_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002593 null_at(&current->next->data, next_line_len - break_pos);
David Lawrence Ramsey01a6bf42004-07-03 05:23:19 +00002594
2595 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002596 current = current->next;
2597 }
2598 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002599 continue_loc:
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002600 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002601 current = current->next;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002602
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002603 /* We've moved to the next line after justifying the
2604 * current line. If the justified line was not the last
2605 * line of the paragraph, add a space to the end of it to
2606 * replace the one removed or left out by justify_format().
2607 * If it was the last line of the paragraph, and
2608 * justify_format() left a space on the end of it, remove
2609 * the space. */
2610 if (allow_respacing) {
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002611 size_t prev_line_len = strlen(current->prev->data);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002612
2613 if (par_len > 1) {
2614 current->prev->data = charealloc(current->prev->data,
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002615 prev_line_len + 2);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002616 current->prev->data[prev_line_len] = ' ';
2617 current->prev->data[prev_line_len + 1] = '\0';
2618 totsize++;
2619 } else if (par_len == 1 &&
2620 current->prev->data[prev_line_len - 1] == ' ') {
2621 current->prev->data = charealloc(current->prev->data,
2622 prev_line_len);
2623 current->prev->data[prev_line_len - 1] = '\0';
2624 totsize--;
2625 }
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002626 }
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002627 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002628
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002629 /* We've just justified a paragraph. If we're not justifying the
2630 * entire file, break out of the loop. Otherwise, continue the
2631 * loop so that we justify all the paragraphs in the file. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002632 if (!full_justify)
2633 break;
2634
2635 } /* while (TRUE) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002636
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002637 /* We are now done justifying the paragraph or the file, so clean
2638 * up. totlines, totsize, and current_y have been maintained above.
2639 * Set last_par_line to the new end of the paragraph, update
2640 * fileage, and set current_x. Also, edit_refresh() needs the line
2641 * numbers to be right, so renumber(). */
2642 last_par_line = current->prev;
2643 if (first_par_line->prev == NULL)
2644 fileage = first_par_line;
2645 renumber(first_par_line);
2646
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002647 edit_refresh();
Chris Allegretta6df90f52002-07-19 01:08:59 +00002648
Chris Allegretta9149e612000-11-27 00:23:41 +00002649 statusbar(_("Can now UnJustify!"));
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002650 /* Display the shortcut list with UnJustify. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002651 shortcut_init(TRUE);
Chris Allegretta07798352000-11-27 22:58:23 +00002652 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002653 reset_cursor();
2654
Chris Allegretta6df90f52002-07-19 01:08:59 +00002655 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002656 * keystroke and return. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002657 kbinput = get_kbinput(edit, &meta_key);
Chris Allegretta5f071802001-05-06 02:34:31 +00002658
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002659#ifndef DISABLE_MOUSE
2660 /* If it was a mouse click, parse it with do_mouse() and it
2661 * might become the unjustify key. Else give it back to the
2662 * input stream. */
2663 if (kbinput == KEY_MOUSE) {
2664 do_mouse();
2665 kbinput = get_kbinput(edit, &meta_key);
2666 }
2667#endif
2668
2669 if (meta_key || (kbinput != NANO_UNJUSTIFY_KEY &&
2670 kbinput != NANO_UNJUSTIFY_FKEY)) {
2671 ungetch(kbinput);
2672 if (meta_key)
2673 ungetch(NANO_CONTROL_3);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002674 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002675 } else {
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002676 /* Else restore the justify we just did (ungrateful user!). */
2677 filestruct *cutbottom = get_cutbottom();
2678
Chris Allegretta6df90f52002-07-19 01:08:59 +00002679 current = current_save;
2680 current_x = current_x_save;
2681 current_y = current_y_save;
2682 edittop = edittop_save;
Chris Allegrettad022eac2000-11-27 02:50:49 +00002683
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002684 /* Splice the cutbuffer back into the file. */
2685 cutbottom->next = last_par_line->next;
2686 cutbottom->next->prev = cutbottom;
2687 /* The line numbers after the end of the paragraph have been
2688 * changed, so we change them back. */
2689 renumber(cutbottom->next);
2690 if (first_par_line->prev != NULL) {
2691 cutbuffer->prev = first_par_line->prev;
2692 cutbuffer->prev->next = cutbuffer;
2693 } else
2694 fileage = cutbuffer;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002695
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002696 last_par_line->next = NULL;
2697 free_filestruct(first_par_line);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002698
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002699 /* Restore global variables from before the justify. */
2700 totsize = totsize_save;
2701 totlines = filebot->lineno;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002702#ifndef NANO_SMALL
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002703 mark_beginbuf = mark_beginbuf_save;
2704 mark_beginx = mark_beginx_save;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002705#endif
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002706 flags = flags_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002707 if (!ISSET(MODIFIED))
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002708 titlebar(NULL);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002709 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002710 }
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002711
Chris Allegretta6df90f52002-07-19 01:08:59 +00002712 cutbuffer = cutbuffer_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002713 /* Note that now cutbottom is invalid, but that's okay. */
2714 blank_statusbar();
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002715 /* Display the shortcut list with UnCut. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002716 shortcut_init(FALSE);
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002717 display_main_list();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002718}
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002719
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002720void do_justify_void(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002721{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002722 do_justify(FALSE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002723}
2724
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002725void do_full_justify(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002726{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002727 do_justify(TRUE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002728}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00002729#endif /* !DISABLE_JUSTIFY */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002730
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002731void do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002732{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002733 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002734
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002735 if (!ISSET(MODIFIED))
2736 i = 0; /* Pretend the user chose not to save. */
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00002737 else if (ISSET(TEMP_FILE))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002738 i = 1;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002739 else
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002740 i = do_yesno(FALSE,
2741 _("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
2742
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002743#ifdef DEBUG
2744 dump_buffer(fileage);
2745#endif
2746
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002747 if (i == 0 || (i == 1 && do_writeout(TRUE) > 0)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002748#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002749 /* Exit only if there are no more open buffers. */
2750 if (close_open_file() != 0)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002751#endif
David Lawrence Ramseyda141062004-05-25 19:41:11 +00002752 finish();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002753 } else if (i != 1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002754 statusbar(_("Cancelled"));
2755
2756 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002757}
2758
2759void signal_init(void)
2760{
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002761 /* Trap SIGINT and SIGQUIT because we want them to do useful
2762 * things. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002763 memset(&act, 0, sizeof(struct sigaction));
2764 act.sa_handler = SIG_IGN;
2765 sigaction(SIGINT, &act, NULL);
David Lawrence Ramsey2897d2b2004-01-26 20:56:20 +00002766 sigaction(SIGQUIT, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002767
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002768 /* Trap SIGHUP and SIGTERM because we want to write the file out. */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002769 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002770 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002771 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002772
2773#ifndef NANO_SMALL
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002774 /* Trap SIGWINCH because we want to handle window resizes. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002775 act.sa_handler = handle_sigwinch;
2776 sigaction(SIGWINCH, &act, NULL);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002777 allow_pending_sigwinch(FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002778#endif
2779
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002780 /* Trap normal suspend (^Z) so we can handle it ourselves. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002781 if (!ISSET(SUSPEND)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002782 act.sa_handler = SIG_IGN;
2783 sigaction(SIGTSTP, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002784 } else {
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002785 /* Block all other signals in the suspend and continue handlers.
2786 * If we don't do this, other stuff interrupts them! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002787 sigfillset(&act.sa_mask);
2788
2789 act.sa_handler = do_suspend;
2790 sigaction(SIGTSTP, &act, NULL);
2791
2792 act.sa_handler = do_cont;
2793 sigaction(SIGCONT, &act, NULL);
2794 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002795}
2796
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002797/* Handler for SIGHUP (hangup) and SIGTERM (terminate). */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002798RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002799{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002800 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002801}
2802
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002803/* Handler for SIGTSTP (suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002804RETSIGTYPE do_suspend(int signal)
2805{
2806 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00002807 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002808 fflush(stdout);
2809
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002810 /* Restore the old terminal settings. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002811 tcsetattr(0, TCSANOW, &oldterm);
2812
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002813 /* Trap SIGHUP and SIGTERM so we can properly deal with them while
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002814 * suspended. */
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002815 act.sa_handler = handle_hupterm;
2816 sigaction(SIGHUP, &act, NULL);
2817 sigaction(SIGTERM, &act, NULL);
2818
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002819 /* Do what mutt does: send ourselves a SIGSTOP. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002820 kill(0, SIGSTOP);
2821}
2822
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002823/* Handler for SIGCONT (continue after suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002824RETSIGTYPE do_cont(int signal)
2825{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002826#ifndef NANO_SMALL
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002827 /* Perhaps the user resized the window while we slept. Handle it
2828 * and update the screen in the process. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002829 handle_sigwinch(0);
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002830#else
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002831 /* Just update the screen. */
2832 doupdate();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002833#endif
2834}
2835
2836#ifndef NANO_SMALL
2837void handle_sigwinch(int s)
2838{
2839 const char *tty = ttyname(0);
2840 int fd;
2841 int result = 0;
2842 struct winsize win;
2843
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002844 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002845 return;
2846 fd = open(tty, O_RDWR);
2847 if (fd == -1)
2848 return;
2849 result = ioctl(fd, TIOCGWINSZ, &win);
2850 close(fd);
2851 if (result == -1)
2852 return;
2853
2854 /* Could check whether the COLS or LINES changed, and return
2855 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2856 * variables, and in some cases ncurses has already updated them.
2857 * But not in all cases, argh. */
2858 COLS = win.ws_col;
2859 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002860 editwinrows = LINES - 5 + no_help();
2861 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002862 die_too_small();
2863
2864#ifndef DISABLE_WRAPJUSTIFY
2865 fill = wrap_at;
2866 if (fill <= 0)
2867 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002868 if (fill < 0)
2869 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002870#endif
2871
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002872 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002873 memset(hblank, ' ', COLS);
2874 hblank[COLS] = '\0';
2875
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002876#ifdef USE_SLANG
2877 /* Slang curses emulation brain damage, part 1: If we just do what
2878 * curses does here, it'll only work properly if the resize made the
2879 * window smaller. Do what mutt does: Leave and immediately reenter
2880 * Slang screen management mode. */
2881 SLsmg_reset_smg();
2882 SLsmg_init_smg();
2883#else
2884 /* Do the equivalent of what Minimum Profit does: Leave and
2885 * immediately reenter curses mode. */
2886 endwin();
2887 refresh();
2888#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002889
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002890 /* Do the equivalent of what both mutt and Minimum Profit do:
2891 * Reinitialize all the windows based on the new screen
2892 * dimensions. */
2893 window_init();
2894
2895 /* Redraw the contents of the windows that need it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002896 blank_statusbar();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002897 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002898 total_refresh();
2899
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002900 /* Turn cursor back on for sure. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002901 curs_set(1);
2902
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002903 /* Restore the terminal to its previously saved state. */
2904 resetty();
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002905
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00002906 /* Reset all the input routines that rely on character sequences. */
2907 reset_kbinput();
2908
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002909 /* Jump back to the main loop. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002910 siglongjmp(jmpbuf, 1);
2911}
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002912
2913void allow_pending_sigwinch(int allow)
2914{
2915 sigset_t winch;
2916 sigemptyset(&winch);
2917 sigaddset(&winch, SIGWINCH);
2918 if (allow)
2919 sigprocmask(SIG_UNBLOCK, &winch, NULL);
2920 else
2921 sigprocmask(SIG_BLOCK, &winch, NULL);
2922}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002923#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002924
Chris Allegrettadab017e2002-04-23 10:56:06 +00002925#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002926void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002927{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002928 int enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002929
Chris Allegretta658399a2001-06-14 02:54:22 +00002930 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002931 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002932
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002933 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002934 case TOGGLE_SUSPEND_KEY:
2935 signal_init();
2936 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002937#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00002938 case TOGGLE_MOUSE_KEY:
2939 mouse_init();
2940 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002941#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002942 case TOGGLE_NOHELP_KEY:
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002943 blank_statusbar();
2944 blank_bottombars();
Chris Allegretta2a42af12000-09-12 23:02:49 +00002945 wrefresh(bottomwin);
2946 window_init();
2947 edit_refresh();
2948 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00002949 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00002950 case TOGGLE_DOS_KEY:
2951 UNSET(MAC_FILE);
2952 break;
2953 case TOGGLE_MAC_KEY:
2954 UNSET(DOS_FILE);
2955 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002956#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00002957 case TOGGLE_SYNTAX_KEY:
2958 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002959 break;
2960#endif
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00002961#ifdef ENABLE_NANORC
2962 case TOGGLE_WHITESPACE_KEY:
2963 edit_refresh();
2964 break;
2965#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002966 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00002967
Chris Allegretta6df90f52002-07-19 01:08:59 +00002968 /* We are assuming here that shortcut_init() above didn't free and
2969 * reallocate the toggles. */
2970 enabled = ISSET(which->flag);
2971 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
2972 enabled = !enabled;
2973 statusbar("%s %s", which->desc,
2974 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00002975}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002976#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00002977
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002978void disable_signals(void)
2979{
2980 struct termios term;
2981
2982 tcgetattr(0, &term);
2983 term.c_lflag &= ~ISIG;
2984 tcsetattr(0, TCSANOW, &term);
2985}
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002986
2987#ifndef NANO_SMALL
2988void enable_signals(void)
2989{
2990 struct termios term;
2991
2992 tcgetattr(0, &term);
2993 term.c_lflag |= ISIG;
2994 tcsetattr(0, TCSANOW, &term);
2995}
2996#endif
2997
2998void disable_flow_control(void)
2999{
3000 struct termios term;
3001
3002 tcgetattr(0, &term);
3003 term.c_iflag &= ~(IXON|IXOFF);
3004 tcsetattr(0, TCSANOW, &term);
3005}
3006
3007void enable_flow_control(void)
3008{
3009 struct termios term;
3010
3011 tcgetattr(0, &term);
3012 term.c_iflag |= (IXON|IXOFF);
3013 tcsetattr(0, TCSANOW, &term);
3014}
3015
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003016int main(int argc, char *argv[])
3017{
3018 int optchr;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003019 int startline = 0; /* Line to try and start at */
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003020 int fill_flag_used = FALSE; /* Was the fill option used? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003021 const shortcut *s;
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003022 int keyhandled = FALSE; /* Have we handled the keystroke yet? */
David Lawrence Ramseyf8ddf312004-01-09 22:38:09 +00003023 int kbinput; /* Input from keyboard */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003024 int meta_key;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003025
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003026#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00003027 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003028#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003029#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003030 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003031 {"help", 0, 0, 'h'},
3032#ifdef ENABLE_MULTIBUFFER
3033 {"multibuffer", 0, 0, 'F'},
3034#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003035#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003036#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003037 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003038#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003039 {"ignorercfiles", 0, 0, 'I'},
3040#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003041#ifndef DISABLE_JUSTIFY
3042 {"quotestr", 1, 0, 'Q'},
3043#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003044#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003045 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003046#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003047 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003048 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003049#ifdef ENABLE_COLOR
3050 {"syntax", 1, 0, 'Y'},
3051#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003052 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003053 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003054 {"nofollow", 0, 0, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003055#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003056 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003057#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003058#ifndef DISABLE_OPERATINGDIR
3059 {"operatingdir", 1, 0, 'o'},
3060#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003061 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003062#ifndef DISABLE_WRAPJUSTIFY
3063 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003064#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003065#ifndef DISABLE_SPELLER
3066 {"speller", 1, 0, 's'},
3067#endif
3068 {"tempfile", 0, 0, 't'},
3069 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003070#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003071 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003072#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003073 {"nohelp", 0, 0, 'x'},
3074 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003075#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003076 {"smarthome", 0, 0, 'A'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003077 {"backup", 0, 0, 'B'},
3078 {"dos", 0, 0, 'D'},
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003079 {"backupdir", 1, 0, 'E'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003080 {"mac", 0, 0, 'M'},
3081 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003082 {"smooth", 0, 0, 'S'},
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003083 {"restricted", 0, 0, 'Z'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003084 {"autoindent", 0, 0, 'i'},
3085 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003086#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003087 {0, 0, 0, 0}
3088 };
3089#endif
3090
Chris Allegretta8bc03b62001-02-09 02:57:52 +00003091#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003092 setlocale(LC_ALL, "");
3093 bindtextdomain(PACKAGE, LOCALEDIR);
3094 textdomain(PACKAGE);
3095#endif
3096
Chris Allegretta7662c862003-01-13 01:35:15 +00003097#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003098 /* if we don't have rcfile support, we're root, and
3099 --disable-wrapping-as-root is used, turn wrapping off */
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003100 if (geteuid() == NANO_ROOT_UID)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003101 SET(NO_WRAP);
3102#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003103
3104#ifdef HAVE_GETOPT_LONG
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003105 while ((optchr = getopt_long(argc, argv, "h?ABDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz",
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00003106 long_options, NULL)) != -1) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00003107#else
3108 while ((optchr =
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003109 getopt(argc, argv, "h?ABDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz")) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003110#endif
3111
3112 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003113
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003114 case 'a':
3115 case 'b':
3116 case 'e':
3117 case 'f':
3118 case 'g':
3119 case 'j':
3120 /* Pico compatibility flags */
3121 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003122#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003123 case 'A':
3124 SET(SMART_HOME);
3125 break;
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003126 case 'B':
3127 SET(BACKUP_FILE);
3128 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003129 case 'D':
3130 SET(DOS_FILE);
3131 break;
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003132 case 'E':
3133 backup_dir = mallocstrcpy(backup_dir, optarg);
3134 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003135#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003136#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003137 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003138 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003139 break;
3140#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003141#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003142#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003143 case 'H':
3144 SET(HISTORYLOG);
3145 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003146#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003147 case 'I':
Chris Allegretta7662c862003-01-13 01:35:15 +00003148 SET(NO_RCFILE);
3149 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003150#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003151#ifndef NANO_SMALL
3152 case 'M':
3153 SET(MAC_FILE);
3154 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003155 case 'N':
3156 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003157 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003158#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003159#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003160 case 'Q':
Chris Allegretta7662c862003-01-13 01:35:15 +00003161 quotestr = mallocstrcpy(quotestr, optarg);
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003162 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003163#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003164#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003165 case 'R':
3166 SET(USE_REGEXP);
3167 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003168#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003169#ifndef NANO_SMALL
3170 case 'S':
3171 SET(SMOOTHSCROLL);
3172 break;
3173#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003174 case 'T':
Chris Allegretta6df90f52002-07-19 01:08:59 +00003175 {
3176 int i;
3177 char *first_error;
3178
Chris Allegretta7662c862003-01-13 01:35:15 +00003179 /* Using strtol() instead of atoi() lets us accept 0
3180 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003181 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003182 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003183 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003184 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003185 tabsize = i;
3186 if (tabsize <= 0) {
3187 fprintf(stderr, _("Tab size is too small for nano...\n"));
3188 exit(1);
3189 }
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003190 }
3191 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003192 case 'V':
3193 version();
3194 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003195#ifdef ENABLE_COLOR
3196 case 'Y':
3197 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3198 break;
3199#endif
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003200 case 'Z':
3201 SET(RESTRICTED);
3202 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003203 case 'c':
3204 SET(CONSTUPDATE);
3205 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003206 case 'd':
3207 SET(REBIND_DELETE);
3208 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003209#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003210 case 'i':
3211 SET(AUTOINDENT);
3212 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003213 case 'k':
3214 SET(CUT_TO_END);
3215 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003216#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003217 case 'l':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003218 SET(NOFOLLOW_SYMLINKS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003219 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003220#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003221 case 'm':
3222 SET(USE_MOUSE);
3223 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003224#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003225#ifndef DISABLE_OPERATINGDIR
3226 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003227 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003228 break;
3229#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003230 case 'p':
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003231 SET(PRESERVE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003232 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003233#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003234 case 'r':
3235 {
3236 int i;
3237 char *first_error;
3238
Chris Allegretta7662c862003-01-13 01:35:15 +00003239 /* Using strtol() instead of atoi() lets us accept 0
3240 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003241 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003242 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003243 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003244 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003245 wrap_at = i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003246 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003247 fill_flag_used = TRUE;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003248 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003249#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003250#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003251 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003252 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003253 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003254#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003255 case 't':
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00003256 SET(TEMP_FILE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003257 break;
3258 case 'v':
3259 SET(VIEW_MODE);
3260 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003261#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003262 case 'w':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003263 SET(NO_WRAP);
3264 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003265#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003266 case 'x':
3267 SET(NO_HELP);
3268 break;
3269 case 'z':
3270 SET(SUSPEND);
3271 break;
3272 default:
3273 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003274 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003275 }
3276
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003277 /* If the executable filename starts with 'r', we use restricted
3278 * mode. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003279 if (*(tail(argv[0])) == 'r')
3280 SET(RESTRICTED);
3281
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003282 /* If we're using restricted mode, disable suspending, backups, and
3283 * reading rcfiles, since they all would allow reading from or
3284 * writing to files not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003285 if (ISSET(RESTRICTED)) {
3286 UNSET(SUSPEND);
3287 UNSET(BACKUP_FILE);
3288 SET(NO_RCFILE);
3289 }
3290
Chris Allegretta7662c862003-01-13 01:35:15 +00003291/* We've read through the command line options. Now back up the flags
3292 and values that are set, and read the rcfile(s). If the values
3293 haven't changed afterward, restore the backed-up values. */
3294#ifdef ENABLE_NANORC
3295 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003296#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003297 char *operating_dir_cpy = operating_dir;
3298#endif
3299#ifndef DISABLE_WRAPPING
3300 int wrap_at_cpy = wrap_at;
3301#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003302#ifndef NANO_SMALL
3303 char *backup_dir_cpy = backup_dir;
3304#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003305#ifndef DISABLE_JUSTIFY
3306 char *quotestr_cpy = quotestr;
3307#endif
3308#ifndef DISABLE_SPELLER
3309 char *alt_speller_cpy = alt_speller;
3310#endif
3311 int tabsize_cpy = tabsize;
3312 long flags_cpy = flags;
3313
Chris Allegretta5ec68622003-02-05 02:39:34 +00003314#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003315 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003316#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003317#ifndef NANO_SMALL
3318 backup_dir = NULL;
3319#endif
Chris Allegretta5ec68622003-02-05 02:39:34 +00003320#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003321 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003322#endif
3323#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003324 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003325#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003326
3327 do_rcfile();
3328
3329#ifndef DISABLE_OPERATINGDIR
3330 if (operating_dir_cpy != NULL) {
3331 free(operating_dir);
3332 operating_dir = operating_dir_cpy;
3333 }
3334#endif
3335#ifndef DISABLE_WRAPPING
3336 if (fill_flag_used)
3337 wrap_at = wrap_at_cpy;
3338#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003339#ifndef NANO_SMALL
3340 if (backup_dir_cpy != NULL) {
3341 free(backup_dir);
3342 backup_dir = backup_dir_cpy;
3343 }
3344#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003345#ifndef DISABLE_JUSTIFY
3346 if (quotestr_cpy != NULL) {
3347 free(quotestr);
3348 quotestr = quotestr_cpy;
3349 }
3350#endif
3351#ifndef DISABLE_SPELLER
3352 if (alt_speller_cpy != NULL) {
3353 free(alt_speller);
3354 alt_speller = alt_speller_cpy;
3355 }
3356#endif
3357 if (tabsize_cpy > 0)
3358 tabsize = tabsize_cpy;
3359 flags |= flags_cpy;
3360 }
3361#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003362 else if (geteuid() == NANO_ROOT_UID)
Chris Allegretta7662c862003-01-13 01:35:15 +00003363 SET(NO_WRAP);
3364#endif
3365#endif /* ENABLE_NANORC */
3366
Chris Allegrettad8451932003-03-11 03:50:40 +00003367#ifndef NANO_SMALL
3368 history_init();
3369#ifdef ENABLE_NANORC
3370 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3371 load_history();
3372#endif
3373#endif
3374
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003375#ifndef NANO_SMALL
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003376 /* Set up the backup directory (unless we're using restricted mode,
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003377 * in which case backups are disabled, since they would allow
3378 * reading from or writing to files not specified on the command
3379 * line). This entails making sure it exists and is a directory, so
3380 * that backup files will be saved there. */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003381 if (!ISSET(RESTRICTED))
3382 init_backup_dir();
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003383#endif
3384
Chris Allegretta7662c862003-01-13 01:35:15 +00003385#ifndef DISABLE_OPERATINGDIR
3386 /* Set up the operating directory. This entails chdir()ing there,
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003387 * so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003388 init_operating_dir();
3389#endif
3390
Chris Allegretta7662c862003-01-13 01:35:15 +00003391#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003392 if (punct == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003393 punct = mallocstrcpy(punct, ".?!");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003394
3395 if (brackets == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003396 brackets = mallocstrcpy(brackets, "'\")}]>");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003397
Chris Allegretta7662c862003-01-13 01:35:15 +00003398 if (quotestr == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003399 quotestr = mallocstrcpy(NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00003400#ifdef HAVE_REGEX_H
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003401 "^([ \t]*[|>:}#])+"
Chris Allegretta7662c862003-01-13 01:35:15 +00003402#else
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003403 "> "
Chris Allegretta7662c862003-01-13 01:35:15 +00003404#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003405 );
Chris Allegretta7662c862003-01-13 01:35:15 +00003406#endif /* !DISABLE_JUSTIFY */
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003407
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00003408#ifndef DISABLE_SPELLER
3409 /* If we don't have an alternative spell checker after reading the
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003410 * command line and/or rcfile(s), check $SPELL for one, as Pico
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003411 * does (unless we're using restricted mode, in which case spell
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003412 * checking is disabled, since it would allow reading from or
3413 * writing to files not specified on the command line). */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003414 if (!ISSET(RESTRICTED) && alt_speller == NULL) {
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00003415 char *spellenv = getenv("SPELL");
3416 if (spellenv != NULL)
3417 alt_speller = mallocstrcpy(NULL, spellenv);
3418 }
3419#endif
3420
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00003421#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
3422 if (whitespace == NULL)
3423 whitespace = mallocstrcpy(NULL, " ");
3424#endif
3425
Chris Allegretta7662c862003-01-13 01:35:15 +00003426 if (tabsize == -1)
3427 tabsize = 8;
3428
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003429 /* Clear the filename we'll be using */
3430 filename = charalloc(1);
3431 filename[0] = '\0';
3432
Chris Allegretta7662c862003-01-13 01:35:15 +00003433 /* If there's a +LINE flag, it is the first non-option argument. */
3434 if (0 < optind && optind < argc && argv[optind][0] == '+') {
3435 startline = atoi(&argv[optind][1]);
3436 optind++;
3437 }
3438 if (0 < optind && optind < argc)
3439 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003440
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003441 /* See if there's a non-option in argv (first non-option is the
3442 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003443 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003444 /* Look for the +line flag... */
3445 if (argv[optind][0] == '+') {
3446 startline = atoi(&argv[optind][1]);
3447 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003448 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003449 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003450 } else
3451 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003452 }
3453
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003454 /* Back up the old terminal settings so that they can be restored. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003455 tcgetattr(0, &oldterm);
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003456
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003457 /* Curses initialization stuff: Start curses, save the state of the
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003458 * terminal mode, put the terminal in cbreak mode (read one character
3459 * at a time and interpret the special control keys), disable
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003460 * translation of carriage return (^M) into newline (^J) so that we
David Lawrence Ramseyfd462b12004-05-19 15:41:17 +00003461 * can tell the difference between the Enter key and Ctrl-J, and
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003462 * disable echoing of characters as they're typed. Finally, disable
3463 * interpretation of the special control keys, and if we're not in
3464 * preserve mode, disable interpretation of the flow control
3465 * characters too. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003466 initscr();
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003467 cbreak();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003468 nonl();
David Lawrence Ramseyd03216a2004-01-28 18:21:21 +00003469 noecho();
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003470 disable_signals();
3471 if (!ISSET(PRESERVE))
3472 disable_flow_control();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003473
3474#ifndef NANO_SMALL
3475 /* Save the terminal's current state, so that we can restore it
3476 * after a resize. */
3477 savetty();
3478#endif
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003479
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003480 /* Set up the global variables and the shortcuts. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003481 global_init(FALSE);
3482 shortcut_init(FALSE);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003483
3484 /* Set up the signal handlers. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003485 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003486
3487#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003488 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003489#endif
3490
Chris Allegretta2a42af12000-09-12 23:02:49 +00003491 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003492#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003493 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003494#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003495
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003496#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003497 fprintf(stderr, "Main: bottom win\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003498#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003499 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003500 display_main_list();
3501
3502#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003503 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003504#endif
3505
David Lawrence Ramsey97133f52004-05-14 17:39:19 +00003506 open_file(filename, 0, 0);
Chris Allegretta7662c862003-01-13 01:35:15 +00003507#ifdef ENABLE_MULTIBUFFER
3508 /* If we're using multibuffers and more than one file is specified
3509 on the command line, load them all and switch to the first one
3510 afterward */
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003511 if (optind + 1 < argc) {
3512 int old_multibuffer = ISSET(MULTIBUFFER);
3513 SET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003514 for (optind++; optind < argc; optind++) {
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003515 add_open_file(TRUE);
Chris Allegretta7662c862003-01-13 01:35:15 +00003516 new_file();
3517 filename = mallocstrcpy(filename, argv[optind]);
3518 open_file(filename, 0, 0);
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003519 load_file(FALSE);
Chris Allegretta7662c862003-01-13 01:35:15 +00003520 }
3521 open_nextfile_void();
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003522 if (!old_multibuffer)
3523 UNSET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003524 }
3525#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003526
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003527 titlebar(NULL);
3528
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003529 if (startline > 0)
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003530 do_gotoline(startline, 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003531
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003532#ifndef NANO_SMALL
3533 /* Return here after a SIGWINCH. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003534 sigsetjmp(jmpbuf, 1);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003535#endif
Chris Allegretta08020882001-01-29 23:37:54 +00003536
Robert Siemborski6967eec2000-07-08 14:23:32 +00003537 edit_refresh();
3538 reset_cursor();
3539
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00003540 while (TRUE) {
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003541 keyhandled = FALSE;
Chris Allegretta9239d742000-09-06 15:19:18 +00003542
Chris Allegrettad26ab912003-01-28 01:16:47 +00003543 if (ISSET(CONSTUPDATE))
David Lawrence Ramsey74912c62004-07-01 19:41:09 +00003544 do_cursorpos(TRUE);
Chris Allegrettad26ab912003-01-28 01:16:47 +00003545
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003546#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003547 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003548#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003549
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003550 kbinput = get_kbinput(edit, &meta_key);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003551#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003552 fprintf(stderr, "AHA! %c (%d)\n", kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003553#endif
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003554 if (meta_key == TRUE) {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003555 /* Check for the metaval and miscval defs... */
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003556 for (s =
3557#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || !defined(DISABLE_MOUSE)
3558 currshortcut
3559#else
3560 main_list
3561#endif
3562 ; s != NULL && !keyhandled; s = s->next) {
David Lawrence Ramsey82138502003-12-24 08:03:54 +00003563 if ((s->metaval != NANO_NO_KEY && kbinput == s->metaval) ||
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003564 (s->miscval != NANO_NO_KEY && kbinput == s->miscval)) {
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003565 if (ISSET(VIEW_MODE) && !s->viewok)
3566 print_view_warning();
3567 else {
3568 if (s->func != do_cut_text)
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003569 cutbuffer_reset();
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003570 s->func();
3571 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003572 keyhandled = TRUE;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003573 }
3574#ifndef NANO_SMALL
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003575 if (!keyhandled) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003576 /* And for toggle switches */
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003577 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003578 if (kbinput == t->val) {
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003579 cutbuffer_reset();
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003580 do_toggle(t);
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003581 keyhandled = TRUE;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003582 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003583 }
3584 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003585#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003586 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003587#ifdef DEBUG
3588 fprintf(stderr, "I got Alt-%c! (%d)\n", kbinput,
3589 kbinput);
3590#endif
3591 }
3592
3593 /* Look through the main shortcut list to see if we've hit a
3594 shortcut key or function key */
3595
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003596 if (!keyhandled) {
3597 for (s =
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003598#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || !defined(DISABLE_MOUSE)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003599 currshortcut
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003600#else
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003601 main_list
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003602#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003603 ; s != NULL && !keyhandled; s = s->next) {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003604 if ((s->ctrlval != NANO_NO_KEY && kbinput == s->ctrlval) ||
3605 (s->funcval != NANO_NO_KEY && kbinput == s->funcval)) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003606 if (ISSET(VIEW_MODE) && !s->viewok)
3607 print_view_warning();
3608 else {
3609 if (s->func != do_cut_text)
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003610 cutbuffer_reset();
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003611 s->func();
3612 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003613 keyhandled = TRUE;
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003614 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003615 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003616 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003617
3618 if (!keyhandled)
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003619 cutbuffer_reset();
Chris Allegrettae42df732002-10-15 00:27:55 +00003620
Chris Allegrettae42df732002-10-15 00:27:55 +00003621 /* Don't even think about changing this string */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003622 if (kbinput == NANO_XON_KEY)
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003623 statusbar(_("XON ignored, mumble mumble."));
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003624 if (kbinput == NANO_XOFF_KEY)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003625 statusbar(_("XOFF ignored, mumble mumble."));
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003626 if (kbinput == NANO_XON_KEY || kbinput == NANO_XOFF_KEY)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003627 keyhandled = TRUE;
Chris Allegretta9239d742000-09-06 15:19:18 +00003628
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003629 /* Catch ^Z by hand when triggered also */
3630 if (kbinput == NANO_SUSPEND_KEY) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003631 if (ISSET(SUSPEND))
3632 do_suspend(0);
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003633 keyhandled = TRUE;
Chris Allegretta9239d742000-09-06 15:19:18 +00003634 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003635
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003636 /* Last gasp, stuff that's not in the main lists */
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003637 if (!keyhandled) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003638 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003639#ifndef DISABLE_MOUSE
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003640 case KEY_MOUSE:
3641 do_mouse();
3642 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003643#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003644 case NANO_CONTROL_3: /* Ctrl-[ (Esc), which should
3645 * have been handled before we
3646 * got here */
3647 case NANO_CONTROL_5: /* Ctrl-] */
3648 break;
3649 default:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003650#ifdef DEBUG
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003651 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003652#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003653 /* We no longer stop unhandled sequences so that
3654 people with odd character sets can type... */
3655 if (ISSET(VIEW_MODE))
3656 print_view_warning();
3657 else
3658 do_char((char)kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003659 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003660 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003661 reset_cursor();
3662 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003663 }
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003664 assert(FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003665}