                          /* usage.c, 12 May 10 */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "global.h"
#include "isprop.h"
#include "utils.h"
#include "fltval.h"
#include "singlefile.h"
#include "chkfiles.h"
#include "usage.h"


#define MAX_NUM_EXT 500 // Am approximation to infinity
#define MAX_EXT_LEN 5   // Maximum characters considered in a file extension
#define NO_EXT 0
#define MAX_OTHER_TOKS 200
#define MIN_LOG_VAL 340
#define NUM_LOG_VALS (2*MIN_LOG_VAL)

/*
 * Assign a file extension number for every extension.
 * Used to count number of filenames containing a given extension.
 */
struct f_ext_rec {
		  int ext_num;
		  char ext[1+MAX_EXT_LEN];
		  struct f_ext_rec *next;
		 };


BOOL do_usage_value,
     do_usage_file;
int total_dir_seen;


static int total_lits;
static int file_ext_cnt;
static int total_mantissa_len[MAX_NUM_DIGITS];
static int total_signif_len[MAX_NUM_DIGITS],
           data_signif_len[MAX_NUM_DIGITS];
static struct f_ext_rec *f_ext_list[MAX_EXT_LEN];

static int total_file_ext[2][MAX_NUM_EXT];
static int total_num_tok_sep[MAX_OTHER_TOKS+1];
static int total_val_cnt[NUM_LOG_VALS];


void cnt_val_usage(DIGIT_CHAR * mantissa,
	       int len_mantissa,
	       DIGIT_CHAR * exponent)
{
// Save information about a literal value seen in the source
int num_signif_digits;
int dig_num;
int log_val;

if (len_mantissa < MAX_NUM_DIGITS)
   total_mantissa_len[len_mantissa]++;

// Count the number of significant digits
num_signif_digits=0;

for (dig_num=0; dig_num < len_mantissa; dig_num++)
   if ((!is_dec_point(mantissa[dig_num])) &&
       // don't count leading zeroes
       !((num_signif_digits == 0) && is_zero(mantissa[dig_num])))
      num_signif_digits++;

// not interested in trailing zeros
for (dig_num=len_mantissa; dig_num > 0; dig_num--)
   if (is_zero(mantissa[dig_num-1]))
      num_signif_digits--;
   else
      break;

if ((last_tok == ',') || (other_toks == 0) ||
    ((other_toks == 2) && (last_last_tok = ',')))
   data_signif_len[num_signif_digits]++;
else
   total_signif_len[num_signif_digits]++;
last_tok=' ';

if (other_toks < MAX_OTHER_TOKS)
   total_num_tok_sep[other_toks]++;
else
   total_num_tok_sep[MAX_OTHER_TOKS]++;
other_toks=0;
total_lits++;

log_val=log10(fp_to_double(cur_fp_val))/log10(2.0);
if (fabs(log_val) < MIN_LOG_VAL)
   total_val_cnt[log_val+MIN_LOG_VAL]++;
}


void print_val_usage(void)
{
int mlen;

printf(".File: signif_digits\n");
printf("     Characters        ( expression    initialization) significant digits\n");
for (mlen=0; mlen < MAX_NUM_DIGITS; mlen++)
   printf("%2d   %7d  %5.2f   %7d  %5.2f  %7d  %5.2f\n", mlen,
		 total_mantissa_len[mlen], (100.0*total_mantissa_len[mlen])/total_lits,
		 total_signif_len[mlen], (100.0*total_signif_len[mlen])/total_lits,
		 data_signif_len[mlen], (100.0*data_signif_len[mlen])/total_lits);

printf(".File: token_distance\n");
printf("Token distance between literals\n");

for (mlen=0; mlen <= MAX_OTHER_TOKS; mlen++)
   printf("%3d   %7d  %5.2f\n", mlen, total_num_tok_sep[mlen],
                        ((total_num_tok_sep[mlen]+0.0)/total_lits)*100.0);

printf(".File: values in range\n");
for (mlen=0; mlen < NUM_LOG_VALS; mlen++)
   printf("%4d  %7d  %5.2f\n", mlen-MIN_LOG_VAL, total_val_cnt[mlen],
				(100.0*total_val_cnt[mlen])/total_lits);
}


static unsigned int file_ext_num(char *filename)
{
/*
 * Return the number associated with any extension filename has,
 * if no extension return NO_EXT.  An extension is any sequence
 * of characters appearing after a '.' in filename.
 */
size_t file_len = strlen(filename),
       ch_offset = file_len;
int ext_len;
struct f_ext_rec *known_ext_ptr;

while (ch_offset > 0)
   {
   if (filename[ch_offset] == '.')
      {
      ext_len=file_len-ch_offset;
      if ((ext_len > MAX_EXT_LEN) ||
	  (ext_len == 0))
	 return NO_EXT; 
      known_ext_ptr=f_ext_list[ext_len-1];
      while (known_ext_ptr)
	 {
	 if (strcmp(filename+ch_offset+1, known_ext_ptr->ext) == 0)
	    return known_ext_ptr->ext_num;
	 known_ext_ptr=known_ext_ptr->next;
	 }
 // Extension not found, add it
      file_ext_cnt++;
      if (file_ext_cnt >= MAX_NUM_EXT)
	 return NO_EXT;
      known_ext_ptr=get_heap(sizeof(struct f_ext_rec));
      if (known_ext_ptr == NULL)
	 return NO_EXT;
      strcpy(known_ext_ptr->ext, filename+ch_offset+1);
      known_ext_ptr->ext[ext_len]=NULL_CHAR;
      known_ext_ptr->ext_num=file_ext_cnt;
      known_ext_ptr->next=f_ext_list[ext_len-1];
      f_ext_list[ext_len-1]=known_ext_ptr;
      return file_ext_cnt;
      }
   ch_offset--;
   }
return NO_EXT;
}


void cnt_file_not_processed(char *filename)
{
total_file_ext[0][file_ext_num(filename)]++;
}


void cnt_file_processed(char *filename)
{
total_file_ext[1][file_ext_num(filename)]++;
}


static void print_file_usage(void)
{
int elen;
struct f_ext_rec *known_ext_ptr;

printf("File information: %d directories\n", total_dir_seen);

for (elen=0; elen < MAX_EXT_LEN; elen++)
   {
   known_ext_ptr=f_ext_list[elen];
   while (known_ext_ptr)
      {
      printf("%7d  %7d  %5s\n", total_file_ext[0][known_ext_ptr->ext_num],
				total_file_ext[1][known_ext_ptr->ext_num],
							known_ext_ptr->ext);
      known_ext_ptr=known_ext_ptr->next;
      }
   }
}


void print_usage(void)
{
if (do_usage_file)
   print_file_usage();
if (do_usage_value)
   print_val_usage();
}

