More detail for Motif version, and change button labels on help browser to be more...
[nedit.git] / source / shift.c
bloba1664f059c7d346614a36311ebb882dd42391044
1 static const char CVSID[] = "$Id: shift.c,v 1.13 2002/07/11 21:18:10 slobasso 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. *
12 * *
13 * This software is distributed in the hope that it will be useful, but WITHOUT *
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
16 * for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License along with *
19 * software; if not, write to the Free Software Foundation, Inc., 59 Temple *
20 * Place, Suite 330, Boston, MA 02111-1307 USA *
21 * *
22 * Nirvana Text Editor *
23 * June 18, 1991 *
24 * *
25 * Written by Mark Edel *
26 * *
27 *******************************************************************************/
29 #ifdef HAVE_CONFIG_H
30 #include "../config.h"
31 #endif
33 #include "shift.h"
34 #include "textBuf.h"
35 #include "text.h"
36 #include "nedit.h"
37 #include "window.h"
38 #include "../util/DialogF.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 text = BufGetAll(tempBuf);
173 BufReplace(buf, selStart, selEnd, text);
174 XtFree(text);
175 BufRectSelect(buf, selStart, selStart + tempBuf->length,
176 rectStart+offset, rectEnd+offset);
177 BufFree(tempBuf);
180 void UpcaseSelection(WindowInfo *window)
182 changeCase(window, True);
185 void DowncaseSelection(WindowInfo *window)
187 changeCase(window, False);
191 ** Capitalize or lowercase the contents of the selection (or of the character
192 ** before the cursor if there is no selection). If "makeUpper" is true,
193 ** change to upper case, otherwise, change to lower case.
195 static void changeCase(WindowInfo *window, int makeUpper)
197 textBuffer *buf = window->buffer;
198 char *text, *c;
199 int cursorPos, start, end, isRect, rectStart, rectEnd;
201 /* Get the selection. Use character before cursor if no selection */
202 if (!BufGetSelectionPos(buf, &start, &end, &isRect, &rectStart, &rectEnd)) {
203 char bufChar[2] = " ";
204 cursorPos = TextGetCursorPos(window->lastFocus);
205 if (cursorPos == 0) {
206 XBell(TheDisplay, 0);
207 return;
209 *bufChar = BufGetCharacter(buf, cursorPos-1);
210 *bufChar = makeUpper ? toupper((unsigned char)*bufChar) :
211 tolower((unsigned char)*bufChar);
212 BufReplace(buf, cursorPos-1, cursorPos, bufChar);
213 } else {
214 text = BufGetSelectionText(buf);
215 for (c=text; *c!='\0'; c++)
216 *c = makeUpper ? toupper((unsigned char)*c) :
217 tolower((unsigned char)*c);
218 BufReplaceSelected(buf, text);
219 XtFree(text);
220 if (isRect)
221 BufRectSelect(buf, start, end, rectStart, rectEnd);
222 else
223 BufSelect(buf, start, end);
227 void FillSelection(WindowInfo *window)
229 textBuffer *buf = window->buffer;
230 char *text, *filledText;
231 int left, right, nCols, len, isRect, rectStart, rectEnd;
232 int rightMargin, wrapMargin;
233 int insertPos = TextGetCursorPos(window->lastFocus);
234 int hasSelection = window->buffer->primary.selected;
236 /* Find the range of characters and get the text to fill. If there is a
237 selection, use it but extend non-rectangular selections to encompass
238 whole lines. If there is no selection, find the paragraph containing
239 the insertion cursor */
240 if (!BufGetSelectionPos(buf, &left, &right, &isRect, &rectStart, &rectEnd)) {
241 left = findParagraphStart(buf, insertPos);
242 right = findParagraphEnd(buf, insertPos);
243 if (left == right) {
244 XBell(TheDisplay, 0);
245 return;
247 text = BufGetRange(buf, left, right);
248 } else if (isRect) {
249 left = BufStartOfLine(buf, left);
250 right = BufEndOfLine(buf, right);
251 text = BufGetTextInRect(buf, left, right, rectStart, INT_MAX);
252 } else {
253 left = BufStartOfLine(buf, left);
254 if (right != 0 && BufGetCharacter(buf, right-1) != '\n') {
255 right = BufEndOfLine(buf, right);
256 if (right < buf->length)
257 right++;
259 BufSelect(buf, left, right);
260 text = BufGetRange(buf, left, right);
263 /* Find right margin either as specified in the rectangular selection, or
264 by measuring the text and querying the window's wrap margin (or width) */
265 if (hasSelection && isRect) {
266 rightMargin = rectEnd - rectStart;
267 } else {
268 XtVaGetValues(window->textArea, textNcolumns, &nCols,
269 textNwrapMargin, &wrapMargin, NULL);
270 rightMargin = (wrapMargin == 0 ? nCols : wrapMargin) - 1;
273 /* Fill the text */
274 filledText = fillParagraphs(text, rightMargin, buf->tabDist, buf->useTabs,
275 buf->nullSubsChar, &len, False);
276 XtFree(text);
278 /* Replace the text in the window */
279 if (hasSelection && isRect) {
280 BufReplaceRect(buf, left, right, rectStart, INT_MAX, filledText);
281 BufRectSelect(buf, left,
282 BufEndOfLine(buf, BufCountForwardNLines(buf, left,
283 countLines(filledText)-1)), rectStart, rectEnd);
284 } else {
285 BufReplace(buf, left, right, filledText);
286 if (hasSelection)
287 BufSelect(buf, left, left + len);
289 XtFree(filledText);
291 /* Find a reasonable cursor position. Usually insertPos is best, but
292 if the text was indented, positions can shift */
293 if (hasSelection && isRect)
294 TextSetCursorPos(window->lastFocus, buf->cursorPosHint);
295 else
296 TextSetCursorPos(window->lastFocus, insertPos < left ? left :
297 (insertPos > left + len ? left + len : insertPos));
301 ** shift lines left and right in a multi-line text string. Returns the
302 ** shifted text in memory that must be freed by the caller with XtFree.
304 char *ShiftText(char *text, int direction, int tabsAllowed, int tabDist,
305 int nChars, int *newLen)
307 char *shiftedText, *shiftedLine;
308 char *textPtr, *lineStartPtr, *shiftedPtr;
309 int bufLen;
312 ** Allocate memory for shifted string. Shift left adds a maximum of
313 ** tabDist-2 characters per line (remove one tab, add tabDist-1 spaces).
314 ** Shift right adds a maximum of nChars character per line.
316 if (direction == SHIFT_RIGHT)
317 bufLen = strlen(text) + countLines(text) * nChars;
318 else
319 bufLen = strlen(text) + countLines(text) * tabDist;
320 shiftedText = (char *)XtMalloc(bufLen + 1);
323 ** break into lines and call shiftLine(Left/Right) on each
325 lineStartPtr = text;
326 textPtr = text;
327 shiftedPtr = shiftedText;
328 while (TRUE) {
329 if (*textPtr=='\n' || *textPtr=='\0') {
330 shiftedLine = (direction == SHIFT_RIGHT) ?
331 shiftLineRight(lineStartPtr, textPtr-lineStartPtr,
332 tabsAllowed, tabDist, nChars) :
333 shiftLineLeft(lineStartPtr, textPtr-lineStartPtr, tabDist,
334 nChars);
335 strcpy(shiftedPtr, shiftedLine);
336 shiftedPtr += strlen(shiftedLine);
337 XtFree(shiftedLine);
338 if (*textPtr == '\0') {
339 /* terminate string & exit loop at end of text */
340 *shiftedPtr = '\0';
341 break;
342 } else {
343 /* move the newline from text to shifted text */
344 *shiftedPtr++ = *textPtr++;
346 /* start line over */
347 lineStartPtr = textPtr;
348 } else
349 textPtr++;
351 *newLen = shiftedPtr - shiftedText;
352 return shiftedText;
355 static char *shiftLineRight(char *line, int lineLen, int tabsAllowed,
356 int tabDist, int nChars)
358 char *lineOut;
359 char *lineInPtr, *lineOutPtr;
360 int whiteWidth, i;
362 lineInPtr = line;
363 lineOut = XtMalloc(lineLen + nChars + 1);
364 lineOutPtr = lineOut;
365 whiteWidth = 0;
366 while (TRUE) {
367 if (*lineInPtr == '\0' || (lineInPtr - line) >= lineLen) {
368 /* nothing on line, wipe it out */
369 *lineOut = '\0';
370 return lineOut;
371 } else if (*lineInPtr == ' ') {
372 /* white space continues with tab, advance to next tab stop */
373 whiteWidth++;
374 *lineOutPtr++ = *lineInPtr++;
375 } else if (*lineInPtr == '\t') {
376 /* white space continues with tab, advance to next tab stop */
377 whiteWidth = nextTab(whiteWidth, tabDist);
378 *lineOutPtr++ = *lineInPtr++;
379 } else {
380 /* end of white space, add nChars of space */
381 for (i=0; i<nChars; i++) {
382 *lineOutPtr++ = ' ';
383 whiteWidth++;
384 /* if we're now at a tab stop, change last 8 spaces to a tab */
385 if (tabsAllowed && atTabStop(whiteWidth, tabDist)) {
386 lineOutPtr -= tabDist;
387 *lineOutPtr++ = '\t';
390 /* move remainder of line */
391 while (*lineInPtr!='\0' && (lineInPtr - line) < lineLen)
392 *lineOutPtr++ = *lineInPtr++;
393 *lineOutPtr = '\0';
394 return lineOut;
399 static char *shiftLineLeft(char *line, int lineLen, int tabDist, int nChars)
401 char *lineOut;
402 int i, whiteWidth, lastWhiteWidth, whiteGoal;
403 char *lineInPtr, *lineOutPtr;
405 lineInPtr = line;
406 lineOut = XtMalloc(lineLen + tabDist + 1);
407 lineOutPtr = lineOut;
408 whiteWidth = 0;
409 lastWhiteWidth = 0;
410 while (TRUE) {
411 if (*lineInPtr == '\0' || (lineInPtr - line) >= lineLen) {
412 /* nothing on line, wipe it out */
413 *lineOut = '\0';
414 return lineOut;
415 } else if (*lineInPtr == ' ') {
416 /* white space continues with space, advance one character */
417 whiteWidth++;
418 *lineOutPtr++ = *lineInPtr++;
419 } else if (*lineInPtr == '\t') {
420 /* white space continues with tab, advance to next tab stop */
421 /* save the position, though, in case we need to remove the tab */
422 lastWhiteWidth = whiteWidth;
423 whiteWidth = nextTab(whiteWidth, tabDist);
424 *lineOutPtr++ = *lineInPtr++;
425 } else {
426 /* end of white space, remove nChars characters */
427 for (i=1; i<=nChars; i++) {
428 if (lineOutPtr > lineOut) {
429 if (*(lineOutPtr-1) == ' ') {
430 /* end of white space is a space, just remove it */
431 lineOutPtr--;
432 } else {
433 /* end of white space is a tab, remove it and add
434 back spaces */
435 lineOutPtr--;
436 whiteGoal = whiteWidth - i;
437 whiteWidth = lastWhiteWidth;
438 while (whiteWidth < whiteGoal) {
439 *lineOutPtr++ = ' ';
440 whiteWidth++;
445 /* move remainder of line */
446 while (*lineInPtr!='\0' && (lineInPtr - line) < lineLen)
447 *lineOutPtr++ = *lineInPtr++;
448 /* add a null */
449 *lineOutPtr = '\0';
450 return lineOut;
455 static int atTabStop(int pos, int tabDist)
457 return (pos%tabDist == 0);
460 static int nextTab(int pos, int tabDist)
462 return (pos/tabDist)*tabDist + tabDist;
465 static int countLines(const char *text)
467 int count = 1;
469 while(*text != '\0') {
470 if (*text++ == '\n') {
471 count++;
474 return count;
478 ** Find the implied left margin of a text string (the number of columns to the
479 ** first non-whitespace character on any line) up to either the terminating
480 ** null character at the end of the string, or "length" characters, whever
481 ** comes first.
483 static int findLeftMargin(char *text, int length, int tabDist)
485 char *c;
486 int col = 0, leftMargin = INT_MAX;
487 int inMargin = True;
489 for (c=text; *c!='\0' && c-text<length; c++) {
490 if (*c == '\t') {
491 col += BufCharWidth('\t', col, tabDist, '\0');
492 } else if (*c == ' ') {
493 col++;
494 } else if (*c == '\n') {
495 col = 0;
496 inMargin = True;
497 } else {
498 /* non-whitespace */
499 if (col < leftMargin && inMargin)
500 leftMargin = col;
501 inMargin = False;
505 /* if no non-white text is found, the leftMargin will never be set */
506 if (leftMargin == INT_MAX)
507 return 0;
509 return leftMargin;
513 ** Fill multiple paragraphs between rightMargin and an implied left margin
514 ** and first line indent determined by analyzing the text. alignWithFirst
515 ** aligns subsequent paragraphs with the margins of the first paragraph (a
516 ** capability not currently used in NEdit, but carried over from code for
517 ** previous versions which did all paragraphs together).
519 static char *fillParagraphs(char *text, int rightMargin, int tabDist,
520 int useTabs, char nullSubsChar, int *filledLen, int alignWithFirst)
522 int paraStart, paraEnd, fillEnd;
523 char *c, ch, *secondLineStart, *paraText, *filledText;
524 int firstLineLen, firstLineIndent, leftMargin, len;
525 textBuffer *buf;
527 /* Create a buffer to accumulate the filled paragraphs */
528 buf = BufCreate();
529 BufSetAll(buf, text);
532 ** Loop over paragraphs, filling each one, and accumulating the results
533 ** in buf
535 paraStart = 0;
536 for (;;) {
538 /* Skip over white space */
539 while (paraStart < buf->length) {
540 ch = BufGetCharacter(buf, paraStart);
541 if (ch != ' ' && ch != '\t' && ch != '\n')
542 break;
543 paraStart++;
545 if (paraStart >= buf->length)
546 break;
547 paraStart = BufStartOfLine(buf, paraStart);
549 /* Find the end of the paragraph */
550 paraEnd = findParagraphEnd(buf, paraStart);
552 /* Operate on either the one paragraph, or to make them all identical,
553 do all of them together (fill paragraph can format all the paragraphs
554 it finds with identical specs if it gets passed more than one) */
555 fillEnd = alignWithFirst ? buf->length : paraEnd;
557 /* Get the paragraph in a text string (or all of the paragraphs if
558 we're making them all the same) */
559 paraText = BufGetRange(buf, paraStart, fillEnd);
561 /* Find separate left margins for the first and for the first line of
562 the paragraph, and for rest of the remainder of the paragraph */
563 for (c=paraText ; *c!='\0' && *c!='\n'; c++);
564 firstLineLen = c - paraText;
565 secondLineStart = *c == '\0' ? paraText : c + 1;
566 firstLineIndent = findLeftMargin(paraText, firstLineLen, tabDist);
567 leftMargin = findLeftMargin(secondLineStart, paraEnd - paraStart -
568 (secondLineStart - paraText), tabDist);
570 /* Fill the paragraph */
571 filledText = fillParagraph(paraText, leftMargin, firstLineIndent,
572 rightMargin, tabDist, useTabs, nullSubsChar, &len);
573 XtFree(paraText);
575 /* Replace it in the buffer */
576 BufReplace(buf, paraStart, fillEnd, filledText);
577 XtFree(filledText);
579 /* move on to the next paragraph */
580 paraStart += len;
583 /* Free the buffer and return its contents */
584 filledText = BufGetAll(buf);
585 *filledLen = buf->length;
586 BufFree(buf);
587 return filledText;
591 ** Trim leading space, and arrange text to fill between leftMargin and
592 ** rightMargin (except for the first line which fills from firstLineIndent),
593 ** re-creating whitespace to the left of the text using tabs (if allowTabs is
594 ** True) calculated using tabDist, and spaces. Returns a newly allocated
595 ** string as the function result, and the length of the new string in filledLen.
597 static char *fillParagraph(char *text, int leftMargin, int firstLineIndent,
598 int rightMargin, int tabDist, int allowTabs, char nullSubsChar,
599 int *filledLen)
601 char *cleanedText, *outText, *indentString, *leadIndentStr, *outPtr, *c, *b;
602 int col, cleanedLen, indentLen, leadIndentLen, nLines = 1;
603 int inWhitespace, inMargin;
605 /* remove leading spaces, convert newlines to spaces */
606 cleanedText = XtMalloc(strlen(text)+1);
607 outPtr = cleanedText;
608 inMargin = True;
609 for (c=text; *c!='\0'; c++) {
610 if (*c == '\t' || *c == ' ') {
611 if (!inMargin)
612 *outPtr++ = *c;
613 } else if (*c == '\n') {
614 if (inMargin) {
615 /* a newline before any text separates paragraphs, so leave
616 it in, back up, and convert the previous space back to \n */
617 if (outPtr > cleanedText && *(outPtr-1) == ' ')
618 *(outPtr-1) = '\n';
619 *outPtr++ = '\n';
620 nLines +=2;
621 } else
622 *outPtr++ = ' ';
623 inMargin = True;
624 } else {
625 *outPtr++ = *c;
626 inMargin = False;
629 cleanedLen = outPtr - cleanedText;
630 *outPtr = '\0';
632 /* Put back newlines breaking text at word boundaries within the margins.
633 Algorithm: scan through characters, counting columns, and when the
634 margin width is exceeded, search backward for beginning of the word
635 and convert the last whitespace character into a newline */
636 col = firstLineIndent;
637 for (c=cleanedText; *c!='\0'; c++) {
638 if (*c == '\n')
639 col = leftMargin;
640 else
641 col += BufCharWidth(*c, col, tabDist, nullSubsChar);
642 if (col-1 > rightMargin) {
643 inWhitespace = True;
644 for (b=c; b>=cleanedText && *b!='\n'; b--) {
645 if (*b == '\t' || *b == ' ') {
646 if (!inWhitespace) {
647 *b = '\n';
648 c = b;
649 col = leftMargin;
650 nLines++;
651 break;
653 } else
654 inWhitespace = False;
658 nLines++;
660 /* produce a string to prepend to lines to indent them to the left margin */
661 leadIndentStr = makeIndentString(firstLineIndent, tabDist,
662 allowTabs, &leadIndentLen);
663 indentString = makeIndentString(leftMargin, tabDist, allowTabs, &indentLen);
665 /* allocate memory for the finished string */
666 outText = XtMalloc(sizeof(char) * (cleanedLen + leadIndentLen +
667 indentLen * (nLines-1) + 1));
668 outPtr = outText;
670 /* prepend the indent string to each line of the filled text */
671 strncpy(outPtr, leadIndentStr, leadIndentLen);
672 outPtr += leadIndentLen;
673 for (c=cleanedText; *c!='\0'; c++) {
674 *outPtr++ = *c;
675 if (*c == '\n') {
676 strncpy(outPtr, indentString, indentLen);
677 outPtr += indentLen;
681 /* convert any trailing space to newline. Add terminating null */
682 if (*(outPtr-1) == ' ')
683 *(outPtr-1) = '\n';
684 *outPtr = '\0';
686 /* clean up, return result */
687 XtFree(cleanedText);
688 XtFree(leadIndentStr);
689 XtFree(indentString);
690 *filledLen = outPtr - outText;
691 return outText;
694 static char *makeIndentString(int indent, int tabDist, int allowTabs, int *nChars)
696 char *indentString, *outPtr;
697 int i;
699 outPtr = indentString = XtMalloc(sizeof(char) * indent + 1);
700 if (allowTabs) {
701 for (i=0; i<indent/tabDist; i++)
702 *outPtr++ = '\t';
703 for (i=0; i<indent%tabDist; i++)
704 *outPtr++ = ' ';
705 } else {
706 for (i=0; i<indent; i++)
707 *outPtr++ = ' ';
709 *outPtr = '\0';
710 *nChars = outPtr - indentString;
711 return indentString;
715 ** Find the boundaries of the paragraph containing pos
717 static int findParagraphEnd(textBuffer *buf, int startPos)
719 char c;
720 int pos;
721 static char whiteChars[] = " \t";
723 pos = BufEndOfLine(buf, startPos)+1;
724 while (pos < buf->length) {
725 c = BufGetCharacter(buf, pos);
726 if (c == '\n')
727 break;
728 if (strchr(whiteChars, c) != NULL)
729 pos++;
730 else
731 pos = BufEndOfLine(buf, pos)+1;
733 return pos < buf->length ? pos : buf->length;
735 static int findParagraphStart(textBuffer *buf, int startPos)
737 char c;
738 int pos, parStart;
739 static char whiteChars[] = " \t";
741 if (startPos == 0)
742 return 0;
743 parStart = BufStartOfLine(buf, startPos);
744 pos = parStart - 2;
745 while (pos > 0) {
746 c = BufGetCharacter(buf, pos);
747 if (c == '\n')
748 break;
749 if (strchr(whiteChars, c) != NULL)
750 pos--;
751 else {
752 parStart = BufStartOfLine(buf, pos);
753 pos = parStart - 2;
756 return parStart > 0 ? parStart : 0;