home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 2 / crawlyvol2.bin / program / c / lbbs07 / linedit.c < prev    next >
C/C++ Source or Header  |  1993-05-20  |  12KB  |  608 lines

  1. /* linedit.c - Line-oriented text editor 
  2.  * by Vincent "TMS" Archer
  3.  * adapted for the LazyBBS project by Franck Arnaud
  4.  *    settings:    LINED_UNIX    define to enable original unix version parts
  5.  *                LINED_ALONE    define to make a stand alone version
  6.  *                LINED_ECHO  define to echo chars to console
  7.  *                LINED_IDIOTPROOF define to quit after MAX_IDIOTPROOF
  8.  *                            blanklines
  9.  *                LINED_CLEAN clear buffer so that next call ok
  10.  */
  11.  
  12. /*#define LINED_ALONE*/
  13. #define LINED_IDIOTPROOF
  14. #define LINED_CLEAN
  15.  
  16. #define MAX_IDIOTPROOF 2 /* number of blanklines to quit */
  17.  
  18. #ifdef LINED_UNIX
  19. #include <sys/termios.h>
  20. #endif
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <stdlib.h>
  24. #include <time.h>
  25. #include "linedit.h"
  26.  
  27. #ifndef LINED_ALONE
  28. #include "bbs.h"
  29. #include "miscio.h"
  30. #else
  31. #define out_char putchar
  32. #endif
  33.  
  34. #ifdef LINED_UNIX
  35. struct termios oldmode, newmode;
  36. #ifndef LINED_ECHO /* unix implies echo */
  37. #define LINED_ECHO
  38. #endif
  39. #endif
  40.  
  41. char *filename;
  42. char buffer[1024];
  43.  
  44. #ifdef LINED_UNIX
  45. int Lines, Columns;
  46. #else
  47. #define Lines 23
  48. #define Columns 78
  49. #endif
  50.  
  51. A_line *first_line, *last_line;
  52. int nb_lines;
  53.  
  54. #ifdef LINED_ALONE
  55. int getkey(void )
  56. {
  57.     char c;
  58.     while (read(0, &c, 1) != 1) 
  59.         ;
  60.     return (int) c;
  61. }
  62. #endif
  63.  
  64. yes()
  65. {
  66.     int c;
  67.  
  68.     while (1) {
  69.         fflush(stdout);
  70.         c=getkey();
  71.         if(c<0)
  72.             return 0;
  73.             
  74.         switch (c) {
  75.             case '\r':
  76.             case '\n':
  77.             case 'Y':
  78.             case 'y':
  79.             return(1);
  80.             case 'N':
  81.             case 'n':
  82.             return(0);
  83.         }
  84.     }
  85. }
  86.  
  87.  
  88. void listbuffer(dsp)
  89. int dsp;
  90. {
  91. A_line *line;
  92. int l,n;
  93.  
  94.     l = 1;
  95.     n = Lines-2-dsp;
  96.     for (line = first_line; line; line = line->next) {
  97.         out_printf("%3d|%s\n", l++, line->text);
  98.         if (!n--) {
  99.             out_printf("More [Yes/No]?");
  100.             if (!yes()) {
  101.                 out_char('\n');
  102.                 return;
  103.             }
  104.             out_printf("\r              \r");
  105.             n = Lines-2;
  106.         }
  107.     }
  108. }
  109.  
  110.  
  111. A_line *whichline(no)
  112. int no;
  113. {
  114. A_line *line;
  115.  
  116.     for (line = first_line; line; line = line->next)
  117.         if (--no <= 0)
  118.             break;
  119.     return(line);
  120. }
  121.  
  122.  
  123. int geti(min, max, deflt)
  124. int min, max, deflt;
  125. {
  126. int c;
  127. int i, val;
  128.  
  129.     i = 0;
  130.     val = 0;
  131.     while (1) {
  132.         fflush(stdout);
  133.         c=getkey();
  134.         
  135.         if (c == '\r' || c == '\n') {
  136.             if (!i)
  137.                 val = deflt;
  138.             else
  139.                 if (val < min || val > max)
  140.                     return deflt;
  141.             out_char('\n');
  142.             return val;
  143.         }
  144.         if (c == '\b' && i) {
  145. #ifdef LINED_ECHO
  146.             out_printf("\b \b");
  147. #else
  148.             out_printf(" \b");
  149. #endif
  150.             i--;
  151.             val = val/10;
  152.             continue;
  153.         }
  154.         if (c < '0' || c > '9' || i > 3)
  155.             continue;
  156.         if (c == '0' && val == 0)
  157.             continue;
  158.         
  159. #ifdef LINED_ECHO
  160.         out_char(c);
  161. #endif
  162.  
  163.         i++;
  164.         val = val*10 + (c-'0');
  165.     }
  166. }
  167.  
  168. void deleteline(line)
  169. A_line *line;
  170. {
  171.     if (!line)
  172.         return;
  173.     if (line->prev) {
  174.         if (line->cr_at_end)
  175.             line->prev->cr_at_end = 1;
  176.         line->prev->next = line->next;
  177.         if (line->next) {
  178.             line->next->prev = line->prev;
  179.             line->next->cr_before = line->prev->cr_at_end;
  180.         } else
  181.             last_line = line->prev;
  182.     } else {
  183.         first_line = line->next;
  184.         if (line->next) {
  185.             line->next->prev = 0;
  186.             line->next->cr_before = 1;
  187.         } else
  188.             last_line = NULL;
  189.     }
  190.     free(line->text);
  191.     free(line);
  192.     nb_lines--;
  193. }
  194.  
  195.  
  196. A_line *insertline(text, before)
  197. char *text;
  198. A_line *before;
  199. {
  200. A_line *line2;
  201.  
  202.     if (!(line2 = (A_line *)malloc(sizeof(A_line)) )) {
  203.         out_printf("Out of memory!\n");
  204.         return(0);
  205.     }
  206.     if (!(line2->text = strdup(text))) {
  207.         free(line2);
  208.         out_printf("Out of memory!\n");
  209.         return(0);
  210.     }
  211.     line2->cr_at_end = 0;
  212.     line2->next = before;
  213.     if (before) {
  214.         before->cr_before = 0;
  215.         line2->prev = before->prev;
  216.         if (line2->prev) {
  217.             line2->cr_before = line2->prev->cr_at_end;
  218.             line2->prev->next = line2;
  219.         } else {
  220.             line2->cr_before = 1;
  221.             first_line = line2;
  222.         }
  223.         before->prev = line2;
  224.     } else {
  225.         line2->prev = last_line;
  226.         if (last_line) {
  227.             line2->cr_before = line2->prev->cr_at_end;
  228.             last_line->next = line2;
  229.         } else
  230.             first_line = line2;
  231.         last_line = line2;
  232.     }
  233.     nb_lines++;
  234.     return(line2);
  235. }
  236.  
  237.  
  238. ifold(line)
  239. char *line;
  240. {
  241. int l, m, c, cr_at_end;
  242. char *s;
  243. A_line *ll;
  244.  
  245.     l = strlen(line);
  246.     if (line[l-1] == '\n') {
  247.         line[--l] = 0;
  248.         cr_at_end = 1;
  249.     } else
  250.         cr_at_end = 0;
  251.     m = Columns-5;
  252.     while (l > m) {
  253.         c = line[m];
  254.         line[m] = 0;
  255.         if (s = strrchr(line, ' ')) {
  256.             *s++ = '\0';
  257.             line[m] = c;
  258.             if (!insertline(line, (A_line *)0))
  259.                 return(-1);
  260.             line = s;
  261.         } else {
  262.             if (!insertline(line, (A_line *)0))
  263.                 return(-1);
  264.             line += m;
  265.             line[0] = c;
  266.         }
  267.         l = strlen(line);
  268.     }
  269.     if (!(ll = insertline(line, (A_line *)0)))
  270.         return (-1);
  271.     ll->cr_at_end = 1;
  272.     return(0);
  273. }
  274.  
  275.  
  276. void insertbefore(no)
  277. int no;
  278. {
  279. int c;
  280. A_line *line, *line2;
  281. int l, f, brok;
  282. char *s;
  283. #ifdef LINED_IDIOTPROOF
  284. int count_idiot=0;
  285. #endif
  286.  
  287.     if (no == 0) {
  288.         no = nb_lines+1;
  289.         line = 0;
  290.     } else if (!(line = whichline(no)))
  291.         return;
  292.     buffer[0] = 0;
  293.     while (nb_lines < 999) {
  294.         out_printf("%3d|%s", no, buffer);
  295.         l = strlen(buffer);
  296.         f = Columns-5-l;
  297.         brok = 1;
  298.         while (brok) {
  299.             fflush(stdout);
  300.         
  301.             c=getkey();
  302.  
  303.             if (c == '\b' && l) {
  304. #ifdef LINED_ECHO
  305.                 out_printf("\b \b");
  306. #else
  307.                 out_printf(" \b");
  308. #endif
  309.                 buffer[--l] = 0;
  310.                 f++;
  311.                 continue;
  312.             }
  313.             if (c == '\r' || c == '\n') {
  314.                 out_char('\n');
  315.                 if (buffer[0] == '.' && !buffer[1])
  316.                     return;
  317. #ifdef LINED_IDIOTPROOF
  318.                 if(!buffer[0])
  319.                 {
  320.                     if(count_idiot++>=MAX_IDIOTPROOF)
  321.                         return;
  322.                 }
  323.                 else
  324.                     count_idiot=0;
  325. #endif
  326.                 if (!(line2 = insertline(buffer, line)))
  327.                     return;
  328.                 line2->cr_at_end = 1;
  329.                 if (line)
  330.                     line->cr_before = 1;
  331.                 no++;
  332.                 buffer[0] = 0;
  333.                 l = 0;
  334.                 f = Columns-5;
  335.                 break;
  336.             }
  337.             if (c < ' ')
  338.                 continue;
  339.             if (!f) {
  340.                 if (s = strrchr(buffer, ' ')) {
  341.                     *s++ = '\0';
  342.                     for (l = 0; l < strlen(s); l++)
  343.                         out_printf("\b \b");
  344. /* don't (fixme, " \b" ???) */
  345.                     if (!(line2 = insertline(buffer, line)))
  346.                         return;
  347.                     strcpy(buffer, s);
  348.                 } else {
  349.                     if (!(line2 = insertline(buffer, line)))
  350.                         return;
  351.                     buffer[0] = 0;
  352.                 }
  353.                 no++;
  354.                 l = strlen(buffer);
  355.                 f = Columns-5-l;
  356.                 out_char('\n');
  357.                 brok = 0;
  358.             } 
  359. #ifdef LINED_ECHO
  360.             else
  361.                 out_char(c);
  362. #endif
  363.             buffer[l++] = c;
  364.             buffer[l] = 0;
  365.             f--;
  366.         }
  367.     }
  368. }
  369.  
  370.  
  371. int menu_loop()
  372. {
  373. FILE *f;
  374. int c;
  375. int nook;
  376. A_line *line;
  377. int i,j;
  378.  
  379.  
  380.     while (1) {
  381.         out_printf("\
  382. [A]bort edition, [D]elete line(s), [I]nsert text, [L]ist, [R]eplace line(s)\n\
  383. [S]save & exit, your choice: ");
  384.         nook = 1;
  385.         while (nook) {
  386.             fflush(stdout);
  387.             c=getkey();
  388. #ifndef LINED_ECHO
  389.             out_printf("\b");
  390. #endif
  391.             
  392.             switch (c) {
  393.                 case 'a':
  394.                 case 'A':
  395.                 out_printf("Abort\nConfirm abort [Yes/No]?");
  396.                 if (yes()) {
  397.                     out_char('\n');
  398. #ifdef LINED_CLEAN
  399.                     for (line = first_line; line; line = line->next)
  400.                         free(line->text);
  401.                         
  402.                     first_line=0;
  403.                     last_line=0;
  404.                     nb_lines=0;
  405. #endif
  406.                     return 0;
  407.                 }
  408.                 out_char('\n');
  409.                 nook = 0;
  410.                 break;
  411.                 case 'D':
  412.                 case 'd':
  413.                 if (!nb_lines)
  414.                     break;
  415.                 nook = 0;
  416.                 out_printf("Delete\nFrom line[%s%d, none]:",
  417.                     nb_lines==1 ? "" : "1-", nb_lines);
  418.                 i = geti(0, nb_lines, 0);
  419.                 if (!i)
  420.                     break;
  421.                 if (i < nb_lines) {
  422.                     out_printf("  To line[%d-%d, %d]:", i, nb_lines, i);
  423.                     j = geti(i, nb_lines, i);
  424.                 } else
  425.                     j = i;
  426.                 j -= i;
  427.                 while (j-- >= 0)
  428.                     deleteline(whichline(i));
  429.                 break;
  430.                 case 'I':
  431.                 case 'i':
  432.                 nook = 0;
  433.                 out_printf("Insert\n");
  434.                 if (!nb_lines)
  435.                     i = 0;
  436.                 else {
  437.                     out_printf("Before line [%s%d, at end]:",
  438.                         nb_lines==1 ? "" : "1-", nb_lines);
  439.                     i = geti(1, nb_lines, 0);
  440.                 }
  441.                 out_printf("    End insertion with a dot ('.') on an otherwise empty line.\n\
  442.    +");
  443.                 for (j=5; j<Columns; j++)
  444.                     out_char('-');
  445.                 out_char('\n');
  446.                 insertbefore(i);
  447.                 break;
  448.                 case 'L':
  449.                 case 'l':
  450.                 out_printf("List\n");
  451.                 listbuffer(0);
  452.                 nook = 0;
  453.                 break;
  454.                             case 'R':
  455.                             case 'r':
  456.                                 if (!nb_lines)
  457.                                         break;
  458.                                 nook = 0;
  459.                                 out_printf("Replace\nFrom line[%s%d, none]:",
  460.                                         nb_lines==1 ? "" : "1-", nb_lines);
  461.                                 i = geti(0, nb_lines, 0);
  462.                                 if (!i)
  463.                                         break;
  464.                                 if (i < nb_lines) {
  465.                                         out_printf("  To line[%d-%d, %d]:", i, nb_lines, i);
  466.                                         j = geti(i, nb_lines, i);
  467.                                 } else
  468.                                         j = i;
  469.                                 j -= i;
  470.                                 while (j-- >= 0)
  471.                                         deleteline(whichline(i));
  472.                 if (!whichline(i))
  473.                     i = -1;
  474.                                 out_printf("    End insertion with a dot ('.') on an otherwise empty line.\n\
  475.    +");
  476.                                 for (j=5; j<Columns; j++)
  477.                                         out_char('-');
  478.                                 out_char('\n');
  479.                                 insertbefore(i);
  480.                                 break;
  481.                 case 'S':
  482.                 case 's':
  483.                 out_printf("Save\n");
  484.                 if (!(f = fopen(filename, "w"))) {
  485.                     perror("text");
  486.                     nook = 0;
  487.                     break;
  488.                 }
  489.                 for (line = first_line; line; line = line->next)
  490.                 {
  491.                     fprintf(f, "%s\n", line->text);
  492. #ifdef LINED_CLEAN
  493.                     free(line->text);
  494. #endif
  495.                 }
  496.                 fclose(f);
  497. #ifdef LINED_CLEAN
  498.                 first_line=0;
  499.                 last_line=0;
  500.                 nb_lines=0;
  501. #endif
  502.                 return 1;
  503.             }
  504.         }
  505.         out_char('\n');
  506.     }
  507.     return 0;
  508. }
  509.  
  510.  
  511. #ifdef LINED_ALONE
  512. main(argc, argv)
  513. int argc;
  514. char *argv[];
  515. {
  516. char *arg;
  517. FILE *f;
  518. #ifdef LINED_UNIX
  519. char *s, *getenv();
  520. #endif
  521. int i;
  522.  
  523.     argc--;
  524.     argv++;
  525.     while (argc--) {
  526.         arg = *argv++;
  527.         if (*arg == '+')
  528.             continue;
  529.         if (*arg == '-')
  530.             continue;
  531.         filename = arg;
  532.     }
  533. #else /* ! stand_alone */
  534. int edit_file(char *arg)
  535. {
  536.     FILE *f;
  537.     int i;
  538.     filename=arg;
  539. #endif
  540.  
  541.     if (!filename) {
  542.         fprintf(stderr,"edit: file name missing\n");
  543.         exit(1);
  544.     }
  545. #ifdef LINED_UNIX /* terminal initialisation */
  546.     ioctl(0, TCGETS, &oldmode);
  547.     memcpy(&newmode, &oldmode, sizeof(newmode));
  548.     newmode.c_iflag |= IGNBRK|IGNPAR|ISTRIP|ICRNL;
  549.     newmode.c_lflag &= ~(ISIG|ICANON|ECHO|ECHOE|ECHONL);
  550.     newmode.c_cc[VMIN] = 1;
  551.     newmode.c_cc[VTIME] = 0;
  552.     ioctl(0, TCSETS, &newmode);
  553. #endif
  554.  
  555. /*
  556.  * Read the file
  557.  */
  558. #ifdef LINED_UNIX
  559.     s = getenv("TERM");
  560.     if (s && tgetent(buffer, s) == 1) {
  561.         Lines = tgetnum("li");
  562.         Columns = tgetnum("co");
  563.     } else 
  564.     {
  565.         Lines = 23;
  566.         Columns = 80;
  567.     }
  568. #endif
  569.     
  570.     if (f = fopen(filename, "r")) {
  571.         while (fgets(buffer, sizeof(buffer), f) != (char *)0)
  572.             ifold(buffer);
  573.         fclose(f);
  574.     }
  575. /*
  576.  * Enter the editor session
  577.  */
  578.     out_char('\n');
  579.     out_printf("    Please compose your message. End insertion with a single dot on a line.\n");
  580.     out_printf("    Any dot at the beginning of a line will be stripped, so put TWO dots\n");
  581.     out_printf("    when you want one. In other words, type '.' on first column to exit.\n");
  582.     out_printf("   +");
  583.     for (i=6; i<Columns; i++)
  584.         out_char('-');
  585.     out_char('+');
  586.     out_char('\n');
  587.  
  588.     if (first_line)
  589.         listbuffer(4);
  590.     else
  591.         insertbefore(0);
  592.  
  593. #ifdef LINED_ALONE
  594.     menu_loop();
  595. #else
  596.     if(menu_loop())
  597.         return BBSOK;
  598.     return BBSFAIL;
  599. #endif
  600. #ifdef LINED_UNIX
  601.     ioctl(0, TCSETS, &oldmode);
  602. #endif
  603. #ifdef LINED_ALONE
  604.     return 0;
  605. #endif
  606. }
  607.  
  608.