/*{{{}}}*/
/*{{{  #includes*/
#ifdef CONFIG_H
#   include "config.h"
#endif

#ifdef VARARGS
#  include <varargs.h>
#else
#  include <stdarg.h>
#endif
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>

#define GETMSG_C
#define I_MESSAGES_C
#define I_SCREEN_C

#include "origami.h"
#include <h/envvar_str.h>
#include <lib/ori_add_lib.h>
/*}}}  */

/*{{{  variable declarations*/
public unsigned char **rc_msg=0;
public int rc_msg_count=0;
public int msg_file= -1;
public msgtyp last_message = M_BASE_FORMAT;
/*}}}  */

/*{{{  i_to_ua*/
public unsigned char *i_to_ua(int x)
{
# define NBSIZE ((sizeof(int)<<2)+1)
  static unsigned char number[NBSIZE];
  unsigned char *s;
  boolean neg;

  if ((neg=(x<0))) x= -x;
  s=number+NBSIZE-1;
  *s=0;
  do
   { *(--s)=hex_digits[x%10]; }
  while ((x/=10)>0);
  if (neg) *(--s)='-';
  return(s);
}
/*}}}  */
/*{{{  get and format a message*/
#ifdef VARARGS
   public unsigned char *get_msg(n,va_alist) msgtyp n; va_dcl
#else
   public unsigned char *get_msg(msgtyp n, ... )
#endif
{
  /*{{{  variable declarations*/
  va_list ap;
#  define MAX_MSG_LEN (1024+BIND_NAME_LEN*NO_OCL_CMD_OPTS+3*_POSIX_PATH_MAX)
#  define GETMSGLEN ((LINELEN>=MAX_MSG_LEN)?(LINELEN+1):MAX_MSG_LEN)
  static unsigned char s[GETMSGLEN+1];
  unsigned char *x;
  unsigned char *y;
  unsigned char *z;
  /*{{{  buffer for read msg-entries*/
  /*{{{  type MSGBUFF*/
  typedef struct
   { unsigned int time;
     msgtyp n;
     unsigned char str[MSG_LENGTH+2];
   } MSGBUFF;
  /*}}}  */
#  define MSG_START_TIME ((unsigned int) ~0)
  static MSGBUFF msg_buff[]=
   /*{{{  empty init. end of list is M_BASE_FORMAT*/
   { { MSG_START_TIME, NUM_MESSAGES, "" },
     { MSG_START_TIME, NUM_MESSAGES, "" },
     { MSG_START_TIME, NUM_MESSAGES, "" },
     { MSG_START_TIME, NUM_MESSAGES, "" },
     { MSG_START_TIME, NUM_MESSAGES, "" },
     { MSG_START_TIME, NUM_MESSAGES, "" },
     { MSG_START_TIME, NUM_MESSAGES, "" },
     { MSG_START_TIME, M_BASE_FORMAT, "\0" BASENAMEF }
   };
   /*}}}  */
  static unsigned int msg_time=MSG_START_TIME;
  /*}}}  */
  /*}}}  */

  ocl_msg("get msg %d",n);
  /*{{{  start arglist handling*/
#  ifdef VARARGS
     va_start(ap);
#  else
     va_start(ap,n);
#  endif
  /*}}}  */
  /*{{{  x=format string*/
  if (n==MSG_ARG_FORMAT)
     x=va_arg(ap,unsigned char*);
  else
   /*{{{  set x to msg-string from file*/
   { unsigned int t = --msg_time;
     int i = 0;
     MSGBUFF *b = msg_buff;

     last_message=n;
     /*{{{  search in list*/
     while (b->n!=n && b->n!=M_BASE_FORMAT)
      { if (b->time>t)
         { t=b->time;
           i=b-msg_buff;
         }
        b++;
      }
     /*}}}  */
     if (b->n==n)
      /*{{{  found, so set time to now*/
      { b->time=msg_time;
        x=b->str+1;
      }
      /*}}}  */
     else
      /*{{{  read msg from file to buffer*/
      { ori_assert(msg_file>=0,"msg-file");
        b=msg_buff+i;
        if
          /*{{{  seek or read not ok?*/
          (   (  lseek(msg_file,
                        (off_t)((n-1)*(MSG_LENGTH+MSG_ADDITIONAL)),
                        SEEK_SET)
                 ==(off_t)-1
                )
           || (read(msg_file,(char *)b->str+1,(size_t)MSG_LENGTH)==-1)
           || !b->str[1]
          )
          /*}}}  */
            x=(unsigned char*)M_MIS_MES;
         else
          /*{{{  prepare read string for buffer*/
          {
            /*{{{  cut trailing spaces*/
            x=x=b->str+MSG_LENGTH;
            while (*--x==' ');
            *(x+1)='\0';
            x=b->str+1;
            if (!*x)
               x=(unsigned char*)one_space;
            /*}}}  */
            b->time=msg_time;
            b->n=n;
           }
          /*}}}  */
      }
      /*}}}  */
     /*{{{  maybe shift time, if 0 reached*/
     if (!msg_time)
      { for (b=msg_buff;b->n!=M_BASE_FORMAT;(b++)->time=MSG_START_TIME);
        msg_time=MSG_START_TIME;
      }
     /*}}}  */
   }
   /*}}}  */
  /*}}}  */
  for (y=s;;)
   /*{{{  handle one char/format in msg*/
   { ori_assert(y<=(s+GETMSGLEN),"msg-length");
     switch ((*y = *x++))
      {
        /*{{{  0 -> end string*/
        case '\0':
           break;
        /*}}}  */
        /*{{{  % - only %s, %c, %o, %x and %d implemented*/
        case '%':
         {
#          define BUFF_SIZE (4+3*sizeof(int))
           unsigned char buff[BUFF_SIZE];
           unsigned int modul;

           switch (*x++)
            {
              /*{{{  get string*/
              case 's':
                 z=va_arg(ap,unsigned char*);
                 break;
              /*}}}  */
              /*{{{  get char-string*/
              case 'c':
                 buff[0]=(unsigned char)va_arg(ap,int);
                 if (buff[0]=='\0')
                    goto end_string;
                 if (buff[0]<' ')
                  { buff[1]=ctrl_decode[buff[0]];
                    buff[0]=CTRL_MARK;
                    buff[2]='\0';
                  }
                 else
                    buff[1]='\0';
                 z=buff;
                 break;
              /*}}}  */
              /*{{{  get hex-string*/
              case 'x':
                 modul=16;
                 goto decode_ox;
              /*}}}  */
              /*{{{  get octal-string*/
              case 'o':
                 modul=8;
                 goto decode_ox;
              /*}}}  */
              /*{{{  get int-string*/
              case 'd':
                 modul=10;
                 goto decode_ox;
              /*}}}  */
              /*{{{  decode %o or %x*/
              decode_ox:
               { unsigned int d;

                 z=buff+BUFF_SIZE-1;
                 d=va_arg(ap,unsigned int);
                 *z='\0';
                 do
                  { *--z=hex_digits[d%modul];
                    d=d/modul;
                  }
                 while (d);
                 break;
               }
              /*}}}  */
              /*{{{  empty string*/
              default:
                 continue;
              /*}}}  */
            }
           while (*z)
              *y++ = *z++;
           continue;
         }
        /*}}}  */
        /*{{{  \ - only \n,\\ implemented*/
        case '\\':
         { switch ((*y = *x++))
            { case 'n':
                 *y='\n';
              default:
                 y++;
                 break;
            }
           continue;
         }
        /*}}}  */
        /*{{{  default*/
        default:
           y++;
           continue;
        /*}}}  */
      }
     break;
   }
   /*}}}  */
end_string:
  *y='\0';
  va_end(ap);
  ocl_msg((char*)s,0);
  return s;
}
/*}}}  */
