/*************************************************************************/
/*PRIYA RAMAKRISHNAN                                                     */
/*                                                                       */
/*Columnar Transposition Cipher Decryption Tool                          */
/*                                                                       */
/*-----------------------------------------------------------------------*/
/* To compile: cc col.c -o col                                           */
/* To execute: col inputFileName outputFileName                          */
/*-----------------------------------------------------------------------*/
/* This program is an tool that can be used to decrypt plaintext that    */
/* has been encrypted with a columnar transposition cipher system.       */
/*-----------------------------------------------------------------------*/
/* Made the following improvements to this tool. Added options to:       */
/* 1) read data into a specified rectangle by columns                    */
/* 2) permute rows of data                                               */
/* 3) read data out of a rectangle to a file by columns                  */
/* 4) provided vowel count by columns                                    */
/* 5) made other modifactions in "style": removed several global vars,   */
/*      and provided function declarations.                              */
/*************************************************************************/
/*                                                                       */
/* Feb 17, 2001 - Jeff Walton (J. W.)                                    */
/*     1) Added Transposition functions                                  */
/*                                                                       */
/*                    Clockwise      Counter Clockwise                   */
/*                       FA                 EJ                           */
/*     ABCDE             GB                 DI                           */
/*     FGHIJ       ==>   HC                 CH                           */
/*                       ID                 BG                           */
/*                       JE                 AF                           */
/*                                                                       */
/*     2) Added check on size of MSGLEN #define and file size            */
/*                                                                       */
/*     3) Added check on output file creation                            */
/*                                                                       */
/*     4) Added check on submenu scanf - 0 would cause division by 0     */
/*                                                                       */
/*************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MSGLEN 500

int Read_Message();
void Print_Main_Menu();
void Print_Sub_Menu(char);
void Print_To_File_Rows(int);
void Print_To_File_Columns(int);
void Print_Cipher_by_Rows(char[],int);
void Print_Cipher_by_Column(char[],int);
void Solving_Mode_Rows();
void Solving_Mode_Columns();
void Transpose_Clockwise(int*, int*);          /* Added by J. W. 2-17-2001 */
void Transpose_Counter_Clockwise(int*, int*);  /* Added by J. W. 2-17-2001 */
void Swap(int,int,int,int);
void Print_Vowel_Count(char);
void Print_Rectangle_Sizes();



FILE *fp1;                              /* Message file pointer.        */
FILE *fp2;                              /* Output file pointer.         */

int message_length;                     /* Length of cipher.            */

char current_message[MSGLEN];           /* Current message array.       */
char message[MSGLEN];                   /* Starting message array.      */

void main(int argc, char* argv[]) {
int danswer,input;
fpos_t pos;                                 /* Added by J. W. 2-17-2001 */

    /* Check the number of program arguments.                           */
    if ( argc != 3 ) {
        fprintf(stderr, "Usage: %s message_file output_file\n", argv[0]);
        exit(0);
    }
  
    /* Open the message file.                                           */
    if ((fp1 = fopen(argv[1],"r")) == NULL ) {
        fprintf(stderr, "Message file %s does not exist.\n",argv[1]);
        exit(2);
    }

    /* Sanity check added by J. W. 2-17-2001                            
    fseek(fp1, 0L, SEEK_END);
    fgetpos(fp1, &pos);
    if(MSGLEN < pos) {
        fprintf(stderr, "Message file is too long.\n");
        fprintf(stderr, "Increase value of MSGLEN and recompile.\n");
        fprintf(stderr, "MSGLEN is %d.\n", MSGLEN);
        fprintf(stderr, "File size is %ld.\n", (long)pos);
        exit(2);
    }
    fseek(fp1, 0L, SEEK_SET);     */
    /* End Sanity check hack --eliminated 2/16/05 stephens           */

    /* Open the output file.                                            */
    fp2 = fopen(argv[2],"w");
    /* Sanity check on fp2 added by J. W. 2-17-2001                     */
    if(NULL == fp2) {
        fprintf(stderr, "Unable to open output file %s\n", argv[2]);
        fclose(fp1);
        exit(2);
    }
    /* End Sanity check hack                                            */

    /* 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 by rows.               */
        if ( danswer == 1 ) {
            printf("\n   Enter a valid rectangle width --> ");
            scanf("%d",&input);
            if ( ( message_length % input ) != 0 ) {
                printf("   Using default width of 50.\n");
                input = 50;
            }
            Print_Cipher_by_Rows(message,input);
        }

        /* If option 2, print out the cipher text by columns.           */
        if(danswer == 2){
            printf("\n Enter a valid rectangle height --> ");
            scanf("%d",&input);
            if( (message_length%input ) != 0) {
                printf("   Using default height of 50.\n");
                input = 50;
            }
            Print_Cipher_by_Column(message,input);
        }    

        /* If option 3, print out the character count of the cipher.    */
        if ( danswer == 3 ) {
            printf("\n   There are %i characters in the message.\n\n", message_length);
        }

        /* If option 4, print out possible rectangle sizes.             */
        if ( danswer == 4 ) {
            Print_Rectangle_Sizes();
        }

        /* If option 5, print out vowel counts by row.                  */
        if ( danswer == 5 ) {
            Print_Vowel_Count('R');
        }

        /*If option 6, print vowel counts by column.                    */
        if (danswer == 6) {
            Print_Vowel_Count('C');
        }            

        /*If option 7, enter solving mode for rows.                     */
        if ( danswer == 7 ) {
            printf("\n   Entering solving mode...\n");
            Solving_Mode_Rows();
        }

        /*If option 8, enter solving mode for columns                   */
        if ( danswer == 8 ) {
            printf("\n   Entering solving mode...\n");
            Solving_Mode_Columns();
        }

        /*If option 9, exit the program.                                */
        if ( danswer == 9 ) {
            printf("Program exiting...\n\n");
            exit(0);
        }

        Print_Main_Menu();
        printf("Enter a command --> ");
    } /* End While */

    /* Added by J. W. 2-17-2001 */
    /* VC++ buffers and does not write the file */
    fclose(fp1);
    fclose(fp2);
}



/*********************************************************************/
/*                                                                   */
/*                       FUNCTION READ_MESSAGE                       */
/*                                                                   */
/*       Function READ_MESSAGE reads in the cipher from the input    */
/*       file.                                                       */
/*                                                                   */
/*********************************************************************/
int Read_Message() {
int pos=0,nch=0;

    while(((nch=getc(fp1))!=EOF)&&pos<MSGLEN) {
        if(nch>=32&&nch<128) {
            message[pos++]=(char)nch;
        }
    }
    message[pos]='\0';
    return(pos);
}

/*********************************************************************/
/*                                                                   */
/*                       FUNCTION PRINT_MAIN_MENU                    */
/*                                                                   */
/*       Function PRINT_MAIN_MENU prints the main menu options to    */
/*       the screen.                                                 */
/*                                                                   */
/*********************************************************************/
void Print_Main_Menu() {

    printf("             Main Menu Options\n");
    printf("             -----------------\n");
    printf("     1) Display the cipher text by rows.\n");
    printf("     2) Display the cipher text by columns.\n");
    printf("     3) Count the total number of characters.\n");
    printf("     4) Print possible rectangle sizes.\n");
    printf("     5) Print vowel count by row.\n");
    printf("     6) Print vowel count by column.\n"); 
    printf("     7) Enter solving mode-Rows.\n");
    printf("     8) Enter solving mode-Columns.\n");
    printf("     9) Quit.\n\n");
}

/*********************************************************************/
/*                                                                   */
/*                       FUNCTION PRINT_SUB_MENU                     */
/*                                                                   */
/*       Function PRINT_SUB_MENU print the solving mode menu to      */
/*       the screen.                                                 */
/*                                                                   */
/*********************************************************************/
void Print_Sub_Menu(char mode) {
    printf("             Solving Mode Options\n");
    printf("             --------------------\n");
    if(mode == 'R') {
        printf("     1) Permute two columns of text.\n");
    } else {
        printf("     1) Permute two rows 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");
    /* 5 and 6 added by J. W. 2-17-2001 */
    printf("     5) Transpose Rectange Clockwise.\n");
    printf("     6) Transpose Rectange Counter Clockwise.\n");
    /* 5 renamed to 7 by J. W. 2-17-2001 */
    printf("     7) Return to main menu.\n\n");
}

/*********************************************************************/
/*                                                                   */
/*                   FUNCTION PRINT_TO_FILE_ROWS                     */
/*                                                                   */
/*       Function PRINT_TO_FILE prints the current rectangle to      */
/*       the output file by rows.                                    */
/*                                                                   */
/*********************************************************************/
void Print_To_File_Rows(int width) {
int x;                
   
    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");

    /* Added by J. W. 2-17-2001 */
    fflush(fp2);
}

/*********************************************************************/
/*                                                                   */
/*                   FUNCTION PRINT_TO_FILE_COLUMNS                  */
/*                                                                   */
/*       Function PRINT_TO_FILE_COLUMNS prints the current           */
/*       rectangle to the output file by columns.                    */
/*                                                                   */
/*********************************************************************/
void Print_To_File_Columns(int height) {
int i,j,cnt;            
int width;
char temp[MSGLEN][MSGLEN];

    if(message_length%height == 0) {
        width=message_length/height;
    } else {
        width = message_length/height + 1;
    }
  
    /* Store in temp array by height and print out by width */
    cnt=0;
    for( i = 0; i<width; i++) {
        for(j=0; j<height; j++) {
            if(cnt < message_length) {
                temp[i][j]=current_message[cnt];
                cnt++;
            } else {
                break;
            }
        }
        if(cnt>message_length) { break; }
    }
 
    fprintf(fp2,"\n   ");
    for(i=0; i<height; i++) { 
        fprintf(fp2,"\n   ");
        for(j=0; j<width; j++) {
            fprintf(fp2,"%c",temp[j][i]);
        }
    }

    /* Added by J. W. 2-17-2001 */
    fflush(fp2);

    printf("\n\n");
}

/*********************************************************************/
/*                                                                   */
/*                    FUNCTION PRINT_CIPHER_BY_ROWS                  */
/*                                                                   */
/* Function PRINT_CIPHER_BY_ROWS prints the cipher text to the       */
/*screen by Rows.                                                    */
/*                                                                   */
/*********************************************************************/
void Print_Cipher_by_Rows(char msg[],int width) {
int x;                
  
    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 PRINT_CIPHER_BY_COLUMN                */
/*                                                                   */
/* Function PRINT_CIPHER_BY_COLUMN prints the cipher text to the     */
/* screen by Columns.                                                */
/*                                                                   */
/*********************************************************************/
void Print_Cipher_by_Column(char msg[],int height) {
int i,j,cnt;            
int width;
char temp[MSGLEN][MSGLEN];
  
    printf("\n   Cipher text on a height of %d\n\n   ",height);
    printf("\n");
  
    if(message_length%height == 0) {
        width=message_length/height;
    } else {
        width = message_length/height + 1;
    }

    /*Store in temp array by height and print out by width*/
    cnt=0;
    for( i = 0; i<width; i++) {
        for(j=0; j<height; j++) {
            if(cnt < message_length) {
                temp[i][j]=msg[cnt];
                cnt++;
            } else {
                break;
            }
        }
        if(cnt>message_length) { break; }
    }

    cnt=1;
    for(i=0; i<height; i++) {
        printf("\n%2d|", cnt);
        for(j=0; j<width; j++) {
            printf("%c", temp[j][i]);
        }
        cnt++;
    }
    printf("\n\n");
} 

/*********************************************************************/
/*                                                                   */
/*                   FUNCTION SOLVING_MODE_ROWS                      */
/*                                                                   */
/*       Function SOLVING_MODE_ROWS puts the user into message       */
/*       solving mode - Ciphertext Displayed by Rows.                */
/*                                                                   */
/*********************************************************************/
void Solving_Mode_Rows() {
int columns = 0,                        /* Number of columns in rect.   */
    rows = 0,                           /* Number of rows in rectangle. */
    swap1 = 0,                          /* Column to swap.              */
    swap2 = 0,                          /* Column to swap.              */
    x = 0;                              /* Simple counter.              */
int danswer;
  
int swaps[2][1000];                     /* List of user permutes.       */
int swap_pointer = 0;                   /* Pointer to current swap.     */

  
    printf("\n   Enter a valid rectangle width -- > ");
    scanf("%d",&danswer);

    /* Sanity cheack added by J. W. 2-17-2001 */
    if(danswer < 1) { return; }
    /* End Sanity check hack                 */

    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_by_Rows(current_message,columns);
    Print_Sub_Menu('R');
    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(swap1,swap2,rows,columns);
        } /* End If 1 */
    
        /* 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(swap1,swap2,rows,columns);
            } else {
                printf("\n   No previous permutations to undo...\n\n");
            }
        } /* End If 2 */
      
        /* 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;
        } /* End If 3 */
      
        /* 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_Rows(columns);
        } /* End If 4 */

        /* Added by J. W. 2-17-2001                                     */
        /* If option 5, rotate clockwise                                */
        if ( danswer == 5 ) {
            printf("\n   Transposing rectangle clockwise...\n");
            Transpose_Clockwise(&rows, &columns);
            /* Undo Not available */
            /* To Do:  clean up the lack of undo */
            swap_pointer = 0;
        } /* End If 5 */

        /* Added by J. W. 2-17-2001                                     */
        /* If option 6, rotate counter clockwise                        */
        if ( danswer == 6 ) {
            printf("\n   Transposing rectangle counter clockwise...\n");
            Transpose_Counter_Clockwise(&rows, &columns);
            /* Undo Not available */
            /* To Do:  clean up the lack of undo */
            swap_pointer = 0;
        } /* End If 6 */

        /* If option 7, return to the main menu.                        */
        if ( danswer == 7 ) {
            printf("\n   Returning to main menu...\n\n");
            return;
        } /* End If 7 */

        Print_Cipher_by_Rows(current_message,columns);
        Print_Sub_Menu('R');
        printf("\nEnter a command --> ");
    } /* End While */
} 

/*********************************************************************/
/*                                                                   */
/*                     FUNCTION SOLVING_MODE_COLUMNS                 */
/*                                                                   */
/*       Function SOLVING_MODE_COLUMNS puts the user into message    */
/*        solving mode -Ciphertext displayed as Columns              */
/*                                                                   */
/*********************************************************************/
void Solving_Mode_Columns() {
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.              */
int danswer;

int swaps[2][1000];                     /* List of user permutes.       */
int swap_pointer = 0;                   /* Pointer to current swap.     */
  
    printf("\n   Enter a valid rectangle height -- > ");
    scanf("%d",&danswer);

    /* Sanity cheack added by J. W. 2-17-2001   */
    if(danswer < 1) { return; }
    /* End Sanity check hack                    */

    while ( ( message_length % danswer ) != 0 ) {
        printf("   Invalid rectangle height %d.\n",danswer);
        printf("\n   Enter a valid rectangle height --> ");
        scanf("%d",&danswer);
    }
    printf("\n");
    rows = danswer;
    columns = message_length / rows;
  
    /* 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_by_Column(current_message,rows);
    Print_Sub_Menu('C');
    printf("Enter a command --> ");

    /* Interactively process user requests.                         */
    while ( scanf("%d",&danswer) > 0 ) {

        /* If option 1, permute two rows of the rectangle.          */
        if ( danswer == 1 ) {
            printf("\n   Enter one row number --> ");
            scanf("%d",&swap1);
            printf("   Enter the second row number --> ");
            scanf("%d",&swap2);
            while ( swap1 < 1 || swap1 > rows ||
                swap2 < 1 || swap2 > rows ) {
                printf("   Invalid row number given.\n");
                printf("\n   Enter one row number --> ");
                scanf("%d",&swap1);
                printf("   Enter the second row number --> ");
                scanf("%d",&swap2);
            } /* End While */
            swaps[0][swap_pointer] = swap1;
            swaps[1][swap_pointer] = swap2;
            swap_pointer++;
            Swap(swap1,swap2,columns,rows);
        } /* End If 1 */

        /* 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(swap1,swap2,columns,rows);
            } else {
                printf("\n   No previous permutations to undo...\n\n");
            }
        } /* End If 2 */

        /* 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;
        } /* End If 3 */
      
        /* 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(rows);
        } /* End If 4 */


        /* Added by J. W. 2-17-2001                                     */
        /* If option 5, rotate clockwise                                */
        if ( danswer == 5 ) {
            printf("\n   Transpose rectangle not implemented\n");
            printf("\n   in Column Solving mode due to internal\n");
            printf("\n   data structure limitations.\n");
        } /* End If 5 */

        /* Added by J. W. 2-17-2001                                     */
        /* If option 6, rotate counter clockwise                        */
        if ( danswer == 6 ) {
            printf("\n   Transpose rectangle not implemented\n");
            printf("\n   in Column Solving mode due to internal\n");
            printf("\n   data structure limitations.\n");
        } /* End If 6 */
              
        /* If option 7, return to the main menu.                        */
        if ( danswer == 7 ) {
            printf("\n   Returning to main menu...\n\n");
            return;
        } /* End If 7 */

        Print_Cipher_by_Column(current_message,rows);
        Print_Sub_Menu('C');
        printf("\nEnter a command --> ");
    } /* End While */
} 

/*********************************************************************/
/*                                                                   */
/*                       FUNCTION SWAP                               */
/*                                                                   */
/*       Function SWAP swaps two columns or rows of cipher.          */
/*                                                                   */
/*********************************************************************/
void Swap(int s1,int s2,int r,int 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;
    }
}

/*********************************************************************/
/*                                                                   */
/*                     FUNCTION PRINT_VOWEL_COUNT                    */
/*                                                                   */
/*       Function PRINT_VOWEL_COUNT prints the vowel count by rows   */
/*                 or columns.                                       */
/*********************************************************************/
void Print_Vowel_Count(char mode) {
int row_col_count = 1,              /* Counts current message row/col.*/
    vowel_count = 0,                /* Total number of vowels.        */
    x;                              /* Simple counter.                */
int danswer;
  
    if(mode == 'R') {
        printf("\n   Enter a valid rectangle width --> ");
    } else {
        printf("\n   Enter a valid rectangle height --> "); 
    }

    scanf("%d",&danswer);
    if ( ( message_length % danswer ) != 0 ) {
        if(mode == 'R') {
            printf("   Invalid rectangle width %d.\n",danswer);
        } else {
            printf("   Invalid rectangle height %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 ) {
            if(mode == 'R') {
                printf("   Row number %d - %d vowels.\n",row_col_count,vowel_count);
            } else {
                printf("   Column number %d - %d vowels.\n",row_col_count, vowel_count);
            }
            row_col_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++; }
    } /* End For */

    if(mode == 'R') {
        printf("   Row number %d - %d vowels.\n",row_col_count, vowel_count);
    } else {
        printf("   Column number %d - %d vowels.\n",row_col_count, vowel_count);
    }

    row_col_count = 1;
    vowel_count = 0;
    danswer = 0;
    printf("\n\n");
}

/*********************************************************************/
/*                                                                   */
/*                     FUNCTION PRINT_RECTANGLE_SIZES                */
/*                                                                   */
/*       Function PRINT_RECTANGLE_SIZES prints out possible          */
/*       rectangle sizes.                                            */
/*                                                                   */
/*********************************************************************/
void Print_Rectangle_Sizes() {
int size_count = 0;                /* Count of valid sizes.        */
int x = 0;

    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");
}

/*********************************************************************/
/*                                                                   */
/*                     FUNCTION TRANSPOSE_CLOCKWISE                  */
/*                                                                   */
/*       Function TRANSPOSE_CLOCKWISE logically rotates the          */
/*       rectangle.  It is destructive on global current_message.    */
/*                                                                   */
/*       Added by J. W. 2-17-2001                                    */
/*                                                                   */
/*       Note: This could have been written much more tersely.       */
/*             Verbosity was used for future maintenance.            */
/*                                                                   */
/*********************************************************************/
void Transpose_Clockwise(int* rows, int* columns) {
int  cr = 0;    /* current row in current_message[]      */
int  cc = 0;    /* current column in current_message[]   */
int  nr = 0;    /* new row in temp[]                     */
int  nc = 0;    /* new column in temp[]                  */
int  cl = 0;    /* current linear into current_message[] */
int  nl = 0;    /* new linear into temp[]                */
char temp[MSGLEN];
char c = 0;

    /* zero temporary array */
    memset(temp, 0, MSGLEN * sizeof(char));

    for(cr=0; cr<*rows; cr++) {
        for(cc=0; cc<*columns; cc++) {

            /* current linear */
            cl = cr * (*columns) + cc;
            /* current character */
            c = current_message[cl];

            /* logically swaping a row for a column */
            nr = cc;
            /* logically swaping a column for a row */
            nc = (*rows) - cr;
            /* calculate new linear */
            nl = nr * (*rows) + nc - 1;
            /* write it */
            temp[nl] = c;
        }
    }

    /* save off our results */
    memcpy(current_message, temp, MSGLEN * sizeof(char));

    /* swap rows and columns */
    /* in calling function   */
    nr = *columns;
    nc = *rows;
    *columns = nc;
    *rows = nr;

}

/*********************************************************************/
/*                                                                   */
/*              FUNCTION TRANSPOSE_COUNTER_CLOCKWISE                 */
/*                                                                   */
/*       Function TRANSPOSE_COUNTER_CLOCKWISE logically rotates the  */
/*       rectangle.  It is destructive on global current_message.    */
/*                                                                   */
/*       Added by J. W. 2-17-2001                                    */
/*                                                                   */
/*********************************************************************/
void Transpose_Counter_Clockwise(int* rows, int* columns) {

    /* Three clockwise is a counter clockwise */
    /* I am that lazy                         */
    Transpose_Clockwise(rows, columns);
    Transpose_Clockwise(rows, columns);
    Transpose_Clockwise(rows, columns);
    
}

