/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
 * files.C -
 *    demostrate files operations:
 *          fopen, fclose, fseek, ftell, fgets, fprintf  
 *       fflush.
\*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>

/*--- Constants ---*/
#define  LINE_SIZE  1000

/*--- Start of Code ---*/
static void create_file(char * file_name)
{
  FILE * fl;
  int i;

  /* fopen( char * filename, char * mode ):
   * mode: 
   *   r         open for reading
   *   w         truncate or create for writing
   *   a         append: open for writing at end of  file,  or
   *             create for writing
   *   r+        open for update (reading and writing)
   *   w+        truncate or create for update
   \*   a+        append; open or create for update at EOF */
  fl = fopen(file_name, "w");
  assert(fl != NULL);

  for (i = 0; i < 10; i++) {
    fprintf(fl, "%5d\n", 100 * i * i);
  }
  fclose(fl);
}
    
static void print_file(char * file_name)
{
  FILE * fl;
  char line[ LINE_SIZE ], * str;

  fl = fopen(file_name, "rt");
  if (fl == NULL) {  
    fprintf(stderr, "Unable to open file: %s\n", file_name);
    exit(-1);
  }

  while (!feof(fl)) {
    str = fgets(line, 80, fl);
    if (str == NULL)
      break;
    printf("%s", str);
  }
     
  fclose(fl);
}

static int search_in_file(FILE * fl, int num, int left, int right)
{
  int  mid, num_in_file, chars_read;
  char line[LINE_SIZE], * str;

  if (left > right)
    return  -1;

  mid = (left + right) / 2;
    
  /* fseek - The new position is at the signed
   *    distance offset bytes from the beginning, 
   *    the current position, or the end of the
   *    file, according as ptrname has the
   \*    value 0, 1, or 2. */
  assert(fseek(fl, mid * 6, SEEK_SET) >= 0);
    
  str = fgets(line, LINE_SIZE, fl);
  assert(str != NULL);

  chars_read = sscanf(str, "%d", &num_in_file);
  assert(chars_read > 0);
    
  if (num_in_file == num)
    return  mid;

  if (num_in_file < num)
    return search_in_file(fl, num, mid+1, right);
  else
    return search_in_file(fl, num, left, mid - 1);
}

static void replace_in_file(char * file_name, int from, int to)
{
  long size, new_pos;
  int pos;
  FILE  * fl;

  fl = fopen(file_name, "r+");
  if (fl == NULL) {
    fprintf(stderr, "Unable to open file: %s\n", file_name);
    exit(-1);
  }

  assert(fseek(fl, 0, SEEK_END) >= 0);
  size = ftell(fl);
  assert(size >= 0);

  pos = search_in_file(fl, from, 0, (int)((size - 1)/6));
  if (pos < 0) {
    printf("Unable to find number: %d\n", from);
    exit(-1);
  }
  new_pos = ftell(fl) - 6;
  assert(fseek(fl, new_pos, SEEK_SET) >= 0);

  fprintf(fl, "%5d\n", to);
  fflush(fl);

  fclose(fl);    
}

int main(int argc, char * argv[])
{
  if (argc <= 1) {
    printf("files [command] file-name\n");
    printf("\tcreate\t Create and fill file with random numbers\n");
    printf("\tprint \t Print the file\n");
    printf("\tsr    \t Search and replace a number\n");
    return 0;
  }
  
  if (strcmp(argv[1], "create") == 0) {
    assert(argc == 3);
    create_file(argv[2]);
    return 0;
  }
  if (strcmp(argv[1], "print") == 0) {
    assert(argc == 3);
    print_file(argv[2]);
    return 0;
  }
  if (strcmp(argv[1], "sr") == 0) {
    assert(argc == 5);
    replace_in_file(argv[2], atoi(argv[3]), atoi(argv[4]));
    return 0;
  }

  printf("Unknown command: [%s]\n", argv[1]);

   return  0;
}
