00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "mined.h"
00010 #include <string.h>
00011
00012
00013
00014
00015 void UP()
00016 {
00017 if (y == 0) {
00018 (void) reverse_scroll();
00019 move_to(x, y);
00020 }
00021 else
00022 move_to(x, y - 1);
00023 }
00024
00025
00026
00027
00028 void DN()
00029 {
00030 if (y == last_y) {
00031 if (bot_line->next == tail && bot_line->text[0] != '\n') {
00032 dummy_line();
00033 DN();
00034 return;
00035 }
00036 else {
00037 (void) forward_scroll();
00038 move_to(x, y);
00039 }
00040 }
00041 else
00042 move_to(x, y + 1);
00043 }
00044
00045
00046
00047
00048 void LF()
00049 {
00050 if (x == 0 && get_shift(cur_line->shift_count) == 0) {
00051 if (cur_line->prev != header) {
00052 UP();
00053 move_to(LINE_END, y);
00054 }
00055 }
00056 else
00057 move_to(x - 1, y);
00058 }
00059
00060
00061
00062
00063 void RT()
00064 {
00065 if (*cur_text == '\n') {
00066 if (cur_line->next != tail) {
00067 DN();
00068 move_to(LINE_START, y);
00069 }
00070 }
00071 else
00072 move_to(x + 1, y);
00073 }
00074
00075
00076
00077
00078 void HIGH()
00079 {
00080 move_to(0, 0);
00081 }
00082
00083
00084
00085
00086 void LOW()
00087 {
00088 move_to(0, last_y);
00089 }
00090
00091
00092
00093
00094 void BL()
00095 {
00096 move_to(LINE_START, y);
00097 }
00098
00099
00100
00101
00102 void EL()
00103 {
00104 move_to(LINE_END, y);
00105 }
00106
00107
00108
00109
00110 void GOTO()
00111 {
00112 int number;
00113 LINE *line;
00114
00115 if (get_number("Please enter line number.", &number) == ERRORS)
00116 return;
00117
00118 if (number <= 0 || (line = proceed(header->next, number - 1)) == tail)
00119 error("Illegal line number: ", num_out((long) number));
00120 else
00121 move_to(x, find_y(line));
00122 }
00123
00124
00125
00126
00127
00128
00129 void PD()
00130 {
00131 register int i;
00132
00133 for (i = 0; i < screenmax; i++)
00134 if (forward_scroll() == ERRORS)
00135 break;
00136 if (y - i < 0)
00137 move_to(0, screenmax >> 1);
00138 else
00139 move_to(0, y - i);
00140 }
00141
00142
00143
00144
00145
00146
00147
00148
00149 void PU()
00150 {
00151 register int i;
00152
00153 for (i = 0; i < screenmax; i++)
00154 if (reverse_scroll() == ERRORS)
00155 break;
00156 set_cursor(0, ymax);
00157 #ifdef UNIX
00158 tputs(CE, 0, _putchar);
00159 #else
00160 string_print(blank_line);
00161 #endif
00162 if (y + i > screenmax)
00163 move_to(0, screenmax >> 1);
00164 else
00165 move_to(0, y + i);
00166 }
00167
00168
00169
00170
00171 void HO()
00172 {
00173 if (proceed(top_line, -screenmax) == header)
00174 PU();
00175 else {
00176 reset(header->next, 0);
00177 RD();
00178 }
00179 move_to(LINE_START, 0);
00180 }
00181
00182
00183
00184
00185 void EF()
00186 {
00187 if (tail->prev->text[0] != '\n')
00188 dummy_line();
00189 if (proceed(bot_line, screenmax) == tail)
00190 PD();
00191 else {
00192 reset(proceed(tail->prev, -screenmax), screenmax);
00193 RD();
00194 }
00195 move_to(LINE_START, last_y);
00196 }
00197
00198
00199
00200
00201 void SU()
00202 {
00203 if (top_line->prev == header)
00204 return;
00205
00206 (void) reverse_scroll();
00207 set_cursor(0, ymax);
00208 #ifdef UNIX
00209 tputs(CE, 0, _putchar);
00210 #else
00211 string_print(blank_line);
00212 #endif
00213 move_to(x, (y == screenmax) ? screenmax : y + 1);
00214 }
00215
00216
00217
00218
00219 void SD()
00220 {
00221 if (forward_scroll() != ERRORS)
00222 move_to(x, (y == 0) ? 0 : y - 1);
00223 else
00224 set_cursor(x, y);
00225 }
00226
00227
00228
00229
00230
00231 int forward_scroll()
00232 {
00233 if (bot_line->next == tail)
00234 return ERRORS;
00235 top_line = top_line->next;
00236 bot_line = bot_line->next;
00237 cur_line = cur_line->next;
00238 set_cursor(0, ymax);
00239 line_print(bot_line);
00240
00241 return FINE;
00242 }
00243
00244
00245
00246
00247
00248 int reverse_scroll()
00249 {
00250 if (top_line->prev == header)
00251 return ERRORS;
00252
00253 if (last_y != screenmax)
00254 last_y++;
00255 else
00256 bot_line = bot_line->prev;
00257 top_line = top_line->prev;
00258 cur_line = cur_line->prev;
00259
00260
00261 set_cursor(0, 0);
00262 #ifdef UNIX
00263 tputs(AL, 0, _putchar);
00264 #else
00265 string_print(rev_scroll);
00266 #endif
00267 set_cursor(0, 0);
00268 line_print(top_line);
00269
00270 return FINE;
00271 }
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282 void MP()
00283 {
00284 move_previous_word(NO_DELETE);
00285 }
00286
00287 void move_previous_word(remove)
00288 FLAG remove;
00289 {
00290 register char *begin_line;
00291 register char *textp;
00292 char start_char = *cur_text;
00293 char *start_pos = cur_text;
00294
00295
00296 if (cur_text == cur_line->text) {
00297 if (cur_line->prev == header)
00298 return;
00299 start_char = '\0';
00300 }
00301
00302 LF();
00303
00304 begin_line = cur_line->text;
00305 textp = cur_text;
00306
00307
00308 if (!alpha(*textp) || !alpha(start_char)) {
00309 while (textp != begin_line && (white_space(*textp) || *textp == '\n'))
00310 textp--;
00311 }
00312
00313
00314 while (textp != begin_line && alpha(*textp))
00315 textp--;
00316
00317
00318 if (textp != begin_line && *textp != '\n')
00319 textp++;
00320
00321
00322 move_address(textp);
00323 if (remove == DELETE)
00324 delete(cur_line, textp, cur_line, start_pos);
00325 }
00326
00327
00328
00329
00330
00331
00332 void MN()
00333 {
00334 move_next_word(NO_DELETE);
00335 }
00336
00337 void move_next_word(remove)
00338 FLAG remove;
00339 {
00340 register char *textp = cur_text;
00341
00342
00343 while (*textp != '\n' && alpha(*textp))
00344 textp++;
00345
00346
00347 while (*textp != '\n' && white_space(*textp))
00348 textp++;
00349
00350 if (remove == DELETE) {
00351 delete(cur_line, cur_text, cur_line, textp);
00352 return;
00353 }
00354
00355
00356 if (*textp == '\n' && cur_line->next != tail) {
00357 DN();
00358 move_to(LINE_START, y);
00359 textp = cur_text;
00360 while (*textp != '\n' && white_space(*textp))
00361 textp++;
00362 }
00363 move_address(textp);
00364 }
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376 void DCC()
00377 {
00378 if (*cur_text == '\n')
00379 delete(cur_line,cur_text, cur_line->next,cur_line->next->text);
00380 else
00381 delete(cur_line, cur_text, cur_line, cur_text + 1);
00382 }
00383
00384
00385
00386
00387
00388
00389 void DPC()
00390 {
00391 if (x == 0 && cur_line->prev == header)
00392 return;
00393
00394 LF();
00395 DCC();
00396 }
00397
00398
00399
00400
00401
00402 void DLN()
00403 {
00404 if (*cur_text == '\n')
00405 DCC();
00406 else
00407 delete(cur_line, cur_text, cur_line, cur_text + length_of(cur_text) -1);
00408 }
00409
00410
00411
00412
00413 void DNW()
00414 {
00415 if (*cur_text == '\n')
00416 DCC();
00417 else
00418 move_next_word(DELETE);
00419 }
00420
00421
00422
00423
00424 void DPW()
00425 {
00426 if (cur_text == cur_line->text)
00427 DPC();
00428 else
00429 move_previous_word(DELETE);
00430 }
00431
00432
00433
00434
00435 void S(character)
00436 register char character;
00437 {
00438 static char buffer[2];
00439
00440 buffer[0] = character;
00441
00442 if (insert(cur_line, cur_text, buffer) == ERRORS)
00443 return;
00444
00445
00446 if (character == '\n') {
00447 set_cursor(0, y);
00448 if (y == screenmax) {
00449 line_print(cur_line);
00450 (void) forward_scroll();
00451 }
00452 else {
00453 reset(top_line, y);
00454 display(0, y, cur_line, last_y - y);
00455 }
00456 move_to(0, (y == screenmax) ? y : y + 1);
00457 }
00458 else if (x + 1 == XBREAK)
00459 move_to(x + 1, y);
00460 else {
00461 put_line(cur_line, x, FALSE);
00462 move_to(x + 1, y);
00463 }
00464 }
00465
00466
00467
00468
00469
00470 void CTL()
00471 {
00472 register char ctrl;
00473
00474 status_line("Enter control character.", NIL_PTR);
00475 if ((ctrl = getchar()) >= '\01' && ctrl <= '\037') {
00476 S(ctrl);
00477 clear_status();
00478 }
00479 else
00480 error ("Unknown control character", NIL_PTR);
00481 }
00482
00483
00484
00485
00486
00487 void LIB()
00488 {
00489 S('\n');
00490 UP();
00491 move_to(LINE_END, y);
00492 }
00493
00494
00495
00496
00497
00498 LINE *line_insert(line, string, len)
00499 register LINE *line;
00500 char *string;
00501 int len;
00502 {
00503 register LINE *new_line;
00504
00505
00506 new_line = install_line(string, len);
00507
00508
00509 new_line->prev = line;
00510 new_line->next = line->next;
00511 line->next = new_line;
00512 new_line->next->prev = new_line;
00513
00514
00515 nlines++;
00516
00517 return new_line;
00518 }
00519
00520
00521
00522
00523 int insert(line, location, string)
00524 register LINE *line;
00525 char *location, *string;
00526 {
00527 register char *bufp = text_buffer;
00528 register char *textp = line->text;
00529
00530 if (length_of(textp) + length_of(string) >= MAX_CHARS) {
00531 error("Line too long", NIL_PTR);
00532 return ERRORS;
00533 }
00534
00535 modified = TRUE;
00536
00537
00538 while (textp != location)
00539 *bufp++ = *textp++;
00540
00541
00542 while (*string != '\0')
00543 *bufp++ = *string++;
00544 *bufp = '\0';
00545
00546 if (*(string - 1) == '\n')
00547 (void) line_insert(line, location, length_of(location));
00548 else
00549 copy_string(bufp, location);
00550
00551
00552 free_space(line->text);
00553 line->text = alloc(length_of(text_buffer) + 1);
00554 copy_string(line->text, text_buffer);
00555
00556 return FINE;
00557 }
00558
00559
00560
00561
00562
00563 LINE *line_delete(line)
00564 register LINE *line;
00565 {
00566 register LINE *next_line = line->next;
00567
00568
00569 line->prev->next = line->next;
00570 line->next->prev = line->prev;
00571
00572
00573 free_space(line->text);
00574 free_space((char*)line);
00575
00576
00577 nlines--;
00578
00579 return next_line;
00580 }
00581
00582
00583
00584
00585
00586
00587 void delete(start_line, start_textp, end_line, end_textp)
00588 register LINE *start_line;
00589 LINE *end_line;
00590 char *start_textp, *end_textp;
00591 {
00592 register char *textp = start_line->text;
00593 register char *bufp = text_buffer;
00594 LINE *line, *stop;
00595 int line_cnt = 0;
00596 int count = 0;
00597 int shift = 0;
00598 int nx = x;
00599
00600 modified = TRUE;
00601
00602
00603 while (textp < start_textp) {
00604 *bufp++ = *textp++;
00605 count++;
00606 }
00607
00608
00609 if (count + length_of(end_textp) >= MAX_CHARS) {
00610 error("Line too long", NIL_PTR);
00611 return;
00612 }
00613
00614
00615 copy_string(bufp, (end_textp != NIL_PTR) ? end_textp : "\n");
00616
00617
00618 line = start_line->next;
00619 stop = end_line->next;
00620 while (line != stop && line != tail) {
00621 line = line_delete(line);
00622 line_cnt++;
00623 }
00624
00625
00626 if (end_textp == NIL_PTR && length_of(start_line->text) == 1 && nlines > 1) {
00627 start_line = start_line->prev;
00628 (void) line_delete(start_line->next);
00629 line_cnt++;
00630 }
00631 else {
00632 free_space(start_line->text);
00633 start_line->text = alloc(length_of(text_buffer) + 1);
00634 copy_string(start_line->text, text_buffer);
00635 }
00636
00637
00638 if (get_shift(start_line->shift_count)) {
00639 shift = (XBREAK - count_chars(start_line)) / SHIFT_SIZE;
00640 if (shift > 0) {
00641 if (shift >= get_shift(start_line->shift_count))
00642 start_line->shift_count = 0;
00643 else
00644 start_line->shift_count -= shift;
00645 nx += shift * SHIFT_SIZE;
00646 }
00647 }
00648
00649 if (line_cnt == 0) {
00650 if (shift > 0) {
00651 set_cursor(0, y);
00652 line_print(start_line);
00653 }
00654 else {
00655 set_cursor(x, y);
00656 put_line(start_line, x, TRUE);
00657 }
00658 move_to(nx, y);
00659 return;
00660 }
00661
00662 shift = last_y;
00663 reset(top_line, y);
00664 display(0, y, start_line, shift - y);
00665 move_to((line_cnt == 1) ? nx : 0, y);
00666 }
00667
00668
00669
00670
00671
00672 LINE *mark_line;
00673 char *mark_text;
00674 int lines_saved;
00675
00676
00677
00678
00679 void PT()
00680 {
00681 register int fd;
00682
00683 if ((fd = scratch_file(READ)) == ERRORS)
00684 error("Buffer is empty.", NIL_PTR);
00685 else {
00686 file_insert(fd, FALSE);
00687 (void) close(fd);
00688 }
00689 }
00690
00691
00692
00693
00694
00695 void IF()
00696 {
00697 register int fd;
00698 char name[LINE_LEN];
00699
00700
00701 if (get_file("Get and insert file:", name) != FINE)
00702 return;
00703
00704 if ((fd = open(name, 0)) < 0)
00705 error("Cannot open ", name);
00706 else {
00707 file_insert(fd, TRUE);
00708 (void) close(fd);
00709 }
00710 }
00711
00712
00713
00714
00715
00716 void file_insert(fd, old_pos)
00717 int fd;
00718 FLAG old_pos;
00719 {
00720 char line_buffer[MAX_CHARS];
00721 register LINE *line = cur_line;
00722 register int line_count = nlines;
00723 LINE *page = cur_line;
00724 int ret = ERRORS;
00725
00726
00727 if (get_line(fd, line_buffer) == ERRORS)
00728 return;
00729
00730
00731 if (insert(line, cur_text, line_buffer) == ERRORS)
00732 return;
00733
00734
00735 while ((ret = get_line(fd, line_buffer)) != ERRORS && ret != NO_LINE)
00736 line = line_insert(line, line_buffer, ret);
00737
00738 if (ret == NO_LINE) {
00739 line = line->next;
00740 (void) insert(line, line->text, line_buffer);
00741 }
00742
00743
00744 line_count = nlines - line_count;
00745
00746
00747 if (line_count == 0) {
00748 set_cursor(0, y);
00749 line_print(line);
00750 move_to((old_pos == TRUE) ? x : x + length_of(line_buffer), y);
00751 }
00752 else {
00753 reset(top_line, y);
00754 while (page != line && page != bot_line->next)
00755 page = page->next;
00756 if (page != bot_line->next || old_pos == TRUE)
00757 display(0, y, cur_line, screenmax - y);
00758 if (old_pos == TRUE)
00759 move_to(x, y);
00760 else if (ret == NO_LINE)
00761 move_to(length_of(line_buffer), find_y(line));
00762 else
00763 move_to(0, find_y(line->next));
00764 }
00765
00766
00767 if (line_count >= REPORT)
00768 status_line(num_out((long) line_count), " lines added.");
00769 }
00770
00771
00772
00773
00774
00775 void WB()
00776 {
00777 register int new_fd;
00778 int yank_fd;
00779 register int cnt;
00780 int ret = 0;
00781 char file[LINE_LEN];
00782
00783
00784 if ((yank_fd = scratch_file(READ)) == ERRORS) {
00785 error("Buffer is empty.", NIL_PTR);
00786 return;
00787 }
00788
00789
00790 if (get_file("Write buffer to file:", file) != FINE)
00791 return;
00792
00793
00794 if ((new_fd = creat(file, 0644)) < 0) {
00795 error("Cannot create ", file);
00796 return;
00797 }
00798
00799 status_line("Writing ", file);
00800
00801
00802 while ((cnt = read(yank_fd, text_buffer, sizeof(text_buffer))) > 0)
00803 if (write(new_fd, text_buffer, cnt) != cnt) {
00804 bad_write(new_fd);
00805 ret = ERRORS;
00806 break;
00807 }
00808
00809
00810 (void) close(new_fd);
00811 (void) close(yank_fd);
00812
00813 if (ret != ERRORS)
00814 file_status("Wrote", chars_saved, file, lines_saved, TRUE, FALSE);
00815 }
00816
00817
00818
00819
00820 void MA()
00821 {
00822 mark_line = cur_line;
00823 mark_text = cur_text;
00824 status_line("Mark set", NIL_PTR);
00825 }
00826
00827
00828
00829
00830
00831 void YA()
00832 {
00833 set_up(NO_DELETE);
00834 }
00835
00836
00837
00838
00839 void DT()
00840 {
00841 set_up(DELETE);
00842 }
00843
00844
00845
00846
00847
00848
00849 void set_up(remove)
00850 FLAG remove;
00851 {
00852 switch (checkmark()) {
00853 case NOT_VALID :
00854 error("Mark not set.", NIL_PTR);
00855 return;
00856 case SMALLER :
00857 yank(mark_line, mark_text, cur_line, cur_text, remove);
00858 break;
00859 case BIGGER :
00860 yank(cur_line, cur_text, mark_line, mark_text, remove);
00861 break;
00862 case SAME :
00863 yank_status = EMPTY;
00864 chars_saved = 0L;
00865 status_line("0 characters saved in buffer.", NIL_PTR);
00866 break;
00867 }
00868 }
00869
00870
00871
00872
00873
00874
00875
00876
00877 FLAG checkmark()
00878 {
00879 register LINE *line;
00880 FLAG cur_seen = FALSE;
00881
00882
00883 if (mark_line == cur_line) {
00884 if (mark_text == cur_text)
00885 return SAME;
00886 if (legal() == ERRORS)
00887 return NOT_VALID;
00888 return (mark_text < cur_text) ? SMALLER : BIGGER;
00889 }
00890
00891
00892 for (line = header->next; line != tail; line = line->next) {
00893 if (line == cur_line)
00894 cur_seen = TRUE;
00895 else if (line == mark_line)
00896 break;
00897 }
00898
00899
00900 if (line == tail || legal() == ERRORS)
00901 return NOT_VALID;
00902
00903
00904 return (cur_seen == TRUE) ? BIGGER : SMALLER;
00905 }
00906
00907
00908
00909
00910 int legal()
00911 {
00912 register char *textp = mark_line->text;
00913
00914
00915 while (textp != mark_text && *textp++ != '\0')
00916 ;
00917 return (*textp == '\0') ? ERRORS : FINE;
00918 }
00919
00920
00921
00922
00923
00924
00925
00926 void yank(start_line, start_textp, end_line, end_textp, remove)
00927 LINE *start_line, *end_line;
00928 char *start_textp, *end_textp;
00929 FLAG remove;
00930 {
00931 register LINE *line = start_line;
00932 register char *textp = start_textp;
00933 int fd;
00934
00935
00936 if ((fd = scratch_file(WRITE)) == ERRORS)
00937 return;
00938
00939 chars_saved = 0L;
00940 lines_saved = 0;
00941 status_line("Saving text.", NIL_PTR);
00942
00943
00944 while (textp != end_textp) {
00945 if (write_char(fd, *textp) == ERRORS) {
00946 (void) close(fd);
00947 return;
00948 }
00949 if (*textp++ == '\n') {
00950 line = line->next;
00951 textp = line->text;
00952 lines_saved++;
00953 }
00954 chars_saved++;
00955 }
00956
00957
00958 if (flush_buffer(fd) == ERRORS) {
00959 (void) close(fd);
00960 return;
00961 }
00962 (void) close(fd);
00963 yank_status = VALID;
00964
00965
00966
00967
00968
00969
00970
00971
00972 if (remove == DELETE) {
00973 move_to(find_x(start_line, start_textp), find_y(start_line));
00974 delete(start_line, start_textp, end_line, end_textp);
00975 }
00976
00977 status_line(num_out(chars_saved), " characters saved in buffer.");
00978 }
00979
00980
00981
00982
00983
00984
00985
00986
00987 #define MAXTRAILS 26
00988
00989 int scratch_file(mode)
00990 FLAG mode;
00991 {
00992 static int trials = 0;
00993 register char *y_ptr, *n_ptr;
00994 int fd;
00995
00996
00997 if (yank_status == NOT_VALID && mode == WRITE) {
00998
00999 y_ptr = &yank_file[11];
01000 n_ptr = num_out((long) getpid());
01001 while ((*y_ptr = *n_ptr++) != '\0')
01002 y_ptr++;
01003 *y_ptr++ = 'a' + trials;
01004 *y_ptr = '\0';
01005
01006 if (access(yank_file, 0) == 0 || (fd = creat(yank_file, 0644)) < 0) {
01007 if (trials++ >= MAXTRAILS) {
01008 error("Unable to creat scratchfile.", NIL_PTR);
01009 return ERRORS;
01010 }
01011 else
01012 return scratch_file(mode);
01013 }
01014 }
01015 else if ((mode == READ && (fd = open(yank_file, 0)) < 0) ||
01016 (mode == WRITE && (fd = creat(yank_file, 0644)) < 0)) {
01017 yank_status = NOT_VALID;
01018 return ERRORS;
01019 }
01020
01021 clear_buffer();
01022 return fd;
01023 }
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047 char typed_expression[LINE_LEN];
01048
01049
01050
01051
01052 void SF()
01053 {
01054 search("Search forward:", FORWARD);
01055 }
01056
01057
01058
01059
01060 void SR()
01061 {
01062 search("Search reverse:", REVERSE);
01063 }
01064
01065
01066
01067
01068
01069
01070
01071
01072 REGEX *get_expression(message)
01073 char *message;
01074 {
01075 static REGEX program;
01076 char exp_buf[LINE_LEN];
01077
01078 if (get_string(message, exp_buf, FALSE) == ERRORS)
01079 return NIL_REG;
01080
01081 if (exp_buf[0] == '\0' && typed_expression[0] == '\0') {
01082 error("No previous expression.", NIL_PTR);
01083 return NIL_REG;
01084 }
01085
01086 if (exp_buf[0] != '\0') {
01087 copy_string(typed_expression, exp_buf);
01088 compile(exp_buf, &program);
01089 }
01090
01091 if (program.status == REG_ERROR) {
01092 error(program.result.err_mess, NIL_PTR);
01093 return NIL_REG;
01094 }
01095 return &program;
01096 }
01097
01098
01099
01100
01101
01102 void GR()
01103 {
01104 change("Global replace:", VALID);
01105 }
01106
01107
01108
01109
01110 void LR()
01111 {
01112 change("Line replace:", NOT_VALID);
01113 }
01114
01115
01116
01117
01118
01119
01120
01121 void change(message, file)
01122 char *message;
01123 FLAG file;
01124 {
01125 char mess_buf[LINE_LEN];
01126 char replacement[LINE_LEN];
01127 REGEX *program;
01128 register LINE *line = cur_line;
01129 register char *textp;
01130 long lines = 0L;
01131 long subs = 0L;
01132 int page = y;
01133
01134
01135 copy_string(mess_buf, message);
01136 if ((program = get_expression(mess_buf)) == NIL_REG)
01137 return;
01138
01139
01140 build_string(mess_buf, "%s %s by:", mess_buf, typed_expression);
01141 if (get_string(mess_buf, replacement, FALSE) == ERRORS)
01142 return;
01143
01144 set_cursor(0, ymax);
01145 flush();
01146
01147 do {
01148 if (line_check(program, line->text, FORWARD)) {
01149 lines++;
01150
01151 do {
01152 subs++;
01153 if ((textp = substitute(line, program,replacement))
01154 == NIL_PTR)
01155 return;
01156 } while ((program->status & BEGIN_LINE) != BEGIN_LINE &&
01157 (program->status & END_LINE) != END_LINE &&
01158 line_check(program, textp, FORWARD));
01159
01160 if (page <= screenmax) {
01161 set_cursor(0, page);
01162 line_print(line);
01163 }
01164 }
01165 if (page <= screenmax)
01166 page++;
01167 line = line->next;
01168 } while (line != tail && file == VALID && quit == FALSE);
01169
01170 copy_string(mess_buf, (quit == TRUE) ? "(Aborted) " : "");
01171
01172 if (subs == 0L && quit == FALSE)
01173 error("Pattern not found.", NIL_PTR);
01174 else if (lines >= REPORT || quit == TRUE) {
01175 build_string(mess_buf, "%s %D substitutions on %D lines.", mess_buf,
01176 subs, lines);
01177 status_line(mess_buf, NIL_PTR);
01178 }
01179 else if (file == NOT_VALID && subs >= REPORT)
01180 status_line(num_out(subs), " substitutions.");
01181 else
01182 clear_status();
01183 move_to (x, y);
01184 }
01185
01186
01187
01188
01189
01190
01191 char *substitute(line, program, replacement)
01192 LINE *line;
01193 REGEX *program;
01194 char *replacement;
01195 {
01196 register char *textp = text_buffer;
01197 register char *subp = replacement;
01198 char *linep = line->text;
01199 char *amp;
01200
01201 modified = TRUE;
01202
01203
01204 while (linep != program->start_ptr)
01205 *textp++ = *linep++;
01206
01207
01208
01209
01210
01211 while (*subp != '\0' && textp < &text_buffer[MAX_CHARS]) {
01212 if (*subp == '&') {
01213 amp = program->start_ptr;
01214 while (amp < program->end_ptr && textp<&text_buffer[MAX_CHARS])
01215 *textp++ = *amp++;
01216 subp++;
01217 }
01218 else {
01219 if (*subp == '\\' && *(subp + 1) != '\0')
01220 subp++;
01221 *textp++ = *subp++;
01222 }
01223 }
01224
01225
01226 if (length_of(text_buffer) + length_of(program->end_ptr) >= MAX_CHARS) {
01227 error("Substitution result: line too big", NIL_PTR);
01228 return NIL_PTR;
01229 }
01230
01231
01232 copy_string(textp, program->end_ptr);
01233
01234
01235 free_space(line->text);
01236 line->text = alloc(length_of(text_buffer) + 1);
01237 copy_string(line->text, text_buffer);
01238
01239 return(line->text + (textp - text_buffer));
01240 }
01241
01242
01243
01244
01245
01246
01247
01248
01249 void search(message, method)
01250 char *message;
01251 FLAG method;
01252 {
01253 register REGEX *program;
01254 register LINE *match_line;
01255
01256
01257 if ((program = get_expression(message)) == NIL_REG)
01258 return;
01259
01260 set_cursor(0, ymax);
01261 flush();
01262
01263 if ((match_line = match(program, cur_text, method)) == NIL_LINE) {
01264 if (quit == TRUE)
01265 status_line("Aborted", NIL_PTR);
01266 else
01267 status_line("Pattern not found.", NIL_PTR);
01268 return;
01269 }
01270
01271 move(0, program->start_ptr, find_y(match_line));
01272 clear_status();
01273 }
01274
01275
01276
01277
01278
01279
01280 int find_y(match_line)
01281 LINE *match_line;
01282 {
01283 register LINE *line;
01284 register int count = 0;
01285
01286
01287 for (line = top_line; line != match_line && line != bot_line->next;
01288 line = line->next)
01289 count++;
01290 if (line != bot_line->next)
01291 return count;
01292
01293
01294 if ((line = proceed(match_line, -(screenmax >> 1))) == header) {
01295
01296 count = 0;
01297 for (line = header->next; line != match_line; line = line->next)
01298 count++;
01299 line = header->next;
01300 }
01301 else
01302 count = screenmax >> 1;
01303
01304
01305 reset(line, 0);
01306 RD();
01307
01308 return count;
01309 }
01310
01311
01312 #define NORMAL 0x0200
01313 #define DOT 0x0400
01314 #define EOLN 0x0800
01315 #define STAR 0x1000
01316 #define BRACKET 0x2000
01317 #define NEGATE 0x0100
01318 #define DONE 0x4000
01319
01320
01321 #define LOW_BYTE 0x00FF
01322 #define HIGH_BYTE 0xFF00
01323
01324
01325 #define previous(ptr) (*((ptr) - 1))
01326
01327
01328 int exp_buffer[BLOCK_SIZE];
01329
01330
01331 char *too_long = "Regular expression too long";
01332
01333
01334
01335
01336
01337 #define reg_error(str) program->status = REG_ERROR, \
01338 program->result.err_mess = (str)
01339
01340
01341
01342
01343
01344 void finished(program, last_exp)
01345 register REGEX *program;
01346 int *last_exp;
01347 {
01348 register int length = (last_exp - exp_buffer) * sizeof(int);
01349
01350
01351 program->result.expression = (int *) alloc(length);
01352
01353 bcopy(exp_buffer, program->result.expression, length);
01354 }
01355
01356
01357
01358
01359
01360
01361
01362
01363 void compile(pattern, program)
01364 register char *pattern;
01365 REGEX *program;
01366 {
01367 register int *expression = exp_buffer;
01368 int *prev_char;
01369 int *acct_field;
01370 FLAG negate;
01371 char low_char;
01372 char c;
01373
01374
01375 if (*pattern == '^') {
01376 program->status = BEGIN_LINE;
01377 pattern++;
01378 }
01379 else {
01380 program->status = 0;
01381
01382 if (*pattern == '*') {
01383 *expression++ = '*' + NORMAL;
01384 pattern++;
01385 }
01386 }
01387
01388 for (; ;) {
01389 switch (c = *pattern++) {
01390 case '.' :
01391 *expression++ = DOT;
01392 break;
01393 case '$' :
01394
01395
01396
01397 if (*pattern == '\0') {
01398 *expression++ = EOLN | DONE;
01399 program->status |= END_LINE;
01400 finished(program, expression);
01401 return;
01402 }
01403 else
01404 *expression++ = NORMAL + '$';
01405 break;
01406 case '\0' :
01407 *expression++ = DONE;
01408 finished(program, expression);
01409 return;
01410 case '\\' :
01411
01412 if (*pattern == '\0')
01413 *expression++ = NORMAL + '\\';
01414 else
01415 *expression++ = NORMAL + *pattern++;
01416 break;
01417 case '*' :
01418
01419
01420
01421
01422 prev_char = expression - 1;
01423 if (*prev_char & BRACKET)
01424 *(expression - (*acct_field & LOW_BYTE))|= STAR;
01425 else
01426 *prev_char |= STAR;
01427 break;
01428 case '[' :
01429
01430
01431
01432
01433
01434
01435
01436
01437
01438 acct_field = expression++;
01439 if (*pattern == '^') {
01440 pattern++;
01441 negate = TRUE;
01442 }
01443 else
01444 negate = FALSE;
01445 while (*pattern != ']') {
01446 if (*pattern == '\0') {
01447 reg_error("Missing ]");
01448 return;
01449 }
01450 if (*pattern == '\\')
01451 pattern++;
01452 *expression++ = *pattern++;
01453 if (*pattern == '-') {
01454
01455 low_char = previous(pattern);
01456 pattern++;
01457 if (low_char++ > *pattern) {
01458 reg_error("Bad range in [a-z]");
01459 return;
01460 }
01461
01462 while (low_char <= *pattern)
01463 *expression++ = low_char++;
01464 pattern++;
01465 }
01466 if (expression >= &exp_buffer[BLOCK_SIZE]) {
01467 reg_error(too_long);
01468 return;
01469 }
01470 }
01471 pattern++;
01472
01473 if ((*acct_field = (expression - acct_field)) == 1) {
01474 reg_error("Empty []");
01475 return;
01476 }
01477
01478 *acct_field |= BRACKET;
01479 if (negate == TRUE)
01480 *acct_field |= NEGATE;
01481
01482
01483
01484
01485 previous(expression) |= BRACKET;
01486 break;
01487 default :
01488 *expression++ = c + NORMAL;
01489 }
01490 if (expression == &exp_buffer[BLOCK_SIZE]) {
01491 reg_error(too_long);
01492 return;
01493 }
01494 }
01495
01496 }
01497
01498
01499
01500
01501
01502
01503
01504 LINE *match(program, string, method)
01505 REGEX *program;
01506 char *string;
01507 register FLAG method;
01508 {
01509 register LINE *line = cur_line;
01510 char old_char;
01511
01512
01513 if (program->status == REG_ERROR)
01514 return NIL_LINE;
01515
01516
01517 if (!(program->status & BEGIN_LINE)) {
01518 if (method == FORWARD) {
01519 if (line_check(program, string + 1, method) == MATCH)
01520 return cur_line;
01521 }
01522 else if (!(program->status & END_LINE)) {
01523 old_char = *string;
01524 *string = '\n';
01525 if (line_check(program, line->text, method) == MATCH) {
01526 *string = old_char;
01527 return cur_line;
01528 }
01529 *string = old_char;
01530 }
01531 }
01532
01533
01534 do {
01535 line = (method == FORWARD) ? line->next : line->prev;
01536 if (line->text == NIL_PTR)
01537 continue;
01538 if (line_check(program, line->text, method) == MATCH)
01539 return line;
01540 } while (line != cur_line && quit == FALSE);
01541
01542
01543 return NIL_LINE;
01544 }
01545
01546
01547
01548
01549
01550
01551 int line_check(program, string, method)
01552 register REGEX *program;
01553 char *string;
01554 FLAG method;
01555 {
01556 register char *textp = string;
01557
01558
01559 program->start_ptr = textp;
01560
01561
01562 if (program->status & BEGIN_LINE)
01563 return check_string(program, string, NIL_INT);
01564
01565 if (method == REVERSE) {
01566
01567 for (textp = string; *textp != '\n'; textp++)
01568 ;
01569
01570 while (textp >= string) {
01571 program->start_ptr = textp;
01572 if (check_string(program, textp--, NIL_INT))
01573 return MATCH;
01574 }
01575 }
01576 else {
01577
01578 while (quit == FALSE && *textp != '\0') {
01579 program->start_ptr = textp;
01580 if (check_string(program, textp, NIL_INT))
01581 return MATCH;
01582 if (*textp == '\n')
01583 break;
01584 textp++;
01585 }
01586 }
01587
01588 return NO_MATCH;
01589 }
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599 int check_string(program, string, expression)
01600 REGEX *program;
01601 register char *string;
01602 int *expression;
01603 {
01604 register int opcode;
01605 char c;
01606 char *mark;
01607 int star_fl;
01608
01609 if (expression == NIL_INT)
01610 expression = program->result.expression;
01611
01612
01613 while (quit == FALSE && !(*expression & DONE) &&
01614 *string != '\0' && *string != '\n') {
01615 c = *expression & LOW_BYTE;
01616 opcode = *expression & HIGH_BYTE;
01617 if (star_fl = (opcode & STAR)) {
01618 opcode &= ~STAR;
01619 mark = string;
01620 }
01621 expression++;
01622 switch (opcode) {
01623 case NORMAL :
01624 if (star_fl)
01625 while (*string++ == c)
01626 ;
01627 else if (*string++ != c)
01628 return NO_MATCH;
01629 break;
01630 case DOT :
01631 string++;
01632 if (star_fl)
01633 while (*string != '\0' && *string++ != '\n')
01634 ;
01635 break;
01636 case NEGATE | BRACKET:
01637 case BRACKET :
01638 if (star_fl)
01639 while (in_list(expression, *string++, c, opcode)
01640 == MATCH)
01641 ;
01642 else if (in_list(expression, *string++, c, opcode) == NO_MATCH)
01643 return NO_MATCH;
01644 expression += c - 1;
01645 break;
01646 default :
01647 panic("Corrupted program in check_string()");
01648 }
01649 if (star_fl)
01650 return star(program, mark, string, expression);
01651 }
01652 if (*expression & DONE) {
01653 program->end_ptr = string;
01654
01655
01656
01657
01658
01659
01660 if ((*expression & EOLN) && *string != '\n' && *string != '\0')
01661 return NO_MATCH;
01662 if (string == program->start_ptr && !(program->status & BEGIN_LINE)
01663 && !(*expression & EOLN))
01664 return NO_MATCH;
01665 return MATCH;
01666 }
01667 return NO_MATCH;
01668 }
01669
01670
01671
01672
01673
01674
01675 int star(program, end_position, string, expression)
01676 REGEX *program;
01677 register char *end_position;
01678 register char *string;
01679 int *expression;
01680 {
01681 do {
01682 string--;
01683 if (check_string(program, string, expression))
01684 return MATCH;
01685 } while (string != end_position);
01686
01687 return NO_MATCH;
01688 }
01689
01690
01691
01692
01693
01694
01695 int in_list(list, c, list_length, opcode)
01696 register int *list;
01697 char c;
01698 register int list_length;
01699 int opcode;
01700 {
01701 if (c == '\0' || c == '\n')
01702 return NO_MATCH;
01703 while (list_length-- > 1) {
01704 if ((*list & LOW_BYTE) == c)
01705 return (opcode & NEGATE) ? NO_MATCH : MATCH;
01706 list++;
01707 }
01708 return (opcode & NEGATE) ? MATCH : NO_MATCH;
01709 }
01710
01711
01712
01713
01714
01715
01716 void dummy_line()
01717 {
01718 (void) line_insert(tail->prev, "\n", 1);
01719 tail->prev->shift_count = DUMMY;
01720 if (last_y != screenmax) {
01721 last_y++;
01722 bot_line = bot_line->next;
01723 }
01724 }