Workaround for KDE's FONTLIST bug (and for the various
[nedit.git] / source / shift.c
bloba258c3675596b5bce7e53b31a15855a503f47b47
1 static const char CVSID[] = "$Id: shift.c,v 1.14 2003/04/07 22:51:41 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. *
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"
39 #include <string.h>
40 #include <limits.h>
41 #include <ctype.h>
42 #ifdef VMS
43 #include "../util/VMSparam.h"
44 #else
45 #ifndef __MVS__
46 #include <sys/param.h>
47 #endif
48 #endif /*VMS*/
50 #include <Xm/Xm.h>
52 #ifdef HAVE_DEBUG_H
53 #include "../debug.h"
54 #endif
57 static void shiftRect(WindowInfo *window, int direction, int byTab,
58 int selStart, int selEnd, int rectStart, int rectEnd);
59 static void changeCase(WindowInfo *window, int makeUpper);
60 static char *shiftLineRight(char *line, int lineLen, int tabsAllowed,
61 int tabDist, int nChars);
62 static char *shiftLineLeft(char *line, int lineLen, int tabDist, int nChars);
63 static int findLeftMargin(char *text, int length, int tabDist);
64 static char *fillParagraphs(char *text, int rightMargin, int tabDist,
65 int useTabs, char nullSubsChar, int *filledLen, int alignWithFirst);
66 static char *fillParagraph(char *text, int leftMargin, int firstLineIndent,
67 int rightMargin, int tabDist, int allowTabs, char nullSubsChar,
68 int *filledLen);
69 static char *makeIndentString(int indent, int tabDist, int allowTabs, int *nChars);
70 static int atTabStop(int pos, int tabDist);
71 static int nextTab(int pos, int tabDist);
72 static int countLines(const char *text);
73 static int findParagraphStart(textBuffer *buf, int startPos);
74 static int findParagraphEnd(textBuffer *buf, int startPos);
77 ** Shift the selection left or right by a single character, or by one tab stop
78 ** if "byTab" is true. (The length of a tab stop is the size of an emulated
79 ** tab if emulated tabs are turned on, or a hardware tab if not).
81 void ShiftSelection(WindowInfo *window, int direction, int byTab)
83 int selStart, selEnd, isRect, rectStart, rectEnd;
84 int shiftedLen, newEndPos, cursorPos, origLength, emTabDist, shiftDist;
85 char *text, *shiftedText;
86 textBuffer *buf = window->buffer;
88 /* get selection, if no text selected, use current insert position */
89 if (!BufGetSelectionPos(buf, &selStart, &selEnd, &isRect,
90 &rectStart, &rectEnd)) {
91 cursorPos = TextGetCursorPos(window->lastFocus);
92 selStart = BufStartOfLine(buf, cursorPos);
93 selEnd = BufEndOfLine(buf, cursorPos);
94 if (selEnd < buf->length)
95 selEnd++;
96 BufSelect(buf, selStart, selEnd);
97 isRect = False;
98 text = BufGetRange(buf, selStart, selEnd);
99 } else if (isRect) {
100 cursorPos = TextGetCursorPos(window->lastFocus);
101 origLength = buf->length;
102 shiftRect(window, direction, byTab, selStart, selEnd, rectStart,
103 rectEnd);
104 TextSetCursorPos(window->lastFocus, (cursorPos < (selEnd+selStart)/2) ?
105 selStart : cursorPos + (buf->length - origLength));
106 return;
107 } else {
108 selStart = BufStartOfLine(buf, selStart);
109 if (selEnd != 0 && BufGetCharacter(buf, selEnd-1) != '\n') {
110 selEnd = BufEndOfLine(buf, selEnd);
111 if (selEnd < buf->length)
112 selEnd++;
114 BufSelect(buf, selStart, selEnd);
115 text = BufGetRange(buf, selStart, selEnd);
118 /* shift the text by the appropriate distance */
119 if (byTab) {
120 XtVaGetValues(window->textArea, textNemulateTabs, &emTabDist, NULL);
121 shiftDist = emTabDist == 0 ? buf->tabDist : emTabDist;
122 } else
123 shiftDist = 1;
124 shiftedText = ShiftText(text, direction, buf->useTabs, buf->tabDist,
125 shiftDist, &shiftedLen);
126 XtFree(text);
127 BufReplaceSelected(buf, shiftedText);
128 XtFree(shiftedText);
130 newEndPos = selStart + shiftedLen;
131 BufSelect(buf, selStart, newEndPos);
134 static void shiftRect(WindowInfo *window, int direction, int byTab,
135 int selStart, int selEnd, int rectStart, int rectEnd)
137 int offset, emTabDist;
138 textBuffer *tempBuf, *buf = window->buffer;
139 char *text;
141 /* Make sure selStart and SelEnd refer to whole lines */
142 selStart = BufStartOfLine(buf, selStart);
143 selEnd = BufEndOfLine(buf, selEnd);
145 /* Calculate the the left/right offset for the new rectangle */
146 if (byTab) {
147 XtVaGetValues(window->textArea, textNemulateTabs, &emTabDist, NULL);
148 offset = emTabDist == 0 ? buf->tabDist : emTabDist;
149 } else
150 offset = 1;
151 offset *= direction == SHIFT_LEFT ? -1 : 1;
152 if (rectStart + offset < 0)
153 offset = -rectStart;
155 /* Create a temporary buffer for the lines containing the selection, to
156 hide the intermediate steps from the display update routines */
157 tempBuf = BufCreate();
158 tempBuf->tabDist = buf->tabDist;
159 tempBuf->useTabs = buf->useTabs;
160 text = BufGetRange(buf, selStart, selEnd);
161 BufSetAll(tempBuf, text);
162 XtFree(text);
164 /* Do the shift in the temporary buffer */
165 text = BufGetTextInRect(buf, selStart, selEnd, rectStart, rectEnd);
166 BufRemoveRect(tempBuf, 0, selEnd-selStart, rectStart, rectEnd);
167 BufInsertCol(tempBuf, rectStart+offset, 0, text, NULL, NULL);
168 XtFree(text);
170 /* Make the change in the real buffer */
171 text = BufGetAll(tempBuf);
172 BufReplace(buf, selStart, selEnd, text);
173 XtFree(text);
174 BufRectSelect(buf, selStart, selStart + tempBuf->length,
175 rectStart+offset, rectEnd+offset);
176 BufFree(tempBuf);
179 void UpcaseSelection(WindowInfo *window)
181 changeCase(window, True);
184 void DowncaseSelection(WindowInfo *window)
186 changeCase(window, False);
190 ** Capitalize or lowercase the contents of the selection (or of the character
191 ** before the cursor if there is no selection). If "makeUpper" is true,
192 ** change to upper case, otherwise, change to lower case.
194 static void changeCase(WindowInfo *window, int makeUpper)
196 textBuffer *buf = window->buffer;
197 char *text, *c;
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 text = BufGetSelectionText(buf);
214 for (c=text; *c!='\0'; c++)
215 *c = makeUpper ? toupper((unsigned char)*c) :
216 tolower((unsigned char)*c);
217 BufReplaceSelected(buf, text);
218 XtFree(text);
219 if (isRect)
220 BufRectSelect(buf, start, end, rectStart, rectEnd);
221 else
222 BufSelect(buf, start, end);
226 void FillSelection(WindowInfo *window)
228 textBuffer *buf = window->buffer;
229 char *text, *filledText;
230 int left, right, nCols, len, isRect, rectStart, rectEnd;
231 int rightMargin, wrapMargin;
232 int insertPos = TextGetCursorPos(window->lastFocus);
233 int hasSelection = window->buffer->primary.selected;
235 /* Find the range of characters and get the text to fill. If there is a
236 selection, use it but extend non-rectangular selections to encompass
237 whole lines. If there is no selection, find the paragraph containing
238 the insertion cursor */
239 if (!BufGetSelectionPos(buf, &left, &right, &isRect, &rectStart, &rectEnd)) {
240 left = findParagraphStart(buf, insertPos);
241 right = findParagraphEnd(buf, insertPos);
242 if (left == right) {
243 XBell(TheDisplay, 0);
244 return;
246 text = BufGetRange(buf, left, right);
247 } else if (isRect) {
248 left = BufStartOfLine(buf, left);
249 right = BufEndOfLine(buf, right);
250 text = BufGetTextInRect(buf, left, right, rectStart, INT_MAX);
251 } else {
252 left = BufStartOfLine(buf, left);
253 if (right != 0 && BufGetCharacter(buf, right-1) != '\n') {
254 right = BufEndOfLine(buf, right);
255 if (right < buf->length)
256 right++;
258 BufSelect(buf, left, right);
259 text = BufGetRange(buf, left, right);
262 /* Find right margin either as specified in the rectangular selection, or
263 by measuring the text and querying the window's wrap margin (or width) */
264 if (hasSelection && isRect) {
265 rightMargin = rectEnd - rectStart;
266 } else {
267 XtVaGetValues(window->textArea, textNcolumns, &nCols,
268 textNwrapMargin, &wrapMargin, NULL);
269 rightMargin = (wrapMargin == 0 ? nCols : wrapMargin) - 1;
272 /* Fill the text */
273 filledText = fillParagraphs(text, rightMargin, buf->tabDist, buf->useTabs,
274 buf->nullSubsChar, &len, False);
275 XtFree(text);
277 /* Replace the text in the window */
278 if (hasSelection && isRect) {
279 BufReplaceRect(buf, left, right, rectStart, INT_MAX, filledText);
280 BufRectSelect(buf, left,
281 BufEndOfLine(buf, BufCountForwardNLines(buf, left,
282 countLines(filledText)-1)), rectStart, rectEnd);
283 } else {
284 BufReplace(buf, left, right, filledText);
285 if (hasSelection)
286 BufSelect(buf, left, left + len);
288 XtFree(filledText);
290 /* Find a reasonable cursor position. Usually insertPos is best, but
291 if the text was indented, positions can shift */
292 if (hasSelection && isRect)
293 TextSetCursorPos(window->lastFocus, buf->cursorPosHint);
294 else
295 TextSetCursorPos(window->lastFocus, insertPos < left ? left :
296 (insertPos > left + len ? left + len : insertPos));
300 ** shift lines left and right in a multi-line text string. Returns the
301 ** shifted text in memory that must be freed by the caller with XtFree.
303 char *ShiftText(char *text, int direction, int tabsAllowed, int tabDist,
304 int nChars, int *newLen)
306 char *shiftedText, *shiftedLine;
307 char *textPtr, *lineStartPtr, *shiftedPtr;
308 int bufLen;
311 ** Allocate memory for shifted string. Shift left adds a maximum of
312 ** tabDist-2 characters per line (remove one tab, add tabDist-1 spaces).
313 ** Shift right adds a maximum of nChars character per line.
315 if (direction == SHIFT_RIGHT)
316 bufLen = strlen(text) + countLines(text) * nChars;
317 else
318 bufLen = strlen(text) + countLines(text) * tabDist;
319 shiftedText = (char *)XtMalloc(bufLen + 1);
322 ** break into lines and call shiftLine(Left/Right) on each
324 lineStartPtr = text;
325 textPtr = text;
326 shiftedPtr = shiftedText;
327 while (TRUE) {
328 if (*textPtr=='\n' || *textPtr=='\0') {
329 shiftedLine = (direction == SHIFT_RIGHT) ?
330 shiftLineRight(lineStartPtr, textPtr-lineStartPtr,
331 tabsAllowed, tabDist, nChars) :
332 shiftLineLeft(lineStartPtr, textPtr-lineStartPtr, tabDist,
333 nChars);
334 strcpy(shiftedPtr, shiftedLine);
335 shiftedPtr += strlen(shiftedLine);
336 XtFree(shiftedLine);
337 if (*textPtr == '\0') {
338 /* terminate string & exit loop at end of text */
339 *shiftedPtr = '\0';
340 break;
341 } else {
342 /* move the newline from text to shifted text */
343 *shiftedPtr++ = *textPtr++;
345 /* start line over */
346 lineStartPtr = textPtr;
347 } else
348 textPtr++;
350 *newLen = shiftedPtr - shiftedText;
351 return shiftedText;
354 static char *shiftLineRight(char *line, int lineLen, int tabsAllowed,
355 int tabDist, int nChars)
357 char *lineOut;
358 char *lineInPtr, *lineOutPtr;
359 int whiteWidth, i;
361 lineInPtr = line;
362 lineOut = XtMalloc(lineLen + nChars + 1);
363 lineOutPtr = lineOut;
364 whiteWidth = 0;
365 while (TRUE) {
366 if (*lineInPtr == '\0' || (lineInPtr - line) >= lineLen) {
367 /* nothing on line, wipe it out */
368 *lineOut = '\0';
369 return lineOut;
370 } else if (*lineInPtr == ' ') {
371 /* white space continues with tab, advance to next tab stop */
372 whiteWidth++;
373 *lineOutPtr++ = *lineInPtr++;
374 } else if (*lineInPtr == '\t') {
375 /* white space continues with tab, advance to next tab stop */
376 whiteWidth = nextTab(whiteWidth, tabDist);
377 *lineOutPtr++ = *lineInPtr++;
378 } else {
379 /* end of white space, add nChars of space */
380 for (i=0; i<nChars; i++) {
381 *lineOutPtr++ = ' ';
382 whiteWidth++;
383 /* if we're now at a tab stop, change last 8 spaces to a tab */
384 if (tabsAllowed && atTabStop(whiteWidth, tabDist)) {
385 lineOutPtr -= tabDist;
386 *lineOutPtr++ = '\t';
389 /* move remainder of line */
390 while (*lineInPtr!='\0' && (lineInPtr - line) < lineLen)
391 *lineOutPtr++ = *lineInPtr++;
392 *lineOutPtr = '\0';
393 return lineOut;
398 static char *shiftLineLeft(char *line, int lineLen, int tabDist, int nChars)
400 char *lineOut;
401 int i, whiteWidth, lastWhiteWidth, whiteGoal;
402 char *lineInPtr, *lineOutPtr;
404 lineInPtr = line;
405 lineOut = XtMalloc(lineLen + tabDist + 1);
406 lineOutPtr = lineOut;
407 whiteWidth = 0;
408 lastWhiteWidth = 0;
409 while (TRUE) {
410 if (*lineInPtr == '\0' || (lineInPtr - line) >= lineLen) {
411 /* nothing on line, wipe it out */
412 *lineOut = '\0';
413 return lineOut;
414 } else if (*lineInPtr == ' ') {
415 /* white space continues with space, advance one character */
416 whiteWidth++;
417 *lineOutPtr++ = *lineInPtr++;
418 } else if (*lineInPtr == '\t') {
419 /* white space continues with tab, advance to next tab stop */
420 /* save the position, though, in case we need to remove the tab */
421 lastWhiteWidth = whiteWidth;
422 whiteWidth = nextTab(whiteWidth, tabDist);
423 *lineOutPtr++ = *lineInPtr++;
424 } else {
425 /* end of white space, remove nChars characters */
426 for (i=1; i<=nChars; i++) {
427 if (lineOutPtr > lineOut) {
428 if (*(lineOutPtr-1) == ' ') {
429 /* end of white space is a space, just remove it */
430 lineOutPtr--;
431 } else {
432 /* end of white space is a tab, remove it and add
433 back spaces */
434 lineOutPtr--;
435 whiteGoal = whiteWidth - i;
436 whiteWidth = lastWhiteWidth;
437 while (whiteWidth < whiteGoal) {
438 *lineOutPtr++ = ' ';
439 whiteWidth++;
444 /* move remainder of line */
445 while (*lineInPtr!='\0' && (lineInPtr - line) < lineLen)
446 *lineOutPtr++ = *lineInPtr++;
447 /* add a null */
448 *lineOutPtr = '\0';
449 return lineOut;
454 static int atTabStop(int pos, int tabDist)
456 return (pos%tabDist == 0);
459 static int nextTab(int pos, int tabDist)
461 return (pos/tabDist)*tabDist + tabDist;
464 static int countLines(const char *text)
466 int count = 1;
468 while(*text != '\0') {
469 if (*text++ == '\n') {
470 count++;
473 return count;
477 ** Find the implied left margin of a text string (the number of columns to the
478 ** first non-whitespace character on any line) up to either the terminating
479 ** null character at the end of the string, or "length" characters, whever
480 ** comes first.
482 static int findLeftMargin(char *text, int length, int tabDist)
484 char *c;
485 int col = 0, leftMargin = INT_MAX;
486 int inMargin = True;
488 for (c=text; *c!='\0' && c-text<length; c++) {
489 if (*c == '\t') {
490 col += BufCharWidth('\t', col, tabDist, '\0');
491 } else if (*c == ' ') {
492 col++;
493 } else if (*c == '\n') {
494 col = 0;
495 inMargin = True;
496 } else {
497 /* non-whitespace */
498 if (col < leftMargin && inMargin)
499 leftMargin = col;
500 inMargin = False;
504 /* if no non-white text is found, the leftMargin will never be set */
505 if (leftMargin == INT_MAX)
506 return 0;
508 return leftMargin;
512 ** Fill multiple paragraphs between rightMargin and an implied left margin
513 ** and first line indent determined by analyzing the text. alignWithFirst
514 ** aligns subsequent paragraphs with the margins of the first paragraph (a
515 ** capability not currently used in NEdit, but carried over from code for
516 ** previous versions which did all paragraphs together).
518 static char *fillParagraphs(char *text, int rightMargin, int tabDist,
519 int useTabs, char nullSubsChar, int *filledLen, int alignWithFirst)
521 int paraStart, paraEnd, fillEnd;
522 char *c, ch, *secondLineStart, *paraText, *filledText;
523 int firstLineLen, firstLineIndent, leftMargin, len;
524 textBuffer *buf;
526 /* Create a buffer to accumulate the filled paragraphs */
527 buf = BufCreate();
528 BufSetAll(buf, text);
531 ** Loop over paragraphs, filling each one, and accumulating the results
532 ** in buf
534 paraStart = 0;
535 for (;;) {
537 /* Skip over white space */
538 while (paraStart < buf->length) {
539 ch = BufGetCharacter(buf, paraStart);
540 if (ch != ' ' && ch != '\t' && ch != '\n')
541 break;
542 paraStart++;
544 if (paraStart >= buf->length)
545 break;
546 paraStart = BufStartOfLine(buf, paraStart);
548 /* Find the end of the paragraph */
549 paraEnd = findParagraphEnd(buf, paraStart);
551 /* Operate on either the one paragraph, or to make them all identical,
552 do all of them together (fill paragraph can format all the paragraphs
553 it finds with identical specs if it gets passed more than one) */
554 fillEnd = alignWithFirst ? buf->length : paraEnd;
556 /* Get the paragraph in a text string (or all of the paragraphs if
557 we're making them all the same) */
558 paraText = BufGetRange(buf, paraStart, fillEnd);
560 /* Find separate left margins for the first and for the first line of
561 the paragraph, and for rest of the remainder of the paragraph */
562 for (c=paraText ; *c!='\0' && *c!='\n'; c++);
563 firstLineLen = c - paraText;
564 secondLineStart = *c == '\0' ? paraText : c + 1;
565 firstLineIndent = findLeftMargin(paraText, firstLineLen, tabDist);
566 leftMargin = findLeftMargin(secondLineStart, paraEnd - paraStart -
567 (secondLineStart - paraText), tabDist);
569 /* Fill the paragraph */
570 filledText = fillParagraph(paraText, leftMargin, firstLineIndent,
571 rightMargin, tabDist, useTabs, nullSubsChar, &len);
572 XtFree(paraText);
574 /* Replace it in the buffer */
575 BufReplace(buf, paraStart, fillEnd, filledText);
576 XtFree(filledText);
578 /* move on to the next paragraph */
579 paraStart += len;
582 /* Free the buffer and return its contents */
583 filledText = BufGetAll(buf);
584 *filledLen = buf->length;
585 BufFree(buf);
586 return filledText;
590 ** Trim leading space, and arrange text to fill between leftMargin and
591 ** rightMargin (except for the first line which fills from firstLineIndent),
592 ** re-creating whitespace to the left of the text using tabs (if allowTabs is
593 ** True) calculated using tabDist, and spaces. Returns a newly allocated
594 ** string as the function result, and the length of the new string in filledLen.
596 static char *fillParagraph(char *text, int leftMargin, int firstLineIndent,
597 int rightMargin, int tabDist, int allowTabs, char nullSubsChar,
598 int *filledLen)
600 char *cleanedText, *outText, *indentString, *leadIndentStr, *outPtr, *c, *b;
601 int col, cleanedLen, indentLen, leadIndentLen, nLines = 1;
602 int inWhitespace, inMargin;
604 /* remove leading spaces, convert newlines to spaces */
605 cleanedText = XtMalloc(strlen(text)+1);
606 outPtr = cleanedText;
607 inMargin = True;
608 for (c=text; *c!='\0'; c++) {
609 if (*c == '\t' || *c == ' ') {
610 if (!inMargin)
611 *outPtr++ = *c;
612 } else if (*c == '\n') {
613 if (inMargin) {
614 /* a newline before any text separates paragraphs, so leave
615 it in, back up, and convert the previous space back to \n */
616 if (outPtr > cleanedText && *(outPtr-1) == ' ')
617 *(outPtr-1) = '\n';
618 *outPtr++ = '\n';
619 nLines +=2;
620 } else
621 *outPtr++ = ' ';
622 inMargin = True;
623 } else {
624 *outPtr++ = *c;
625 inMargin = False;
628 cleanedLen = outPtr - cleanedText;
629 *outPtr = '\0';
631 /* Put back newlines breaking text at word boundaries within the margins.
632 Algorithm: scan through characters, counting columns, and when the
633 margin width is exceeded, search backward for beginning of the word
634 and convert the last whitespace character into a newline */
635 col = firstLineIndent;
636 for (c=cleanedText; *c!='\0'; c++) {
637 if (*c == '\n')
638 col = leftMargin;
639 else
640 col += BufCharWidth(*c, col, tabDist, nullSubsChar);
641 if (col-1 > rightMargin) {
642 inWhitespace = True;
643 for (b=c; b>=cleanedText && *b!='\n'; b--) {
644 if (*b == '\t' || *b == ' ') {
645 if (!inWhitespace) {
646 *b = '\n';
647 c = b;
648 col = leftMargin;
649 nLines++;
650 break;
652 } else
653 inWhitespace = False;
657 nLines++;
659 /* produce a string to prepend to lines to indent them to the left margin */
660 leadIndentStr = makeIndentString(firstLineIndent, tabDist,
661 allowTabs, &leadIndentLen);
662 indentString = makeIndentString(leftMargin, tabDist, allowTabs, &indentLen);
664 /* allocate memory for the finished string */
665 outText = XtMalloc(sizeof(char) * (cleanedLen + leadIndentLen +
666 indentLen * (nLines-1) + 1));
667 outPtr = outText;
669 /* prepend the indent string to each line of the filled text */
670 strncpy(outPtr, leadIndentStr, leadIndentLen);
671 outPtr += leadIndentLen;
672 for (c=cleanedText; *c!='\0'; c++) {
673 *outPtr++ = *c;
674 if (*c == '\n') {
675 strncpy(outPtr, indentString, indentLen);
676 outPtr += indentLen;
680 /* convert any trailing space to newline. Add terminating null */
681 if (*(outPtr-1) == ' ')
682 *(outPtr-1) = '\n';
683 *outPtr = '\0';
685 /* clean up, return result */
686 XtFree(cleanedText);
687 XtFree(leadIndentStr);
688 XtFree(indentString);
689 *filledLen = outPtr - outText;
690 return outText;
693 static char *makeIndentString(int indent, int tabDist, int allowTabs, int *nChars)
695 char *indentString, *outPtr;
696 int i;
698 outPtr = indentString = XtMalloc(sizeof(char) * indent + 1);
699 if (allowTabs) {
700 for (i=0; i<indent/tabDist; i++)
701 *outPtr++ = '\t';
702 for (i=0; i<indent%tabDist; i++)
703 *outPtr++ = ' ';
704 } else {
705 for (i=0; i<indent; i++)
706 *outPtr++ = ' ';
708 *outPtr = '\0';
709 *nChars = outPtr - indentString;
710 return indentString;
714 ** Find the boundaries of the paragraph containing pos
716 static int findParagraphEnd(textBuffer *buf, int startPos)
718 char c;
719 int pos;
720 static char whiteChars[] = " \t";
722 pos = BufEndOfLine(buf, startPos)+1;
723 while (pos < buf->length) {
724 c = BufGetCharacter(buf, pos);
725 if (c == '\n')
726 break;
727 if (strchr(whiteChars, c) != NULL)
728 pos++;
729 else
730 pos = BufEndOfLine(buf, pos)+1;
732 return pos < buf->length ? pos : buf->length;
734 static int findParagraphStart(textBuffer *buf, int startPos)
736 char c;
737 int pos, parStart;
738 static char whiteChars[] = " \t";
740 if (startPos == 0)
741 return 0;
742 parStart = BufStartOfLine(buf, startPos);
743 pos = parStart - 2;
744 while (pos > 0) {
745 c = BufGetCharacter(buf, pos);
746 if (c == '\n')
747 break;
748 if (strchr(whiteChars, c) != NULL)
749 pos--;
750 else {
751 parStart = BufStartOfLine(buf, pos);
752 pos = parStart - 2;
755 return parStart > 0 ? parStart : 0;