home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / fish / disks / d1050.lha / Programs / Man_dt / source / dispatch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-28  |  18.8 KB  |  587 lines

  1. /*
  2. ** $PROJECT: man.datatype
  3. **
  4. ** $VER: dispatch.c 39.4 (28.12.94)
  5. **
  6. ** by
  7. **
  8. ** Stefan Ruppert , Windthorststraße 5 , 65439 Flörsheim , GERMANY
  9. **
  10. ** (C) Copyright 1994
  11. ** All Rights Reserved !
  12. **
  13. ** $HISTORY:
  14. **
  15. ** 28.12.94 : 039.004 : word wrap disabled due to a bug I can't find
  16. ** 23.11.94 : 039.003 : now handles more than one backspace for each character
  17. ** 16.11.94 : 039.002 : added wordwrap support
  18. ** 15.11.94 : 039.001 : initial
  19. */
  20.  
  21. /* ------------------------------- include -------------------------------- */
  22.  
  23. #include "classbase.h"
  24.  
  25. /* ------------------------------- autodoc -------------------------------- */
  26.  
  27. /*FS*/ /*"AutoDoc"*/
  28. /*GB*** man.datatype/man.datatype ********************************************
  29. *
  30. *    NAME
  31. *        man.datatype -- data type for unix manual page files
  32. *
  33. *    FUNCTION
  34. *        The man data type, a sub-class of the text.datatype, is used to
  35. *        load a unix manual page file and to displays it
  36. *
  37. *    METHODS
  38. *        OM_NEW -- Create a new text object from a manual page file.
  39. *
  40. *        GM_LAYOUT -- Method to layout the text
  41. *
  42. *    SEE ALSO
  43. *        text.datatype
  44. *
  45. ******************************************************************************
  46. *
  47. */
  48. /*FE*/
  49.  
  50. /* ------------------------------- defines -------------------------------- */
  51.  
  52. #define PUDDLE_SIZE        2048
  53. #define G(o)               ((struct Gadget *) (o))
  54.  
  55. #define BUFFER_SIZE        1024
  56. #define BACKSPACE          '\010'
  57. #define EOS                '\0'
  58.  
  59. /* ---------------------------- instance data ----------------------------- */
  60.  
  61. struct ManData
  62. {
  63.    APTR md_Pool;
  64. };
  65.  
  66. /* ------------------------------ init class ------------------------------ */
  67.  
  68. /*FS*/ LibCall Class *initClass(REGA6 struct ClassBase *cb)
  69. {
  70.    Class *cl;
  71.  
  72.    D(bug("init man.datatype !\n"));
  73.  
  74.    if((cl = MakeClass(DATATYPENAME,TEXTDTCLASS,NULL,sizeof(struct ManData ),0)))
  75.    {
  76.       cl->cl_Dispatcher.h_Entry = (HOOKFUNC) dispatch;
  77.       cl->cl_UserData = (ULONG) cb;
  78.  
  79.       AddClass(cl);
  80.    }
  81.  
  82.    return(cl);
  83. }
  84. /*FE*/
  85.  
  86. /* ---------------------------- notify object ----------------------------- */
  87.  
  88. /*FS*/ ULONG notifyAttrChanges(Object * o, void * ginfo, ULONG flags, ULONG tag1,...)
  89. {
  90.     return(DoMethod(o, OM_NOTIFY, &tag1, ginfo, flags));
  91. }
  92. /*FE*/
  93.  
  94. /* --------------------------- class dispatcher --------------------------- */
  95.  
  96. /*FS*/ ClassCall ULONG dispatch(REGA0 Class *cl,REGA2 Object *obj,REGA1 Msg msg)
  97. {
  98.    struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
  99.    struct ManData *md;
  100.    ULONG retval;
  101.  
  102.    switch(msg->MethodID)
  103.    {
  104.    case OM_NEW:
  105.       if((retval = DoSuperMethodA(cl,obj,msg)))
  106.       {
  107.          STRPTR buffer = NULL;
  108.          ULONG bufferlen = 0;
  109.  
  110.          if(GetDTAttrs((Object *) retval,TDTA_Buffer    ,&buffer,
  111.                                          TDTA_BufferLen ,&bufferlen,
  112.                                          TAG_DONE) != 2 || !buffer || !bufferlen)
  113.          {
  114.             D(bug("can't get buffer ! %lx , %ld \n",buffer,bufferlen));
  115.  
  116.             SetIoErr(ERROR_REQUIRED_ARG_MISSING);
  117.             D(bug("man.datatype error : %ld\n",IoErr()));
  118.             CoerceMethod(cl,(Object *) retval,OM_DISPOSE);
  119.             retval = NULL;
  120.          }
  121.       }
  122.       break;
  123.    case OM_DISPOSE:
  124.       {
  125.          struct List *linelist;
  126.  
  127.          md = INST_DATA(cl,obj);
  128.  
  129.          if(GetDTAttrs(obj,TDTA_LineList,&linelist,TAG_DONE) && linelist)
  130.             NewList(linelist);
  131.  
  132.          if(md->md_Pool)
  133.             DeletePool(md->md_Pool);
  134.  
  135.          retval = DoSuperMethodA(cl,obj,msg);
  136.       }
  137.       break;
  138.    case OM_UPDATE:
  139.    case OM_SET:
  140.       /* no own attributes */
  141.       #if 0
  142.          md = INST_DATA(cl,obj);
  143.  
  144.          if((retval = setattrs(cl,obj,(struct opSet *) msg)))
  145.             DoMethod(obj,GM_LAYOUT,((struct opSet *) msg)->ops_GInfo,0);
  146.          else
  147.             retval = 0;
  148.       #endif
  149.  
  150.       /* Pass the attributes to the text class and force a refresh
  151.        * if we need it */
  152.       if((retval = DoSuperMethodA (cl, obj, msg)) && (OCLASS (obj) == cl))
  153.       {
  154.          struct RastPort *rp;
  155.  
  156.          /* Get a pointer to the rastport */
  157.          if(rp = ObtainGIRPort (((struct opSet *) msg)->ops_GInfo))
  158.          {
  159.             struct gpRender gpr;
  160.  
  161.             /* Force a redraw */
  162.             gpr.MethodID   = GM_RENDER;
  163.             gpr.gpr_GInfo  = ((struct opSet *) msg)->ops_GInfo;
  164.             gpr.gpr_RPort  = rp;
  165.             gpr.gpr_Redraw = GREDRAW_UPDATE;
  166.             DoMethodA (obj, (Msg) &gpr);
  167.  
  168.             /* Release the temporary rastport */
  169.             ReleaseGIRPort (rp);
  170.          }
  171.  
  172.          retval = 0;
  173.       }
  174.       break;
  175.    case OM_GET:
  176.       retval = DoSuperMethodA(cl,obj,msg);
  177.       break;
  178.    case GM_LAYOUT:
  179.        /* Tell everyone that we are busy doing things */
  180.        notifyAttrChanges (obj, ((struct gpLayout *) msg)->gpl_GInfo, NULL,
  181.                           GA_ID,       G(obj)->GadgetID,
  182.                           DTA_Busy,    TRUE,
  183.                           TAG_DONE);
  184.       /* Let the super-class partake */
  185.       retval = DoSuperMethodA (cl, obj, msg);
  186.  
  187.       /* We need to do this one asynchronously */
  188.       retval += DoAsyncLayout (obj, (struct gpLayout *) msg);
  189.       break;
  190.    case DTM_PROCLAYOUT:
  191.       /* Tell everyone that we are busy doing things */
  192.       notifyAttrChanges (obj, ((struct gpLayout *) msg)->gpl_GInfo, NULL,
  193.                          GA_ID,       G(obj)->GadgetID,
  194.                          DTA_Busy,    TRUE,
  195.                          TAG_DONE);
  196.  
  197.       /* Let the super-class partake and then fall through to our layout method */
  198.       DoSuperMethodA (cl, obj, msg);
  199.    case DTM_ASYNCLAYOUT:
  200.       /* Layout the text */
  201.       retval = layout(cb, cl, obj, (struct gpLayout *) msg);
  202.       break;
  203.    default:
  204.       retval = DoSuperMethodA(cl,obj,msg);
  205.    }
  206.  
  207.    return(retval);
  208. }
  209. /*FE*/
  210.  
  211. /*FS*/ /*"Get-/SetAttr support (not used yet)"*/
  212. #if 0
  213. ULONG getattrs(Class *cl,Object *obj,struct opGet *msg)
  214. {
  215.    if(msg->opg_AttrID == TAG_ANY)
  216.    {
  217.       struct ManData *md = INST_DATA(cl,obj);
  218.  
  219.       *msg->opg_Storage = (ULONG) md->md_Attr;
  220.  
  221.       return(1);
  222.    }
  223.    return(0);
  224. }
  225.  
  226. ULONG setattrs(Class *cl,Object *obj,struct opSet *msg)
  227. {
  228.    struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
  229.    struct TagItem *tag;
  230.  
  231.    if((tag = FindTagItem(TAG_ANY,msg->ops_AttrList)))
  232.    {
  233.       struct ManData *md = INST_DATA(cl,obj);
  234.  
  235.       md->md_Attr = tag->ti_Data;
  236.       return(1);
  237.    }
  238.    return(0);
  239. }
  240. #endif
  241. /*FE*/
  242.  
  243. /*FS*/ GetA4 ULONG layout(struct ClassBase *cb, Class * cl, Object * obj, struct gpLayout * gpl)
  244. {
  245.    struct DTSpecialInfo *si = (struct DTSpecialInfo *) G(obj)->SpecialInfo;
  246.    struct ManData *md = INST_DATA(cl,obj);
  247.    struct DrawInfo *dri = (gpl->gpl_GInfo) ? gpl->gpl_GInfo->gi_DrInfo : NULL;
  248.  
  249.    struct RastPort trp;
  250.  
  251.    ULONG visible;
  252.    ULONG hunit;
  253.  
  254.    ULONG total = 0;
  255.    ULONG bsig = 0;
  256.  
  257.    /* Switches */
  258.    BOOL abort = FALSE;
  259.  
  260.    /* Attributes obtained from super-class */
  261.    struct TextAttr *tattr;
  262.    struct TextFont *font;
  263.    struct List *linelist;
  264.    ULONG wrap;
  265.    ULONG bufferlen;
  266.    STRPTR buffer;
  267.  
  268.    struct IBox *domain;
  269.    STRPTR title;
  270.  
  271.    D(bug("layout !\n"));
  272.  
  273.    /* Get all the attributes that we are going to need for a successful layout */
  274.    if(GetDTAttrs(obj,DTA_TextFont,  (ULONG) &font,
  275.                      DTA_TextAttr,  (ULONG) &tattr,
  276.                      DTA_Domain,    (ULONG) &domain,
  277.                      DTA_ObjName,   (ULONG) &title,
  278.                      TDTA_LineList, (ULONG) &linelist,
  279.                      TDTA_Buffer,   (ULONG) &buffer,
  280.                      TDTA_BufferLen,(ULONG) &bufferlen,
  281.                      TDTA_WordWrap, (ULONG) &wrap,
  282.                      TAG_DONE) == 8)
  283.    {
  284.       struct Line *line;
  285.       ULONG maxwidth = 0;
  286.       ULONG yoffset = 0;
  287.       UBYTE fgpen = (dri) ? dri->dri_Pens[TEXTPEN]       : 1;
  288.       UBYTE bgpen = (dri) ? dri->dri_Pens[BACKGROUNDPEN] : 0;
  289.  
  290.       /* Lock the global object data so that nobody else can manipulate it */
  291.       ObtainSemaphore (&(si->si_Lock));
  292.  
  293.       /* Make sure we have a buffer */
  294.       if(buffer)
  295.       {
  296.          /* Initialize the temporary RastPort */
  297.          InitRastPort (&trp);
  298.          SetFont (&trp, font);
  299.  
  300.          /* We only need to perform layout if this is the initial layout call
  301.           * or word wrap (not supported yet) */
  302.          if (gpl->gpl_Initial)
  303.          {
  304.             STRPTR namebuf;
  305.  
  306.             if(md->md_Pool)
  307.             {
  308.                NewList(linelist);
  309.                DeletePool(md->md_Pool);
  310.                md->md_Pool = NULL;
  311.             }
  312.  
  313.             if((md->md_Pool = CreatePool(MEMF_CLEAR | MEMF_ANY , PUDDLE_SIZE,PUDDLE_SIZE)))
  314.             {
  315.                if((namebuf = AllocPooled(md->md_Pool,BUFFER_SIZE)))
  316.                {
  317.                   STRPTR anchorptr = buffer;
  318.                   STRPTR ptr = buffer;
  319.                   STRPTR end = &buffer[bufferlen];
  320.                   STRPTR newptr;
  321.                   BOOL newseg   = FALSE;
  322.                   BOOL linefeed = FALSE;
  323.                   BOOL wrapped  = FALSE;
  324.                   BOOL countspaces = TRUE;
  325.  
  326.  
  327.                   ULONG swidth;
  328.                   ULONG style    = FS_NORMAL;
  329.                   ULONG tabspace = 8;
  330.                   ULONG offset   = 0;
  331.                   ULONG num      = 0;
  332.                   ULONG numtabs  = 0;
  333.                   ULONG mansize  = 0;
  334.                   ULONG spaces   = 0;
  335.  
  336.                   *namebuf = EOS;
  337.  
  338.                   for(; (ptr < end) && (bsig == 0) && !abort; ptr++)
  339.                   {
  340.                      if(ptr[1] == BACKSPACE)
  341.                      {
  342.                         if(num > 0)
  343.                         {
  344.                            newseg = TRUE;
  345.                            newptr = ptr;
  346.                            ptr--;         /* remember this position */
  347.                         } else
  348.                         {
  349.                            STRPTR nptr = namebuf;
  350.  
  351.                            if(*ptr == '_')
  352.                               style = FSF_UNDERLINED;
  353.                            else if(*ptr == ptr[2])
  354.                               style = FSF_BOLD;
  355.  
  356.                            while((ptr[1] == BACKSPACE) && ((nptr-namebuf) < BUFFER_SIZE))
  357.                            {
  358.                               *nptr++ = ptr[2];
  359.                               ptr++;
  360.  
  361.                               while(*ptr == BACKSPACE)
  362.                                  ptr += 2;
  363.                            }
  364.                            *nptr = EOS;
  365.  
  366.                            D(bug("man word : \"%s\", style : %ld\n",namebuf,style));
  367.                            if(*ptr == '\n' || *ptr == '\f')
  368.                            {
  369.                               spaces   = 0;
  370.                               linefeed = TRUE;
  371.                            } else
  372.                               ptr--;
  373.  
  374.                            mansize = strlen(namebuf);
  375.                            newptr = ptr + 1;
  376.                            newseg = TRUE;
  377.                         }
  378.                      } else
  379.                      {
  380.                         if(countspaces)
  381.                         {
  382.                            if(*ptr == ' ')
  383.                               spaces++;
  384.                            else
  385.                               countspaces = FALSE;
  386.                         }
  387.  
  388.                         switch(*ptr)
  389.                         {
  390.                         case '\n':
  391.                            /* newline */
  392.                            spaces = 0;
  393.                            newseg = linefeed = TRUE;
  394.                            newptr = ptr + 1;
  395.                            break;
  396.                         case '\f':
  397.                            /* end of page */
  398.                            newseg = linefeed = TRUE;
  399.                            newptr = ptr + 1;
  400.                            break;
  401.                         case '\t':
  402.                            /* tabulator */
  403.                            /* See if we need to terminate a line segment */
  404.                            if ((numtabs == 0) && num)
  405.                                newseg = TRUE;
  406.                            numtabs++;
  407.                            break;
  408.                         default:
  409.                            /* See if we have any TABs that we need to finish out */
  410.                            if(numtabs)
  411.                            {
  412.                               offset += (((offset / tabspace) + 1) * tabspace) - offset;
  413.                               num = numtabs = 0;
  414.                               anchorptr = ptr;
  415.                            }
  416.  
  417.                            #if 0
  418.                            if(wrap)
  419.                            {
  420.                               /* Compute the width of the line. */
  421.                               swidth = TextLength (&trp, anchorptr, num+1);
  422.                               if (offset + swidth > domain->Width)
  423.                               {
  424.                                  STRPTR nptr;
  425.  
  426.                                  /* Search for a whitespace character */
  427.                                  for (nptr = ptr; (nptr > anchorptr) && !newseg; nptr--)
  428.                                  {
  429.                                     if (*nptr == ' ')
  430.                                     {
  431.                                        num -= (ptr - nptr);
  432.                                        newseg = TRUE;
  433.                                        ptr = nptr + 1;
  434.                                     }
  435.                                  }
  436.  
  437.                                  if(!newseg)
  438.                                  {
  439.                                     num -= (ptr - nptr);
  440.                                     ptr = nptr + 1;
  441.                                  }
  442.  
  443.                                  newseg = linefeed = TRUE;
  444.                                  newptr = ptr;
  445.                                  ptr--;
  446.                                  wrapped = TRUE;
  447.                               }
  448.                               else
  449.                               {
  450.                                   num++;
  451.                               }
  452.                            } else
  453.                            #endif
  454.                                num++;
  455.                         }
  456.                      }
  457.  
  458.                      /* Time for a new text segment yet? */
  459.                      if(newseg)
  460.                      {
  461.                         /* the following don't work , because the text.datatype don't use
  462.                          * the YOffset field of each line segment. It adds font YSize each
  463.                          * line !
  464.                          * Oh no is there anybody out there , who can tell me why ???
  465.                          */
  466.                         #if 0
  467.                         if(num == 0 && mansize == 0 && linefeed)
  468.                         {
  469.                            yoffset += font->tf_YSize;
  470.                         } else
  471.                         #endif
  472.  
  473.                         /* Allocate a new line segment from our memory pool */
  474.                         if (line = AllocPooled(md->md_Pool,sizeof(struct Line) + mansize))
  475.                         {
  476.                            line->ln_Flags   = (linefeed) ? LNF_LF : NULL;
  477.                            line->ln_FgPen   = fgpen;
  478.                            line->ln_BgPen   = bgpen;
  479.                            line->ln_Style   = style;
  480.                            line->ln_Data    = NULL;
  481.                            /* this is a man segment */
  482.                            if(mansize)
  483.                            {
  484.                               line->ln_Text    = (STRPTR) (line + 1);
  485.                               line->ln_TextLen = mansize;
  486.                               strcpy(line->ln_Text,namebuf);
  487.                               style = FS_NORMAL;
  488.                               mansize  = 0;
  489.                            } else
  490.                            {
  491.                               line->ln_Text    = anchorptr;
  492.                               line->ln_TextLen = num;
  493.                            }
  494.  
  495.                            swidth = TextLength (&trp, line->ln_Text, line->ln_TextLen);
  496.                            line->ln_XOffset = offset;
  497.                            line->ln_YOffset = yoffset + font->tf_Baseline;
  498.                            line->ln_Width   = swidth;
  499.                            line->ln_Height  = font->tf_YSize;
  500.  
  501.                            maxwidth = MAX(maxwidth,offset + swidth);
  502.  
  503.                            /* Increment the line count */
  504.                            if (linefeed)
  505.                            {
  506.                                yoffset += font->tf_YSize;
  507.                                offset  = spaces * font->tf_XSize;
  508.                                total++;
  509.                            }
  510.                            else
  511.                                offset += swidth;
  512.  
  513.                            AddTail(linelist, (struct Node *) line);
  514.  
  515.                            if(linefeed && !wrapped)
  516.                            {
  517.                               countspaces = TRUE;
  518.                               spaces      = 0;
  519.                            } else
  520.                               countspaces = FALSE;
  521.                         }
  522.                         else
  523.                            abort = TRUE;
  524.  
  525.                         wrapped  =
  526.                         newseg   =
  527.                         linefeed = FALSE;
  528.  
  529.                         anchorptr = newptr;
  530.                         num = 0;
  531.                      }
  532.  
  533.                      bsig = CheckSignal(SIGBREAKF_CTRL_C);
  534.                   }
  535.                   FreePooled(md->md_Pool,namebuf,BUFFER_SIZE);
  536.                }
  537.             }
  538.          }
  539.          else
  540.          {
  541.             /* No layout to perform */
  542.             total    = si->si_TotVert;
  543.             maxwidth = si->si_TotHoriz;
  544.          }
  545.       }
  546.  
  547.       /* Compute the lines and columns type information */
  548.       si->si_VertUnit  = font->tf_YSize;
  549.       si->si_VisVert   = visible = domain->Height / si->si_VertUnit;
  550.       si->si_TotVert   = total;
  551.  
  552.       si->si_HorizUnit = hunit = 1;
  553.       si->si_VisHoriz  = (LONG) domain->Width / hunit;
  554.       si->si_TotHoriz  = maxwidth;
  555.  
  556.       /* Release the global data lock */
  557.       ReleaseSemaphore(&si->si_Lock);
  558.  
  559.       /* Were we aborted? */
  560.       if (bsig == 0)
  561.       {
  562.          /* Not aborted, so tell the world of our newest attributes */
  563.          notifyAttrChanges (obj, gpl->gpl_GInfo, NULL,
  564.                             GA_ID,                   G(obj)->GadgetID,
  565.  
  566.                             DTA_VisibleVert,         visible,
  567.                             DTA_TotalVert,           total,
  568.                             DTA_NominalVert,         font->tf_YSize * 25,
  569.                             DTA_VertUnit,            font->tf_YSize,
  570.  
  571.                             DTA_VisibleHoriz,        (ULONG) (domain->Width / hunit),
  572.                             DTA_TotalHoriz,          maxwidth,
  573.                             DTA_NominalHoriz,        font->tf_XSize * 80,
  574.                             DTA_HorizUnit,           hunit,
  575.  
  576.                             DTA_Title,               title,
  577.                             DTA_Busy,                FALSE,
  578.                             DTA_Sync,                TRUE,
  579.                             TAG_DONE);
  580.       }
  581.    }
  582.  
  583.    return(total);
  584. }
  585. /*FE*/
  586.  
  587.