

/************************************************************************/
/*                                                                      */
/* Written by one of CMSC 443 past students                             */
/* It is intended to be a tool for present 443 students                 */
/* SSN: XXXXXXXXXXXX                                                    */
/* CMSC 443 Section 101                                                 */
/*                                                                      */
/* Goal: Develop an aid to solving simple                               */
/*       transposition cipher systems.                                  */
/* new..improved version..character counting fixed                      */
/*                                                                      */
/* compile this program using gcc, name it say, "col"                   */
/* then at the command line use                                         */
/*          col "inputfile name" "output file name"                     */
/************************************************************************/

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MSGLEN 12000

FILE *fp1,                              /* Message file pointer.        */
     *fp2;                              /* Output file pointer.         */

int message_length,                     /* Length of cipher.            */
    swaps[2][1000],                     /* List of user permutes.       */
    swap_pointer = 0,                   /* Pointer to current swap.     */
    danswer;                            /* User responses.              */

char current_message[MSGLEN], 		/* Current message array.	*/
     message[MSGLEN];                   /* Starting message array.      */

main(argc,argv)
int argc;
char *argv[];
{
   int x;                               /* Simple counter.              */

     /*     Check the number of program arguments.                      */

   if ( argc != 3 ) {
      printf("Usage: sts message_file output_file\n");
      exit(0);
   }

     /*     Open the message file.                                      */

   if ((fp1 = fopen(argv[1],"r")) == NULL ) {
      printf("Message file %s does not exist. \n",argv[1]);
      exit(2);
   }

     /*     Open the output file.                                       */

   fp2 = fopen(argv[2],"w");

     /*     Read in the message.                                        */

   message_length = Read_Message();

     /*     Print the initial main menu to the screen.                  */

   printf("\nWelcome to the Simple Transposition Solver.\n\n");
   Print_Main_Menu();
   printf("Enter a command --> ");

     /*     Interactively process user requests.                        */

   while ( scanf("%d",&danswer) > 0 ) {

     /*     If option 1, print out the cipher text from the input file. */

      if ( danswer == 1 ) {
         printf("\n   Enter a valid rectangle width --> ");
         scanf("%d",&danswer);
         if ( ( message_length % danswer ) != 0 ) {
            printf("   Using default width of 50.\n");
            danswer = 50;
         }
         Print_Cipher(message,danswer);
      }

     /*     If option 2, print out the character count of the cipher.   */

      if ( danswer == 2 ) {
         printf("\n   There are %i characters in the message.\n\n",
                message_length);
      }

     /*     If option 3, print out possible rectangle sizes.            */

      if ( danswer == 3 ) {
         Print_Rectangle_Sizes();
      }

     /*     If option 4, print out vowel counts by row.                 */

      if ( danswer == 4 ) {
         Print_Vowel_Count();
      }

     /*     If option 5, enter solving mode.                            */

      if ( danswer == 5 ) {
         printf("\n   Entering solving mode...\n");
         Solving_Mode();
      }
 
     /*     If option 6, exit the program.                              */

      if ( danswer == 6 ) {
         printf("Program exiting...\n\n");
         exit(0);
      }
      Print_Main_Menu();
      printf("Enter a command --> ");
   }
}



     /*******************************************************************/
     /*                                                                 */
     /*                     FUNCTION READ_MESSAGE                       */
     /*                                                                 */
     /*     Function READ_MESSAGE reads in the cipher from the input    */
     /*     file.                                                       */
     /*                                                                 */
     /*******************************************************************/

Read_Message()
{

  int pos=0,nch;

  while(((nch=getc(fp1))!=EOF)&&pos<MSGLEN)
    if(nch>=32&&nch<128)
      message[pos++]=nch;

  message[pos]='\0';
  return(pos);

}



     /*******************************************************************/
     /*                                                                 */
     /*                     FUNCTION PRINT_MAIN_MENU                    */
     /*                                                                 */
     /*     Function PRINT_MAIN_MENU prints the main menu options to    */
     /*     the screen.                                                 */
     /*                                                                 */
     /*******************************************************************/

Print_Main_Menu()
{
   printf("             Main Menu Options\n");
   printf("             -----------------\n");
   printf("     1) Display the cipher text.\n");
   printf("     2) Count the total number of characters.\n");
   printf("     3) Print possible rectangle sizes.\n");
   printf("     4) Print vowel count by row.\n");
   printf("     5) Enter solving mode.\n");
   printf("     6) Quit.\n\n");
   return(0);
}



     /*******************************************************************/
     /*                                                                 */
     /*                     FUNCTION PRINT_SUB_MENU                     */
     /*                                                                 */
     /*     Function PRINT_SUB_MENU print the solving mode menu to      */
     /*     the screen.                                                 */
     /*                                                                 */
     /*******************************************************************/

Print_Sub_Menu()
{
   printf("             Solving Mode Options\n");
   printf("             --------------------\n");
   printf("     1) Permute two columns of text.\n");
   printf("     2) Undo the last permutation.\n");
   printf("     3) Undo all permutations (Start over).\n");
   printf("     4) Print the current rectangle to output file.\n");
   printf("     5) Return to main menu.\n\n");
   return(0);
}



     /*******************************************************************/
     /*                                                                 */
     /*                     FUNCTION PRINT_TO_FILE                      */
     /*                                                                 */
     /*     Function PRINT_TO_FILE prints the current rectangle to      */
     /*     the output file.                                            */
     /*                                                                 */
     /*******************************************************************/

Print_To_File(width)
int width;
{
   int x;                               /* Simple counter.              */  

   fprintf(fp2,"\n   ");
   for ( x = 0; x < message_length; x++ ) {
      if ( x > 0 && ( x % width ) == 0 ) {
         fprintf(fp2,"\n   ");
      }
      fprintf(fp2,"%c",current_message[x]);
   }
   fprintf(fp2,"\n");
}



     /*******************************************************************/
     /*                                                                 */
     /*                     FUNCTION PRINT_CIPHER                       */
     /*                                                                 */
     /*     Function PRINT_CIPHER prints the cipher text to the screen. */
     /*                                                                 */
     /*******************************************************************/

Print_Cipher(msg,width)
char msg[];
int width;
{
   int x;                               /* Simple counter.              */  

   printf("\n   Cipher text on a width of %d\n\n   ",width);
   if ( width > 9 ) {
      printf("         ");
      for ( x = 10; x <= width; x++ ) {
         printf("%i",(x % 100) / 10); 
      }
      printf("\n   ");
   } 
   for ( x = 1; x <= width; x++ ) {
      printf("%d",x % 10);
   }
   printf("\n   ");
   for ( x = 1; x <= width; x++ ) {
      printf("-");
   }
   printf("\n   ");
   for ( x = 0; x < message_length; x++ ) {
      if ( x > 0 && ( x % width ) == 0 ) {
         printf("\n   ");
      }
      printf("%c",msg[x]);
   }
   printf("\n\n");
} 



     /*******************************************************************/
     /*                                                                 */
     /*                     FUNCTION SOLVING_MODE                       */
     /*                                                                 */
     /*     Function SOLVING_MODE puts the user into message solving    */
     /*     mode.                                                       */
     /*                                                                 */
     /*******************************************************************/

Solving_Mode()
{
   int columns = 0,                     /* Number of columns in rect.   */
       rows = 0,                        /* Number of rows in rectangle. */
       swap1,                           /* Column to swap.              */
       swap2,                           /* Column to swap.              */
       x;                               /* Simple counter.              */

   printf("\n   Enter a valid rectangle width -- > ");
   scanf("%d",&danswer);
   while ( ( message_length % danswer ) != 0 ) {
      printf("   Invalid rectangle width %d.\n",danswer);
      printf("\n   Enter a valid rectangle width --> ");
      scanf("%d",&danswer);
   }
   printf("\n");
   columns = danswer;
   rows = message_length / columns;

     /*     Copy the original cipher text into the current cipher 
            text array.                                                 */

   for ( x = 0; x < MSGLEN; x++ ) {
      current_message[x] = message[x];
   }

     /*     Print out the current rectangle and then the sub-menu.      */

   Print_Cipher(current_message,columns);
   Print_Sub_Menu();
   printf("Enter a command --> ");

     /*     Interactively process user requests.                        */

   while ( scanf("%d",&danswer) > 0 ) {

     /*     If option 1, permute two columns of the rectangle.          */

      if ( danswer == 1 ) {
         printf("\n   Enter one column number --> ");
         scanf("%d",&swap1);
         printf("   Enter the second column number --> ");
         scanf("%d",&swap2);
         while ( swap1 < 1 || swap1 > columns ||
                 swap2 < 1 || swap2 > columns ) {
            printf("   Invalid column number given.\n");
            printf("\n   Enter one column number --> ");
            scanf("%d",&swap1);
            printf("   Enter the second column number --> ");
            scanf("%d",&swap2);
         }
         swaps[0][swap_pointer] = swap1;
         swaps[1][swap_pointer] = swap2;
         swap_pointer++;
         Swap_Columns(swap1,swap2,rows,columns);
      }

     /*     If option 2, undo the last permutation.                     */

      if ( danswer == 2 ) {
         if ( swap_pointer > 0 ) {
            printf("\n   Undoing the previous permutation...\n\n");
            swap_pointer--;
            swap1 = swaps[0][swap_pointer];
            swap2 = swaps[1][swap_pointer];
            Swap_Columns(swap1,swap2,rows,columns);
         }
         else {
            printf("\n   No previous permutations to undo...\n\n");
         }
      }
 
     /*     If option 3, erase all previous permutations.               */

      if ( danswer == 3 ) {
         printf("\n   Erasing all previous permutations...\n\n");
         for ( x = 0; x < MSGLEN; x++ ) {
            current_message[x] = message[x];
         }
         swap_pointer = 0;
      }

     /*     If option 4, print the current rectangle to the output
            file.                                                       */

      if ( danswer == 4 ) {
         printf("\n   Printing current rectangle to output file...\n\n");
         Print_To_File(columns);
      }

     /*     If option 5, return to the main menu.                       */

      if ( danswer == 5 ) {
         printf("\n   Returning to main menu...\n\n");
         return(0);
      }
      Print_Cipher(current_message,columns);
      Print_Sub_Menu();
      printf("\nEnter a command --> ");
   }
   return(0); 
} 



     /*******************************************************************/
     /*                                                                 */
     /*                     FUNCTION SWAP_COLUMNS                       */
     /*                                                                 */
     /*     Function SWAP_COLUMNS swaps two columns of cipher.          */
     /*                                                                 */
     /*******************************************************************/

Swap_Columns(s1,s2,r,c)
int s1,
    s2,
    r,
    c;
{
   int x;
   char hold;

   for ( x = 0; x < r; x++ ) {
      hold = current_message[((x*c) + s1) - 1];
      current_message[((x*c)+s1)-1] = current_message[((x*c)+s2)-1];
      current_message[((x*c)+s2)-1] = hold;
   }
   return(0);
}



     /*******************************************************************/
     /*                                                                 */
     /*                   FUNCTION PRINT_VOWEL_COUNT                    */
     /*                                                                 */
     /*     Function PRINT_VOWEL_COUNT prints the vowel count by rows.  */
     /*                                                                 */
     /*******************************************************************/

Print_Vowel_Count()
{
   int row_count = 1,                   /* Counts current message row.  */
       vowel_count = 0,                 /* Total number of vowels.      */
       x;                               /* Simple counter.              */

   printf("\n   Enter a valid rectangle width --> ");
   scanf("%d",&danswer);
   if ( ( message_length % danswer ) != 0 ) {
      printf("   Invalid rectangle width %d.\n",danswer);
      printf("   Returning to main menu...\n\n");
   }
   printf("\n");
   for ( x = 0; x < message_length; x++ ) {
      if ( x > 0 && ( x % danswer ) == 0 ) {
         printf("   Row number %d - %d vowels.\n",row_count,
                vowel_count);
         row_count++;
         vowel_count = 0;
      }
      if ( message[x] == 'a' || message[x] == 'e' ||
           message[x] == 'i' || message[x] == 'o' ||
           message[x] == 'u' ||
           message[x] == 'A' || message[x] == 'E' ||
           message[x] == 'I' || message[x] == 'O' ||
           message[x] == 'U' ) vowel_count++;
   }
   printf("   Row number %d - %d vowels.\n",row_count, vowel_count);
   row_count = 1;
   vowel_count == 0;
   printf("\n\n");
   return(0);
}



     /*******************************************************************/
     /*                                                                 */
     /*                   FUNCTION PRINT_RECTANGLE_SIZES                */
     /*                                                                 */
     /*     Function PRINT_RECTANGLE_SIZES prints out possible          */
     /*     rectangle sizes.                                            */
     /*                                                                 */
     /*******************************************************************/

Print_Rectangle_Sizes()
{
   int size_count = 0,                  /* Count of valid sizes.        */
       x;                               /* Simple counter.              */

   printf("\n   Possible rectangle sizes are...\n");
   printf("     ");
   for ( x = 1; x <= message_length; x++ ) {
      if ( ( message_length % x ) == 0 ) {
         size_count++;
         printf("%d X %d   ",x,message_length / x);
         if ( size_count == 5 ) {
            printf("\n     ");
            size_count = 0;
         }
      }
   }
   printf("\n\n");
}



