Xft support under OpenMotif 2.3.3 - I've been using this for quite a while on
[nedit.git] / source / shift.c
blob5bc68efa377a821c690d1062f6b4f0a25942f3f1
1 static const char CVSID[] = "$Id: shift.c,v 1.18 2006/10/17 10:10:59 yooden Exp $";
2 /*******************************************************************************
3 * *
4 * shift.c -- Nirvana Editor built-in filter commands *
5 * *
6 * Copyright (C) 1999 Mark Edel *
7 * *
8 * This is free software; you can redistribute it and/or modify it under the *
9 * terms of the GNU General Public License as published by the Free Software *
10 * Foundation; either version 2 of the License, or (at your option) any later *
11 * version. In addition, you may distribute version of this program linked to *
12 * Motif or Open Motif. See README for details. *
13 * *
14 * This software is distributed in the hope that it will be useful, but WITHOUT *
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
17 * for more details. *
18 * *
19 * You should have received a copy of the GNU General Public License along with *
20 * software; if not, write to the Free Software Foundation, Inc., 59 Temple *
21 * Place, Suite 330, Boston, MA 02111-1307 USA *
22 * *
23 * Nirvana Text Editor *
24 * June 18, 1991 *
25 * *
26 * Written by Mark Edel *
27 * *
28 *******************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 #include "../config.h"
32 #endif
34 #include "shift.h"
35 #include "textBuf.h"
36 #include "text.h"
37 #include "nedit.h"
38 #include "window.h"
40 #include <string.h>
41 #include <limits.h>
42 #include <ctype.h>
43 #ifdef VMS
44 #include "../util/VMSparam.h"
45 #else
46 #ifndef __MVS__
47 #include <sys/param.h>
48 #endif
49 #endif /*VMS*/
51 #include <Xm/Xm.h>
53 #ifdef HAVE_DEBUG_H
54 #include "../debug.h"
55 #endif
58 static void shiftRect(WindowInfo *window, int direction, int byTab,
59 int selStart, int selEnd, int rectStart, int rectEnd);
60 static void changeCase(WindowInfo *window, int makeUpper);
61 static char *shiftLineRight(char *line, int lineLen, int tabsAllowed,
62 int tabDist, int nChars);
63 static char *shiftLineLeft(char *line, int lineLen, int tabDist, int nChars);
64 static int findLeftMargin(char *text, int length, int tabDist);
65 static char *fillParagraphs(char *text, int rightMargin, int tabDist,
66 int useTabs, char nullSubsChar, int *filledLen, int alignWithFirst);
67 static char *fillParagraph(char *text, int leftMargin, int firstLineIndent,
68 int rightMargin, int tabDist, int allowTabs, char nullSubsChar,
69 int *filledLen);
70 static char *makeIndentString(int indent, int tabDist, int allowTabs, int *nChars);
71 static int atTabStop(int pos, int tabDist);
72 static int nextTab(int pos, int tabDist);
73 static int countLines(const char *text);
74 static int findParagraphStart(textBuffer *buf, int startPos);
75 static int findParagraphEnd(textBuffer *buf, int startPos);
78 ** Shift the selection left or right by a single character, or by one tab stop
79 ** if "byTab" is true. (The length of a tab stop is the size of an emulated
80 ** tab if emulated tabs are turned on, or a hardware tab if not).
82 void ShiftSelection(WindowInfo *window, int direction, int byTab)
84 int selStart, selEnd, isRect, rectStart, rectEnd;
85 int shiftedLen, newEndPos, cursorPos, origLength, emTabDist, shiftDist;
86 char *text, *shiftedText;
87 textBuffer *buf = window->buffer;
89 /* get selection, if no text selected, use current insert position */
90 if (!BufGetSelectionPos(buf, &selStart, &selEnd, &isRect,
91 &rectStart, &rectEnd)) {
92 cursorPos = TextGetCursorPos(window->lastFocus);
93 selStart = BufStartOfLine(buf, cursorPos);
94 selEnd = BufEndOfLine(buf, cursorPos);
95 if (selEnd < buf->length)
96 selEnd++;
97 BufSelect(buf, selStart, selEnd);
98 isRect = False;
99 text = BufGetRange(buf, selStart, selEnd);
100 } else if (isRect) {
101 cursorPos = TextGetCursorPos(window->lastFocus);
102 origLength = buf->length;
103 shiftRect(window, direction, byTab, selStart, selEnd, rectStart,
104 rectEnd);
105 TextSetCursorPos(window->lastFocus, (cursorPos < (selEnd+selStart)/2) ?
106 selStart : cursorPos + (buf->length - origLength));
107 return;
108 } else {
109 selStart = BufStartOfLine(buf, selStart);
110 if (selEnd != 0 && BufGetCharacter(buf, selEnd-1) != '\n') {
111 selEnd = BufEndOfLine(buf, selEnd);
112 if (selEnd < buf->length)
113 selEnd++;
115 BufSelect(buf, selStart, selEnd);
116 text = BufGetRange(buf, selStart, selEnd);
119 /* shift the text by the appropriate distance */
120 if (byTab) {
121 XtVaGetValues(window->textArea, textNemulateTabs, &emTabDist, NULL);
122 shiftDist = emTabDist == 0 ? buf->tabDist : emTabDist;
123 } else
124 shiftDist = 1;
125 shiftedText = ShiftText(text, direction, buf->useTabs, buf->tabDist,
126 shiftDist, &shiftedLen);
127 XtFree(text);
128 BufReplaceSelected(buf, shiftedText);
129 XtFree(shiftedText);
131 newEndPos = selStart + shiftedLen;
132 BufSelect(buf, selStart, newEndPos);
135 static void shiftRect(WindowInfo *window, int direction, int byTab,
136 int selStart, int selEnd, int rectStart, int rectEnd)
138 int offset, emTabDist;
139 textBuffer *tempBuf, *buf = window->buffer;
140 char *text;
142 /* Make sure selStart and SelEnd refer to whole lines */
143 selStart = BufStartOfLine(buf, selStart);
144 selEnd = BufEndOfLine(buf, selEnd);
146 /* Calculate the the left/right offset for the new rectangle */
147 if (byTab) {
148 XtVaGetValues(window->textArea, textNemulateTabs, &emTabDist, NULL);
149 offset = emTabDist == 0 ? buf->tabDist : emTabDist;
150 } else
151 offset = 1;
152 offset *= direction == SHIFT_LEFT ? -1 : 1;
153 if (rectStart + offset < 0)
154 offset = -rectStart;
156 /* Create a temporary buffer for the lines containing the selection, to
157 hide the intermediate steps from the display update routines */
158 tempBuf = BufCreate();
159 tempBuf->tabDist = buf->tabDist;
160 tempBuf->useTabs = buf->useTabs;
161 text = BufGetRange(buf, selStart, selEnd);
162 BufSetAll(tempBuf, text);
163 XtFree(text);
165 /* Do the shift in the temporary buffer */
166 text = BufGetTextInRect(buf, selStart, selEnd, rectStart, rectEnd);
167 BufRemoveRect(tempBuf, 0, selEnd-selStart, rectStart, rectEnd);
168 BufInsertCol(tempBuf, rectStart+offset, 0, text, NULL, NULL);
169 XtFree(text);
171 /* Make the change in the real buffer */
172 BufReplace(buf, selStart, selEnd, BufAsString(tempBuf));
173 BufRectSelect(buf, selStart, selStart + tempBuf->length,
174 rectStart+offset, rectEnd+offset);
175 BufFree(tempBuf);
178 void UpcaseSelection(WindowInfo *window)
180 changeCase(window, True);
183 void DowncaseSelection(WindowInfo *window)
185 changeCase(window, False);
189 ** Capitalize or lowercase the contents of the selection (or of the character
190 ** before the cursor if there is no selection). If "makeUpper" is true,
191 ** change to upper case, otherwise, change to lower case.
193 static void changeCase(WindowInfo *window, int makeUpper)
195 textBuffer *buf = window->buffer;
196 char *text, *c;
197 char oldChar;
198 int cursorPos, start, end, isRect, rectStart, rectEnd;
200 /* Get the selection. Use character before cursor if no selection */
201 if (!BufGetSelectionPos(buf, &start, &end, &isRect, &rectStart, &rectEnd)) {
202 char bufChar[2] = " ";
203 cursorPos = TextGetCursorPos(window->lastFocus);
204 if (cursorPos == 0) {
205 XBell(TheDisplay, 0);
206 return;
208 *bufChar = BufGetCharacter(buf, cursorPos-1);
209 *bufChar = makeUpper ? toupper((unsigned char)*bufChar) :
210 tolower((unsigned char)*bufChar);
211 BufReplace(buf, cursorPos-1, cursorPos, bufChar);
212 } else {
213 Boolean modified = False;
215 text = BufGetSelectionText(buf);
216 for (c = text; *c != '\0'; c++) {
217 oldChar = *c;
218 *c = makeUpper ? toupper((unsigned char)*c) :
219 tolower((unsigned char)*c);
220 if (*c != oldChar) {
221 modified = True;
225 if (modified) {
226 BufReplaceSelected(buf, text);
229 XtFree(text);
230 if (isRect)
231 BufRectSelect(buf, start, end, rectStart, rectEnd);
232 else
233 BufSelect(buf, start, end);
237 void FillSelection(WindowInfo *window)
239 textBuffer *buf = window->buffer;
240 char *text, *filledText;
241 int left, right, nCols, len, isRect, rectStart, rectEnd;
242 int rightMargin, wrapMargin;
243 int insertPos = TextGetCursorPos(window->lastFocus);
244 int hasSelection = window->buffer->primary.selected;
246 /* Find the range of characters and get the text to fill. If there is a
247 selection, use it but extend non-rectangular selections to encompass
248 whole lines. If there is no selection, find the paragraph containing
249 the insertion cursor */
250 if (!BufGetSelectionPos(buf, &left, &right, &isRect, &rectStart, &rectEnd)) {
251 left = findParagraphStart(buf, insertPos);
252 right = findParagraphEnd(buf, insertPos);
253 if (left == right) {
254 XBell(TheDisplay, 0);
255 return;
257 text = BufGetRange(buf, left, right);
258 } else if (isRect) {
259 left = BufStartOfLine(buf, left);
260 right = BufEndOfLine(buf, right);
261 text = BufGetTextInRect(buf, left, right, rectStart, INT_MAX);
262 } else {
263 left = BufStartOfLine(buf, left);
264 if (right != 0 && BufGetCharacter(buf, right-1) != '\n') {
265 right = BufEndOfLine(buf, right);
266 if (right < buf->length)
267 right++;
269 BufSelect(buf, left, right);
270 text = BufGetRange(buf, left, right);
273 /* Find right margin either as specified in the rectangular selection, or
274 by measuring the text and querying the window's wrap margin (or width) */
275 if (hasSelection && isRect) {
276 rightMargin = rectEnd - rectStart;
277 } else
279 XtVaGetValues(window->textArea,
280 textNcolumns, &nCols,
281 textNwrapMargin, &wrapMargin,
282 NULL);
283 rightMargin = (wrapMargin == 0 ? nCols : wrapMargin);
286 /* Fill the text */
287 filledText = fillParagraphs(text, rightMargin, buf->tabDist, buf->useTabs,
288 buf->nullSubsChar, &len, False);
289 XtFree(text);
291 /* Replace the text in the window */
292 if (hasSelection && isRect) {
293 BufReplaceRect(buf, left, right, rectStart, INT_MAX, filledText);
294 BufRectSelect(buf, left,
295 BufEndOfLine(buf, BufCountForwardNLines(buf, left,
296 countLines(filledText)-1)), rectStart, rectEnd);
297 } else {
298 BufReplace(buf, left, right, filledText);
299 if (hasSelection)
300 BufSelect(buf, left, left + len);
302 XtFree(filledText);
304 /* Find a reasonable cursor position. Usually insertPos is best, but
305 if the text was indented, positions can shift */
306 if (hasSelection && isRect)
307 TextSetCursorPos(window->lastFocus, buf->cursorPosHint);
308 else
309 TextSetCursorPos(window->lastFocus, insertPos < left ? left :
310 (insertPos > left + len ? left + len : insertPos));
314 ** shift lines left and right in a multi-line text string. Returns the
315 ** shifted text in memory that must be freed by the caller with XtFree.
317 char *ShiftText(char *text, int direction, int tabsAllowed, int tabDist,
318 int nChars, int *newLen)
320 char *shiftedText, *shiftedLine;
321 char *textPtr, *lineStartPtr, *shiftedPtr;
322 int bufLen;
325 ** Allocate memory for shifted string. Shift left adds a maximum of
326 ** tabDist-2 characters per line (remove one tab, add tabDist-1 spaces).
327 ** Shift right adds a maximum of nChars character per line.
329 if (direction == SHIFT_RIGHT)
330 bufLen = strlen(text) + countLines(text) * nChars;
331 else
332 bufLen = strlen(text) + countLines(text) * tabDist;
333 shiftedText = (char *)XtMalloc(bufLen + 1);
336 ** break into lines and call shiftLine(Left/Right) on each
338 lineStartPtr = text;
339 textPtr = text;
340 shiftedPtr = shiftedText;
341 while (TRUE) {
342 if (*textPtr=='\n' || *textPtr=='\0') {
343 shiftedLine = (direction == SHIFT_RIGHT) ?
344 shiftLineRight(lineStartPtr, textPtr-lineStartPtr,
345 tabsAllowed, tabDist, nChars) :
346 shiftLineLeft(lineStartPtr, textPtr-lineStartPtr, tabDist,
347 nChars);
348 strcpy(shiftedPtr, shiftedLine);
349 shiftedPtr += strlen(shiftedLine);
350 XtFree(shiftedLine);
351 if (*textPtr == '\0') {
352 /* terminate string & exit loop at end of text */
353 *shiftedPtr = '\0';
354 break;
355 } else {
356 /* move the newline from text to shifted text */
357 *shiftedPtr++ = *textPtr++;
359 /* start line over */
360 lineStartPtr = textPtr;
361 } else
362 textPtr++;
364 *newLen = shiftedPtr - shiftedText;
365 return shiftedText;
368 static char *shiftLineRight(char *line, int lineLen, int tabsAllowed,
369 int tabDist, int nChars)
371 char *lineOut;
372 char *lineInPtr, *lineOutPtr;
373 int whiteWidth, i;
375 lineInPtr = line;
376 lineOut = XtMalloc(lineLen + nChars + 1);
377 lineOutPtr = lineOut;
378 whiteWidth = 0;
379 while (TRUE) {
380 if (*lineInPtr == '\0' || (lineInPtr - line) >= lineLen) {
381 /* nothing on line, wipe it out */
382 *lineOut = '\0';
383 return lineOut;
384 } else if (*lineInPtr == ' ') {
385 /* white space continues with tab, advance to next tab stop */
386 whiteWidth++;
387 *lineOutPtr++ = *lineInPtr++;
388 } else if (*lineInPtr == '\t') {
389 /* white space continues with tab, advance to next tab stop */
390 whiteWidth = nextTab(whiteWidth, tabDist);
391 *lineOutPtr++ = *lineInPtr++;
392 } else {
393 /* end of white space, add nChars of space */
394 for (i=0; i<nChars; i++) {
395 *lineOutPtr++ = ' ';
396 whiteWidth++;
397 /* if we're now at a tab stop, change last 8 spaces to a tab */
398 if (tabsAllowed && atTabStop(whiteWidth, tabDist)) {
399 lineOutPtr -= tabDist;
400 *lineOutPtr++ = '\t';
403 /* move remainder of line */
404 while (*lineInPtr!='\0' && (lineInPtr - line) < lineLen)
405 *lineOutPtr++ = *lineInPtr++;
406 *lineOutPtr = '\0';
407 return lineOut;
412 static char *shiftLineLeft(char *line, int lineLen, int tabDist, int nChars)
414 char *lineOut;
415 int i, whiteWidth, lastWhiteWidth, whiteGoal;
416 char *lineInPtr, *lineOutPtr;
418 lineInPtr = line;
419 lineOut = XtMalloc(lineLen + tabDist + 1);
420 lineOutPtr = lineOut;
421 whiteWidth = 0;
422 lastWhiteWidth = 0;
423 while (TRUE) {
424 if (*lineInPtr == '\0' || (lineInPtr - line) >= lineLen) {
425 /* nothing on line, wipe it out */
426 *lineOut = '\0';
427 return lineOut;
428 } else if (*lineInPtr == ' ') {
429 /* white space continues with space, advance one character */
430 whiteWidth++;
431 *lineOutPtr++ = *lineInPtr++;
432 } else if (*lineInPtr == '\t') {
433 /* white space continues with tab, advance to next tab stop */
434 /* save the position, though, in case we need to remove the tab */
435 lastWhiteWidth = whiteWidth;
436 whiteWidth = nextTab(whiteWidth, tabDist);
437 *lineOutPtr++ = *lineInPtr++;
438 } else {
439 /* end of white space, remove nChars characters */
440 for (i=1; i<=nChars; i++) {
441 if (lineOutPtr > lineOut) {
442 if (*(lineOutPtr-1) == ' ') {
443 /* end of white space is a space, just remove it */
444 lineOutPtr--;
445 } else {
446 /* end of white space is a tab, remove it and add
447 back spaces */
448 lineOutPtr--;
449 whiteGoal = whiteWidth - i;
450 whiteWidth = lastWhiteWidth;
451 while (whiteWidth < whiteGoal) {
452 *lineOutPtr++ = ' ';
453 whiteWidth++;
458 /* move remainder of line */
459 while (*lineInPtr!='\0' && (lineInPtr - line) < lineLen)
460 *lineOutPtr++ = *lineInPtr++;
461 /* add a null */
462 *lineOutPtr = '\0';
463 return lineOut;
468 static int atTabStop(int pos, int tabDist)
470 return (pos%tabDist == 0);
473 static int nextTab(int pos, int tabDist)
475 return (pos/tabDist)*tabDist + tabDist;
478 static int countLines(const char *text)
480 int count = 1;
482 while(*text != '\0') {
483 if (*text++ == '\n') {
484 count++;
487 return count;
491 ** Find the implied left margin of a text string (the number of columns to the
492 ** first non-whitespace character on any line) up to either the terminating
493 ** null character at the end of the string, or "length" characters, whever
494 ** comes first.
496 static int findLeftMargin(char *text, int length, int tabDist)
498 char *c;
499 int col = 0, leftMargin = INT_MAX;
500 int inMargin = True;
502 for (c=text; *c!='\0' && c-text<length; c++) {
503 if (*c == '\t') {
504 col += BufCharWidth('\t', col, tabDist, '\0');
505 } else if (*c == ' ') {
506 col++;
507 } else if (*c == '\n') {
508 col = 0;
509 inMargin = True;
510 } else {
511 /* non-whitespace */
512 if (col < leftMargin && inMargin)
513 leftMargin = col;
514 inMargin = False;
518 /* if no non-white text is found, the leftMargin will never be set */
519 if (leftMargin == INT_MAX)
520 return 0;
522 return leftMargin;
526 ** Fill multiple paragraphs between rightMargin and an implied left margin
527 ** and first line indent determined by analyzing the text. alignWithFirst
528 ** aligns subsequent paragraphs with the margins of the first paragraph (a
529 ** capability not currently used in NEdit, but carried over from code for
530 ** previous versions which did all paragraphs together).
532 static char *fillParagraphs(char *text, int rightMargin, int tabDist,
533 int useTabs, char nullSubsChar, int *filledLen, int alignWithFirst)
535 int paraStart, paraEnd, fillEnd;
536 char *c, ch, *secondLineStart, *paraText, *filledText;
537 int firstLineLen, firstLineIndent, leftMargin, len;
538 textBuffer *buf;
540 /* Create a buffer to accumulate the filled paragraphs */
541 buf = BufCreate();
542 BufSetAll(buf, text);
545 ** Loop over paragraphs, filling each one, and accumulating the results
546 ** in buf
548 paraStart = 0;
549 for (;;) {
551 /* Skip over white space */
552 while (paraStart < buf->length) {
553 ch = BufGetCharacter(buf, paraStart);
554 if (ch != ' ' && ch != '\t' && ch != '\n')
555 break;
556 paraStart++;
558 if (paraStart >= buf->length)
559 break;
560 paraStart = BufStartOfLine(buf, paraStart);
562 /* Find the end of the paragraph */
563 paraEnd = findParagraphEnd(buf, paraStart);
565 /* Operate on either the one paragraph, or to make them all identical,
566 do all of them together (fill paragraph can format all the paragraphs
567 it finds with identical specs if it gets passed more than one) */
568 fillEnd = alignWithFirst ? buf->length : paraEnd;
570 /* Get the paragraph in a text string (or all of the paragraphs if
571 we're making them all the same) */
572 paraText = BufGetRange(buf, paraStart, fillEnd);
574 /* Find separate left margins for the first and for the first line of
575 the paragraph, and for rest of the remainder of the paragraph */
576 for (c=paraText ; *c!='\0' && *c!='\n'; c++);
577 firstLineLen = c - paraText;
578 secondLineStart = *c == '\0' ? paraText : c + 1;
579 firstLineIndent = findLeftMargin(paraText, firstLineLen, tabDist);
580 leftMargin = findLeftMargin(secondLineStart, paraEnd - paraStart -
581 (secondLineStart - paraText), tabDist);
583 /* Fill the paragraph */
584 filledText = fillParagraph(paraText, leftMargin, firstLineIndent,
585 rightMargin, tabDist, useTabs, nullSubsChar, &len);
586 XtFree(paraText);
588 /* Replace it in the buffer */
589 BufReplace(buf, paraStart, fillEnd, filledText);
590 XtFree(filledText);
592 /* move on to the next paragraph */
593 paraStart += len;
596 /* Free the buffer and return its contents */
597 filledText = BufGetAll(buf);
598 *filledLen = buf->length;
599 BufFree(buf);
600 return filledText;
604 ** Trim leading space, and arrange text to fill between leftMargin and
605 ** rightMargin (except for the first line which fills from firstLineIndent),
606 ** re-creating whitespace to the left of the text using tabs (if allowTabs is
607 ** True) calculated using tabDist, and spaces. Returns a newly allocated
608 ** string as the function result, and the length of the new string in filledLen.
610 static char *fillParagraph(char *text, int leftMargin, int firstLineIndent,
611 int rightMargin, int tabDist, int allowTabs, char nullSubsChar,
612 int *filledLen)
614 char *cleanedText, *outText, *indentString, *leadIndentStr, *outPtr, *c, *b;
615 int col, cleanedLen, indentLen, leadIndentLen, nLines = 1;
616 int inWhitespace, inMargin;
618 /* remove leading spaces, convert newlines to spaces */
619 cleanedText = XtMalloc(strlen(text)+1);
620 outPtr = cleanedText;
621 inMargin = True;
622 for (c=text; *c!='\0'; c++) {
623 if (*c == '\t' || *c == ' ') {
624 if (!inMargin)
625 *outPtr++ = *c;
626 } else if (*c == '\n') {
627 if (inMargin) {
628 /* a newline before any text separates paragraphs, so leave
629 it in, back up, and convert the previous space back to \n */
630 if (outPtr > cleanedText && *(outPtr-1) == ' ')
631 *(outPtr-1) = '\n';
632 *outPtr++ = '\n';
633 nLines +=2;
634 } else
635 *outPtr++ = ' ';
636 inMargin = True;
637 } else {
638 *outPtr++ = *c;
639 inMargin = False;
642 cleanedLen = outPtr - cleanedText;
643 *outPtr = '\0';
645 /* Put back newlines breaking text at word boundaries within the margins.
646 Algorithm: scan through characters, counting columns, and when the
647 margin width is exceeded, search backward for beginning of the word
648 and convert the last whitespace character into a newline */
649 col = firstLineIndent;
650 for (c=cleanedText; *c!='\0'; c++) {
651 if (*c == '\n')
652 col = leftMargin;
653 else
654 col += BufCharWidth(*c, col, tabDist, nullSubsChar);
655 if (col-1 > rightMargin) {
656 inWhitespace = True;
657 for (b=c; b>=cleanedText && *b!='\n'; b--) {
658 if (*b == '\t' || *b == ' ') {
659 if (!inWhitespace) {
660 *b = '\n';
661 c = b;
662 col = leftMargin;
663 nLines++;
664 break;
666 } else
667 inWhitespace = False;
671 nLines++;
673 /* produce a string to prepend to lines to indent them to the left margin */
674 leadIndentStr = makeIndentString(firstLineIndent, tabDist,
675 allowTabs, &leadIndentLen);
676 indentString = makeIndentString(leftMargin, tabDist, allowTabs, &indentLen);
678 /* allocate memory for the finished string */
679 outText = XtMalloc(sizeof(char) * (cleanedLen + leadIndentLen +
680 indentLen * (nLines-1) + 1));
681 outPtr = outText;
683 /* prepend the indent string to each line of the filled text */
684 strncpy(outPtr, leadIndentStr, leadIndentLen);
685 outPtr += leadIndentLen;
686 for (c=cleanedText; *c!='\0'; c++) {
687 *outPtr++ = *c;
688 if (*c == '\n') {
689 strncpy(outPtr, indentString, indentLen);
690 outPtr += indentLen;
694 /* convert any trailing space to newline. Add terminating null */
695 if (*(outPtr-1) == ' ')
696 *(outPtr-1) = '\n';
697 *outPtr = '\0';
699 /* clean up, return result */
700 XtFree(cleanedText);
701 XtFree(leadIndentStr);
702 XtFree(indentString);
703 *filledLen = outPtr - outText;
704 return outText;
707 static char *makeIndentString(int indent, int tabDist, int allowTabs, int *nChars)
709 char *indentString, *outPtr;
710 int i;
712 outPtr = indentString = XtMalloc(sizeof(char) * indent + 1);
713 if (allowTabs) {
714 for (i=0; i<indent/tabDist; i++)
715 *outPtr++ = '\t';
716 for (i=0; i<indent%tabDist; i++)
717 *outPtr++ = ' ';
718 } else {
719 for (i=0; i<indent; i++)
720 *outPtr++ = ' ';
722 *outPtr = '\0';
723 *nChars = outPtr - indentString;
724 return indentString;
728 ** Find the boundaries of the paragraph containing pos
730 static int findParagraphEnd(textBuffer *buf, int startPos)
732 char c;
733 int pos;
734 static char whiteChars[] = " \t";
736 pos = BufEndOfLine(buf, startPos)+1;
737 while (pos < buf->length) {
738 c = BufGetCharacter(buf, pos);
739 if (c == '\n')
740 break;
741 if (strchr(whiteChars, c) != NULL)
742 pos++;
743 else
744 pos = BufEndOfLine(buf, pos)+1;
746 return pos < buf->length ? pos : buf->length;
748 static int findParagraphStart(textBuffer *buf, int startPos)
750 char c;
751 int pos, parStart;
752 static char whiteChars[] = " \t";
754 if (startPos == 0)
755 return 0;
756 parStart = BufStartOfLine(buf, startPos);
757 pos = parStart - 2;
758 while (pos > 0) {
759 c = BufGetCharacter(buf, pos);
760 if (c == '\n')
761 break;
762 if (strchr(whiteChars, c) != NULL)
763 pos--;
764 else {
765 parStart = BufStartOfLine(buf, pos);
766 pos = parStart - 2;
769 return parStart > 0 ? parStart : 0;