/* Problem 3--Interpreting Control Characters
   This was tedious but not too hard.  You just maintain a grid of
   characters and make the changes according to the commands that come
   in. */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))

typedef struct LLC {
 /* ANSI C has no standard routine for reading a string of unspecified
    length, so this data structure accomplishes this. */
 char c;
 struct LLC *n;
} LLC;

FILE *in, *out;

char Grid[10][10]; /* The grid of characters */
int r, c, ins; /* The row and column of our cursor, and whether we are
                  in insert mode. */

int main (int argc, char **argv);
void Process (char *line);
void ReadString (char **A);

int main (int argc, char **argv) {

  int l,cs=0,i,j;
  char *line;

 in = fopen ("prob3.in","r");
 out = fopen ("prob3.out","w");
 while (fscanf (in,"%d",&l),l>0) { /* get number of lines in grid */
  memset (Grid,' ',sizeof Grid);
  r = c = ins = 0;
  ReadString (&line); /* kill EOLN */
  free (line);
  for (i=0;i<l;i++) {
   ReadString (&line); /* get and process each line */
   Process(line);
   free (line);
  }
  fprintf (out,"Case %d\n",++cs);
  fprintf (out,"+----------+\n");
  for (i=0;i<10;i++) {            /* print grid */
   fprintf (out,"|");
   for (j=0;j<10;j++) fprintf (out,"%c",Grid[i][j]);
   fprintf (out,"|\n");
  }
  fprintf (out,"+----------+\n");
 }
 fclose (in);
 fclose (out);
 return EXIT_SUCCESS;
}

/* Process processes a line of text and makes appropriate changes to
   the grid */
void Process (char *line) {

  int i, j, k;

 for (i=0;i<strlen(line);i++)
  if (line[i]=='^') {
   i++;
   switch (line[i]) {  /* all the different command cases here */
    case 'b' : c = 0; break;
    case 'c' : for (j=0; j < 10; j++)
               for (k=0; k < 10; k++) Grid[j][k] = ' '; break;
    case 'd' : r = MIN (r+1,9); break;
    case 'e' : for (j=c; j < 10; j++) Grid[r][j] = ' '; break;
    case 'h' : r = c = 0; break;
    case 'i' : ins = 1; break;
    case 'l' : c = MAX (c-1,0); break;
    case 'o' : ins = 0; break;
    case 'r' : c = MIN (c+1,9); break;
    case 'u' : r = MAX (r-1,0);break;
    case '^' : if (ins) for (j=9; j>c;j--) Grid[r][j]=Grid[r][j-1];
               Grid[r][c] = '^'; c = MIN (c+1,9);break;
    default : r = line[i++]-'0'; c = line[i]-'0';
   }
  } else { /* a character is added depending on the insert mode */
   if (ins) for (j=9; j>c;j--) Grid[r][j]=Grid[r][j-1];
   Grid[r][c] = line[i]; c = MIN (c+1,9);
  }
}

/* ReadString reads in a string of unspecified length into a linked
   list and then converts it to a char array. */
void ReadString (char **A) {

  int c, ct=0;
  LLC *head = NULL, *t;

 do {
  c = fgetc (in);  /* Read characters into linked list until EOLN */
  t = malloc (sizeof (LLC));
  t->n = head;
  head = t;
  t->c = c=='\n' ? 0 : c;
  ct++;
 } while (c!='\n');
 *A = malloc (ct*sizeof(char)); /* Build string from list */
 while (head != NULL) {
  (*A)[--ct] = head->c;
  t = head; head=t->n; free (t);
 }
}
