First bunch of mhl_mem_free removal patches
[midnight-commander.git] / edit / wordproc.c
blobfc16136b143fecbe9eb7a7272b48a2d8b0ced6d9
1 /* wordproc.c - word-processor mode for the editor: does dynamic
2 paragraph formatting.
3 Copyright (C) 1996 Paul Sheer
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 02110-1301, USA.
21 #include <config.h>
23 #include <stdio.h>
24 #include <stdarg.h>
25 #include <sys/types.h>
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif
29 #include <string.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <sys/stat.h>
34 #include <stdlib.h>
36 #include "../src/global.h"
38 #include "edit.h"
39 #include "edit-widget.h"
41 #define tab_width option_tab_spacing
43 #define NO_FORMAT_CHARS_START "-+*\\,.;:&>"
44 #define FONT_MEAN_WIDTH 1
46 static long
47 line_start (WEdit *edit, long line)
49 long p, l;
51 l = edit->curs_line;
52 p = edit->curs1;
54 if (line < l)
55 p = edit_move_backward (edit, p, l - line);
56 else if (line > l)
57 p = edit_move_forward (edit, p, line - l, 0);
59 p = edit_bol (edit, p);
60 while (strchr ("\t ", edit_get_byte (edit, p)))
61 p++;
62 return p;
65 static int bad_line_start (WEdit * edit, long p)
67 int c;
68 c = edit_get_byte (edit, p);
69 if (c == '.') { /* `...' is acceptable */
70 if (edit_get_byte (edit, p + 1) == '.')
71 if (edit_get_byte (edit, p + 2) == '.')
72 return 0;
73 return 1;
75 if (c == '-') {
76 if (edit_get_byte (edit, p + 1) == '-')
77 if (edit_get_byte (edit, p + 2) == '-')
78 return 0; /* `---' is acceptable */
79 return 1;
81 if (strchr (NO_FORMAT_CHARS_START, c))
82 return 1;
83 return 0;
87 * Find the start of the current paragraph for the purpose of formatting.
88 * Return position in the file.
90 static long
91 begin_paragraph (WEdit *edit, int force)
93 int i;
94 for (i = edit->curs_line - 1; i >= 0; i--) {
95 if (line_is_blank (edit, i)) {
96 i++;
97 break;
99 if (force) {
100 if (bad_line_start (edit, line_start (edit, i))) {
101 i++;
102 break;
106 return edit_move_backward (edit, edit_bol (edit, edit->curs1),
107 edit->curs_line - i);
111 * Find the end of the current paragraph for the purpose of formatting.
112 * Return position in the file.
114 static long
115 end_paragraph (WEdit *edit, int force)
117 int i;
118 for (i = edit->curs_line + 1; i <= edit->total_lines; i++) {
119 if (line_is_blank (edit, i)) {
120 i--;
121 break;
123 if (force)
124 if (bad_line_start (edit, line_start (edit, i))) {
125 i--;
126 break;
129 return edit_eol (edit,
130 edit_move_forward (edit, edit_bol (edit, edit->curs1),
131 i - edit->curs_line, 0));
134 static unsigned char *
135 get_paragraph (WEdit *edit, long p, long q, int indent, int *size)
137 unsigned char *s, *t;
138 #if 0
139 t = g_malloc ((q - p) + 2 * (q - p) / option_word_wrap_line_length +
140 10);
141 #else
142 t = g_malloc (2 * (q - p) + 100);
143 #endif
144 if (!t)
145 return 0;
146 for (s = t; p < q; p++, s++) {
147 if (indent)
148 if (edit_get_byte (edit, p - 1) == '\n')
149 while (strchr ("\t ", edit_get_byte (edit, p)))
150 p++;
151 *s = edit_get_byte (edit, p);
153 *size = (unsigned long) s - (unsigned long) t;
154 t[*size] = '\n';
155 return t;
158 static void strip_newlines (unsigned char *t, int size)
160 unsigned char *p = t;
161 while (size--) {
162 *p = *p == '\n' ? ' ' : *p;
163 p++;
168 This is a copy of the function
169 int calc_text_pos (WEdit * edit, long b, long *q, int l)
170 in propfont.c :(
171 It calculates the number of chars in a line specified to length l in pixels
173 static inline int next_tab_pos (int x)
175 return x += tab_width - x % tab_width;
177 static int line_pixel_length (unsigned char *t, long b, int l)
179 int x = 0, c, xn = 0;
180 for (;;) {
181 c = t[b];
182 switch (c) {
183 case '\n':
184 return b;
185 case '\t':
186 xn = next_tab_pos (x);
187 break;
188 default:
189 xn = x + 1;
190 break;
192 if (xn > l)
193 break;
194 x = xn;
195 b++;
197 return b;
200 static int
201 next_word_start (unsigned char *t, int q, int size)
203 int i;
204 int saw_ws = 0;
206 for (i = q; i < size; i++) {
207 switch (t[i]) {
208 case '\n':
209 return -1;
210 case '\t':
211 case ' ':
212 saw_ws = 1;
213 break;
214 default:
215 if (saw_ws != 0)
216 return i;
217 break;
220 return -1;
223 /* find the start of a word */
224 static int
225 word_start (unsigned char *t, int q, int size)
227 int i = q;
228 if (t[q] == ' ' || t[q] == '\t')
229 return next_word_start (t, q, size);
230 for (;;) {
231 int c;
232 if (!i)
233 return -1;
234 c = t[i - 1];
235 if (c == '\n')
236 return -1;
237 if (c == ' ' || c == '\t')
238 return i;
239 i--;
243 /* replaces ' ' with '\n' to properly format a paragraph */
244 static void format_this (unsigned char *t, int size, int indent)
246 int q = 0, ww;
247 strip_newlines (t, size);
248 ww = option_word_wrap_line_length * FONT_MEAN_WIDTH - indent;
249 if (ww < FONT_MEAN_WIDTH * 2)
250 ww = FONT_MEAN_WIDTH * 2;
251 for (;;) {
252 int p;
253 q = line_pixel_length (t, q, ww);
254 if (q > size)
255 break;
256 if (t[q] == '\n')
257 break;
258 p = word_start (t, q, size);
259 if (p == -1)
260 q = next_word_start (t, q, size); /* Return the end of the word if the beginning
261 of the word is at the beginning of a line
262 (i.e. a very long word) */
263 else
264 q = p;
265 if (q == -1) /* end of paragraph */
266 break;
267 if (q)
268 t[q - 1] = '\n';
272 static void replace_at (WEdit * edit, long q, int c)
274 edit_cursor_move (edit, q - edit->curs1);
275 edit_delete (edit);
276 edit_insert_ahead (edit, c);
279 /* replaces a block of text */
280 static void
281 put_paragraph (WEdit * edit, unsigned char *t, long p, int indent, int size)
283 long cursor;
284 int i, c = 0;
285 cursor = edit->curs1;
286 if (indent)
287 while (strchr ("\t ", edit_get_byte (edit, p)))
288 p++;
289 for (i = 0; i < size; i++, p++) {
290 if (i && indent) {
291 if (t[i - 1] == '\n' && c == '\n') {
292 while (strchr ("\t ", edit_get_byte (edit, p)))
293 p++;
294 } else if (t[i - 1] == '\n') {
295 long curs;
296 edit_cursor_move (edit, p - edit->curs1);
297 curs = edit->curs1;
298 edit_insert_indent (edit, indent);
299 if (cursor >= curs)
300 cursor += edit->curs1 - p;
301 p = edit->curs1;
302 } else if (c == '\n') {
303 edit_cursor_move (edit, p - edit->curs1);
304 while (strchr ("\t ", edit_get_byte (edit, p))) {
305 edit_delete (edit);
306 if (cursor > edit->curs1)
307 cursor--;
309 p = edit->curs1;
312 c = edit_get_byte (edit, p);
313 if (c != t[i])
314 replace_at (edit, p, t[i]);
316 edit_cursor_move (edit, cursor - edit->curs1); /* restore cursor position */
319 static int test_indent (WEdit * edit, long p, long q)
321 int indent;
322 indent = edit_indent_width (edit, p++);
323 if (!indent)
324 return 0;
325 for (; p < q; p++)
326 if (edit_get_byte (edit, p - 1) == '\n')
327 if (indent != edit_indent_width (edit, p))
328 return 0;
329 return indent;
332 void
333 format_paragraph (WEdit *edit, int force)
335 long p, q;
336 int size;
337 unsigned char *t;
338 int indent = 0;
339 if (option_word_wrap_line_length < 2)
340 return;
341 if (line_is_blank (edit, edit->curs_line))
342 return;
343 p = begin_paragraph (edit, force);
344 q = end_paragraph (edit, force);
345 indent = test_indent (edit, p, q);
346 t = get_paragraph (edit, p, q, indent, &size);
347 if (!t)
348 return;
349 if (!force) {
350 int i;
351 if (strchr (NO_FORMAT_CHARS_START, *t)) {
352 g_free (t);
353 return;
355 for (i = 0; i < size - 1; i++) {
356 if (t[i] == '\n') {
357 if (strchr (NO_FORMAT_CHARS_START "\t ", t[i + 1])) {
358 g_free (t);
359 return;
364 format_this (t, q - p, indent);
365 put_paragraph (edit, t, p, indent, size);
366 g_free (t);
368 /* Scroll left as much as possible to show the formatted paragraph */
369 edit_scroll_left (edit, -edit->start_col);