blob: 83ef8e057196c1d19a6da3f11c21040b8135e3c4 [file] [log] [blame]
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001/* $Id$ */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002/**************************************************************************
David Lawrence Ramsey4005fc62005-10-08 06:12:41 +00003 * text.c *
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00004 * *
David Lawrence Ramseyd8a1d372007-10-11 05:01:32 +00005 * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 *
6 * Free Software Foundation, Inc. *
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00007 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
David Lawrence Ramseyd0035b42007-08-11 05:17:36 +00009 * the Free Software Foundation; either version 3, or (at your option) *
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000010 * any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, but *
13 * WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
15 * General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
20 * 02110-1301, USA. *
21 * *
22 **************************************************************************/
23
David Lawrence Ramsey034b9942005-12-08 02:47:10 +000024#include "proto.h"
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000025
David Lawrence Ramseyee11c6a2005-11-02 19:42:02 +000026#include <stdio.h>
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000027#include <signal.h>
28#include <unistd.h>
29#include <string.h>
30#include <fcntl.h>
31#include <sys/wait.h>
32#include <errno.h>
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000033
David Lawrence Ramseyebe34252005-11-15 03:17:35 +000034#ifndef NANO_TINY
David Lawrence Ramsey8779a172005-11-08 16:45:22 +000035static pid_t pid = -1;
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +000036 /* The PID of the forked process in execute_command(), for use
37 * with the cancel_command() signal handler. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000038#endif
39#ifndef DISABLE_WRAPPING
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +000040static bool prepend_wrap = FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000041 /* Should we prepend wrapped text to the next line? */
42#endif
43#ifndef DISABLE_JUSTIFY
44static filestruct *jusbottom = NULL;
David Lawrence Ramseyae4c3a62005-09-20 19:46:39 +000045 /* Pointer to the end of the justify buffer. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000046#endif
47
David Lawrence Ramseyebe34252005-11-15 03:17:35 +000048#ifndef NANO_TINY
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +000049/* Toggle the mark. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000050void do_mark(void)
51{
52 openfile->mark_set = !openfile->mark_set;
53 if (openfile->mark_set) {
54 statusbar(_("Mark Set"));
55 openfile->mark_begin = openfile->current;
56 openfile->mark_begin_x = openfile->current_x;
57 } else {
David Lawrence Ramsey7b0531a2006-07-31 01:30:31 +000058 statusbar(_("Mark Unset"));
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000059 openfile->mark_begin = NULL;
60 openfile->mark_begin_x = 0;
61 edit_refresh();
62 }
63}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +000064#endif /* !NANO_TINY */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000065
David Lawrence Ramseyf1982f02006-12-10 17:57:09 +000066/* Delete the character under the cursor. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000067void do_delete(void)
68{
69 bool do_refresh = FALSE;
70 /* Do we have to call edit_refresh(), or can we get away with
David Lawrence Ramsey75e9dfe2006-05-18 17:50:08 +000071 * just update_line()? */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000072
Chris Allegretta07fcc4c2008-07-10 20:13:04 +000073#ifndef NANO_TINY
Chris Allegretta14c86202008-08-03 04:48:05 +000074 update_undo(DEL);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +000075#endif
76
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000077 assert(openfile->current != NULL && openfile->current->data != NULL && openfile->current_x <= strlen(openfile->current->data));
78
79 openfile->placewewant = xplustabs();
80
81 if (openfile->current->data[openfile->current_x] != '\0') {
82 int char_buf_len = parse_mbchar(openfile->current->data +
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +000083 openfile->current_x, NULL, NULL);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000084 size_t line_len = strlen(openfile->current->data +
85 openfile->current_x);
86
87 assert(openfile->current_x < strlen(openfile->current->data));
88
89 /* Let's get dangerous. */
90 charmove(&openfile->current->data[openfile->current_x],
91 &openfile->current->data[openfile->current_x +
92 char_buf_len], line_len - char_buf_len + 1);
93
94 null_at(&openfile->current->data, openfile->current_x +
95 line_len - char_buf_len);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +000096#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000097 if (openfile->mark_set && openfile->mark_begin ==
98 openfile->current && openfile->current_x <
99 openfile->mark_begin_x)
100 openfile->mark_begin_x -= char_buf_len;
101#endif
102 openfile->totsize--;
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +0000103 } else if (openfile->current != openfile->filebot) {
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000104 filestruct *foo = openfile->current->next;
105
106 assert(openfile->current_x == strlen(openfile->current->data));
107
108 /* If we're deleting at the end of a line, we need to call
109 * edit_refresh(). */
110 if (openfile->current->data[openfile->current_x] == '\0')
111 do_refresh = TRUE;
112
113 openfile->current->data = charealloc(openfile->current->data,
114 openfile->current_x + strlen(foo->data) + 1);
115 strcpy(openfile->current->data + openfile->current_x,
116 foo->data);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000117#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000118 if (openfile->mark_set && openfile->mark_begin ==
119 openfile->current->next) {
120 openfile->mark_begin = openfile->current;
121 openfile->mark_begin_x += openfile->current_x;
122 }
123#endif
124 if (openfile->filebot == foo)
125 openfile->filebot = openfile->current;
126
127 unlink_node(foo);
128 delete_node(foo);
129 renumber(openfile->current);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000130 openfile->totsize--;
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +0000131
David Lawrence Ramseya0168ca2005-11-05 17:35:44 +0000132 /* If the NO_NEWLINES flag isn't set, and text has been added to
133 * the magicline as a result of deleting at the end of the line
David Lawrence Ramsey0f6236f2005-11-09 00:08:29 +0000134 * before filebot, add a new magicline. */
David Lawrence Ramseya0168ca2005-11-05 17:35:44 +0000135 if (!ISSET(NO_NEWLINES) && openfile->current ==
136 openfile->filebot && openfile->current->data[0] != '\0')
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +0000137 new_magicline();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000138 } else
139 return;
140
David Lawrence Ramsey0f6236f2005-11-09 00:08:29 +0000141 set_modified();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000142
143#ifdef ENABLE_COLOR
144 /* If color syntaxes are available and turned on, we need to call
145 * edit_refresh(). */
146 if (openfile->colorstrings != NULL && !ISSET(NO_COLOR_SYNTAX))
147 do_refresh = TRUE;
148#endif
149
150 if (do_refresh)
Chris Allegrettafd265af2009-02-06 03:41:02 +0000151 edit_refresh_needed = TRUE;
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000152 else
153 update_line(openfile->current, openfile->current_x);
154}
155
David Lawrence Ramsey5b7b3e32005-12-31 21:22:54 +0000156/* Backspace over one character. That is, move the cursor left one
David Lawrence Ramsey84d22e32006-11-08 13:05:50 +0000157 * character, and then delete the character under the cursor. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000158void do_backspace(void)
159{
160 if (openfile->current != openfile->fileage ||
161 openfile->current_x > 0) {
David Lawrence Ramsey1c3bfa92005-09-13 04:53:44 +0000162 do_left();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000163 do_delete();
164 }
165}
166
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000167/* Insert a tab. If the TABS_TO_SPACES flag is set, insert the number
168 * of spaces that a tab would normally take up. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000169void do_tab(void)
170{
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000171#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000172 if (ISSET(TABS_TO_SPACES)) {
173 char *output;
David Lawrence Ramsey90b07fc2005-10-07 15:57:48 +0000174 size_t output_len = 0, new_pww = xplustabs();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000175
176 do {
177 new_pww++;
178 output_len++;
179 } while (new_pww % tabsize != 0);
180
181 output = charalloc(output_len + 1);
182
183 charset(output, ' ', output_len);
184 output[output_len] = '\0';
185
186 do_output(output, output_len, TRUE);
187
188 free(output);
189 } else {
190#endif
191 do_output("\t", 1, TRUE);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000192#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000193 }
194#endif
195}
196
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000197#ifndef NANO_TINY
David Lawrence Ramseye44cd2d2007-01-11 22:54:55 +0000198/* Indent or unindent the current line (or, if the mark is on, all lines
199 * covered by the mark) len columns, depending on whether len is
200 * positive or negative. If the TABS_TO_SPACES flag is set, indent or
201 * unindent by len spaces. Otherwise, indent or unindent by (len /
202 * tabsize) tabs and (len % tabsize) spaces. */
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000203void do_indent(ssize_t cols)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000204{
205 bool indent_changed = FALSE;
206 /* Whether any indenting or unindenting was done. */
207 bool unindent = FALSE;
208 /* Whether we're unindenting text. */
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000209 char *line_indent = NULL;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000210 /* The text added to each line in order to indent it. */
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000211 size_t line_indent_len = 0;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000212 /* The length of the text added to each line in order to indent
213 * it. */
214 filestruct *top, *bot, *f;
215 size_t top_x, bot_x;
216
217 assert(openfile->current != NULL && openfile->current->data != NULL);
218
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000219 /* If cols is zero, get out. */
220 if (cols == 0)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000221 return;
222
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000223 /* If cols is negative, make it positive and set unindent to
224 * TRUE. */
225 if (cols < 0) {
226 cols = -cols;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000227 unindent = TRUE;
228 /* Otherwise, we're indenting, in which case the file will always be
229 * modified, so set indent_changed to TRUE. */
230 } else
231 indent_changed = TRUE;
232
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000233 /* If the mark is on, use all lines covered by the mark. */
234 if (openfile->mark_set)
235 mark_order((const filestruct **)&top, &top_x,
236 (const filestruct **)&bot, &bot_x, NULL);
237 /* Otherwise, use the current line. */
238 else {
239 top = openfile->current;
240 bot = top;
241 }
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000242
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000243 if (!unindent) {
244 /* Set up the text we'll be using as indentation. */
245 line_indent = charalloc(cols + 1);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000246
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000247 if (ISSET(TABS_TO_SPACES)) {
248 /* Set the indentation to cols spaces. */
249 charset(line_indent, ' ', cols);
250 line_indent_len = cols;
251 } else {
252 /* Set the indentation to (cols / tabsize) tabs and (cols %
253 * tabsize) spaces. */
254 size_t num_tabs = cols / tabsize;
255 size_t num_spaces = cols % tabsize;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000256
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000257 charset(line_indent, '\t', num_tabs);
258 charset(line_indent + num_tabs, ' ', num_spaces);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000259
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000260 line_indent_len = num_tabs + num_spaces;
261 }
262
263 line_indent[line_indent_len] = '\0';
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000264 }
265
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000266 /* Go through each line of the text. */
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000267 for (f = top; f != bot->next; f = f->next) {
268 size_t line_len = strlen(f->data);
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000269 size_t indent_len = indent_length(f->data);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000270
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000271 if (!unindent) {
272 /* If we're indenting, add the characters in line_indent to
273 * the beginning of the non-whitespace text of this line. */
274 f->data = charealloc(f->data, line_len +
275 line_indent_len + 1);
276 charmove(&f->data[indent_len + line_indent_len],
277 &f->data[indent_len], line_len - indent_len + 1);
278 strncpy(f->data + indent_len, line_indent, line_indent_len);
279 openfile->totsize += line_indent_len;
280
281 /* Keep track of the change in the current line. */
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000282 if (openfile->mark_set && f == openfile->mark_begin &&
283 openfile->mark_begin_x >= indent_len)
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000284 openfile->mark_begin_x += line_indent_len;
285
286 if (f == openfile->current && openfile->current_x >=
287 indent_len)
288 openfile->current_x += line_indent_len;
289
290 /* If the NO_NEWLINES flag isn't set, and this is the
291 * magicline, add a new magicline. */
292 if (!ISSET(NO_NEWLINES) && f == openfile->filebot)
293 new_magicline();
294 } else {
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000295 size_t indent_col = strnlenpt(f->data, indent_len);
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000296 /* The length in columns of the indentation on this
297 * line. */
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000298
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000299 if (cols <= indent_col) {
300 size_t indent_new = actual_x(f->data, indent_col -
301 cols);
David Lawrence Ramsey5bb77272006-05-06 14:37:33 +0000302 /* The length of the indentation remaining on
303 * this line after we unindent. */
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000304 size_t indent_shift = indent_len - indent_new;
David Lawrence Ramsey5bb77272006-05-06 14:37:33 +0000305 /* The change in the indentation on this line
306 * after we unindent. */
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000307
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000308 /* If we're unindenting, and there's at least cols
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000309 * columns' worth of indentation at the beginning of the
310 * non-whitespace text of this line, remove it. */
311 charmove(&f->data[indent_new], &f->data[indent_len],
312 line_len - indent_shift - indent_new + 1);
313 null_at(&f->data, line_len - indent_shift + 1);
314 openfile->totsize -= indent_shift;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000315
David Lawrence Ramsey2e8fac62006-04-29 15:44:58 +0000316 /* Keep track of the change in the current line. */
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000317 if (openfile->mark_set && f == openfile->mark_begin &&
David Lawrence Ramseyeb4f90e2006-05-05 14:22:42 +0000318 openfile->mark_begin_x > indent_new) {
319 if (openfile->mark_begin_x <= indent_len)
320 openfile->mark_begin_x = indent_new;
321 else
322 openfile->mark_begin_x -= indent_shift;
323 }
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000324
David Lawrence Ramseyac37b042006-05-03 12:59:05 +0000325 if (f == openfile->current && openfile->current_x >
David Lawrence Ramseyeb4f90e2006-05-05 14:22:42 +0000326 indent_new) {
327 if (openfile->current_x <= indent_len)
328 openfile->current_x = indent_new;
329 else
330 openfile->current_x -= indent_shift;
331 }
David Lawrence Ramsey7194a612006-04-29 16:11:21 +0000332
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000333 /* We've unindented, so set indent_changed to TRUE. */
334 if (!indent_changed)
335 indent_changed = TRUE;
336 }
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000337 }
338 }
339
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000340 if (!unindent)
David Lawrence Ramsey25456862006-05-05 15:43:52 +0000341 /* Clean up. */
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000342 free(line_indent);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000343
344 if (indent_changed) {
345 /* Mark the file as modified. */
346 set_modified();
347
348 /* Update the screen. */
Chris Allegrettafd265af2009-02-06 03:41:02 +0000349 edit_refresh_needed = TRUE;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000350 }
351}
352
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000353/* Indent the current line, or all lines covered by the mark if the mark
354 * is on, tabsize columns. */
355void do_indent_void(void)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000356{
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000357 do_indent(tabsize);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000358}
359
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000360/* Unindent the current line, or all lines covered by the mark if the
361 * mark is on, tabsize columns. */
362void do_unindent(void)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000363{
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000364 do_indent(-tabsize);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000365}
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000366
Chris Allegrettab549f372008-09-16 21:35:19 +0000367/* undo a cut, or re-do an uncut */
368void undo_cut(undo *u)
369{
370 cutbuffer = copy_filestruct(u->cutbuffer);
371
372 /* Compute cutbottom for the uncut using out copy */
373 for (cutbottom = cutbuffer; cutbottom->next != NULL; cutbottom = cutbottom->next)
374 ;
375
376 /* Get to where we need to uncut from */
377 if (u->mark_set && u->mark_begin_lineno < u->lineno)
378 do_gotolinecolumn(u->mark_begin_lineno, u->mark_begin_x+1, FALSE, FALSE, FALSE, FALSE);
379 else
380 do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE);
381
382 copy_from_filestruct(cutbuffer, cutbottom);
383 free_filestruct(cutbuffer);
384 cutbuffer = NULL;
385
386}
387
388/* Re-do a cut, or undo an uncut */
389void redo_cut(undo *u) {
390 int i;
Chris Allegrettac81cf522008-10-14 04:34:56 +0000391 filestruct *t, *c;
Chris Allegrettab549f372008-09-16 21:35:19 +0000392
393 do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE);
394 openfile->mark_set = u->mark_set;
395 if (cutbuffer)
396 free(cutbuffer);
397 cutbuffer = NULL;
398
399 /* Move ahead the same # lines we had if a marked cut */
400 if (u->mark_set) {
401 for (i = 1, t = openfile->fileage; i != u->mark_begin_lineno; i++)
402 t = t->next;
403 openfile->mark_begin = t;
404 } else if (!u->to_end) {
405 /* Here we have a regular old potentially multi-line ^K cut. We'll
406 need to trick nano into thinking it's a marked cut to cut more
407 than one line again */
Chris Allegrettac81cf522008-10-14 04:34:56 +0000408 for (c = u->cutbuffer, t = openfile->current; c->next != NULL && t->next != NULL; ) {
Chris Allegrettab549f372008-09-16 21:35:19 +0000409
410#ifdef DEBUG
411 fprintf(stderr, "Advancing, lineno = %d, data = \"%s\"\n", t->lineno, t->data);
412#endif
Chris Allegrettac81cf522008-10-14 04:34:56 +0000413 c = c->next;
Chris Allegrettab549f372008-09-16 21:35:19 +0000414 t = t->next;
415 }
416 openfile->mark_begin = t;
417 openfile->mark_begin_x = 0;
418 openfile->mark_set = TRUE;
419 }
420
421 openfile->mark_begin_x = u->mark_begin_x;
422 do_cut_text(FALSE, u->to_end, TRUE);
423 openfile->mark_set = FALSE;
424 openfile->mark_begin = NULL;
425 openfile->mark_begin_x = 0;
Chris Allegrettafd265af2009-02-06 03:41:02 +0000426 edit_refresh_needed = TRUE;
Chris Allegrettab549f372008-09-16 21:35:19 +0000427}
428
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000429/* Undo the last thing(s) we did */
430void do_undo(void)
431{
432 undo *u = openfile->current_undo;
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000433 filestruct *f = openfile->current, *t;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000434 int len = 0;
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000435 char *undidmsg, *data;
Chris Allegretta14c86202008-08-03 04:48:05 +0000436 filestruct *oldcutbuffer = cutbuffer, *oldcutbottom = cutbottom;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000437
438 if (!u) {
439 statusbar(_("Nothing in undo buffer!"));
440 return;
441 }
442
443
444 if (u->lineno <= f->lineno)
445 for (; f->prev != NULL && f->lineno != u->lineno; f = f->prev)
446 ;
447 else
448 for (; f->next != NULL && f->lineno != u->lineno; f = f->next)
449 ;
450 if (f->lineno != u->lineno) {
Chris Allegretta77bf1b52008-08-21 04:21:06 +0000451 statusbar(_("Internal error: can't match line %d. Please save your work"), u->lineno);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000452 return;
453 }
454#ifdef DEBUG
455 fprintf(stderr, "data we're about to undo = \"%s\"\n", f->data);
456 fprintf(stderr, "Undo running for type %d\n", u->type);
457#endif
458
Chris Allegrettafa406942008-07-13 16:44:19 +0000459 openfile->current_x = u->begin;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000460 switch(u->type) {
461 case ADD:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000462 undidmsg = _("text add");
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000463 len = strlen(f->data) - strlen(u->strdata) + 1;
464 data = charalloc(len);
465 strncpy(data, f->data, u->begin);
466 strcpy(&data[u->begin], &f->data[u->begin + strlen(u->strdata)]);
467 free(f->data);
468 f->data = data;
469 break;
470 case DEL:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000471 undidmsg = _("text delete");
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000472 len = strlen(f->data) + strlen(u->strdata) + 1;
473 data = charalloc(len);
474
475 strncpy(data, f->data, u->begin);
476 strcpy(&data[u->begin], u->strdata);
477 strcpy(&data[u->begin + strlen(u->strdata)], &f->data[u->begin]);
478 free(f->data);
479 f->data = data;
Chris Allegretta0b499d42008-07-14 07:18:22 +0000480 if (u->xflags == UNDO_DEL_BACKSPACE)
481 openfile->current_x += strlen(u->strdata);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000482 break;
483 case SPLIT:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000484 undidmsg = _("line split");
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000485 free(f->data);
486 f->data = mallocstrcpy(NULL, u->strdata);
487 if (f->next != NULL) {
488 filestruct *tmp = f->next;
489 unlink_node(tmp);
490 delete_node(tmp);
491 }
Chris Allegretta0b499d42008-07-14 07:18:22 +0000492 renumber(f);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000493 break;
494 case UNSPLIT:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000495 undidmsg = _("line join");
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000496 t = make_new_node(f);
497 t->data = mallocstrcpy(NULL, u->strdata);
498 data = mallocstrncpy(NULL, f->data, u->begin);
499 data[u->begin] = '\0';
500 free(f->data);
501 f->data = data;
502 splice_node(f, t, f->next);
Chris Allegretta0b499d42008-07-14 07:18:22 +0000503 renumber(f);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000504 break;
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000505 case CUT:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000506 undidmsg = _("text cut");
Chris Allegrettab549f372008-09-16 21:35:19 +0000507 undo_cut(u);
508 break;
509 case UNCUT:
510 undidmsg = _("text uncut");
511 redo_cut(u);
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000512 break;
Chris Allegretta14c86202008-08-03 04:48:05 +0000513 case INSERT:
514 undidmsg = _("text insert");
515 cutbuffer = NULL;
516 cutbottom = NULL;
517 /* When we updated mark_begin_lineno in update_undo, it was effectively how many line
518 were inserted due to being partitioned before read_file was called. So we
519 add its value here */
520 openfile->mark_begin = fsfromline(u->lineno + u->mark_begin_lineno - 1);
521 openfile->mark_begin_x = 0;
522 openfile->mark_set = TRUE;
523 do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE);
524 cut_marked();
525 u->cutbuffer = cutbuffer;
526 u->cutbottom = cutbottom;
527 cutbuffer = oldcutbuffer;
528 cutbottom = oldcutbottom;
529 openfile->mark_set = FALSE;
530 break;
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000531 case REPLACE:
532 undidmsg = _("text replace");
533 data = u->strdata;
534 u->strdata = f->data;
535 f->data = data;
536 break;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000537 default:
Chris Allegretta77bf1b52008-08-21 04:21:06 +0000538 undidmsg = _("Internal error: unknown type. Please save your work");
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000539 break;
540
541 }
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000542 do_gotolinecolumn(u->lineno, u->begin, FALSE, FALSE, FALSE, TRUE);
543 statusbar(_("Undid action (%s)"), undidmsg);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000544 openfile->current_undo = openfile->current_undo->next;
Chris Allegretta6f681c12008-08-08 03:02:03 +0000545 openfile->last_action = OTHER;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000546}
547
548void do_redo(void)
549{
550 undo *u = openfile->undotop;
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000551 filestruct *f = openfile->current, *t;
Chris Allegretta4e12cb82008-10-14 19:55:34 +0000552 int len = 0;
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000553 char *undidmsg, *data;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000554
555 for (; u != NULL && u->next != openfile->current_undo; u = u->next)
556 ;
557 if (!u) {
558 statusbar(_("Nothing to re-do!"));
559 return;
560 }
561 if (u->next != openfile->current_undo) {
Chris Allegretta77bf1b52008-08-21 04:21:06 +0000562 statusbar(_("Internal error: Redo setup failed. Please save your work"));
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000563 return;
564 }
565
566 if (u->lineno <= f->lineno)
567 for (; f->prev != NULL && f->lineno != u->lineno; f = f->prev)
568 ;
569 else
570 for (; f->next != NULL && f->lineno != u->lineno; f = f->next)
571 ;
572 if (f->lineno != u->lineno) {
Chris Allegretta77bf1b52008-08-21 04:21:06 +0000573 statusbar(_("Internal error: can't match line %d. Please save your work"), u->lineno);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000574 return;
575 }
576#ifdef DEBUG
577 fprintf(stderr, "data we're about to redo = \"%s\"\n", f->data);
578 fprintf(stderr, "Redo running for type %d\n", u->type);
579#endif
580
581 switch(u->type) {
582 case ADD:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000583 undidmsg = _("text add");
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000584 len = strlen(f->data) + strlen(u->strdata) + 1;
585 data = charalloc(len);
Chris Allegretta1f37c452008-08-01 04:11:57 +0000586 strncpy(data, f->data, u->begin);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000587 strcpy(&data[u->begin], u->strdata);
588 strcpy(&data[u->begin + strlen(u->strdata)], &f->data[u->begin]);
589 free(f->data);
590 f->data = data;
591 break;
592 case DEL:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000593 undidmsg = _("text delete");
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000594 len = strlen(f->data) + strlen(u->strdata) + 1;
595 data = charalloc(len);
596 strncpy(data, f->data, u->begin);
597 strcpy(&data[u->begin], &f->data[u->begin + strlen(u->strdata)]);
598 free(f->data);
599 f->data = data;
600 break;
601 case SPLIT:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000602 undidmsg = _("line split");
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000603 t = make_new_node(f);
Chris Allegretta5c27d722008-08-09 09:28:07 +0000604 t->data = mallocstrcpy(NULL, &u->strdata[u->begin]);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000605 data = mallocstrncpy(NULL, f->data, u->begin);
606 data[u->begin] = '\0';
607 free(f->data);
608 f->data = data;
609 splice_node(f, t, f->next);
Chris Allegretta0b499d42008-07-14 07:18:22 +0000610 renumber(f);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000611 break;
612 case UNSPLIT:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000613 undidmsg = _("line join");
Chris Allegretta0b499d42008-07-14 07:18:22 +0000614 len = strlen(f->data) + strlen(u->strdata + 1);
615 data = charalloc(len);
616 strcpy(data, f->data);
617 strcat(data, u->strdata);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000618 free(f->data);
Chris Allegretta0b499d42008-07-14 07:18:22 +0000619 f->data = data;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000620 if (f->next != NULL) {
621 filestruct *tmp = f->next;
622 unlink_node(tmp);
623 delete_node(tmp);
624 }
Chris Allegretta0b499d42008-07-14 07:18:22 +0000625 renumber(f);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000626 break;
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000627 case CUT:
Chris Allegrettab549f372008-09-16 21:35:19 +0000628 undidmsg = _("text cut");
629 redo_cut(u);
630 break;
631 case UNCUT:
632 undidmsg = _("text uncut");
633 undo_cut(u);
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000634 break;
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000635 case REPLACE:
636 undidmsg = _("text replace");
637 data = u->strdata;
638 u->strdata = f->data;
639 f->data = data;
640 break;
Chris Allegrettab549f372008-09-16 21:35:19 +0000641 case INSERT:
Chris Allegrettaea577872008-08-03 20:19:42 +0000642 undidmsg = _("text insert");
Chris Allegrettaea577872008-08-03 20:19:42 +0000643 do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE);
Chris Allegrettab549f372008-09-16 21:35:19 +0000644 copy_from_filestruct(u->cutbuffer, u->cutbottom);
645 openfile->placewewant = xplustabs();
Chris Allegrettaea577872008-08-03 20:19:42 +0000646 break;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000647 default:
Chris Allegretta77bf1b52008-08-21 04:21:06 +0000648 undidmsg = _("Internal error: unknown type. Please save your work");
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000649 break;
650
651 }
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000652 do_gotolinecolumn(u->lineno, u->begin, FALSE, FALSE, FALSE, TRUE);
653 statusbar(_("Redid action (%s)"), undidmsg);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000654
655 openfile->current_undo = u;
Chris Allegretta6f681c12008-08-08 03:02:03 +0000656 openfile->last_action = OTHER;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000657
658}
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000659#endif /* !NANO_TINY */
660
David Lawrence Ramseyb0e04c02005-12-08 07:24:54 +0000661/* Someone hits Enter *gasp!* */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000662void do_enter(void)
663{
664 filestruct *newnode = make_new_node(openfile->current);
665 size_t extra = 0;
666
Chris Allegrettadc7136a2008-08-21 04:24:25 +0000667 assert(openfile->current != NULL && openfile->current->data != NULL);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000668
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000669#ifndef NANO_TINY
Chris Allegretta14c86202008-08-03 04:48:05 +0000670 update_undo(SPLIT);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000671
672
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000673 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
674 if (ISSET(AUTOINDENT)) {
675 /* If we are breaking the line in the indentation, the new
676 * indentation should have only current_x characters, and
677 * current_x should not change. */
678 extra = indent_length(openfile->current->data);
679 if (extra > openfile->current_x)
680 extra = openfile->current_x;
681 }
682#endif
683 newnode->data = charalloc(strlen(openfile->current->data +
684 openfile->current_x) + extra + 1);
685 strcpy(&newnode->data[extra], openfile->current->data +
686 openfile->current_x);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000687#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000688 if (ISSET(AUTOINDENT)) {
689 strncpy(newnode->data, openfile->current->data, extra);
690 openfile->totsize += mbstrlen(newnode->data);
691 }
692#endif
693 null_at(&openfile->current->data, openfile->current_x);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000694#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000695 if (openfile->mark_set && openfile->current ==
696 openfile->mark_begin && openfile->current_x <
697 openfile->mark_begin_x) {
698 openfile->mark_begin = newnode;
699 openfile->mark_begin_x += extra - openfile->current_x;
700 }
701#endif
702 openfile->current_x = extra;
703
704 if (openfile->current == openfile->filebot)
705 openfile->filebot = newnode;
706 splice_node(openfile->current, newnode,
707 openfile->current->next);
708
709 renumber(openfile->current);
710 openfile->current = newnode;
711
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000712 openfile->totsize++;
713 set_modified();
David Lawrence Ramseyfeb89db2005-09-13 04:45:46 +0000714
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000715 openfile->placewewant = xplustabs();
David Lawrence Ramseyfeb89db2005-09-13 04:45:46 +0000716
Chris Allegrettafd265af2009-02-06 03:41:02 +0000717 edit_refresh_needed = TRUE;
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000718}
719
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000720#ifndef NANO_TINY
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000721/* Send a SIGKILL (unconditional kill) to the forked process in
722 * execute_command(). */
David Lawrence Ramsey8befda62005-12-06 19:39:56 +0000723RETSIGTYPE cancel_command(int signal)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000724{
725 if (kill(pid, SIGKILL) == -1)
726 nperror("kill");
727}
728
David Lawrence Ramsey0ed71712005-11-08 23:09:47 +0000729/* Execute command in a shell. Return TRUE on success. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000730bool execute_command(const char *command)
731{
732 int fd[2];
733 FILE *f;
David Lawrence Ramseyeae85712005-11-29 05:48:06 +0000734 char *shellenv;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000735 struct sigaction oldaction, newaction;
736 /* Original and temporary handlers for SIGINT. */
737 bool sig_failed = FALSE;
738 /* Did sigaction() fail without changing the signal handlers? */
739
740 /* Make our pipes. */
741 if (pipe(fd) == -1) {
742 statusbar(_("Could not pipe"));
743 return FALSE;
744 }
745
David Lawrence Ramseyeae85712005-11-29 05:48:06 +0000746 /* Check $SHELL for the shell to use. If it isn't set, use
David Lawrence Ramsey1932dfb2005-11-29 05:52:49 +0000747 * /bin/sh. Note that $SHELL should contain only a path, with no
748 * arguments. */
David Lawrence Ramseyeae85712005-11-29 05:48:06 +0000749 shellenv = getenv("SHELL");
750 if (shellenv == NULL)
751 shellenv = "/bin/sh";
752
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000753 /* Fork a child. */
754 if ((pid = fork()) == 0) {
755 close(fd[0]);
756 dup2(fd[1], fileno(stdout));
757 dup2(fd[1], fileno(stderr));
758
759 /* If execl() returns at all, there was an error. */
David Lawrence Ramsey5da68ee2005-11-29 05:21:06 +0000760 execl(shellenv, tail(shellenv), "-c", command, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000761 exit(0);
762 }
763
David Lawrence Ramseyc838a4c2006-04-26 18:33:50 +0000764 /* Continue as parent. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000765 close(fd[1]);
766
767 if (pid == -1) {
768 close(fd[0]);
769 statusbar(_("Could not fork"));
770 return FALSE;
771 }
772
773 /* Before we start reading the forked command's output, we set
774 * things up so that Ctrl-C will cancel the new process. */
775
776 /* Enable interpretation of the special control keys so that we get
777 * SIGINT when Ctrl-C is pressed. */
778 enable_signals();
779
780 if (sigaction(SIGINT, NULL, &newaction) == -1) {
781 sig_failed = TRUE;
782 nperror("sigaction");
783 } else {
784 newaction.sa_handler = cancel_command;
785 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
786 sig_failed = TRUE;
787 nperror("sigaction");
788 }
789 }
790
791 /* Note that now oldaction is the previous SIGINT signal handler,
792 * to be restored later. */
793
794 f = fdopen(fd[0], "rb");
795 if (f == NULL)
796 nperror("fdopen");
797
Chris Allegretta14c86202008-08-03 04:48:05 +0000798 read_file(f, "stdin", TRUE);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000799
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000800 if (wait(NULL) == -1)
801 nperror("wait");
802
803 if (!sig_failed && sigaction(SIGINT, &oldaction, NULL) == -1)
804 nperror("sigaction");
805
David Lawrence Ramsey8b9c91b2007-12-18 01:28:53 +0000806 /* Restore the terminal to its previous state. In the process,
807 * disable interpretation of the special control keys so that we can
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000808 * use Ctrl-C for other things. */
David Lawrence Ramsey8b9c91b2007-12-18 01:28:53 +0000809 terminal_init();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000810
811 return TRUE;
812}
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000813
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000814/* Add a new undo struct to the top of the current pile */
Chris Allegretta14c86202008-08-03 04:48:05 +0000815void add_undo(undo_type current_action)
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000816{
Chris Allegretta4e12cb82008-10-14 19:55:34 +0000817 undo *u;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000818 char *data;
Chris Allegretta14c86202008-08-03 04:48:05 +0000819 openfilestruct *fs = openfile;
Chris Allegretta5c1c1432008-10-04 11:10:11 +0000820 static undo *last_cutu = NULL; /* Last thing we cut to set up the undo for uncut */
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000821
Chris Allegretta8f761122008-08-01 06:52:15 +0000822 /* Ugh, if we were called while cutting not-to-end, non-marked and on the same lineno,
823 we need to abort here */
824 u = fs->current_undo;
Chris Allegretta80ea9c52008-08-09 10:08:33 +0000825 if (current_action == CUT && u && u->type == CUT
826 && !u->mark_set && u->lineno == fs->current->lineno)
Chris Allegretta8f761122008-08-01 06:52:15 +0000827 return;
828
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000829 /* Blow away the old undo stack if we are starting from the middle */
Chris Allegretta91a18622008-08-01 03:50:20 +0000830 while (fs->undotop != NULL && fs->undotop != fs->current_undo) {
831 undo *u2 = fs->undotop;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000832 fs->undotop = fs->undotop->next;
Chris Allegretta91a18622008-08-01 03:50:20 +0000833 if (u2->strdata != NULL)
834 free(u2->strdata);
Chris Allegretta6f681c12008-08-08 03:02:03 +0000835 if (u2->cutbuffer)
Chris Allegrettaea577872008-08-03 20:19:42 +0000836 free_filestruct(u2->cutbuffer);
Chris Allegretta91a18622008-08-01 03:50:20 +0000837 free(u2);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000838 }
839
Chris Allegretta8f761122008-08-01 06:52:15 +0000840 /* Allocate and initialize a new undo type */
841 u = nmalloc(sizeof(undo));
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000842 u->type = current_action;
843 u->lineno = fs->current->lineno;
844 u->begin = fs->current_x;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000845 u->next = fs->undotop;
846 fs->undotop = u;
847 fs->current_undo = u;
Chris Allegretta91a18622008-08-01 03:50:20 +0000848 u->strdata = NULL;
849 u->cutbuffer = NULL;
850 u->cutbottom = NULL;
Chris Allegrettab549f372008-09-16 21:35:19 +0000851 u->mark_set = 0;
Chris Allegrettad31ddb72008-08-01 07:29:06 +0000852 u->mark_begin_lineno = 0;
853 u->mark_begin_x = 0;
Chris Allegretta91a18622008-08-01 03:50:20 +0000854 u->xflags = 0;
Chris Allegrettac81cf522008-10-14 04:34:56 +0000855 u->to_end = FALSE;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000856
857 switch (u->type) {
858 /* We need to start copying data into the undo buffer or we wont be able
859 to restore it later */
860 case ADD:
861 data = charalloc(2);
862 data[0] = fs->current->data[fs->current_x];
863 data[1] = '\0';
864 u->strdata = data;
865 break;
866 case DEL:
867 if (u->begin != strlen(fs->current->data)) {
868 data = mallocstrncpy(NULL, &fs->current->data[u->begin], 2);
869 data[1] = '\0';
870 u->strdata = data;
871 break;
872 }
873 /* Else purposely fall into unsplit code */
874 current_action = u->type = UNSPLIT;
875 case UNSPLIT:
876 if (fs->current->next) {
877 data = mallocstrcpy(NULL, fs->current->next->data);
878 u->strdata = data;
879 }
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000880 break;
Chris Allegretta14c86202008-08-03 04:48:05 +0000881 case INSERT:
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000882 case SPLIT:
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000883 case REPLACE:
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000884 data = mallocstrcpy(NULL, fs->current->data);
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000885 u->strdata = data;
886 break;
887 case CUT:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000888 u->mark_set = openfile->mark_set;
889 if (u->mark_set) {
890 u->mark_begin_lineno = openfile->mark_begin->lineno;
891 u->mark_begin_x = openfile->mark_begin_x;
892 }
Chris Allegrettac84e7652008-10-14 01:14:12 +0000893 u->to_end = (ISSET(CUT_TO_END)) ? TRUE : FALSE;
Chris Allegretta5c1c1432008-10-04 11:10:11 +0000894 last_cutu = u;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000895 break;
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000896 case UNCUT:
Chris Allegretta5c1c1432008-10-04 11:10:11 +0000897 if (!last_cutu)
898 statusbar(_("Internal error: can't setup uncut. Please save your work."));
899 else if (last_cutu->type == CUT) {
900 u->cutbuffer = last_cutu->cutbuffer;
901 u->cutbottom = last_cutu->cutbottom;
Chris Allegretta5c1c1432008-10-04 11:10:11 +0000902 }
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000903 break;
904 case OTHER:
Chris Allegretta77bf1b52008-08-21 04:21:06 +0000905 statusbar(_("Internal error: unknown type. Please save your work."));
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000906 break;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000907 }
908
909#ifdef DEBUG
910 fprintf(stderr, "fs->current->data = \"%s\", current_x = %d, u->begin = %d, type = %d\n",
911 fs->current->data, fs->current_x, u->begin, current_action);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000912 fprintf(stderr, "left update_add...\n");
913#endif
914 fs->last_action = current_action;
915}
916
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000917/* Update an undo item, or determine whether a new one
918 is really needed and bounce the data to add_undo
919 instead. The latter functionality just feels
920 gimmicky and may just be more hassle than
921 it's worth, so it should be axed if needed. */
Chris Allegretta14c86202008-08-03 04:48:05 +0000922void update_undo(undo_type action)
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000923{
924 undo *u;
925 char *data;
926 int len = 0;
Chris Allegretta14c86202008-08-03 04:48:05 +0000927 openfilestruct *fs = openfile;
Chris Allegretta91a18622008-08-01 03:50:20 +0000928
929#ifdef DEBUG
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000930 fprintf(stderr, "action = %d, fs->last_action = %d, openfile->current->lineno = %d",
931 action, fs->last_action, openfile->current->lineno);
932 if (fs->current_undo)
933 fprintf(stderr, "fs->current_undo->lineno = %d\n", fs->current_undo->lineno);
934 else
935 fprintf(stderr, "\n");
Chris Allegretta91a18622008-08-01 03:50:20 +0000936#endif
937
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000938 /* Change to an add if we're not using the same undo struct
939 that we should be using */
940 if (action != fs->last_action
Chris Allegrettac84e7652008-10-14 01:14:12 +0000941 || (action != CUT && action != INSERT
Chris Allegretta91a18622008-08-01 03:50:20 +0000942 && openfile->current->lineno != fs->current_undo->lineno)) {
Chris Allegretta14c86202008-08-03 04:48:05 +0000943 add_undo(action);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000944 return;
945 }
946
947 assert(fs->undotop != NULL);
948 u = fs->undotop;
949
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000950 switch (u->type) {
951 case ADD:
952#ifdef DEBUG
953 fprintf(stderr, "fs->current->data = \"%s\", current_x = %d, u->begin = %d\n",
954 fs->current->data, fs->current_x, u->begin);
955#endif
956 len = strlen(u->strdata) + 2;
957 data = nrealloc((void *) u->strdata, len * sizeof(char *));
958 data[len-2] = fs->current->data[fs->current_x];
959 data[len-1] = '\0';
960 u->strdata = (char *) data;
961#ifdef DEBUG
962 fprintf(stderr, "current undo data now \"%s\"\n", u->strdata);
963#endif
964 break;
965 case DEL:
966 len = strlen(u->strdata) + 2;
967 assert(len > 2);
968 if (fs->current_x == u->begin) {
969 /* They're deleting */
Chris Allegretta0b499d42008-07-14 07:18:22 +0000970 if (!u->xflags)
971 u->xflags = UNDO_DEL_DEL;
972 else if (u->xflags != UNDO_DEL_DEL) {
Chris Allegretta14c86202008-08-03 04:48:05 +0000973 add_undo(action);
Chris Allegretta0b499d42008-07-14 07:18:22 +0000974 return;
975 }
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000976 data = charalloc(len);
977 strcpy(data, u->strdata);
978 data[len-2] = fs->current->data[fs->current_x];;
979 data[len-1] = '\0';
980 free(u->strdata);
981 u->strdata = data;
982 } else if (fs->current_x == u->begin - 1) {
983 /* They're backspacing */
Chris Allegretta0b499d42008-07-14 07:18:22 +0000984 if (!u->xflags)
985 u->xflags = UNDO_DEL_BACKSPACE;
986 else if (u->xflags != UNDO_DEL_BACKSPACE) {
Chris Allegretta14c86202008-08-03 04:48:05 +0000987 add_undo(action);
Chris Allegretta0b499d42008-07-14 07:18:22 +0000988 return;
989 }
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000990 data = charalloc(len);
991 data[0] = fs->current->data[fs->current_x];
992 strcpy(&data[1], u->strdata);
993 free(u->strdata);
994 u->strdata = data;
995 u->begin--;
996 } else {
997 /* They deleted something else on the line */
Chris Allegretta14c86202008-08-03 04:48:05 +0000998 add_undo(DEL);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000999 return;
1000 }
1001#ifdef DEBUG
Chris Allegretta0b499d42008-07-14 07:18:22 +00001002 fprintf(stderr, "current undo data now \"%s\"\nu->begin = %d\n", u->strdata, u->begin);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001003#endif
1004 break;
Chris Allegretta12dc8ca2008-07-31 04:24:04 +00001005 case CUT:
Chris Allegrettac84e7652008-10-14 01:14:12 +00001006 if (!cutbuffer)
1007 break;
Chris Allegretta8f761122008-08-01 06:52:15 +00001008 if (u->cutbuffer)
1009 free(u->cutbuffer);
Chris Allegretta12dc8ca2008-07-31 04:24:04 +00001010 u->cutbuffer = copy_filestruct(cutbuffer);
Chris Allegrettac81cf522008-10-14 04:34:56 +00001011 /* Compute cutbottom for the uncut using out copy */
1012 for (u->cutbottom = u->cutbuffer; u->cutbottom->next != NULL; u->cutbottom = u->cutbottom->next)
1013 ;
Chris Allegretta12dc8ca2008-07-31 04:24:04 +00001014 break;
Chris Allegretta3c1131a2008-08-02 22:31:01 +00001015 case REPLACE:
Chris Allegrettab549f372008-09-16 21:35:19 +00001016 case UNCUT:
Chris Allegretta14c86202008-08-03 04:48:05 +00001017 add_undo(action);
Chris Allegretta3c1131a2008-08-02 22:31:01 +00001018 break;
Chris Allegretta14c86202008-08-03 04:48:05 +00001019 case INSERT:
1020 u->mark_begin_lineno = openfile->current->lineno;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001021 case SPLIT:
1022 case UNSPLIT:
Chris Allegretta3c1131a2008-08-02 22:31:01 +00001023 /* These cases are handled by the earlier check for a new line and action */
1024 case OTHER:
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001025 break;
1026 }
1027
1028#ifdef DEBUG
1029 fprintf(stderr, "Done in udpate_undo (type was %d)\n", action);
1030#endif
1031 if (fs->last_action != action) {
1032#ifdef DEBUG
1033 fprintf(stderr, "Starting add_undo for new action as it does not match last_action\n");
1034#endif
Chris Allegretta14c86202008-08-03 04:48:05 +00001035 add_undo(action);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001036 }
1037 fs->last_action = action;
1038}
1039
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001040#endif /* !NANO_TINY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001041
1042#ifndef DISABLE_WRAPPING
David Lawrence Ramseyef0d5a72006-05-22 02:08:49 +00001043/* Unset the prepend_wrap flag. We need to do this as soon as we do
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001044 * something other than type text. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001045void wrap_reset(void)
1046{
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +00001047 prepend_wrap = FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001048}
1049
1050/* We wrap the given line. Precondition: we assume the cursor has been
David Lawrence Ramsey139fa652006-05-22 01:26:24 +00001051 * moved forward since the last typed character. Return TRUE if we
1052 * wrapped, and FALSE otherwise. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001053bool do_wrap(filestruct *line)
1054{
1055 size_t line_len;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001056 /* The length of the line we wrap. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001057 ssize_t wrap_loc;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001058 /* The index of line->data where we wrap. */
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001059#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001060 const char *indent_string = NULL;
1061 /* Indentation to prepend to the new line. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001062 size_t indent_len = 0;
1063 /* The length of indent_string. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001064#endif
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001065 const char *after_break;
1066 /* The text after the wrap point. */
1067 size_t after_break_len;
1068 /* The length of after_break. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +00001069 bool prepending = FALSE;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001070 /* Do we prepend to the next line? */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001071 const char *next_line = NULL;
1072 /* The next line, minus indentation. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001073 size_t next_line_len = 0;
1074 /* The length of next_line. */
1075 char *new_line = NULL;
1076 /* The line we create. */
1077 size_t new_line_len = 0;
1078 /* The eventual length of new_line. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001079
1080 /* There are three steps. First, we decide where to wrap. Then, we
1081 * create the new wrap line. Finally, we clean up. */
1082
1083 /* Step 1, finding where to wrap. We are going to add a new line
1084 * after a blank character. In this step, we call break_line() to
1085 * get the location of the last blank we can break the line at, and
David Lawrence Ramseyd4686b82006-06-11 19:14:14 +00001086 * set wrap_loc to the location of the character after it, so that
1087 * the blank is preserved at the end of the line.
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001088 *
1089 * If there is no legal wrap point, or we reach the last character
1090 * of the line while trying to find one, we should return without
1091 * wrapping. Note that if autoindent is turned on, we don't break
1092 * at the end of it! */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001093 assert(line != NULL && line->data != NULL);
1094
1095 /* Save the length of the line. */
1096 line_len = strlen(line->data);
1097
1098 /* Find the last blank where we can break the line. */
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001099 wrap_loc = break_line(line->data, fill
1100#ifndef DISABLE_HELP
1101 , FALSE
1102#endif
1103 );
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001104
1105 /* If we couldn't break the line, or we've reached the end of it, we
1106 * don't wrap. */
1107 if (wrap_loc == -1 || line->data[wrap_loc] == '\0')
1108 return FALSE;
1109
1110 /* Otherwise, move forward to the character just after the blank. */
1111 wrap_loc += move_mbright(line->data + wrap_loc, 0);
1112
1113 /* If we've reached the end of the line, we don't wrap. */
1114 if (line->data[wrap_loc] == '\0')
1115 return FALSE;
1116
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001117#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001118 /* If autoindent is turned on, and we're on the character just after
1119 * the indentation, we don't wrap. */
1120 if (ISSET(AUTOINDENT)) {
1121 /* Get the indentation of this line. */
1122 indent_string = line->data;
1123 indent_len = indent_length(indent_string);
1124
1125 if (wrap_loc == indent_len)
1126 return FALSE;
1127 }
1128#endif
1129
1130 /* Step 2, making the new wrap line. It will consist of indentation
1131 * followed by the text after the wrap point, optionally followed by
1132 * a space (if the text after the wrap point doesn't end in a blank)
David Lawrence Ramsey03979d72006-06-11 19:15:59 +00001133 * and the text of the next line, if they can fit without wrapping,
1134 * the next line exists, and the prepend_wrap flag is set. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001135
1136 /* after_break is the text that will be wrapped to the next line. */
1137 after_break = line->data + wrap_loc;
1138 after_break_len = line_len - wrap_loc;
1139
1140 assert(strlen(after_break) == after_break_len);
1141
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +00001142 /* We prepend the wrapped text to the next line, if the prepend_wrap
1143 * flag is set, there is a next line, and prepending would not make
1144 * the line too long. */
1145 if (prepend_wrap && line != openfile->filebot) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001146 const char *end = after_break + move_mbleft(after_break,
1147 after_break_len);
1148
1149 /* If after_break doesn't end in a blank, make sure it ends in a
1150 * space. */
1151 if (!is_blank_mbchar(end)) {
1152 line_len++;
1153 line->data = charealloc(line->data, line_len + 1);
1154 line->data[line_len - 1] = ' ';
1155 line->data[line_len] = '\0';
1156 after_break = line->data + wrap_loc;
1157 after_break_len++;
1158 openfile->totsize++;
1159 }
1160
1161 next_line = line->next->data;
1162 next_line_len = strlen(next_line);
1163
1164 if (after_break_len + next_line_len <= fill) {
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +00001165 prepending = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001166 new_line_len += next_line_len;
1167 }
1168 }
1169
1170 /* new_line_len is now the length of the text that will be wrapped
1171 * to the next line, plus (if we're prepending to it) the length of
1172 * the text of the next line. */
1173 new_line_len += after_break_len;
1174
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001175#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001176 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +00001177 if (prepending) {
1178 /* If we're prepending, the indentation will come from the
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001179 * next line. */
1180 indent_string = next_line;
1181 indent_len = indent_length(indent_string);
1182 next_line += indent_len;
1183 } else {
1184 /* Otherwise, it will come from this line, in which case
1185 * we should increase new_line_len to make room for it. */
1186 new_line_len += indent_len;
1187 openfile->totsize += mbstrnlen(indent_string, indent_len);
1188 }
1189 }
1190#endif
1191
1192 /* Now we allocate the new line and copy the text into it. */
1193 new_line = charalloc(new_line_len + 1);
1194 new_line[0] = '\0';
1195
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001196#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001197 if (ISSET(AUTOINDENT)) {
1198 /* Copy the indentation. */
1199 strncpy(new_line, indent_string, indent_len);
1200 new_line[indent_len] = '\0';
1201 new_line_len += indent_len;
1202 }
1203#endif
1204
1205 /* Copy all the text after the wrap point of the current line. */
1206 strcat(new_line, after_break);
1207
1208 /* Break the current line at the wrap point. */
1209 null_at(&line->data, wrap_loc);
1210
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +00001211 if (prepending) {
1212 /* If we're prepending, copy the text from the next line, minus
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001213 * the indentation that we already copied above. */
1214 strcat(new_line, next_line);
1215
1216 free(line->next->data);
1217 line->next->data = new_line;
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +00001218
1219 /* If the NO_NEWLINES flag isn't set, and text has been added to
1220 * the magicline, make a new magicline. */
1221 if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0')
1222 new_magicline();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001223 } else {
1224 /* Otherwise, make a new line and copy the text after where we
1225 * broke this line to the beginning of the new line. */
1226 splice_node(openfile->current, make_new_node(openfile->current),
1227 openfile->current->next);
1228
David Lawrence Ramsey219a8142005-11-22 22:08:01 +00001229 /* If the current line is the last line of the file, move the
1230 * last line of the file down to the next line. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +00001231 if (openfile->filebot == openfile->current)
1232 openfile->filebot = openfile->current->next;
1233
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001234 openfile->current->next->data = new_line;
1235
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001236 openfile->totsize++;
1237 }
1238
1239 /* Step 3, clean up. Reposition the cursor and mark, and do some
1240 * other sundry things. */
1241
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +00001242 /* Set the prepend_wrap flag, so that later wraps of this line will
1243 * be prepended to the next line. */
1244 prepend_wrap = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001245
David Lawrence Ramsey2829aae2006-05-22 01:24:09 +00001246 /* Each line knows its number. We recalculate these if we inserted
1247 * a new line. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +00001248 if (!prepending)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001249 renumber(line);
1250
1251 /* If the cursor was after the break point, we must move it. We
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +00001252 * also clear the prepend_wrap flag in this case. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001253 if (openfile->current_x > wrap_loc) {
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +00001254 prepend_wrap = FALSE;
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +00001255
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001256 openfile->current = openfile->current->next;
1257 openfile->current_x -= wrap_loc
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001258#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001259 - indent_len
1260#endif
1261 ;
1262 openfile->placewewant = xplustabs();
1263 }
1264
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001265#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001266 /* If the mark was on this line after the wrap point, we move it
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +00001267 * down. If it was on the next line and we prepended to that line,
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001268 * we move it right. */
1269 if (openfile->mark_set) {
1270 if (openfile->mark_begin == line && openfile->mark_begin_x >
1271 wrap_loc) {
1272 openfile->mark_begin = line->next;
1273 openfile->mark_begin_x -= wrap_loc - indent_len + 1;
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +00001274 } else if (prepending && openfile->mark_begin == line->next)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001275 openfile->mark_begin_x += after_break_len;
1276 }
1277#endif
1278
1279 return TRUE;
1280}
1281#endif /* !DISABLE_WRAPPING */
1282
David Lawrence Ramseyc7c04bb2005-11-29 21:30:00 +00001283#if !defined(DISABLE_HELP) || !defined(DISABLE_WRAPJUSTIFY)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001284/* We are trying to break a chunk off line. We find the last blank such
David Lawrence Ramseycd9a5f02005-09-20 06:12:54 +00001285 * that the display length to there is at most (goal + 1). If there is
1286 * no such blank, then we find the first blank. We then take the last
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001287 * blank in that group of blanks. The terminating '\0' counts as a
1288 * blank, as does a '\n' if newline is TRUE. */
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001289ssize_t break_line(const char *line, ssize_t goal
1290#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +00001291 , bool newln
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001292#endif
1293 )
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001294{
1295 ssize_t blank_loc = -1;
1296 /* Current tentative return value. Index of the last blank we
1297 * found with short enough display width. */
1298 ssize_t cur_loc = 0;
1299 /* Current index in line. */
David Lawrence Ramsey2d3d1e92006-05-18 17:28:16 +00001300 size_t cur_pos = 0;
1301 /* Current column position in line. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001302 int line_len;
1303
1304 assert(line != NULL);
1305
David Lawrence Ramsey2d3d1e92006-05-18 17:28:16 +00001306 while (*line != '\0' && goal >= cur_pos) {
1307 line_len = parse_mbchar(line, NULL, &cur_pos);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001308
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001309 if (is_blank_mbchar(line)
1310#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +00001311 || (newln && *line == '\n')
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001312#endif
1313 ) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001314 blank_loc = cur_loc;
1315
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001316#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +00001317 if (newln && *line == '\n')
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001318 break;
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001319#endif
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001320 }
1321
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001322 line += line_len;
1323 cur_loc += line_len;
1324 }
1325
David Lawrence Ramsey2d3d1e92006-05-18 17:28:16 +00001326 if (goal >= cur_pos)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001327 /* In fact, the whole line displays shorter than goal. */
1328 return cur_loc;
1329
Chris Allegretta09b81242008-07-12 01:54:49 +00001330#ifndef DISABLE_HELP
1331 if (newln && blank_loc <= 0) {
1332 /* If blank was not found or was found only first character,
1333 * force line break. */
1334 cur_loc -= line_len;
1335 return cur_loc;
1336 }
1337#endif
1338
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001339 if (blank_loc == -1) {
1340 /* No blank was found that was short enough. */
1341 bool found_blank = FALSE;
David Lawrence Ramsey5ab12ca2005-09-20 17:52:52 +00001342 ssize_t found_blank_loc = 0;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001343
1344 while (*line != '\0') {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001345 line_len = parse_mbchar(line, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001346
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001347 if (is_blank_mbchar(line)
1348#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +00001349 || (newln && *line == '\n')
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001350#endif
1351 ) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001352 if (!found_blank)
1353 found_blank = TRUE;
David Lawrence Ramseybdc1b9b2005-09-20 16:36:08 +00001354 found_blank_loc = cur_loc;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001355 } else if (found_blank)
David Lawrence Ramseybdc1b9b2005-09-20 16:36:08 +00001356 return found_blank_loc;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001357
1358 line += line_len;
1359 cur_loc += line_len;
1360 }
1361
1362 return -1;
1363 }
1364
1365 /* Move to the last blank after blank_loc, if there is one. */
1366 line -= cur_loc;
1367 line += blank_loc;
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001368 line_len = parse_mbchar(line, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001369 line += line_len;
1370
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001371 while (*line != '\0' && (is_blank_mbchar(line)
1372#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +00001373 || (newln && *line == '\n')
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001374#endif
1375 )) {
David Lawrence Ramseycd243f52006-05-19 23:27:16 +00001376#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +00001377 if (newln && *line == '\n')
David Lawrence Ramseycd243f52006-05-19 23:27:16 +00001378 break;
1379#endif
1380
David Lawrence Ramsey39bd1b32006-05-20 13:11:56 +00001381 line_len = parse_mbchar(line, NULL, NULL);
1382
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001383 line += line_len;
1384 blank_loc += line_len;
1385 }
1386
1387 return blank_loc;
1388}
David Lawrence Ramseyc7c04bb2005-11-29 21:30:00 +00001389#endif /* !DISABLE_HELP || !DISABLE_WRAPJUSTIFY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001390
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001391#if !defined(NANO_TINY) || !defined(DISABLE_JUSTIFY)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001392/* The "indentation" of a line is the whitespace between the quote part
1393 * and the non-whitespace of the line. */
1394size_t indent_length(const char *line)
1395{
1396 size_t len = 0;
1397 char *blank_mb;
1398 int blank_mb_len;
1399
1400 assert(line != NULL);
1401
1402 blank_mb = charalloc(mb_cur_max());
1403
1404 while (*line != '\0') {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001405 blank_mb_len = parse_mbchar(line, blank_mb, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001406
1407 if (!is_blank_mbchar(blank_mb))
1408 break;
1409
1410 line += blank_mb_len;
1411 len += blank_mb_len;
1412 }
1413
1414 free(blank_mb);
1415
1416 return len;
1417}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001418#endif /* !NANO_TINY || !DISABLE_JUSTIFY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001419
1420#ifndef DISABLE_JUSTIFY
1421/* justify_format() replaces blanks with spaces and multiple spaces by 1
1422 * (except it maintains up to 2 after a character in punct optionally
1423 * followed by a character in brackets, and removes all from the end).
1424 *
1425 * justify_format() might make paragraph->data shorter, and change the
1426 * actual pointer with null_at().
1427 *
1428 * justify_format() will not look at the first skip characters of
1429 * paragraph. skip should be at most strlen(paragraph->data). The
1430 * character at paragraph[skip + 1] must not be blank. */
1431void justify_format(filestruct *paragraph, size_t skip)
1432{
1433 char *end, *new_end, *new_paragraph_data;
1434 size_t shift = 0;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001435#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001436 size_t mark_shift = 0;
1437#endif
1438
1439 /* These four asserts are assumptions about the input data. */
1440 assert(paragraph != NULL);
1441 assert(paragraph->data != NULL);
1442 assert(skip < strlen(paragraph->data));
1443 assert(!is_blank_mbchar(paragraph->data + skip));
1444
1445 end = paragraph->data + skip;
1446 new_paragraph_data = charalloc(strlen(paragraph->data) + 1);
1447 strncpy(new_paragraph_data, paragraph->data, skip);
1448 new_end = new_paragraph_data + skip;
1449
1450 while (*end != '\0') {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001451 int end_len;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001452
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001453 /* If this character is blank, change it to a space if
1454 * necessary, and skip over all blanks after it. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001455 if (is_blank_mbchar(end)) {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001456 end_len = parse_mbchar(end, NULL, NULL);
1457
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001458 *new_end = ' ';
1459 new_end++;
1460 end += end_len;
1461
1462 while (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001463 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001464
1465 end += end_len;
1466 shift += end_len;
1467
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001468#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001469 /* Keep track of the change in the current line. */
1470 if (openfile->mark_set && openfile->mark_begin ==
1471 paragraph && openfile->mark_begin_x >= end -
1472 paragraph->data)
1473 mark_shift += end_len;
1474#endif
1475 }
1476 /* If this character is punctuation optionally followed by a
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001477 * bracket and then followed by blanks, change no more than two
1478 * of the blanks to spaces if necessary, and skip over all
1479 * blanks after them. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001480 } else if (mbstrchr(punct, end) != NULL) {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001481 end_len = parse_mbchar(end, NULL, NULL);
1482
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001483 while (end_len > 0) {
1484 *new_end = *end;
1485 new_end++;
1486 end++;
1487 end_len--;
1488 }
1489
1490 if (*end != '\0' && mbstrchr(brackets, end) != NULL) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001491 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001492
1493 while (end_len > 0) {
1494 *new_end = *end;
1495 new_end++;
1496 end++;
1497 end_len--;
1498 }
1499 }
1500
1501 if (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001502 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001503
1504 *new_end = ' ';
1505 new_end++;
1506 end += end_len;
1507 }
1508
1509 if (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001510 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001511
1512 *new_end = ' ';
1513 new_end++;
1514 end += end_len;
1515 }
1516
1517 while (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001518 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001519
1520 end += end_len;
1521 shift += end_len;
1522
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001523#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001524 /* Keep track of the change in the current line. */
1525 if (openfile->mark_set && openfile->mark_begin ==
1526 paragraph && openfile->mark_begin_x >= end -
1527 paragraph->data)
1528 mark_shift += end_len;
1529#endif
1530 }
1531 /* If this character is neither blank nor punctuation, leave it
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001532 * unchanged. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001533 } else {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001534 end_len = parse_mbchar(end, NULL, NULL);
1535
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001536 while (end_len > 0) {
1537 *new_end = *end;
1538 new_end++;
1539 end++;
1540 end_len--;
1541 }
1542 }
1543 }
1544
1545 assert(*end == '\0');
1546
1547 *new_end = *end;
1548
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001549 /* If there are spaces at the end of the line, remove them. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001550 while (new_end > new_paragraph_data + skip &&
1551 *(new_end - 1) == ' ') {
1552 new_end--;
1553 shift++;
1554 }
1555
1556 if (shift > 0) {
1557 openfile->totsize -= shift;
1558 null_at(&new_paragraph_data, new_end - new_paragraph_data);
1559 free(paragraph->data);
1560 paragraph->data = new_paragraph_data;
1561
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001562#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001563 /* Adjust the mark coordinates to compensate for the change in
1564 * the current line. */
1565 if (openfile->mark_set && openfile->mark_begin == paragraph) {
1566 openfile->mark_begin_x -= mark_shift;
1567 if (openfile->mark_begin_x > new_end - new_paragraph_data)
1568 openfile->mark_begin_x = new_end - new_paragraph_data;
1569 }
1570#endif
1571 } else
1572 free(new_paragraph_data);
1573}
1574
1575/* The "quote part" of a line is the largest initial substring matching
1576 * the quote string. This function returns the length of the quote part
1577 * of the given line.
1578 *
1579 * Note that if !HAVE_REGEX_H then we match concatenated copies of
1580 * quotestr. */
1581size_t quote_length(const char *line)
1582{
1583#ifdef HAVE_REGEX_H
1584 regmatch_t matches;
1585 int rc = regexec(&quotereg, line, 1, &matches, 0);
1586
1587 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t)-1)
1588 return 0;
1589 /* matches.rm_so should be 0, since the quote string should start
1590 * with the caret ^. */
1591 return matches.rm_eo;
1592#else /* !HAVE_REGEX_H */
1593 size_t qdepth = 0;
1594
1595 /* Compute quote depth level. */
1596 while (strncmp(line + qdepth, quotestr, quotelen) == 0)
1597 qdepth += quotelen;
1598 return qdepth;
1599#endif /* !HAVE_REGEX_H */
1600}
1601
1602/* a_line and b_line are lines of text. The quotation part of a_line is
1603 * the first a_quote characters. Check that the quotation part of
1604 * b_line is the same. */
1605bool quotes_match(const char *a_line, size_t a_quote, const char
1606 *b_line)
1607{
1608 /* Here is the assumption about a_quote. */
1609 assert(a_quote == quote_length(a_line));
1610
1611 return (a_quote == quote_length(b_line) &&
1612 strncmp(a_line, b_line, a_quote) == 0);
1613}
1614
1615/* We assume a_line and b_line have no quote part. Then, we return
1616 * whether b_line could follow a_line in a paragraph. */
1617bool indents_match(const char *a_line, size_t a_indent, const char
1618 *b_line, size_t b_indent)
1619{
1620 assert(a_indent == indent_length(a_line));
1621 assert(b_indent == indent_length(b_line));
1622
1623 return (b_indent <= a_indent &&
1624 strncmp(a_line, b_line, b_indent) == 0);
1625}
1626
1627/* Is foo the beginning of a paragraph?
1628 *
1629 * A line of text consists of a "quote part", followed by an
1630 * "indentation part", followed by text. The functions quote_length()
1631 * and indent_length() calculate these parts.
1632 *
1633 * A line is "part of a paragraph" if it has a part not in the quote
1634 * part or the indentation.
1635 *
1636 * A line is "the beginning of a paragraph" if it is part of a
1637 * paragraph and
1638 * 1) it is the top line of the file, or
1639 * 2) the line above it is not part of a paragraph, or
1640 * 3) the line above it does not have precisely the same quote
1641 * part, or
1642 * 4) the indentation of this line is not an initial substring of
1643 * the indentation of the previous line, or
1644 * 5) this line has no quote part and some indentation, and
1645 * autoindent isn't turned on.
1646 * The reason for number 5) is that if autoindent isn't turned on,
1647 * then an indented line is expected to start a paragraph, as in
1648 * books. Thus, nano can justify an indented paragraph only if
1649 * autoindent is turned on. */
1650bool begpar(const filestruct *const foo)
1651{
David Lawrence Ramsey0083bd22005-11-09 18:26:44 +00001652 size_t quote_len, indent_len, temp_id_len;
1653
1654 if (foo == NULL)
1655 return FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001656
1657 /* Case 1). */
David Lawrence Ramsey0083bd22005-11-09 18:26:44 +00001658 if (foo == openfile->fileage)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001659 return TRUE;
1660
1661 quote_len = quote_length(foo->data);
1662 indent_len = indent_length(foo->data + quote_len);
1663
1664 /* Not part of a paragraph. */
1665 if (foo->data[quote_len + indent_len] == '\0')
1666 return FALSE;
1667
1668 /* Case 3). */
1669 if (!quotes_match(foo->data, quote_len, foo->prev->data))
1670 return TRUE;
1671
1672 temp_id_len = indent_length(foo->prev->data + quote_len);
1673
1674 /* Case 2) or 5) or 4). */
1675 if (foo->prev->data[quote_len + temp_id_len] == '\0' ||
1676 (quote_len == 0 && indent_len > 0
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001677#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001678 && !ISSET(AUTOINDENT)
1679#endif
1680 ) || !indents_match(foo->prev->data + quote_len, temp_id_len,
1681 foo->data + quote_len, indent_len))
1682 return TRUE;
1683
1684 return FALSE;
1685}
1686
1687/* Is foo inside a paragraph? */
1688bool inpar(const filestruct *const foo)
1689{
1690 size_t quote_len;
1691
1692 if (foo == NULL)
1693 return FALSE;
1694
1695 quote_len = quote_length(foo->data);
1696
David Lawrence Ramsey21014032005-11-09 20:33:42 +00001697 return (foo->data[quote_len + indent_length(foo->data +
1698 quote_len)] != '\0');
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001699}
1700
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00001701/* Move the next par_len lines, starting with first_line, into the
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00001702 * justify buffer, leaving copies of those lines in place. Assume that
1703 * par_len is greater than zero, and that there are enough lines after
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00001704 * first_line. */
1705void backup_lines(filestruct *first_line, size_t par_len)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001706{
1707 filestruct *top = first_line;
1708 /* The top of the paragraph we're backing up. */
1709 filestruct *bot = first_line;
1710 /* The bottom of the paragraph we're backing up. */
1711 size_t i;
1712 /* Generic loop variable. */
1713 size_t current_x_save = openfile->current_x;
1714 ssize_t fl_lineno_save = first_line->lineno;
1715 ssize_t edittop_lineno_save = openfile->edittop->lineno;
1716 ssize_t current_lineno_save = openfile->current->lineno;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001717#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001718 bool old_mark_set = openfile->mark_set;
1719 ssize_t mb_lineno_save = 0;
1720 size_t mark_begin_x_save = 0;
1721
1722 if (old_mark_set) {
1723 mb_lineno_save = openfile->mark_begin->lineno;
1724 mark_begin_x_save = openfile->mark_begin_x;
1725 }
1726#endif
1727
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001728 /* par_len will be one greater than the number of lines between
1729 * current and filebot if filebot is the last line in the
1730 * paragraph. */
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00001731 assert(par_len > 0 && openfile->current->lineno + par_len <=
David Lawrence Ramsey24777c02005-12-01 05:49:08 +00001732 openfile->filebot->lineno + 1);
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00001733
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001734 /* Move bot down par_len lines to the line after the last line of
1735 * the paragraph, if there is one. */
1736 for (i = par_len; i > 0 && bot != openfile->filebot; i--)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001737 bot = bot->next;
1738
1739 /* Move the paragraph from the current buffer's filestruct to the
1740 * justify buffer. */
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001741 move_to_filestruct(&jusbuffer, &jusbottom, top, 0, bot,
David Lawrence Ramseyf0575cf2005-11-09 23:27:51 +00001742 (i == 1 && bot == openfile->filebot) ? strlen(bot->data) : 0);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001743
1744 /* Copy the paragraph back to the current buffer's filestruct from
1745 * the justify buffer. */
1746 copy_from_filestruct(jusbuffer, jusbottom);
1747
1748 /* Move upward from the last line of the paragraph to the first
1749 * line, putting first_line, edittop, current, and mark_begin at the
1750 * same lines in the copied paragraph that they had in the original
1751 * paragraph. */
David Lawrence Ramseyee43ea62007-04-22 15:04:05 +00001752 if (openfile->current != openfile->fileage) {
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001753 top = openfile->current->prev;
David Lawrence Ramseyee43ea62007-04-22 15:04:05 +00001754#ifndef NANO_TINY
1755 if (old_mark_set &&
1756 openfile->current->lineno == mb_lineno_save) {
1757 openfile->mark_begin = openfile->current;
1758 openfile->mark_begin_x = mark_begin_x_save;
1759 }
1760#endif
1761 } else
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001762 top = openfile->current;
David Lawrence Ramseye8d505b2005-11-10 03:40:45 +00001763 for (i = par_len; i > 0 && top != NULL; i--) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001764 if (top->lineno == fl_lineno_save)
1765 first_line = top;
1766 if (top->lineno == edittop_lineno_save)
1767 openfile->edittop = top;
1768 if (top->lineno == current_lineno_save)
1769 openfile->current = top;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001770#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001771 if (old_mark_set && top->lineno == mb_lineno_save) {
1772 openfile->mark_begin = top;
1773 openfile->mark_begin_x = mark_begin_x_save;
1774 }
1775#endif
1776 top = top->prev;
1777 }
1778
1779 /* Put current_x at the same place in the copied paragraph that it
1780 * had in the original paragraph. */
1781 openfile->current_x = current_x_save;
1782
1783 set_modified();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001784}
1785
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001786/* Find the beginning of the current paragraph if we're in one, or the
1787 * beginning of the next paragraph if we're not. Afterwards, save the
1788 * quote length and paragraph length in *quote and *par. Return TRUE if
David Lawrence Ramsey139fa652006-05-22 01:26:24 +00001789 * we found a paragraph, and FALSE if there was an error or we didn't
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001790 * find a paragraph.
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001791 *
1792 * See the comment at begpar() for more about when a line is the
1793 * beginning of a paragraph. */
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001794bool find_paragraph(size_t *const quote, size_t *const par)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001795{
1796 size_t quote_len;
1797 /* Length of the initial quotation of the paragraph we search
1798 * for. */
1799 size_t par_len;
1800 /* Number of lines in the paragraph we search for. */
1801 filestruct *current_save;
1802 /* The line at the beginning of the paragraph we search for. */
1803 ssize_t current_y_save;
1804 /* The y-coordinate at the beginning of the paragraph we search
1805 * for. */
1806
1807#ifdef HAVE_REGEX_H
1808 if (quoterc != 0) {
1809 statusbar(_("Bad quote string %s: %s"), quotestr, quoteerr);
1810 return FALSE;
1811 }
1812#endif
1813
1814 assert(openfile->current != NULL);
1815
David Lawrence Ramsey1be131a2005-11-11 03:55:52 +00001816 /* If we're at the end of the last line of the file, it means that
1817 * there aren't any paragraphs left, so get out. */
1818 if (openfile->current == openfile->filebot && openfile->current_x ==
1819 strlen(openfile->filebot->data))
1820 return FALSE;
1821
1822 /* If the current line isn't in a paragraph, move forward to the
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001823 * last line of the next paragraph, if any. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001824 if (!inpar(openfile->current)) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001825 do_para_end(FALSE);
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00001826
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001827 /* If we end up past the beginning of the line, it means that
1828 * we're at the end of the last line of the file, and the line
1829 * isn't blank, in which case the last line of the file is the
1830 * last line of the next paragraph.
1831 *
1832 * Otherwise, if we end up on a line that's in a paragraph, it
1833 * means that we're on the line after the last line of the next
1834 * paragraph, in which case we should move back to the last line
1835 * of the next paragraph. */
1836 if (openfile->current_x == 0) {
1837 if (!inpar(openfile->current->prev))
1838 return FALSE;
1839 if (openfile->current != openfile->fileage)
1840 openfile->current = openfile->current->prev;
1841 }
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001842 }
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00001843
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001844 /* If the current line isn't the first line of the paragraph, move
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001845 * back to the first line of the paragraph. */
1846 if (!begpar(openfile->current))
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001847 do_para_begin(FALSE);
1848
1849 /* Now current is the first line of the paragraph. Set quote_len to
1850 * the quotation length of that line, and set par_len to the number
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001851 * of lines in this paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001852 quote_len = quote_length(openfile->current->data);
1853 current_save = openfile->current;
1854 current_y_save = openfile->current_y;
1855 do_para_end(FALSE);
1856 par_len = openfile->current->lineno - current_save->lineno;
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00001857
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001858 /* If we end up past the beginning of the line, it means that we're
1859 * at the end of the last line of the file, and the line isn't
1860 * blank, in which case the last line of the file is part of the
1861 * paragraph. */
David Lawrence Ramseybdff6652005-11-11 04:14:33 +00001862 if (openfile->current_x > 0)
1863 par_len++;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001864 openfile->current = current_save;
1865 openfile->current_y = current_y_save;
1866
1867 /* Save the values of quote_len and par_len. */
1868 assert(quote != NULL && par != NULL);
1869
1870 *quote = quote_len;
1871 *par = par_len;
1872
1873 return TRUE;
1874}
1875
1876/* If full_justify is TRUE, justify the entire file. Otherwise, justify
1877 * the current paragraph. */
1878void do_justify(bool full_justify)
1879{
1880 filestruct *first_par_line = NULL;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001881 /* Will be the first line of the justified paragraph(s), if any.
1882 * For restoring after unjustify. */
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001883 filestruct *last_par_line = NULL;
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001884 /* Will be the line after the last line of the justified
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001885 * paragraph(s), if any. Also for restoring after unjustify. */
David Lawrence Ramsey82b5deb2005-11-10 06:07:57 +00001886 bool filebot_inpar = FALSE;
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001887 /* Whether the text at filebot is part of the current
1888 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001889
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00001890 /* We save these variables to be restored if the user
1891 * unjustifies. */
David Lawrence Ramsey52161ee2005-11-10 19:56:26 +00001892 filestruct *edittop_save = openfile->edittop;
1893 filestruct *current_save = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001894 size_t current_x_save = openfile->current_x;
1895 size_t pww_save = openfile->placewewant;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001896 size_t totsize_save = openfile->totsize;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001897#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001898 filestruct *mark_begin_save = openfile->mark_begin;
1899 size_t mark_begin_x_save = openfile->mark_begin_x;
1900#endif
David Lawrence Ramsey52161ee2005-11-10 19:56:26 +00001901 bool modified_save = openfile->modified;
1902
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001903 int kbinput;
1904 bool meta_key, func_key, s_or_t, ran_func, finished;
Chris Allegretta0018d8e2008-03-13 08:23:52 +00001905 const sc *s;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001906
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001907 /* Move to the beginning of the current line, so that justifying at
David Lawrence Ramseybdff6652005-11-11 04:14:33 +00001908 * the end of the last line of the file, if that line isn't blank,
1909 * will work the first time through. */
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001910 openfile->current_x = 0;
1911
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001912 /* If we're justifying the entire file, start at the beginning. */
1913 if (full_justify)
1914 openfile->current = openfile->fileage;
1915
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001916 while (TRUE) {
1917 size_t i;
1918 /* Generic loop variable. */
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001919 filestruct *curr_first_par_line;
1920 /* The first line of the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001921 size_t quote_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001922 /* Length of the initial quotation of the current
1923 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001924 size_t indent_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001925 /* Length of the initial indentation of the current
1926 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001927 size_t par_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001928 /* Number of lines in the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001929 ssize_t break_pos;
1930 /* Where we will break lines. */
1931 char *indent_string;
1932 /* The first indentation that doesn't match the initial
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001933 * indentation of the current paragraph. This is put at the
1934 * beginning of every line broken off the first justified
1935 * line of the paragraph. Note that this works because a
1936 * paragraph can only contain two indentations at most: the
1937 * initial one, and a different one starting on a line after
1938 * the first. See the comment at begpar() for more about
1939 * when a line is part of a paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001940
1941 /* Find the first line of the paragraph to be justified. That
1942 * is the start of this paragraph if we're in one, or the start
1943 * of the next otherwise. Save the quote length and paragraph
1944 * length (number of lines). Don't refresh the screen yet,
1945 * since we'll do that after we justify.
1946 *
1947 * If the search failed, we do one of two things. If we're
David Lawrence Ramsey8b203d62005-11-11 03:17:44 +00001948 * justifying the whole file, and we've found at least one
1949 * paragraph, it means that we should justify all the way to the
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001950 * last line of the file, so set the last line of the text to be
1951 * justified to the last line of the file and break out of the
1952 * loop. Otherwise, it means that there are no paragraph(s) to
1953 * justify, so refresh the screen and get out. */
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001954 if (!find_paragraph(&quote_len, &par_len)) {
David Lawrence Ramsey8b203d62005-11-11 03:17:44 +00001955 if (full_justify && first_par_line != NULL) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001956 last_par_line = openfile->filebot;
1957 break;
1958 } else {
Chris Allegrettafd265af2009-02-06 03:41:02 +00001959 edit_refresh_needed = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001960 return;
1961 }
1962 }
1963
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001964 /* par_len will be one greater than the number of lines between
1965 * current and filebot if filebot is the last line in the
1966 * paragraph. Set filebot_inpar to TRUE if this is the case. */
1967 filebot_inpar = (openfile->current->lineno + par_len ==
1968 openfile->filebot->lineno + 1);
1969
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00001970 /* If we haven't already done it, move the original paragraph(s)
1971 * to the justify buffer, splice a copy of the original
1972 * paragraph(s) into the file in the same place, and set
1973 * first_par_line to the first line of the copy. */
1974 if (first_par_line == NULL) {
1975 backup_lines(openfile->current, full_justify ?
David Lawrence Ramsey53f641f2005-11-10 21:57:56 +00001976 openfile->filebot->lineno - openfile->current->lineno +
1977 ((openfile->filebot->data[0] != '\0') ? 1 : 0) :
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00001978 par_len);
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00001979 first_par_line = openfile->current;
1980 }
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001981
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001982 /* Set curr_first_par_line to the first line of the current
1983 * paragraph. */
1984 curr_first_par_line = openfile->current;
1985
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001986 /* Initialize indent_string to a blank string. */
1987 indent_string = mallocstrcpy(NULL, "");
1988
1989 /* Find the first indentation in the paragraph that doesn't
David Lawrence Ramsey8602fd62006-05-28 18:43:21 +00001990 * match the indentation of the first line, and save it in
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001991 * indent_string. If all the indentations are the same, save
1992 * the indentation of the first line in indent_string. */
1993 {
1994 const filestruct *indent_line = openfile->current;
1995 bool past_first_line = FALSE;
1996
1997 for (i = 0; i < par_len; i++) {
1998 indent_len = quote_len +
1999 indent_length(indent_line->data + quote_len);
2000
2001 if (indent_len != strlen(indent_string)) {
2002 indent_string = mallocstrncpy(indent_string,
2003 indent_line->data, indent_len + 1);
2004 indent_string[indent_len] = '\0';
2005
2006 if (past_first_line)
2007 break;
2008 }
2009
2010 if (indent_line == openfile->current)
2011 past_first_line = TRUE;
2012
2013 indent_line = indent_line->next;
2014 }
2015 }
2016
2017 /* Now tack all the lines of the paragraph together, skipping
2018 * the quoting and indentation on all lines after the first. */
2019 for (i = 0; i < par_len - 1; i++) {
2020 filestruct *next_line = openfile->current->next;
2021 size_t line_len = strlen(openfile->current->data);
2022 size_t next_line_len =
2023 strlen(openfile->current->next->data);
2024
2025 indent_len = quote_len +
2026 indent_length(openfile->current->next->data +
2027 quote_len);
2028
2029 next_line_len -= indent_len;
2030 openfile->totsize -= indent_len;
2031
2032 /* We're just about to tack the next line onto this one. If
2033 * this line isn't empty, make sure it ends in a space. */
2034 if (line_len > 0 &&
2035 openfile->current->data[line_len - 1] != ' ') {
2036 line_len++;
2037 openfile->current->data =
2038 charealloc(openfile->current->data,
2039 line_len + 1);
2040 openfile->current->data[line_len - 1] = ' ';
2041 openfile->current->data[line_len] = '\0';
2042 openfile->totsize++;
2043 }
2044
2045 openfile->current->data =
2046 charealloc(openfile->current->data, line_len +
2047 next_line_len + 1);
2048 strcat(openfile->current->data, next_line->data +
2049 indent_len);
2050
David Lawrence Ramsey9bedc4b2005-11-09 19:51:48 +00002051 /* Don't destroy edittop or filebot! */
David Lawrence Ramsey32bd29e2005-11-09 03:44:23 +00002052 if (next_line == openfile->edittop)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002053 openfile->edittop = openfile->current;
David Lawrence Ramsey9bedc4b2005-11-09 19:51:48 +00002054 if (next_line == openfile->filebot)
2055 openfile->filebot = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002056
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002057#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002058 /* Adjust the mark coordinates to compensate for the change
2059 * in the next line. */
2060 if (openfile->mark_set && openfile->mark_begin ==
2061 next_line) {
2062 openfile->mark_begin = openfile->current;
2063 openfile->mark_begin_x += line_len - indent_len;
2064 }
2065#endif
2066
2067 unlink_node(next_line);
2068 delete_node(next_line);
2069
2070 /* If we've removed the next line, we need to go through
2071 * this line again. */
2072 i--;
2073
2074 par_len--;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002075 openfile->totsize--;
2076 }
2077
2078 /* Call justify_format() on the paragraph, which will remove
2079 * excess spaces from it and change all blank characters to
2080 * spaces. */
2081 justify_format(openfile->current, quote_len +
2082 indent_length(openfile->current->data + quote_len));
2083
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00002084 while (par_len > 0 && strlenpt(openfile->current->data) >
2085 fill) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002086 size_t line_len = strlen(openfile->current->data);
2087
2088 indent_len = strlen(indent_string);
2089
2090 /* If this line is too long, try to wrap it to the next line
2091 * to make it short enough. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00002092 break_pos = break_line(openfile->current->data + indent_len,
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00002093 fill - strnlenpt(openfile->current->data, indent_len)
2094#ifndef DISABLE_HELP
2095 , FALSE
2096#endif
2097 );
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002098
2099 /* We can't break the line, or don't need to, so get out. */
2100 if (break_pos == -1 || break_pos + indent_len == line_len)
2101 break;
2102
2103 /* Move forward to the character after the indentation and
2104 * just after the space. */
2105 break_pos += indent_len + 1;
2106
2107 assert(break_pos <= line_len);
2108
2109 /* Make a new line, and copy the text after where we're
2110 * going to break this line to the beginning of the new
2111 * line. */
2112 splice_node(openfile->current,
2113 make_new_node(openfile->current),
2114 openfile->current->next);
2115
2116 /* If this paragraph is non-quoted, and autoindent isn't
2117 * turned on, set the indentation length to zero so that the
2118 * indentation is treated as part of the line. */
2119 if (quote_len == 0
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002120#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002121 && !ISSET(AUTOINDENT)
2122#endif
2123 )
2124 indent_len = 0;
2125
2126 /* Copy the text after where we're going to break the
2127 * current line to the next line. */
2128 openfile->current->next->data = charalloc(indent_len + 1 +
2129 line_len - break_pos);
2130 strncpy(openfile->current->next->data, indent_string,
2131 indent_len);
2132 strcpy(openfile->current->next->data + indent_len,
2133 openfile->current->data + break_pos);
2134
2135 par_len++;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002136 openfile->totsize += indent_len + 1;
2137
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002138#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002139 /* Adjust the mark coordinates to compensate for the change
2140 * in the current line. */
2141 if (openfile->mark_set && openfile->mark_begin ==
2142 openfile->current && openfile->mark_begin_x >
2143 break_pos) {
2144 openfile->mark_begin = openfile->current->next;
2145 openfile->mark_begin_x -= break_pos - indent_len;
2146 }
2147#endif
2148
2149 /* Break the current line. */
2150 null_at(&openfile->current->data, break_pos);
2151
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00002152 /* If the current line is the last line of the file, move
David Lawrence Ramseyb885c9c2005-11-10 05:20:25 +00002153 * the last line of the file down to the next line. */
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00002154 if (openfile->filebot == openfile->current)
2155 openfile->filebot = openfile->filebot->next;
2156
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002157 /* Go to the next line. */
2158 par_len--;
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00002159 openfile->current_y++;
2160 openfile->current = openfile->current->next;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002161 }
2162
2163 /* We're done breaking lines, so we don't need indent_string
2164 * anymore. */
2165 free(indent_string);
2166
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00002167 /* Go to the next line, if possible. If there is no next line,
2168 * move to the end of the current line. */
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00002169 if (openfile->current != openfile->filebot) {
2170 openfile->current_y++;
2171 openfile->current = openfile->current->next;
2172 } else
2173 openfile->current_x = strlen(openfile->current->data);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002174
David Lawrence Ramseya6854682005-11-30 21:19:42 +00002175 /* Renumber the lines of the now-justified current paragraph,
2176 * since both find_paragraph() and edit_refresh() need the line
2177 * numbers to be right. */
2178 renumber(curr_first_par_line);
David Lawrence Ramseyad1b64c2005-11-29 19:00:09 +00002179
2180 /* We've just finished justifying the paragraph. If we're not
2181 * justifying the entire file, break out of the loop.
2182 * Otherwise, continue the loop so that we justify all the
2183 * paragraphs in the file. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002184 if (!full_justify)
2185 break;
2186 }
2187
2188 /* We are now done justifying the paragraph or the file, so clean
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00002189 * up. current_y and totsize have been maintained above. If we
David Lawrence Ramseyad1b64c2005-11-29 19:00:09 +00002190 * actually justified something, set last_par_line to the new end of
2191 * the paragraph. */
2192 if (first_par_line != NULL)
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00002193 last_par_line = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002194
2195 edit_refresh();
2196
David Lawrence Ramseyfc0f8f82006-05-10 13:41:53 +00002197#ifndef NANO_TINY
David Lawrence Ramsey1c5af642006-05-10 15:15:06 +00002198 /* We're going to set jump_buf so that we return here after a
2199 * SIGWINCH instead of to main(). Indicate this. */
2200 jump_buf_main = FALSE;
2201
David Lawrence Ramseyfc0f8f82006-05-10 13:41:53 +00002202 /* Return here after a SIGWINCH. */
David Lawrence Ramsey1c5af642006-05-10 15:15:06 +00002203 sigsetjmp(jump_buf, 1);
David Lawrence Ramseyfc0f8f82006-05-10 13:41:53 +00002204#endif
2205
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002206 statusbar(_("Can now UnJustify!"));
2207
2208 /* If constant cursor position display is on, make sure the current
2209 * cursor position will be properly displayed on the statusbar. */
2210 if (ISSET(CONST_UPDATE))
2211 do_cursorpos(TRUE);
2212
2213 /* Display the shortcut list with UnJustify. */
2214 shortcut_init(TRUE);
2215 display_main_list();
2216
2217 /* Now get a keystroke and see if it's unjustify. If not, put back
2218 * the keystroke and return. */
2219 kbinput = do_input(&meta_key, &func_key, &s_or_t, &ran_func,
2220 &finished, FALSE);
Chris Allegretta0018d8e2008-03-13 08:23:52 +00002221 s = get_shortcut(currmenu, &kbinput, &meta_key, &func_key);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002222
Chris Allegrettaa1171632009-01-19 19:10:39 +00002223 if (s && s->scfunc == DO_UNCUT_TEXT) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002224 /* Splice the justify buffer back into the file, but only if we
2225 * actually justified something. */
2226 if (first_par_line != NULL) {
2227 filestruct *top_save;
2228
2229 /* Partition the filestruct so that it contains only the
2230 * text of the justified paragraph. */
2231 filepart = partition_filestruct(first_par_line, 0,
David Lawrence Ramseyccd1b7b2005-11-18 20:21:48 +00002232 last_par_line, filebot_inpar ?
2233 strlen(last_par_line->data) : 0);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002234
2235 /* Remove the text of the justified paragraph, and
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00002236 * replace it with the text in the justify buffer. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002237 free_filestruct(openfile->fileage);
2238 openfile->fileage = jusbuffer;
2239 openfile->filebot = jusbottom;
2240
2241 top_save = openfile->fileage;
2242
2243 /* Unpartition the filestruct so that it contains all the
2244 * text again. Note that the justified paragraph has been
2245 * replaced with the unjustified paragraph. */
2246 unpartition_filestruct(&filepart);
2247
2248 /* Renumber starting with the beginning line of the old
2249 * partition. */
2250 renumber(top_save);
2251
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00002252 /* Restore the justify we just did (ungrateful user!). */
2253 openfile->edittop = edittop_save;
2254 openfile->current = current_save;
2255 openfile->current_x = current_x_save;
2256 openfile->placewewant = pww_save;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002257 openfile->totsize = totsize_save;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002258#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002259 if (openfile->mark_set) {
2260 openfile->mark_begin = mark_begin_save;
2261 openfile->mark_begin_x = mark_begin_x_save;
2262 }
2263#endif
2264 openfile->modified = modified_save;
2265
2266 /* Clear the justify buffer. */
2267 jusbuffer = NULL;
2268
2269 if (!openfile->modified)
2270 titlebar(NULL);
Chris Allegrettafd265af2009-02-06 03:41:02 +00002271 edit_refresh_needed = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002272 }
2273 } else {
2274 unget_kbinput(kbinput, meta_key, func_key);
2275
2276 /* Blow away the text in the justify buffer. */
2277 free_filestruct(jusbuffer);
2278 jusbuffer = NULL;
2279 }
2280
2281 blank_statusbar();
2282
2283 /* Display the shortcut list with UnCut. */
2284 shortcut_init(FALSE);
2285 display_main_list();
2286}
2287
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002288/* Justify the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002289void do_justify_void(void)
2290{
2291 do_justify(FALSE);
2292}
2293
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002294/* Justify the entire file. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002295void do_full_justify(void)
2296{
2297 do_justify(TRUE);
2298}
2299#endif /* !DISABLE_JUSTIFY */
2300
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002301#ifndef DISABLE_SPELLER
2302/* A word is misspelled in the file. Let the user replace it. We
2303 * return FALSE if the user cancels. */
2304bool do_int_spell_fix(const char *word)
2305{
2306 char *save_search, *save_replace;
2307 size_t match_len, current_x_save = openfile->current_x;
2308 size_t pww_save = openfile->placewewant;
Chris Allegretta10f868d2008-03-14 04:08:51 +00002309 bool meta_key = FALSE, func_key = FALSE;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002310 filestruct *edittop_save = openfile->edittop;
2311 filestruct *current_save = openfile->current;
2312 /* Save where we are. */
2313 bool canceled = FALSE;
2314 /* The return value. */
2315 bool case_sens_set = ISSET(CASE_SENSITIVE);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002316#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002317 bool backwards_search_set = ISSET(BACKWARDS_SEARCH);
2318#endif
2319#ifdef HAVE_REGEX_H
2320 bool regexp_set = ISSET(USE_REGEXP);
2321#endif
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002322#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002323 bool old_mark_set = openfile->mark_set;
2324 bool added_magicline = FALSE;
2325 /* Whether we added a magicline after filebot. */
2326 bool right_side_up = FALSE;
2327 /* TRUE if (mark_begin, mark_begin_x) is the top of the mark,
2328 * FALSE if (current, current_x) is. */
2329 filestruct *top, *bot;
2330 size_t top_x, bot_x;
2331#endif
2332
2333 /* Make sure spell-check is case sensitive. */
2334 SET(CASE_SENSITIVE);
2335
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002336#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002337 /* Make sure spell-check goes forward only. */
2338 UNSET(BACKWARDS_SEARCH);
2339#endif
2340#ifdef HAVE_REGEX_H
2341 /* Make sure spell-check doesn't use regular expressions. */
2342 UNSET(USE_REGEXP);
2343#endif
2344
2345 /* Save the current search/replace strings. */
2346 search_init_globals();
2347 save_search = last_search;
2348 save_replace = last_replace;
2349
2350 /* Set the search/replace strings to the misspelled word. */
2351 last_search = mallocstrcpy(NULL, word);
2352 last_replace = mallocstrcpy(NULL, word);
2353
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002354#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002355 if (old_mark_set) {
2356 /* If the mark is on, partition the filestruct so that it
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002357 * contains only the marked text; if the NO_NEWLINES flag isn't
2358 * set, keep track of whether the text will have a magicline
2359 * added when we're done correcting misspelled words; and
2360 * turn the mark off. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002361 mark_order((const filestruct **)&top, &top_x,
2362 (const filestruct **)&bot, &bot_x, &right_side_up);
2363 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002364 if (!ISSET(NO_NEWLINES))
2365 added_magicline = (openfile->filebot->data[0] != '\0');
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002366 openfile->mark_set = FALSE;
2367 }
2368#endif
2369
2370 /* Start from the top of the file. */
2371 openfile->edittop = openfile->fileage;
2372 openfile->current = openfile->fileage;
2373 openfile->current_x = (size_t)-1;
2374 openfile->placewewant = 0;
2375
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00002376 /* Find the first whole occurrence of word. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002377 findnextstr_wrap_reset();
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00002378 while (findnextstr(TRUE, FALSE, openfile->fileage, 0, word,
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002379 &match_len)) {
2380 if (is_whole_word(openfile->current_x, openfile->current->data,
2381 word)) {
2382 size_t xpt = xplustabs();
2383 char *exp_word = display_string(openfile->current->data,
2384 xpt, strnlenpt(openfile->current->data,
2385 openfile->current_x + match_len) - xpt, FALSE);
2386
2387 edit_refresh();
2388
2389 do_replace_highlight(TRUE, exp_word);
2390
2391 /* Allow all instances of the word to be corrected. */
David Lawrence Ramsey9d8c2842006-02-07 21:11:05 +00002392 canceled = (do_prompt(FALSE,
2393#ifndef DISABLE_TABCOMP
2394 TRUE,
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002395#endif
Chris Allegretta79a33bb2008-03-05 07:34:01 +00002396 MSPELL, word,
Chris Allegretta10f868d2008-03-14 04:08:51 +00002397 &meta_key, &func_key,
David Lawrence Ramsey9d8c2842006-02-07 21:11:05 +00002398#ifndef NANO_TINY
2399 NULL,
2400#endif
David Lawrence Ramsey68160072006-02-18 21:32:29 +00002401 edit_refresh, _("Edit a replacement")) == -1);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002402
2403 do_replace_highlight(FALSE, exp_word);
2404
2405 free(exp_word);
2406
2407 if (!canceled && strcmp(word, answer) != 0) {
2408 openfile->current_x--;
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00002409 do_replace_loop(TRUE, &canceled, openfile->current,
2410 &openfile->current_x, word);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002411 }
2412
2413 break;
2414 }
2415 }
2416
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002417#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002418 if (old_mark_set) {
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002419 /* If the mark was on, the NO_NEWLINES flag isn't set, and we
2420 * added a magicline, remove it now. */
2421 if (!ISSET(NO_NEWLINES) && added_magicline)
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002422 remove_magicline();
2423
2424 /* Put the beginning and the end of the mark at the beginning
2425 * and the end of the spell-checked text. */
2426 if (openfile->fileage == openfile->filebot)
2427 bot_x += top_x;
2428 if (right_side_up) {
2429 openfile->mark_begin_x = top_x;
2430 current_x_save = bot_x;
2431 } else {
2432 current_x_save = top_x;
2433 openfile->mark_begin_x = bot_x;
2434 }
2435
2436 /* Unpartition the filestruct so that it contains all the text
2437 * again, and turn the mark back on. */
2438 unpartition_filestruct(&filepart);
2439 openfile->mark_set = TRUE;
2440 }
2441#endif
2442
2443 /* Restore the search/replace strings. */
2444 free(last_search);
2445 last_search = save_search;
2446 free(last_replace);
2447 last_replace = save_replace;
2448
2449 /* Restore where we were. */
2450 openfile->edittop = edittop_save;
2451 openfile->current = current_save;
2452 openfile->current_x = current_x_save;
2453 openfile->placewewant = pww_save;
2454
2455 /* Restore case sensitivity setting. */
2456 if (!case_sens_set)
2457 UNSET(CASE_SENSITIVE);
2458
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002459#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002460 /* Restore search/replace direction. */
2461 if (backwards_search_set)
2462 SET(BACKWARDS_SEARCH);
2463#endif
2464#ifdef HAVE_REGEX_H
2465 /* Restore regular expression usage setting. */
2466 if (regexp_set)
2467 SET(USE_REGEXP);
2468#endif
2469
2470 return !canceled;
2471}
2472
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002473/* Internal (integrated) spell checking using the spell program,
2474 * filtered through the sort and uniq programs. Return NULL for normal
2475 * termination, and the error string otherwise. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002476const char *do_int_speller(const char *tempfile_name)
2477{
2478 char *read_buff, *read_buff_ptr, *read_buff_word;
2479 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
2480 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
2481 pid_t pid_spell, pid_sort, pid_uniq;
2482 int spell_status, sort_status, uniq_status;
2483
2484 /* Create all three pipes up front. */
2485 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 ||
2486 pipe(uniq_fd) == -1)
2487 return _("Could not create pipe");
2488
2489 statusbar(_("Creating misspelled word list, please wait..."));
2490
2491 /* A new process to run spell in. */
2492 if ((pid_spell = fork()) == 0) {
David Lawrence Ramseyb159f942006-07-28 17:06:27 +00002493 /* Child continues (i.e. future spell process). */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002494 close(spell_fd[0]);
2495
2496 /* Replace the standard input with the temp file. */
2497 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
2498 goto close_pipes_and_exit;
2499
2500 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
2501 goto close_pipes_and_exit;
2502
2503 close(tempfile_fd);
2504
2505 /* Send spell's standard output to the pipe. */
2506 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
2507 goto close_pipes_and_exit;
2508
2509 close(spell_fd[1]);
2510
David Lawrence Ramsey3239ff22005-11-29 20:01:06 +00002511 /* Start the spell program; we are using $PATH. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002512 execlp("spell", "spell", NULL);
2513
2514 /* This should not be reached if spell is found. */
2515 exit(1);
2516 }
2517
2518 /* Parent continues here. */
2519 close(spell_fd[1]);
2520
2521 /* A new process to run sort in. */
2522 if ((pid_sort = fork()) == 0) {
David Lawrence Ramseyb159f942006-07-28 17:06:27 +00002523 /* Child continues (i.e. future spell process). Replace the
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002524 * standard input with the standard output of the old pipe. */
2525 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
2526 goto close_pipes_and_exit;
2527
2528 close(spell_fd[0]);
2529
2530 /* Send sort's standard output to the new pipe. */
2531 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
2532 goto close_pipes_and_exit;
2533
2534 close(sort_fd[1]);
2535
2536 /* Start the sort program. Use -f to remove mixed case. If
2537 * this isn't portable, let me know. */
2538 execlp("sort", "sort", "-f", NULL);
2539
2540 /* This should not be reached if sort is found. */
2541 exit(1);
2542 }
2543
2544 close(spell_fd[0]);
2545 close(sort_fd[1]);
2546
2547 /* A new process to run uniq in. */
2548 if ((pid_uniq = fork()) == 0) {
David Lawrence Ramseyb159f942006-07-28 17:06:27 +00002549 /* Child continues (i.e. future uniq process). Replace the
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002550 * standard input with the standard output of the old pipe. */
2551 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
2552 goto close_pipes_and_exit;
2553
2554 close(sort_fd[0]);
2555
2556 /* Send uniq's standard output to the new pipe. */
2557 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
2558 goto close_pipes_and_exit;
2559
2560 close(uniq_fd[1]);
2561
2562 /* Start the uniq program; we are using PATH. */
2563 execlp("uniq", "uniq", NULL);
2564
2565 /* This should not be reached if uniq is found. */
2566 exit(1);
2567 }
2568
2569 close(sort_fd[0]);
2570 close(uniq_fd[1]);
2571
2572 /* The child process was not forked successfully. */
2573 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
2574 close(uniq_fd[0]);
2575 return _("Could not fork");
2576 }
2577
2578 /* Get the system pipe buffer size. */
2579 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
2580 close(uniq_fd[0]);
2581 return _("Could not get size of pipe buffer");
2582 }
2583
2584 /* Read in the returned spelling errors. */
2585 read_buff_read = 0;
2586 read_buff_size = pipe_buff_size + 1;
2587 read_buff = read_buff_ptr = charalloc(read_buff_size);
2588
2589 while ((bytesread = read(uniq_fd[0], read_buff_ptr,
2590 pipe_buff_size)) > 0) {
2591 read_buff_read += bytesread;
2592 read_buff_size += pipe_buff_size;
2593 read_buff = read_buff_ptr = charealloc(read_buff,
2594 read_buff_size);
2595 read_buff_ptr += read_buff_read;
2596 }
2597
2598 *read_buff_ptr = '\0';
2599 close(uniq_fd[0]);
2600
2601 /* Process the spelling errors. */
2602 read_buff_word = read_buff_ptr = read_buff;
2603
2604 while (*read_buff_ptr != '\0') {
2605 if ((*read_buff_ptr == '\r') || (*read_buff_ptr == '\n')) {
2606 *read_buff_ptr = '\0';
2607 if (read_buff_word != read_buff_ptr) {
2608 if (!do_int_spell_fix(read_buff_word)) {
2609 read_buff_word = read_buff_ptr;
2610 break;
2611 }
2612 }
2613 read_buff_word = read_buff_ptr + 1;
2614 }
2615 read_buff_ptr++;
2616 }
2617
2618 /* Special case: the last word doesn't end with '\r' or '\n'. */
2619 if (read_buff_word != read_buff_ptr)
2620 do_int_spell_fix(read_buff_word);
2621
2622 free(read_buff);
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002623 search_replace_abort();
Chris Allegrettafd265af2009-02-06 03:41:02 +00002624 edit_refresh_needed = TRUE;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002625
2626 /* Process the end of the spell process. */
2627 waitpid(pid_spell, &spell_status, 0);
2628 waitpid(pid_sort, &sort_status, 0);
2629 waitpid(pid_uniq, &uniq_status, 0);
2630
2631 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
2632 return _("Error invoking \"spell\"");
2633
2634 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
2635 return _("Error invoking \"sort -f\"");
2636
2637 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
2638 return _("Error invoking \"uniq\"");
2639
2640 /* Otherwise... */
2641 return NULL;
2642
2643 close_pipes_and_exit:
2644 /* Don't leak any handles. */
2645 close(tempfile_fd);
2646 close(spell_fd[0]);
2647 close(spell_fd[1]);
2648 close(sort_fd[0]);
2649 close(sort_fd[1]);
2650 close(uniq_fd[0]);
2651 close(uniq_fd[1]);
2652 exit(1);
2653}
2654
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002655/* External (alternate) spell checking. Return NULL for normal
2656 * termination, and the error string otherwise. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002657const char *do_alt_speller(char *tempfile_name)
2658{
2659 int alt_spell_status;
2660 size_t current_x_save = openfile->current_x;
2661 size_t pww_save = openfile->placewewant;
2662 ssize_t current_y_save = openfile->current_y;
2663 ssize_t lineno_save = openfile->current->lineno;
2664 pid_t pid_spell;
2665 char *ptr;
2666 static int arglen = 3;
2667 static char **spellargs = NULL;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002668#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002669 bool old_mark_set = openfile->mark_set;
2670 bool added_magicline = FALSE;
2671 /* Whether we added a magicline after filebot. */
2672 bool right_side_up = FALSE;
2673 /* TRUE if (mark_begin, mark_begin_x) is the top of the mark,
2674 * FALSE if (current, current_x) is. */
2675 filestruct *top, *bot;
2676 size_t top_x, bot_x;
2677 ssize_t mb_lineno_save = 0;
2678 /* We're going to close the current file, and open the output of
2679 * the alternate spell command. The line that mark_begin points
2680 * to will be freed, so we save the line number and restore it
2681 * afterwards. */
2682 size_t totsize_save = openfile->totsize;
2683 /* Our saved value of totsize, used when we spell-check a marked
2684 * selection. */
2685
2686 if (old_mark_set) {
2687 /* If the mark is on, save the number of the line it starts on,
2688 * and then turn the mark off. */
2689 mb_lineno_save = openfile->mark_begin->lineno;
2690 openfile->mark_set = FALSE;
2691 }
2692#endif
2693
2694 endwin();
2695
2696 /* Set up an argument list to pass execvp(). */
2697 if (spellargs == NULL) {
2698 spellargs = (char **)nmalloc(arglen * sizeof(char *));
2699
2700 spellargs[0] = strtok(alt_speller, " ");
2701 while ((ptr = strtok(NULL, " ")) != NULL) {
2702 arglen++;
2703 spellargs = (char **)nrealloc(spellargs, arglen *
2704 sizeof(char *));
2705 spellargs[arglen - 3] = ptr;
2706 }
2707 spellargs[arglen - 1] = NULL;
2708 }
2709 spellargs[arglen - 2] = tempfile_name;
2710
2711 /* Start a new process for the alternate speller. */
2712 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey2e2112c2005-11-29 05:39:31 +00002713 /* Start alternate spell program; we are using $PATH. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002714 execvp(spellargs[0], spellargs);
2715
2716 /* Should not be reached, if alternate speller is found!!! */
2717 exit(1);
2718 }
2719
2720 /* If we couldn't fork, get out. */
2721 if (pid_spell < 0)
2722 return _("Could not fork");
2723
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002724#ifndef NANO_TINY
David Lawrence Ramseyb18482e2005-07-26 00:06:34 +00002725 /* Don't handle a pending SIGWINCH until the alternate spell checker
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00002726 * is finished and we've loaded the spell-checked file back in. */
David Lawrence Ramseyb18482e2005-07-26 00:06:34 +00002727 allow_pending_sigwinch(FALSE);
2728#endif
2729
2730 /* Wait for the alternate spell checker to finish. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002731 wait(&alt_spell_status);
2732
David Lawrence Ramsey84fdb902005-08-14 20:08:49 +00002733 /* Reenter curses mode. */
2734 doupdate();
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002735
2736 /* Restore the terminal to its previous state. */
2737 terminal_init();
2738
2739 /* Turn the cursor back on for sure. */
2740 curs_set(1);
2741
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00002742 /* The screen might have been resized. If it has, reinitialize all
2743 * the windows based on the new screen dimensions. */
2744 window_init();
2745
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002746 if (!WIFEXITED(alt_spell_status) ||
2747 WEXITSTATUS(alt_spell_status) != 0) {
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00002748 char *alt_spell_error;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002749 char *invoke_error = _("Error invoking \"%s\"");
2750
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002751#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002752 /* Turn the mark back on if it was on before. */
2753 openfile->mark_set = old_mark_set;
2754#endif
2755
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00002756 alt_spell_error =
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002757 charalloc(strlen(invoke_error) +
2758 strlen(alt_speller) + 1);
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00002759 sprintf(alt_spell_error, invoke_error, alt_speller);
2760 return alt_spell_error;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002761 }
2762
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002763#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002764 if (old_mark_set) {
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002765 /* If the mark is on, partition the filestruct so that it
2766 * contains only the marked text; if the NO_NEWLINES flag isn't
2767 * set, keep track of whether the text will have a magicline
2768 * added when we're done correcting misspelled words; and
2769 * turn the mark off. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002770 mark_order((const filestruct **)&top, &top_x,
2771 (const filestruct **)&bot, &bot_x, &right_side_up);
2772 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002773 if (!ISSET(NO_NEWLINES))
2774 added_magicline = (openfile->filebot->data[0] != '\0');
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002775
2776 /* Get the number of characters in the marked text, and subtract
2777 * it from the saved value of totsize. */
2778 totsize_save -= get_totsize(top, bot);
2779 }
2780#endif
2781
David Lawrence Ramsey9c984e82005-11-08 19:15:58 +00002782 /* Replace the text of the current buffer with the spell-checked
2783 * text. */
2784 replace_buffer(tempfile_name);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002785
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002786#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002787 if (old_mark_set) {
2788 filestruct *top_save = openfile->fileage;
2789
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002790 /* If the mark was on, the NO_NEWLINES flag isn't set, and we
2791 * added a magicline, remove it now. */
2792 if (!ISSET(NO_NEWLINES) && added_magicline)
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002793 remove_magicline();
2794
2795 /* Put the beginning and the end of the mark at the beginning
2796 * and the end of the spell-checked text. */
2797 if (openfile->fileage == openfile->filebot)
2798 bot_x += top_x;
2799 if (right_side_up) {
2800 openfile->mark_begin_x = top_x;
2801 current_x_save = bot_x;
2802 } else {
2803 current_x_save = top_x;
2804 openfile->mark_begin_x = bot_x;
2805 }
2806
2807 /* Unpartition the filestruct so that it contains all the text
2808 * again. Note that we've replaced the marked text originally
2809 * in the partition with the spell-checked marked text in the
2810 * temp file. */
2811 unpartition_filestruct(&filepart);
2812
2813 /* Renumber starting with the beginning line of the old
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002814 * partition. Also add the number of characters in the
2815 * spell-checked marked text to the saved value of totsize, and
2816 * then make that saved value the actual value. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002817 renumber(top_save);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002818 totsize_save += openfile->totsize;
2819 openfile->totsize = totsize_save;
2820
2821 /* Assign mark_begin to the line where the mark began before. */
2822 do_gotopos(mb_lineno_save, openfile->mark_begin_x,
2823 current_y_save, 0);
2824 openfile->mark_begin = openfile->current;
2825
2826 /* Assign mark_begin_x to the location in mark_begin where the
2827 * mark began before, adjusted for any shortening of the
2828 * line. */
2829 openfile->mark_begin_x = openfile->current_x;
2830
2831 /* Turn the mark back on. */
2832 openfile->mark_set = TRUE;
2833 }
2834#endif
2835
2836 /* Go back to the old position, and mark the file as modified. */
2837 do_gotopos(lineno_save, current_x_save, current_y_save, pww_save);
2838 set_modified();
2839
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002840#ifndef NANO_TINY
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00002841 /* Handle a pending SIGWINCH again. */
2842 allow_pending_sigwinch(TRUE);
2843#endif
2844
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002845 return NULL;
2846}
2847
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002848/* Spell check the current file. If an alternate spell checker is
2849 * specified, use it. Otherwise, use the internal spell checker. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002850void do_spell(void)
2851{
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00002852 bool status;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002853 FILE *temp_file;
2854 char *temp = safe_tempfile(&temp_file);
2855 const char *spell_msg;
2856
2857 if (temp == NULL) {
David Lawrence Ramseyf0e3ca62006-05-03 13:11:00 +00002858 statusbar(_("Error writing temp file: %s"), strerror(errno));
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002859 return;
2860 }
2861
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00002862 status =
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002863#ifndef NANO_TINY
David Lawrence Ramsey0e1df432007-01-12 02:58:12 +00002864 openfile->mark_set ? write_marked_file(temp, temp_file, TRUE,
David Lawrence Ramseyb6c4dbf2006-11-25 22:38:17 +00002865 OVERWRITE) :
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002866#endif
David Lawrence Ramseyb6c4dbf2006-11-25 22:38:17 +00002867 write_file(temp, temp_file, TRUE, OVERWRITE, FALSE);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002868
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00002869 if (!status) {
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002870 statusbar(_("Error writing temp file: %s"), strerror(errno));
2871 free(temp);
2872 return;
2873 }
2874
2875 spell_msg = (alt_speller != NULL) ? do_alt_speller(temp) :
2876 do_int_speller(temp);
2877 unlink(temp);
2878 free(temp);
2879
Chris Allegretta79a33bb2008-03-05 07:34:01 +00002880 currmenu = MMAIN;
David Lawrence Ramseyf32e1dd2006-06-09 17:09:51 +00002881
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002882 /* If the spell-checker printed any error messages onscreen, make
2883 * sure that they're cleared off. */
David Lawrence Ramseyf32e1dd2006-06-09 17:09:51 +00002884 total_refresh();
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002885
2886 if (spell_msg != NULL) {
2887 if (errno == 0)
2888 /* Don't display an error message of "Success". */
2889 statusbar(_("Spell checking failed: %s"), spell_msg);
2890 else
2891 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
2892 strerror(errno));
2893 } else
2894 statusbar(_("Finished checking spelling"));
2895}
2896#endif /* !DISABLE_SPELLER */
2897
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002898#ifndef NANO_TINY
David Lawrence Ramseyd7f0fe92005-08-10 22:51:49 +00002899/* Our own version of "wc". Note that its character counts are in
2900 * multibyte characters instead of single-byte characters. */
David Lawrence Ramsey8e942342005-07-25 04:21:46 +00002901void do_wordlinechar_count(void)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002902{
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002903 size_t words = 0, chars = 0;
Chris Allegretta8b6461f2008-05-31 23:09:40 +00002904 ssize_t nlines = 0;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002905 size_t current_x_save = openfile->current_x;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002906 size_t pww_save = openfile->placewewant;
2907 filestruct *current_save = openfile->current;
2908 bool old_mark_set = openfile->mark_set;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002909 filestruct *top, *bot;
2910 size_t top_x, bot_x;
2911
2912 if (old_mark_set) {
2913 /* If the mark is on, partition the filestruct so that it
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +00002914 * contains only the marked text, and turn the mark off. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002915 mark_order((const filestruct **)&top, &top_x,
2916 (const filestruct **)&bot, &bot_x, NULL);
2917 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002918 openfile->mark_set = FALSE;
2919 }
2920
2921 /* Start at the top of the file. */
2922 openfile->current = openfile->fileage;
2923 openfile->current_x = 0;
2924 openfile->placewewant = 0;
2925
2926 /* Keep moving to the next word (counting punctuation characters as
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002927 * part of a word, as "wc -w" does), without updating the screen,
2928 * until we reach the end of the file, incrementing the total word
2929 * count whenever we're on a word just before moving. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002930 while (openfile->current != openfile->filebot ||
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +00002931 openfile->current->data[openfile->current_x] != '\0') {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002932 if (do_next_word(TRUE, FALSE))
2933 words++;
2934 }
2935
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002936 /* Get the total line and character counts, as "wc -l" and "wc -c"
2937 * do, but get the latter in multibyte characters. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002938 if (old_mark_set) {
Chris Allegretta8b6461f2008-05-31 23:09:40 +00002939 nlines = openfile->filebot->lineno -
David Lawrence Ramsey78a81b22005-07-25 18:59:24 +00002940 openfile->fileage->lineno + 1;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002941 chars = get_totsize(openfile->fileage, openfile->filebot);
2942
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002943 /* Unpartition the filestruct so that it contains all the text
2944 * again, and turn the mark back on. */
2945 unpartition_filestruct(&filepart);
2946 openfile->mark_set = TRUE;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002947 } else {
Chris Allegretta8b6461f2008-05-31 23:09:40 +00002948 nlines = openfile->filebot->lineno;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002949 chars = openfile->totsize;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002950 }
2951
2952 /* Restore where we were. */
2953 openfile->current = current_save;
2954 openfile->current_x = current_x_save;
2955 openfile->placewewant = pww_save;
2956
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002957 /* Display the total word, line, and character counts on the
2958 * statusbar. */
David Lawrence Ramsey7b71f572005-10-06 20:46:11 +00002959 statusbar(_("%sWords: %lu Lines: %ld Chars: %lu"), old_mark_set ?
Chris Allegretta8b6461f2008-05-31 23:09:40 +00002960 _("In Selection: ") : "", (unsigned long)words, (long)nlines,
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002961 (unsigned long)chars);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002962}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002963#endif /* !NANO_TINY */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002964
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002965/* Get verbatim input. */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002966void do_verbatim_input(void)
2967{
2968 int *kbinput;
2969 size_t kbinput_len, i;
2970 char *output;
2971
David Lawrence Ramseyf451d6a2006-05-27 16:02:48 +00002972 /* TRANSLATORS: This is displayed when the next keystroke will be
2973 * inserted verbatim. */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002974 statusbar(_("Verbatim Input"));
2975
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002976 /* Read in all the verbatim characters. */
2977 kbinput = get_verbatim_kbinput(edit, &kbinput_len);
2978
David Lawrence Ramseya620e682006-05-27 18:19:03 +00002979 /* If constant cursor position display is on, make sure the current
2980 * cursor position will be properly displayed on the statusbar.
2981 * Otherwise, blank the statusbar. */
2982 if (ISSET(CONST_UPDATE))
2983 do_cursorpos(TRUE);
2984 else {
2985 blank_statusbar();
2986 wnoutrefresh(bottomwin);
2987 }
David Lawrence Ramsey6fb66892006-05-27 17:39:19 +00002988
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002989 /* Display all the verbatim characters at once, not filtering out
2990 * control characters. */
2991 output = charalloc(kbinput_len + 1);
2992
2993 for (i = 0; i < kbinput_len; i++)
2994 output[i] = (char)kbinput[i];
2995 output[i] = '\0';
2996
David Lawrence Ramseyad36bdc2006-12-02 17:22:21 +00002997 free(kbinput);
2998
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002999 do_output(output, kbinput_len, TRUE);
3000
3001 free(output);
3002}
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00003003