home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 4 / CDPD_IV.bin / networking / uucp / amigauucpsrc / dnews / display.c < prev    next >
C/C++ Source or Header  |  1994-06-29  |  20KB  |  921 lines

  1.  
  2. /*
  3.  *  DISPLAY.C
  4.  *
  5.  *  This module handles all display windows.
  6.  *
  7.  */
  8.  
  9. #include <exec/types.h>
  10. #include <exec/memory.h>
  11. #include "defs.h"
  12. #include <intuition/intuition.h>
  13. #include <clib/exec_protos.h>
  14. #include <clib/intuition_protos.h>
  15.  
  16. Prototype int getyn(char *);
  17. Prototype void *OpenBrowseDisplay(char *, char *, short);
  18. Prototype void SetBrowseTitle(void *, char *);
  19. Prototype void CloseBrowseDisplay(void *);
  20. Prototype void ChangeBrowseDisplay(void *, char *, char *);
  21. Prototype int WaitBrowseEvent(void **, int *, int *);
  22. Prototype void    LoadDisplayConfig(void);
  23. Prototype void    SaveDisplayConfig(void);
  24. Prototype void    RefreshBrowseDisplay(void *, short);
  25.  
  26. Local void TabExpand(char *, short);
  27.  
  28.  
  29.  
  30. #define MAXCONF 3
  31.  
  32. typedef struct Window        Window;
  33. typedef struct NewWindow    NewWindow;
  34. typedef struct IntuiMessage IMsg;
  35.  
  36. typedef struct Display {
  37.     struct Display *Next;
  38.     Window  *Win;        /*    associated window    */
  39.     char    *Name;        /*    name of file        */
  40.     char    *Title;        /*    window title        */
  41.     FILE    *Fi;        /*    file pointer        */
  42.     long    WMask;        /*    wait mask for window    */
  43.     short   Id;         /*    config id        */
  44.     short   FlagRefresh;
  45.     short   ColStart;
  46.     long    FirstNonHdrLine;/*    first non-header line    */
  47.  
  48.     long    TLineNo;        /*    line # for top line    */
  49.     long    TPos;        /*    position (top line)     */
  50.     long    BPos;        /*    position (bottom line)  */
  51.     long    XPos;        /*    end of file (or scan)   */
  52.     long    WLines;        /*    lines displayed in win    */
  53.     long    WMaxLines;        /*    maximum #lines in window*/
  54.     long    FLines;        /*    lines in file if known    */
  55.     struct  Gadget *PropGad;/*    prop gadget for window    */
  56.     long    LastTLine;
  57. } Display;
  58.  
  59. typedef struct Config {
  60.     short   TopEdge;
  61.     short   LeftEdge;
  62.     short   Width;
  63.     short   Height;
  64. } Config;
  65.  
  66. static long    WMask;       /*  Window mask       */
  67. static Display *CachDisp;  /*  last display that had an event           */
  68. static Display *DispBase;  /*  list of displays    */
  69. static short   FlagRefresh;
  70.  
  71. static Config  ConfAry[MAXCONF];
  72.  
  73. Local int   HandleEvent(Display *, int *, int *);
  74. Local void  SaveWindowConfig(Display *);
  75. Local long  BackupFile(Display *, long, long);
  76. Local long  ForwardFile(Display *, long, long);
  77. Local void  SetRefresh(Display *, int);
  78.  
  79. void
  80. FixPropGadget(_disp, all)
  81. void *_disp;
  82. short all;
  83. {
  84.     Display *disp=_disp;
  85.     UWORD VertPot,VertBody;
  86.     short hidden;
  87.     short TopLine;
  88.     short WLines;
  89.  
  90.     if (disp->PropGad==0)
  91.     return;
  92.  
  93.     WLines=(disp->Win->Height-disp->Win->BorderTop)-(disp->Win->BorderBottom+1);
  94.     WLines/=disp->Win->RPort->TxHeight;
  95.  
  96.     if (WLines<disp->FLines) {
  97.     hidden=disp->FLines-WLines;
  98.  
  99.     if (disp->TLineNo>hidden)
  100.         TopLine=hidden;
  101.     else
  102.         TopLine=disp->TLineNo;
  103.  
  104.     VertBody=((WLines-1)*MAXBODY)/(disp->FLines-1);
  105.     VertPot=(TopLine*MAXPOT)/hidden;
  106.     } else {
  107.     VertPot=MAXPOT;
  108.     VertBody=MAXBODY;
  109.     };
  110.     if (all)
  111.     NewModifyProp(disp->PropGad, disp->Win, 0, AUTOKNOB|PROPBORDERLESS|PROPNEWLOOK|FREEVERT, -1, VertPot,-1,VertBody,1);
  112. }
  113.  
  114.  
  115. void *
  116. OpenBrowseDisplay(fileName, title, id)
  117. char *fileName;
  118. char *title;
  119. short id;
  120. {
  121.     static NewWindow Nw = {
  122.     0, 0, 320, 200, -1, -1,
  123.     CLOSEWINDOW|NEWSIZE|MOUSEBUTTONS|VANILLAKEY|REFRESHWINDOW|RAWKEY|
  124.     GADGETUP|GADGETDOWN|MOUSEMOVE,
  125.     WINDOWSIZING|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|
  126.     SIMPLE_REFRESH|ACTIVATE,
  127.     NULL, NULL, NULL, NULL, NULL,
  128.     32, 16, -1, -1, WBENCHSCREEN
  129.     };
  130.     static struct PropInfo PropInfoTemplate = {
  131.     PROPBORDERLESS|FREEVERT|AUTOKNOB|PROPNEWLOOK,    /* Flags */
  132.     -1,                    /* HorizPot     */
  133.     -1,                    /* VertPot        */
  134.     -1,                    /* HorizBody    */
  135.     -1,                    /* VertBody     */
  136.     };
  137.     static struct Gadget WindowGad = {
  138.     0,                    /* Next        */
  139.     0,0,0,0,                /* Position     */
  140.     GFLG_RELHEIGHT|GFLG_RELRIGHT,        /* Flags        */
  141.     GACT_RIGHTBORDER|            /* Activation   */
  142.     GACT_FOLLOWMOUSE|GACT_IMMEDIATE,
  143.     GTYP_PROPGADGET,            /* Type        */
  144.     NULL, NULL,                /* Render        */
  145.     NULL,                    /* GadgetText   */
  146.     NULL,                    /* MX        */
  147.     NULL,                    /* SpecialInfo  */
  148.     1,                    /* Gadget ID    */
  149.     NULL,                    /* UserData     */
  150.     };
  151.  
  152.     Display *disp = malloc(sizeof(Display));
  153.  
  154.     if (title == NULL)
  155.     title = fileName;
  156.  
  157.     setmem(disp, sizeof(Display), 0);
  158.  
  159.     if (id < 0 || id >= MAXCONF)
  160.     id = MAXCONF - 1;
  161.  
  162.     {
  163.     Config *conf = ConfAry + id;
  164.     Nw.LeftEdge = conf->LeftEdge;
  165.     Nw.TopEdge  = conf->TopEdge;
  166.     Nw.Width    = conf->Width;
  167.     Nw.Height   = conf->Height;
  168.     if (Nw.Width < 32) {
  169.         Nw.LeftEdge = 40;
  170.         Nw.Width = 600;
  171.     }
  172.     if (Nw.Height < 16)
  173.         Nw.Height = 150;
  174.     }
  175.  
  176.     disp->Win = OpenWindow(&Nw);
  177.     if (disp->Win == NULL) {
  178.     Nw.LeftEdge = 0;
  179.     Nw.TopEdge  = 0;
  180.     Nw.Width    = 320;
  181.     Nw.Height   = 100;
  182.     disp->Win = OpenWindow(&Nw);
  183.     }
  184.  
  185.     if (disp->Win) {
  186.     struct Gadget *Gad;
  187.     struct PropInfo *Prop;
  188.  
  189.     disp->Name = strdup(fileName);
  190.     disp->Title= strdup(title);
  191.     disp->WMask = 1 << disp->Win->UserPort->mp_SigBit;
  192.     disp->Id = id;
  193.     disp->LastTLine = -20;
  194.  
  195.     disp->Win->UserData = 0;
  196.     Gad = AllocRemember(&disp->Win->UserData, sizeof(*Gad), MEMF_CLEAR);
  197.     Prop = AllocRemember(&disp->Win->UserData, sizeof(*Prop), MEMF_CLEAR);
  198.  
  199.     if (Gad && Prop) {
  200.         struct Window *Window=disp->Win;
  201.  
  202.         *Gad=WindowGad;
  203.         *Prop=PropInfoTemplate;
  204.  
  205.         Gad->LeftEdge=-(Window->BorderRight-5);
  206.         Gad->TopEdge=Window->BorderTop+1;
  207.         Gad->Width=Window->BorderRight-8;
  208.         Gad->Height=-(Window->BorderBottom+Window->BorderTop+11);
  209.  
  210.         Gad->SpecialInfo=(APTR)Prop;
  211.         Gad->GadgetRender=AllocRemember(&disp->Win->UserData, sizeof(struct Image), MEMF_CLEAR);
  212.         if (Gad->GadgetRender) {
  213.         disp->PropGad=Gad;
  214.         AddGadget(Window, Gad, -1);
  215.         RefreshGadgets(Gad, Window, NULL);
  216.         }
  217.     }
  218.  
  219.     SetAPen(disp->Win->RPort, 1);
  220.  
  221.     SetWindowTitles(disp->Win, disp->Title, (char *)-1L);
  222.  
  223.     disp->Next = DispBase;
  224.     DispBase = disp;
  225.  
  226.     WMask |= disp->WMask;
  227.  
  228.     SetRefresh(disp, 0);
  229.     disp->FLines = 0;
  230.     if (disp->Fi = fopen(disp->Name, "r")) {
  231.         disp->FirstNonHdrLine = 0;
  232.         while (fgets(TmpBuf, sizeof(TmpBuf), disp->Fi) && TmpBuf[0] != '\n') {
  233.         ++disp->FirstNonHdrLine;
  234.         ++disp->FLines;
  235.         }
  236.         while (fgets(TmpBuf, sizeof(TmpBuf), disp->Fi))
  237.         ++disp->FLines;
  238.         disp->XPos = ftell(disp->Fi);
  239.     }
  240.     } else {
  241.     free(disp);
  242.     disp = NULL;
  243.     }
  244.     return((void *)disp);
  245. }
  246.  
  247. void
  248. SetBrowseTitle(_disp, title)
  249. void *_disp;
  250. char *title;
  251. {
  252.     Display *disp = _disp;
  253.     char *old = disp->Title;
  254.  
  255.     disp->Title = strdup(title);
  256.     SetWindowTitles(disp->Win, disp->Title, (char *)-1L);
  257.     free(old);
  258. }
  259.  
  260. void
  261. CloseBrowseDisplay(_disp)
  262. void *_disp;
  263. {
  264.     Display *disp = _disp;
  265.     Display *d;
  266.  
  267.     if (disp == CachDisp)
  268.     CachDisp = NULL;
  269.  
  270.     if (DispBase == disp) {                     /*  unlink display  */
  271.     DispBase = disp->Next;
  272.     } else {
  273.     for (d = DispBase; d; d = d->Next) {
  274.         if (d->Next == disp) {
  275.         d->Next = disp->Next;
  276.         break;
  277.         }
  278.     }
  279.     }
  280.  
  281.     SetWindowTitles(disp->Win, NULL, NULL);
  282.  
  283.     if (disp->Win) {
  284.     SaveWindowConfig(disp);
  285.     CloseWindow(disp->Win);
  286.     FreeRemember(&disp->Win->UserData, TRUE);
  287.     }
  288.  
  289.     WMask &= ~disp->WMask;
  290.  
  291.     free(disp->Title);
  292.     free(disp->Name);
  293.     if (disp->Fi)
  294.     fclose(disp->Fi);
  295.     free(disp);
  296. }
  297.  
  298. /*
  299.  *  Change file being displayed
  300.  */
  301.  
  302. void
  303. ChangeBrowseDisplay(_disp, fileName, title)
  304. void *_disp;
  305. char *fileName;
  306. char *title;
  307. {
  308.     Display *disp = _disp;
  309.     Window *win = disp->Win;
  310.  
  311.     if (title == NULL)
  312.     title = fileName;
  313.  
  314.     {
  315.     char *old = disp->Title;
  316.     disp->Title = strdup(title);
  317.     SetWindowTitles(disp->Win, disp->Title, (char *)-1L);
  318.     free(old);
  319.     }
  320.  
  321.     free(disp->Name);
  322.     disp->Name = strdup(fileName);
  323.     if (disp->Fi) {
  324.     fclose(disp->Fi);
  325.     disp->Fi = NULL;
  326.     }
  327.  
  328.     disp->TLineNo = 0;
  329.     disp->LastTLine = -20;
  330.     disp->TPos = 0;
  331.     disp->XPos = 0;
  332.     disp->WLines = 0;
  333.     disp->WMaxLines = 0;
  334.     disp->FLines = 0;
  335.  
  336.     SetRefresh(disp, 0);
  337. }
  338.  
  339. /*
  340.  *  Wait for an event.    While waiting finish up scanning files for which we
  341.  *  do not know the line number extent.  Returns 0 if there are no windows
  342.  *  left.
  343.  */
  344.  
  345. int
  346. WaitBrowseEvent(_pdisp, prow, pcol)
  347. void **_pdisp;
  348. int *prow;
  349. int *pcol;
  350. {
  351.     long mask;
  352.     Display **pdisp = _pdisp;
  353.  
  354.     if (WMask == 0)
  355.     return(0);
  356.  
  357.     for (;;) {
  358.     Display *disp;
  359.  
  360.     if (FlagRefresh && (SetSignal(0,0) & WMask) == 0) {
  361.         for (disp = DispBase; disp; disp = disp->Next) {
  362.         if (disp->FlagRefresh)
  363.             RefreshBrowseDisplay(disp, 0);
  364.         }
  365.         FlagRefresh = 0;
  366.     }
  367.     mask = Wait(WMask);
  368.     if ((disp = CachDisp) && (disp->WMask & mask)) {
  369.         mask &= ~disp->WMask;
  370.         if (HandleEvent(disp, prow, pcol))
  371.         goto event_handled;
  372.     }
  373.     if (mask) {
  374.         for (disp = DispBase; disp; disp = disp->Next) {
  375.         if (mask & disp->WMask) {
  376.             mask &= ~disp->WMask;
  377.             if (HandleEvent(disp, prow, pcol)) {
  378. event_handled:
  379.             *pdisp = disp;
  380.             if (GetHead(&disp->Win->UserPort->mp_MsgList))
  381.                 mask |= disp->WMask;
  382.             if (mask)
  383.                 SetSignal(mask, mask);
  384.             return(1);
  385.             }
  386.         }
  387.         }
  388.     }
  389.     }
  390. }
  391.  
  392. static int
  393. HandleEvent(disp, prow, pcol)
  394. Display *disp;
  395. int *prow;
  396. int *pcol;
  397. {
  398.     int ret = 0;
  399.     IMsg *im;
  400.     Window *win = disp->Win;
  401.     static short PropGadgetDown;
  402.  
  403.     while ((ret == 0) && (im = GetMsg(win->UserPort))) {
  404.     switch(im->Class) {
  405.     case GADGETDOWN:
  406.         PropGadgetDown = 1;
  407.         break;
  408.     case GADGETUP:
  409.         PropGadgetDown = -1;
  410.     case MOUSEMOVE:
  411.         if (PropGadgetDown) {
  412.         UWORD hidden,WLines;
  413.         long lineNo;
  414.  
  415.         if (disp->FLines>disp->WLines) {
  416.             struct PropInfo *PI=(struct SpecialInfo *)disp->PropGad->SpecialInfo;
  417.  
  418.             WLines=(disp->Win->Height-disp->Win->BorderTop)-(disp->Win->BorderBottom+1);
  419.             WLines/=disp->Win->RPort->TxHeight;
  420.             hidden=disp->FLines-WLines;
  421.             lineNo = ((hidden*PI->VertPot)+(MAXPOT/2))/MAXPOT;
  422.             if (lineNo != disp->TLineNo) {
  423.             disp->TLineNo = lineNo;
  424.             disp->TPos = GotoLine(disp, lineNo);
  425.             SetRefresh(disp,0);
  426.             }
  427.         }
  428.         }
  429.         if (PropGadgetDown < 0)
  430.         PropGadgetDown = 0;
  431.         break;
  432.     case CLOSEWINDOW:
  433.         *prow = -1;
  434.         *pcol = -1;
  435.         ret = 1;
  436.         break;
  437.     case VANILLAKEY:
  438.         switch(im->Code) {
  439.         case 27:
  440.         *prow = -1;
  441.         *pcol = -1;
  442.         ret = 1;
  443.         break;
  444.         case 13:
  445.         if (disp->BPos != disp->XPos) {
  446.             disp->TPos = ForwardFile(disp, disp->TPos, 2);
  447.             ++disp->TLineNo;
  448.             SetRefresh(disp, 0);
  449.         }
  450.         break;
  451.         case '2':       /*  page down   */
  452.         case ' ':
  453.         if (disp->BPos != disp->XPos) {
  454.             long move;
  455.  
  456.             for (move = disp->WMaxLines; disp->TLineNo + move > disp->FLines - disp->WMaxLines; --move)
  457.             ;
  458.             if (move < 0)
  459.             move = 0;
  460.  
  461.             disp->TPos = ForwardFile(disp, disp->TPos, move);
  462.             disp->TLineNo += move;
  463.             SetRefresh(disp, 0);
  464.         }
  465.         break;
  466.         case '8':       /*  page up   this article  */
  467.         if (disp->TPos != 0) {
  468.             disp->TPos = BackupFile(disp, disp->TPos, disp->WMaxLines);
  469.             disp->TLineNo -= disp->WMaxLines;
  470.             if (disp->TLineNo < 0)
  471.             disp->TLineNo = 0;
  472.             SetRefresh(disp, 0);
  473.         }
  474.         break;
  475.         case '3':
  476.         if (disp->BPos != disp->XPos) {
  477.             disp->TPos = BackupFile(disp, disp->XPos, disp->WLines);
  478.             disp->TLineNo = disp->FLines - disp->WLines;    /* XXX */
  479.             if (disp->TLineNo < 0)
  480.             disp->TLineNo = 0;
  481.             SetRefresh(disp, 0);
  482.         }
  483.         break;
  484.         case '9':
  485.         if (disp->TPos != 0) {
  486.             disp->TPos = 0;
  487.             disp->TLineNo = 0;
  488.             SetRefresh(disp, 0);
  489.         }
  490.         break;
  491.         case '6':
  492.         SetRefresh(disp, disp->ColStart + 40);
  493.         break;
  494.         case '4':
  495.         SetRefresh(disp, disp->ColStart - 40);
  496.         break;
  497.         default:
  498.         *prow = -1;
  499.         *pcol = im->Code;
  500.         ret = 1;
  501.         }
  502.         break;
  503.     case RAWKEY:
  504.         switch (im->Code) {
  505.         case 0x4c:
  506.         if (im->Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)) {
  507.             if (disp->TPos != 0) {
  508.             disp->TPos = BackupFile(disp, disp->TPos, disp->WMaxLines);
  509.             disp->TLineNo -= disp->WMaxLines;
  510.             if (disp->TLineNo < 0)
  511.                 disp->TLineNo = 0;
  512.             SetRefresh(disp, 0);
  513.             }
  514.         } else {
  515.             if (disp->TPos != 0) {
  516.             disp->TPos = BackupFile(disp, disp->TPos, 1);
  517.             disp->TLineNo--;
  518.             if (disp->TLineNo < 0)
  519.                 disp->TLineNo = 0;
  520.             SetRefresh(disp, 0);
  521.             }
  522.         }
  523.         break;
  524.         case 0x4d:
  525.         if (im->Qualifier&(IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)) {
  526.             if (disp->BPos != disp->XPos) {
  527.             int move;
  528.  
  529.             move=disp->WMaxLines;
  530.             while ((disp->TLineNo+move) >= (disp->FLines-disp->WMaxLines))
  531.                 move--;
  532.  
  533.             if (move < 0)
  534.                 move = 0;
  535.  
  536.             disp->TPos = ForwardFile(disp, disp->TPos, move);
  537.             disp->TLineNo += move;
  538.             SetRefresh(disp, 0);
  539.             }
  540.         } else {
  541.             if (disp->BPos != disp->XPos && (disp->TLineNo+disp->WMaxLines < disp->FLines)) {
  542.             disp->TPos = ForwardFile(disp, disp->TPos, 1);
  543.             ++disp->TLineNo;
  544.             SetRefresh(disp, 0);
  545.             }
  546.         }
  547.         break;
  548.         case 0x5f:
  549.         *prow=-1;
  550.         *pcol='h';
  551.         ret=1;
  552.         break;
  553.         default:
  554.         break;
  555.         }
  556.         break;
  557.  
  558.     case MOUSEBUTTONS:
  559.         if (im->MouseX < win->Width - win->BorderLeft && im->MouseY > win->BorderTop) {
  560.         if (im->Code == SELECTDOWN) {
  561.             *pcol = (im->MouseX - win->BorderLeft) / win->RPort->TxWidth;
  562.             *prow = ((im->MouseY - win->BorderTop) / win->RPort->TxHeight) + disp->TLineNo;
  563.             if (*prow >= 0)
  564.             ret = 1;
  565.         }
  566.         }
  567.         break;
  568.     case NEWSIZE:
  569.         SetRefresh(disp, 0);
  570.         break;
  571.     case REFRESHWINDOW:
  572.         BeginRefresh(win);
  573.         EndRefresh(win, 1);
  574.         RefreshBrowseDisplay(disp, 1);
  575.         break;
  576.     default:
  577.         break;
  578.     }
  579.     ReplyMsg(im);
  580.     }
  581.     return(ret);
  582. }
  583.  
  584. void
  585. RefreshBrowseDisplay(vdisp, all)
  586. void *vdisp;
  587. short all;
  588. {
  589.     Display *disp = (Display *)vdisp;
  590.     long x, y;
  591.     int maxx;
  592.     int dispLines = 0;
  593.     int lineNo;
  594.     short skipLineBeg = 0;
  595.     short skipLineEnd = 0;
  596.     Window *win = disp->Win;
  597.     short b;
  598.     short isHdr;
  599.     short rvsMode;
  600.  
  601.     {
  602.     long diff = disp->LastTLine-disp->TLineNo;
  603.  
  604.     if (all == 0 && diff > 0 && diff < disp->WLines/2) {
  605.         skipLineBeg = diff;
  606.         skipLineEnd = disp->WLines;
  607.  
  608.         ScrollRaster(
  609.         disp->Win->RPort,
  610.         0,
  611.         -(disp->Win->RPort->TxHeight * diff),
  612.         disp->Win->BorderLeft, disp->Win->BorderTop,
  613.         disp->Win->Width - (disp->Win->BorderRight + 1),
  614.         disp->Win->Height - (disp->Win->BorderBottom + 1)
  615.         );
  616.     } else if (all == 0 && diff < 0 && diff > -disp->WLines/2) {
  617.         skipLineBeg = 0;
  618.         skipLineEnd = disp->WLines + diff;
  619.  
  620.         ScrollRaster(
  621.         disp->Win->RPort,
  622.         0,
  623.         -(diff * disp->Win->RPort->TxHeight),
  624.         disp->Win->BorderLeft, disp->Win->BorderTop,
  625.         disp->Win->Width - (disp->Win->BorderRight + 1),
  626.         disp->Win->Height - (disp->Win->BorderBottom + 1)
  627.         );
  628.     } else {
  629.         SetAPen(win->RPort, 0);
  630.         RectFill(win->RPort, win->BorderLeft, win->BorderTop, win->Width - (win->BorderRight+1), win->Height - (win->BorderBottom+1));
  631.         SetAPen(win->RPort, 1);
  632.         all = 1;
  633.     }
  634.     }
  635.     disp->LastTLine=disp->TLineNo;
  636.     disp->FlagRefresh = 0;
  637.  
  638.     if (disp->Fi == NULL) {
  639.     disp->Fi = fopen(disp->Name, "r");
  640.     if (disp->Fi == NULL)       /*  can't refresh if can't open file */
  641.         return;
  642.     for (disp->FLines = 0; fgets(TmpBuf, sizeof(TmpBuf), disp->Fi); ++disp->FLines)
  643.         ;
  644.     fseek(disp->Fi, 0L, 2);
  645.     disp->XPos = ftell(disp->Fi);
  646.     }
  647.     if (ftell(disp->Fi) != disp->TPos)
  648.     fseek(disp->Fi, disp->TPos, 0);
  649.     lineNo = disp->TLineNo - 1;
  650.     x = win->BorderLeft;
  651.     y = win->BorderTop + win->RPort->TxBaseline;
  652.     maxx = (win->Width - win->BorderLeft - win->BorderRight) / win->RPort->TxWidth;
  653.  
  654.     b = 0;
  655.     TmpBuf[0] = 0;
  656.  
  657.     disp->WMaxLines = (win->Height - win->BorderBottom - win->BorderTop - 2) / win->RPort->TxHeight;
  658.  
  659.     while (y < win->Height - win->BorderBottom - 2) {
  660.     int len;
  661.  
  662.     if (TmpBuf[b] == 0) {
  663.         if (fgets(TmpBuf, sizeof(TmpBuf), disp->Fi) == NULL)
  664.         break;
  665.         rvsMode = 0;
  666.         if (++lineNo < disp->FirstNonHdrLine) {
  667.         isHdr = 1;
  668.         if (strncmp(TmpBuf, "Subject:", 8) == 0)
  669.             rvsMode = 1;
  670.         } else {
  671.         isHdr = 0;
  672.         }
  673.         TabExpand(TmpBuf, sizeof(TmpBuf));
  674.         b = 0;
  675.     }
  676.     len = strlen(TmpBuf + b) - disp->ColStart;
  677.     if (len > maxx)
  678.         len = maxx;
  679.     if (len > 0) {
  680.         if (rvsMode) {
  681.         SetAPen(win->RPort, 0);
  682.         SetBPen(win->RPort, 1);
  683.         }
  684.         if (skipLineBeg > 0 || skipLineEnd <= 0) {
  685.         Move(win->RPort, x, y);
  686.         Text(win->RPort, TmpBuf + b + disp->ColStart, len);
  687.         }
  688.  
  689.         if (rvsMode) {
  690.         SetAPen(win->RPort, 1);
  691.         SetBPen(win->RPort, 0);
  692.         }
  693.     }
  694.     --skipLineBeg;
  695.     --skipLineEnd;
  696.     ++dispLines;
  697.     y += win->RPort->TxHeight;
  698.     if (isHdr || disp->ColStart || len <= 0)
  699.         b = strlen(TmpBuf);
  700.     else
  701.         b += len;
  702.     }
  703.     disp->BPos = ftell(disp->Fi);
  704.     disp->WLines = dispLines;
  705.     FixPropGadget(disp, all);
  706. }
  707.  
  708. void
  709. LoadDisplayConfig()
  710. {
  711.     FILE *fi;
  712.  
  713.     if (fi = fopen("s:dnews.config", "r")) {
  714.     fread(ConfAry, 1, sizeof(ConfAry), fi);
  715.     fclose(fi);
  716.     }
  717. }
  718.  
  719. void
  720. SaveDisplayConfig()
  721. {
  722.     FILE *fi;
  723.  
  724.     if (fi = fopen("s:dnews.config", "w")) {
  725.     fwrite(ConfAry, 1, sizeof(ConfAry), fi);
  726.     fclose(fi);
  727.     }
  728. }
  729.  
  730. static void
  731. SaveWindowConfig(disp)
  732. Display *disp;
  733. {
  734.     Config *conf = ConfAry + disp->Id;
  735.     Window *win = disp->Win;
  736.  
  737.     conf->TopEdge   = win->TopEdge;
  738.     conf->LeftEdge  = win->LeftEdge;
  739.     conf->Width     = win->Width;
  740.     conf->Height    = win->Height;
  741. }
  742.  
  743. /*
  744.  *  Count lines forwards
  745.  */
  746.  
  747. static long
  748. ForwardFile(disp, pos, lines)
  749. Display *disp;
  750. long pos;
  751. long lines;
  752. {
  753.     long n;
  754.     long i;
  755.  
  756.     if (disp->Fi == NULL) {
  757.     disp->Fi = fopen(disp->Name, "r");
  758.     if (disp->Fi == NULL)
  759.         return(0);
  760.     }
  761.     fseek(disp->Fi, pos, 0);
  762.     while (lines) {
  763.     if (fgets(TmpBuf, sizeof(TmpBuf), disp->Fi) == NULL)
  764.         break;
  765.     --lines;
  766.     }
  767.     return(ftell(disp->Fi));
  768. }
  769.  
  770.  
  771. /*
  772.  *  Find a given line
  773.  */
  774.  
  775. long
  776. GotoLine(disp, lines)
  777. Display *disp;
  778. long lines;
  779. {
  780.     if (disp->Fi == NULL) {
  781.     disp->Fi = fopen(disp->Name, "r");
  782.     if (disp->Fi == NULL)
  783.         return(0);
  784.     }
  785.     fseek(disp->Fi, 0, 0);
  786.     while (lines) {
  787.     if (fgets(TmpBuf, sizeof(TmpBuf), disp->Fi) == NULL)
  788.         break;
  789.     --lines;
  790.     }
  791.     return(ftell(disp->Fi));
  792. }
  793.  
  794. /*
  795.  *  Count lines backwards
  796.  */
  797.  
  798. static long
  799. BackupFile(disp, pos, rlines)
  800. Display *disp;
  801. long pos;
  802. long rlines;
  803. {
  804.     long n;
  805.     long i;
  806.  
  807.     if (disp->Fi == NULL) {
  808.     disp->Fi = fopen(disp->Name, "r");
  809.     if (disp->Fi == NULL)
  810.         return(0);
  811.     }
  812.     ++rlines;    /*  think of the case where rlines is 1 in the below code   */
  813.  
  814.     while (rlines && pos) {
  815.     n = sizeof(TmpBuf);
  816.     if (pos < n)
  817.         n = pos;
  818.     fseek(disp->Fi, pos - n, 0);
  819.     fread(TmpBuf, 1, n, disp->Fi);
  820.     for (i = n - 1; i >= 0; --i) {
  821.         if (TmpBuf[i] == '\n') {
  822.         if (--rlines == 0)
  823.             break;
  824.         }
  825.     }
  826.     ++i;
  827.     pos = pos - n + i;
  828.     }
  829.     return(pos);
  830. }
  831.  
  832. /*
  833.  *  Flag that the display should be refreshed without doing so immediately.
  834.  *  This allows the user to skip around articles without having to wait
  835.  *  for the display to catch up.
  836.  */
  837.  
  838. static void
  839. SetRefresh(disp, lrc)
  840. Display *disp;
  841. int lrc;
  842. {
  843.     FlagRefresh = 1;
  844.  
  845.     if (lrc < 0)
  846.     lrc = 0;
  847.  
  848.     if (lrc > TMPBSIZE - 1)
  849.     lrc = TMPBSIZE - 1;
  850.  
  851.     disp->FlagRefresh = 1;
  852.     disp->ColStart = lrc;
  853. }
  854.  
  855.  
  856. /*
  857.  *                YES OR NO
  858.  */
  859.  
  860. typedef struct IntuiText    ITEXT;
  861. typedef unsigned char    ubyte;
  862.  
  863. int
  864. getyn(text)
  865. char *text;
  866. {
  867.     int result;
  868.     ITEXT *body, *pos, *neg;
  869.  
  870.     if (DispBase == NULL)
  871.     return(0);
  872.  
  873.     body = (ITEXT *)AllocMem(sizeof(ITEXT), 0);
  874.     pos  = (ITEXT *)AllocMem(sizeof(ITEXT), 0);
  875.     neg  = (ITEXT *)AllocMem(sizeof(ITEXT), 0);
  876.     setmem(body, sizeof(ITEXT), 0);
  877.     setmem(pos , sizeof(ITEXT), 0);
  878.     setmem(neg , sizeof(ITEXT), 0);
  879.     body->BackPen = pos->BackPen = neg->BackPen = 1;
  880.     body->DrawMode= pos->DrawMode= neg->DrawMode= AUTODRAWMODE;
  881.     body->LeftEdge = 10;
  882.     body->TopEdge  = 12;
  883.     body->IText    = (ubyte *)text;
  884.     pos->LeftEdge = AUTOLEFTEDGE;
  885.     pos->TopEdge = AUTOTOPEDGE;
  886.     pos->IText = (ubyte *)"OK";
  887.     neg->LeftEdge = AUTOLEFTEDGE;
  888.     neg->TopEdge = AUTOTOPEDGE;
  889.     neg->IText = (ubyte *)"CANCEL";
  890.     result = AutoRequest(DispBase->Win, body, pos, neg, 0, 0, 320, 58);
  891.     FreeMem(body, sizeof(ITEXT));
  892.     FreeMem(pos , sizeof(ITEXT));
  893.     FreeMem(neg , sizeof(ITEXT));
  894.     return(result);
  895. }
  896.  
  897. void
  898. TabExpand(buf, max)
  899. char *buf;
  900. short max;
  901. {
  902.     short i;
  903.     short len = strlen(buf);
  904.     char *ptr;
  905.  
  906.     max -= 9;
  907.     for (i = 0, ptr = buf; *ptr; ++ptr, ++i) {
  908.     if (*ptr == '\n') {
  909.         *ptr = 0;
  910.         break;
  911.     }
  912.     if (*ptr == 9 && len < max) {
  913.         int n = ~i & 7;
  914.         movmem(ptr, ptr + n, len - i + 1);
  915.         setmem(ptr, n + 1, ' ');
  916.         len += n;
  917.     }
  918.     }
  919. }
  920.  
  921.