#include #include #include #include #include /* * This program takes a file containing "messages", each on a separate line * of the file, and encodes each message using the 1 June 1861 version of the * wig-wag flag signal code. It should handle the common endings and pre- * concerted codes. * * To run this program, run "encoder filename", where encoder.exe is the compiled * name of this program and filename is the name of a file containing the messages * to be encoded. * * This program was compiled with Borland Turbo C++ 4.5. * * Copyright 27 September 2000 by Lee A. Taylor */ /* * These 3 functions are available on most systems in a standard library. */ #define ISALPHA(c) (ISLOWER(c) || ISUPPER(c)) #define ISDIGIT(c) (((c) >= '0') && ((c) <= '9')) #define ISLOWER(c) (((c) >= 'a') && ((c) <= 'z')) #define ISUPPER(c) (((c) >= 'A') && ((c) <= 'Z')) #define ISPUNCT(c) (((c) == '.') || ((c) == '?') || ((c) == '!')) /* * BUFSIZE is the length of the longest message you can put on a line * in the message file. The flagman will be REALLY mad at you if you * send a message that contains 1024 characters! */ #define BUFSIZE 1024 /* * alpha is the array containing the encoding for each letter of the alphabet. * alpha[0][] is the encoding for "A", alpha[1][] is the encoding for "B", etc. */ char alpha[26][5] = { "11", "221", "1212", "122", "1", "2111", "2112", "111", "112", "1122", "2122", "211", "1111", "21", "12", "1112", "1121", "121", "22", "2", "212", "222", "1211", "2121", "1221", "1222" }; /* * numbers is the array containing the encoding for each number. numbers[i][] * is the encoding for the number i. I'm not sure numbers are handled completely * correctly, I'll think about it... */ char numbers[10][6] = { "22222", "11111", "11121", "12111", "11122", "12222", "11222", "21111", "11211", "11112" }; /* * precon1 and precon2 contains the lists of words that I look for in the text * to convert to preconcerted codes. If precon1[i][] is seen, the code for the * ith letter of the alphabet is encoded, surrounded by 3's. If precon2[i][] is * seen, the code for the ith letter of the alphabet is encoded TWICE, surrounded * by 3's. lp1 and lp2 contain the lengths of each word in the corresponding * precon list. */ char precon1[26][15] = { "ARTILLERY", "BACK", "CALVARY", "CENTER", "RETURN", "ADVANCE", "CONFEDERATE", "HALT", "INFANTRY", "CEASE FIRE", "REPEAT", "LEFT", "MINUTES", "DEPLOY", "ORDER", "LOCATION", "QUESTION", "RIGHT", "SKIRMISHERS", "EXTEND", "UNION", "FIRE", "WHERE", "SHUTTING DOWN", "READY", "IN POSITION" }; char precon2[26][15] = { "ATTACK", "BEGIN", "CONCENTRATE", "WAIT", "END", "FLANK", "SEND", "COURIER", "IDENTIFY", "RUNNER", "WORD", "LOW AMMO.", "MED. EMERG.", "MOVE", "SIGNATURE", "PREPARE", "ADDRESS", "REINFORCEMENTS", "SIGNAL", "RELAY", "WHO", "WHAT", "WHEN", "CANCEL", "YARDS", "LAST" }; int lp1[26], lp2[26]; /* * buf is an array of characters to hold an input line from the message file. */ char buf[BUFSIZE]; main (int argc, char *argv[]) { FILE *fp; /* file pointer used for reading the message file */ int i, innumber, /* state variable, 1 if we're in a number and 0 if not */ inword, /* state variable, 1 if we're in a word and 0 if not */ j, precon; /* flag indicating whether one of the preconcerted codes was found in the message */ /* * Check to see if the program is being called correctly... */ if (argc != 2) { printf ("%s: usage is %s messagefile\n", argv[0], argv[0]); exit (-1); } fp = fopen (argv[1], "r"); if (fp == (FILE *)NULL) { printf ("%s: cannot open file %s\n", argv[0], argv[1]); exit (-1); } /* * Compute the lengths of each of the strings in the preconcerted code arrays. */ for (i = 0; i < 26; i++) { lp1[i] = strlen (precon1[i]); lp2[i] = strlen (precon2[i]); } /* * Process each message in the file... */ while (fgets (buf, BUFSIZE, fp) != NULL) { innumber = 0; inword = 0; /* * First, convert all of the lower case letters to upper case. */ for (i = 0; (i < BUFSIZE) && (buf[i] != '\0'); i++) if (ISLOWER(buf[i])) buf[i] = buf[i] - 'a' + 'A'; for (i = 0; (i < BUFSIZE) && (buf[i] != '\0'); i++) { /* * There is potential for going off the end of the array in the strncmp, * but what do you expect from free software? Our processing depends on * whether not our last letters processed were in a word or not. */ if (inword) { /* * If we're in a word and we see a digit, then end the word and output the * code for the digit and set the state variable that says we're now in a * number. */ if (ISDIGIT (buf[i])) { printf ("3%sP", numbers[buf[i] - '0']); inword = 0; innumber = 1; } /* * If we're in a word and we see ING at the end of the word, output the code * for ING and skip ahead past the G */ else if ((strncmp (&(buf[i]), "ING", 3) == 0) && (!ISALPHA (buf[i+3]))) { printf ("2212P"); i += 2; } /* * If we're in a word and we see ED at the end of the word, output the code * for ED and skip ahead past the D */ else if ((strncmp (&(buf[i]), "ED", 2) == 0) && (!ISALPHA (buf[i+2]))) { printf ("2221P"); i += 1; } /* * If we're in a word and we see TION at the end of the word, output the code * for TION and skip ahead past the N */ else if ((strncmp (&(buf[i]), "TION", 4) == 0) && (!ISALPHA (buf[i+4]))) { printf ("2222P"); i += 3; } /* * If we're in a word and we see a letter, just output the code for the letter. */ else if (ISALPHA (buf[i])) printf ("%sP", alpha[buf[i] - 'A']); /* * If we see a ., ? or !, then it's the end of a sentence. Output the code * for Q if it's a ?, otherwise just end the sentence with a 33. */ else if (ISPUNCT (buf[i])) { inword = 0; if (buf[i] == '?') printf ("31121P33"); else printf ("33"); } else /* * If we got here, then there's something other than a letter, digit, common * ending or punctuation when we were in a word, so end the word with a 3 * and set the inword state variable accordingly. */ { printf ("3"); inword = 0; } } else { /* * Here's the code for when we're NOT in a word. We set inword to 1 at the * beginning to make the code a little shorter. If we see something that * indicates we're not in a word, then we'll set it back to 0 afterward. */ inword = 1; /* * If the current character is a digit and we're not in a number, output * a 3 and the code for the number, if we're in a number, then just output * the code for the number. */ if (ISDIGIT (buf[i])) { if (innumber) printf ("%sP", numbers[buf[i] - '0']); else printf ("3%sP", numbers[buf[i] - '0']); inword = 0; innumber = 1; } /* * If we see AND and we're not in a word, then output the code for AND. * As a quirk, I allow AND to appear at the BEGINNING of a word, so I * leave inword set to 1 and don't output a 3 after the code for AND. I * won't find AND and replace it with its code if it appears anywhere else. */ else if ((strncmp (&(buf[i]), "AND", 3) == 0) && (!ISALPHA (buf[i+3]))) { if (innumber) { printf ("3"); innumber = 0; } printf ("2211P"); i += 2; } else { /* * Here's the code that finds the preconcerted codes. The first loop handles * the single letter codes, the second loop handles the double letter codes. */ precon = 0; for (j = 0; j < 26; j++) if ((strncmp (&(buf[i]), precon1[j], lp1[j]) == 0) && (!ISALPHA (buf[i + lp1[j]]))) { if (innumber) { printf ("3"); innumber = 0; } printf ("%sP", alpha[j]); i += lp1[j] - 1; precon = 1; } if (!precon) for (j = 0; j < 26; j++) if ((strncmp (&(buf[i]), precon2[j], lp2[j]) == 0) && (!ISALPHA (buf[i + lp2[j]]))) { if (innumber) { printf ("3"); innumber = 0; } printf ("%sP%sP", alpha[j], alpha[j]); i += lp2[j] - 1; precon = 1; } /* * If we didn't find a preconcerted code but do see a letter, then we're * starting a new word! So output the code for the character. */ if (!precon) if (ISALPHA (buf[i])) { if (innumber) { printf ("3"); innumber = 0; } printf ("%sP", alpha[buf[i] - 'A']); } else if (innumber) { printf ("3"); innumber = 0; inword = 0; } } } } /* * This 3 makes sure the right number of 3s ends up at the end of the message. */ printf ("3\n"); } fclose (fp); }