blob: 302e6374dc416fc37a55f2fa0829ce67cad80319 [file] [log] [blame]
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001/* $Id$ */
2/**************************************************************************
David Lawrence Ramsey4005fc62005-10-08 06:12:41 +00003 * text.c *
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00004 * *
David Lawrence Ramsey315eb322005-11-28 19:35:29 +00005 * Copyright (C) 1999-2004 Chris Allegretta *
David Lawrence Ramsey33f2a082006-02-07 21:11:49 +00006 * Copyright (C) 2005-2006 David Lawrence Ramsey *
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 *
9 * the Free Software Foundation; either version 2, or (at your option) *
10 * 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 {
58 statusbar(_("Mark UNset"));
59 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 Ramsey6d6a36c2005-12-08 07:09:08 +000066/* Delete one character. */
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
71 * update_line()? */
72
73 assert(openfile->current != NULL && openfile->current->data != NULL && openfile->current_x <= strlen(openfile->current->data));
74
75 openfile->placewewant = xplustabs();
76
77 if (openfile->current->data[openfile->current_x] != '\0') {
78 int char_buf_len = parse_mbchar(openfile->current->data +
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +000079 openfile->current_x, NULL, NULL);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000080 size_t line_len = strlen(openfile->current->data +
81 openfile->current_x);
82
83 assert(openfile->current_x < strlen(openfile->current->data));
84
85 /* Let's get dangerous. */
86 charmove(&openfile->current->data[openfile->current_x],
87 &openfile->current->data[openfile->current_x +
88 char_buf_len], line_len - char_buf_len + 1);
89
90 null_at(&openfile->current->data, openfile->current_x +
91 line_len - char_buf_len);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +000092#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000093 if (openfile->mark_set && openfile->mark_begin ==
94 openfile->current && openfile->current_x <
95 openfile->mark_begin_x)
96 openfile->mark_begin_x -= char_buf_len;
97#endif
98 openfile->totsize--;
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +000099 } else if (openfile->current != openfile->filebot) {
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000100 filestruct *foo = openfile->current->next;
101
102 assert(openfile->current_x == strlen(openfile->current->data));
103
104 /* If we're deleting at the end of a line, we need to call
105 * edit_refresh(). */
106 if (openfile->current->data[openfile->current_x] == '\0')
107 do_refresh = TRUE;
108
109 openfile->current->data = charealloc(openfile->current->data,
110 openfile->current_x + strlen(foo->data) + 1);
111 strcpy(openfile->current->data + openfile->current_x,
112 foo->data);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000113#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000114 if (openfile->mark_set && openfile->mark_begin ==
115 openfile->current->next) {
116 openfile->mark_begin = openfile->current;
117 openfile->mark_begin_x += openfile->current_x;
118 }
119#endif
120 if (openfile->filebot == foo)
121 openfile->filebot = openfile->current;
122
123 unlink_node(foo);
124 delete_node(foo);
125 renumber(openfile->current);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000126 openfile->totsize--;
127#ifndef DISABLE_WRAPPING
128 wrap_reset();
129#endif
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +0000130
David Lawrence Ramseya0168ca2005-11-05 17:35:44 +0000131 /* If the NO_NEWLINES flag isn't set, and text has been added to
132 * the magicline as a result of deleting at the end of the line
David Lawrence Ramsey0f6236f2005-11-09 00:08:29 +0000133 * before filebot, add a new magicline. */
David Lawrence Ramseya0168ca2005-11-05 17:35:44 +0000134 if (!ISSET(NO_NEWLINES) && openfile->current ==
135 openfile->filebot && openfile->current->data[0] != '\0')
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +0000136 new_magicline();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000137 } else
138 return;
139
David Lawrence Ramsey0f6236f2005-11-09 00:08:29 +0000140 set_modified();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000141
142#ifdef ENABLE_COLOR
143 /* If color syntaxes are available and turned on, we need to call
144 * edit_refresh(). */
145 if (openfile->colorstrings != NULL && !ISSET(NO_COLOR_SYNTAX))
146 do_refresh = TRUE;
147#endif
148
149 if (do_refresh)
150 edit_refresh();
151 else
152 update_line(openfile->current, openfile->current_x);
153}
154
David Lawrence Ramsey5b7b3e32005-12-31 21:22:54 +0000155/* Backspace over one character. That is, move the cursor left one
156 * character, and then delete the character there. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000157void do_backspace(void)
158{
159 if (openfile->current != openfile->fileage ||
160 openfile->current_x > 0) {
David Lawrence Ramsey1c3bfa92005-09-13 04:53:44 +0000161 do_left();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000162 do_delete();
163 }
164}
165
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000166/* Insert a tab. If the TABS_TO_SPACES flag is set, insert the number
167 * of spaces that a tab would normally take up. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000168void do_tab(void)
169{
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000170#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000171 if (ISSET(TABS_TO_SPACES)) {
172 char *output;
David Lawrence Ramsey90b07fc2005-10-07 15:57:48 +0000173 size_t output_len = 0, new_pww = xplustabs();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000174
175 do {
176 new_pww++;
177 output_len++;
178 } while (new_pww % tabsize != 0);
179
180 output = charalloc(output_len + 1);
181
182 charset(output, ' ', output_len);
183 output[output_len] = '\0';
184
185 do_output(output, output_len, TRUE);
186
187 free(output);
188 } else {
189#endif
190 do_output("\t", 1, TRUE);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000191#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000192 }
193#endif
194}
195
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000196#ifndef NANO_TINY
197/* Indent or unindent all lines covered by the mark len characters,
198 * depending on whether len is positive or negative. If the
199 * TABS_TO_SPACES flag is set, indent/unindent by len spaces.
200 * Otherwise, indent/unindent by (len / tabsize) tabs and (len %
201 * tabsize) spaces. */
202void do_indent_marked(ssize_t len)
203{
204 bool indent_changed = FALSE;
205 /* Whether any indenting or unindenting was done. */
206 bool unindent = FALSE;
207 /* Whether we're unindenting text. */
208 char *line_indent;
209 /* The text added to each line in order to indent it. */
210 size_t line_indent_len;
211 /* The length of the text added to each line in order to indent
212 * it. */
213 filestruct *top, *bot, *f;
214 size_t top_x, bot_x;
215
216 assert(openfile->current != NULL && openfile->current->data != NULL);
217
218 check_statusblank();
219
220 /* If the mark isn't on, indicate it on the statusbar and get
221 * out. */
222 if (!openfile->mark_set) {
223 statusbar(_("No lines selected, nothing to do!"));
224 return;
225 }
226
227 /* If len is zero, get out. */
228 if (len == 0)
229 return;
230
231 /* If len is negative, make it positive and set unindent to TRUE. */
232 if (len < 0) {
233 len = -len;
234 unindent = TRUE;
235 /* Otherwise, we're indenting, in which case the file will always be
236 * modified, so set indent_changed to TRUE. */
237 } else
238 indent_changed = TRUE;
239
240 /* Get the coordinates of the marked text. */
241 mark_order((const filestruct **)&top, &top_x,
242 (const filestruct **)&bot, &bot_x, NULL);
243
244 /* Set up the text we'll be using as indentation. */
245 line_indent = charalloc(len + 1);
246
247 if (ISSET(TABS_TO_SPACES)) {
248 /* Set the indentation to len spaces. */
249 charset(line_indent, ' ', len);
250 line_indent_len = len;
251 } else {
252 /* Set the indentation to (len / tabsize) tabs and (len %
253 * tabsize) spaces. */
254 size_t num_tabs = len / tabsize;
255 size_t num_spaces = len % tabsize;
256
257 charset(line_indent, '\t', num_tabs);
258 charset(line_indent + num_tabs, ' ', num_spaces);
259
260 line_indent_len = num_tabs + num_spaces;
261 }
262
263 line_indent[line_indent_len] = '\0';
264
265 /* Go through each line of the marked text. */
266 for (f = top; f != bot->next; f = f->next) {
267 size_t line_len = strlen(f->data);
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000268 size_t indent_len = indent_length(f->data);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000269
270 if (unindent) {
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000271 size_t indent_col = strnlenpt(f->data, indent_len);
272
273 if (len <= indent_col) {
274 size_t indent_new = actual_x(f->data, indent_col - len);
275 size_t indent_shift = indent_len - indent_new;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000276
277 /* If we're unindenting, and there's at least len
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000278 * columns' worth of indentation at the beginning of the
279 * non-whitespace text of this line, remove it. */
280 charmove(&f->data[indent_new], &f->data[indent_len],
281 line_len - indent_shift - indent_new + 1);
282 null_at(&f->data, line_len - indent_shift + 1);
283 openfile->totsize -= indent_shift;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000284
David Lawrence Ramsey2e8fac62006-04-29 15:44:58 +0000285 /* Keep track of the change in the current line. */
David Lawrence Ramsey2e8fac62006-04-29 15:44:58 +0000286 if (f == openfile->mark_begin &&
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000287 openfile->mark_begin_x >= indent_shift)
288 openfile->mark_begin_x -= indent_shift;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000289
David Lawrence Ramsey7194a612006-04-29 16:11:21 +0000290 if (f == openfile->current && openfile->current_x >=
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000291 indent_shift)
292 openfile->current_x -= indent_shift;
David Lawrence Ramsey7194a612006-04-29 16:11:21 +0000293
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000294 /* We've unindented, so set indent_changed to TRUE. */
295 if (!indent_changed)
296 indent_changed = TRUE;
297 }
298 } else {
299 /* If we're indenting, add the characters in line_indent to
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000300 * the beginning of the non-whitespace text of this line. */
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000301 f->data = charealloc(f->data, line_len +
302 line_indent_len + 1);
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000303 charmove(&f->data[indent_len + line_indent_len],
304 &f->data[indent_len], line_len - indent_len + 1);
305 strncpy(f->data + indent_len, line_indent, line_indent_len);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000306 openfile->totsize += line_indent_len;
307
David Lawrence Ramsey2e8fac62006-04-29 15:44:58 +0000308 /* Keep track of the change in the current line. */
David Lawrence Ramseyfd3ccee2006-04-30 01:29:51 +0000309 if (f == openfile->mark_begin)
David Lawrence Ramsey7194a612006-04-29 16:11:21 +0000310 openfile->mark_begin_x += line_indent_len;
311
David Lawrence Ramsey2e8fac62006-04-29 15:44:58 +0000312 if (f == openfile->current)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000313 openfile->current_x += line_indent_len;
David Lawrence Ramsey2e8fac62006-04-29 15:44:58 +0000314
David Lawrence Ramsey5c819b52006-04-29 15:12:07 +0000315 /* If the NO_NEWLINES flag isn't set, and this is the
316 * magicline, add a new magicline. */
317 if (!ISSET(NO_NEWLINES) && f == openfile->filebot)
318 new_magicline();
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000319 }
320 }
321
322 free(line_indent);
323
324 if (indent_changed) {
325 /* Mark the file as modified. */
326 set_modified();
327
328 /* Update the screen. */
329 edit_refresh();
330 }
331}
332
333/* Indent all lines covered by the mark tabsize characters. */
334void do_indent_marked_void(void)
335{
336 do_indent_marked(tabsize);
337}
338
339/* Unindent all lines covered by the mark tabsize characters. */
340void do_unindent_marked_void(void)
341{
342 do_indent_marked(-tabsize);
343}
344#endif /* !NANO_TINY */
345
David Lawrence Ramseyb0e04c02005-12-08 07:24:54 +0000346/* Someone hits Enter *gasp!* */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000347void do_enter(void)
348{
349 filestruct *newnode = make_new_node(openfile->current);
350 size_t extra = 0;
351
352 assert(openfile->current != NULL && openfile->current->data != NULL);
353
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000354#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000355 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
356 if (ISSET(AUTOINDENT)) {
357 /* If we are breaking the line in the indentation, the new
358 * indentation should have only current_x characters, and
359 * current_x should not change. */
360 extra = indent_length(openfile->current->data);
361 if (extra > openfile->current_x)
362 extra = openfile->current_x;
363 }
364#endif
365 newnode->data = charalloc(strlen(openfile->current->data +
366 openfile->current_x) + extra + 1);
367 strcpy(&newnode->data[extra], openfile->current->data +
368 openfile->current_x);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000369#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000370 if (ISSET(AUTOINDENT)) {
371 strncpy(newnode->data, openfile->current->data, extra);
372 openfile->totsize += mbstrlen(newnode->data);
373 }
374#endif
375 null_at(&openfile->current->data, openfile->current_x);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000376#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000377 if (openfile->mark_set && openfile->current ==
378 openfile->mark_begin && openfile->current_x <
379 openfile->mark_begin_x) {
380 openfile->mark_begin = newnode;
381 openfile->mark_begin_x += extra - openfile->current_x;
382 }
383#endif
384 openfile->current_x = extra;
385
386 if (openfile->current == openfile->filebot)
387 openfile->filebot = newnode;
388 splice_node(openfile->current, newnode,
389 openfile->current->next);
390
391 renumber(openfile->current);
392 openfile->current = newnode;
393
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000394 openfile->totsize++;
395 set_modified();
David Lawrence Ramseyfeb89db2005-09-13 04:45:46 +0000396
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000397 openfile->placewewant = xplustabs();
David Lawrence Ramseyfeb89db2005-09-13 04:45:46 +0000398
399 edit_refresh();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000400}
401
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000402#ifndef NANO_TINY
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000403/* Send a SIGKILL (unconditional kill) to the forked process in
404 * execute_command(). */
David Lawrence Ramsey8befda62005-12-06 19:39:56 +0000405RETSIGTYPE cancel_command(int signal)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000406{
407 if (kill(pid, SIGKILL) == -1)
408 nperror("kill");
409}
410
David Lawrence Ramsey0ed71712005-11-08 23:09:47 +0000411/* Execute command in a shell. Return TRUE on success. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000412bool execute_command(const char *command)
413{
414 int fd[2];
415 FILE *f;
David Lawrence Ramseyeae85712005-11-29 05:48:06 +0000416 char *shellenv;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000417 struct sigaction oldaction, newaction;
418 /* Original and temporary handlers for SIGINT. */
419 bool sig_failed = FALSE;
420 /* Did sigaction() fail without changing the signal handlers? */
421
422 /* Make our pipes. */
423 if (pipe(fd) == -1) {
424 statusbar(_("Could not pipe"));
425 return FALSE;
426 }
427
David Lawrence Ramseyeae85712005-11-29 05:48:06 +0000428 /* Check $SHELL for the shell to use. If it isn't set, use
David Lawrence Ramsey1932dfb2005-11-29 05:52:49 +0000429 * /bin/sh. Note that $SHELL should contain only a path, with no
430 * arguments. */
David Lawrence Ramseyeae85712005-11-29 05:48:06 +0000431 shellenv = getenv("SHELL");
432 if (shellenv == NULL)
433 shellenv = "/bin/sh";
434
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000435 /* Fork a child. */
436 if ((pid = fork()) == 0) {
437 close(fd[0]);
438 dup2(fd[1], fileno(stdout));
439 dup2(fd[1], fileno(stderr));
440
441 /* If execl() returns at all, there was an error. */
David Lawrence Ramsey5da68ee2005-11-29 05:21:06 +0000442 execl(shellenv, tail(shellenv), "-c", command, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000443 exit(0);
444 }
445
David Lawrence Ramseyc838a4c2006-04-26 18:33:50 +0000446 /* Continue as parent. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000447 close(fd[1]);
448
449 if (pid == -1) {
450 close(fd[0]);
451 statusbar(_("Could not fork"));
452 return FALSE;
453 }
454
455 /* Before we start reading the forked command's output, we set
456 * things up so that Ctrl-C will cancel the new process. */
457
458 /* Enable interpretation of the special control keys so that we get
459 * SIGINT when Ctrl-C is pressed. */
460 enable_signals();
461
462 if (sigaction(SIGINT, NULL, &newaction) == -1) {
463 sig_failed = TRUE;
464 nperror("sigaction");
465 } else {
466 newaction.sa_handler = cancel_command;
467 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
468 sig_failed = TRUE;
469 nperror("sigaction");
470 }
471 }
472
473 /* Note that now oldaction is the previous SIGINT signal handler,
474 * to be restored later. */
475
476 f = fdopen(fd[0], "rb");
477 if (f == NULL)
478 nperror("fdopen");
479
480 read_file(f, "stdin");
481
482 /* If multibuffer mode is on, we could be here in view mode. If so,
483 * don't set the modification flag. */
484 if (!ISSET(VIEW_MODE))
485 set_modified();
486
487 if (wait(NULL) == -1)
488 nperror("wait");
489
490 if (!sig_failed && sigaction(SIGINT, &oldaction, NULL) == -1)
491 nperror("sigaction");
492
493 /* Disable interpretation of the special control keys so that we can
494 * use Ctrl-C for other things. */
495 disable_signals();
496
497 return TRUE;
498}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000499#endif /* !NANO_TINY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000500
501#ifndef DISABLE_WRAPPING
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000502/* Clear the prepend_wrap flag. We need to do this as soon as we do
503 * something other than type text. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000504void wrap_reset(void)
505{
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000506 prepend_wrap = FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000507}
508
509/* We wrap the given line. Precondition: we assume the cursor has been
510 * moved forward since the last typed character. Return value: whether
511 * we wrapped. */
512bool do_wrap(filestruct *line)
513{
514 size_t line_len;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000515 /* The length of the line we wrap. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000516 ssize_t wrap_loc;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000517 /* The index of line->data where we wrap. */
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000518#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000519 const char *indent_string = NULL;
520 /* Indentation to prepend to the new line. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000521 size_t indent_len = 0;
522 /* The length of indent_string. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000523#endif
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000524 const char *after_break;
525 /* The text after the wrap point. */
526 size_t after_break_len;
527 /* The length of after_break. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000528 bool prepending = FALSE;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000529 /* Do we prepend to the next line? */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000530 const char *next_line = NULL;
531 /* The next line, minus indentation. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000532 size_t next_line_len = 0;
533 /* The length of next_line. */
534 char *new_line = NULL;
535 /* The line we create. */
536 size_t new_line_len = 0;
537 /* The eventual length of new_line. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000538
539 /* There are three steps. First, we decide where to wrap. Then, we
540 * create the new wrap line. Finally, we clean up. */
541
542 /* Step 1, finding where to wrap. We are going to add a new line
543 * after a blank character. In this step, we call break_line() to
544 * get the location of the last blank we can break the line at, and
545 * and set wrap_loc to the location of the character after it, so
546 * that the blank is preserved at the end of the line.
547 *
548 * If there is no legal wrap point, or we reach the last character
549 * of the line while trying to find one, we should return without
550 * wrapping. Note that if autoindent is turned on, we don't break
551 * at the end of it! */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000552 assert(line != NULL && line->data != NULL);
553
554 /* Save the length of the line. */
555 line_len = strlen(line->data);
556
557 /* Find the last blank where we can break the line. */
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000558 wrap_loc = break_line(line->data, fill
559#ifndef DISABLE_HELP
560 , FALSE
561#endif
562 );
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000563
564 /* If we couldn't break the line, or we've reached the end of it, we
565 * don't wrap. */
566 if (wrap_loc == -1 || line->data[wrap_loc] == '\0')
567 return FALSE;
568
569 /* Otherwise, move forward to the character just after the blank. */
570 wrap_loc += move_mbright(line->data + wrap_loc, 0);
571
572 /* If we've reached the end of the line, we don't wrap. */
573 if (line->data[wrap_loc] == '\0')
574 return FALSE;
575
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000576#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000577 /* If autoindent is turned on, and we're on the character just after
578 * the indentation, we don't wrap. */
579 if (ISSET(AUTOINDENT)) {
580 /* Get the indentation of this line. */
581 indent_string = line->data;
582 indent_len = indent_length(indent_string);
583
584 if (wrap_loc == indent_len)
585 return FALSE;
586 }
587#endif
588
589 /* Step 2, making the new wrap line. It will consist of indentation
590 * followed by the text after the wrap point, optionally followed by
591 * a space (if the text after the wrap point doesn't end in a blank)
592 * and the text of the next line, if they can fit without
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000593 * wrapping, the next line exists, and the prepend_wrap flag is
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000594 * set. */
595
596 /* after_break is the text that will be wrapped to the next line. */
597 after_break = line->data + wrap_loc;
598 after_break_len = line_len - wrap_loc;
599
600 assert(strlen(after_break) == after_break_len);
601
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000602 /* We prepend the wrapped text to the next line, if the prepend_wrap
603 * flag is set, there is a next line, and prepending would not make
604 * the line too long. */
605 if (prepend_wrap && line != openfile->filebot) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000606 const char *end = after_break + move_mbleft(after_break,
607 after_break_len);
608
609 /* If after_break doesn't end in a blank, make sure it ends in a
610 * space. */
611 if (!is_blank_mbchar(end)) {
612 line_len++;
613 line->data = charealloc(line->data, line_len + 1);
614 line->data[line_len - 1] = ' ';
615 line->data[line_len] = '\0';
616 after_break = line->data + wrap_loc;
617 after_break_len++;
618 openfile->totsize++;
619 }
620
621 next_line = line->next->data;
622 next_line_len = strlen(next_line);
623
624 if (after_break_len + next_line_len <= fill) {
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000625 prepending = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000626 new_line_len += next_line_len;
627 }
628 }
629
630 /* new_line_len is now the length of the text that will be wrapped
631 * to the next line, plus (if we're prepending to it) the length of
632 * the text of the next line. */
633 new_line_len += after_break_len;
634
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000635#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000636 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000637 if (prepending) {
638 /* If we're prepending, the indentation will come from the
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000639 * next line. */
640 indent_string = next_line;
641 indent_len = indent_length(indent_string);
642 next_line += indent_len;
643 } else {
644 /* Otherwise, it will come from this line, in which case
645 * we should increase new_line_len to make room for it. */
646 new_line_len += indent_len;
647 openfile->totsize += mbstrnlen(indent_string, indent_len);
648 }
649 }
650#endif
651
652 /* Now we allocate the new line and copy the text into it. */
653 new_line = charalloc(new_line_len + 1);
654 new_line[0] = '\0';
655
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000656#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000657 if (ISSET(AUTOINDENT)) {
658 /* Copy the indentation. */
659 strncpy(new_line, indent_string, indent_len);
660 new_line[indent_len] = '\0';
661 new_line_len += indent_len;
662 }
663#endif
664
665 /* Copy all the text after the wrap point of the current line. */
666 strcat(new_line, after_break);
667
668 /* Break the current line at the wrap point. */
669 null_at(&line->data, wrap_loc);
670
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000671 if (prepending) {
672 /* If we're prepending, copy the text from the next line, minus
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000673 * the indentation that we already copied above. */
674 strcat(new_line, next_line);
675
676 free(line->next->data);
677 line->next->data = new_line;
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000678
679 /* If the NO_NEWLINES flag isn't set, and text has been added to
680 * the magicline, make a new magicline. */
681 if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0')
682 new_magicline();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000683 } else {
684 /* Otherwise, make a new line and copy the text after where we
685 * broke this line to the beginning of the new line. */
686 splice_node(openfile->current, make_new_node(openfile->current),
687 openfile->current->next);
688
David Lawrence Ramsey219a8142005-11-22 22:08:01 +0000689 /* If the current line is the last line of the file, move the
690 * last line of the file down to the next line. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000691 if (openfile->filebot == openfile->current)
692 openfile->filebot = openfile->current->next;
693
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000694 openfile->current->next->data = new_line;
695
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000696 openfile->totsize++;
697 }
698
699 /* Step 3, clean up. Reposition the cursor and mark, and do some
700 * other sundry things. */
701
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000702 /* Set the prepend_wrap flag, so that later wraps of this line will
703 * be prepended to the next line. */
704 prepend_wrap = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000705
706 /* Each line knows its line number. We recalculate these if we
707 * inserted a new line. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000708 if (!prepending)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000709 renumber(line);
710
711 /* If the cursor was after the break point, we must move it. We
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000712 * also clear the prepend_wrap flag in this case. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000713 if (openfile->current_x > wrap_loc) {
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000714 prepend_wrap = FALSE;
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000715
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000716 openfile->current = openfile->current->next;
717 openfile->current_x -= wrap_loc
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000718#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000719 - indent_len
720#endif
721 ;
722 openfile->placewewant = xplustabs();
723 }
724
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000725#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000726 /* If the mark was on this line after the wrap point, we move it
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000727 * down. If it was on the next line and we prepended to that line,
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000728 * we move it right. */
729 if (openfile->mark_set) {
730 if (openfile->mark_begin == line && openfile->mark_begin_x >
731 wrap_loc) {
732 openfile->mark_begin = line->next;
733 openfile->mark_begin_x -= wrap_loc - indent_len + 1;
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000734 } else if (prepending && openfile->mark_begin == line->next)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000735 openfile->mark_begin_x += after_break_len;
736 }
737#endif
738
739 return TRUE;
740}
741#endif /* !DISABLE_WRAPPING */
742
David Lawrence Ramseyc7c04bb2005-11-29 21:30:00 +0000743#if !defined(DISABLE_HELP) || !defined(DISABLE_WRAPJUSTIFY)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000744/* We are trying to break a chunk off line. We find the last blank such
David Lawrence Ramseycd9a5f02005-09-20 06:12:54 +0000745 * that the display length to there is at most (goal + 1). If there is
746 * no such blank, then we find the first blank. We then take the last
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000747 * blank in that group of blanks. The terminating '\0' counts as a
748 * blank, as does a '\n' if newline is TRUE. */
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000749ssize_t break_line(const char *line, ssize_t goal
750#ifndef DISABLE_HELP
751 , bool newline
752#endif
753 )
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000754{
755 ssize_t blank_loc = -1;
756 /* Current tentative return value. Index of the last blank we
757 * found with short enough display width. */
758 ssize_t cur_loc = 0;
759 /* Current index in line. */
760 int line_len;
761
762 assert(line != NULL);
763
764 while (*line != '\0' && goal >= 0) {
David Lawrence Ramsey95ef3372005-09-20 19:44:19 +0000765 size_t pos = 0;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000766
David Lawrence Ramseyca37ee62005-09-20 17:47:27 +0000767 line_len = parse_mbchar(line, NULL, &pos);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000768
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000769 if (is_blank_mbchar(line)
770#ifndef DISABLE_HELP
771 || (newline && *line == '\n')
772#endif
773 ) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000774 blank_loc = cur_loc;
775
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000776#ifndef DISABLE_HELP
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000777 if (newline && *line == '\n')
778 break;
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000779#endif
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000780 }
781
David Lawrence Ramsey95ef3372005-09-20 19:44:19 +0000782 goal -= pos;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000783 line += line_len;
784 cur_loc += line_len;
785 }
786
787 if (goal >= 0)
788 /* In fact, the whole line displays shorter than goal. */
789 return cur_loc;
790
791 if (blank_loc == -1) {
792 /* No blank was found that was short enough. */
793 bool found_blank = FALSE;
David Lawrence Ramsey5ab12ca2005-09-20 17:52:52 +0000794 ssize_t found_blank_loc = 0;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000795
796 while (*line != '\0') {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000797 line_len = parse_mbchar(line, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000798
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000799 if (is_blank_mbchar(line)
800#ifndef DISABLE_HELP
801 || (newline && *line == '\n')
802#endif
803 ) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000804 if (!found_blank)
805 found_blank = TRUE;
David Lawrence Ramseybdc1b9b2005-09-20 16:36:08 +0000806 found_blank_loc = cur_loc;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000807 } else if (found_blank)
David Lawrence Ramseybdc1b9b2005-09-20 16:36:08 +0000808 return found_blank_loc;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000809
810 line += line_len;
811 cur_loc += line_len;
812 }
813
814 return -1;
815 }
816
817 /* Move to the last blank after blank_loc, if there is one. */
818 line -= cur_loc;
819 line += blank_loc;
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000820 line_len = parse_mbchar(line, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000821 line += line_len;
822
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000823 while (*line != '\0' && (is_blank_mbchar(line)
824#ifndef DISABLE_HELP
825 || (newline && *line == '\n')
826#endif
827 )) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000828 line_len = parse_mbchar(line, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000829
830 line += line_len;
831 blank_loc += line_len;
832 }
833
834 return blank_loc;
835}
David Lawrence Ramseyc7c04bb2005-11-29 21:30:00 +0000836#endif /* !DISABLE_HELP || !DISABLE_WRAPJUSTIFY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000837
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000838#if !defined(NANO_TINY) || !defined(DISABLE_JUSTIFY)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000839/* The "indentation" of a line is the whitespace between the quote part
840 * and the non-whitespace of the line. */
841size_t indent_length(const char *line)
842{
843 size_t len = 0;
844 char *blank_mb;
845 int blank_mb_len;
846
847 assert(line != NULL);
848
849 blank_mb = charalloc(mb_cur_max());
850
851 while (*line != '\0') {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000852 blank_mb_len = parse_mbchar(line, blank_mb, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000853
854 if (!is_blank_mbchar(blank_mb))
855 break;
856
857 line += blank_mb_len;
858 len += blank_mb_len;
859 }
860
861 free(blank_mb);
862
863 return len;
864}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000865#endif /* !NANO_TINY || !DISABLE_JUSTIFY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000866
867#ifndef DISABLE_JUSTIFY
868/* justify_format() replaces blanks with spaces and multiple spaces by 1
869 * (except it maintains up to 2 after a character in punct optionally
870 * followed by a character in brackets, and removes all from the end).
871 *
872 * justify_format() might make paragraph->data shorter, and change the
873 * actual pointer with null_at().
874 *
875 * justify_format() will not look at the first skip characters of
876 * paragraph. skip should be at most strlen(paragraph->data). The
877 * character at paragraph[skip + 1] must not be blank. */
878void justify_format(filestruct *paragraph, size_t skip)
879{
880 char *end, *new_end, *new_paragraph_data;
881 size_t shift = 0;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000882#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000883 size_t mark_shift = 0;
884#endif
885
886 /* These four asserts are assumptions about the input data. */
887 assert(paragraph != NULL);
888 assert(paragraph->data != NULL);
889 assert(skip < strlen(paragraph->data));
890 assert(!is_blank_mbchar(paragraph->data + skip));
891
892 end = paragraph->data + skip;
893 new_paragraph_data = charalloc(strlen(paragraph->data) + 1);
894 strncpy(new_paragraph_data, paragraph->data, skip);
895 new_end = new_paragraph_data + skip;
896
897 while (*end != '\0') {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000898 int end_len;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000899
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000900 /* If this character is blank, change it to a space if
901 * necessary, and skip over all blanks after it. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000902 if (is_blank_mbchar(end)) {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000903 end_len = parse_mbchar(end, NULL, NULL);
904
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000905 *new_end = ' ';
906 new_end++;
907 end += end_len;
908
909 while (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000910 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000911
912 end += end_len;
913 shift += end_len;
914
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000915#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000916 /* Keep track of the change in the current line. */
917 if (openfile->mark_set && openfile->mark_begin ==
918 paragraph && openfile->mark_begin_x >= end -
919 paragraph->data)
920 mark_shift += end_len;
921#endif
922 }
923 /* If this character is punctuation optionally followed by a
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000924 * bracket and then followed by blanks, change no more than two
925 * of the blanks to spaces if necessary, and skip over all
926 * blanks after them. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000927 } else if (mbstrchr(punct, end) != NULL) {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000928 end_len = parse_mbchar(end, NULL, NULL);
929
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000930 while (end_len > 0) {
931 *new_end = *end;
932 new_end++;
933 end++;
934 end_len--;
935 }
936
937 if (*end != '\0' && mbstrchr(brackets, end) != NULL) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000938 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000939
940 while (end_len > 0) {
941 *new_end = *end;
942 new_end++;
943 end++;
944 end_len--;
945 }
946 }
947
948 if (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000949 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000950
951 *new_end = ' ';
952 new_end++;
953 end += end_len;
954 }
955
956 if (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000957 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000958
959 *new_end = ' ';
960 new_end++;
961 end += end_len;
962 }
963
964 while (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000965 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000966
967 end += end_len;
968 shift += end_len;
969
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000970#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000971 /* Keep track of the change in the current line. */
972 if (openfile->mark_set && openfile->mark_begin ==
973 paragraph && openfile->mark_begin_x >= end -
974 paragraph->data)
975 mark_shift += end_len;
976#endif
977 }
978 /* If this character is neither blank nor punctuation, leave it
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000979 * unchanged. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000980 } else {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000981 end_len = parse_mbchar(end, NULL, NULL);
982
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000983 while (end_len > 0) {
984 *new_end = *end;
985 new_end++;
986 end++;
987 end_len--;
988 }
989 }
990 }
991
992 assert(*end == '\0');
993
994 *new_end = *end;
995
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000996 /* If there are spaces at the end of the line, remove them. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000997 while (new_end > new_paragraph_data + skip &&
998 *(new_end - 1) == ' ') {
999 new_end--;
1000 shift++;
1001 }
1002
1003 if (shift > 0) {
1004 openfile->totsize -= shift;
1005 null_at(&new_paragraph_data, new_end - new_paragraph_data);
1006 free(paragraph->data);
1007 paragraph->data = new_paragraph_data;
1008
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001009#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001010 /* Adjust the mark coordinates to compensate for the change in
1011 * the current line. */
1012 if (openfile->mark_set && openfile->mark_begin == paragraph) {
1013 openfile->mark_begin_x -= mark_shift;
1014 if (openfile->mark_begin_x > new_end - new_paragraph_data)
1015 openfile->mark_begin_x = new_end - new_paragraph_data;
1016 }
1017#endif
1018 } else
1019 free(new_paragraph_data);
1020}
1021
1022/* The "quote part" of a line is the largest initial substring matching
1023 * the quote string. This function returns the length of the quote part
1024 * of the given line.
1025 *
1026 * Note that if !HAVE_REGEX_H then we match concatenated copies of
1027 * quotestr. */
1028size_t quote_length(const char *line)
1029{
1030#ifdef HAVE_REGEX_H
1031 regmatch_t matches;
1032 int rc = regexec(&quotereg, line, 1, &matches, 0);
1033
1034 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t)-1)
1035 return 0;
1036 /* matches.rm_so should be 0, since the quote string should start
1037 * with the caret ^. */
1038 return matches.rm_eo;
1039#else /* !HAVE_REGEX_H */
1040 size_t qdepth = 0;
1041
1042 /* Compute quote depth level. */
1043 while (strncmp(line + qdepth, quotestr, quotelen) == 0)
1044 qdepth += quotelen;
1045 return qdepth;
1046#endif /* !HAVE_REGEX_H */
1047}
1048
1049/* a_line and b_line are lines of text. The quotation part of a_line is
1050 * the first a_quote characters. Check that the quotation part of
1051 * b_line is the same. */
1052bool quotes_match(const char *a_line, size_t a_quote, const char
1053 *b_line)
1054{
1055 /* Here is the assumption about a_quote. */
1056 assert(a_quote == quote_length(a_line));
1057
1058 return (a_quote == quote_length(b_line) &&
1059 strncmp(a_line, b_line, a_quote) == 0);
1060}
1061
1062/* We assume a_line and b_line have no quote part. Then, we return
1063 * whether b_line could follow a_line in a paragraph. */
1064bool indents_match(const char *a_line, size_t a_indent, const char
1065 *b_line, size_t b_indent)
1066{
1067 assert(a_indent == indent_length(a_line));
1068 assert(b_indent == indent_length(b_line));
1069
1070 return (b_indent <= a_indent &&
1071 strncmp(a_line, b_line, b_indent) == 0);
1072}
1073
1074/* Is foo the beginning of a paragraph?
1075 *
1076 * A line of text consists of a "quote part", followed by an
1077 * "indentation part", followed by text. The functions quote_length()
1078 * and indent_length() calculate these parts.
1079 *
1080 * A line is "part of a paragraph" if it has a part not in the quote
1081 * part or the indentation.
1082 *
1083 * A line is "the beginning of a paragraph" if it is part of a
1084 * paragraph and
1085 * 1) it is the top line of the file, or
1086 * 2) the line above it is not part of a paragraph, or
1087 * 3) the line above it does not have precisely the same quote
1088 * part, or
1089 * 4) the indentation of this line is not an initial substring of
1090 * the indentation of the previous line, or
1091 * 5) this line has no quote part and some indentation, and
1092 * autoindent isn't turned on.
1093 * The reason for number 5) is that if autoindent isn't turned on,
1094 * then an indented line is expected to start a paragraph, as in
1095 * books. Thus, nano can justify an indented paragraph only if
1096 * autoindent is turned on. */
1097bool begpar(const filestruct *const foo)
1098{
David Lawrence Ramsey0083bd22005-11-09 18:26:44 +00001099 size_t quote_len, indent_len, temp_id_len;
1100
1101 if (foo == NULL)
1102 return FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001103
1104 /* Case 1). */
David Lawrence Ramsey0083bd22005-11-09 18:26:44 +00001105 if (foo == openfile->fileage)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001106 return TRUE;
1107
1108 quote_len = quote_length(foo->data);
1109 indent_len = indent_length(foo->data + quote_len);
1110
1111 /* Not part of a paragraph. */
1112 if (foo->data[quote_len + indent_len] == '\0')
1113 return FALSE;
1114
1115 /* Case 3). */
1116 if (!quotes_match(foo->data, quote_len, foo->prev->data))
1117 return TRUE;
1118
1119 temp_id_len = indent_length(foo->prev->data + quote_len);
1120
1121 /* Case 2) or 5) or 4). */
1122 if (foo->prev->data[quote_len + temp_id_len] == '\0' ||
1123 (quote_len == 0 && indent_len > 0
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001124#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001125 && !ISSET(AUTOINDENT)
1126#endif
1127 ) || !indents_match(foo->prev->data + quote_len, temp_id_len,
1128 foo->data + quote_len, indent_len))
1129 return TRUE;
1130
1131 return FALSE;
1132}
1133
1134/* Is foo inside a paragraph? */
1135bool inpar(const filestruct *const foo)
1136{
1137 size_t quote_len;
1138
1139 if (foo == NULL)
1140 return FALSE;
1141
1142 quote_len = quote_length(foo->data);
1143
David Lawrence Ramsey21014032005-11-09 20:33:42 +00001144 return (foo->data[quote_len + indent_length(foo->data +
1145 quote_len)] != '\0');
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001146}
1147
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00001148/* Move the next par_len lines, starting with first_line, into the
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00001149 * justify buffer, leaving copies of those lines in place. Assume that
1150 * par_len is greater than zero, and that there are enough lines after
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00001151 * first_line. */
1152void backup_lines(filestruct *first_line, size_t par_len)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001153{
1154 filestruct *top = first_line;
1155 /* The top of the paragraph we're backing up. */
1156 filestruct *bot = first_line;
1157 /* The bottom of the paragraph we're backing up. */
1158 size_t i;
1159 /* Generic loop variable. */
1160 size_t current_x_save = openfile->current_x;
1161 ssize_t fl_lineno_save = first_line->lineno;
1162 ssize_t edittop_lineno_save = openfile->edittop->lineno;
1163 ssize_t current_lineno_save = openfile->current->lineno;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001164#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001165 bool old_mark_set = openfile->mark_set;
1166 ssize_t mb_lineno_save = 0;
1167 size_t mark_begin_x_save = 0;
1168
1169 if (old_mark_set) {
1170 mb_lineno_save = openfile->mark_begin->lineno;
1171 mark_begin_x_save = openfile->mark_begin_x;
1172 }
1173#endif
1174
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001175 /* par_len will be one greater than the number of lines between
1176 * current and filebot if filebot is the last line in the
1177 * paragraph. */
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00001178 assert(par_len > 0 && openfile->current->lineno + par_len <=
David Lawrence Ramsey24777c02005-12-01 05:49:08 +00001179 openfile->filebot->lineno + 1);
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00001180
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001181 /* Move bot down par_len lines to the line after the last line of
1182 * the paragraph, if there is one. */
1183 for (i = par_len; i > 0 && bot != openfile->filebot; i--)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001184 bot = bot->next;
1185
1186 /* Move the paragraph from the current buffer's filestruct to the
1187 * justify buffer. */
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001188 move_to_filestruct(&jusbuffer, &jusbottom, top, 0, bot,
David Lawrence Ramseyf0575cf2005-11-09 23:27:51 +00001189 (i == 1 && bot == openfile->filebot) ? strlen(bot->data) : 0);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001190
1191 /* Copy the paragraph back to the current buffer's filestruct from
1192 * the justify buffer. */
1193 copy_from_filestruct(jusbuffer, jusbottom);
1194
1195 /* Move upward from the last line of the paragraph to the first
1196 * line, putting first_line, edittop, current, and mark_begin at the
1197 * same lines in the copied paragraph that they had in the original
1198 * paragraph. */
David Lawrence Ramsey5d6f1272005-11-10 03:32:59 +00001199 if (openfile->current != openfile->fileage)
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001200 top = openfile->current->prev;
1201 else
1202 top = openfile->current;
David Lawrence Ramseye8d505b2005-11-10 03:40:45 +00001203 for (i = par_len; i > 0 && top != NULL; i--) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001204 if (top->lineno == fl_lineno_save)
1205 first_line = top;
1206 if (top->lineno == edittop_lineno_save)
1207 openfile->edittop = top;
1208 if (top->lineno == current_lineno_save)
1209 openfile->current = top;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001210#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001211 if (old_mark_set && top->lineno == mb_lineno_save) {
1212 openfile->mark_begin = top;
1213 openfile->mark_begin_x = mark_begin_x_save;
1214 }
1215#endif
1216 top = top->prev;
1217 }
1218
1219 /* Put current_x at the same place in the copied paragraph that it
1220 * had in the original paragraph. */
1221 openfile->current_x = current_x_save;
1222
1223 set_modified();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001224}
1225
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001226/* Find the beginning of the current paragraph if we're in one, or the
1227 * beginning of the next paragraph if we're not. Afterwards, save the
1228 * quote length and paragraph length in *quote and *par. Return TRUE if
1229 * we found a paragraph, or FALSE if there was an error or we didn't
1230 * find a paragraph.
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001231 *
1232 * See the comment at begpar() for more about when a line is the
1233 * beginning of a paragraph. */
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001234bool find_paragraph(size_t *const quote, size_t *const par)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001235{
1236 size_t quote_len;
1237 /* Length of the initial quotation of the paragraph we search
1238 * for. */
1239 size_t par_len;
1240 /* Number of lines in the paragraph we search for. */
1241 filestruct *current_save;
1242 /* The line at the beginning of the paragraph we search for. */
1243 ssize_t current_y_save;
1244 /* The y-coordinate at the beginning of the paragraph we search
1245 * for. */
1246
1247#ifdef HAVE_REGEX_H
1248 if (quoterc != 0) {
1249 statusbar(_("Bad quote string %s: %s"), quotestr, quoteerr);
1250 return FALSE;
1251 }
1252#endif
1253
1254 assert(openfile->current != NULL);
1255
David Lawrence Ramsey1be131a2005-11-11 03:55:52 +00001256 /* If we're at the end of the last line of the file, it means that
1257 * there aren't any paragraphs left, so get out. */
1258 if (openfile->current == openfile->filebot && openfile->current_x ==
1259 strlen(openfile->filebot->data))
1260 return FALSE;
1261
1262 /* If the current line isn't in a paragraph, move forward to the
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001263 * last line of the next paragraph, if any. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001264 if (!inpar(openfile->current)) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001265 do_para_end(FALSE);
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00001266
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001267 /* If we end up past the beginning of the line, it means that
1268 * we're at the end of the last line of the file, and the line
1269 * isn't blank, in which case the last line of the file is the
1270 * last line of the next paragraph.
1271 *
1272 * Otherwise, if we end up on a line that's in a paragraph, it
1273 * means that we're on the line after the last line of the next
1274 * paragraph, in which case we should move back to the last line
1275 * of the next paragraph. */
1276 if (openfile->current_x == 0) {
1277 if (!inpar(openfile->current->prev))
1278 return FALSE;
1279 if (openfile->current != openfile->fileage)
1280 openfile->current = openfile->current->prev;
1281 }
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001282 }
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00001283
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001284 /* If the current line isn't the first line of the paragraph, move
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001285 * back to the first line of the paragraph. */
1286 if (!begpar(openfile->current))
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001287 do_para_begin(FALSE);
1288
1289 /* Now current is the first line of the paragraph. Set quote_len to
1290 * the quotation length of that line, and set par_len to the number
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001291 * of lines in this paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001292 quote_len = quote_length(openfile->current->data);
1293 current_save = openfile->current;
1294 current_y_save = openfile->current_y;
1295 do_para_end(FALSE);
1296 par_len = openfile->current->lineno - current_save->lineno;
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00001297
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001298 /* If we end up past the beginning of the line, it means that we're
1299 * at the end of the last line of the file, and the line isn't
1300 * blank, in which case the last line of the file is part of the
1301 * paragraph. */
David Lawrence Ramseybdff6652005-11-11 04:14:33 +00001302 if (openfile->current_x > 0)
1303 par_len++;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001304 openfile->current = current_save;
1305 openfile->current_y = current_y_save;
1306
1307 /* Save the values of quote_len and par_len. */
1308 assert(quote != NULL && par != NULL);
1309
1310 *quote = quote_len;
1311 *par = par_len;
1312
1313 return TRUE;
1314}
1315
1316/* If full_justify is TRUE, justify the entire file. Otherwise, justify
1317 * the current paragraph. */
1318void do_justify(bool full_justify)
1319{
1320 filestruct *first_par_line = NULL;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001321 /* Will be the first line of the justified paragraph(s), if any.
1322 * For restoring after unjustify. */
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001323 filestruct *last_par_line = NULL;
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001324 /* Will be the line after the last line of the justified
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001325 * paragraph(s), if any. Also for restoring after unjustify. */
David Lawrence Ramsey82b5deb2005-11-10 06:07:57 +00001326 bool filebot_inpar = FALSE;
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001327 /* Whether the text at filebot is part of the current
1328 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001329
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00001330 /* We save these variables to be restored if the user
1331 * unjustifies. */
David Lawrence Ramsey52161ee2005-11-10 19:56:26 +00001332 filestruct *edittop_save = openfile->edittop;
1333 filestruct *current_save = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001334 size_t current_x_save = openfile->current_x;
1335 size_t pww_save = openfile->placewewant;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001336 size_t totsize_save = openfile->totsize;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001337#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001338 filestruct *mark_begin_save = openfile->mark_begin;
1339 size_t mark_begin_x_save = openfile->mark_begin_x;
1340#endif
David Lawrence Ramsey52161ee2005-11-10 19:56:26 +00001341 bool modified_save = openfile->modified;
1342
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001343 int kbinput;
1344 bool meta_key, func_key, s_or_t, ran_func, finished;
1345
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001346 /* Move to the beginning of the current line, so that justifying at
David Lawrence Ramseybdff6652005-11-11 04:14:33 +00001347 * the end of the last line of the file, if that line isn't blank,
1348 * will work the first time through. */
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001349 openfile->current_x = 0;
1350
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001351 /* If we're justifying the entire file, start at the beginning. */
1352 if (full_justify)
1353 openfile->current = openfile->fileage;
1354
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001355 while (TRUE) {
1356 size_t i;
1357 /* Generic loop variable. */
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001358 filestruct *curr_first_par_line;
1359 /* The first line of the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001360 size_t quote_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001361 /* Length of the initial quotation of the current
1362 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001363 size_t indent_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001364 /* Length of the initial indentation of the current
1365 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001366 size_t par_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001367 /* Number of lines in the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001368 ssize_t break_pos;
1369 /* Where we will break lines. */
1370 char *indent_string;
1371 /* The first indentation that doesn't match the initial
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001372 * indentation of the current paragraph. This is put at the
1373 * beginning of every line broken off the first justified
1374 * line of the paragraph. Note that this works because a
1375 * paragraph can only contain two indentations at most: the
1376 * initial one, and a different one starting on a line after
1377 * the first. See the comment at begpar() for more about
1378 * when a line is part of a paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001379
1380 /* Find the first line of the paragraph to be justified. That
1381 * is the start of this paragraph if we're in one, or the start
1382 * of the next otherwise. Save the quote length and paragraph
1383 * length (number of lines). Don't refresh the screen yet,
1384 * since we'll do that after we justify.
1385 *
1386 * If the search failed, we do one of two things. If we're
David Lawrence Ramsey8b203d62005-11-11 03:17:44 +00001387 * justifying the whole file, and we've found at least one
1388 * paragraph, it means that we should justify all the way to the
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001389 * last line of the file, so set the last line of the text to be
1390 * justified to the last line of the file and break out of the
1391 * loop. Otherwise, it means that there are no paragraph(s) to
1392 * justify, so refresh the screen and get out. */
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001393 if (!find_paragraph(&quote_len, &par_len)) {
David Lawrence Ramsey8b203d62005-11-11 03:17:44 +00001394 if (full_justify && first_par_line != NULL) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001395 last_par_line = openfile->filebot;
1396 break;
1397 } else {
1398 edit_refresh();
1399 return;
1400 }
1401 }
1402
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001403 /* par_len will be one greater than the number of lines between
1404 * current and filebot if filebot is the last line in the
1405 * paragraph. Set filebot_inpar to TRUE if this is the case. */
1406 filebot_inpar = (openfile->current->lineno + par_len ==
1407 openfile->filebot->lineno + 1);
1408
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00001409 /* If we haven't already done it, move the original paragraph(s)
1410 * to the justify buffer, splice a copy of the original
1411 * paragraph(s) into the file in the same place, and set
1412 * first_par_line to the first line of the copy. */
1413 if (first_par_line == NULL) {
1414 backup_lines(openfile->current, full_justify ?
David Lawrence Ramsey53f641f2005-11-10 21:57:56 +00001415 openfile->filebot->lineno - openfile->current->lineno +
1416 ((openfile->filebot->data[0] != '\0') ? 1 : 0) :
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00001417 par_len);
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00001418 first_par_line = openfile->current;
1419 }
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001420
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001421 /* Set curr_first_par_line to the first line of the current
1422 * paragraph. */
1423 curr_first_par_line = openfile->current;
1424
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001425 /* Initialize indent_string to a blank string. */
1426 indent_string = mallocstrcpy(NULL, "");
1427
1428 /* Find the first indentation in the paragraph that doesn't
1429 * match the indentation of the first line, and save it in
1430 * indent_string. If all the indentations are the same, save
1431 * the indentation of the first line in indent_string. */
1432 {
1433 const filestruct *indent_line = openfile->current;
1434 bool past_first_line = FALSE;
1435
1436 for (i = 0; i < par_len; i++) {
1437 indent_len = quote_len +
1438 indent_length(indent_line->data + quote_len);
1439
1440 if (indent_len != strlen(indent_string)) {
1441 indent_string = mallocstrncpy(indent_string,
1442 indent_line->data, indent_len + 1);
1443 indent_string[indent_len] = '\0';
1444
1445 if (past_first_line)
1446 break;
1447 }
1448
1449 if (indent_line == openfile->current)
1450 past_first_line = TRUE;
1451
1452 indent_line = indent_line->next;
1453 }
1454 }
1455
1456 /* Now tack all the lines of the paragraph together, skipping
1457 * the quoting and indentation on all lines after the first. */
1458 for (i = 0; i < par_len - 1; i++) {
1459 filestruct *next_line = openfile->current->next;
1460 size_t line_len = strlen(openfile->current->data);
1461 size_t next_line_len =
1462 strlen(openfile->current->next->data);
1463
1464 indent_len = quote_len +
1465 indent_length(openfile->current->next->data +
1466 quote_len);
1467
1468 next_line_len -= indent_len;
1469 openfile->totsize -= indent_len;
1470
1471 /* We're just about to tack the next line onto this one. If
1472 * this line isn't empty, make sure it ends in a space. */
1473 if (line_len > 0 &&
1474 openfile->current->data[line_len - 1] != ' ') {
1475 line_len++;
1476 openfile->current->data =
1477 charealloc(openfile->current->data,
1478 line_len + 1);
1479 openfile->current->data[line_len - 1] = ' ';
1480 openfile->current->data[line_len] = '\0';
1481 openfile->totsize++;
1482 }
1483
1484 openfile->current->data =
1485 charealloc(openfile->current->data, line_len +
1486 next_line_len + 1);
1487 strcat(openfile->current->data, next_line->data +
1488 indent_len);
1489
David Lawrence Ramsey9bedc4b2005-11-09 19:51:48 +00001490 /* Don't destroy edittop or filebot! */
David Lawrence Ramsey32bd29e2005-11-09 03:44:23 +00001491 if (next_line == openfile->edittop)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001492 openfile->edittop = openfile->current;
David Lawrence Ramsey9bedc4b2005-11-09 19:51:48 +00001493 if (next_line == openfile->filebot)
1494 openfile->filebot = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001495
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001496#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001497 /* Adjust the mark coordinates to compensate for the change
1498 * in the next line. */
1499 if (openfile->mark_set && openfile->mark_begin ==
1500 next_line) {
1501 openfile->mark_begin = openfile->current;
1502 openfile->mark_begin_x += line_len - indent_len;
1503 }
1504#endif
1505
1506 unlink_node(next_line);
1507 delete_node(next_line);
1508
1509 /* If we've removed the next line, we need to go through
1510 * this line again. */
1511 i--;
1512
1513 par_len--;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001514 openfile->totsize--;
1515 }
1516
1517 /* Call justify_format() on the paragraph, which will remove
1518 * excess spaces from it and change all blank characters to
1519 * spaces. */
1520 justify_format(openfile->current, quote_len +
1521 indent_length(openfile->current->data + quote_len));
1522
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001523 while (par_len > 0 && strlenpt(openfile->current->data) >
1524 fill) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001525 size_t line_len = strlen(openfile->current->data);
1526
1527 indent_len = strlen(indent_string);
1528
1529 /* If this line is too long, try to wrap it to the next line
1530 * to make it short enough. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001531 break_pos = break_line(openfile->current->data + indent_len,
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001532 fill - strnlenpt(openfile->current->data, indent_len)
1533#ifndef DISABLE_HELP
1534 , FALSE
1535#endif
1536 );
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001537
1538 /* We can't break the line, or don't need to, so get out. */
1539 if (break_pos == -1 || break_pos + indent_len == line_len)
1540 break;
1541
1542 /* Move forward to the character after the indentation and
1543 * just after the space. */
1544 break_pos += indent_len + 1;
1545
1546 assert(break_pos <= line_len);
1547
1548 /* Make a new line, and copy the text after where we're
1549 * going to break this line to the beginning of the new
1550 * line. */
1551 splice_node(openfile->current,
1552 make_new_node(openfile->current),
1553 openfile->current->next);
1554
1555 /* If this paragraph is non-quoted, and autoindent isn't
1556 * turned on, set the indentation length to zero so that the
1557 * indentation is treated as part of the line. */
1558 if (quote_len == 0
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001559#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001560 && !ISSET(AUTOINDENT)
1561#endif
1562 )
1563 indent_len = 0;
1564
1565 /* Copy the text after where we're going to break the
1566 * current line to the next line. */
1567 openfile->current->next->data = charalloc(indent_len + 1 +
1568 line_len - break_pos);
1569 strncpy(openfile->current->next->data, indent_string,
1570 indent_len);
1571 strcpy(openfile->current->next->data + indent_len,
1572 openfile->current->data + break_pos);
1573
1574 par_len++;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001575 openfile->totsize += indent_len + 1;
1576
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001577#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001578 /* Adjust the mark coordinates to compensate for the change
1579 * in the current line. */
1580 if (openfile->mark_set && openfile->mark_begin ==
1581 openfile->current && openfile->mark_begin_x >
1582 break_pos) {
1583 openfile->mark_begin = openfile->current->next;
1584 openfile->mark_begin_x -= break_pos - indent_len;
1585 }
1586#endif
1587
1588 /* Break the current line. */
1589 null_at(&openfile->current->data, break_pos);
1590
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001591 /* If the current line is the last line of the file, move
David Lawrence Ramseyb885c9c2005-11-10 05:20:25 +00001592 * the last line of the file down to the next line. */
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001593 if (openfile->filebot == openfile->current)
1594 openfile->filebot = openfile->filebot->next;
1595
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001596 /* Go to the next line. */
1597 par_len--;
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001598 openfile->current_y++;
1599 openfile->current = openfile->current->next;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001600 }
1601
1602 /* We're done breaking lines, so we don't need indent_string
1603 * anymore. */
1604 free(indent_string);
1605
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001606 /* Go to the next line, if possible. If there is no next line,
1607 * move to the end of the current line. */
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001608 if (openfile->current != openfile->filebot) {
1609 openfile->current_y++;
1610 openfile->current = openfile->current->next;
1611 } else
1612 openfile->current_x = strlen(openfile->current->data);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001613
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001614 /* Renumber the lines of the now-justified current paragraph,
1615 * since both find_paragraph() and edit_refresh() need the line
1616 * numbers to be right. */
1617 renumber(curr_first_par_line);
David Lawrence Ramseyad1b64c2005-11-29 19:00:09 +00001618
1619 /* We've just finished justifying the paragraph. If we're not
1620 * justifying the entire file, break out of the loop.
1621 * Otherwise, continue the loop so that we justify all the
1622 * paragraphs in the file. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001623 if (!full_justify)
1624 break;
1625 }
1626
1627 /* We are now done justifying the paragraph or the file, so clean
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001628 * up. current_y and totsize have been maintained above. If we
David Lawrence Ramseyad1b64c2005-11-29 19:00:09 +00001629 * actually justified something, set last_par_line to the new end of
1630 * the paragraph. */
1631 if (first_par_line != NULL)
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001632 last_par_line = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001633
1634 edit_refresh();
1635
1636 statusbar(_("Can now UnJustify!"));
1637
1638 /* If constant cursor position display is on, make sure the current
1639 * cursor position will be properly displayed on the statusbar. */
1640 if (ISSET(CONST_UPDATE))
1641 do_cursorpos(TRUE);
1642
1643 /* Display the shortcut list with UnJustify. */
1644 shortcut_init(TRUE);
1645 display_main_list();
1646
1647 /* Now get a keystroke and see if it's unjustify. If not, put back
1648 * the keystroke and return. */
1649 kbinput = do_input(&meta_key, &func_key, &s_or_t, &ran_func,
1650 &finished, FALSE);
1651
1652 if (!meta_key && !func_key && s_or_t &&
1653 kbinput == NANO_UNJUSTIFY_KEY) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001654 /* Splice the justify buffer back into the file, but only if we
1655 * actually justified something. */
1656 if (first_par_line != NULL) {
1657 filestruct *top_save;
1658
1659 /* Partition the filestruct so that it contains only the
1660 * text of the justified paragraph. */
1661 filepart = partition_filestruct(first_par_line, 0,
David Lawrence Ramseyccd1b7b2005-11-18 20:21:48 +00001662 last_par_line, filebot_inpar ?
1663 strlen(last_par_line->data) : 0);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001664
1665 /* Remove the text of the justified paragraph, and
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00001666 * replace it with the text in the justify buffer. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001667 free_filestruct(openfile->fileage);
1668 openfile->fileage = jusbuffer;
1669 openfile->filebot = jusbottom;
1670
1671 top_save = openfile->fileage;
1672
1673 /* Unpartition the filestruct so that it contains all the
1674 * text again. Note that the justified paragraph has been
1675 * replaced with the unjustified paragraph. */
1676 unpartition_filestruct(&filepart);
1677
1678 /* Renumber starting with the beginning line of the old
1679 * partition. */
1680 renumber(top_save);
1681
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001682 /* Restore the justify we just did (ungrateful user!). */
1683 openfile->edittop = edittop_save;
1684 openfile->current = current_save;
1685 openfile->current_x = current_x_save;
1686 openfile->placewewant = pww_save;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001687 openfile->totsize = totsize_save;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001688#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001689 if (openfile->mark_set) {
1690 openfile->mark_begin = mark_begin_save;
1691 openfile->mark_begin_x = mark_begin_x_save;
1692 }
1693#endif
1694 openfile->modified = modified_save;
1695
1696 /* Clear the justify buffer. */
1697 jusbuffer = NULL;
1698
1699 if (!openfile->modified)
1700 titlebar(NULL);
1701 edit_refresh();
1702 }
1703 } else {
1704 unget_kbinput(kbinput, meta_key, func_key);
1705
1706 /* Blow away the text in the justify buffer. */
1707 free_filestruct(jusbuffer);
1708 jusbuffer = NULL;
1709 }
1710
1711 blank_statusbar();
1712
1713 /* Display the shortcut list with UnCut. */
1714 shortcut_init(FALSE);
1715 display_main_list();
1716}
1717
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001718/* Justify the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001719void do_justify_void(void)
1720{
1721 do_justify(FALSE);
1722}
1723
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001724/* Justify the entire file. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001725void do_full_justify(void)
1726{
1727 do_justify(TRUE);
1728}
1729#endif /* !DISABLE_JUSTIFY */
1730
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001731#ifndef DISABLE_SPELLER
1732/* A word is misspelled in the file. Let the user replace it. We
1733 * return FALSE if the user cancels. */
1734bool do_int_spell_fix(const char *word)
1735{
1736 char *save_search, *save_replace;
1737 size_t match_len, current_x_save = openfile->current_x;
1738 size_t pww_save = openfile->placewewant;
1739 filestruct *edittop_save = openfile->edittop;
1740 filestruct *current_save = openfile->current;
1741 /* Save where we are. */
1742 bool canceled = FALSE;
1743 /* The return value. */
1744 bool case_sens_set = ISSET(CASE_SENSITIVE);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001745#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001746 bool backwards_search_set = ISSET(BACKWARDS_SEARCH);
1747#endif
1748#ifdef HAVE_REGEX_H
1749 bool regexp_set = ISSET(USE_REGEXP);
1750#endif
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001751#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001752 bool old_mark_set = openfile->mark_set;
1753 bool added_magicline = FALSE;
1754 /* Whether we added a magicline after filebot. */
1755 bool right_side_up = FALSE;
1756 /* TRUE if (mark_begin, mark_begin_x) is the top of the mark,
1757 * FALSE if (current, current_x) is. */
1758 filestruct *top, *bot;
1759 size_t top_x, bot_x;
1760#endif
1761
1762 /* Make sure spell-check is case sensitive. */
1763 SET(CASE_SENSITIVE);
1764
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001765#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001766 /* Make sure spell-check goes forward only. */
1767 UNSET(BACKWARDS_SEARCH);
1768#endif
1769#ifdef HAVE_REGEX_H
1770 /* Make sure spell-check doesn't use regular expressions. */
1771 UNSET(USE_REGEXP);
1772#endif
1773
1774 /* Save the current search/replace strings. */
1775 search_init_globals();
1776 save_search = last_search;
1777 save_replace = last_replace;
1778
1779 /* Set the search/replace strings to the misspelled word. */
1780 last_search = mallocstrcpy(NULL, word);
1781 last_replace = mallocstrcpy(NULL, word);
1782
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001783#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001784 if (old_mark_set) {
1785 /* If the mark is on, partition the filestruct so that it
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00001786 * contains only the marked text; if the NO_NEWLINES flag isn't
1787 * set, keep track of whether the text will have a magicline
1788 * added when we're done correcting misspelled words; and
1789 * turn the mark off. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001790 mark_order((const filestruct **)&top, &top_x,
1791 (const filestruct **)&bot, &bot_x, &right_side_up);
1792 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00001793 if (!ISSET(NO_NEWLINES))
1794 added_magicline = (openfile->filebot->data[0] != '\0');
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001795 openfile->mark_set = FALSE;
1796 }
1797#endif
1798
1799 /* Start from the top of the file. */
1800 openfile->edittop = openfile->fileage;
1801 openfile->current = openfile->fileage;
1802 openfile->current_x = (size_t)-1;
1803 openfile->placewewant = 0;
1804
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00001805 /* Find the first whole occurrence of word. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001806 findnextstr_wrap_reset();
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00001807 while (findnextstr(TRUE, FALSE, openfile->fileage, 0, word,
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001808 &match_len)) {
1809 if (is_whole_word(openfile->current_x, openfile->current->data,
1810 word)) {
1811 size_t xpt = xplustabs();
1812 char *exp_word = display_string(openfile->current->data,
1813 xpt, strnlenpt(openfile->current->data,
1814 openfile->current_x + match_len) - xpt, FALSE);
1815
1816 edit_refresh();
1817
1818 do_replace_highlight(TRUE, exp_word);
1819
1820 /* Allow all instances of the word to be corrected. */
David Lawrence Ramsey9d8c2842006-02-07 21:11:05 +00001821 canceled = (do_prompt(FALSE,
1822#ifndef DISABLE_TABCOMP
1823 TRUE,
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001824#endif
David Lawrence Ramsey9d8c2842006-02-07 21:11:05 +00001825 spell_list, word,
1826#ifndef NANO_TINY
1827 NULL,
1828#endif
David Lawrence Ramsey68160072006-02-18 21:32:29 +00001829 edit_refresh, _("Edit a replacement")) == -1);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001830
1831 do_replace_highlight(FALSE, exp_word);
1832
1833 free(exp_word);
1834
1835 if (!canceled && strcmp(word, answer) != 0) {
1836 openfile->current_x--;
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00001837 do_replace_loop(TRUE, &canceled, openfile->current,
1838 &openfile->current_x, word);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001839 }
1840
1841 break;
1842 }
1843 }
1844
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001845#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001846 if (old_mark_set) {
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00001847 /* If the mark was on, the NO_NEWLINES flag isn't set, and we
1848 * added a magicline, remove it now. */
1849 if (!ISSET(NO_NEWLINES) && added_magicline)
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001850 remove_magicline();
1851
1852 /* Put the beginning and the end of the mark at the beginning
1853 * and the end of the spell-checked text. */
1854 if (openfile->fileage == openfile->filebot)
1855 bot_x += top_x;
1856 if (right_side_up) {
1857 openfile->mark_begin_x = top_x;
1858 current_x_save = bot_x;
1859 } else {
1860 current_x_save = top_x;
1861 openfile->mark_begin_x = bot_x;
1862 }
1863
1864 /* Unpartition the filestruct so that it contains all the text
1865 * again, and turn the mark back on. */
1866 unpartition_filestruct(&filepart);
1867 openfile->mark_set = TRUE;
1868 }
1869#endif
1870
1871 /* Restore the search/replace strings. */
1872 free(last_search);
1873 last_search = save_search;
1874 free(last_replace);
1875 last_replace = save_replace;
1876
1877 /* Restore where we were. */
1878 openfile->edittop = edittop_save;
1879 openfile->current = current_save;
1880 openfile->current_x = current_x_save;
1881 openfile->placewewant = pww_save;
1882
1883 /* Restore case sensitivity setting. */
1884 if (!case_sens_set)
1885 UNSET(CASE_SENSITIVE);
1886
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001887#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001888 /* Restore search/replace direction. */
1889 if (backwards_search_set)
1890 SET(BACKWARDS_SEARCH);
1891#endif
1892#ifdef HAVE_REGEX_H
1893 /* Restore regular expression usage setting. */
1894 if (regexp_set)
1895 SET(USE_REGEXP);
1896#endif
1897
1898 return !canceled;
1899}
1900
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001901/* Internal (integrated) spell checking using the spell program,
1902 * filtered through the sort and uniq programs. Return NULL for normal
1903 * termination, and the error string otherwise. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001904const char *do_int_speller(const char *tempfile_name)
1905{
1906 char *read_buff, *read_buff_ptr, *read_buff_word;
1907 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
1908 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
1909 pid_t pid_spell, pid_sort, pid_uniq;
1910 int spell_status, sort_status, uniq_status;
1911
1912 /* Create all three pipes up front. */
1913 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 ||
1914 pipe(uniq_fd) == -1)
1915 return _("Could not create pipe");
1916
1917 statusbar(_("Creating misspelled word list, please wait..."));
1918
1919 /* A new process to run spell in. */
1920 if ((pid_spell = fork()) == 0) {
1921 /* Child continues (i.e, future spell process). */
1922 close(spell_fd[0]);
1923
1924 /* Replace the standard input with the temp file. */
1925 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1926 goto close_pipes_and_exit;
1927
1928 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1929 goto close_pipes_and_exit;
1930
1931 close(tempfile_fd);
1932
1933 /* Send spell's standard output to the pipe. */
1934 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1935 goto close_pipes_and_exit;
1936
1937 close(spell_fd[1]);
1938
David Lawrence Ramsey3239ff22005-11-29 20:01:06 +00001939 /* Start the spell program; we are using $PATH. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001940 execlp("spell", "spell", NULL);
1941
1942 /* This should not be reached if spell is found. */
1943 exit(1);
1944 }
1945
1946 /* Parent continues here. */
1947 close(spell_fd[1]);
1948
1949 /* A new process to run sort in. */
1950 if ((pid_sort = fork()) == 0) {
1951 /* Child continues (i.e, future spell process). Replace the
1952 * standard input with the standard output of the old pipe. */
1953 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1954 goto close_pipes_and_exit;
1955
1956 close(spell_fd[0]);
1957
1958 /* Send sort's standard output to the new pipe. */
1959 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1960 goto close_pipes_and_exit;
1961
1962 close(sort_fd[1]);
1963
1964 /* Start the sort program. Use -f to remove mixed case. If
1965 * this isn't portable, let me know. */
1966 execlp("sort", "sort", "-f", NULL);
1967
1968 /* This should not be reached if sort is found. */
1969 exit(1);
1970 }
1971
1972 close(spell_fd[0]);
1973 close(sort_fd[1]);
1974
1975 /* A new process to run uniq in. */
1976 if ((pid_uniq = fork()) == 0) {
1977 /* Child continues (i.e, future uniq process). Replace the
1978 * standard input with the standard output of the old pipe. */
1979 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1980 goto close_pipes_and_exit;
1981
1982 close(sort_fd[0]);
1983
1984 /* Send uniq's standard output to the new pipe. */
1985 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1986 goto close_pipes_and_exit;
1987
1988 close(uniq_fd[1]);
1989
1990 /* Start the uniq program; we are using PATH. */
1991 execlp("uniq", "uniq", NULL);
1992
1993 /* This should not be reached if uniq is found. */
1994 exit(1);
1995 }
1996
1997 close(sort_fd[0]);
1998 close(uniq_fd[1]);
1999
2000 /* The child process was not forked successfully. */
2001 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
2002 close(uniq_fd[0]);
2003 return _("Could not fork");
2004 }
2005
2006 /* Get the system pipe buffer size. */
2007 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
2008 close(uniq_fd[0]);
2009 return _("Could not get size of pipe buffer");
2010 }
2011
2012 /* Read in the returned spelling errors. */
2013 read_buff_read = 0;
2014 read_buff_size = pipe_buff_size + 1;
2015 read_buff = read_buff_ptr = charalloc(read_buff_size);
2016
2017 while ((bytesread = read(uniq_fd[0], read_buff_ptr,
2018 pipe_buff_size)) > 0) {
2019 read_buff_read += bytesread;
2020 read_buff_size += pipe_buff_size;
2021 read_buff = read_buff_ptr = charealloc(read_buff,
2022 read_buff_size);
2023 read_buff_ptr += read_buff_read;
2024 }
2025
2026 *read_buff_ptr = '\0';
2027 close(uniq_fd[0]);
2028
2029 /* Process the spelling errors. */
2030 read_buff_word = read_buff_ptr = read_buff;
2031
2032 while (*read_buff_ptr != '\0') {
2033 if ((*read_buff_ptr == '\r') || (*read_buff_ptr == '\n')) {
2034 *read_buff_ptr = '\0';
2035 if (read_buff_word != read_buff_ptr) {
2036 if (!do_int_spell_fix(read_buff_word)) {
2037 read_buff_word = read_buff_ptr;
2038 break;
2039 }
2040 }
2041 read_buff_word = read_buff_ptr + 1;
2042 }
2043 read_buff_ptr++;
2044 }
2045
2046 /* Special case: the last word doesn't end with '\r' or '\n'. */
2047 if (read_buff_word != read_buff_ptr)
2048 do_int_spell_fix(read_buff_word);
2049
2050 free(read_buff);
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002051 search_replace_abort();
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002052 edit_refresh();
2053
2054 /* Process the end of the spell process. */
2055 waitpid(pid_spell, &spell_status, 0);
2056 waitpid(pid_sort, &sort_status, 0);
2057 waitpid(pid_uniq, &uniq_status, 0);
2058
2059 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
2060 return _("Error invoking \"spell\"");
2061
2062 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
2063 return _("Error invoking \"sort -f\"");
2064
2065 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
2066 return _("Error invoking \"uniq\"");
2067
2068 /* Otherwise... */
2069 return NULL;
2070
2071 close_pipes_and_exit:
2072 /* Don't leak any handles. */
2073 close(tempfile_fd);
2074 close(spell_fd[0]);
2075 close(spell_fd[1]);
2076 close(sort_fd[0]);
2077 close(sort_fd[1]);
2078 close(uniq_fd[0]);
2079 close(uniq_fd[1]);
2080 exit(1);
2081}
2082
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002083/* External (alternate) spell checking. Return NULL for normal
2084 * termination, and the error string otherwise. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002085const char *do_alt_speller(char *tempfile_name)
2086{
2087 int alt_spell_status;
2088 size_t current_x_save = openfile->current_x;
2089 size_t pww_save = openfile->placewewant;
2090 ssize_t current_y_save = openfile->current_y;
2091 ssize_t lineno_save = openfile->current->lineno;
2092 pid_t pid_spell;
2093 char *ptr;
2094 static int arglen = 3;
2095 static char **spellargs = NULL;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002096#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002097 bool old_mark_set = openfile->mark_set;
2098 bool added_magicline = FALSE;
2099 /* Whether we added a magicline after filebot. */
2100 bool right_side_up = FALSE;
2101 /* TRUE if (mark_begin, mark_begin_x) is the top of the mark,
2102 * FALSE if (current, current_x) is. */
2103 filestruct *top, *bot;
2104 size_t top_x, bot_x;
2105 ssize_t mb_lineno_save = 0;
2106 /* We're going to close the current file, and open the output of
2107 * the alternate spell command. The line that mark_begin points
2108 * to will be freed, so we save the line number and restore it
2109 * afterwards. */
2110 size_t totsize_save = openfile->totsize;
2111 /* Our saved value of totsize, used when we spell-check a marked
2112 * selection. */
2113
2114 if (old_mark_set) {
2115 /* If the mark is on, save the number of the line it starts on,
2116 * and then turn the mark off. */
2117 mb_lineno_save = openfile->mark_begin->lineno;
2118 openfile->mark_set = FALSE;
2119 }
2120#endif
2121
2122 endwin();
2123
2124 /* Set up an argument list to pass execvp(). */
2125 if (spellargs == NULL) {
2126 spellargs = (char **)nmalloc(arglen * sizeof(char *));
2127
2128 spellargs[0] = strtok(alt_speller, " ");
2129 while ((ptr = strtok(NULL, " ")) != NULL) {
2130 arglen++;
2131 spellargs = (char **)nrealloc(spellargs, arglen *
2132 sizeof(char *));
2133 spellargs[arglen - 3] = ptr;
2134 }
2135 spellargs[arglen - 1] = NULL;
2136 }
2137 spellargs[arglen - 2] = tempfile_name;
2138
2139 /* Start a new process for the alternate speller. */
2140 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey2e2112c2005-11-29 05:39:31 +00002141 /* Start alternate spell program; we are using $PATH. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002142 execvp(spellargs[0], spellargs);
2143
2144 /* Should not be reached, if alternate speller is found!!! */
2145 exit(1);
2146 }
2147
2148 /* If we couldn't fork, get out. */
2149 if (pid_spell < 0)
2150 return _("Could not fork");
2151
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002152#ifndef NANO_TINY
David Lawrence Ramseyb18482e2005-07-26 00:06:34 +00002153 /* Don't handle a pending SIGWINCH until the alternate spell checker
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00002154 * is finished and we've loaded the spell-checked file back in. */
David Lawrence Ramseyb18482e2005-07-26 00:06:34 +00002155 allow_pending_sigwinch(FALSE);
2156#endif
2157
2158 /* Wait for the alternate spell checker to finish. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002159 wait(&alt_spell_status);
2160
David Lawrence Ramsey84fdb902005-08-14 20:08:49 +00002161 /* Reenter curses mode. */
2162 doupdate();
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002163
2164 /* Restore the terminal to its previous state. */
2165 terminal_init();
2166
2167 /* Turn the cursor back on for sure. */
2168 curs_set(1);
2169
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00002170 /* The screen might have been resized. If it has, reinitialize all
2171 * the windows based on the new screen dimensions. */
2172 window_init();
2173
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002174 if (!WIFEXITED(alt_spell_status) ||
2175 WEXITSTATUS(alt_spell_status) != 0) {
2176 char *altspell_error;
2177 char *invoke_error = _("Error invoking \"%s\"");
2178
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002179#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002180 /* Turn the mark back on if it was on before. */
2181 openfile->mark_set = old_mark_set;
2182#endif
2183
2184 altspell_error =
2185 charalloc(strlen(invoke_error) +
2186 strlen(alt_speller) + 1);
2187 sprintf(altspell_error, invoke_error, alt_speller);
2188 return altspell_error;
2189 }
2190
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002191#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002192 if (old_mark_set) {
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002193 /* If the mark is on, partition the filestruct so that it
2194 * contains only the marked text; if the NO_NEWLINES flag isn't
2195 * set, keep track of whether the text will have a magicline
2196 * added when we're done correcting misspelled words; and
2197 * turn the mark off. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002198 mark_order((const filestruct **)&top, &top_x,
2199 (const filestruct **)&bot, &bot_x, &right_side_up);
2200 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002201 if (!ISSET(NO_NEWLINES))
2202 added_magicline = (openfile->filebot->data[0] != '\0');
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002203
2204 /* Get the number of characters in the marked text, and subtract
2205 * it from the saved value of totsize. */
2206 totsize_save -= get_totsize(top, bot);
2207 }
2208#endif
2209
David Lawrence Ramsey9c984e82005-11-08 19:15:58 +00002210 /* Replace the text of the current buffer with the spell-checked
2211 * text. */
2212 replace_buffer(tempfile_name);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002213
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002214#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002215 if (old_mark_set) {
2216 filestruct *top_save = openfile->fileage;
2217
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002218 /* If the mark was on, the NO_NEWLINES flag isn't set, and we
2219 * added a magicline, remove it now. */
2220 if (!ISSET(NO_NEWLINES) && added_magicline)
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002221 remove_magicline();
2222
2223 /* Put the beginning and the end of the mark at the beginning
2224 * and the end of the spell-checked text. */
2225 if (openfile->fileage == openfile->filebot)
2226 bot_x += top_x;
2227 if (right_side_up) {
2228 openfile->mark_begin_x = top_x;
2229 current_x_save = bot_x;
2230 } else {
2231 current_x_save = top_x;
2232 openfile->mark_begin_x = bot_x;
2233 }
2234
2235 /* Unpartition the filestruct so that it contains all the text
2236 * again. Note that we've replaced the marked text originally
2237 * in the partition with the spell-checked marked text in the
2238 * temp file. */
2239 unpartition_filestruct(&filepart);
2240
2241 /* Renumber starting with the beginning line of the old
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002242 * partition. Also add the number of characters in the
2243 * spell-checked marked text to the saved value of totsize, and
2244 * then make that saved value the actual value. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002245 renumber(top_save);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002246 totsize_save += openfile->totsize;
2247 openfile->totsize = totsize_save;
2248
2249 /* Assign mark_begin to the line where the mark began before. */
2250 do_gotopos(mb_lineno_save, openfile->mark_begin_x,
2251 current_y_save, 0);
2252 openfile->mark_begin = openfile->current;
2253
2254 /* Assign mark_begin_x to the location in mark_begin where the
2255 * mark began before, adjusted for any shortening of the
2256 * line. */
2257 openfile->mark_begin_x = openfile->current_x;
2258
2259 /* Turn the mark back on. */
2260 openfile->mark_set = TRUE;
2261 }
2262#endif
2263
2264 /* Go back to the old position, and mark the file as modified. */
2265 do_gotopos(lineno_save, current_x_save, current_y_save, pww_save);
2266 set_modified();
2267
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002268#ifndef NANO_TINY
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00002269 /* Handle a pending SIGWINCH again. */
2270 allow_pending_sigwinch(TRUE);
2271#endif
2272
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002273 return NULL;
2274}
2275
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002276/* Spell check the current file. If an alternate spell checker is
2277 * specified, use it. Otherwise, use the internal spell checker. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002278void do_spell(void)
2279{
2280 int i;
2281 FILE *temp_file;
2282 char *temp = safe_tempfile(&temp_file);
2283 const char *spell_msg;
2284
2285 if (temp == NULL) {
2286 statusbar(_("Could not create temp file: %s"), strerror(errno));
2287 return;
2288 }
2289
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002290#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002291 if (openfile->mark_set)
David Lawrence Ramseye014fbd2005-08-29 19:11:26 +00002292 i = write_marked_file(temp, temp_file, TRUE, OVERWRITE);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002293 else
2294#endif
David Lawrence Ramseye014fbd2005-08-29 19:11:26 +00002295 i = write_file(temp, temp_file, TRUE, OVERWRITE, FALSE);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002296
2297 if (i == -1) {
2298 statusbar(_("Error writing temp file: %s"), strerror(errno));
2299 free(temp);
2300 return;
2301 }
2302
2303 spell_msg = (alt_speller != NULL) ? do_alt_speller(temp) :
2304 do_int_speller(temp);
2305 unlink(temp);
2306 free(temp);
2307
2308 /* If the spell-checker printed any error messages onscreen, make
2309 * sure that they're cleared off. */
2310 total_refresh();
2311
2312 if (spell_msg != NULL) {
2313 if (errno == 0)
2314 /* Don't display an error message of "Success". */
2315 statusbar(_("Spell checking failed: %s"), spell_msg);
2316 else
2317 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
2318 strerror(errno));
2319 } else
2320 statusbar(_("Finished checking spelling"));
2321}
2322#endif /* !DISABLE_SPELLER */
2323
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002324#ifndef NANO_TINY
David Lawrence Ramseyd7f0fe92005-08-10 22:51:49 +00002325/* Our own version of "wc". Note that its character counts are in
2326 * multibyte characters instead of single-byte characters. */
David Lawrence Ramsey8e942342005-07-25 04:21:46 +00002327void do_wordlinechar_count(void)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002328{
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002329 size_t words = 0, chars = 0;
2330 ssize_t lines = 0;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002331 size_t current_x_save = openfile->current_x;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002332 size_t pww_save = openfile->placewewant;
2333 filestruct *current_save = openfile->current;
2334 bool old_mark_set = openfile->mark_set;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002335 filestruct *top, *bot;
2336 size_t top_x, bot_x;
2337
2338 if (old_mark_set) {
2339 /* If the mark is on, partition the filestruct so that it
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +00002340 * contains only the marked text, and turn the mark off. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002341 mark_order((const filestruct **)&top, &top_x,
2342 (const filestruct **)&bot, &bot_x, NULL);
2343 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002344 openfile->mark_set = FALSE;
2345 }
2346
2347 /* Start at the top of the file. */
2348 openfile->current = openfile->fileage;
2349 openfile->current_x = 0;
2350 openfile->placewewant = 0;
2351
2352 /* Keep moving to the next word (counting punctuation characters as
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002353 * part of a word, as "wc -w" does), without updating the screen,
2354 * until we reach the end of the file, incrementing the total word
2355 * count whenever we're on a word just before moving. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002356 while (openfile->current != openfile->filebot ||
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +00002357 openfile->current->data[openfile->current_x] != '\0') {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002358 if (do_next_word(TRUE, FALSE))
2359 words++;
2360 }
2361
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002362 /* Get the total line and character counts, as "wc -l" and "wc -c"
2363 * do, but get the latter in multibyte characters. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002364 if (old_mark_set) {
David Lawrence Ramsey78a81b22005-07-25 18:59:24 +00002365 lines = openfile->filebot->lineno -
2366 openfile->fileage->lineno + 1;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002367 chars = get_totsize(openfile->fileage, openfile->filebot);
2368
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002369 /* Unpartition the filestruct so that it contains all the text
2370 * again, and turn the mark back on. */
2371 unpartition_filestruct(&filepart);
2372 openfile->mark_set = TRUE;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002373 } else {
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002374 lines = openfile->filebot->lineno;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002375 chars = openfile->totsize;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002376 }
2377
2378 /* Restore where we were. */
2379 openfile->current = current_save;
2380 openfile->current_x = current_x_save;
2381 openfile->placewewant = pww_save;
2382
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002383 /* Display the total word, line, and character counts on the
2384 * statusbar. */
David Lawrence Ramsey7b71f572005-10-06 20:46:11 +00002385 statusbar(_("%sWords: %lu Lines: %ld Chars: %lu"), old_mark_set ?
David Lawrence Ramsey815fb0a2005-08-05 19:38:11 +00002386 _("In Selection: ") : "", (unsigned long)words, (long)lines,
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002387 (unsigned long)chars);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002388}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002389#endif /* !NANO_TINY */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002390
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002391/* Get verbatim input. */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002392void do_verbatim_input(void)
2393{
2394 int *kbinput;
2395 size_t kbinput_len, i;
2396 char *output;
2397
2398 statusbar(_("Verbatim Input"));
2399
2400 /* If constant cursor position display is on, make sure the current
2401 * cursor position will be properly displayed on the statusbar. */
2402 if (ISSET(CONST_UPDATE))
2403 do_cursorpos(TRUE);
2404
2405 /* Read in all the verbatim characters. */
2406 kbinput = get_verbatim_kbinput(edit, &kbinput_len);
2407
2408 /* Display all the verbatim characters at once, not filtering out
2409 * control characters. */
2410 output = charalloc(kbinput_len + 1);
2411
2412 for (i = 0; i < kbinput_len; i++)
2413 output[i] = (char)kbinput[i];
2414 output[i] = '\0';
2415
2416 do_output(output, kbinput_len, TRUE);
2417
2418 free(output);
2419}