/*->c.style */

#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <locale.h>
#include <ctype.h>

#include "h.os"
#include "h.wimp"
#include "h.wimpt"
#include "h.werr"
#include "h.wos"
#include "h.flex"
#include "h.font"
#include "h.transform"

#include "h.etc"
#include "h.err"
#include "h.crc"
#include "h.xext"
#include "h.bits"
#include "h.xmath"
#include "h.fsx"
#include "h.bf"


#include "h.str"
#include "h.constants"

#include "h.reslink"
#include "h.xredraw"
#include "h.object"

#include "h.xcolour"

#include "h.file"
#include "h.utils"
#include "h.view"
#include "h.undo"
#include "h.pref"


#include "h.txstr"
#include "h.tx"
#include "h.text"
#include "h.codes"
#include "h.fox"
#include "h.tabs"
#include "h.dbstyle"
#include "h.ustyle"
#include "h.style"
#include "h.act"
#include "h.fmap"
#include "h.fl"







typedef struct scrcstr
{
 int crc;
 int seq;
} scrcstr;








static int        cmpchainn(const void * s1,const void * s2);



/**************************************************************************/


#ifdef NEVER


static void dumpstyle(stylestr * s)
{
 char * p;
 int    i;

 p=(char*)s;

 printf("dump style\n");
 for(i=0;i<sizeof(stylestr);i++) printf("%02x",*p++);
 printf("\n");

}




static os_error * styledebug(filestr * file)
{
 os_error      * err;
 cstylebasestr * cbase;
 int             cstyles;
 int             i;

 err=NULL;

 cstyles=file->hdr.cstyles;
 cbase=fob_find(cstyles,file);

 for(i=0;i<cbase->n;i++)
 {
  printf("key=%x count=%d offset=%d\n",cbase->stylechain[i].key,
                    cbase->stylechain[i].count,cbase->stylechain[i].offset);
 }

 return(err);
}




void styletest(void)
{
 filestr * file=firstfile;
 int       chain[4];
 int       key;
 int       key1;
 int       keyn[200];
 FILE    * fp;
 int       i;

  chain[0]=101;
  chain[1]=102;
  chain[2]=103;
  chain[3]=104;

 os_cli("sp.xx");

  dprintf(0,"***********************************\n");
  addstylechain(file,chain,4,&key,1);
  printf("added chain key=%x\n",key);
  addstylechain(file,chain,4,&key,1);
  printf("added chain key=%x\n",key);
  key1=key;
  addstylechain(file,chain,3,&key,1);
  printf("added chain key=%x\n",key);
  remstylechain(file,key1,1);
  printf("rem chain\n");
  findstylechain(file,key1,chain,&key);
  printf("find chain %d %d %d %d\n",chain[0],chain[1],chain[2],chain[3]);

  for(i=0;i<100;i++)
  {
   chain[2]=i;
   addstylechain(file,chain,1+i%4,&key,1);
   keyn[i]=key;
   printf("added chain key=%x\n",key);
  }

  styledebug(file);

  for(i=0;i<100;i++)
  {
   printf("rem chain key=%x\n",keyn[i]);
   remstylechain(file,keyn[i],1);
  }


  styledebug(file);

 os_cli("sp.");
}


#endif



/**************************************************************************/


os_error * remapvector(vector * v)
{
 os_error    * err;
 char        * p;
 int           c;
 int           bits;
 int           sn;
 int           offset;
 int           maxlen;
 int           firstoffset;
 int           lastoffset;
 absstylestr * stylep;
 vector        s;
 flowstr       fl;
 filestr     * file;

 file=v->file;

/*
 {
  sectionstr * sectionp;

  sectionp=fob_find(v->section,file);

  dprintf(0,"remapvector unit=%d chapter=%d",v->textsrc.u,sectionp->data.number);

 }
*/


 err=txlock(&v->textsrc,file);
 if(!err)
 {
  offset=0;
  firstoffset=-1;
  lastoffset=0;  /* compiler */
  maxlen=v->textsrc.sourcep->len;
  while(offset<maxlen)
  {
   p=txptr(v->textsrc.sourcep,offset);
   c=*p;
   bits=codex[c];

   if(c==SNO)
   {
    sn=p[1]+(p[2]<<8)+(p[3]<<16);
    findabsstylep(file,sn,&stylep);

    if(stylep->changed)
    {
     if(firstoffset<0) firstoffset=offset;
     lastoffset=maxlen;
    }
    else
    if(!stylep->changed) lastoffset=offset;
   }

   offset+=bits & CODELEN;
  }

  txunlock(&v->textsrc,file);


  if(firstoffset>=0)
  {
/* dprintf(0,"remap vector len=%d first=%d last=%d",maxlen,firstoffset,
                                                           lastoffset); */

   /* we're forcing an immediate flow here with FSUB - don't know why */

   fl.opcode=FDATA|FSUB;
   fl.data.type=FLDIRTY;
   fl.data.offset=firstoffset;
   fl.data.delta=0;
   fl.data.length=lastoffset-firstoffset;

   if(act.valid && act.file==file && act.textsrc.source==v->textsrc.source)
   {
    if(zone)
    {
     fl.opcode|=FLV0|FLV1;
     fl.roff[0]=lozon->textsrc.offset;
     fl.roff[1]=hizon->textsrc.offset;
     fl.resultv[0]=lozon;
     fl.resultv[1]=hizon;
    }
    else
    {
     fl.opcode|=FLV0;
     s=act;
     fl.roff[0]=s.textsrc.offset;
     fl.resultv[0]=&s;
    }
   }

   flow(v,&fl);

   if(act.valid && act.file==file && act.textsrc.source==v->textsrc.source)
   {
    if(zone)
    {


    }
    else
    {
     err=txlock(&s.textsrc,s.file);

     setxa(&s);
     setactive(&s);
     screencaret(&s);

     txunlock(&s.textsrc,s.file);
    }
   }
  }
 }

 return(err);
}

/****************************************************************************/

static char * deffontnames[5]=
{
 "Trinity.Medium",
 "SwissB.Medium",
 "Homerton.Medium",
 "Helvetica.Medium",
 "Helvetica"
};


int defltfont(void)
{
 int font;

 int i;

 for(i=0;i<5;i++)
 {
  if((font=findxfont(deffontnames[i]))!=-1) break;
 }

 if(i==5) font=0;

 return(font);
}


/* 

   key point;

   the font map font numbers are only updated when a new style
   is added to the style store.
   they are only ever used when a style is in the store, to
   refill its font manager style number.

   try to make add/rem, styles as atomic as possible

*/ 


/* used to return font cache font number from style */

static int stylefont(xstylestr * s)
{
 return(s->data.font);
}

/* don't think this can be answered for mapped fonts */

static int stylecmpfont(xstylestr * s1,xstylestr * s2)
{
 int code;

 code=(ufont(s1->data.font)-ufont(s2->data.font));
 if(!code)
 {
  code=s1->data.font-s2->data.font;
  if(code)
  {
   if(s1->data.bold!=s2->data.bold ||
      s1->data.italic!=s2->data.italic) code=0;

   /* the problem here is fonts which have no bold/italic members  */
   /* ufont numbers are the same, ifonts are different and there's */
   /* no difference in the italic/bold flags  DP324                */
  }
 }

 return(code);
}


static void styleassignfont(xstylestr * d,xstylestr * s)
{
 d->data.mfont=s->data.mfont;
 d->data.font=s->data.font;
 d->data.height=s->data.height;
 d->data.lead=s->data.lead;
/* d->data.leaderwidth=s->data.leaderwidth; */
 d->data.ascent=s->data.ascent;
}


void styleassignjust(xstylestr * d,xstylestr * s)
{
 d->data.justlettermin=s->data.justlettermin;
 d->data.justlettermax=s->data.justlettermax;
 d->data.justsingle=s->data.justsingle;
 d->data.justwordmin=s->data.justwordmin;
 d->data.justwordmax=s->data.justwordmax;
 d->data.justflushzone=s->data.justflushzone;
 d->data.justification=s->data.justification;
}


void styleassignbullet(xstylestr * d,xstylestr * s)
{
 d->data.bullet=s->data.bullet;
 d->data.bulletornumber=s->data.bulletornumber;
 d->data.bullettab=s->data.bullettab;
 d->data.bulletbefore=s->data.bulletbefore;
 d->data.bulletafter=s->data.bulletafter;
 d->data.bulletdata=s->data.bulletdata;
 d->data.bulletstart=s->data.bulletstart;
 d->data.bulletstyle=s->data.bulletstyle;
}



void styleassignhyph(xstylestr * d,xstylestr * s)
{
 d->data.hyphenation=s->data.hyphenation;
 d->data.hpbreaklast=s->data.hpbreaklast;
 d->data.hpbreakcaps=s->data.hpbreakcaps;
 d->data.hpmin=s->data.hpmin;
 d->data.hpbefore=s->data.hpbefore;
 d->data.hpafter=s->data.hpafter;
 d->data.hpconsec=s->data.hpconsec;
 d->data.hpzone=s->data.hpzone;
}


static void styleassignvrule(xstylestr * d,xstylestr * s)
{
 d->data.ruleleft=s->data.ruleleft;
 d->data.ruleleftshift=s->data.ruleleftshift;
 d->data.ruleright=s->data.ruleright;
 d->data.rulerightshift=s->data.rulerightshift;
 d->data.vrulecolour=s->data.vrulecolour;
 d->data.vrulethickness=s->data.vrulethickness;
}


static void styleassignhrule(xstylestr * d,xstylestr * s)
{
 d->data.ruleabove=s->data.ruleabove;
 d->data.ruleaboveshift=s->data.ruleaboveshift;
 d->data.rulebelow=s->data.rulebelow;
 d->data.rulebelowshift=s->data.rulebelowshift;
 d->data.hrulecolour=s->data.hrulecolour;
 d->data.hrulethickness=s->data.hrulethickness;
}


void styleassignuline(xstylestr * d,xstylestr * s)
{
 d->data.underline=s->data.underline;
 d->data.uldouble=s->data.uldouble;
 d->data.ulword=s->data.ulword;
 d->data.ulthickness=s->data.ulthickness;
 d->data.ulcolour=s->data.ulcolour;
 d->data.ultype=s->data.ultype;
}


void styleassignstrike(xstylestr * d,xstylestr * s)
{
 d->data.strikeout=s->data.strikeout;
 d->data.stthickness=s->data.stthickness;
 d->data.sttype=s->data.sttype;
 d->data.stcolour=s->data.stcolour;
}



os_error * validfontstyle(xstylestr * s,int * fh)
{
 int font;
 int fxpts;
 int fypts;

 font=stylefont(s);
 fxpts=s->data.xpts;
 fypts=s->data.ypts;

#ifdef NEVER
 if(s->data.supersub==SUBS || s->data.supersub==SUPS) 
 {
  fxpts=(fxpts*2)/3;     /* this is wrong, should come from prefs */
  fypts=(fypts*2)/3;
 }
#endif

 return(validfont(font,fxpts,fypts,fh,NULL));
}




#ifdef NEVER

 int        fh2;
 int        w;
 int        h;
 int        i;
 int        c;
 int        smlcaps;
 int        smallsize;




  smlcaps=s->data.smlcaps;

  if(!err)
  {
   if(smlcaps)
   {
    smallsize=prefp(file)->smallsize;
    validfont(stylefont(s),scale(s->data.xpts,smallsize,0x10000),
                           scale(s->data.ypts,smallsize,0x10000),&fh2,NULL);
   }

   s->data.leaderwidth=0;
   i=0;
   while(i<LEADERLEN && (c=s->data.leaderchar[i])!=0)
   {
    if(smlcaps && riscos_islower(c)) err=fontcharwidth(fh2,riscos_toupper(c),&w,&h);
    else                      err=fontcharwidth(fh,c,&w,&h);


    if(!err) s->data.leaderwidth+=w;
    else     
    {
     s->data.leaderwidth=s->data.xpts;
     break;
    }

    i++;
   }
  }

#endif




/* function to setup positive offset for font */

os_error * getstylefbbox(xstylestr * s,filestr * file)
{
 os_error * err;
 font_info  fi1;
 font_info  fi2;
 int        fh;

 err=validfontstyle(s,&fh);
 if(!err)
 {
  err=fontbbox(fh,&fi1,&fi2);
  s->data.lead=fi2.maxy;
  s->data.height=fi2.maxy-fi2.miny;
  s->data.ascent=fi1.maxy;
 }

 if(err)
 {
  s->data.lead=s->data.xpts;
/*  s->data.leaderwidth=s->data.xpts; */
  s->data.height=s->data.ypts;
  s->data.ascent=s->data.ypts;
 }

/* dprintf(0,"ascent=%x",s->data.ascent); */

 return(err);

 USE(file);
}



static void checkstyle(xstylestr * d,filestr * file)
{
 if((!d->data.mfont) || (!d->data.height)) getstylefbbox(d,file);

/*((!d->data.leaderwidth) && d->data.leaderchar[0])) getstylefbbox(d,file);*/
}



void checkfont(xstylestr * d,int * changefont)
{
 int newfont;

 if(*changefont)
 {
  newfont=fontfromstyle2(d->data.font,d->data.bold,d->data.italic);
  if(newfont==d->data.font) *changefont=(*changefont)&(~CHANGEFONTSTYLE);
  else
  {
   d->data.font=newfont;
  }
 }
}




/* find the size of a space in kpts */

int emsize(xstylestr * s)
{ 
 return(s->data.ypts);
}


/* return tracking value in em * 1000 */ 

int readtrack(int track,xstylestr * s)
{
 int em=emsize(s);
 return((track*1000)/em);
}

int readtrackpc(int track,xstylestr * s)
{
 int em=emsize(s);
 return(scale(0x10000,track,em));
}


/* convert the frac xpts track value to absolute value */

int writetrack(int ens,xstylestr * s)
{
 int em=emsize(s);
 return((ens*em)/1000);
}


int writetrackpc(int ens,xstylestr * s)
{
 int em=emsize(s);
 return(scale(ens,em,0x10000));
}


/*****************************************************************************/
/* functions for handling absolute styles */

#define MAXSINT  0x0003FFFF
#define PRSINT   0x0001FFFF
#define MINSINT  0x1
#define BADSTYLE 0x0


static int cmpstylecrc(const void * s1,const void * s2)
{
 return(((scrcstr*)s1)->crc-((scrcstr*)s2)->crc);
}


static int cmpstylen(const void * s1,const void * s2)
{
 return(((absstylestr*)s1)->style.n-((absstylestr*)s2)->style.n);
}


static int cmpastyles(const void * r1,const void * r2)
{
 absstylestr * s1;
 absstylestr * s2;
 int        diff;
 int        count1;
 int        seq1;
 int        font1;
 int        height1;
 int        lead1;
 int        ascent1;

 s1=(absstylestr*)r1;
 s2=(absstylestr*)r2;

 count1=s1->count;
 seq1=s1->style.n;
 font1=s1->style.data.font;
 height1=s1->style.data.height;
 lead1=s1->style.data.lead;
 ascent1=s1->style.data.ascent;

 s1->count=s2->count;
 s1->style.n=s2->style.n;
 s1->style.data.font=s2->style.data.font;
 s1->style.data.height=s2->style.data.height;
 s1->style.data.lead=s2->style.data.lead;
 s1->style.data.ascent=s2->style.data.ascent;

 diff=memcmp(s1,s2,sizeof(absstylestr));

 s1->count=count1;
 s1->style.n=seq1;
 s1->style.data.font=font1;
 s1->style.data.height=height1;
 s1->style.data.lead=lead1;
 s1->style.data.ascent=ascent1;

 return(diff);
}




os_error * findabsstylep(filestr * file,int n,absstylestr ** sp)
{               
 os_error        * err;
 absstylebasestr * sbase;
 absstylestr     * r;
 absstylestr       s;
 int               astyles;
 static int        ecount;


 err=NULL;

 astyles=file->hdr.astyles;
 sbase=fob_find(astyles,file);

 s.style.n=n;
 r=(absstylestr*)bsearch(&s,sbase->absstyle,sbase->n,
                                         sizeof(absstylestr),cmpstylen);
 if(r)
 {
  *sp=r;
 }
 else
 {
  if(!ecount)
  {
   err=geterror(STYLE03);
   ecount++;
  }
  *sp=&sbase->absstyle[0];

#ifndef PROD
 dprintf(5,"lost style search=%d style[0]=%d [1]=%d",n,
                   sbase->absstyle[0].style.n,sbase->absstyle[1].style.n);
#endif

 }

 return(err);
}


os_error * findabsstyle(filestr * file,int n,absstylestr * s)
{
 os_error    * err;
 absstylestr * r;
 err=findabsstylep(file,n,&r);
 *s=*r;
 return(err);
}



os_error * findabsstylex(filestr * file,int n,xstylestr * s)
{
 os_error    * err;
 absstylestr * r;
 err=findabsstylep(file,n,&r);
 *s=r->style;
 return(err);
}





static int stylecrc(xstylestr * s)
{
 int font;
 int height;
 int lead;
 int ascent;
 int seq;
 int crc;

 font=s->data.font;
 height=s->data.height;
 lead=s->data.lead;
 ascent=s->data.ascent;

 seq=s->n;
                          /* !!!! */
 s->n=0;                  /* note that crc must not reflect things that are */
 s->data.font=0;          /* not data */
 s->data.height=0;
 s->data.lead=0;
 s->data.ascent=0;

 crc=0;

 crcblock32(&crc,(char*)s,sizeof(xstylestr));

 s->data.font=font;
 s->data.height=height;
 s->data.lead=lead;
 s->data.ascent=ascent;

 s->n=seq;

 crc&=MAXSINT;
 if(crc<MINSINT) crc+=PRSINT;

 return(crc);
}




os_error * remabsstyle(filestr * file,int n)
{
 os_error         * err;
 absstylebasestr  * sbase;
 int                astyles;
 int                size;
 absstylestr        r;
 absstylestr      * s;
 int                chain;
 int                tabs;
 int                mfont;
 scrcstr            c1;
 scrcstr          * c2;
 scrcstr          * scrcbase;
 int                i;
 int                j;
 int                max;
 int                fcrc;
 int                scrc;


 astyles=file->hdr.astyles;
 err=fob_mod(astyles,file,(fobjptr)&sbase);
 if(!err)
 {
  r.style.n=n;
  max=sbase->n;

  s=bsearch(&r,sbase->absstyle,max,sizeof(absstylestr),cmpstylen);
  if(s)
  {
   s->count--;
   if(s->count)
   {
    fmaprem(file,s->style.data.mfont,1);
   }
   else
   {
    chain=s->chain;
    tabs=s->style.data.tab;
    mfont=s->style.data.mfont;

    scrc=stylecrc(&s->style);

    scrcbase=(scrcstr*)(((char*)sbase->absstyle)+(max*sizeof(absstylestr)));

    c2=NULL;    /* compiler */
    fcrc=max+1;
    while(fcrc--)
    {
     c1.crc=scrc;
     c2=bsearch(&c1,scrcbase,max,sizeof(scrcstr),cmpstylecrc);
     if(c2 && c2->seq==n) break;
     else     /* crc not found, presumeably rehashed */
     {
      scrc+=PRSINT;
      if(scrc>MAXSINT) scrc-=MAXSINT;
      if(scrc<MINSINT) scrc+=PRSINT;
     }
    }

    if(fcrc>=0)
    {
     i=s-sbase->absstyle;
     j=c2-scrcbase;

     memmove(s,s+1,(max-i-1)*sizeof(absstylestr)+j*sizeof(scrcstr));
     memmove(((char*)c2)-sizeof(absstylestr),c2+1,(max-j-1)*sizeof(scrcstr));

     sbase->n--;
     size=sizeof(absstylebasestr)+
                              sbase->n*(sizeof(absstylestr)+sizeof(scrcstr));

     err=fob_change(astyles,file,size,(fobjptr)&sbase);

     /* removing an absolute style, remove any referenced objects */

     remstylechain(file,chain,1);
     remtabruler(file,tabs);
     fmaprem(file,mfont,1);
    }
   }
  }
 }
 return(err);
}



os_error * addabsstyle(filestr * file,absstylestr * s1,int number)
{
 os_error        * err;
 absstylebasestr * sbase;
 int               astyles;
 scrcstr           c1;
 int               n;
 int               size;
 int               scrc;
 scrcstr         * scrcbase;
 scrcstr         * c2;
 absstylestr     * s2;
 int               mfont;


 fmapadd(file,s1->style.data.font,number,&mfont);
 s1->style.data.mfont=mfont;


 scrc=stylecrc(&s1->style);

 astyles=file->hdr.astyles;

 err=fob_mod(astyles,file,(fobjptr)&sbase);
 if(!err)
 {
  scrcbase=(scrcstr*)(((char*)sbase->absstyle)+(sbase->n*sizeof(absstylestr)));

  while(1)
  {
   c1.crc=scrc;
   c2=bnearest(&c1,scrcbase,sbase->n,sizeof(scrcstr),cmpstylecrc);
   n=c2-scrcbase;

   if(n<sbase->n && scrc==c2->crc)
   {                                /* equal numbers */

    s1->style.n=c2->seq;
    s2=bnearest(s1,sbase->absstyle,sbase->n,sizeof(absstylestr),cmpstylen);

    if(cmpastyles(s1,s2))            /* but different styles - a collision */
    {
     scrc+=PRSINT;
     if(scrc>MAXSINT) scrc-=MAXSINT;
     if(scrc<MINSINT) scrc+=PRSINT;
    }
    else                            /* identical styles */
    {
     s2->count+=number;
     break;
    }
   }
   else
   {
    checkstyle(&s1->style,file);

    size=sizeof(absstylebasestr)+
                           (sbase->n+1)*(sizeof(absstylestr)+sizeof(scrcstr));

    err=fob_change(astyles,file,size,(fobjptr)&sbase);

    c1.seq=s1->style.n=sbase->sequence++;

    scrcbase=(scrcstr*)(((char*)sbase->absstyle)+
                                         (sbase->n*sizeof(absstylestr)));
    c2=scrcbase+n;

    memmove(((char*)c2)+sizeof(scrcstr)+sizeof(absstylestr),
                    c2,(sbase->n-n)*sizeof(scrcstr));

    c2=(scrcstr*)(((char*)c2)+sizeof(absstylestr));
    *c2=c1;

    s2=sbase->absstyle+sbase->n;

    memmove(s2+1,s2,n*sizeof(scrcstr));

    *s2=*s1;
    s2->count=number;
    sbase->n++;

    /* we adding a style and must duplicate any referenced objects */
    /* i.e. style chains and tabs */

    dupstylechain(file,s1->chain);
    duptabruler(file,s1->style.data.tab);

    break;
   }
  }
 }

 return(err);
}


os_error * dupabsstyle(filestr * file,int key)
{
 os_error        * err;
 absstylebasestr * sbase;
 int               astyles;
 absstylestr       r;
 absstylestr     * s;


 astyles=file->hdr.astyles;
 err=fob_mod(astyles,file,(fobjptr)&sbase);
 if(!err)
 {
  r.style.n=key;
  s=bsearch(&r,sbase->absstyle,sbase->n,sizeof(absstylestr),cmpstylen);
  if(s)
  {
   s->count++;
   fmapdup(file,s->style.data.mfont);
  }
 }
 return(err);
}



os_error * clearabschanges(filestr * file)
{
 int               astyles;
 absstylebasestr * sbase;
 absstylestr     * s;
 int               n;


 astyles=file->hdr.astyles;

 sbase=fob_find(astyles,file);

 s=sbase->absstyle;
 n=sbase->n;

 while(n--)
 {
  s->changed=0;
  s++;
 }

 return(NULL);
}


/* observation, could set off with an empty hash table of right size */


static os_error * refillabsstyles(filestr * file,int changes)
{
 os_error        * err;
 int               astyles;
 absstylebasestr * sbase;
 int               max;
 int               i;
 absstylestr       style;
 int               oldcrc;
 int               newcrc;
 int               scrc;
 int               fcrc;
 scrcstr           c1;
 scrcstr         * c2;
 scrcstr         * scrcbase;
 int               n;
 int               ins;
 int               rem;
 int               oldtab;
 int               oldmfont;
 int               newmfont;


 err=NULL;

 if(changes)
 {
  astyles=file->hdr.astyles;

  fob_lock((fobjptr)&sbase,astyles,file);

  max=sbase->n;

  for(i=0;i<max;i++)
  {
   style=*(sbase->absstyle+i);

   if(style.changed)
   {
    oldcrc=stylecrc(&style.style);
    oldmfont=style.style.data.mfont;
    oldtab=style.style.data.tab;


    fillinstyle(&style,file);


    if(oldtab!=style.style.data.tab)
    {
     duptabruler(file,style.style.data.tab);
     remtabruler(file,oldtab);
    }


    fmapadd(file,style.style.data.font,style.count,&newmfont);
    fmaprem(file,oldmfont,style.count);
    style.style.data.mfont=newmfont;


    checkstyle(&style.style,file);

    newcrc=stylecrc(&style.style);
    *(sbase->absstyle+i)=style;

    scrc=oldcrc;

    scrcbase=(scrcstr*)(((char*)sbase->absstyle)+(max*sizeof(absstylestr)));

    c2=NULL;    /* compiler */
    fcrc=max+1;
    while(fcrc--)
    {
     c1.crc=scrc;
     c2=bsearch(&c1,scrcbase,max,sizeof(scrcstr),cmpstylecrc);
     if(c2 && c2->seq==style.style.n) break;
     else     /* crc not found, presumeably rehashed */
     {
      scrc+=PRSINT;
      if(scrc>MAXSINT) scrc-=MAXSINT;
      if(scrc<MINSINT) scrc+=PRSINT;
     }
    }


    if(fcrc>=0)
    {
     rem=c2-scrcbase;

     scrc=newcrc;
     while(1)
     {
      c1.crc=scrc;
      c2=bnearest(&c1,scrcbase,sbase->n,sizeof(scrcstr),cmpstylecrc);
      n=c2-scrcbase;

      if(n<max && scrc==c2->crc)
      {                                /* equal numbers */
       scrc+=PRSINT;
       if(scrc>MAXSINT) scrc-=MAXSINT;
       if(scrc<MINSINT) scrc+=PRSINT;
      }
      else                            /* identical styles */
      {
       break;
      }
     }

     ins=c2-scrcbase;


     if(ins<rem)
     {
      memcpy(scrcbase+ins+1,scrcbase+ins,(rem-ins-1)*sizeof(scrcstr));
     }
     else
     if(ins>rem)
     {
      memcpy(scrcbase+rem,scrcbase+rem+1,(ins-rem-1)*sizeof(scrcstr));
      ins--;
     }

     scrcbase[ins].seq=style.style.n;
     scrcbase[ins].crc=scrc;
    }
   }
  }

  fob_unlock((fobjptr)&sbase,file);
 }

 return(err);
}



os_error * updateabsstyles(filestr * file,int * changesp,int clear)
{
 int               cstyles;
 int               astyles;
 cstylebasestr   * cbase;
 stylechainstr     chainhdr;
 stylechainstr   * c;
 absstylebasestr * sbase;
 int               n;
 absstylestr     * s;
 int               changes;



 cstyles=file->hdr.cstyles;
 astyles=file->hdr.astyles;

 cbase=fob_find(cstyles,file);
 sbase=fob_find(astyles,file);

 s=sbase->absstyle;
 n=sbase->n;
 if(clear) changes=0;
 else      changes=*changesp;

 while(n--)
 {
  chainhdr.key=s->chain;
  c=(stylechainstr*)bsearch(&chainhdr,cbase->stylechain,cbase->n,
                                      sizeof(stylechainstr),cmpchainn);
  if(c && c->changed)
  {
   s->changed=1;
   changes++;
  }
  else
  if(clear)
  {
   s->changed=0;
  }

  s++;
 }

 *changesp=changes;

 refillabsstyles(file,changes);

/* dprintf(2,"abs update changes=%d",changes); */

 return(NULL);
}

/*****************************************************************************/
/* style chains */

#define MAXCINT  0x3FFFFFFF
#define MINCINT  0x1
#define PRCINT   0x1FFFFFFF
#define BADCHAIN 0x0


static int cmpchainn(const void * s1,const void * s2)
{
 return(((stylechainstr*)s1)->key-((stylechainstr*)s2)->key);
}

static int cmpchains(int * c1,int n1,int * c2,int n2)
{
 if(n1==n2)
   return(memcmp(c1,c2,sizeof(int)*n1));
 else
   return(n1-n2);
}



os_error * dupstylechain(filestr * file,int key)
{
 os_error      * err;
 cstylebasestr * cbase;
 int             cstyles;
 stylechainstr   chainhdr;
 stylechainstr * s;

 cstyles=file->hdr.cstyles;
 err=fob_mod(cstyles,file,(fobjptr)&cbase);
 if(!err)
 {
  chainhdr.key=key;
  s=(stylechainstr*)bsearch(&chainhdr,&cbase->stylechain[0],cbase->n,
                                         sizeof(stylechainstr),cmpchainn);

  if(s)
  {
   s->count++;
  }
 }
 return(err);
}



os_error * findstylechainp(filestr * file,int key,int ** chainp,int * n)
{
 os_error      * err;
 cstylebasestr * cbase;
 stylechainstr * r;
 int             cstyles;
 static int      ecount;
 stylechainstr   chainhdr;
 int           * p;

 err=NULL;


 cstyles=file->hdr.cstyles;
 cbase=fob_find(cstyles,file);

 chainhdr.key=key;

/*
 {
  int i;
  for(i=0;i<cbase->n;i++)
  {
   dprintf(0,"find key=%d offset=%d n=%d",cbase->stylechain[i].key,
                                     cbase->stylechain[i].offset,
                                     cbase->stylechain[i].n);
  }
 } 
*/

 r=(stylechainstr*)bsearch(&chainhdr,&cbase->stylechain[0],cbase->n,
                                         sizeof(stylechainstr),cmpchainn);

 if(!r)
 {
  if(!ecount)
  {
   err=geterror(STYLE04);
   ecount++;
  }
  r=cbase->stylechain;
 }


 p=(int*)((char*)cbase->stylechain+r->offset);
 *chainp=p;
 *n=r->n;

 return(err);
}



/* style chains contain dud entries after user styles have been deleted */

static os_error * stripstylechain(filestr * file,int * chain,int * n)
{
 userstylestr *  s;
 int             max;
 int             r;
 int             w;

 max=*n;
 w=0;

 for(r=0;r<max;r++)
 {
  finduserstylep(&s,chain[r],file);
  if(s)
  {
   if(r!=w) chain[w]=chain[r];
   w++;
  }
 }

 *n=w;

 return(NULL);
}




os_error * findstylechain(filestr * file,int key,int * chain,int * n)
{
 os_error * err;
 int        m;
 int      * chainp;

 err=findstylechainp(file,key,&chainp,&m);
 if(!err)
 {
  memcpy(chain,chainp,m*sizeof(int));
  *n=m;
 }

 return(err);
}



os_error * findstylechains(filestr * file,int key,int * chain,int * n)
{
 os_error * err;
 err=findstylechain(file,key,chain,n);
 if(!err) err=stripstylechain(file,chain,n);
 return(err);
}




os_error * remstylechain(filestr * file,int key,int number)
{
 os_error      * err;
 cstylebasestr * cbase;
 stylechainstr * r;
 stylechainstr * m;
 stylechainstr   chainhdr;
 int             cstyles;
 int             size;
 int             maxoffset;
 int             offset;
 int             n;
 int             i;
 static int      ecount;


 cstyles=file->hdr.cstyles;
 err=fob_mod(cstyles,file,(fobjptr)&cbase);
 if(!err)
 {
  chainhdr.key=key;

  r=(stylechainstr*)bsearch(&chainhdr,&cbase->stylechain[0],
                                 cbase->n,sizeof(stylechainstr),cmpchainn);
  if(r)
  {
   r->count-=number;
   if(!r->count)
   {
    size=r->n*sizeof(int)+sizeof(stylechainstr);
    offset=r->offset;
    m=&cbase->stylechain[cbase->n-1];
    maxoffset=m->offset+m->n*sizeof(int);
    n=r-cbase->stylechain;

    for(i=n;i<(cbase->n-1);i++)
    {
     cbase->stylechain[i]=cbase->stylechain[i+1];
     cbase->stylechain[i].offset-=size;
    }
    for(i=0;i<n;i++)
    {
     cbase->stylechain[i].offset-=sizeof(stylechainstr);
    }

    memmove((char*)cbase->stylechain+(cbase->n-1)*sizeof(stylechainstr),
            (char*)cbase->stylechain+cbase->n*sizeof(stylechainstr),
             offset-cbase->n*sizeof(stylechainstr));

    offset-=sizeof(stylechainstr);
    memmove((char*)cbase->stylechain+offset,
            (char*)cbase->stylechain+offset+size,maxoffset-offset-size);

    maxoffset-=size;
    size=(int)sizeof(cstylebasestr)-(int)sizeof(stylechainstr)+maxoffset;
    err=fob_change(cstyles,file,size,(fobjptr)&cbase);
    cbase->n--;
   }
  }
  else
  {
   if(!ecount)
   {
    err=geterror(STYLE04);
    ecount++;
   }
  }
 }
 return(err);
}


static int chaincrc(int * s,int n)
{
 int crc;
 crc=0;
 crcblock32(&crc,(char*)s,n*sizeof(int));
 crc&=MAXCINT;
 if(crc<MINCINT) crc+=PRCINT;
 return(crc);
}


os_error * addstylechain(filestr * file,int * chain,int new,
                 int * nkey,int number)
{
 os_error      * err;
 cstylebasestr * cbase;
 stylechainstr   chainhdr;
 int             cstyles;
 stylechainstr * s;
 stylechainstr * m;
 int             key;
 int             n;
 int             size;
 int             i;
 int             offset;
 int             maxoffset;
 int             minoffset;


 cstyles=file->hdr.cstyles;

 key=chaincrc(chain,new);

 err=fob_mod(cstyles,file,(fobjptr)&cbase);
 if(!err)
 {
  while(1)
  {
   chainhdr.key=key;
   s=(stylechainstr*)bnearest(&chainhdr,&cbase->stylechain[0],
                                 cbase->n,sizeof(stylechainstr),cmpchainn);
   n=s-cbase->stylechain;

   if(n<cbase->n && !cmpchainn(s,&chainhdr))
   {                              /* equal numbers */
    if(cmpchains((int*)((char*)cbase->stylechain+s->offset),s->n,chain,new))
    {                             /* but different chains - a collision */
     key+=PRCINT;
     if(key>MAXCINT) key-=MAXCINT;
     if(key<MINCINT) key+=PRCINT;
    }
    else                            /* identical styles */
    {
     s->count+=number;
     break;
    }
   }
   else
   {
    if(cbase->n)
    {
     m=&cbase->stylechain[cbase->n-1];
     maxoffset=m->offset+m->n*sizeof(int);
     size=maxoffset+sizeof(cstylebasestr)-sizeof(stylechainstr);
     size+=sizeof(stylechainstr)+new*sizeof(int);
    }
    else
    {
     size=sizeof(cstylebasestr)+new*sizeof(int);
     maxoffset=0;
    }

    err=fob_change(cstyles,file,size,(fobjptr)&cbase);
    size=new*sizeof(int);

    if(n<cbase->n)
    {
     offset=cbase->stylechain[n].offset;
     memmove(((char*)cbase->stylechain)+offset+sizeof(stylechainstr)+size,
            ((char*)cbase->stylechain)+offset,maxoffset-offset);
    }
    else
    {
     offset=maxoffset;
    }


    if(cbase->n)
    {
     minoffset=cbase->stylechain[0].offset;
     memmove(((char*)cbase->stylechain)+minoffset+sizeof(stylechainstr),
             ((char*)cbase->stylechain)+minoffset,offset-minoffset);
     offset+=sizeof(stylechainstr);

     for(i=cbase->n-1;i>=n;i--)
     {
      cbase->stylechain[i+1]=cbase->stylechain[i];
      cbase->stylechain[i+1].offset+=size+sizeof(stylechainstr);
     }
     for(i=0;i<n;i++)
     {
      cbase->stylechain[i].offset+=sizeof(stylechainstr);
     }
    }
    else
    {
     offset=sizeof(stylechainstr);
    }

    cbase->stylechain[n].offset=offset;
    cbase->stylechain[n].key=key;
    cbase->stylechain[n].count=number;
    cbase->stylechain[n].n=new;
    memmove(((char*)cbase->stylechain)+offset,chain,size);
    cbase->n++;


  /*  {
     int * p;

     p=(int*)(((char*)cbase->stylechain)+offset);

     dprintf(0,"addc offset=%d first=%d size=%d n=%d",
                 offset,*p,size,n);



     for(i=0;i<cbase->n;i++)
     {
      dprintf(0,"offset=%d key=%d n=%d",cbase->stylechain[i].offset,
                  cbase->stylechain[i].key,
                  cbase->stylechain[i].n);

     }
    }  */
    break;
   }
  }
 }

 *nkey=key;
 return(err);
}



os_error * clearchainchanges(filestr * file)
{
 int             cstyles;
 cstylebasestr * cbase;
 stylechainstr * chain;
 int             n;


 cstyles=file->hdr.cstyles;

 cbase=fob_find(cstyles,file);

 chain=cbase->stylechain;
 n=cbase->n;

 while(n--)
 {
  chain->changed=0;
  chain++;
 }

 return(NULL);
}


os_error * updatestylechains(filestr * file,int * changesp)
{
 int                cstyles;
 int                ustyles;
 cstylebasestr    * cbase;
 stylechainstr    * chain;
 userstylebasestr * usersbase;
 int                n;
 int              * p;
 int                i;
 userstylestr       t;
 userstylestr     * r;
 int                changes;
                 

 cstyles=file->hdr.cstyles;
 ustyles=file->hdr.ustyles;

 cbase=fob_find(cstyles,file);
 usersbase=fob_find(ustyles,file);

 chain=cbase->stylechain;
 n=cbase->n;
 changes=0;

 while(n--)
 {
  p=(int*)((char*)cbase->stylechain+chain->offset);
  i=chain->n;

  while(i--)
  {
   t.style.n=*p++;
   r=(userstylestr*)bsearch(&t,usersbase->userstyle,usersbase->n,
                                           sizeof(userstylestr),cmpustylen);

   if(!r) /* !!! there is a problem here, we don't know if missing styles */
   {      /* have just been deleted, or were zapped a long time ago       */
          /* this will lead to false updates */
    chain->changed=1;
    changes++;
    break;
   }
   else
   if(r->changed)
   {
    chain->changed=1;
    changes++;
    break;
   }
  }

  if(i<0) chain->changed=0;
  chain++;
 }

 *changesp=changes;

 return(NULL);
}


/*****************************************************************************/

/* this is called when the fonts have changed whilst doc loaded */


static filestr * styleloadfile;

/* used to prevent checkfontschanged generated events from mapping the */
/* file currently being loaded                                         */


os_error * stylefontchange(int post,filestr * file)
{
 os_error * err;
 int        n;
 int        first;
 int        changed;
 int        changesu;
 int        changesa;


 err=NULL;

 if(post && file!=styleloadfile)
 {
  fmapremap(file,&n,&first,&changed);

  fmapuserstylebase(file,0,&changesu);
  fmapabsstylebase(file,0,&changesa);

  if(changed) refreshfile(file);
 }

 return(err);
}




static os_error * recalcstylesfbb(filestr * file,int missingfonts)
{                 
 os_error         * err;
 absstylebasestr  * sbase;
 int                i;
 userstylebasestr * ubase;

 err=NULL;

 sbase=fob_find(file->hdr.astyles,file);
 if(sbase && sbase->leaderfix==0)
 {
  for(i=0;i<sbase->n;i++)
  {
/*   dprintf(0,"ht=%d ld=%d as=%d",sbase->absstyle[i].style.data.height,
                                 sbase->absstyle[i].style.data.lead,
                                 sbase->absstyle[i].style.data.ascent); */

   getstylefbbox(&sbase->absstyle[i].style,file);

/*   dprintf(1,"ht=%d ld=%d as=%d",sbase->absstyle[i].style.data.height,
                                 sbase->absstyle[i].style.data.lead,
                                 sbase->absstyle[i].style.data.ascent); */

  }
 }

 if(!missingfonts) sbase->leaderfix=1;


 ubase=fob_find(file->hdr.ustyles,file);
 if(ubase && ubase->leaderfix==0)
 {
  for(i=0;i<ubase->n;i++)
  {
   getstylefbbox(&ubase->userstyle[i].style,file);
  }
 }

 if(!missingfonts) ubase->leaderfix=1;


 return(err);
}




/* this is called when doc being loaded */

os_error * stylefontload(filestr * file,int * load)
{
 os_error * err;
 int        n;
 int        first;
 int        action;
 int        changed;
 int        changesu;
 int        changesa;


 err=NULL;

 *load=1;


 styleloadfile=file;

 fmapremap(file,&n,&first,&changed);
 if(n)
 {
  checkforfontschange();
  fmapremap(file,&n,&first,&changed);
  if(n)
  {
   fmapdeclarefonts(file,&changed);
   checkforfontschange();
   fmapremap(file,&n,&first,&changed);
  }
 }

 styleloadfile=NULL;


 if(n) 
 {
  /* if substitute - just fix up fonts                                  */
  /* if replace    - set change bits on styles that have missing fonts  */

  fmapbox(file,&action,n,first);

  if(action==FMAPSUB) 
  {
   fmapuserstylebase(file,0,&changesu);
   fmapabsstylebase(file,0,&changesa);
   recalcstylesfbb(file,1);
  }
  else
  if(action==FMAPREPLACE)
  {
   /* we have to scan styles, and find any that have missing fonts    */
   /* these have to lose their current font, and have a new one added */
   /* they must have the change bit set                               */
   /* style CRC's will change and have to be recaculated              */
   /* remap styles in text                                            */
   /* clear change bits                                               */

   fmapuserstylebase(file,1,&changesu);
   fmapabsstylebase(file,1,&changesa);
   stylemapchange(changesu,changesa,file);
   recalcstylesfbb(file,0);
   fmaptrim(file); /* because we've replaced fonts, we can get rid of unused */
  }
  else
  {
   *load=0;
  }
 }
 else
 {
  fmapuserstylebase(file,0,&changesu);
  fmapabsstylebase(file,0,&changesa);
  recalcstylesfbb(file,0);
 }

 

 return(err);
}


/*****************************************************************************/
/* given s fill in the pieces which the action bits allow */


os_error * fillinstyle(absstylestr * d,filestr * file)
{
 os_error   * err;
 int          chain[MAXCHAIN];
 int          n;
 int          i;
 userstylestr s;
 actionbits   a;
 int          changefont;
 int          changefontsize;
/* int          changeleader; */


 err=findstylechain(file,d->chain,chain,&n);
 if(!err)
 {
  a=d->style.action;

  changefont=changefontsize=0; /* changeleader=0; */
                                                                                  for(i=0;i<n;i++)
  {
   finduserstyle(&s,chain[i],file);

   if(s.style.n)
   {
    if(s.style.action.bold && !a.bold)
    {
     d->style.data.bold=s.style.data.bold;
     a.bold=1;
     changefont|=CHANGEFONTSTYLE;
    }

    if(s.style.action.italic && !a.italic)
    {
     d->style.data.italic=s.style.data.italic;
     a.italic=1;
     changefont|=CHANGEFONTSTYLE;
    }

    if(s.style.action.underline && !a.underline)
    {
     styleassignuline(&d->style,&s.style);
     a.underline=1;
    }

    if(s.style.action.reverse && !a.reverse)
    {
     d->style.data.reverse=s.style.data.reverse;
     a.reverse=1;
    }

    if(s.style.action.supersub && !a.supersub) 
    {
     d->style.data.supersub=s.style.data.supersub;
     a.supersub=1;
    }

    if(s.style.action.strikeout && !a.strikeout) 
    {
     styleassignstrike(&d->style,&s.style);
     a.strikeout=1;
    }

    if(s.style.action.rulevert && !a.rulevert)
    {
     styleassignvrule(&d->style,&s.style);
     a.rulevert=1;
    }

    if(s.style.action.rulehoriz && !a.rulehoriz)
    {
     styleassignhrule(&d->style,&s.style);
     a.rulehoriz=1;
    }

    if(s.style.action.font && !a.font)
    {
     styleassignfont(&d->style,&s.style);
     a.font=1;
     changefont|=CHANGEFONTNAME;
    }

    if(s.style.action.fcolour && !a.fcolour) 
    {
     d->style.data.fcolour=s.style.data.fcolour;
     a.fcolour=1;
    }

    if(s.style.action.bcolour && !a.bcolour) 
    {
     d->style.data.bcolour=s.style.data.bcolour;
     a.bcolour=1;
    }

    if(s.style.action.size && !a.size)
    {
     d->style.data.track=scale(d->style.data.track,emsize(&s.style),
                                                   emsize(&d->style));

     d->style.data.baseshift=scale(d->style.data.baseshift,emsize(&s.style),
                                                           emsize(&d->style));
     
     d->style.data.xpts=scale(s.style.data.ypts,
                              d->style.data.xpts,d->style.data.ypts);
     d->style.data.ypts=s.style.data.ypts;

     a.size=1;
     changefontsize=1;
    }

    if(s.style.action.hscale && !a.hscale)
    {
     d->style.data.xpts=scale(d->style.data.ypts,
                                s.style.data.xpts,s.style.data.ypts);
     a.hscale=1;
     changefontsize=1;
    }

    if(s.style.action.track && !a.track)
    {
     d->style.data.track=scale(s.style.data.track,emsize(&d->style),
                                                  emsize(&s.style));
     a.track=1;
    }

    if(s.style.action.baseshift && !a.baseshift)
    {
     d->style.data.baseshift=scale(s.style.data.baseshift,emsize(&d->style),
                                                          emsize(&s.style));
     a.baseshift=1;
    }

    if(s.style.action.align && !a.align)
    {
     d->style.data.align=s.style.data.align;
     a.align=1;
    }

    if(s.style.action.before && !a.before)
    {
     d->style.data.before=s.style.data.before;
     d->style.data.beforetype=s.style.data.beforetype;
     a.before=1;
    }

    if(s.style.action.after && !a.after)
    {
     d->style.data.after=s.style.data.after;
     d->style.data.aftertype=s.style.data.aftertype;
     a.after=1;
    }

    if(s.style.action.leading && !a.leading)
    {
     d->style.data.leading=s.style.data.leading;
     d->style.data.leadingtype=s.style.data.leadingtype;
     a.leading=1;
    }

    if(s.style.action.left && !a.left)
    {
     d->style.data.lefttype=s.style.data.lefttype;
     d->style.data.leftshift=s.style.data.leftshift;
     a.left=1;
    }

    if(s.style.action.right && !a.right)
    {
     d->style.data.righttype=s.style.data.righttype;
     d->style.data.rightshift=s.style.data.rightshift;
     a.right=1;
    }

    if(s.style.action.first && !a.first)
    {
     d->style.data.firstshift=s.style.data.firstshift;
     a.first=1;
    }

    if(s.style.action.xcase && !a.xcase)
    {
     d->style.data.xcase=s.style.data.xcase;
     a.xcase=1;
    }

    if(s.style.action.drop && !a.drop)
    {
     d->style.data.drop=s.style.data.drop;
     d->style.data.dropno=s.style.data.dropno;
     a.drop=1;
    }

    if(s.style.action.bullet && !a.bullet)
    {
     styleassignbullet(&d->style,&s.style);
     a.bullet=1;
    }
   
    if(s.style.action.hyphenation && !a.hyphenation)
    {
     styleassignhyph(&d->style,&s.style);
     a.hyphenation=1;
    }

    if(s.style.action.justification && !a.justification)
    {
     styleassignjust(&d->style,&s.style);
     a.justification=1;
    }

    if(s.style.action.akern && !a.akern)
    {
     d->style.data.akern=s.style.data.akern;
     a.akern=1;
    }

    if(s.style.action.wordwrap && !a.wordwrap)
    {
     d->style.data.wordwrap=s.style.data.wordwrap;
     a.wordwrap=1;
    }

    if(s.style.action.index && !a.index)
    {
     d->style.data.index=s.style.data.index;
     a.index=1;
    }

    if(s.style.action.contents && !a.contents)
    {
     d->style.data.contents=s.style.data.contents;
     a.contents=1;
    }

    if(s.style.action.layer && !a.layer)
    {
     d->style.data.layer=s.style.data.layer;
     a.layer=1;
    }

    if(s.style.action.baselinelock && !a.baselinelock)
    {
     d->style.data.baselinelock=s.style.data.baselinelock;
     a.baselinelock=1;
    }

    if(s.style.action.smlcaps && !a.smlcaps)
    {
     d->style.data.smlcaps=s.style.data.smlcaps;
     a.smlcaps=1;
    }

    if(s.style.action.keeplines && !a.keeplines)
    {
     d->style.data.keeplines=s.style.data.keeplines;
     d->style.data.keeplinesno=s.style.data.keeplinesno;
     a.keeplines=1;
    }

    if(s.style.action.keeppara && !a.keeppara)
    {
     d->style.data.keeppara=s.style.data.keeppara;
     a.keeppara=1;
    }

    if(s.style.action.keepnext && !a.keepnext)
    {
     d->style.data.keepnext=s.style.data.keepnext;
     a.keepnext=1;
    }

    if(s.style.action.language && !a.language)
    {
     d->style.data.language=s.style.data.language;
     a.language=1;
    }

    if(s.style.action.tab && !a.tab)
    {
     d->style.data.tab=s.style.data.tab;
     a.tab=1;
  /* d->style.data.leaderwidth=s.style.data.leaderwidth; */
     if(strncmp(d->style.data.leaderchar,s.style.data.leaderchar,LEADERLEN))
     {
     /* changeleader=1; */
      strncpy(d->style.data.leaderchar,s.style.data.leaderchar,LEADERLEN);
     }
    }

    if(s.style.action.rotate && !a.rotate)
    {
     d->style.data.rotate=s.style.data.rotate;
     a.rotate=1;
    }

    if(s.style.action.skew && !a.skew)
    {
     d->style.data.skew=s.style.data.skew;
     a.skew=1;
    }

    if(s.style.action.spare && !a.spare)
    {
     d->style.data.spare=s.style.data.spare;
     a.spare=1;
    }
   }
  }


  checkfont(&d->style,&changefont);
  if(changefont)                   d->style.data.mfont=0;
  if(changefont || changefontsize) d->style.data.height=0;
/* if(changeleader)                 d->style.data.leaderwidth=0; */
 }

 return(err);
}




/* apply the action bits of astyle to rstyle */

void applystyle(xstylestr * rstyle,xstylestr * astyle)
{
 int temp;
 int changefont;
 int changefontsize;
/* int changeleader; */


 changefont=changefontsize=0; /* changeleader=0; */


 if(astyle->action.bold)
 {
  if(rstyle->data.bold!=astyle->data.bold) changefont=CHANGEFONTSTYLE;
  rstyle->data.bold=astyle->data.bold;
  rstyle->action.bold=1;
 }

 if(astyle->action.italic)
 {
  if(rstyle->data.italic!=astyle->data.italic) changefont=CHANGEFONTSTYLE;
  rstyle->data.italic=astyle->data.italic;
  rstyle->action.italic=1;
 }

 if(astyle->action.underline)
 {
  styleassignuline(rstyle,astyle);
  rstyle->action.underline=1;
 }

 if(astyle->action.reverse)
 {
  rstyle->data.reverse=astyle->data.reverse;
  rstyle->action.reverse=1;
 }

 if(astyle->action.supersub) 
 {
  rstyle->data.supersub=astyle->data.supersub;
  rstyle->action.supersub=1;
 }

 if(astyle->action.strikeout) 
 {
  styleassignstrike(rstyle,astyle);
  rstyle->action.strikeout=1;
 }

 if(astyle->action.rulevert)
 {
  styleassignvrule(rstyle,astyle);
  rstyle->action.rulevert=1;
 }

 if(astyle->action.rulehoriz)
 {
  styleassignhrule(rstyle,astyle);
  rstyle->action.rulehoriz=1;
 }

 if(astyle->action.font)
 {
  if(rstyle->data.font!=astyle->data.font) 
  {
   changefont=CHANGEFONTNAME;
   styleassignfont(rstyle,astyle);
  }
  rstyle->action.font=1;
 }

 if(astyle->action.fcolour) 
 {
  rstyle->data.fcolour=astyle->data.fcolour;
  rstyle->action.fcolour=1;
 }

 if(astyle->action.bcolour) 
 {
  rstyle->data.bcolour=astyle->data.bcolour;
  rstyle->action.bcolour=1;
 }

 if(astyle->action.size)
 {
  if(rstyle->data.ypts!=astyle->data.ypts) changefontsize=1;

  rstyle->data.track=scale(rstyle->data.track,emsize(astyle),
                                              emsize(rstyle));

  rstyle->data.baseshift=scale(rstyle->data.baseshift,emsize(astyle),
                                                      emsize(rstyle));

  rstyle->data.xpts=scale(astyle->data.ypts,rstyle->data.xpts,
                                            rstyle->data.ypts);

  rstyle->data.ypts=astyle->data.ypts;

  rstyle->action.size=1;
 }

 if(astyle->action.hscale)
 {
  temp=scale(rstyle->data.ypts,astyle->data.xpts,astyle->data.ypts);
  if(temp!=rstyle->data.xpts)
  {
   rstyle->data.xpts=temp;
   changefontsize=1;
  }
  rstyle->action.hscale=1;
 }

 if(astyle->action.track)
 {
  rstyle->data.track=scale(astyle->data.track,emsize(rstyle),
                                              emsize(astyle));
  rstyle->action.track=1;
 }

 if(astyle->action.baseshift)
 {
  rstyle->data.baseshift=scale(astyle->data.baseshift,emsize(rstyle),
                                                      emsize(astyle));
  rstyle->action.baseshift=1;
 }

 if(astyle->action.align)
 {
  rstyle->data.align=astyle->data.align;
  rstyle->action.align=1;
 }

 if(astyle->action.before)
 {
  rstyle->data.before=astyle->data.before;
  rstyle->data.beforetype=astyle->data.beforetype;
  rstyle->action.before=1;
 }

 if(astyle->action.after)
 {
  rstyle->data.after=astyle->data.after;
  rstyle->data.aftertype=astyle->data.aftertype;
  rstyle->action.after=1;
 }

 if(astyle->action.leading)
 {
  rstyle->data.leading=astyle->data.leading;
  rstyle->data.leadingtype=astyle->data.leadingtype;
  rstyle->action.leading=1;
 }

 if(astyle->action.left)
 {
  rstyle->data.lefttype=astyle->data.lefttype;
  rstyle->data.leftshift=astyle->data.leftshift;
  rstyle->action.left=1;
 }

 if(astyle->action.right)
 {
  rstyle->data.righttype=astyle->data.righttype;
  rstyle->data.rightshift=astyle->data.rightshift;
  rstyle->action.right=1;
 }

 if(astyle->action.first)
 {
  rstyle->data.firstshift=astyle->data.firstshift;
  rstyle->action.first=1;
 }

 if(astyle->action.xcase)
 {
  rstyle->data.xcase=astyle->data.xcase;
  rstyle->action.xcase=1;
 }

 if(astyle->action.drop)
 {
  rstyle->data.drop=astyle->data.drop;
  rstyle->data.dropno=astyle->data.dropno;
  rstyle->action.drop=1;
 }

 if(astyle->action.bullet)
 {
  styleassignbullet(rstyle,astyle);
  rstyle->action.bullet=1;
 }

 if(astyle->action.hyphenation)
 {
  styleassignhyph(rstyle,astyle);
  rstyle->action.hyphenation=1;
 }

 if(astyle->action.justification)
 {
  styleassignjust(rstyle,astyle);
  rstyle->action.justification=1;
 }

 if(astyle->action.akern)
 {
  rstyle->data.akern=astyle->data.akern;
  rstyle->action.akern=1;
 }

 if(astyle->action.wordwrap)
 {
  rstyle->data.wordwrap=astyle->data.wordwrap;
  rstyle->action.wordwrap=1;
 }

 if(astyle->action.index)
 {
  rstyle->data.index=astyle->data.index;
  rstyle->action.index=1;
 }

 if(astyle->action.contents)
 {
  rstyle->data.contents=astyle->data.contents;
  rstyle->action.contents=1;
 }

 if(astyle->action.layer)
 {
  rstyle->data.layer=astyle->data.layer;
  rstyle->action.layer=1;
 }

 if(astyle->action.baselinelock)
 {
  rstyle->data.baselinelock=astyle->data.baselinelock;
  rstyle->action.baselinelock=1;
 }

 if(astyle->action.smlcaps)
 {
  rstyle->data.smlcaps=astyle->data.smlcaps;
  rstyle->action.smlcaps=1;
 }

 if(astyle->action.keeplines)
 {
  rstyle->data.keeplines=astyle->data.keeplines;
  rstyle->data.keeplinesno=astyle->data.keeplinesno;
  rstyle->action.keeplines=1;
 }

 if(astyle->action.keeppara)
 {
  rstyle->data.keeppara=astyle->data.keeppara;
  rstyle->action.keeppara=1;
 }

 if(astyle->action.keepnext)
 {
  rstyle->data.keepnext=astyle->data.keepnext;
  rstyle->action.keepnext=1;
 }

 if(astyle->action.language)
 {
  rstyle->data.language=astyle->data.language;
  rstyle->action.language=1;
 }


 if(astyle->action.tab)
 {
  rstyle->data.tab=astyle->data.tab;
/* rstyle->data.leaderwidth=astyle->data.leaderwidth; */

  if(strncmp(rstyle->data.leaderchar,astyle->data.leaderchar,LEADERLEN))
  {
  /* changeleader=1; */
   strncpy(rstyle->data.leaderchar,astyle->data.leaderchar,LEADERLEN);
  }

  rstyle->action.tab=1;
 }

 if(astyle->action.rotate)
 {
  rstyle->data.rotate=astyle->data.rotate;
  rstyle->action.rotate=1;
 }

 if(astyle->action.skew)
 {
  rstyle->data.skew=astyle->data.skew;
  rstyle->action.skew=1;
 }

 if(astyle->action.spare)
 {
  rstyle->data.spare=astyle->data.spare;
  rstyle->action.spare=1;
 }

 checkfont(rstyle,&changefont);

 if(changefont)                   rstyle->data.mfont=0;
 if(changefontsize || changefont) rstyle->data.height=0;
/* if(changeleader)                 rstyle->data.leaderwidth=0; */
}


void stylesetall(xstylestr * style)
{
 memset(&style->action,0xFF,sizeof(actionbits));
 style->action.spare=1; /* so remaining bits are zero as in def style */
}


void styleclrall(xstylestr * style)
{
 memset(&style->action,0,sizeof(actionbits));
}




/* be careful that last action bit is 23 bits wide */
/* bit ops do not always give right result         */

void stylexorbits(actionbits * result,actionbits * a1,actionbits * a2)
{
 int   i;
 int * r;
 int * p1;
 int * p2;

 r=(int*)result;
 p1=(int*)a1;
 p2=(int*)a2;

 for(i=0;i<sizeof(actionbits)/sizeof(int);i++)
 {
  *r++=(*p1++)^(*p2++);
 }
}


void styleandbits(actionbits * result,actionbits * a1,actionbits * a2)
{
 int   i;
 int * r;
 int * p1;
 int * p2;

 r=(int*)result;
 p1=(int*)a1;
 p2=(int*)a2;

 for(i=0;i<sizeof(actionbits)/sizeof(int);i++)
 {
  *r++=(*p1++)&(*p2++);
 }
}


void styleorrbits(actionbits * result,actionbits * a1,actionbits * a2)
{
 int   i;
 int * r;
 int * p1;
 int * p2;

 r=(int*)result;
 p1=(int*)a1;
 p2=(int*)a2;

 for(i=0;i<sizeof(actionbits)/sizeof(int);i++)
 {
  *r++=(*p1++)|(*p2++);
 }
}



void styleclrbits(actionbits * result,actionbits * a1,actionbits * a2)
{
 int   i;
 int * r;
 int * p1;
 int * p2;

 r=(int*)result;
 p1=(int*)a1;
 p2=(int*)a2;

 for(i=0;i<sizeof(actionbits)/sizeof(int);i++)
 {
 // cprintf("clr bits %x %x %x",*p1,*p2,(*p1)&(~(*p2)));

  *r++=(*p1++)&(~(*p2++));

 }
}




void styleflipall(xstylestr * style)
{
 actionbits setbits;
 memset(&setbits,0xFF,sizeof(actionbits));
 stylexorbits(&style->action,&style->action,&setbits);
}


static actionbits fbits=
{
  /* action bits */

  0, /* bold      */
  0, /* italic    */
  0, /* underline */
  0, /* reverse   */
  0, /* supersub  */
  0, /* strikeout */

  0, /* rulevert  */
  0, /* rulehoriz */

  0, /* font */
  0, /* fcolour */
  0, /* bcolour */
  0, /* size */
  0, /* hscale */
  0, /* track */
  0, /* baseshift */


  1, /* align */
  1, /* before */
  1, /* after */
  1, /* leading */
  1, /* left */
  1, /* right */
  1, /* first */
  0, /* case */
  1, /* drop */
  1, /* bullet */

  1, /* hyphenation */
  1, /* auto kern */
  1, /* word wrap */

  0, /* index */
  1, /* contents */
  1, /* layer    */

  0, /* base line lock */
  0, /* small caps */

  1, /* keeplines */
  1, /* keep para */
  1, /* keep next */

  1, /* language */

  1, /*  tab */

  0, /* rotate */
  0, /* skew   */

  1, /* justification */

  0, /* spare bytes */

};




void styleclrxformat(xstylestr * style)
{
 styleandbits(&style->action,&style->action,&fbits);
}




/* clear the act bits in style, for any attributes that differ from rstyle */
                   
void stylediffbits(xstylestr * style,xstylestr * rstyle)
{

 if(style->data.bold!=rstyle->data.bold) style->action.bold=0;

 if(style->data.italic!=rstyle->data.italic) style->action.italic=0;

 if(style->data.underline!=rstyle->data.underline ||
    style->data.uldouble!=rstyle->data.uldouble ||
    style->data.ulword!=rstyle->data.ulword ||
    style->data.ulthickness!=rstyle->data.ulthickness ||
    style->data.ultype!=rstyle->data.ultype ||
    cmpcolourval(&style->data.ulcolour,&rstyle->data.ulcolour)
   )
                                                  style->action.underline=0;

 if(style->data.reverse!=rstyle->data.reverse) style->action.reverse=0;

 if(style->data.supersub!=rstyle->data.supersub) style->action.supersub=0;

 if(style->data.strikeout!=rstyle->data.strikeout ||
    style->data.stthickness!=rstyle->data.stthickness ||
    style->data.sttype!=rstyle->data.sttype ||
    cmpcolourval(&style->data.stcolour,&rstyle->data.stcolour)
   )                                             style->action.strikeout=0;

 if(style->data.ruleleft!=rstyle->data.ruleleft   ||
    style->data.ruleright!=rstyle->data.ruleright ||

    style->data.ruleleftshift!=rstyle->data.ruleleftshift ||
    style->data.rulerightshift!=rstyle->data.rulerightshift ||

    cmpcolourval(&style->data.vrulecolour,&rstyle->data.vrulecolour) ||
    style->data.vrulethickness!=rstyle->data.vrulethickness
   ) 
                                                   style->action.rulevert=0;

 if(style->data.ruleabove!=rstyle->data.ruleabove ||
    style->data.rulebelow!=rstyle->data.rulebelow ||
    style->data.ruleaboveshift!=rstyle->data.ruleaboveshift ||
    style->data.rulebelowshift!=rstyle->data.rulebelowshift ||
    cmpcolourval(&style->data.hrulecolour,&rstyle->data.hrulecolour) ||
    style->data.hrulethickness!=rstyle->data.hrulethickness
   ) 
                                                   style->action.rulehoriz=0;



 if(stylecmpfont(style,rstyle)) style->action.font=0;



 if(cmpcolourval(&style->data.fcolour,&rstyle->data.fcolour))
                                                   style->action.fcolour=0;

 if(cmpcolourval(&style->data.bcolour,&rstyle->data.bcolour))
                                                   style->action.bcolour=0;

 if(style->data.ypts!=rstyle->data.ypts) style->action.size=0;

 if(scale(0x10000, style->data.xpts, style->data.ypts)!=
    scale(0x10000,rstyle->data.xpts,rstyle->data.ypts)) style->action.hscale=0;

 if(scale(0x10000,style->data.track,emsize(style))!=
    scale(0x10000,rstyle->data.track,emsize(rstyle))) style->action.track=0;

 if(scale(0x10000,style->data.baseshift,emsize(style))!=
    scale(0x10000,rstyle->data.baseshift,emsize(rstyle))) 
                                                     style->action.baseshift=0;

 if(style->data.align!=rstyle->data.align) style->action.align=0;

 if(style->data.before!=rstyle->data.before ||
    style->data.beforetype!=rstyle->data.beforetype) style->action.before=0;

 if(style->data.after!=rstyle->data.after ||
    style->data.aftertype!=rstyle->data.aftertype) style->action.after=0;

 if(style->data.leading!=rstyle->data.leading ||
    style->data.leadingtype!=rstyle->data.leadingtype) style->action.leading=0;

 if(style->data.lefttype!=rstyle->data.lefttype ||
    style->data.leftshift!=rstyle->data.leftshift) style->action.left=0;

 if(style->data.righttype!=rstyle->data.righttype ||
    style->data.rightshift!=rstyle->data.rightshift) style->action.right=0;

 if(style->data.firstshift!=rstyle->data.firstshift) style->action.first=0;

 if(style->data.xcase!=rstyle->data.xcase) style->action.xcase=0;

 if(style->data.drop!=rstyle->data.drop ||
    style->data.dropno!=rstyle->data.dropno) style->action.drop=0;

 if(style->data.bullet!=rstyle->data.bullet ||
    style->data.bulletornumber!=rstyle->data.bulletornumber ||
    style->data.bullettab!=rstyle->data.bullettab ||
    style->data.bulletbefore!=rstyle->data.bulletbefore ||
    style->data.bulletafter!=rstyle->data.bulletafter ||
    style->data.bulletdata!=rstyle->data.bulletdata ||
    style->data.bulletstart!=rstyle->data.bulletstart ||
    style->data.bulletstyle!=rstyle->data.bulletstyle) style->action.bullet=0;

 if(style->data.hyphenation!=rstyle->data.hyphenation ||
    style->data.hpbreaklast!=rstyle->data.hpbreaklast ||
    style->data.hpbreakcaps!=rstyle->data.hpbreakcaps ||
    style->data.hpmin!=rstyle->data.hpmin ||
    style->data.hpbefore!=rstyle->data.hpbefore ||
    style->data.hpafter!=rstyle->data.hpafter ||
    style->data.hpconsec!=rstyle->data.hpconsec ||
    style->data.hpzone!=rstyle->data.hpzone) style->action.hyphenation=0;

 if(style->data.justlettermin!=rstyle->data.justlettermin ||
    style->data.justlettermax!=rstyle->data.justlettermax ||
    style->data.justsingle!=rstyle->data.justsingle ||
    style->data.justwordmin!=rstyle->data.justwordmin ||
    style->data.justwordmax!=rstyle->data.justwordmax ||
    style->data.justflushzone!=rstyle->data.justflushzone ||
    style->data.justification!=rstyle->data.justification) 
                                             style->action.justification=0;

 if(style->data.akern!=rstyle->data.akern) style->action.akern=0;

 if(style->data.wordwrap!=rstyle->data.wordwrap) style->action.wordwrap=0;

 if(style->data.index!=rstyle->data.index) style->action.index=0;

 if(style->data.contents!=rstyle->data.contents) style->action.contents=0;

 if(style->data.layer!=rstyle->data.layer)       style->action.layer=0;

 if(style->data.baselinelock!=rstyle->data.baselinelock) 
                                                style->action.baselinelock=0;

 if(style->data.smlcaps!=rstyle->data.smlcaps) style->action.smlcaps=0;

 if(style->data.keeplines!=rstyle->data.keeplines ||
  style->data.keeplinesno!=rstyle->data.keeplinesno) style->action.keeplines=0;

 if(style->data.keeppara!=rstyle->data.keeppara) style->action.keeppara=0;

 if(style->data.keepnext!=rstyle->data.keepnext) style->action.keepnext=0;

 if(style->data.language!=rstyle->data.language) style->action.language=0;

 if(style->data.tab!=rstyle->data.tab) style->action.tab=0;

 if(style->data.rotate!=rstyle->data.rotate) style->action.rotate=0;

 if(style->data.skew!=rstyle->data.skew) style->action.skew=0;

 if(style->data.spare!=rstyle->data.spare) style->action.spare=0;
}



os_error * writedefltstyle(char * w,filestr * file)
{
 os_error   * err;
 absstylestr  s;
 int          chain[1];
 int          key;

 chain[0]=BODYTEXT;
 err=addstylechain(file,chain,1,&key,1);
 if(!err)
 {
  memset(&s,0,sizeof(absstylestr));

  s.chain=key;

  err=fillinstyle(&s,file);
  if(!err)
  {
   err=addabsstyle(file,&s,1);

   *w++=SNO;
   *w++=s.style.n;
   *w++=s.style.n>>8;
   *w++=s.style.n>>16;

 /*  dprintf(5,"def n=%d",s.style.n); */
  }

  remstylechain(file,key,1);
 }
 return(err);
}


/****************************************************************************/

/* add style maps to a new document */

os_error * newstylemap(filestr * file,int user)
{
 os_error          * err;
 int                 uhandle=0; /* init these to make compiler happy */
 int                 ahandle=0;
 int                 chandle=0;
 int                 thandle=0;
 userstylebasestr  * ustylebase;
 absstylebasestr   * astylebase;
 cstylebasestr     * chainbase;
 tabbasestr        * tabbase;


 err=fob_create(sizeof(userstylebasestr),file,OUSTYLE,(fobjptr)&ustylebase);
 if(!err)
 {
  uhandle=ustylebase->key;
  ustylebase->sequence=BODYTEXT;

  err=fob_create(sizeof(absstylebasestr),file,OASTYLE,(fobjptr)&astylebase);
  if(!err)
  {
   ahandle=astylebase->key;
   astylebase->sequence=MINSINT;
   astylebase->leaderfix=1;
   if(!err)
   {
    err=fob_create(sizeof(cstylebasestr),file,OCSTYLE,(fobjptr)&chainbase);
    chandle=chainbase->key;
    if(!err)
    {
     err=fob_create(sizeof(tabbasestr),file,OTABS,(fobjptr)&tabbase);
     thandle=tabbase->key;
    }
   }
  }
 }

 if(!err)
 {
  file->hdr.ustyles=uhandle;
  file->hdr.astyles=ahandle;
  file->hdr.cstyles=chandle;
  file->hdr.tabs=thandle;

  if(user)
  {
   err=makedefstyle(file,NULL,NULL);
  }
 }
 return(err);
}


