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

#define SET_C

#include "keybind.h"

#include <h/envvar_str.h>
#include <h/rcformat.h>
#include <lib/ori_rc_lib.h>
#include <lib/ori_add_lib.h>
/*}}}  */

/*{{{  types*/
typedef struct charset
 { unsigned char *name;
   int  no;
   SetField set;
   struct charset *next;
 } charset;
/*}}}  */
/*{{{  variables*/
private int set_used=(int)first_user_set;
private charset *sets=0;
/*}}}  */

/*{{{  poke_char*/
private void poke_char(int x,SetField setcode)
 {
   setcode[x/BITS_P_SET_PAKET] |= (1<<(x & (BITS_P_SET_PAKET-1)));
 }
/*}}}  */
/*{{{  init_sets*/
public void init_sets(void)
{
  charset *x;
  int i;

  sets=0;
  /*{{{  alnum*/
  x=(charset*)calloc(1,sizeof(charset));
  if (!x)
     goto mem_exit;
  x->name=(unsigned char*)ALNUM_STR;
  x->no=alnum_set;
  for (i=0;i<O_NOP;i++)
     if (isalnum(i))
        poke_char(i,x->set);
  x->next=sets;
  sets=x;
  /*}}}  */
  /*{{{  digit*/
  x=(charset*)calloc(1,sizeof(charset));
  if (!x)
     goto mem_exit;
  x->name=(unsigned char*)DIGIT_STR;
  x->no=digit_set;
  for (i=0;i<O_NOP;i++)
     if (isdigit(i))
        poke_char(i,x->set);
  x->next=sets;
  sets=x;
  /*}}}  */
  /*{{{  alpha*/
  x=(charset*)calloc(1,sizeof(charset));
  if (!x)
     goto mem_exit;
  x->name=(unsigned char*)ALPHA_STR;
  x->no=alpha_set;
  for (i=0;i<O_NOP;i++)
     if (isalpha(i))
        poke_char(i,x->set);
  x->next=sets;
  sets=x;
  /*}}}  */
  /*{{{  upper*/
  x=(charset*)calloc(1,sizeof(charset));
  if (!x)
     goto mem_exit;
  x->name=(unsigned char*)UPPER_STR;
  x->no=upper_set;
  for (i=0;i<O_NOP;i++)
     if (isupper(i))
        poke_char(i,x->set);
  x->next=sets;
  sets=x;
  /*}}}  */
  /*{{{  lower*/
  x=(charset*)calloc(1,sizeof(charset));
  if (!x)
     goto mem_exit;
  x->name=(unsigned char*)LOWER_STR;
  x->no=lower_set;
  for (i=0;i<O_NOP;i++)
     if (islower(i))
        poke_char(i,x->set);
  x->next=sets;
  sets=x;
  /*}}}  */
  /*{{{  blank*/
  x=(charset*)calloc(1,sizeof(charset));
  if (!x)
     goto mem_exit;
  x->name=(unsigned char*)BLANK_STR;
  x->no=blank_set;
  poke_char(' ',x->set);
  poke_char('\t',x->set);
  x->next=sets;
  sets=x;
  /*}}}  */
  /*{{{  xdigit*/
  x=(charset*)calloc(1,sizeof(charset));
  if (!x)
     goto mem_exit;
  x->name=(unsigned char*)XDIGIT_STR;
  x->no=xdigi_set;
  for (i=0;i<O_NOP;i++)
     if (isxdigit(i))
        poke_char(i,x->set);
  x->next=sets;
  sets=x;
  /*}}}  */
  /*{{{  cntrl*/
  x=(charset*)calloc(1,sizeof(charset));
  if (!x)
     goto mem_exit;
  x->name=(unsigned char*)CNTRL_STR;
  x->no=cntrl_set;
  for (i=0;i<O_NOP;i++)
     if (iscntrl(i))
        poke_char(i,x->set);
  x->next=sets;
  sets=x;
  /*}}}  */
  /*{{{  punct*/
  x=(charset*)calloc(1,sizeof(charset));
  if (!x)
     goto mem_exit;
  x->name=(unsigned char*)PUNCT_STR;
  x->no=punct_set;
  for (i=0;i<O_NOP;i++)
     if (ispunct(i))
        poke_char(i,x->set);
  x->next=sets;
  sets=x;
  /*}}}  */
  /*{{{  print*/
  x=(charset*)calloc(1,sizeof(charset));
  if (!x)
     goto mem_exit;
  x->name=(unsigned char*)PRINT_STR;
  x->no=print_set;
  for (i=0;i<O_NOP;i++)
     if (isprint(i))
        poke_char(i,x->set);
  x->next=sets;
  sets=x;
  /*}}}  */
  /*{{{  space*/
  x=(charset*)calloc(1,sizeof(charset));
  if (!x)
     goto mem_exit;
  x->name=(unsigned char*)SPACE_STR;
  x->no=space_set;
  for (i=0;i<O_NOP;i++)
     if (isspace(i))
        poke_char(i,x->set);
  x->next=sets;
  sets=x;
  /*}}}  */
  /*{{{  graph*/
  x=(charset*)calloc(1,sizeof(charset));
  if (!x)
     goto mem_exit;
  x->name=(unsigned char*)GRAPH_STR;
  x->no=graph_set;
  for (i=0;i<O_NOP;i++)
     if (isgraph(i))
        poke_char(i,x->set);
  x->next=sets;
  sets=x;
  /*}}}  */
  return;

mem_exit:
  m_exit(M_NOMEMORY);
}
/*}}}  */
/*{{{  parse_set*/
public void parse_set(void)
{
  charset *x;

  /*{{{  get memory for set*/
  x=kbd_malloc(sizeof(charset));
  memset(x->set,0,(size_t)SET_LG);
  /*}}}  */
  /*{{{  get name for set*/
  if (get_full_token()!=NAME)
     m_exit(M_SNAME);
  x->name=mstrcpy(tk_string);
  if (verbose_level>0)
     fprintf(stderr,F_SETDEC,tk_string,set_used);
  /*}}}  */
  /*{{{  get all set members*/
  for (begin_parse();;)
   { switch (get_full_token())
      { case END:
           break;
        case NAME:
         /*{{{  predefined set or ctrl-char*/
         { charset *y;

           /*{{{  try to set y to the set, belonging to tk_string*/
           for (y=sets;y;y=y->next)
              if (!ustrcmp(tk_string,y->name))
               /*{{{  or the codes and*/
               { int j;

                 for (j=0;j<SET_LG;j++) x->set[j] |= y->set[j];
                 break;
               }
               /*}}}  */
           /*}}}  */
           if (!y)
              if
               /*{{{  a ctrl-string*/
               (    tk_string[0]=='C'
                 && tk_string[1]=='-'
                 && tk_string[2]!='\0'
                 && tk_string[3]=='\0'
               )
               /*}}}  */
               /*{{{  ctrl-char*/
                 poke_char(ctrl_c[(int)tk_string[2]],x->set);
               /*}}}  */
              else
                 goto set_expected;
           continue;
         }
         /*}}}  */
        case MACRO:
         /*{{{  single char parsing*/
           if (ustrlen(tk_string)==1)
            /*{{{  single char*/
            { poke_char((int)(tk_string[0]),x->set);
              continue;
            }
            /*}}}  */
           else
              goto set_expected;
         /*}}}  */
        set_expected:
        default:
           m_exit(M_NOSETCHAR);
      }
     break;
   }
  /*}}}  */
  /*{{{  add to list of sets*/
  x->no=set_used;
  x->next=sets;
  sets=x;
  /*}}}  */
  set_used+=add_new_set;
}
/*}}}  */
/*{{{  get_set*/
public int get_set(void)
{ charset *x=sets;

  /*{{{  name?*/
  if (get_full_token()!=NAME)
     m_exit(M_SNAME);
  /*}}}  */
  /*{{{  look in list and return no*/
  while (x)
     if (!ustrcmp(tk_string,x->name))
        return(x->no);
     else
        x=x->next;
  /*}}}  */
  m_exit(M_SETMISS);
}
/*}}}  */
/*{{{  parse_set_macro*/
public TOKEN *parse_set_macro(TOKEN* buff)
{
  *buff++=M_SET_COPY;
  if ((*buff++=get_set())<0)
     m_exit(M_SNAME);
  *buff++=(TOKEN)get_set();

  return(buff);
}
/*}}}  */
/*{{{  writesets*/
public void writesets(FILE *rc_file)
{
  if (set_used)
   { if (verbose_level>0)
        fprintf(stderr,F_SETUSE,set_used);
     rc_put_c(RC_CHARSET,rc_file);
     rc_put_w(set_used,rc_file);
     /*{{{  write all sets*/
     { charset *x;

       for (x=sets;x;x=x->next)
          if (x->no>=(int)first_user_set)
           { int i;

             for (i=0;i<SET_LG;i++)
                rc_put_c(x->set[i],rc_file);
           }
     }
     /*}}}  */
     /*{{{  put names*/
     { int lg;
       charset *x;

       /*{{{  get length of all names*/
       for (lg=0,x=sets;x;x=x->next)
          if (x->no>=(int)first_user_set)
             lg+=1+ustrlen(x->name);
       /*}}}  */
       rc_put_w(lg,rc_file);
       for (x=sets;x;x=x->next)
          if (x->no>=(int)first_user_set)
           { unsigned char *s;

             for (s=x->name;;s++)
              { unsigned char c;

                c = *s;
                rc_put_c(c,rc_file);
                if (!c)
                   break;
              }
           }
     }
     /*}}}  */
   }
}
/*}}}  */
