SDDSlib
Loading...
Searching...
No Matches
edit_string.c File Reference

Implements a simple single-line text-driven editor for user-directed data editing. More...

#include "mdb.h"
#include <ctype.h>

Go to the source code of this file.

Classes

struct  EDIT_SEQUENCE
 

Macros

#define DEBUG   0
 
#define IS_WORD_END(c)
 

Functions

long edit_string (char *text, char *edit0)
 Edits the provided text based on the specified edit commands.
 
void edit_strings (char **string, long strings, char *buffer, char *edit)
 Applies edit commands to an array of strings.
 

Detailed Description

Implements a simple single-line text-driven editor for user-directed data editing.

This file provides functionalities to edit strings based on user-defined commands. It includes operations such as inserting, deleting, moving the cursor, searching, killing, and yanking text within a single line of text. The editor supports complex command sequences and maintains a kill buffer for temporary storage of deleted text.

License
This file is distributed under the terms of the Software License Agreement found in the file LICENSE included with this distribution.
Author
M. Borland, C. Saunders, R. Soliday, H. Shang

Definition in file edit_string.c.

Macro Definition Documentation

◆ DEBUG

#define DEBUG   0

Definition at line 25 of file edit_string.c.

◆ IS_WORD_END

#define IS_WORD_END ( c)
Value:
((c) == ' ' || (c) == '\t' || (c) == '_' || (c) == '-')

Definition at line 27 of file edit_string.c.

Function Documentation

◆ edit_string()

long edit_string ( char * text,
char * edit0 )

Edits the provided text based on the specified edit commands.

Processes a single line of text by applying a sequence of editing commands. Supports operations like inserting, deleting characters or words, moving the cursor, searching for substrings, and manipulating the kill buffer.

Parameters
textPointer to the text string to be edited. The string is modified in place.
editPointer to the string containing edit commands to apply to the text.
Returns
Returns 1 on successful editing, or 0 if an error occurs (e.g., memory allocation failure).

Definition at line 75 of file edit_string.c.

75 {
76 short count, new_kill;
77 char *ptr, *text_start, delimiter, *ptr1, *ptr2, *ptr3;
78 char *delimLoc, *editNext, *charList;
79 static char kill[4096], buffer[4096];
80 char *orig, *repl;
81 int global, conditional, conditionalReturn, here, i;
82 char *edit, cSave;
83 EDIT_SEQUENCE *editSeq;
84 int stackLevel, stackDepth, doPush, parenCount, invert;
85 size_t j;
86
87#if DEBUG
88 printf("text = %s\nedit = %s\n", text, edit0);
89#endif
90 text_start = text;
91 kill[0] = 0;
92 if (!(editSeq = malloc(sizeof(*editSeq) * (stackDepth = 10))))
93 return 0;
94 cp_str(&editSeq[0].editText, edit0);
95 editSeq[0].count = 1;
96 for (i = 0; i < stackDepth; i++)
97 editSeq[i].pending = 0;
98 editSeq[0].editPtr = NULL;
99 stackLevel = 0;
100
101 new_kill = 1;
102 while (stackLevel >= 0) {
103#if DEBUG
104 printf("stackLevel = %ld\n", stackLevel);
105#endif
106 while (editSeq[stackLevel].pending || editSeq[stackLevel].count--) {
107 if (!editSeq[stackLevel].pending)
108 editSeq[stackLevel].editPtr = editSeq[stackLevel].editText;
109 editSeq[stackLevel].pending = 0;
110 if (!editSeq[stackLevel].editPtr)
111 continue;
112#if DEBUG
113 printf("Count = %ld\n", editSeq[stackLevel].count + 1);
114 printf("EditPtr = %s\n", editSeq[stackLevel].editPtr);
115#endif
116 edit = editSeq[stackLevel].editPtr;
117 while (*(editSeq[stackLevel].editPtr = edit)) {
118 count = 0;
119 while (isdigit(*edit))
120 count = count * 10 + (*edit++ - '0');
121 if (!count)
122 count = 1;
123 if (!*edit)
124 break;
125#if DEBUG
126 printf("count = %ld command = %c\n", count, *edit);
127#endif
128 doPush = 0;
129 /* this was commented out to avoid reseting the kill buffer before each command except yanks
130 new_kill = 1;
131 */
132 switch (*edit) {
133 case '(':
134 /* expression */
135 parenCount = 1;
136 ptr = edit + 1;
137 while (parenCount && *++edit) {
138 if (*edit == '(')
139 parenCount++;
140 else if (*edit == ')')
141 parenCount--;
142 }
143 if (*edit) {
144 editSeq[stackLevel].pending = 1;
145 editSeq[stackLevel].editPtr = edit + 1;
146 } else {
147 editSeq[stackLevel].pending = 1;
148 editSeq[stackLevel].editPtr = NULL;
149 }
150 if (stackLevel >= stackDepth &&
151 !(editSeq = realloc(editSeq, sizeof(*editSeq) * (stackDepth += 10)))) {
152 fprintf(stderr, "memory allocation failure (edit_string)");
153 return 0;
154 }
155 stackLevel++;
156 editSeq[stackLevel].count = count;
157 cSave = *edit;
158 *edit = 0;
159 cp_str(&editSeq[stackLevel].editText, ptr);
160 *edit = cSave;
161 editSeq[stackLevel].editPtr = NULL;
162 doPush = 1;
163#if DEBUG
164 printf("stack pushing: %ld*>%s<\n", count,
165 editSeq[stackLevel].editText);
166#endif
167 break;
168 case 'c':
169 /* clear the kill buffer */
170 kill[0] = 0;
171 break;
172 case 'd':
173 /* delete N characters */
174 if (count > (long)strlen(text))
175 count = strlen(text);
176 strcpy_ss(text, text + count);
177 new_kill = 1;
178 break;
179 case 'f':
180 /* move forward N chars */
181 if (count > (long)strlen(text))
182 count = strlen(text);
183 text += count;
184 new_kill = 1;
185 break;
186 case 'b':
187 /* move backward N chars */
188 if ((text -= count) < text_start)
189 text = text_start;
190 new_kill = 1;
191 break;
192 case 'D':
193 /* delete N words */
194 while (count-- && (ptr = strpbrk(text, " \t_-"))) {
195 while (IS_WORD_END(*ptr))
196 ptr++;
197 strcpy_ss(text, ptr);
198 }
199 if (count >= 0)
200 *text = 0;
201 new_kill = 1;
202 break;
203 case 'F':
204 /* move forward N words */
205 while (count-- && (ptr = strpbrk(text, " \t_-"))) {
206 while (IS_WORD_END(*ptr))
207 ptr++;
208 text = ptr;
209 }
210 if (count >= 0)
211 text += strlen(text);
212 new_kill = 1;
213 break;
214 case 'B':
215 /* move backward N words */
216 while (count--) {
217 while (IS_WORD_END(*text) && text > text_start)
218 text--;
219 while (!IS_WORD_END(*text) && text > text_start)
220 text--;
221 }
222 if (IS_WORD_END(*text))
223 text++;
224 new_kill = 1;
225 break;
226 case 'a':
227 /* go to start of line */
228 text = text_start;
229 break;
230 case 'e':
231 /* go to end of line */
232 text += strlen(text);
233 break;
234 case 'i':
235 /* insert characters */
236 delimiter = *++edit;
237 ptr1 = NULL;
238 if ((ptr = strchr(++edit, delimiter))) {
239 ptr1 = ptr;
240 *ptr = 0;
241 } else {
242 ptr = edit + strlen(edit) - 1;
243 }
244#if DEBUG
245 printf("insert string = >%s<\n", edit);
246#endif
247 while (count--) {
248 insert(text, edit);
249 text += strlen(edit);
250 }
251 if (ptr1)
252 *ptr1 = delimiter;
253 edit = ptr;
254 new_kill = 1;
255 break;
256 case 'x':
257 /* kill anything in the given string */
258 delimiter = *++edit;
259 if (!*edit)
260 break;
261 invert = 0;
262 if (delimiter == '-') {
263 invert = 1;
264 delimiter = *++edit;
265 if (!*edit)
266 break;
267 }
268 delimLoc = NULL;
269 if ((editNext = strchr(++edit, delimiter))) {
270 delimLoc = editNext;
271 *editNext = 0;
272 } else {
273 editNext = edit + strlen(edit) - 1;
274 }
275 charList = expand_ranges(edit);
276 if (*charList == '[' && *(charList + strlen(charList) - 1) == ']') {
277 /*
278 strcpy_ss(charList, charList+1);
279 *(charList+strlen(charList)-1) = 0;
280*/
281 }
282#if DEBUG
283 printf("x-kill string = >%s< (was >%s<)\n", charList, edit);
284 printf("text position: >%s<\n", text);
285#endif
286 if (new_kill)
287 kill[0] = 0;
288 new_kill = 0;
289 if (invert) {
290 /* kill anything up to a character in the string */
291 if ((ptr = strpbrk(text, charList))) {
292 strncat(kill, text, ptr - text);
293 strcpy_ss(text, ptr);
294 } else
295 /* no occurrence, kill whole string */
296 *text = 0;
297 } else {
298 /* kill anything in the given string */
299 int i, length, found;
300 found = 1;
301 length = strlen(charList);
302 ptr = text;
303 while (found && *ptr) {
304 found = 0;
305 for (i = 0; i < length; i++) {
306 if (*ptr == *(charList + i)) {
307 found = 1;
308 ptr++;
309 break;
310 }
311 }
312 }
313 if (ptr != text) {
314 strncat(kill, text, ptr - text);
315 strcpy_ss(text, ptr);
316 }
317 }
318 free(charList);
319 if (delimLoc)
320 *delimLoc = delimiter;
321 edit = editNext;
322 break;
323 case 'r':
324 /* search backwards for characters, leaving cursor at end of matching section */
325 if (!(delimiter = *++edit))
326 return (0);
327 conditional = 0;
328 if (delimiter == '?') {
329 conditional = 1;
330 if (!(delimiter = *++edit))
331 return (0);
332 }
333 ptr1 = NULL;
334 if ((ptr = strchr(++edit, delimiter))) {
335 ptr1 = ptr;
336 *ptr = 0;
337 } else {
338 ptr = edit + strlen(edit) - 1;
339 }
340#if DEBUG
341 printf("search string = >%s<\n", edit);
342#endif
343 conditionalReturn = 0;
344 while (count--) {
345 j = strlen(text);
346 ptr3 = text;
347 text = text_start;
348 ptr2 = strstr(text, edit);
349 if (ptr2 == NULL) {
350 text = ptr3;
351 conditionalReturn = conditional;
352 break;
353 }
354 if (strlen(ptr2) <= j) {
355 text = ptr3;
356 conditionalReturn = conditional;
357 break;
358 }
359 text = ptr2 + strlen(edit);
360 while (1) {
361 ptr2 = strstr(text, edit);
362 if ((ptr2 == NULL) || (strlen(ptr2) <= j)) {
363 break;
364 }
365 text = ptr2 + strlen(edit);
366 }
367 if (count != 0)
368 text -= strlen(edit);
369 }
370 if (ptr1)
371 *ptr1 = delimiter;
372 edit = ptr;
373 new_kill = 1;
374 if (conditionalReturn)
375 return 1;
376 break;
377 case 'R':
378 /* search backwards for characters, but leave cursor at start of matching section */
379 if (!(delimiter = *++edit))
380 return (0);
381 conditional = 0;
382 if (delimiter == '?') {
383 conditional = 1;
384 if (!(delimiter = *++edit))
385 return (0);
386 }
387 ptr1 = NULL;
388 if ((ptr = strchr(++edit, delimiter))) {
389 ptr1 = ptr;
390 *ptr = 0;
391 } else {
392 ptr = edit + strlen(edit) - 1;
393 }
394#if DEBUG
395 printf("search string = >%s<\n", edit);
396#endif
397 conditionalReturn = 0;
398 while (count--) {
399 j = strlen(text);
400 ptr3 = text;
401 text = text_start;
402 ptr2 = strstr(text, edit);
403 if (ptr2 == NULL) {
404 text = ptr3;
405 conditionalReturn = conditional;
406 break;
407 }
408 if (strlen(ptr2) <= j) {
409 text = ptr3;
410 conditionalReturn = conditional;
411 break;
412 }
413 text = ptr2 + strlen(edit);
414 while (1) {
415 ptr2 = strstr(text, edit);
416 if ((ptr2 == NULL) || (strlen(ptr2) <= j)) {
417 break;
418 }
419 text = ptr2 + strlen(edit);
420 }
421 text -= strlen(edit);
422 }
423 if (ptr1)
424 *ptr1 = delimiter;
425 edit = ptr;
426 new_kill = 1;
427 if (conditionalReturn)
428 return 1;
429 break;
430 case 's':
431 /* search forward for characters, leaving CP at end of matching section */
432 if (!(delimiter = *++edit))
433 return (0);
434 conditional = 0;
435 if (delimiter == '?') {
436 conditional = 1;
437 if (!(delimiter = *++edit))
438 return (0);
439 }
440 ptr1 = NULL;
441 if ((ptr = strchr(++edit, delimiter))) {
442 ptr1 = ptr;
443 *ptr = 0;
444 } else {
445 ptr = edit + strlen(edit) - 1;
446 }
447#if DEBUG
448 printf("search string = >%s<\n", edit);
449#endif
450 conditionalReturn = 0;
451 while (count--) {
452 if ((ptr2 = strstr(text, edit)))
453 text = ptr2 + strlen(edit);
454 else {
455 conditionalReturn = conditional;
456 break;
457 }
458 }
459 if (ptr1)
460 *ptr1 = delimiter;
461 edit = ptr;
462 new_kill = 1;
463 if (conditionalReturn)
464 return 1;
465 break;
466 case 'S':
467 /* search forward for characters, but leave cursor at start of matching section */
468 if (!(delimiter = *++edit))
469 return (0);
470 conditional = 0;
471 if (delimiter == '?') {
472 conditional = 1;
473 if (!(delimiter = *++edit))
474 return (0);
475 }
476 ptr1 = NULL;
477 if ((ptr = strchr(++edit, delimiter))) {
478 ptr1 = ptr;
479 *ptr = 0;
480 } else {
481 ptr = edit + strlen(edit) - 1;
482 }
483#if DEBUG
484 printf("search string = >%s<\n", edit);
485#endif
486 conditionalReturn = 0;
487 while (count--) {
488 if ((ptr2 = strstr(text, edit))) {
489 if (count != 0)
490 text = ptr2 + strlen(edit);
491 else
492 text = ptr2;
493 } else {
494 conditionalReturn = conditional;
495 break;
496 }
497 }
498 if (ptr1)
499 *ptr1 = delimiter;
500 edit = ptr;
501 new_kill = 1;
502 if (conditionalReturn)
503 return 1;
504 break;
505 case 'k':
506 /* kill N characters */
507 if (new_kill)
508 kill[0] = 0;
509 strncat(kill, text, count);
510 strcpy_ss(text, text + count);
511 new_kill = 0;
512#if DEBUG
513 printf("kill buffer: >%s<\n", kill);
514#endif
515 break;
516 case 'K':
517 /* kill N words */
518 if (new_kill)
519 kill[0] = 0;
520 while (count-- && (ptr = strpbrk(text, " \t_-"))) {
521 while (IS_WORD_END(*ptr))
522 ptr++;
523 strncat(kill, text, ptr - text);
524 strcpy_ss(text, ptr);
525 }
526 if (count >= 0)
527 *text = 0;
528 new_kill = 0;
529#if DEBUG
530 printf("kill buffer: >%s<\n", kill);
531#endif
532 break;
533 case 'z':
534 case 'Z':
535 if (!(delimiter = *++edit))
536 return (0);
537 while (count--) {
538 /* kill up to next character */
539 if (new_kill)
540 kill[0] = 0;
541 if ((ptr = strchr(text, delimiter))) {
542 if (*(edit - 1) == 'Z')
543 ptr++; /* delete delimiter */
544 strncat(kill, text, ptr - text);
545 strcpy_ss(text, ptr);
546 }
547 new_kill = 0;
548#if DEBUG
549 printf("kill buffer: >%s<\n", kill);
550#endif
551 if (*(edit - 1) == 'z')
552 break;
553 }
554 break;
555 case 'y':
556 /* yank kill buffer */
557#if DEBUG
558 printf("yank string = >%s<\n", kill);
559#endif
560 while (count--) {
561 insert(text, kill);
562 text += strlen(kill);
563 }
564 break;
565 case '%':
566 /* replace one string with another */
567 global = here = 0;
568 if (*(edit + 1) == 'g') {
569 global = 1;
570 edit++;
571 }
572 if (*(edit + 1) == 'h') {
573 here = 1;
574 edit++;
575 }
576 if (!(delimiter = *++edit))
577 return (0);
578#if DEBUG
579 printf("delimiter = %c\n", delimiter);
580#endif
581 orig = edit + 1;
582 if (!(repl = strchr(orig + 1, delimiter)))
583 return (0);
584 *repl++ = 0;
585 if (!(ptr = strchr(repl, delimiter)))
586 return (0);
587 *ptr = 0;
588#if DEBUG
589 printf("orig: >%s< repl: >%s<\n", orig, repl);
590#endif
591 if (here) {
592 if (!global)
593 replaceString(buffer, text, orig, repl, count, 1);
594 else
595 replaceString(buffer, text, orig, repl, -1, 1);
596 } else {
597 if (!global)
598 replace_stringn(buffer, text, orig, repl, count);
599 else
600 replace_string(buffer, text, orig, repl);
601 }
602 strcpy_ss(text, buffer);
603 edit = ptr;
604 *(repl - 1) = delimiter;
605 *ptr = delimiter;
606 break;
607 default:
608 break;
609 }
610 if (doPush)
611 break;
612 edit++;
613 }
614 }
615 free(editSeq[stackLevel].editText);
616 editSeq[stackLevel].editPtr = NULL;
617 stackLevel--;
618 }
619 free(editSeq);
620 return 1;
621}
char * cp_str(char **s, char *t)
Copies a string, allocating memory for storage.
Definition cp_str.c:28
char * insert(char *s, char *t)
Inserts a substring into a target string.
Definition insert.c:29
int replaceString(char *t, char *s, char *orig, char *repl, long count_limit, long here)
Replace occurrences of one string with another string with additional options.
int replace_stringn(char *t, char *s, char *orig, char *repl, long count_limit)
Replace a limited number of occurrences of one string with another string.
int replace_string(char *t, char *s, char *orig, char *repl)
Replace all occurrences of one string with another string.
char * strcpy_ss(char *dest, const char *src)
Safely copies a string, handling memory overlap.
Definition str_copy.c:34
char * expand_ranges(char *template)
Expand range specifiers in a wildcard template into explicit character lists.
Definition wild_match.c:429

◆ edit_strings()

void edit_strings ( char ** string,
long strings,
char * buffer,
char * edit )

Applies edit commands to an array of strings.

Iterates over an array of strings, applying the specified edit commands to each string. Utilizes a buffer for intermediate processing and ensures that each string is properly updated after editing. Frees the original string memory and replaces it with the edited version.

Parameters
stringDouble pointer to the array of strings to be edited.
stringsThe number of strings in the array.
bufferPointer to a buffer used for temporary storage during editing.
editPointer to the string containing edit commands to apply to each string.

Definition at line 635 of file edit_string.c.

635 {
636 while (strings--) {
637 strcpy_ss(buffer, string[strings]);
638 edit_string(buffer, edit);
639 free(string[strings]);
640 cp_str(string + strings, buffer);
641 }
642}
long edit_string(char *text, char *edit)
Edits the provided text based on the specified edit commands.
Definition edit_string.c:75