home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / pine / pico / pico.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-06  |  22.0 KB  |  1,003 lines

  1. #if    !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: pico.c,v 4.19 1993/12/02 16:44:31 mikes Exp $";
  3. #endif
  4. /*
  5.  * Program:    Main Pine Composer routines
  6.  *
  7.  *
  8.  * Michael Seibel
  9.  * Networks and Distributed Computing
  10.  * Computing and Communications
  11.  * University of Washington
  12.  * Administration Builiding, AG-44
  13.  * Seattle, Washington, 98195, USA
  14.  * Internet: mikes@cac.washington.edu
  15.  *
  16.  * Please address all bugs and comments to "pine-bugs@cac.washington.edu"
  17.  *
  18.  * Copyright 1991-1993  University of Washington
  19.  *
  20.  *  Permission to use, copy, modify, and distribute this software and its
  21.  * documentation for any purpose and without fee to the University of
  22.  * Washington is hereby granted, provided that the above copyright notice
  23.  * appears in all copies and that both the above copyright notice and this
  24.  * permission notice appear in supporting documentation, and that the name
  25.  * of the University of Washington not be used in advertising or publicity
  26.  * pertaining to distribution of the software without specific, written
  27.  * prior permission.  This software is made available "as is", and
  28.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  29.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  30.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  31.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  32.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  33.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  34.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  35.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  36.  *
  37.  * Pine and Pico are trademarks of the University of Washington.
  38.  * No commercial use of these trademarks may be made without prior
  39.  * written permission of the University of Washington.
  40.  *
  41.  *
  42.  * WEEMACS/PICO NOTES:
  43.  *
  44.  * 01 Nov 89 - MicroEmacs 3.6 vastly pared down and becomes a function call 
  45.  *            weemacs() and plugged into the Pine mailer.  Lots of unused
  46.  *           MicroEmacs code laying around.
  47.  *
  48.  * 17 Jan 90 - weemacs() became weemacs() the composer.  Header editing
  49.  *           functions added.
  50.  *
  51.  * 09 Sep 91 - weemacs() renamed pico() for the PIne COmposer.
  52.  *
  53.  */
  54.  
  55.  
  56. /*
  57.  * This program is in public domain; written by Dave G. Conroy.
  58.  * This file contains the main driving routine, and some keyboard processing
  59.  * code, for the MicroEMACS screen editor.
  60.  *
  61.  * REVISION HISTORY:
  62.  *
  63.  * 1.0  Steve Wilhite, 30-Nov-85
  64.  *      - Removed the old LK201 and VT100 logic. Added code to support the
  65.  *        DEC Rainbow keyboard (which is a LK201 layout) using the the Level
  66.  *        1 Console In ROM INT. See "rainbow.h" for the function key defs
  67.  *      Steve Wilhite, 1-Dec-85
  68.  *      - massive cleanup on code in display.c and search.c
  69.  *
  70.  * 2.0  George Jones, 12-Dec-85
  71.  *      - Ported to Amiga.
  72.  *
  73.  * 3.0  Daniel Lawrence, 29-Dec-85
  74.  *    16-apr-86
  75.  *    - updated documentation and froze development for 3.6 net release
  76.  */
  77.  
  78. #include        <stdio.h>
  79. #include    <setjmp.h>
  80.  
  81. /* make global definitions not external */
  82. #define    maindef
  83.  
  84. #include    "osdep.h"    /* operating system dependent includes */
  85. #include    "pico.h"    /* PIne COmposer definitions */
  86. #include        "estruct.h"    /* global structures and defines */
  87. #include    "efunc.h"    /* function declarations and name table    */
  88. #include    "edef.h"    /* global definitions */
  89. #include    "ebind.h"    /* default key bindings */
  90. #ifdef HEBREW
  91. #include "hebrew.h"
  92. #endif
  93.  
  94.  
  95. #ifdef    ANSI
  96.     int  func_init(void);
  97.     void breplace(void *);
  98.     int  insline(LINE **, short *);
  99. #else
  100.     int  func_init();
  101.     void breplace();
  102.     int  insline();
  103. #endif
  104.  
  105.  
  106. /*
  107.  * function key mappings
  108.  */
  109. static int pfkm[12][2] = {
  110.     { F1,  (CTRL|'G')},
  111.     { F2,  (CTRL|'X')},
  112.     { F3,  (CTRL|'C')},
  113.     { F4,  (CTRL|'J')},
  114.     { F5,  (CTRL|'R')},
  115.     { F6,  (CTRL|'W')},
  116.     { F7,  (CTRL|'Y')},
  117.     { F8,  (CTRL|'V')},
  118.     { F9,  (CTRL|'K')},
  119.     { F10, (CTRL|'U')},
  120.     { F11, (CTRL|'O')},
  121. #ifdef    SPELLER
  122.     { F12, (CTRL|'T')}
  123. #else
  124.     { F12, (CTRL|'D')}
  125. #endif
  126. };
  127.  
  128.  
  129. /*
  130.  * flag for the various functions in pico() to set when ready
  131.  * for pico() to return...
  132.  */
  133. int      pico_all_done = 0;
  134. jmp_buf  finstate;
  135. char    *pico_anchor = NULL;
  136.  
  137. /*
  138.  * pico - the main routine for Pine's composer.
  139.  *
  140.  */
  141. pico(pm)
  142. PICO *pm;
  143. {
  144.     register int    c;
  145.     register int    f;
  146.     register int    n;
  147.     int      i;
  148.     char     bname[NBUFN];        /* buffer name of file to read */
  149.     extern   struct on_display ods;
  150.  
  151.     Pmaster       = pm;
  152.     gmode        |= pm->pine_flags;/* high 4 bits rsv'd by pine composer */
  153.     pico_all_done = 0;
  154. #ifdef HEBREW
  155.     init_hebdata();
  156. #endif
  157.  
  158.     if(!vtinit())            /* Init Displays.      */
  159.       return(COMP_CANCEL);
  160.  
  161.     strcpy(bname, "main");        /* default buffer name */
  162.     edinit(bname);            /* Buffers, windows.   */
  163.  
  164.     InitMailHeader(pm);            /* init mail header structure */
  165.     (*Pmaster->clearcur)();
  166.  
  167.     /* setup to process commands */
  168.     lastflag = 0;            /* Fake last flags.     */
  169.     curbp->b_mode |= gmode;        /* and set default modes*/
  170.  
  171.     pico_anchor = (char *)malloc((strlen(Pmaster->pine_anchor) + 1)
  172.                  * sizeof(char));
  173.     if(pico_anchor)
  174.       strcpy(pico_anchor, Pmaster->pine_anchor);
  175.  
  176.     if(pm->msgtext)
  177.       breplace(pm->msgtext);
  178.  
  179.     pico_all_done = setjmp(finstate);    /* jump out of HUP handler ? */
  180.  
  181.     if(!pico_all_done){
  182.     if(pm->pine_flags&P_BODY){    /* begin editing the header? */
  183.         ArrangeHeader();        /* line up pointers */
  184.     }
  185.     else{
  186.         update();            /* paint screen, */
  187.         HeaderEditor(0, 0);        /* start editing... */
  188.     }
  189.     }
  190.  
  191.     while(1){
  192.     if(pico_all_done){
  193.         c = anycb() ? BUF_CHANGED : 0;
  194.         switch(pico_all_done){    /* prepare for/handle final events */
  195.           case COMP_EXIT :        /* already confirmed */
  196.         packheader();
  197.         c |= COMP_EXIT;
  198.         break;
  199.  
  200.           case COMP_CANCEL :    /* also already confirmed */
  201.         c = COMP_CANCEL;
  202.         break;
  203.  
  204.           case COMP_GOTHUP:
  205.         /* 
  206.          * pack up and let caller know that we've received a SIGHUP
  207.          */
  208.         if(ComposerEditing)        /* expand addr if needed */
  209.           resolve_niks(ods.cur_e);
  210.  
  211.         packheader();
  212.         c |= COMP_GOTHUP;
  213.         break;
  214.  
  215.           case COMP_SUSPEND :
  216.           default:            /* safest if internal error */
  217.         packheader();
  218.         c |= COMP_SUSPEND;
  219.         break;
  220.         }
  221.  
  222.         free(pico_anchor);
  223.         vttidy();            /* clean up tty modes */
  224.         zotdisplay();        /* blast display buffers */
  225.         zotedit();
  226.         return(c);
  227.     }
  228.     update();            /* Fix up the screen    */
  229.  
  230. #if    defined(DOS) && defined(MOUSE)
  231.     register_mfunc(pico_mouse, 2, 0, term.t_nrow-3, term.t_ncol);
  232. #endif
  233.     c = GetKey();    
  234.  
  235.     if(c == NODATA || time_to_check()){    /* new mail ? */
  236.         if((*Pmaster->newmail)(&i, 0, c == NODATA ? 0 : 2) >= 0){
  237.         mlerase();
  238.         (*Pmaster->showmsg)(c);
  239.         mpresf = 1;
  240.         }
  241.  
  242.         if(i || mpresf){        /* let em know cursor moved */
  243.         movecursor(0, 0);
  244.         (*Pmaster->clearcur)();
  245.         }
  246.     }
  247.  
  248.     if(c == NODATA)        /* no op, getkey timed out */
  249.       continue;
  250.  
  251.     if (mpresf != FALSE) {        /* message stay around only  */
  252.         if (mpresf++ > MESSDELAY)    /* so long! */
  253.           mlerase();
  254.     }
  255.  
  256.     f = FALSE;            /* vestigial */
  257.     n = 1;
  258.     
  259. #if    defined(DOS) && defined(MOUSE)
  260.     clear_mfunc();
  261. #endif
  262.     execute(normal(c, pfkm, 2), f, n);    /* Do it.               */
  263.     }
  264. }
  265.  
  266. /*
  267.  * Initialize all of the buffers and windows. The buffer name is passed down
  268.  * as an argument, because the main routine may have been told to read in a
  269.  * file by default, and we want the buffer name to be right.
  270.  */
  271.  
  272. /*
  273.  * For the pine composer, we don't want to take over the whole screen
  274.  * for editing.  the first some odd lines are to be used for message 
  275.  * header information editing.
  276.  */
  277. edinit(bname)
  278. char    bname[];
  279. {
  280.     register BUFFER *bp;
  281.     register WINDOW *wp;
  282.  
  283.     if(Pmaster)
  284.       func_init();
  285.  
  286.     bp = bfind(bname, TRUE, 0);             /* First buffer         */
  287.     wp = (WINDOW *) malloc(sizeof(WINDOW)); /* First window         */
  288.  
  289.     if (bp==NULL || wp==NULL){
  290.     if(Pmaster)
  291.       return(0);
  292.     else
  293.       exit(1);
  294.     }
  295.  
  296.     curbp  = bp;                            /* Make this current    */
  297.     wheadp = wp;
  298.     curwp  = wp;
  299.     wp->w_wndp  = NULL;                     /* Initialize window    */
  300.     wp->w_bufp  = bp;
  301.     bp->b_nwnd  = 1;                        /* Displayed.           */
  302.     wp->w_linep = bp->b_linep;
  303.     wp->w_dotp  = bp->b_linep;
  304.     wp->w_doto  = 0;
  305.     wp->w_markp = NULL;
  306.     wp->w_marko = 0;
  307.  
  308.     if(Pmaster){
  309.     wp->w_toprow = COMPOSER_TOP_LINE;
  310.     wp->w_ntrows = term.t_nrow - COMPOSER_TOP_LINE - 2;
  311.     fillcol = (term.t_ncol > 80) ? 77 : term.t_ncol - 6;
  312.     }
  313.     else{
  314.         wp->w_toprow = 2;
  315.         wp->w_ntrows = term.t_nrow-4;           /* "-1" for mode line.  */
  316.     fillcol = term.t_ncol - 6;              /* set fill column */
  317.     }
  318.  
  319.     wp->w_force = 0;
  320.     wp->w_flag  = WFMODE|WFHARD;            /* Full.                */
  321. }
  322.  
  323.  
  324. /*
  325.  * This is the general command execution routine. It handles the fake binding
  326.  * of all the keys to "self-insert". It also clears out the "thisflag" word,
  327.  * and arranges to move it to the "lastflag", so that the next command can
  328.  * look at it. Return the status of command.
  329.  */
  330. execute(c, f, n)
  331. int c, f, n;
  332. {
  333.     register KEYTAB *ktp;
  334.     register int    status;
  335.  
  336.     ktp = (Pmaster) ? &keytab[0] : &pkeytab[0];
  337.  
  338.     while (ktp->k_fp != NULL) {
  339.     if (ktp->k_code == c) {
  340.  
  341.         if(lastflag&CFFILL){
  342.         curwp->w_flag |= WFMODE;
  343.         if(Pmaster == NULL)
  344.           sgarbk = TRUE;
  345.         }
  346.  
  347.         thisflag = 0;
  348.         status   = (*ktp->k_fp)(f, n);
  349.         lastflag = thisflag;
  350.  
  351.         return (status);
  352.     }
  353.     ++ktp;
  354.     }
  355. #ifdef HEBREW
  356.     control_mode=0;
  357. #endif
  358.  
  359. #ifdef    DOS
  360.     if (c>=0x20 && c<=0xFF) {
  361. #else
  362.     if ((c>=0x20 && c<=0x7E)                /* Self inserting.      */
  363.         ||  (c>=0xA0 && c<=0xFE)) {
  364. #endif
  365.  
  366.     if (n <= 0) {                   /* Fenceposts.          */
  367.         lastflag = 0;
  368.         return (n<0 ? FALSE : TRUE);
  369.     }
  370.     thisflag = 0;                   /* For the future.      */
  371.  
  372.     /* if we are in overwrite mode, not at eol,
  373.        and next char is not a tab or we are at a tab stop,
  374.        delete a char forword            */
  375.     if (curwp->w_bufp->b_mode & MDOVER &&
  376.         curwp->w_doto < curwp->w_dotp->l_used &&
  377.         (lgetc(curwp->w_dotp, curwp->w_doto).c != '\t' ||
  378.          (curwp->w_doto) % 8 == 7))
  379.       ldelete(1, FALSE);
  380.  
  381.     /* do the appropriate insertion */
  382.     /* pico never does C mode, this is simple */
  383.     status = linsert(n, c);
  384.  
  385.     /*
  386.      * Check to make sure we didn't go off of the screen
  387.      * with that character.  If so wrap the line...
  388.      * note: in pico,  fillcol and wrap-mode are always set and 
  389.      *      wrapword behaves somewhat differently
  390.      */
  391.     if(((llength(curwp->w_dotp)+2 >= ((Pmaster && term.t_ncol > 80)
  392.                                            ? 77 : term.t_ncol))
  393.         || (c == ' ' && getccol(FALSE) > fillcol))
  394.        && (curwp->w_bufp->b_mode & MDWRAP))
  395. #ifdef HEBREW
  396.       {
  397.       if(compose_heb){
  398.     if((curwp->w_doto>llength(curwp->w_dotp)-3) ||
  399.        (hebmain && ((curwp->w_dotp->l_type==L_ENG &&
  400.         curwp->w_dotp->l_text[0].c!=' ') ||
  401.         (curwp->w_dotp->l_type==L_HEB &&
  402.          curwp->w_dotp->l_text[llength(curwp->w_dotp)-1].c!=' '))) ||
  403.         (!hebmain && ((curwp->w_dotp->l_type==L_ENG &&
  404.             curwp->w_dotp->l_text[llength(curwp->w_dotp)-1].c!=' ') ||
  405.             (curwp->w_dotp->l_type==L_HEB &&
  406.             curwp->w_dotp->l_text[0].c!=' '))))
  407.                 wrapword();
  408.       }
  409.       else wrapword();
  410.     }
  411. #else
  412.       wrapword();
  413. #endif
  414.  
  415.     lastflag = thisflag;
  416.     return (status);
  417.     }
  418.     
  419. #ifdef HEBREW
  420.     control_mode=0;
  421. #endif
  422.     if(c&CTRL)
  423.       emlwrite("\007Unknown Command: ^%c", (void *)(c&0xff));
  424.     else
  425.       emlwrite("\007Unknown Command", NULL);
  426.  
  427.     lastflag = 0;                           /* Fake last flags.     */
  428.     return (FALSE);
  429. }
  430.  
  431.  
  432.  
  433. /*
  434.  * Fancy quit command, as implemented by Norm. If the any buffer has
  435.  * changed do a write on that buffer and exit emacs, otherwise simply exit.
  436.  */
  437. quickexit(f, n)
  438. int f, n;
  439. {
  440.     register BUFFER *bp;    /* scanning pointer to buffers */
  441.  
  442.     bp = bheadp;
  443.     while (bp != NULL) {
  444.     if ((bp->b_flag&BFCHG) != 0    /* Changed.             */
  445.         && (bp->b_flag&BFTEMP) == 0) {    /* Real.                */
  446.         curbp = bp;        /* make that buffer cur    */
  447.         filesave(f, n);
  448.     }
  449.     bp = bp->b_bufp;            /* on to the next buffer */
  450.     }
  451.     wquit(f, n);                             /* conditionally quit   */
  452. }
  453.  
  454.  
  455.  
  456. /* 
  457.  * abort_composer - ask the question here, then go quit or 
  458.  *                  return FALSE
  459.  */
  460. abort_composer(f, n)
  461. int f, n;
  462. {
  463.     switch(mlyesno("Cancelling will abandon your mail message.  Cancel", 
  464.             FALSE)){
  465.       case TRUE:
  466. #ifdef HEBREW
  467.     if(compose_heb)reverse_pad_buf();
  468. #endif
  469.     pico_all_done = COMP_CANCEL;
  470.     return(TRUE);
  471.  
  472.       case ABORT:
  473.     emlwrite("\007Cancel Cancelled", NULL);
  474.     break;
  475.  
  476.       default:
  477.     mlerase();
  478.     }
  479.     return(FALSE);
  480. }
  481.  
  482.  
  483. /*
  484.  * suspend_composer - return to pine with what's been edited so far
  485.  */
  486. suspend_composer(f, n)
  487. int f, n;
  488. {
  489. #ifdef HEBREW
  490.     if(compose_heb)reverse_pad_buf();
  491. #endif
  492.     pico_all_done = COMP_SUSPEND;
  493. }
  494.  
  495.  
  496.  
  497. /*
  498.  * Quit command. If an argument, always quit. Otherwise confirm if a buffer
  499.  * has been changed and not written out. Normally bound to "C-X C-C".
  500.  */
  501. wquit(f, n)
  502. int f, n;
  503. {
  504.     register int    s;
  505.  
  506.     if(Pmaster){
  507.     char *prompt;
  508.     int   defans;
  509.  
  510.     /*
  511.      * if we're not in header, show some of it as we verify sending...
  512.      */
  513.     setimark(FALSE, 1);
  514.     if(ComposerTopLine == COMPOSER_TOP_LINE){
  515.         gotobob(FALSE, 1);
  516.         update();
  517.     }
  518.  
  519.     if(AttachError()){
  520.         prompt = "\007Problem with attachments!  Send anyway";
  521.         defans = FALSE;
  522.     }
  523.     else{
  524.         prompt = "Send message";
  525.         defans = TRUE;
  526.     }
  527.  
  528.     switch(mlyesno(prompt, defans)){
  529.       case TRUE:
  530. #ifdef HEBREW
  531.     if(compose_heb)reverse_pad_buf();
  532. #endif
  533.         pico_all_done = COMP_EXIT;
  534.         return(TRUE);
  535.       case ABORT:
  536.         emlwrite("\007Send Message Cancelled", NULL);
  537.         break;
  538.       default:
  539.         mlerase();
  540.     }
  541.  
  542.     swapimark(FALSE, 1);
  543.     }
  544.     else{
  545.         if (f != FALSE                          /* Argument forces it.  */
  546.         || anycb() == FALSE                     /* All buffers clean.   */
  547.                         /* User says it's OK.   */
  548.         || (s=mlyesno("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES)", -1)) == FALSE) {
  549.                 vttidy();
  550.                 exit(0);
  551.         }
  552.  
  553.     if(s == TRUE){
  554.         if(filewrite(0,1) == TRUE)
  555.           wquit(1, 0);
  556.     }
  557.     else if(s == ABORT){
  558.         emlwrite("\007Exit Cancelled", NULL);
  559.     }
  560.         return(s);
  561.     }
  562.  
  563.     return(FALSE);
  564. }
  565.  
  566.  
  567. /*
  568.  * Abort.
  569.  * Beep the beeper. Kill off any keyboard macro, etc., that is in progress.
  570.  * Sometimes called as a routine, to do general aborting of stuff.
  571.  */
  572. ctrlg(f, n)
  573. int f, n;
  574. {
  575.     (*term.t_beep)();
  576.     if (kbdmip != NULL) {
  577.     kbdm[0] = (CTLX|')');
  578.     kbdmip  = NULL;
  579.     }
  580.     emlwrite("Cancelled", NULL);
  581.     return (ABORT);
  582. }
  583.  
  584.  
  585. /* tell the user that this command is illegal while we are in
  586.  *  VIEW (read-only) mode
  587.  */
  588. rdonly()
  589. {
  590.     (*term.t_beep)();
  591.     emlwrite("Key illegal in VIEW mode", NULL);
  592.     return(FALSE);
  593. }
  594.  
  595.  
  596.  
  597. /*
  598.  * reset all globals to their initial values
  599.  */
  600. func_init()
  601. {
  602.     extern int    vtrow;
  603.     extern int    vtcol;
  604.     extern int    lbound;
  605.     extern int    ttrow;
  606.     extern int    ttcol;
  607.  
  608.     /*
  609.      * re-initialize global buffer type variables ....
  610.      */
  611.     fillcol = (term.t_ncol > 80) ? 77 : term.t_ncol - 6;
  612.     eolexist = TRUE;
  613.     revexist = FALSE;
  614.     sgarbf = TRUE;
  615.     mpresf = FALSE;
  616.     mline_open = FALSE;
  617.     ComposerEditing = FALSE;
  618.  
  619.     /*
  620.      * re-initialize hardware display variables ....
  621.      */
  622.     vtrow = vtcol = lbound = 0;
  623.     ttrow = ttcol = HUGE;
  624.  
  625.     pat[0] = rpat[0] = '\0';
  626. }
  627.  
  628.  
  629. /*
  630.  * pico_help - help function for standalone composer
  631.  */
  632. pico_help(text, title, i)
  633. char *text[], *title;
  634. int i;
  635. {
  636.     register    int numline = 0;
  637.     char        **p;
  638.  
  639.     p = text;
  640.     while(*p++ != NULL) 
  641.       numline++;
  642.     return(wscrollw(COMPOSER_TOP_LINE, term.t_nrow-1, text, numline));
  643.  
  644. }
  645.  
  646.  
  647.  
  648. #if     TERMCAP
  649. /*
  650.  * zottree() - kills the key pad function key search tree
  651.  *                and frees all lines associated with it!!!
  652.  */
  653. zottree(nodeptr)
  654. struct    KBSTREE    *nodeptr;
  655. {
  656.     if(nodeptr != NULL){
  657.     zottree(nodeptr->left);
  658.     zottree(nodeptr->down);
  659.     free((char *) nodeptr);
  660.     }
  661. }
  662. #endif
  663.  
  664.  
  665. /*
  666.  * zotedit() - kills the buffer and frees all lines associated with it!!!
  667.  */
  668. zotedit()
  669. {
  670. #ifdef    OLDWAY
  671.     register int    s;
  672.  
  673.     /*
  674.      * clean up the lines and buffer ...
  675.      */
  676.     curbp->b_flag &= ~BFCHG;
  677.  
  678.     if ((s=bclear(curbp)) != TRUE)        /* Blow text away.      */
  679.       return(s);
  680. #else
  681.     wheadp->w_linep = wheadp->w_dotp = wheadp->w_markp = NULL;
  682.     bheadp->b_linep = bheadp->b_dotp = bheadp->b_markp = NULL;
  683. #endif
  684.  
  685.     free((char *) wheadp);            /* clean up window */
  686.     wheadp = NULL;
  687.     curwp  = NULL;
  688.  
  689.     free((char *) bheadp);            /* clean up buffers */
  690.     bheadp = NULL;
  691.     curbp  = NULL;
  692.  
  693.     zotheader();                /* blast header lines */
  694.  
  695. #ifdef    OLDWAY
  696.     zotdisplay();                /* blast display buffers */
  697. #else
  698.     kdelete();                    /* blast kill buffer */
  699. #endif
  700.  
  701. #if     TERMCAP
  702.     zottree(kpadseqs);
  703.     kpadseqs = NULL;
  704. #endif
  705. }
  706.  
  707.  
  708. /* 
  709.  * Below are functions for use outside pico to manipulate text
  710.  * in a pico's native format (circular linked list of lines).
  711.  *
  712.  * The idea is to streamline pico use by making it fairly easy
  713.  * for outside programs to prepare text intended for pico's use.
  714.  * The simple char * alternative is messy as it requires two copies
  715.  * of the same text, and isn't very economic in limited memory
  716.  * situations (THANKS BELLEVUE-BILLY.).
  717.  */
  718. typedef struct picotext {
  719.     LINE *linep;
  720.     LINE *dotp;
  721.     short doto;
  722.     short crinread;
  723. } PICOTEXT;
  724.  
  725. #define PT(X)    ((PICOTEXT *)(X))
  726.  
  727. /*
  728.  * pico_get - return window struct pointer used as a handle
  729.  *            to the other pico_xxx routines.
  730.  */
  731. void *
  732. pico_get()
  733. {
  734.    PICOTEXT *wp = NULL;
  735.    LINE     *lp = NULL;
  736.  
  737.    if(wp = (PICOTEXT *)malloc(sizeof(PICOTEXT))){
  738.        wp->crinread = 0;
  739.        if((lp = lalloc(0)) == NULL){
  740.        free(wp);
  741.        return(NULL);
  742.        }
  743.  
  744.        wp->dotp = wp->linep = lp->l_fp = lp->l_bp = lp;
  745.        wp->doto = 0;
  746.    }
  747.    else
  748.      emlwrite("Can't allocate space for text", NULL);
  749.  
  750.    return((void *)wp);
  751. }
  752.  
  753. /*
  754.  * pico_give - free resources and give up picotext struct
  755.  */
  756. void
  757. pico_give(w)
  758. void *w;
  759. {
  760.     register LINE *lp;
  761.     register LINE *fp;
  762.  
  763.     fp = lforw(PT(w)->linep);
  764.     while((lp = fp) != PT(w)->linep){
  765.         fp = lforw(lp);
  766.     free(lp);
  767.     }
  768.     free(PT(w)->linep);
  769.     free((PICOTEXT *)w);
  770. }
  771.  
  772. /*
  773.  * pico_readc - return char at current point.  Up to calling routines
  774.  *              to keep cumulative count of chars.
  775.  */
  776. int
  777. pico_readc(w, c)
  778. void          *w;
  779. unsigned char *c;
  780. {
  781.     int rv     = 0;
  782.  
  783.     if(PT(w)->crinread){
  784.     *c = '\012';                /* return LF */
  785.     PT(w)->crinread = 0;
  786.     rv++;
  787.     }
  788.     else if(PT(w)->doto < llength(PT(w)->dotp)){ /* normal char to return */
  789.         *c = (unsigned char) lgetc(PT(w)->dotp, (PT(w)->doto)++).c;
  790.     rv++;
  791.     }
  792.     else if(lforw(PT(w)->dotp) != PT(w)->linep){ /* return line break */
  793.     PT(w)->dotp = lforw(PT(w)->dotp);
  794.     PT(w)->doto = 0;
  795. #if    defined(DOS)
  796.     *c = '\015';
  797.     PT(w)->crinread++;
  798. #else
  799.     *c = '\012';                /* return local eol! */
  800. #endif
  801.     rv++;
  802.     }                        /* else no chars to return */
  803.  
  804.     return(rv);
  805. }
  806.  
  807.  
  808. /*
  809.  * pico_writec - write a char into picotext and advance pointers.
  810.  *               Up to calling routines to keep track of total chars
  811.  *               written
  812.  */
  813. int
  814. pico_writec(w, c)
  815. void *w;
  816. int   c;
  817. {
  818.     int   rv = 0;
  819.  
  820. #ifdef HEBREW
  821.     force_eng=1;
  822. #endif
  823.     if(c == '\r')                /* ignore CR's */
  824.       rv++;                    /* so fake it */
  825.     else if(c == '\n'){                /* insert newlines on LF */
  826.     
  827.     if(PT(w)->linep == PT(w)->dotp){    /* special case */
  828.         if(!insline(&(PT(w)->dotp), &(PT(w)->doto)))
  829.           return(0);
  830.     }
  831.  
  832.     if(!insline(&(PT(w)->dotp), &(PT(w)->doto)))
  833.       return(0);
  834.  
  835.         rv++;
  836.     }
  837.     else
  838.       rv = geninsert(&(PT(w)->dotp), &(PT(w)->doto), PT(w)->linep, c, 0, 1);
  839.  
  840. #ifdef HEBREW
  841.     force_eng=0;
  842. #endif
  843.     return((rv) ? 1 : 0);            /* return number written */
  844. }
  845.  
  846.  
  847. /*
  848.  * pico_puts - just write the given string into the text
  849.  */
  850. int
  851. pico_puts(w, s)
  852. void *w;
  853. char *s;
  854. {
  855.     while(*s != '\0')
  856.       pico_writec(w, (int)*s++);
  857. }
  858.  
  859.  
  860. /*
  861.  * pico_seek - position dotp and dot at requested location
  862.  */
  863. int
  864. pico_seek(w, offset, orig)
  865. void *w;
  866. long  offset;
  867. int   orig;
  868. {
  869.     register LINE *lp;
  870.  
  871.     PT(w)->crinread = 0;
  872.     switch(orig){
  873.       case 0 :                /* SEEK_SET */
  874.     PT(w)->dotp = lforw(PT(w)->linep);
  875.     PT(w)->doto = 0;
  876.       case 1 :                /* SEEK_CUR */
  877.     lp = PT(w)->dotp;
  878.     while(lp != PT(w)->linep){
  879.         if(offset <= llength(lp)){
  880.         PT(w)->doto = (int)offset;
  881.         PT(w)->dotp = lp;
  882.         break;
  883.         }
  884.  
  885.         offset -= ((long)llength(lp)
  886. #ifdef    DOS
  887.                + 2L);
  888. #else
  889.                + 1L);
  890. #endif
  891.         lp = lforw(lp);
  892.     }
  893.         break;
  894.  
  895.       case 2 :                /* SEEK_END */
  896.     PT(w)->dotp = lback(PT(w)->linep);
  897.     PT(w)->doto = llength(PT(w)->dotp);
  898.     break;
  899.       default :
  900.         return(-1);
  901.     }
  902.  
  903.     return(0);
  904. }
  905.  
  906.  
  907. /*
  908.  * pico_replace - replace whatever's in the associated text with
  909.  *                the given string
  910.  */
  911. int
  912. pico_replace(w, s)
  913. void *w;
  914. char *s;
  915. {
  916.     return(0);
  917. }
  918.  
  919. /*
  920.  * breplace - replace the current window's text with the given 
  921.  *            LINEs
  922.  */
  923. void
  924. breplace(w)
  925. void *w;
  926. {
  927.     register LINE *lp;
  928.     register LINE *fp;
  929.  
  930.     fp = lforw(curbp->b_linep);
  931.     while((lp = fp) != curbp->b_linep){        /* blast old lines */
  932.         fp = lforw(lp);
  933.     free(lp);
  934.     }
  935.     free(curbp->b_linep);
  936.  
  937.     curbp->b_linep  = PT(w)->linep;            /* arrange pointers */
  938.  
  939.     curwp->w_linep = lforw(curbp->b_linep);
  940.     curwp->w_dotp  = lforw(curbp->b_linep);
  941.     curwp->w_doto  = 0;
  942.     curwp->w_markp = curwp->w_imarkp = NULL;
  943.     curwp->w_marko = curwp->w_imarko = 0;
  944.  
  945.     curbp->b_dotp   = curwp->w_dotp;
  946.     curbp->b_doto   = curbp->b_marko  = 0;
  947.     curbp->b_markp  = NULL;
  948.  
  949.     curwp->w_flag |= WFHARD;
  950. }
  951.  
  952.  
  953. /*
  954.  * generic line insert function.
  955.  */
  956. insline(dotp, doto)
  957. LINE **dotp;
  958. short *doto;
  959. {
  960.     register LINE *lp;
  961.  
  962.     if((lp = lalloc(0)) == NULL){
  963.     emlwrite("Can't allocate space for more characters",NULL);
  964.     return(FALSE);
  965.     }
  966.  
  967.     lp->l_fp = (*dotp)->l_fp;
  968.     lp->l_bp = (*dotp);
  969.     lp->l_fp->l_bp = (*dotp)->l_fp = lp;
  970.     (*dotp) = lp;
  971.     (*doto) = 0;
  972.     return(TRUE);
  973. }
  974. #ifdef HEBREW
  975. char hebmode=0;
  976. char hebmain=0;
  977. char control_mode=0;
  978. char eng_in_heb=0;
  979. char message_mode=0;
  980. char compose_heb=0;
  981. char search_mode=0;
  982. short last_eng_pos;
  983. char force_eng;
  984.  
  985. init_hebdata()
  986. {
  987. hebmain=1;
  988. hebmode=0;
  989. control_mode=0;
  990. eng_in_heb=0;
  991. message_mode = 0;
  992. search_mode=0;
  993. if(compose_heb){
  994.   keytab[0].k_fp=toggle_language;
  995.   pkeytab[0].k_fp=toggle_language;
  996. }
  997. else{
  998.   keytab[0].k_fp=spell;
  999.   pkeytab[0].k_fp=spell;  
  1000. }
  1001. }
  1002. #endif
  1003.