1
2 static char rcsid[] = "@(#)$Id: wordwrap.c,v 1.3 1996/03/14 17:30:00 wfp5p Exp $";
3
4 /*******************************************************************************
5 * The Elm Mail System - $Revision: 1.3 $ $State: Exp $
6 *
7 * Copyright (c) 1988-1995 USENET Community Trust
8 * Copyright (c) 1986,1987 Dave Taylor
9 *******************************************************************************
10 * Bug reports, patches, comments, suggestions should be sent to:
11 *
12 * Bill Pemberton, Elm Coordinator
13 * flash@virginia.edu
14 *
15 *******************************************************************************
16 * $Log: wordwrap.c,v $
17 * Revision 1.3 1996/03/14 17:30:00 wfp5p
18 * Alpha 9
19 *
20 * Revision 1.2 1995/09/29 17:42:38 wfp5p
21 * Alpha 8 (Chip's big changes)
22 *
23 * Revision 1.1.1.1 1995/04/19 20:38:34 wfp5p
24 * Initial import of elm 2.4 PL0 as base for elm 2.5.
25 *
26 ******************************************************************************/
27
28 /*** Routines to wrap lines when using the "builtin" editor
29
30 ***/
31
32 #include "elm_defs.h"
33 #include "elm_globals.h"
34
35 unsigned alarm();
36
37 #define isstopchar(c) (c == ' ' || c == '\t')
38 #define isslash(c) (c == '/')
39 #define erase_a_char() { WriteChar(BACKSPACE); WriteChar(' '); \
40 WriteChar(BACKSPACE); }
41
42 /* WARNING: this macro destroys nr */
43 #define erase_tab(nr) do WriteChar(BACKSPACE); while (--(nr) > 0)
44
45 int
wrapped_enter(string,tail,x,y,edit_fd,append_current)46 wrapped_enter(string, tail, x, y, edit_fd, append_current)
47 char *string, *tail;
48 int x,y, *append_current;
49 FILE *edit_fd;
50
51 {
52 /** This will display the string on the screen and allow the user to
53 either accept it (by pressing RETURN) or alter it according to
54 what the user types. The various flags are:
55 string is the buffer to use (with optional initial value)
56 tail contains the portion of input to be wrapped to the
57 next line
58 x,y is the location we're at on the screen (-1,-1 means
59 that we can't use this info and need to find out
60 the current location)
61 append_current means that we have an initial string and that
62 the cursor should be placed at the END of the line,
63 not the beginning (the default).
64
65 If we hit an interrupt or EOF we'll return non-zero.
66 **/
67
68 int ch, wrapcolumn = 70, iindex = 0;
69 int addon = 0; /* Space added by tabs. iindex+addon == column */
70 int tindex = 0; /* Index to the tabs array. */
71 int tabs[10]; /* Spaces each tab adds. size <= wrapcolumn/8+1 */
72 register int ch_count = 0, escaped = FALSE;
73 long newpos, pos;
74 char line[SLEN];
75
76 if(!(x >=0 && y >= 0))
77 GetCursorPos(&x, &y);
78 PutLine1(x, y, "%s", string);
79
80 CleartoEOLN();
81
82 if (! *append_current) {
83 MoveCursor(x,y);
84 }
85 else
86 iindex = strlen(string);
87
88 /** now we have the screen as we want it and the cursor in the
89 right place, we can loop around on the input and return the
90 string as soon as the user presses <RETURN> or the line wraps.
91 **/
92
93 do {
94 ch = ReadCh();
95
96 if (ch == ctrl('D')) { /* we've hit EOF */
97 *append_current = 0;
98 return(1);
99 }
100
101 if (ch_count++ == 0) {
102 if (ch == '\n' || ch == '\r') {
103 *append_current = 0;
104 return(0);
105 }
106 else if (! *append_current) {
107 CleartoEOLN();
108 iindex = (*append_current? strlen(string) : 0);
109 }
110 }
111
112 if (!escaped) {
113 if (ch == Term.erase_char)
114 ch = ctrl('H');
115 if (ch == Term.kill_char)
116 ch = ctrl('U');
117 }
118
119 switch (ch) {
120
121 case '\n':
122 case '\r':
123 string[iindex] = '\0';
124 *append_current = 0;
125 return(0);
126
127 case '\0':
128 FlushInput(); /* remove extraneous chars, if any */
129 string[0] = '\0'; /* clean up string, and... */
130 *append_current = 0;
131 return(-1);
132
133 case ctrl('H'):
134 if (iindex > 0) {
135 iindex--;
136 if (string[iindex] == '\t') {
137 addon -= tabs[--tindex] - 1;
138 erase_tab(tabs[tindex]);
139 } else erase_a_char();
140
141 #ifdef FTRUNCATE
142
143 } else { /** backspace to end of previous line **/
144
145 fflush(edit_fd);
146 if ((pos = ftell(edit_fd)) <= 0L) { /** no previous line **/
147 Beep();
148
149 } else {
150
151 /** get the last 256 bytes written **/
152 if ((newpos = pos - 256L) <= 0L) newpos = 0;
153 (void) fseek(edit_fd, newpos, 0L);
154 (void) fread(line, sizeof(*line), (int) (pos-newpos),
155 edit_fd);
156 pos--;
157
158 /** the last char in line should be '\n'
159 change it to null **/
160 if (line[(int) (pos-newpos)] == '\n')
161 line[(int) (pos-newpos)] = '\0';
162
163 /** find the end of the previous line ('\n') **/
164 for (pos--; pos > newpos && line[(int) (pos-newpos)] != '\n';
165 pos--);
166 /** check to see if this was the first line in the file **/
167 if (line[(int) (pos-newpos)] == '\n') /** no - it wasn't **/
168 pos++;
169 (void) strcpy(string, &line[(int) (pos-newpos)]);
170 line[(int) (pos-newpos)] = '\0';
171
172 /** truncate the file to the current position
173 THIS WILL NOT WORK ON SYS-V **/
174 (void) fseek(edit_fd, newpos, 0L);
175 (void) fputs(line, edit_fd);
176 fflush(edit_fd);
177 (void) ftruncate(fileno(edit_fd), (int) ftell(edit_fd));
178 (void) fseek(edit_fd, ftell(edit_fd), 0L);
179
180 /** rewrite line on screen and continue working **/
181 GetCursorPos(&x, &y);
182 if (x > 0) x--;
183 PutLine1(x, y, "%s", string);
184 CleartoEOLN();
185 iindex = strlen(string);
186
187 /* Reload tab positions */
188 addon = tindex = 0;
189 for (pos = 0; pos < iindex; pos++)
190 if (string[pos] == '\t')
191 addon += (tabs[tindex++] = 8 - ((pos+addon) & 07)) - 1;
192 }
193
194 #endif
195
196 }
197 break;
198
199 case ctrl('W'):
200 if (iindex == 0)
201 break; /* no point staying here.. */
202 iindex--;
203 if (isslash(string[iindex])) {
204 erase_a_char();
205 }
206 else {
207 while (iindex >= 0 && isspace(string[iindex])) {
208 if (string[iindex] == '\t') {
209 addon -= tabs[--tindex] - 1;
210 erase_tab(tabs[tindex]);
211 } else erase_a_char();
212 iindex--;
213 }
214
215 while (iindex >= 0 && ! isstopchar(string[iindex])) {
216 iindex--;
217 erase_a_char();
218 }
219 iindex++; /* and make sure we point at the first AVAILABLE slot */
220 }
221 break;
222
223 case ctrl('U'):
224 MoveCursor(x,y);
225 CleartoEOLN();
226 iindex = 0;
227 break;
228
229 case ctrl('R'):
230 string[iindex] = '\0';
231 PutLine1(x,y, "%s", string);
232 CleartoEOLN();
233 break;
234
235 default:
236 if (escaped) {
237 WriteChar(BACKSPACE);
238 iindex--;
239 } else if (ch == '\t') {
240 addon += (tabs[tindex++] = 8 - ((addon+iindex) & 07)) - 1;
241 } else if (ch > 0xFF || !isprint(ch)) {
242 Beep();
243 break;
244 }
245 string[iindex++] = ch;
246 WriteChar(ch);
247 break;
248
249 }
250
251 escaped = (!escaped && ch == '\\');
252
253 } while (iindex+addon < wrapcolumn);
254
255 string[iindex] = '\0';
256 *append_current = line_wrap(string,tail,&iindex,&tabs[tindex-1]);
257
258 return(0);
259 }
260
261 int
line_wrap(string,tail,count,tabs)262 line_wrap(string,tail,count,tabs)
263 char *string; /* The string to be wrapped */
264 char *tail; /* The part of the string which is wrapped */
265 int *count; /* Offset of string terminator */
266 int *tabs; /* List of how many spaces each tab adds */
267 {
268 /** This will check for line wrap. If the line was wrapped,
269 it will back up to white space (if possible), write the
270 shortened line, and put the remainder at the beginning
271 of the string. Returns 1 if wrapped, 0 if not.
272 **/
273
274 int n = *count;
275 int i, j;
276
277 /* Look for a space */
278 while (n && !isstopchar(string[n]))
279 --n;
280
281 /* If break found */
282 if (n) {
283
284 /* Copy part to be wrapped */
285 for (i=0,j=n+1;j<=*count;tail[i++]=string[j++]);
286
287 /* Skip the break character and any whitespace */
288 while (n && isstopchar(string[n]))
289 --n;
290
291 if (n) n++; /* Move back into the whitespace */
292 }
293
294 /* If no break found */
295 if (!n) {
296 (*count)--;
297 strcpy(tail, &string[*count]);
298 erase_a_char();
299 } else /* Erase the stuff that will wrap */
300 while (*count > n) {
301 --(*count);
302 if (string[*count] == '\t') erase_tab(*tabs--);
303 else erase_a_char();
304 }
305
306 string[*count] = '\0';
307 return(1);
308 }
309