%{
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>

#define	PACKER

#include "../proto_util.h"
#include "../kernel.h"
#include "../headers.h"
#include "packit.h"

extern  int		p_lineno;
extern  char		*yytext;
extern  FILE		*yyin;

char			header_dir[256];        /* Headers definition directory
						*/
struct hdir_in		*hd;                    /* Internal header directory structure
						*/
u_int16_t		noh             = 0;    /* Number of headers loaded (header section)
						*/
u_int16_t		nop		= 0;	/* Number of packets
						*/
struct header_hash_table **head_hash;           /* Header definition hash table
                                                */
struct header_info	*finfo;			/* Information returned by gimme_the_data
						*/
u_int16_t		layer;			/* Header layer
						*/
u_int16_t		aux;
int			len_off;		/* Offset of the length information
						*/
u_int8_t		ispointer = 0;		/* The info is a pointer
						 */
int 			i;

struct pack		*the_pack = NULL, *the_pack_aux = NULL, *the_pack_pivot;

struct pack_vect	*out_packs;

char			packs_file[256];	/* Pack file path
						 */
struct fields_list {
  char			field[256];
  union{
    u_int32_t		info;
    char		*pointer;
  }			data;
  struct fields_list 	*next;
} *f_list = NULL, *f_list_aux = NULL, *f_list_pivot, *f_back;

struct layers_list {
  char  		hdr[256];
  struct fields_list 	*fields;
  struct layers_list 	*next;
} *l_list = NULL, *l_list_aux = NULL, *l_list_pivot, *l_back;

u_int32_t pack_string(char *pointer, struct header_info *finfo);
char *parse_expression(char *expr);

%}

%type	<yyinfo> info expression

%union {
  union{
    u_int32_t	info;
    char	*pointer;
  }		yyinfo;
  u_int32_t	yyint;
  char		*yystr;
  int		yyaddr[4];
}

%token	NUMBER EXPR STR ADDR BYTES
%token	PACKET OPEN_BRACE CLOSE_BRACE OPEN_BRACK CLOSE_BRACK LAYER HEADER HEADERS
%token	LOAD OUT_PACK_FILE

%type	<yyaddr> ADDR
%type   <yyint> NUMBER
%type	<yystr> STR EXPR

%%

start: statement
     ;

statement: OUT_PACK_FILE ':' EXPR OPEN_BRACE p_expression CLOSE_BRACE {
             memset(packs_file,0,256);
             memcpy(packs_file,$3,strlen($3)%256);
             put_in_a_file(packs_file,the_pack,nop);
	     printf("%d packet%c %s stored in \"%s\".\n",nop,(nop>1)?('s'):('\0'),(nop>1)?("are"):("is"),packs_file);
	     out_packs = load_packs("out_pack",&i);
	     printf("%d packet%sloaded.\n",i,i<=1?(" "):("s "));
	     show_packs2(out_packs,i);
	     printf("\n");
	     exit(0);
	   }
         | load_h
         ;

p_expression: expression {
                ++nop;
	      }
            | expression p_expression {
	        ++nop;
	      }
            ;
						      
expression: PACKET '#' NUMBER OPEN_BRACE layers_e CLOSE_BRACE {
              the_pack_aux = (struct pack*)malloc(sizeof(struct pack));
              memset(the_pack_aux,0,sizeof(struct pack));
	      the_pack_aux->id = $3;
	      while(l_list != NULL){
		f_list = l_list->fields;
		while(f_list != NULL){
  	 	  if(head_hash == NULL){
                    yyerror("C'mon LOAD the headers!!");
		    exit(0);
                  }else{
                     finfo = gimme_the_data(l_list->hdr,f_list->field,head_hash,noh,&layer);
		     if(finfo == NULL){
		       yyerror("There's no such field!");
		       exit(0);
		     }
		     if(finfo->size != 0){
                       if(!strncmp("hlen",finfo->fname,4) && (layer < MAX_LAYER)){
		         the_pack_aux->layer[layer] = the_pack_aux->layer[layer-1];
                         the_pack_aux->layer[layer] += f_list->data.info << 2+3; // (off<<2)*8bits
		       }
                       if(finfo->swap){
                         if(finfo->size <= 16){
                           f_list->data.info = htons(f_list->data.info);
		         }else{
                            f_list->data.info = htonl(f_list->data.info);
		          }
		       }
		       pack_it(the_pack_aux->data,\
		               f_list->data.info,\
			       finfo->offset+the_pack_aux->layer[layer-1],\
			       finfo->size);
		       the_pack_aux->psize += finfo->size;
		     }else{
		        the_pack_aux->psize += pack_string(f_list->data.pointer,finfo);
		      }
		     f_list_aux = f_list;
		     f_list = f_list->next;
		     free(f_list_aux);
                   }
                }
		l_list_aux = l_list;
		l_list = l_list->next;
		free(l_list_aux);
		l_list_aux = NULL;
	      }
	      f_list_aux = NULL;
	      l_list_aux = NULL;
	      l_list = NULL;
	      f_list = NULL;
 
	      the_pack_pivot = the_pack;
              if(the_pack_pivot != NULL){
	        while(the_pack_pivot->next != NULL)
                  the_pack_pivot = the_pack_pivot->next;
		the_pack_pivot->next = the_pack_aux;
	      }else
	         the_pack = the_pack_aux;
              the_pack_aux->next = NULL;
              the_pack_aux = NULL;
              //printf("\n2send: %d\n",20+((*(the_pack.data+32))>>2)&0x3f);
	      //send_it(the_pack.data,40,the_pack.data+16);
	    }
          ;
	  
load_h:  LOAD HEADERS ':' EXPR {
	   memset(header_dir,0,256);
	   memcpy(header_dir,$4,(strlen($4))%256);
	   count_headers(header_dir,&hd);
	   noh = count_noh(hd);
	   head_hash = mount_header_table(hd,noh);
         }
      ;

layers_e: layers
	| layers_e layers

layers: HEADER ':' STR OPEN_BRACE fields_e CLOSE_BRACE {
	  l_list_aux = (struct layers_list*)malloc(sizeof(struct layers_list));
          memcpy(l_list_aux->hdr,$3,(strlen($3)%256)+1);
          l_list_aux->fields = f_list;
	  
          if(l_list == NULL){
	    l_list = l_list_aux;
	    l_list_pivot = l_list;
          }else{
             l_list_pivot->next = l_list_aux;
	     l_list_pivot = l_list_pivot->next;
	  }
          f_list = NULL;
          f_list_aux = NULL;
        }
      ;

fields_e: fields
	| fields_e fields
	;

fields: STR info {
	  f_list_aux = (struct fields_list*)malloc(sizeof(struct fields_list));
	  memcpy(f_list_aux->field,$1,strlen($1)%256+1);
	  if(!ispointer)
	    f_list_aux->data.info = $2.info;
	  else{
	    //f_list_aux->data.pointer = (char*)malloc(strlen($2.pointer));
	    f_list_aux->data.pointer = parse_expression($2.pointer);
	    //memcpy(f_list_aux->data.pointer,$2.pointer,strlen($2.pointer));
	  }
	  f_list_aux->next = NULL;
	  if(f_list == NULL){
	    f_list = f_list_aux;
	    f_list_pivot = f_list;
	  }else{
	     f_list_pivot->next = f_list_aux;
	     f_list_pivot = f_list_pivot->next;
	   }
	}
      ;

info: NUMBER {
        $$.info = $1;
	ispointer = 0;
      }
    | ADDR {
        if($1[0]<256 && $1[1]<256 && $1[2]<256 && $1[3]<256){
	  $$.info = 0;
	  $$.info |= $1[0];
	  $$.info <<=8;
	  $$.info |= $1[1];
	  $$.info <<=8;
	  $$.info |= $1[2];
	  $$.info <<=8;
	  $$.info |= $1[3];
	  ispointer = 0;
	}
      }
    | EXPR {
        $$.pointer = $1;
	ispointer = 1;
      }
    ;
%%

char *parse_expression(char *expr){
  int 	ei=0;
  int	bi=0;
  char 	*buff;
  char	*retp;

  buff = (char*)malloc(strlen(expr)+1);
  memset(buff,0,strlen(expr)+1);

  while(expr[ei] != 0){
    if(expr[ei]=='\\'){
      switch(expr[ei+1]){
        case '0':	// NUL
	  buff[bi] = 0x0;
	break;
	case 'a':	// BEL
	  buff[bi] = 0x7;
	break;
	case 'b':	// BS
	  buff[bi] = 0x8;
	break;
	case 't':	// HT
	  buff[bi] = 0x9;
	break;
	case 'n':	// LF
	  buff[bi] = 0xa;
	break;
	case 'v':	// VT
	  buff[bi] = 0xb;
	break;
	case 'f':	// FF
	  buff[bi] = 0xc;
	break;
	case 'r':	// CR
	  buff[bi] = 0xd;
	break;
	case '\\':	// /
	   buff[bi] = 0x5c;
	break;
      }
      bi++;
      ei += 2;
    }else{
      buff[bi] = expr[ei];
      ++bi;
      ++ei;
     }
  }
  buff[bi] = 0;
  retp = (char*)malloc(strlen(buff)+1);
  memcpy(retp,buff,strlen(buff)+1);
  return retp;
}

u_int32_t pack_string(pointer,finfo)
char			*pointer;
struct header_info	*finfo;
{
  u_int32_t total;
  u_int32_t data;
  u_int32_t offset = 0;
  u_int32_t size;

  total = strlen(pointer);

  while(offset != total){
    if((total-offset)<4)
      size = total-offset;
    else
      size = 4;
    memcpy(&data,pointer+offset,size);
    pack_it(the_pack_aux->data,\
            data,\
            finfo->offset+the_pack_aux->layer[layer-1]+offset*8,\
            size*8);
    offset +=size;
  }
  
  return total*8;
}

int main(int argc, char **argv){
  FILE *file;

  printf("Packet Assembler - v0.7 - Pack%sMan%s - Daniel Pupim Kano\n",D_CYAN,L_GRAY);
  printf("Supervised by PhD. Prof. Paulo Licio de Geus -- Sponsored by %sFAPESP%s\n",L_BLUE,L_GRAY);
  
  if(argc > 1){
    file = fopen(argv[1],"r");
    yyin = file;
  }else{
     printf("--No input file.--\n");
     return -1;
   }
   while(1) {
     yyparse();
   }
 
  return 0;
}

yyerror(s)
char *s;
{
  fprintf(stderr, "%d: %s at %s\n",p_lineno , s, yytext);
  exit(0);
}
