home *** CD-ROM | disk | FTP | other *** search
- /*
- ** $PROJECT: man.datatype
- **
- ** $VER: dispatch.c 39.4 (28.12.94)
- **
- ** by
- **
- ** Stefan Ruppert , Windthorststraße 5 , 65439 Flörsheim , GERMANY
- **
- ** (C) Copyright 1994
- ** All Rights Reserved !
- **
- ** $HISTORY:
- **
- ** 28.12.94 : 039.004 : word wrap disabled due to a bug I can't find
- ** 23.11.94 : 039.003 : now handles more than one backspace for each character
- ** 16.11.94 : 039.002 : added wordwrap support
- ** 15.11.94 : 039.001 : initial
- */
-
- /* ------------------------------- include -------------------------------- */
-
- #include "classbase.h"
-
- /* ------------------------------- autodoc -------------------------------- */
-
- /*FS*/ /*"AutoDoc"*/
- /*GB*** man.datatype/man.datatype ********************************************
- *
- * NAME
- * man.datatype -- data type for unix manual page files
- *
- * FUNCTION
- * The man data type, a sub-class of the text.datatype, is used to
- * load a unix manual page file and to displays it
- *
- * METHODS
- * OM_NEW -- Create a new text object from a manual page file.
- *
- * GM_LAYOUT -- Method to layout the text
- *
- * SEE ALSO
- * text.datatype
- *
- ******************************************************************************
- *
- */
- /*FE*/
-
- /* ------------------------------- defines -------------------------------- */
-
- #define PUDDLE_SIZE 2048
- #define G(o) ((struct Gadget *) (o))
-
- #define BUFFER_SIZE 1024
- #define BACKSPACE '\010'
- #define EOS '\0'
-
- /* ---------------------------- instance data ----------------------------- */
-
- struct ManData
- {
- APTR md_Pool;
- };
-
- /* ------------------------------ init class ------------------------------ */
-
- /*FS*/ LibCall Class *initClass(REGA6 struct ClassBase *cb)
- {
- Class *cl;
-
- D(bug("init man.datatype !\n"));
-
- if((cl = MakeClass(DATATYPENAME,TEXTDTCLASS,NULL,sizeof(struct ManData ),0)))
- {
- cl->cl_Dispatcher.h_Entry = (HOOKFUNC) dispatch;
- cl->cl_UserData = (ULONG) cb;
-
- AddClass(cl);
- }
-
- return(cl);
- }
- /*FE*/
-
- /* ---------------------------- notify object ----------------------------- */
-
- /*FS*/ ULONG notifyAttrChanges(Object * o, void * ginfo, ULONG flags, ULONG tag1,...)
- {
- return(DoMethod(o, OM_NOTIFY, &tag1, ginfo, flags));
- }
- /*FE*/
-
- /* --------------------------- class dispatcher --------------------------- */
-
- /*FS*/ ClassCall ULONG dispatch(REGA0 Class *cl,REGA2 Object *obj,REGA1 Msg msg)
- {
- struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
- struct ManData *md;
- ULONG retval;
-
- switch(msg->MethodID)
- {
- case OM_NEW:
- if((retval = DoSuperMethodA(cl,obj,msg)))
- {
- STRPTR buffer = NULL;
- ULONG bufferlen = 0;
-
- if(GetDTAttrs((Object *) retval,TDTA_Buffer ,&buffer,
- TDTA_BufferLen ,&bufferlen,
- TAG_DONE) != 2 || !buffer || !bufferlen)
- {
- D(bug("can't get buffer ! %lx , %ld \n",buffer,bufferlen));
-
- SetIoErr(ERROR_REQUIRED_ARG_MISSING);
- D(bug("man.datatype error : %ld\n",IoErr()));
- CoerceMethod(cl,(Object *) retval,OM_DISPOSE);
- retval = NULL;
- }
- }
- break;
- case OM_DISPOSE:
- {
- struct List *linelist;
-
- md = INST_DATA(cl,obj);
-
- if(GetDTAttrs(obj,TDTA_LineList,&linelist,TAG_DONE) && linelist)
- NewList(linelist);
-
- if(md->md_Pool)
- DeletePool(md->md_Pool);
-
- retval = DoSuperMethodA(cl,obj,msg);
- }
- break;
- case OM_UPDATE:
- case OM_SET:
- /* no own attributes */
- #if 0
- md = INST_DATA(cl,obj);
-
- if((retval = setattrs(cl,obj,(struct opSet *) msg)))
- DoMethod(obj,GM_LAYOUT,((struct opSet *) msg)->ops_GInfo,0);
- else
- retval = 0;
- #endif
-
- /* Pass the attributes to the text class and force a refresh
- * if we need it */
- if((retval = DoSuperMethodA (cl, obj, msg)) && (OCLASS (obj) == cl))
- {
- struct RastPort *rp;
-
- /* Get a pointer to the rastport */
- if(rp = ObtainGIRPort (((struct opSet *) msg)->ops_GInfo))
- {
- struct gpRender gpr;
-
- /* Force a redraw */
- gpr.MethodID = GM_RENDER;
- gpr.gpr_GInfo = ((struct opSet *) msg)->ops_GInfo;
- gpr.gpr_RPort = rp;
- gpr.gpr_Redraw = GREDRAW_UPDATE;
- DoMethodA (obj, (Msg) &gpr);
-
- /* Release the temporary rastport */
- ReleaseGIRPort (rp);
- }
-
- retval = 0;
- }
- break;
- case OM_GET:
- retval = DoSuperMethodA(cl,obj,msg);
- break;
- case GM_LAYOUT:
- /* Tell everyone that we are busy doing things */
- notifyAttrChanges (obj, ((struct gpLayout *) msg)->gpl_GInfo, NULL,
- GA_ID, G(obj)->GadgetID,
- DTA_Busy, TRUE,
- TAG_DONE);
- /* Let the super-class partake */
- retval = DoSuperMethodA (cl, obj, msg);
-
- /* We need to do this one asynchronously */
- retval += DoAsyncLayout (obj, (struct gpLayout *) msg);
- break;
- case DTM_PROCLAYOUT:
- /* Tell everyone that we are busy doing things */
- notifyAttrChanges (obj, ((struct gpLayout *) msg)->gpl_GInfo, NULL,
- GA_ID, G(obj)->GadgetID,
- DTA_Busy, TRUE,
- TAG_DONE);
-
- /* Let the super-class partake and then fall through to our layout method */
- DoSuperMethodA (cl, obj, msg);
- case DTM_ASYNCLAYOUT:
- /* Layout the text */
- retval = layout(cb, cl, obj, (struct gpLayout *) msg);
- break;
- default:
- retval = DoSuperMethodA(cl,obj,msg);
- }
-
- return(retval);
- }
- /*FE*/
-
- /*FS*/ /*"Get-/SetAttr support (not used yet)"*/
- #if 0
- ULONG getattrs(Class *cl,Object *obj,struct opGet *msg)
- {
- if(msg->opg_AttrID == TAG_ANY)
- {
- struct ManData *md = INST_DATA(cl,obj);
-
- *msg->opg_Storage = (ULONG) md->md_Attr;
-
- return(1);
- }
- return(0);
- }
-
- ULONG setattrs(Class *cl,Object *obj,struct opSet *msg)
- {
- struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
- struct TagItem *tag;
-
- if((tag = FindTagItem(TAG_ANY,msg->ops_AttrList)))
- {
- struct ManData *md = INST_DATA(cl,obj);
-
- md->md_Attr = tag->ti_Data;
- return(1);
- }
- return(0);
- }
- #endif
- /*FE*/
-
- /*FS*/ GetA4 ULONG layout(struct ClassBase *cb, Class * cl, Object * obj, struct gpLayout * gpl)
- {
- struct DTSpecialInfo *si = (struct DTSpecialInfo *) G(obj)->SpecialInfo;
- struct ManData *md = INST_DATA(cl,obj);
- struct DrawInfo *dri = (gpl->gpl_GInfo) ? gpl->gpl_GInfo->gi_DrInfo : NULL;
-
- struct RastPort trp;
-
- ULONG visible;
- ULONG hunit;
-
- ULONG total = 0;
- ULONG bsig = 0;
-
- /* Switches */
- BOOL abort = FALSE;
-
- /* Attributes obtained from super-class */
- struct TextAttr *tattr;
- struct TextFont *font;
- struct List *linelist;
- ULONG wrap;
- ULONG bufferlen;
- STRPTR buffer;
-
- struct IBox *domain;
- STRPTR title;
-
- D(bug("layout !\n"));
-
- /* Get all the attributes that we are going to need for a successful layout */
- if(GetDTAttrs(obj,DTA_TextFont, (ULONG) &font,
- DTA_TextAttr, (ULONG) &tattr,
- DTA_Domain, (ULONG) &domain,
- DTA_ObjName, (ULONG) &title,
- TDTA_LineList, (ULONG) &linelist,
- TDTA_Buffer, (ULONG) &buffer,
- TDTA_BufferLen,(ULONG) &bufferlen,
- TDTA_WordWrap, (ULONG) &wrap,
- TAG_DONE) == 8)
- {
- struct Line *line;
- ULONG maxwidth = 0;
- ULONG yoffset = 0;
- UBYTE fgpen = (dri) ? dri->dri_Pens[TEXTPEN] : 1;
- UBYTE bgpen = (dri) ? dri->dri_Pens[BACKGROUNDPEN] : 0;
-
- /* Lock the global object data so that nobody else can manipulate it */
- ObtainSemaphore (&(si->si_Lock));
-
- /* Make sure we have a buffer */
- if(buffer)
- {
- /* Initialize the temporary RastPort */
- InitRastPort (&trp);
- SetFont (&trp, font);
-
- /* We only need to perform layout if this is the initial layout call
- * or word wrap (not supported yet) */
- if (gpl->gpl_Initial)
- {
- STRPTR namebuf;
-
- if(md->md_Pool)
- {
- NewList(linelist);
- DeletePool(md->md_Pool);
- md->md_Pool = NULL;
- }
-
- if((md->md_Pool = CreatePool(MEMF_CLEAR | MEMF_ANY , PUDDLE_SIZE,PUDDLE_SIZE)))
- {
- if((namebuf = AllocPooled(md->md_Pool,BUFFER_SIZE)))
- {
- STRPTR anchorptr = buffer;
- STRPTR ptr = buffer;
- STRPTR end = &buffer[bufferlen];
- STRPTR newptr;
- BOOL newseg = FALSE;
- BOOL linefeed = FALSE;
- BOOL wrapped = FALSE;
- BOOL countspaces = TRUE;
-
-
- ULONG swidth;
- ULONG style = FS_NORMAL;
- ULONG tabspace = 8;
- ULONG offset = 0;
- ULONG num = 0;
- ULONG numtabs = 0;
- ULONG mansize = 0;
- ULONG spaces = 0;
-
- *namebuf = EOS;
-
- for(; (ptr < end) && (bsig == 0) && !abort; ptr++)
- {
- if(ptr[1] == BACKSPACE)
- {
- if(num > 0)
- {
- newseg = TRUE;
- newptr = ptr;
- ptr--; /* remember this position */
- } else
- {
- STRPTR nptr = namebuf;
-
- if(*ptr == '_')
- style = FSF_UNDERLINED;
- else if(*ptr == ptr[2])
- style = FSF_BOLD;
-
- while((ptr[1] == BACKSPACE) && ((nptr-namebuf) < BUFFER_SIZE))
- {
- *nptr++ = ptr[2];
- ptr++;
-
- while(*ptr == BACKSPACE)
- ptr += 2;
- }
- *nptr = EOS;
-
- D(bug("man word : \"%s\", style : %ld\n",namebuf,style));
- if(*ptr == '\n' || *ptr == '\f')
- {
- spaces = 0;
- linefeed = TRUE;
- } else
- ptr--;
-
- mansize = strlen(namebuf);
- newptr = ptr + 1;
- newseg = TRUE;
- }
- } else
- {
- if(countspaces)
- {
- if(*ptr == ' ')
- spaces++;
- else
- countspaces = FALSE;
- }
-
- switch(*ptr)
- {
- case '\n':
- /* newline */
- spaces = 0;
- newseg = linefeed = TRUE;
- newptr = ptr + 1;
- break;
- case '\f':
- /* end of page */
- newseg = linefeed = TRUE;
- newptr = ptr + 1;
- break;
- case '\t':
- /* tabulator */
- /* See if we need to terminate a line segment */
- if ((numtabs == 0) && num)
- newseg = TRUE;
- numtabs++;
- break;
- default:
- /* See if we have any TABs that we need to finish out */
- if(numtabs)
- {
- offset += (((offset / tabspace) + 1) * tabspace) - offset;
- num = numtabs = 0;
- anchorptr = ptr;
- }
-
- #if 0
- if(wrap)
- {
- /* Compute the width of the line. */
- swidth = TextLength (&trp, anchorptr, num+1);
- if (offset + swidth > domain->Width)
- {
- STRPTR nptr;
-
- /* Search for a whitespace character */
- for (nptr = ptr; (nptr > anchorptr) && !newseg; nptr--)
- {
- if (*nptr == ' ')
- {
- num -= (ptr - nptr);
- newseg = TRUE;
- ptr = nptr + 1;
- }
- }
-
- if(!newseg)
- {
- num -= (ptr - nptr);
- ptr = nptr + 1;
- }
-
- newseg = linefeed = TRUE;
- newptr = ptr;
- ptr--;
- wrapped = TRUE;
- }
- else
- {
- num++;
- }
- } else
- #endif
- num++;
- }
- }
-
- /* Time for a new text segment yet? */
- if(newseg)
- {
- /* the following don't work , because the text.datatype don't use
- * the YOffset field of each line segment. It adds font YSize each
- * line !
- * Oh no is there anybody out there , who can tell me why ???
- */
- #if 0
- if(num == 0 && mansize == 0 && linefeed)
- {
- yoffset += font->tf_YSize;
- } else
- #endif
-
- /* Allocate a new line segment from our memory pool */
- if (line = AllocPooled(md->md_Pool,sizeof(struct Line) + mansize))
- {
- line->ln_Flags = (linefeed) ? LNF_LF : NULL;
- line->ln_FgPen = fgpen;
- line->ln_BgPen = bgpen;
- line->ln_Style = style;
- line->ln_Data = NULL;
- /* this is a man segment */
- if(mansize)
- {
- line->ln_Text = (STRPTR) (line + 1);
- line->ln_TextLen = mansize;
- strcpy(line->ln_Text,namebuf);
- style = FS_NORMAL;
- mansize = 0;
- } else
- {
- line->ln_Text = anchorptr;
- line->ln_TextLen = num;
- }
-
- swidth = TextLength (&trp, line->ln_Text, line->ln_TextLen);
- line->ln_XOffset = offset;
- line->ln_YOffset = yoffset + font->tf_Baseline;
- line->ln_Width = swidth;
- line->ln_Height = font->tf_YSize;
-
- maxwidth = MAX(maxwidth,offset + swidth);
-
- /* Increment the line count */
- if (linefeed)
- {
- yoffset += font->tf_YSize;
- offset = spaces * font->tf_XSize;
- total++;
- }
- else
- offset += swidth;
-
- AddTail(linelist, (struct Node *) line);
-
- if(linefeed && !wrapped)
- {
- countspaces = TRUE;
- spaces = 0;
- } else
- countspaces = FALSE;
- }
- else
- abort = TRUE;
-
- wrapped =
- newseg =
- linefeed = FALSE;
-
- anchorptr = newptr;
- num = 0;
- }
-
- bsig = CheckSignal(SIGBREAKF_CTRL_C);
- }
- FreePooled(md->md_Pool,namebuf,BUFFER_SIZE);
- }
- }
- }
- else
- {
- /* No layout to perform */
- total = si->si_TotVert;
- maxwidth = si->si_TotHoriz;
- }
- }
-
- /* Compute the lines and columns type information */
- si->si_VertUnit = font->tf_YSize;
- si->si_VisVert = visible = domain->Height / si->si_VertUnit;
- si->si_TotVert = total;
-
- si->si_HorizUnit = hunit = 1;
- si->si_VisHoriz = (LONG) domain->Width / hunit;
- si->si_TotHoriz = maxwidth;
-
- /* Release the global data lock */
- ReleaseSemaphore(&si->si_Lock);
-
- /* Were we aborted? */
- if (bsig == 0)
- {
- /* Not aborted, so tell the world of our newest attributes */
- notifyAttrChanges (obj, gpl->gpl_GInfo, NULL,
- GA_ID, G(obj)->GadgetID,
-
- DTA_VisibleVert, visible,
- DTA_TotalVert, total,
- DTA_NominalVert, font->tf_YSize * 25,
- DTA_VertUnit, font->tf_YSize,
-
- DTA_VisibleHoriz, (ULONG) (domain->Width / hunit),
- DTA_TotalHoriz, maxwidth,
- DTA_NominalHoriz, font->tf_XSize * 80,
- DTA_HorizUnit, hunit,
-
- DTA_Title, title,
- DTA_Busy, FALSE,
- DTA_Sync, TRUE,
- TAG_DONE);
- }
- }
-
- return(total);
- }
- /*FE*/
-
-