/*{{{}}}*/
/*{{{  includes*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define REF_INIT_DECOMP

#include <h/keys.h>
#include <h/token.h>
#include <h/rcformat.h>
#include <lib/ori_bool.h>
#include <lib/ori_rc_lib.h>
#include <lib/ori_add_lib.h>
/*}}}  */

/*{{{  variables*/
static char *ref_comp_words=0;
static int ref_code_word_count=0;
static int ref_code_lg=0;
/*}}}  */

/*{{{  ref_compress_text*/
void ref_compress_text(unsigned char *input)
{
  if (input[0])
   /*{{{  compress words and sequences*/
   { unsigned char *s,*line,cur,cur_1,cur_2,cur_3;

     s=line=input;
   new_init:
     cur_1=s[0];
     cur_2=cur_1?s[1]:'\0';
     cur_3=cur_2?s[2]:'\0';
     while ((cur=cur_1))
      {
        /*{{{  shift chars, and get next one*/
        cur_1=cur_2;cur_2=cur_3;cur_3=cur_2?(++s)[2]:'\0';
        /*}}}  */
        if (cur_1==cur && cur_2==cur && (cur==' ' || cur_2==cur))
         /*{{{  compress sequence*/
         { int l;

           for (l=1;(*s==cur) && (++l<REF_MODULO);s++);
           if (cur==' ')
              *line++=REF_CODE_SPACES;
           else
            { *line++=REF_CODE_CHARS;
              *line++=cur;
            }
           *line++=REF_COUNT_BASE+l;
           goto new_init;
         }
         /*}}}  */
        else
         /*{{{  code word/pattern*/
         { if (isalpha(cur))
            /*{{{  search word*/
            { int i;
              char *w;
              char cmp_c;

              cmp_c=tolower(cur);
              for (w=ref_comp_words,i=0;;i++)
                 if (i>=ref_code_word_count)
                    goto simple_code;
                 else
                  { int lw;

                    lw=w[0];
                    if
                     /*{{{  positions matches current list word*/
                     (w[1]==cmp_c && !strncmp(w+2,(char*)s,lw-1))
                     /*}}}  */
                     /*{{{  code special word*/
                     {
                       /*{{{  add code of the word*/
                       *line++=(cur==(unsigned char)w[1])
                                 ? REF_CODE_LWORD
                                 : REF_CODE_UWORD;
                       *line++=REF_COUNT_BASE+i;
                       /*}}}  */
                       /*{{{  skip word in source*/
                       s+=lw-1;
                       /*}}}  */
                       goto new_init;
                     }
                     /*}}}  */
                    /*{{{  skip current list word*/
                    w+=lw+1;
                    /*}}}  */
                  }
            }
            /*}}}  */
           else
            /*{{{  simple code*/
            { simple_code:

              if (cur=='C' && cur_1=='-')
               /*{{{  ctrl-mark*/
               { *line++=REF_CODE_C;
                 s++;
                 goto new_init;
               }
               /*}}}  */
              else if (cur=='M' && cur_1=='-')
               /*{{{  meta-mark*/
               { *line++=REF_CODE_M;
                 s++;
                 goto new_init;
               }
               /*}}}  */
              else
               /*{{{  single char*/
                 *line++=cur;
               /*}}}  */
            }
            /*}}}  */
         }
         /*}}}  */
      }
    *line='\0';
   }
   /*}}}  */
}
/*}}}  */
/*{{{  ref_put_comp_data*/
void ref_put_comp_data(FILE *f)
{
  int l;
  char *s;

  rc_put_c(RC_REF_COMP_STR,f);
  rc_put_w(ref_code_lg,f);
  for (l=ref_code_word_count,s=ref_comp_words;l;l--)
   { int i;

     for (i= *s++;i;i--)
        rc_put_c(*s++,f);
     rc_put_c('\0',f);
   }
}
/*}}}  */
/*{{{  ref_add_word*/
boolean ref_add_word(char *word)
{
  if (ref_code_word_count<O_NOP-REF_COUNT_BASE && isalpha(*word))
   { int l;

     for (l=1;;l++)
      { char c;

        if (isalnum(c=word[l]))
           continue;
        else if (c!='\0' || l<3 || l>=O_NOP)
           break;
        else
         { char *w;
           int i;
         
           for
            ( i=ref_code_word_count,w=ref_comp_words,c=tolower(word[0])
            ;
            ; i--
            )
              if (i==0)
               /*{{{  add it*/
               {
                 /*{{{  realloc the old words*/
                 { char *s;
                   
                   if (!(s=ORImalloc(ref_code_lg+l+1)))
                      return(True);
                   if (ref_code_word_count)
                    { memcpy(s,ref_comp_words,ref_code_lg);
                      ORIfree(ref_comp_words);
                    }
                   ref_comp_words=s;
                 }
                 /*}}}  */
                 /*{{{  apppend length of word*/
                 ref_comp_words[ref_code_lg++]=l;
                 /*}}}  */
                 /*{{{  append new word, first char lowercase*/
                 memcpy(ref_comp_words+ref_code_lg,word,l);
                 ref_comp_words[ref_code_lg]=c;
                 ref_code_lg+=l;
                 /*}}}  */
                 ref_code_word_count++;
                 break;
               }
               /*}}}  */
              else if (w[1]==c && l==w[0]  && !memcmp(w+2,word+1,l-1))
               /*{{{  already in list*/
                 break;
               /*}}}  */
              else
               /*{{{  skip to next list entry*/
                 w+=w[0]+1;
               /*}}}  */
           break;
         }
      }
   }

  return(False);
}
/*}}}  */
/*{{{  ref_init_comp_data*/
boolean ref_init_comp_data(int init)
{
  if (ref_comp_words)
   /*{{{  set empty list*/
   { ORIfree(ref_comp_words);
     ref_comp_words=0;
     ref_code_lg=0;
   }
   /*}}}  */
  ref_code_word_count=0;
  if (init)
   /*{{{  init with default words*/
   { static char *list[]=REF_INIT_WORD_LIST;
     char **wp;

     for (wp=list;*wp;wp++)
      { if (ref_add_word(*wp))
           return(True);
        else
           continue;
      }
   }
   /*}}}  */
  return(False);
  "="; /* SUNOS4.1.2 needs this, don't ask why :-) */
}
/*}}}  */
