blob: cf0c0fdbee10b73f27f4a7c9b460269ec6d127e9 [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 Ramsey3f7c8c52005-11-14 22:20:35 +00005 * Copyright (C) 1999-2005 Chris Allegretta *
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00006 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2, or (at your option) *
9 * any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, but *
12 * WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14 * General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
19 * 02110-1301, USA. *
20 * *
21 **************************************************************************/
22
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
26
David Lawrence Ramseyee11c6a2005-11-02 19:42:02 +000027#include <stdio.h>
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000028#include <signal.h>
29#include <unistd.h>
30#include <string.h>
31#include <fcntl.h>
32#include <sys/wait.h>
33#include <errno.h>
34#include "proto.h"
35
David Lawrence Ramseyebe34252005-11-15 03:17:35 +000036#ifndef NANO_TINY
David Lawrence Ramsey8779a172005-11-08 16:45:22 +000037static pid_t pid = -1;
38 /* The PID of the newly forked process in execute_command(), for
39 * use with the cancel_command() signal handler. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000040#endif
41#ifndef DISABLE_WRAPPING
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +000042static bool prepend_wrap = FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000043 /* Should we prepend wrapped text to the next line? */
44#endif
45#ifndef DISABLE_JUSTIFY
46static filestruct *jusbottom = NULL;
David Lawrence Ramseyae4c3a62005-09-20 19:46:39 +000047 /* Pointer to the end of the justify buffer. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000048#endif
49
David Lawrence Ramseyebe34252005-11-15 03:17:35 +000050#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000051void do_mark(void)
52{
53 openfile->mark_set = !openfile->mark_set;
54 if (openfile->mark_set) {
55 statusbar(_("Mark Set"));
56 openfile->mark_begin = openfile->current;
57 openfile->mark_begin_x = openfile->current_x;
58 } else {
59 statusbar(_("Mark UNset"));
60 openfile->mark_begin = NULL;
61 openfile->mark_begin_x = 0;
62 edit_refresh();
63 }
64}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +000065#endif /* !NANO_TINY */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000066
67void 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
155void do_backspace(void)
156{
157 if (openfile->current != openfile->fileage ||
158 openfile->current_x > 0) {
David Lawrence Ramsey1c3bfa92005-09-13 04:53:44 +0000159 do_left();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000160 do_delete();
161 }
162}
163
164void do_tab(void)
165{
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000166#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000167 if (ISSET(TABS_TO_SPACES)) {
168 char *output;
David Lawrence Ramsey90b07fc2005-10-07 15:57:48 +0000169 size_t output_len = 0, new_pww = xplustabs();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000170
171 do {
172 new_pww++;
173 output_len++;
174 } while (new_pww % tabsize != 0);
175
176 output = charalloc(output_len + 1);
177
178 charset(output, ' ', output_len);
179 output[output_len] = '\0';
180
181 do_output(output, output_len, TRUE);
182
183 free(output);
184 } else {
185#endif
186 do_output("\t", 1, TRUE);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000187#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000188 }
189#endif
190}
191
David Lawrence Ramseyfeb89db2005-09-13 04:45:46 +0000192/* Someone hits Enter *gasp!* */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000193void do_enter(void)
194{
195 filestruct *newnode = make_new_node(openfile->current);
196 size_t extra = 0;
197
198 assert(openfile->current != NULL && openfile->current->data != NULL);
199
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000200#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000201 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
202 if (ISSET(AUTOINDENT)) {
203 /* If we are breaking the line in the indentation, the new
204 * indentation should have only current_x characters, and
205 * current_x should not change. */
206 extra = indent_length(openfile->current->data);
207 if (extra > openfile->current_x)
208 extra = openfile->current_x;
209 }
210#endif
211 newnode->data = charalloc(strlen(openfile->current->data +
212 openfile->current_x) + extra + 1);
213 strcpy(&newnode->data[extra], openfile->current->data +
214 openfile->current_x);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000215#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000216 if (ISSET(AUTOINDENT)) {
217 strncpy(newnode->data, openfile->current->data, extra);
218 openfile->totsize += mbstrlen(newnode->data);
219 }
220#endif
221 null_at(&openfile->current->data, openfile->current_x);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000222#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000223 if (openfile->mark_set && openfile->current ==
224 openfile->mark_begin && openfile->current_x <
225 openfile->mark_begin_x) {
226 openfile->mark_begin = newnode;
227 openfile->mark_begin_x += extra - openfile->current_x;
228 }
229#endif
230 openfile->current_x = extra;
231
232 if (openfile->current == openfile->filebot)
233 openfile->filebot = newnode;
234 splice_node(openfile->current, newnode,
235 openfile->current->next);
236
237 renumber(openfile->current);
238 openfile->current = newnode;
239
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000240 openfile->totsize++;
241 set_modified();
David Lawrence Ramseyfeb89db2005-09-13 04:45:46 +0000242
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000243 openfile->placewewant = xplustabs();
David Lawrence Ramseyfeb89db2005-09-13 04:45:46 +0000244
245 edit_refresh();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000246}
247
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000248#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000249void cancel_command(int signal)
250{
251 if (kill(pid, SIGKILL) == -1)
252 nperror("kill");
253}
254
David Lawrence Ramsey0ed71712005-11-08 23:09:47 +0000255/* Execute command in a shell. Return TRUE on success. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000256bool execute_command(const char *command)
257{
258 int fd[2];
259 FILE *f;
260 struct sigaction oldaction, newaction;
261 /* Original and temporary handlers for SIGINT. */
262 bool sig_failed = FALSE;
263 /* Did sigaction() fail without changing the signal handlers? */
264
265 /* Make our pipes. */
266 if (pipe(fd) == -1) {
267 statusbar(_("Could not pipe"));
268 return FALSE;
269 }
270
271 /* Fork a child. */
272 if ((pid = fork()) == 0) {
273 close(fd[0]);
274 dup2(fd[1], fileno(stdout));
275 dup2(fd[1], fileno(stderr));
276
277 /* If execl() returns at all, there was an error. */
278 execl("/bin/sh", "sh", "-c", command, NULL);
279 exit(0);
280 }
281
282 /* Else continue as parent. */
283 close(fd[1]);
284
285 if (pid == -1) {
286 close(fd[0]);
287 statusbar(_("Could not fork"));
288 return FALSE;
289 }
290
291 /* Before we start reading the forked command's output, we set
292 * things up so that Ctrl-C will cancel the new process. */
293
294 /* Enable interpretation of the special control keys so that we get
295 * SIGINT when Ctrl-C is pressed. */
296 enable_signals();
297
298 if (sigaction(SIGINT, NULL, &newaction) == -1) {
299 sig_failed = TRUE;
300 nperror("sigaction");
301 } else {
302 newaction.sa_handler = cancel_command;
303 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
304 sig_failed = TRUE;
305 nperror("sigaction");
306 }
307 }
308
309 /* Note that now oldaction is the previous SIGINT signal handler,
310 * to be restored later. */
311
312 f = fdopen(fd[0], "rb");
313 if (f == NULL)
314 nperror("fdopen");
315
316 read_file(f, "stdin");
317
318 /* If multibuffer mode is on, we could be here in view mode. If so,
319 * don't set the modification flag. */
320 if (!ISSET(VIEW_MODE))
321 set_modified();
322
323 if (wait(NULL) == -1)
324 nperror("wait");
325
326 if (!sig_failed && sigaction(SIGINT, &oldaction, NULL) == -1)
327 nperror("sigaction");
328
329 /* Disable interpretation of the special control keys so that we can
330 * use Ctrl-C for other things. */
331 disable_signals();
332
333 return TRUE;
334}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000335#endif /* !NANO_TINY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000336
337#ifndef DISABLE_WRAPPING
338void wrap_reset(void)
339{
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000340 prepend_wrap = FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000341}
342
343/* We wrap the given line. Precondition: we assume the cursor has been
344 * moved forward since the last typed character. Return value: whether
345 * we wrapped. */
346bool do_wrap(filestruct *line)
347{
348 size_t line_len;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000349 /* The length of the line we wrap. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000350 ssize_t wrap_loc;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000351 /* The index of line->data where we wrap. */
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000352#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000353 const char *indent_string = NULL;
354 /* Indentation to prepend to the new line. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000355 size_t indent_len = 0;
356 /* The length of indent_string. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000357#endif
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000358 const char *after_break;
359 /* The text after the wrap point. */
360 size_t after_break_len;
361 /* The length of after_break. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000362 bool prepending = FALSE;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000363 /* Do we prepend to the next line? */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000364 const char *next_line = NULL;
365 /* The next line, minus indentation. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000366 size_t next_line_len = 0;
367 /* The length of next_line. */
368 char *new_line = NULL;
369 /* The line we create. */
370 size_t new_line_len = 0;
371 /* The eventual length of new_line. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000372
373 /* There are three steps. First, we decide where to wrap. Then, we
374 * create the new wrap line. Finally, we clean up. */
375
376 /* Step 1, finding where to wrap. We are going to add a new line
377 * after a blank character. In this step, we call break_line() to
378 * get the location of the last blank we can break the line at, and
379 * and set wrap_loc to the location of the character after it, so
380 * that the blank is preserved at the end of the line.
381 *
382 * If there is no legal wrap point, or we reach the last character
383 * of the line while trying to find one, we should return without
384 * wrapping. Note that if autoindent is turned on, we don't break
385 * at the end of it! */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000386 assert(line != NULL && line->data != NULL);
387
388 /* Save the length of the line. */
389 line_len = strlen(line->data);
390
391 /* Find the last blank where we can break the line. */
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000392 wrap_loc = break_line(line->data, fill
393#ifndef DISABLE_HELP
394 , FALSE
395#endif
396 );
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000397
398 /* If we couldn't break the line, or we've reached the end of it, we
399 * don't wrap. */
400 if (wrap_loc == -1 || line->data[wrap_loc] == '\0')
401 return FALSE;
402
403 /* Otherwise, move forward to the character just after the blank. */
404 wrap_loc += move_mbright(line->data + wrap_loc, 0);
405
406 /* If we've reached the end of the line, we don't wrap. */
407 if (line->data[wrap_loc] == '\0')
408 return FALSE;
409
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000410#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000411 /* If autoindent is turned on, and we're on the character just after
412 * the indentation, we don't wrap. */
413 if (ISSET(AUTOINDENT)) {
414 /* Get the indentation of this line. */
415 indent_string = line->data;
416 indent_len = indent_length(indent_string);
417
418 if (wrap_loc == indent_len)
419 return FALSE;
420 }
421#endif
422
423 /* Step 2, making the new wrap line. It will consist of indentation
424 * followed by the text after the wrap point, optionally followed by
425 * a space (if the text after the wrap point doesn't end in a blank)
426 * and the text of the next line, if they can fit without
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000427 * wrapping, the next line exists, and the prepend_wrap flag is
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000428 * set. */
429
430 /* after_break is the text that will be wrapped to the next line. */
431 after_break = line->data + wrap_loc;
432 after_break_len = line_len - wrap_loc;
433
434 assert(strlen(after_break) == after_break_len);
435
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000436 /* We prepend the wrapped text to the next line, if the prepend_wrap
437 * flag is set, there is a next line, and prepending would not make
438 * the line too long. */
439 if (prepend_wrap && line != openfile->filebot) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000440 const char *end = after_break + move_mbleft(after_break,
441 after_break_len);
442
443 /* If after_break doesn't end in a blank, make sure it ends in a
444 * space. */
445 if (!is_blank_mbchar(end)) {
446 line_len++;
447 line->data = charealloc(line->data, line_len + 1);
448 line->data[line_len - 1] = ' ';
449 line->data[line_len] = '\0';
450 after_break = line->data + wrap_loc;
451 after_break_len++;
452 openfile->totsize++;
453 }
454
455 next_line = line->next->data;
456 next_line_len = strlen(next_line);
457
458 if (after_break_len + next_line_len <= fill) {
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000459 prepending = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000460 new_line_len += next_line_len;
461 }
462 }
463
464 /* new_line_len is now the length of the text that will be wrapped
465 * to the next line, plus (if we're prepending to it) the length of
466 * the text of the next line. */
467 new_line_len += after_break_len;
468
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000469#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000470 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000471 if (prepending) {
472 /* If we're prepending, the indentation will come from the
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000473 * next line. */
474 indent_string = next_line;
475 indent_len = indent_length(indent_string);
476 next_line += indent_len;
477 } else {
478 /* Otherwise, it will come from this line, in which case
479 * we should increase new_line_len to make room for it. */
480 new_line_len += indent_len;
481 openfile->totsize += mbstrnlen(indent_string, indent_len);
482 }
483 }
484#endif
485
486 /* Now we allocate the new line and copy the text into it. */
487 new_line = charalloc(new_line_len + 1);
488 new_line[0] = '\0';
489
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000490#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000491 if (ISSET(AUTOINDENT)) {
492 /* Copy the indentation. */
493 strncpy(new_line, indent_string, indent_len);
494 new_line[indent_len] = '\0';
495 new_line_len += indent_len;
496 }
497#endif
498
499 /* Copy all the text after the wrap point of the current line. */
500 strcat(new_line, after_break);
501
502 /* Break the current line at the wrap point. */
503 null_at(&line->data, wrap_loc);
504
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000505 if (prepending) {
506 /* If we're prepending, copy the text from the next line, minus
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000507 * the indentation that we already copied above. */
508 strcat(new_line, next_line);
509
510 free(line->next->data);
511 line->next->data = new_line;
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000512
513 /* If the NO_NEWLINES flag isn't set, and text has been added to
514 * the magicline, make a new magicline. */
515 if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0')
516 new_magicline();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000517 } else {
518 /* Otherwise, make a new line and copy the text after where we
519 * broke this line to the beginning of the new line. */
520 splice_node(openfile->current, make_new_node(openfile->current),
521 openfile->current->next);
522
David Lawrence Ramsey219a8142005-11-22 22:08:01 +0000523 /* If the current line is the last line of the file, move the
524 * last line of the file down to the next line. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000525 if (openfile->filebot == openfile->current)
526 openfile->filebot = openfile->current->next;
527
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000528 openfile->current->next->data = new_line;
529
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000530 openfile->totsize++;
531 }
532
533 /* Step 3, clean up. Reposition the cursor and mark, and do some
534 * other sundry things. */
535
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000536 /* Set the prepend_wrap flag, so that later wraps of this line will
537 * be prepended to the next line. */
538 prepend_wrap = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000539
540 /* Each line knows its line number. We recalculate these if we
541 * inserted a new line. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000542 if (!prepending)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000543 renumber(line);
544
545 /* If the cursor was after the break point, we must move it. We
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000546 * also clear the prepend_wrap flag in this case. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000547 if (openfile->current_x > wrap_loc) {
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000548 prepend_wrap = FALSE;
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000549
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000550 openfile->current = openfile->current->next;
551 openfile->current_x -= wrap_loc
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000552#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000553 - indent_len
554#endif
555 ;
556 openfile->placewewant = xplustabs();
557 }
558
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000559#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000560 /* If the mark was on this line after the wrap point, we move it
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000561 * down. If it was on the next line and we prepended to that line,
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000562 * we move it right. */
563 if (openfile->mark_set) {
564 if (openfile->mark_begin == line && openfile->mark_begin_x >
565 wrap_loc) {
566 openfile->mark_begin = line->next;
567 openfile->mark_begin_x -= wrap_loc - indent_len + 1;
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000568 } else if (prepending && openfile->mark_begin == line->next)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000569 openfile->mark_begin_x += after_break_len;
570 }
571#endif
572
573 return TRUE;
574}
575#endif /* !DISABLE_WRAPPING */
576
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000577#if !defined(DISABLE_HELP) || !defined(DISABLE_JUSTIFY) || !defined(DISABLE_WRAPPING)
578/* We are trying to break a chunk off line. We find the last blank such
David Lawrence Ramseycd9a5f02005-09-20 06:12:54 +0000579 * that the display length to there is at most (goal + 1). If there is
580 * no such blank, then we find the first blank. We then take the last
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000581 * blank in that group of blanks. The terminating '\0' counts as a
582 * blank, as does a '\n' if newline is TRUE. */
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000583ssize_t break_line(const char *line, ssize_t goal
584#ifndef DISABLE_HELP
585 , bool newline
586#endif
587 )
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000588{
589 ssize_t blank_loc = -1;
590 /* Current tentative return value. Index of the last blank we
591 * found with short enough display width. */
592 ssize_t cur_loc = 0;
593 /* Current index in line. */
594 int line_len;
595
596 assert(line != NULL);
597
598 while (*line != '\0' && goal >= 0) {
David Lawrence Ramsey95ef3372005-09-20 19:44:19 +0000599 size_t pos = 0;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000600
David Lawrence Ramseyca37ee62005-09-20 17:47:27 +0000601 line_len = parse_mbchar(line, NULL, &pos);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000602
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000603 if (is_blank_mbchar(line)
604#ifndef DISABLE_HELP
605 || (newline && *line == '\n')
606#endif
607 ) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000608 blank_loc = cur_loc;
609
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000610#ifndef DISABLE_HELP
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000611 if (newline && *line == '\n')
612 break;
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000613#endif
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000614 }
615
David Lawrence Ramsey95ef3372005-09-20 19:44:19 +0000616 goal -= pos;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000617 line += line_len;
618 cur_loc += line_len;
619 }
620
621 if (goal >= 0)
622 /* In fact, the whole line displays shorter than goal. */
623 return cur_loc;
624
625 if (blank_loc == -1) {
626 /* No blank was found that was short enough. */
627 bool found_blank = FALSE;
David Lawrence Ramsey5ab12ca2005-09-20 17:52:52 +0000628 ssize_t found_blank_loc = 0;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000629
630 while (*line != '\0') {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000631 line_len = parse_mbchar(line, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000632
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000633 if (is_blank_mbchar(line)
634#ifndef DISABLE_HELP
635 || (newline && *line == '\n')
636#endif
637 ) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000638 if (!found_blank)
639 found_blank = TRUE;
David Lawrence Ramseybdc1b9b2005-09-20 16:36:08 +0000640 found_blank_loc = cur_loc;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000641 } else if (found_blank)
David Lawrence Ramseybdc1b9b2005-09-20 16:36:08 +0000642 return found_blank_loc;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000643
644 line += line_len;
645 cur_loc += line_len;
646 }
647
648 return -1;
649 }
650
651 /* Move to the last blank after blank_loc, if there is one. */
652 line -= cur_loc;
653 line += blank_loc;
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000654 line_len = parse_mbchar(line, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000655 line += line_len;
656
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000657 while (*line != '\0' && (is_blank_mbchar(line)
658#ifndef DISABLE_HELP
659 || (newline && *line == '\n')
660#endif
661 )) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000662 line_len = parse_mbchar(line, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000663
664 line += line_len;
665 blank_loc += line_len;
666 }
667
668 return blank_loc;
669}
670#endif /* !DISABLE_HELP || !DISABLE_JUSTIFY || !DISABLE_WRAPPING */
671
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000672#if !defined(NANO_TINY) || !defined(DISABLE_JUSTIFY)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000673/* The "indentation" of a line is the whitespace between the quote part
674 * and the non-whitespace of the line. */
675size_t indent_length(const char *line)
676{
677 size_t len = 0;
678 char *blank_mb;
679 int blank_mb_len;
680
681 assert(line != NULL);
682
683 blank_mb = charalloc(mb_cur_max());
684
685 while (*line != '\0') {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000686 blank_mb_len = parse_mbchar(line, blank_mb, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000687
688 if (!is_blank_mbchar(blank_mb))
689 break;
690
691 line += blank_mb_len;
692 len += blank_mb_len;
693 }
694
695 free(blank_mb);
696
697 return len;
698}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000699#endif /* !NANO_TINY || !DISABLE_JUSTIFY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000700
701#ifndef DISABLE_JUSTIFY
702/* justify_format() replaces blanks with spaces and multiple spaces by 1
703 * (except it maintains up to 2 after a character in punct optionally
704 * followed by a character in brackets, and removes all from the end).
705 *
706 * justify_format() might make paragraph->data shorter, and change the
707 * actual pointer with null_at().
708 *
709 * justify_format() will not look at the first skip characters of
710 * paragraph. skip should be at most strlen(paragraph->data). The
711 * character at paragraph[skip + 1] must not be blank. */
712void justify_format(filestruct *paragraph, size_t skip)
713{
714 char *end, *new_end, *new_paragraph_data;
715 size_t shift = 0;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000716#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000717 size_t mark_shift = 0;
718#endif
719
720 /* These four asserts are assumptions about the input data. */
721 assert(paragraph != NULL);
722 assert(paragraph->data != NULL);
723 assert(skip < strlen(paragraph->data));
724 assert(!is_blank_mbchar(paragraph->data + skip));
725
726 end = paragraph->data + skip;
727 new_paragraph_data = charalloc(strlen(paragraph->data) + 1);
728 strncpy(new_paragraph_data, paragraph->data, skip);
729 new_end = new_paragraph_data + skip;
730
731 while (*end != '\0') {
732 int end_len;
733
734 /* If this character is blank, make sure that it's a space with
735 * no blanks after it. */
736 if (is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000737 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000738
739 *new_end = ' ';
740 new_end++;
741 end += end_len;
742
743 while (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000744 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000745
746 end += end_len;
747 shift += end_len;
748
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000749#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000750 /* Keep track of the change in the current line. */
751 if (openfile->mark_set && openfile->mark_begin ==
752 paragraph && openfile->mark_begin_x >= end -
753 paragraph->data)
754 mark_shift += end_len;
755#endif
756 }
757 /* If this character is punctuation optionally followed by a
758 * bracket and then followed by blanks, make sure there are no
759 * more than two blanks after it, and make sure that the blanks
760 * are spaces. */
761 } else if (mbstrchr(punct, end) != NULL) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000762 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000763
764 while (end_len > 0) {
765 *new_end = *end;
766 new_end++;
767 end++;
768 end_len--;
769 }
770
771 if (*end != '\0' && mbstrchr(brackets, end) != NULL) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000772 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000773
774 while (end_len > 0) {
775 *new_end = *end;
776 new_end++;
777 end++;
778 end_len--;
779 }
780 }
781
782 if (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000783 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000784
785 *new_end = ' ';
786 new_end++;
787 end += end_len;
788 }
789
790 if (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000791 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000792
793 *new_end = ' ';
794 new_end++;
795 end += end_len;
796 }
797
798 while (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000799 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000800
801 end += end_len;
802 shift += end_len;
803
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000804#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000805 /* Keep track of the change in the current line. */
806 if (openfile->mark_set && openfile->mark_begin ==
807 paragraph && openfile->mark_begin_x >= end -
808 paragraph->data)
809 mark_shift += end_len;
810#endif
811 }
812 /* If this character is neither blank nor punctuation, leave it
813 * alone. */
814 } else {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000815 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000816
817 while (end_len > 0) {
818 *new_end = *end;
819 new_end++;
820 end++;
821 end_len--;
822 }
823 }
824 }
825
826 assert(*end == '\0');
827
828 *new_end = *end;
829
830 /* Make sure that there are no spaces at the end of the line. */
831 while (new_end > new_paragraph_data + skip &&
832 *(new_end - 1) == ' ') {
833 new_end--;
834 shift++;
835 }
836
837 if (shift > 0) {
838 openfile->totsize -= shift;
839 null_at(&new_paragraph_data, new_end - new_paragraph_data);
840 free(paragraph->data);
841 paragraph->data = new_paragraph_data;
842
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000843#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000844 /* Adjust the mark coordinates to compensate for the change in
845 * the current line. */
846 if (openfile->mark_set && openfile->mark_begin == paragraph) {
847 openfile->mark_begin_x -= mark_shift;
848 if (openfile->mark_begin_x > new_end - new_paragraph_data)
849 openfile->mark_begin_x = new_end - new_paragraph_data;
850 }
851#endif
852 } else
853 free(new_paragraph_data);
854}
855
856/* The "quote part" of a line is the largest initial substring matching
857 * the quote string. This function returns the length of the quote part
858 * of the given line.
859 *
860 * Note that if !HAVE_REGEX_H then we match concatenated copies of
861 * quotestr. */
862size_t quote_length(const char *line)
863{
864#ifdef HAVE_REGEX_H
865 regmatch_t matches;
866 int rc = regexec(&quotereg, line, 1, &matches, 0);
867
868 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t)-1)
869 return 0;
870 /* matches.rm_so should be 0, since the quote string should start
871 * with the caret ^. */
872 return matches.rm_eo;
873#else /* !HAVE_REGEX_H */
874 size_t qdepth = 0;
875
876 /* Compute quote depth level. */
877 while (strncmp(line + qdepth, quotestr, quotelen) == 0)
878 qdepth += quotelen;
879 return qdepth;
880#endif /* !HAVE_REGEX_H */
881}
882
883/* a_line and b_line are lines of text. The quotation part of a_line is
884 * the first a_quote characters. Check that the quotation part of
885 * b_line is the same. */
886bool quotes_match(const char *a_line, size_t a_quote, const char
887 *b_line)
888{
889 /* Here is the assumption about a_quote. */
890 assert(a_quote == quote_length(a_line));
891
892 return (a_quote == quote_length(b_line) &&
893 strncmp(a_line, b_line, a_quote) == 0);
894}
895
896/* We assume a_line and b_line have no quote part. Then, we return
897 * whether b_line could follow a_line in a paragraph. */
898bool indents_match(const char *a_line, size_t a_indent, const char
899 *b_line, size_t b_indent)
900{
901 assert(a_indent == indent_length(a_line));
902 assert(b_indent == indent_length(b_line));
903
904 return (b_indent <= a_indent &&
905 strncmp(a_line, b_line, b_indent) == 0);
906}
907
908/* Is foo the beginning of a paragraph?
909 *
910 * A line of text consists of a "quote part", followed by an
911 * "indentation part", followed by text. The functions quote_length()
912 * and indent_length() calculate these parts.
913 *
914 * A line is "part of a paragraph" if it has a part not in the quote
915 * part or the indentation.
916 *
917 * A line is "the beginning of a paragraph" if it is part of a
918 * paragraph and
919 * 1) it is the top line of the file, or
920 * 2) the line above it is not part of a paragraph, or
921 * 3) the line above it does not have precisely the same quote
922 * part, or
923 * 4) the indentation of this line is not an initial substring of
924 * the indentation of the previous line, or
925 * 5) this line has no quote part and some indentation, and
926 * autoindent isn't turned on.
927 * The reason for number 5) is that if autoindent isn't turned on,
928 * then an indented line is expected to start a paragraph, as in
929 * books. Thus, nano can justify an indented paragraph only if
930 * autoindent is turned on. */
931bool begpar(const filestruct *const foo)
932{
David Lawrence Ramsey0083bd22005-11-09 18:26:44 +0000933 size_t quote_len, indent_len, temp_id_len;
934
935 if (foo == NULL)
936 return FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000937
938 /* Case 1). */
David Lawrence Ramsey0083bd22005-11-09 18:26:44 +0000939 if (foo == openfile->fileage)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000940 return TRUE;
941
942 quote_len = quote_length(foo->data);
943 indent_len = indent_length(foo->data + quote_len);
944
945 /* Not part of a paragraph. */
946 if (foo->data[quote_len + indent_len] == '\0')
947 return FALSE;
948
949 /* Case 3). */
950 if (!quotes_match(foo->data, quote_len, foo->prev->data))
951 return TRUE;
952
953 temp_id_len = indent_length(foo->prev->data + quote_len);
954
955 /* Case 2) or 5) or 4). */
956 if (foo->prev->data[quote_len + temp_id_len] == '\0' ||
957 (quote_len == 0 && indent_len > 0
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000958#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000959 && !ISSET(AUTOINDENT)
960#endif
961 ) || !indents_match(foo->prev->data + quote_len, temp_id_len,
962 foo->data + quote_len, indent_len))
963 return TRUE;
964
965 return FALSE;
966}
967
968/* Is foo inside a paragraph? */
969bool inpar(const filestruct *const foo)
970{
971 size_t quote_len;
972
973 if (foo == NULL)
974 return FALSE;
975
976 quote_len = quote_length(foo->data);
977
David Lawrence Ramsey21014032005-11-09 20:33:42 +0000978 return (foo->data[quote_len + indent_length(foo->data +
979 quote_len)] != '\0');
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000980}
981
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +0000982/* Move the next par_len lines, starting with first_line, into the
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +0000983 * justify buffer, leaving copies of those lines in place. Assume that
984 * par_len is greater than zero, and that there are enough lines after
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +0000985 * first_line. */
986void backup_lines(filestruct *first_line, size_t par_len)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000987{
988 filestruct *top = first_line;
989 /* The top of the paragraph we're backing up. */
990 filestruct *bot = first_line;
991 /* The bottom of the paragraph we're backing up. */
992 size_t i;
993 /* Generic loop variable. */
994 size_t current_x_save = openfile->current_x;
995 ssize_t fl_lineno_save = first_line->lineno;
996 ssize_t edittop_lineno_save = openfile->edittop->lineno;
997 ssize_t current_lineno_save = openfile->current->lineno;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000998#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000999 bool old_mark_set = openfile->mark_set;
1000 ssize_t mb_lineno_save = 0;
1001 size_t mark_begin_x_save = 0;
1002
1003 if (old_mark_set) {
1004 mb_lineno_save = openfile->mark_begin->lineno;
1005 mark_begin_x_save = openfile->mark_begin_x;
1006 }
1007#endif
1008
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001009 /* par_len will be one greater than the number of lines between
1010 * current and filebot if filebot is the last line in the
1011 * paragraph. */
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00001012 assert(par_len > 0 && openfile->current->lineno + par_len <=
1013 filebot->lineno + 1);
1014
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001015 /* Move bot down par_len lines to the line after the last line of
1016 * the paragraph, if there is one. */
1017 for (i = par_len; i > 0 && bot != openfile->filebot; i--)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001018 bot = bot->next;
1019
1020 /* Move the paragraph from the current buffer's filestruct to the
1021 * justify buffer. */
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001022 move_to_filestruct(&jusbuffer, &jusbottom, top, 0, bot,
David Lawrence Ramseyf0575cf2005-11-09 23:27:51 +00001023 (i == 1 && bot == openfile->filebot) ? strlen(bot->data) : 0);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001024
1025 /* Copy the paragraph back to the current buffer's filestruct from
1026 * the justify buffer. */
1027 copy_from_filestruct(jusbuffer, jusbottom);
1028
1029 /* Move upward from the last line of the paragraph to the first
1030 * line, putting first_line, edittop, current, and mark_begin at the
1031 * same lines in the copied paragraph that they had in the original
1032 * paragraph. */
David Lawrence Ramsey5d6f1272005-11-10 03:32:59 +00001033 if (openfile->current != openfile->fileage)
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001034 top = openfile->current->prev;
1035 else
1036 top = openfile->current;
David Lawrence Ramseye8d505b2005-11-10 03:40:45 +00001037 for (i = par_len; i > 0 && top != NULL; i--) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001038 if (top->lineno == fl_lineno_save)
1039 first_line = top;
1040 if (top->lineno == edittop_lineno_save)
1041 openfile->edittop = top;
1042 if (top->lineno == current_lineno_save)
1043 openfile->current = top;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001044#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001045 if (old_mark_set && top->lineno == mb_lineno_save) {
1046 openfile->mark_begin = top;
1047 openfile->mark_begin_x = mark_begin_x_save;
1048 }
1049#endif
1050 top = top->prev;
1051 }
1052
1053 /* Put current_x at the same place in the copied paragraph that it
1054 * had in the original paragraph. */
1055 openfile->current_x = current_x_save;
1056
1057 set_modified();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001058}
1059
1060/* Find the beginning of the current paragraph if we're in one, or the
1061 * beginning of the next paragraph if we're not. Afterwards, save the
1062 * quote length and paragraph length in *quote and *par. Return TRUE if
1063 * we found a paragraph, or FALSE if there was an error or we didn't
1064 * find a paragraph.
1065 *
1066 * See the comment at begpar() for more about when a line is the
1067 * beginning of a paragraph. */
1068bool find_paragraph(size_t *const quote, size_t *const par)
1069{
1070 size_t quote_len;
1071 /* Length of the initial quotation of the paragraph we search
1072 * for. */
1073 size_t par_len;
1074 /* Number of lines in the paragraph we search for. */
1075 filestruct *current_save;
1076 /* The line at the beginning of the paragraph we search for. */
1077 ssize_t current_y_save;
1078 /* The y-coordinate at the beginning of the paragraph we search
1079 * for. */
1080
1081#ifdef HAVE_REGEX_H
1082 if (quoterc != 0) {
1083 statusbar(_("Bad quote string %s: %s"), quotestr, quoteerr);
1084 return FALSE;
1085 }
1086#endif
1087
1088 assert(openfile->current != NULL);
1089
David Lawrence Ramsey1be131a2005-11-11 03:55:52 +00001090 /* If we're at the end of the last line of the file, it means that
1091 * there aren't any paragraphs left, so get out. */
1092 if (openfile->current == openfile->filebot && openfile->current_x ==
1093 strlen(openfile->filebot->data))
1094 return FALSE;
1095
1096 /* If the current line isn't in a paragraph, move forward to the
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001097 * last line of the next paragraph, if any. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001098 if (!inpar(openfile->current)) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001099 do_para_end(FALSE);
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001100 /* If we end up past the beginning of the line, it means that
1101 * we're at the end of the last line of the file, and the line
1102 * isn't blank, in which case the last line of the file is the
1103 * last line of the next paragraph.
1104 *
1105 * Otherwise, if we end up on a line that's in a paragraph, it
1106 * means that we're on the line after the last line of the next
1107 * paragraph, in which case we should move back to the last line
1108 * of the next paragraph. */
1109 if (openfile->current_x == 0) {
1110 if (!inpar(openfile->current->prev))
1111 return FALSE;
1112 if (openfile->current != openfile->fileage)
1113 openfile->current = openfile->current->prev;
1114 }
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001115 }
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001116 /* If the current line isn't the first line of the paragraph, move
1117 * back to the first line of the paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001118 if (!begpar(openfile->current))
1119 do_para_begin(FALSE);
1120
1121 /* Now current is the first line of the paragraph. Set quote_len to
1122 * the quotation length of that line, and set par_len to the number
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001123 * of lines in this paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001124 quote_len = quote_length(openfile->current->data);
1125 current_save = openfile->current;
1126 current_y_save = openfile->current_y;
1127 do_para_end(FALSE);
1128 par_len = openfile->current->lineno - current_save->lineno;
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001129 /* If we end up past the beginning of the line, it means that we're
1130 * at the end of the last line of the file, and the line isn't
1131 * blank, in which case the last line of the file is part of the
1132 * paragraph. */
David Lawrence Ramseybdff6652005-11-11 04:14:33 +00001133 if (openfile->current_x > 0)
1134 par_len++;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001135 openfile->current = current_save;
1136 openfile->current_y = current_y_save;
1137
1138 /* Save the values of quote_len and par_len. */
1139 assert(quote != NULL && par != NULL);
1140
1141 *quote = quote_len;
1142 *par = par_len;
1143
1144 return TRUE;
1145}
1146
1147/* If full_justify is TRUE, justify the entire file. Otherwise, justify
1148 * the current paragraph. */
1149void do_justify(bool full_justify)
1150{
1151 filestruct *first_par_line = NULL;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001152 /* Will be the first line of the justified paragraph. For
1153 * restoring after unjustify. */
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001154 filestruct *last_par_line = NULL;
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001155 /* Will be the line after the last line of the justified
1156 * paragraph, if any. Also for restoring after unjustify. */
David Lawrence Ramsey82b5deb2005-11-10 06:07:57 +00001157 bool filebot_inpar = FALSE;
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001158 /* Whether the text at filebot is part of the current
1159 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001160
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00001161 /* We save these variables to be restored if the user
1162 * unjustifies. */
David Lawrence Ramsey52161ee2005-11-10 19:56:26 +00001163 filestruct *edittop_save = openfile->edittop;
1164 filestruct *current_save = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001165 size_t current_x_save = openfile->current_x;
1166 size_t pww_save = openfile->placewewant;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001167 size_t totsize_save = openfile->totsize;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001168#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001169 filestruct *mark_begin_save = openfile->mark_begin;
1170 size_t mark_begin_x_save = openfile->mark_begin_x;
1171#endif
David Lawrence Ramsey52161ee2005-11-10 19:56:26 +00001172 bool modified_save = openfile->modified;
1173
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001174 int kbinput;
1175 bool meta_key, func_key, s_or_t, ran_func, finished;
1176
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001177 /* Move to the beginning of the current line, so that justifying at
David Lawrence Ramseybdff6652005-11-11 04:14:33 +00001178 * the end of the last line of the file, if that line isn't blank,
1179 * will work the first time through. */
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001180 openfile->current_x = 0;
1181
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001182 /* If we're justifying the entire file, start at the beginning. */
1183 if (full_justify)
1184 openfile->current = openfile->fileage;
1185
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001186 while (TRUE) {
1187 size_t i;
1188 /* Generic loop variable. */
1189 size_t quote_len;
1190 /* Length of the initial quotation of the paragraph we
1191 * justify. */
1192 size_t indent_len;
1193 /* Length of the initial indentation of the paragraph we
1194 * justify. */
1195 size_t par_len;
1196 /* Number of lines in the paragraph we justify. */
1197 ssize_t break_pos;
1198 /* Where we will break lines. */
1199 char *indent_string;
1200 /* The first indentation that doesn't match the initial
1201 * indentation of the paragraph we justify. This is put at
1202 * the beginning of every line broken off the first
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001203 * justified line of the paragraph. Note that this works
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001204 * because a paragraph can only contain two indentations at
1205 * most: the initial one, and a different one starting on a
1206 * line after the first. See the comment at begpar() for
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001207 * more about when a line is part of a paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001208
1209 /* Find the first line of the paragraph to be justified. That
1210 * is the start of this paragraph if we're in one, or the start
1211 * of the next otherwise. Save the quote length and paragraph
1212 * length (number of lines). Don't refresh the screen yet,
1213 * since we'll do that after we justify.
1214 *
1215 * If the search failed, we do one of two things. If we're
David Lawrence Ramsey8b203d62005-11-11 03:17:44 +00001216 * justifying the whole file, and we've found at least one
1217 * paragraph, it means that we should justify all the way to the
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001218 * last line of the file, so set the last line of the text to be
1219 * justified to the last line of the file and break out of the
1220 * loop. Otherwise, it means that there are no paragraph(s) to
1221 * justify, so refresh the screen and get out. */
1222 if (!find_paragraph(&quote_len, &par_len)) {
David Lawrence Ramsey8b203d62005-11-11 03:17:44 +00001223 if (full_justify && first_par_line != NULL) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001224 last_par_line = openfile->filebot;
1225 break;
1226 } else {
1227 edit_refresh();
1228 return;
1229 }
1230 }
1231
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001232 /* par_len will be one greater than the number of lines between
1233 * current and filebot if filebot is the last line in the
1234 * paragraph. Set filebot_inpar to TRUE if this is the case. */
1235 filebot_inpar = (openfile->current->lineno + par_len ==
1236 openfile->filebot->lineno + 1);
1237
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00001238 /* If we haven't already done it, move the original paragraph(s)
1239 * to the justify buffer, splice a copy of the original
1240 * paragraph(s) into the file in the same place, and set
1241 * first_par_line to the first line of the copy. */
1242 if (first_par_line == NULL) {
1243 backup_lines(openfile->current, full_justify ?
David Lawrence Ramsey53f641f2005-11-10 21:57:56 +00001244 openfile->filebot->lineno - openfile->current->lineno +
1245 ((openfile->filebot->data[0] != '\0') ? 1 : 0) :
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00001246 par_len);
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00001247 first_par_line = openfile->current;
1248 }
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001249
1250 /* Initialize indent_string to a blank string. */
1251 indent_string = mallocstrcpy(NULL, "");
1252
1253 /* Find the first indentation in the paragraph that doesn't
1254 * match the indentation of the first line, and save it in
1255 * indent_string. If all the indentations are the same, save
1256 * the indentation of the first line in indent_string. */
1257 {
1258 const filestruct *indent_line = openfile->current;
1259 bool past_first_line = FALSE;
1260
1261 for (i = 0; i < par_len; i++) {
1262 indent_len = quote_len +
1263 indent_length(indent_line->data + quote_len);
1264
1265 if (indent_len != strlen(indent_string)) {
1266 indent_string = mallocstrncpy(indent_string,
1267 indent_line->data, indent_len + 1);
1268 indent_string[indent_len] = '\0';
1269
1270 if (past_first_line)
1271 break;
1272 }
1273
1274 if (indent_line == openfile->current)
1275 past_first_line = TRUE;
1276
1277 indent_line = indent_line->next;
1278 }
1279 }
1280
1281 /* Now tack all the lines of the paragraph together, skipping
1282 * the quoting and indentation on all lines after the first. */
1283 for (i = 0; i < par_len - 1; i++) {
1284 filestruct *next_line = openfile->current->next;
1285 size_t line_len = strlen(openfile->current->data);
1286 size_t next_line_len =
1287 strlen(openfile->current->next->data);
1288
1289 indent_len = quote_len +
1290 indent_length(openfile->current->next->data +
1291 quote_len);
1292
1293 next_line_len -= indent_len;
1294 openfile->totsize -= indent_len;
1295
1296 /* We're just about to tack the next line onto this one. If
1297 * this line isn't empty, make sure it ends in a space. */
1298 if (line_len > 0 &&
1299 openfile->current->data[line_len - 1] != ' ') {
1300 line_len++;
1301 openfile->current->data =
1302 charealloc(openfile->current->data,
1303 line_len + 1);
1304 openfile->current->data[line_len - 1] = ' ';
1305 openfile->current->data[line_len] = '\0';
1306 openfile->totsize++;
1307 }
1308
1309 openfile->current->data =
1310 charealloc(openfile->current->data, line_len +
1311 next_line_len + 1);
1312 strcat(openfile->current->data, next_line->data +
1313 indent_len);
1314
David Lawrence Ramsey9bedc4b2005-11-09 19:51:48 +00001315 /* Don't destroy edittop or filebot! */
David Lawrence Ramsey32bd29e2005-11-09 03:44:23 +00001316 if (next_line == openfile->edittop)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001317 openfile->edittop = openfile->current;
David Lawrence Ramsey9bedc4b2005-11-09 19:51:48 +00001318 if (next_line == openfile->filebot)
1319 openfile->filebot = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001320
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001321#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001322 /* Adjust the mark coordinates to compensate for the change
1323 * in the next line. */
1324 if (openfile->mark_set && openfile->mark_begin ==
1325 next_line) {
1326 openfile->mark_begin = openfile->current;
1327 openfile->mark_begin_x += line_len - indent_len;
1328 }
1329#endif
1330
1331 unlink_node(next_line);
1332 delete_node(next_line);
1333
1334 /* If we've removed the next line, we need to go through
1335 * this line again. */
1336 i--;
1337
1338 par_len--;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001339 openfile->totsize--;
1340 }
1341
1342 /* Call justify_format() on the paragraph, which will remove
1343 * excess spaces from it and change all blank characters to
1344 * spaces. */
1345 justify_format(openfile->current, quote_len +
1346 indent_length(openfile->current->data + quote_len));
1347
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001348 while (par_len > 0 && strlenpt(openfile->current->data) >
1349 fill) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001350 size_t line_len = strlen(openfile->current->data);
1351
1352 indent_len = strlen(indent_string);
1353
1354 /* If this line is too long, try to wrap it to the next line
1355 * to make it short enough. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001356 break_pos = break_line(openfile->current->data + indent_len,
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001357 fill - strnlenpt(openfile->current->data, indent_len)
1358#ifndef DISABLE_HELP
1359 , FALSE
1360#endif
1361 );
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001362
1363 /* We can't break the line, or don't need to, so get out. */
1364 if (break_pos == -1 || break_pos + indent_len == line_len)
1365 break;
1366
1367 /* Move forward to the character after the indentation and
1368 * just after the space. */
1369 break_pos += indent_len + 1;
1370
1371 assert(break_pos <= line_len);
1372
1373 /* Make a new line, and copy the text after where we're
1374 * going to break this line to the beginning of the new
1375 * line. */
1376 splice_node(openfile->current,
1377 make_new_node(openfile->current),
1378 openfile->current->next);
1379
1380 /* If this paragraph is non-quoted, and autoindent isn't
1381 * turned on, set the indentation length to zero so that the
1382 * indentation is treated as part of the line. */
1383 if (quote_len == 0
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001384#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001385 && !ISSET(AUTOINDENT)
1386#endif
1387 )
1388 indent_len = 0;
1389
1390 /* Copy the text after where we're going to break the
1391 * current line to the next line. */
1392 openfile->current->next->data = charalloc(indent_len + 1 +
1393 line_len - break_pos);
1394 strncpy(openfile->current->next->data, indent_string,
1395 indent_len);
1396 strcpy(openfile->current->next->data + indent_len,
1397 openfile->current->data + break_pos);
1398
1399 par_len++;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001400 openfile->totsize += indent_len + 1;
1401
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001402#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001403 /* Adjust the mark coordinates to compensate for the change
1404 * in the current line. */
1405 if (openfile->mark_set && openfile->mark_begin ==
1406 openfile->current && openfile->mark_begin_x >
1407 break_pos) {
1408 openfile->mark_begin = openfile->current->next;
1409 openfile->mark_begin_x -= break_pos - indent_len;
1410 }
1411#endif
1412
1413 /* Break the current line. */
1414 null_at(&openfile->current->data, break_pos);
1415
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001416 /* If the current line is the last line of the file, move
David Lawrence Ramseyb885c9c2005-11-10 05:20:25 +00001417 * the last line of the file down to the next line. */
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001418 if (openfile->filebot == openfile->current)
1419 openfile->filebot = openfile->filebot->next;
1420
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001421 /* Go to the next line. */
1422 par_len--;
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001423 openfile->current_y++;
1424 openfile->current = openfile->current->next;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001425 }
1426
1427 /* We're done breaking lines, so we don't need indent_string
1428 * anymore. */
1429 free(indent_string);
1430
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001431 /* Go to the next line, if possible. If there is no next line,
1432 * move to the end of the current line. */
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001433 if (openfile->current != openfile->filebot) {
1434 openfile->current_y++;
1435 openfile->current = openfile->current->next;
1436 } else
1437 openfile->current_x = strlen(openfile->current->data);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001438
1439 /* We've just justified a paragraph. If we're not justifying the
1440 * entire file, break out of the loop. Otherwise, continue the
1441 * loop so that we justify all the paragraphs in the file. */
1442 if (!full_justify)
1443 break;
1444 }
1445
1446 /* We are now done justifying the paragraph or the file, so clean
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001447 * up. current_y and totsize have been maintained above. If we
1448 * actually justified something, renumber, since edit_refresh()
1449 * needs the line numbers to be right, and set last_par_line to the
1450 * new end of the paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001451 if (first_par_line != NULL) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001452 renumber(first_par_line);
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001453 last_par_line = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001454 }
1455
1456 edit_refresh();
1457
1458 statusbar(_("Can now UnJustify!"));
1459
1460 /* If constant cursor position display is on, make sure the current
1461 * cursor position will be properly displayed on the statusbar. */
1462 if (ISSET(CONST_UPDATE))
1463 do_cursorpos(TRUE);
1464
1465 /* Display the shortcut list with UnJustify. */
1466 shortcut_init(TRUE);
1467 display_main_list();
1468
1469 /* Now get a keystroke and see if it's unjustify. If not, put back
1470 * the keystroke and return. */
1471 kbinput = do_input(&meta_key, &func_key, &s_or_t, &ran_func,
1472 &finished, FALSE);
1473
1474 if (!meta_key && !func_key && s_or_t &&
1475 kbinput == NANO_UNJUSTIFY_KEY) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001476 /* Splice the justify buffer back into the file, but only if we
1477 * actually justified something. */
1478 if (first_par_line != NULL) {
1479 filestruct *top_save;
1480
1481 /* Partition the filestruct so that it contains only the
1482 * text of the justified paragraph. */
1483 filepart = partition_filestruct(first_par_line, 0,
David Lawrence Ramseyccd1b7b2005-11-18 20:21:48 +00001484 last_par_line, filebot_inpar ?
1485 strlen(last_par_line->data) : 0);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001486
1487 /* Remove the text of the justified paragraph, and
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00001488 * replace it with the text in the justify buffer. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001489 free_filestruct(openfile->fileage);
1490 openfile->fileage = jusbuffer;
1491 openfile->filebot = jusbottom;
1492
1493 top_save = openfile->fileage;
1494
1495 /* Unpartition the filestruct so that it contains all the
1496 * text again. Note that the justified paragraph has been
1497 * replaced with the unjustified paragraph. */
1498 unpartition_filestruct(&filepart);
1499
1500 /* Renumber starting with the beginning line of the old
1501 * partition. */
1502 renumber(top_save);
1503
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001504 /* Restore the justify we just did (ungrateful user!). */
1505 openfile->edittop = edittop_save;
1506 openfile->current = current_save;
1507 openfile->current_x = current_x_save;
1508 openfile->placewewant = pww_save;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001509 openfile->totsize = totsize_save;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001510#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001511 if (openfile->mark_set) {
1512 openfile->mark_begin = mark_begin_save;
1513 openfile->mark_begin_x = mark_begin_x_save;
1514 }
1515#endif
1516 openfile->modified = modified_save;
1517
1518 /* Clear the justify buffer. */
1519 jusbuffer = NULL;
1520
1521 if (!openfile->modified)
1522 titlebar(NULL);
1523 edit_refresh();
1524 }
1525 } else {
1526 unget_kbinput(kbinput, meta_key, func_key);
1527
1528 /* Blow away the text in the justify buffer. */
1529 free_filestruct(jusbuffer);
1530 jusbuffer = NULL;
1531 }
1532
1533 blank_statusbar();
1534
1535 /* Display the shortcut list with UnCut. */
1536 shortcut_init(FALSE);
1537 display_main_list();
1538}
1539
1540void do_justify_void(void)
1541{
1542 do_justify(FALSE);
1543}
1544
1545void do_full_justify(void)
1546{
1547 do_justify(TRUE);
1548}
1549#endif /* !DISABLE_JUSTIFY */
1550
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001551#ifndef DISABLE_SPELLER
1552/* A word is misspelled in the file. Let the user replace it. We
1553 * return FALSE if the user cancels. */
1554bool do_int_spell_fix(const char *word)
1555{
1556 char *save_search, *save_replace;
1557 size_t match_len, current_x_save = openfile->current_x;
1558 size_t pww_save = openfile->placewewant;
1559 filestruct *edittop_save = openfile->edittop;
1560 filestruct *current_save = openfile->current;
1561 /* Save where we are. */
1562 bool canceled = FALSE;
1563 /* The return value. */
1564 bool case_sens_set = ISSET(CASE_SENSITIVE);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001565#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001566 bool backwards_search_set = ISSET(BACKWARDS_SEARCH);
1567#endif
1568#ifdef HAVE_REGEX_H
1569 bool regexp_set = ISSET(USE_REGEXP);
1570#endif
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001571#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001572 bool old_mark_set = openfile->mark_set;
1573 bool added_magicline = FALSE;
1574 /* Whether we added a magicline after filebot. */
1575 bool right_side_up = FALSE;
1576 /* TRUE if (mark_begin, mark_begin_x) is the top of the mark,
1577 * FALSE if (current, current_x) is. */
1578 filestruct *top, *bot;
1579 size_t top_x, bot_x;
1580#endif
1581
1582 /* Make sure spell-check is case sensitive. */
1583 SET(CASE_SENSITIVE);
1584
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001585#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001586 /* Make sure spell-check goes forward only. */
1587 UNSET(BACKWARDS_SEARCH);
1588#endif
1589#ifdef HAVE_REGEX_H
1590 /* Make sure spell-check doesn't use regular expressions. */
1591 UNSET(USE_REGEXP);
1592#endif
1593
1594 /* Save the current search/replace strings. */
1595 search_init_globals();
1596 save_search = last_search;
1597 save_replace = last_replace;
1598
1599 /* Set the search/replace strings to the misspelled word. */
1600 last_search = mallocstrcpy(NULL, word);
1601 last_replace = mallocstrcpy(NULL, word);
1602
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001603#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001604 if (old_mark_set) {
1605 /* If the mark is on, partition the filestruct so that it
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00001606 * contains only the marked text; if the NO_NEWLINES flag isn't
1607 * set, keep track of whether the text will have a magicline
1608 * added when we're done correcting misspelled words; and
1609 * turn the mark off. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001610 mark_order((const filestruct **)&top, &top_x,
1611 (const filestruct **)&bot, &bot_x, &right_side_up);
1612 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00001613 if (!ISSET(NO_NEWLINES))
1614 added_magicline = (openfile->filebot->data[0] != '\0');
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001615 openfile->mark_set = FALSE;
1616 }
1617#endif
1618
1619 /* Start from the top of the file. */
1620 openfile->edittop = openfile->fileage;
1621 openfile->current = openfile->fileage;
1622 openfile->current_x = (size_t)-1;
1623 openfile->placewewant = 0;
1624
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00001625 /* Find the first whole occurrence of word. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001626 findnextstr_wrap_reset();
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00001627 while (findnextstr(TRUE, FALSE, openfile->fileage, 0, word,
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001628 &match_len)) {
1629 if (is_whole_word(openfile->current_x, openfile->current->data,
1630 word)) {
1631 size_t xpt = xplustabs();
1632 char *exp_word = display_string(openfile->current->data,
1633 xpt, strnlenpt(openfile->current->data,
1634 openfile->current_x + match_len) - xpt, FALSE);
1635
1636 edit_refresh();
1637
1638 do_replace_highlight(TRUE, exp_word);
1639
1640 /* Allow all instances of the word to be corrected. */
David Lawrence Ramseye19449e2005-11-07 21:45:44 +00001641 canceled = (do_prompt(FALSE, spell_list, word,
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001642#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001643 NULL,
1644#endif
1645 _("Edit a replacement")) == -1);
1646
1647 do_replace_highlight(FALSE, exp_word);
1648
1649 free(exp_word);
1650
1651 if (!canceled && strcmp(word, answer) != 0) {
1652 openfile->current_x--;
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00001653 do_replace_loop(TRUE, &canceled, openfile->current,
1654 &openfile->current_x, word);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001655 }
1656
1657 break;
1658 }
1659 }
1660
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001661#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001662 if (old_mark_set) {
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00001663 /* If the mark was on, the NO_NEWLINES flag isn't set, and we
1664 * added a magicline, remove it now. */
1665 if (!ISSET(NO_NEWLINES) && added_magicline)
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001666 remove_magicline();
1667
1668 /* Put the beginning and the end of the mark at the beginning
1669 * and the end of the spell-checked text. */
1670 if (openfile->fileage == openfile->filebot)
1671 bot_x += top_x;
1672 if (right_side_up) {
1673 openfile->mark_begin_x = top_x;
1674 current_x_save = bot_x;
1675 } else {
1676 current_x_save = top_x;
1677 openfile->mark_begin_x = bot_x;
1678 }
1679
1680 /* Unpartition the filestruct so that it contains all the text
1681 * again, and turn the mark back on. */
1682 unpartition_filestruct(&filepart);
1683 openfile->mark_set = TRUE;
1684 }
1685#endif
1686
1687 /* Restore the search/replace strings. */
1688 free(last_search);
1689 last_search = save_search;
1690 free(last_replace);
1691 last_replace = save_replace;
1692
1693 /* Restore where we were. */
1694 openfile->edittop = edittop_save;
1695 openfile->current = current_save;
1696 openfile->current_x = current_x_save;
1697 openfile->placewewant = pww_save;
1698
1699 /* Restore case sensitivity setting. */
1700 if (!case_sens_set)
1701 UNSET(CASE_SENSITIVE);
1702
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001703#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001704 /* Restore search/replace direction. */
1705 if (backwards_search_set)
1706 SET(BACKWARDS_SEARCH);
1707#endif
1708#ifdef HAVE_REGEX_H
1709 /* Restore regular expression usage setting. */
1710 if (regexp_set)
1711 SET(USE_REGEXP);
1712#endif
1713
1714 return !canceled;
1715}
1716
1717/* Integrated spell checking using the spell program, filtered through
1718 * the sort and uniq programs. Return NULL for normal termination,
1719 * and the error string otherwise. */
1720const char *do_int_speller(const char *tempfile_name)
1721{
1722 char *read_buff, *read_buff_ptr, *read_buff_word;
1723 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
1724 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
1725 pid_t pid_spell, pid_sort, pid_uniq;
1726 int spell_status, sort_status, uniq_status;
1727
1728 /* Create all three pipes up front. */
1729 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 ||
1730 pipe(uniq_fd) == -1)
1731 return _("Could not create pipe");
1732
1733 statusbar(_("Creating misspelled word list, please wait..."));
1734
1735 /* A new process to run spell in. */
1736 if ((pid_spell = fork()) == 0) {
1737 /* Child continues (i.e, future spell process). */
1738 close(spell_fd[0]);
1739
1740 /* Replace the standard input with the temp file. */
1741 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1742 goto close_pipes_and_exit;
1743
1744 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1745 goto close_pipes_and_exit;
1746
1747 close(tempfile_fd);
1748
1749 /* Send spell's standard output to the pipe. */
1750 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1751 goto close_pipes_and_exit;
1752
1753 close(spell_fd[1]);
1754
1755 /* Start the spell program; we are using PATH. */
1756 execlp("spell", "spell", NULL);
1757
1758 /* This should not be reached if spell is found. */
1759 exit(1);
1760 }
1761
1762 /* Parent continues here. */
1763 close(spell_fd[1]);
1764
1765 /* A new process to run sort in. */
1766 if ((pid_sort = fork()) == 0) {
1767 /* Child continues (i.e, future spell process). Replace the
1768 * standard input with the standard output of the old pipe. */
1769 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1770 goto close_pipes_and_exit;
1771
1772 close(spell_fd[0]);
1773
1774 /* Send sort's standard output to the new pipe. */
1775 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1776 goto close_pipes_and_exit;
1777
1778 close(sort_fd[1]);
1779
1780 /* Start the sort program. Use -f to remove mixed case. If
1781 * this isn't portable, let me know. */
1782 execlp("sort", "sort", "-f", NULL);
1783
1784 /* This should not be reached if sort is found. */
1785 exit(1);
1786 }
1787
1788 close(spell_fd[0]);
1789 close(sort_fd[1]);
1790
1791 /* A new process to run uniq in. */
1792 if ((pid_uniq = fork()) == 0) {
1793 /* Child continues (i.e, future uniq process). Replace the
1794 * standard input with the standard output of the old pipe. */
1795 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1796 goto close_pipes_and_exit;
1797
1798 close(sort_fd[0]);
1799
1800 /* Send uniq's standard output to the new pipe. */
1801 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1802 goto close_pipes_and_exit;
1803
1804 close(uniq_fd[1]);
1805
1806 /* Start the uniq program; we are using PATH. */
1807 execlp("uniq", "uniq", NULL);
1808
1809 /* This should not be reached if uniq is found. */
1810 exit(1);
1811 }
1812
1813 close(sort_fd[0]);
1814 close(uniq_fd[1]);
1815
1816 /* The child process was not forked successfully. */
1817 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1818 close(uniq_fd[0]);
1819 return _("Could not fork");
1820 }
1821
1822 /* Get the system pipe buffer size. */
1823 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1824 close(uniq_fd[0]);
1825 return _("Could not get size of pipe buffer");
1826 }
1827
1828 /* Read in the returned spelling errors. */
1829 read_buff_read = 0;
1830 read_buff_size = pipe_buff_size + 1;
1831 read_buff = read_buff_ptr = charalloc(read_buff_size);
1832
1833 while ((bytesread = read(uniq_fd[0], read_buff_ptr,
1834 pipe_buff_size)) > 0) {
1835 read_buff_read += bytesread;
1836 read_buff_size += pipe_buff_size;
1837 read_buff = read_buff_ptr = charealloc(read_buff,
1838 read_buff_size);
1839 read_buff_ptr += read_buff_read;
1840 }
1841
1842 *read_buff_ptr = '\0';
1843 close(uniq_fd[0]);
1844
1845 /* Process the spelling errors. */
1846 read_buff_word = read_buff_ptr = read_buff;
1847
1848 while (*read_buff_ptr != '\0') {
1849 if ((*read_buff_ptr == '\r') || (*read_buff_ptr == '\n')) {
1850 *read_buff_ptr = '\0';
1851 if (read_buff_word != read_buff_ptr) {
1852 if (!do_int_spell_fix(read_buff_word)) {
1853 read_buff_word = read_buff_ptr;
1854 break;
1855 }
1856 }
1857 read_buff_word = read_buff_ptr + 1;
1858 }
1859 read_buff_ptr++;
1860 }
1861
1862 /* Special case: the last word doesn't end with '\r' or '\n'. */
1863 if (read_buff_word != read_buff_ptr)
1864 do_int_spell_fix(read_buff_word);
1865
1866 free(read_buff);
1867 replace_abort();
1868 edit_refresh();
1869
1870 /* Process the end of the spell process. */
1871 waitpid(pid_spell, &spell_status, 0);
1872 waitpid(pid_sort, &sort_status, 0);
1873 waitpid(pid_uniq, &uniq_status, 0);
1874
1875 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1876 return _("Error invoking \"spell\"");
1877
1878 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1879 return _("Error invoking \"sort -f\"");
1880
1881 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1882 return _("Error invoking \"uniq\"");
1883
1884 /* Otherwise... */
1885 return NULL;
1886
1887 close_pipes_and_exit:
1888 /* Don't leak any handles. */
1889 close(tempfile_fd);
1890 close(spell_fd[0]);
1891 close(spell_fd[1]);
1892 close(sort_fd[0]);
1893 close(sort_fd[1]);
1894 close(uniq_fd[0]);
1895 close(uniq_fd[1]);
1896 exit(1);
1897}
1898
1899/* External spell checking. Return value: NULL for normal termination,
1900 * otherwise the error string. */
1901const char *do_alt_speller(char *tempfile_name)
1902{
1903 int alt_spell_status;
1904 size_t current_x_save = openfile->current_x;
1905 size_t pww_save = openfile->placewewant;
1906 ssize_t current_y_save = openfile->current_y;
1907 ssize_t lineno_save = openfile->current->lineno;
1908 pid_t pid_spell;
1909 char *ptr;
1910 static int arglen = 3;
1911 static char **spellargs = NULL;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001912#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001913 bool old_mark_set = openfile->mark_set;
1914 bool added_magicline = FALSE;
1915 /* Whether we added a magicline after filebot. */
1916 bool right_side_up = FALSE;
1917 /* TRUE if (mark_begin, mark_begin_x) is the top of the mark,
1918 * FALSE if (current, current_x) is. */
1919 filestruct *top, *bot;
1920 size_t top_x, bot_x;
1921 ssize_t mb_lineno_save = 0;
1922 /* We're going to close the current file, and open the output of
1923 * the alternate spell command. The line that mark_begin points
1924 * to will be freed, so we save the line number and restore it
1925 * afterwards. */
1926 size_t totsize_save = openfile->totsize;
1927 /* Our saved value of totsize, used when we spell-check a marked
1928 * selection. */
1929
1930 if (old_mark_set) {
1931 /* If the mark is on, save the number of the line it starts on,
1932 * and then turn the mark off. */
1933 mb_lineno_save = openfile->mark_begin->lineno;
1934 openfile->mark_set = FALSE;
1935 }
1936#endif
1937
1938 endwin();
1939
1940 /* Set up an argument list to pass execvp(). */
1941 if (spellargs == NULL) {
1942 spellargs = (char **)nmalloc(arglen * sizeof(char *));
1943
1944 spellargs[0] = strtok(alt_speller, " ");
1945 while ((ptr = strtok(NULL, " ")) != NULL) {
1946 arglen++;
1947 spellargs = (char **)nrealloc(spellargs, arglen *
1948 sizeof(char *));
1949 spellargs[arglen - 3] = ptr;
1950 }
1951 spellargs[arglen - 1] = NULL;
1952 }
1953 spellargs[arglen - 2] = tempfile_name;
1954
1955 /* Start a new process for the alternate speller. */
1956 if ((pid_spell = fork()) == 0) {
1957 /* Start alternate spell program; we are using PATH. */
1958 execvp(spellargs[0], spellargs);
1959
1960 /* Should not be reached, if alternate speller is found!!! */
1961 exit(1);
1962 }
1963
1964 /* If we couldn't fork, get out. */
1965 if (pid_spell < 0)
1966 return _("Could not fork");
1967
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001968#ifndef NANO_TINY
David Lawrence Ramseyb18482e2005-07-26 00:06:34 +00001969 /* Don't handle a pending SIGWINCH until the alternate spell checker
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00001970 * is finished and we've loaded the spell-checked file back in. */
David Lawrence Ramseyb18482e2005-07-26 00:06:34 +00001971 allow_pending_sigwinch(FALSE);
1972#endif
1973
1974 /* Wait for the alternate spell checker to finish. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001975 wait(&alt_spell_status);
1976
David Lawrence Ramsey84fdb902005-08-14 20:08:49 +00001977 /* Reenter curses mode. */
1978 doupdate();
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001979
1980 /* Restore the terminal to its previous state. */
1981 terminal_init();
1982
1983 /* Turn the cursor back on for sure. */
1984 curs_set(1);
1985
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00001986 /* The screen might have been resized. If it has, reinitialize all
1987 * the windows based on the new screen dimensions. */
1988 window_init();
1989
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001990 if (!WIFEXITED(alt_spell_status) ||
1991 WEXITSTATUS(alt_spell_status) != 0) {
1992 char *altspell_error;
1993 char *invoke_error = _("Error invoking \"%s\"");
1994
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001995#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001996 /* Turn the mark back on if it was on before. */
1997 openfile->mark_set = old_mark_set;
1998#endif
1999
2000 altspell_error =
2001 charalloc(strlen(invoke_error) +
2002 strlen(alt_speller) + 1);
2003 sprintf(altspell_error, invoke_error, alt_speller);
2004 return altspell_error;
2005 }
2006
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002007#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002008 if (old_mark_set) {
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002009 /* If the mark is on, partition the filestruct so that it
2010 * contains only the marked text; if the NO_NEWLINES flag isn't
2011 * set, keep track of whether the text will have a magicline
2012 * added when we're done correcting misspelled words; and
2013 * turn the mark off. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002014 mark_order((const filestruct **)&top, &top_x,
2015 (const filestruct **)&bot, &bot_x, &right_side_up);
2016 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002017 if (!ISSET(NO_NEWLINES))
2018 added_magicline = (openfile->filebot->data[0] != '\0');
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002019
2020 /* Get the number of characters in the marked text, and subtract
2021 * it from the saved value of totsize. */
2022 totsize_save -= get_totsize(top, bot);
2023 }
2024#endif
2025
David Lawrence Ramsey9c984e82005-11-08 19:15:58 +00002026 /* Replace the text of the current buffer with the spell-checked
2027 * text. */
2028 replace_buffer(tempfile_name);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002029
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002030#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002031 if (old_mark_set) {
2032 filestruct *top_save = openfile->fileage;
2033
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002034 /* If the mark was on, the NO_NEWLINES flag isn't set, and we
2035 * added a magicline, remove it now. */
2036 if (!ISSET(NO_NEWLINES) && added_magicline)
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002037 remove_magicline();
2038
2039 /* Put the beginning and the end of the mark at the beginning
2040 * and the end of the spell-checked text. */
2041 if (openfile->fileage == openfile->filebot)
2042 bot_x += top_x;
2043 if (right_side_up) {
2044 openfile->mark_begin_x = top_x;
2045 current_x_save = bot_x;
2046 } else {
2047 current_x_save = top_x;
2048 openfile->mark_begin_x = bot_x;
2049 }
2050
2051 /* Unpartition the filestruct so that it contains all the text
2052 * again. Note that we've replaced the marked text originally
2053 * in the partition with the spell-checked marked text in the
2054 * temp file. */
2055 unpartition_filestruct(&filepart);
2056
2057 /* Renumber starting with the beginning line of the old
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002058 * partition. Also add the number of characters in the
2059 * spell-checked marked text to the saved value of totsize, and
2060 * then make that saved value the actual value. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002061 renumber(top_save);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002062 totsize_save += openfile->totsize;
2063 openfile->totsize = totsize_save;
2064
2065 /* Assign mark_begin to the line where the mark began before. */
2066 do_gotopos(mb_lineno_save, openfile->mark_begin_x,
2067 current_y_save, 0);
2068 openfile->mark_begin = openfile->current;
2069
2070 /* Assign mark_begin_x to the location in mark_begin where the
2071 * mark began before, adjusted for any shortening of the
2072 * line. */
2073 openfile->mark_begin_x = openfile->current_x;
2074
2075 /* Turn the mark back on. */
2076 openfile->mark_set = TRUE;
2077 }
2078#endif
2079
2080 /* Go back to the old position, and mark the file as modified. */
2081 do_gotopos(lineno_save, current_x_save, current_y_save, pww_save);
2082 set_modified();
2083
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002084#ifndef NANO_TINY
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00002085 /* Handle a pending SIGWINCH again. */
2086 allow_pending_sigwinch(TRUE);
2087#endif
2088
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002089 return NULL;
2090}
2091
2092void do_spell(void)
2093{
2094 int i;
2095 FILE *temp_file;
2096 char *temp = safe_tempfile(&temp_file);
2097 const char *spell_msg;
2098
2099 if (temp == NULL) {
2100 statusbar(_("Could not create temp file: %s"), strerror(errno));
2101 return;
2102 }
2103
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002104#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002105 if (openfile->mark_set)
David Lawrence Ramseye014fbd2005-08-29 19:11:26 +00002106 i = write_marked_file(temp, temp_file, TRUE, OVERWRITE);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002107 else
2108#endif
David Lawrence Ramseye014fbd2005-08-29 19:11:26 +00002109 i = write_file(temp, temp_file, TRUE, OVERWRITE, FALSE);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002110
2111 if (i == -1) {
2112 statusbar(_("Error writing temp file: %s"), strerror(errno));
2113 free(temp);
2114 return;
2115 }
2116
2117 spell_msg = (alt_speller != NULL) ? do_alt_speller(temp) :
2118 do_int_speller(temp);
2119 unlink(temp);
2120 free(temp);
2121
2122 /* If the spell-checker printed any error messages onscreen, make
2123 * sure that they're cleared off. */
2124 total_refresh();
2125
2126 if (spell_msg != NULL) {
2127 if (errno == 0)
2128 /* Don't display an error message of "Success". */
2129 statusbar(_("Spell checking failed: %s"), spell_msg);
2130 else
2131 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
2132 strerror(errno));
2133 } else
2134 statusbar(_("Finished checking spelling"));
2135}
2136#endif /* !DISABLE_SPELLER */
2137
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002138#ifndef NANO_TINY
David Lawrence Ramseyd7f0fe92005-08-10 22:51:49 +00002139/* Our own version of "wc". Note that its character counts are in
2140 * multibyte characters instead of single-byte characters. */
David Lawrence Ramsey8e942342005-07-25 04:21:46 +00002141void do_wordlinechar_count(void)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002142{
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002143 size_t words = 0, chars = 0;
2144 ssize_t lines = 0;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002145 size_t current_x_save = openfile->current_x;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002146 size_t pww_save = openfile->placewewant;
2147 filestruct *current_save = openfile->current;
2148 bool old_mark_set = openfile->mark_set;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002149 filestruct *top, *bot;
2150 size_t top_x, bot_x;
2151
2152 if (old_mark_set) {
2153 /* If the mark is on, partition the filestruct so that it
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +00002154 * contains only the marked text, and turn the mark off. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002155 mark_order((const filestruct **)&top, &top_x,
2156 (const filestruct **)&bot, &bot_x, NULL);
2157 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002158 openfile->mark_set = FALSE;
2159 }
2160
2161 /* Start at the top of the file. */
2162 openfile->current = openfile->fileage;
2163 openfile->current_x = 0;
2164 openfile->placewewant = 0;
2165
2166 /* Keep moving to the next word (counting punctuation characters as
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002167 * part of a word, as "wc -w" does), without updating the screen,
2168 * until we reach the end of the file, incrementing the total word
2169 * count whenever we're on a word just before moving. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002170 while (openfile->current != openfile->filebot ||
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +00002171 openfile->current->data[openfile->current_x] != '\0') {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002172 if (do_next_word(TRUE, FALSE))
2173 words++;
2174 }
2175
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002176 /* Get the total line and character counts, as "wc -l" and "wc -c"
2177 * do, but get the latter in multibyte characters. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002178 if (old_mark_set) {
David Lawrence Ramsey78a81b22005-07-25 18:59:24 +00002179 lines = openfile->filebot->lineno -
2180 openfile->fileage->lineno + 1;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002181 chars = get_totsize(openfile->fileage, openfile->filebot);
2182
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002183 /* Unpartition the filestruct so that it contains all the text
2184 * again, and turn the mark back on. */
2185 unpartition_filestruct(&filepart);
2186 openfile->mark_set = TRUE;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002187 } else {
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002188 lines = openfile->filebot->lineno;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002189 chars = openfile->totsize;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002190 }
2191
2192 /* Restore where we were. */
2193 openfile->current = current_save;
2194 openfile->current_x = current_x_save;
2195 openfile->placewewant = pww_save;
2196
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002197 /* Display the total word, line, and character counts on the
2198 * statusbar. */
David Lawrence Ramsey7b71f572005-10-06 20:46:11 +00002199 statusbar(_("%sWords: %lu Lines: %ld Chars: %lu"), old_mark_set ?
David Lawrence Ramsey815fb0a2005-08-05 19:38:11 +00002200 _("In Selection: ") : "", (unsigned long)words, (long)lines,
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002201 (unsigned long)chars);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002202}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002203#endif /* !NANO_TINY */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002204
2205void do_verbatim_input(void)
2206{
2207 int *kbinput;
2208 size_t kbinput_len, i;
2209 char *output;
2210
2211 statusbar(_("Verbatim Input"));
2212
2213 /* If constant cursor position display is on, make sure the current
2214 * cursor position will be properly displayed on the statusbar. */
2215 if (ISSET(CONST_UPDATE))
2216 do_cursorpos(TRUE);
2217
2218 /* Read in all the verbatim characters. */
2219 kbinput = get_verbatim_kbinput(edit, &kbinput_len);
2220
2221 /* Display all the verbatim characters at once, not filtering out
2222 * control characters. */
2223 output = charalloc(kbinput_len + 1);
2224
2225 for (i = 0; i < kbinput_len; i++)
2226 output[i] = (char)kbinput[i];
2227 output[i] = '\0';
2228
2229 do_output(output, kbinput_len, TRUE);
2230
2231 free(output);
2232}