Advertisement
Evyatar12

very modular.c

Nov 16th, 2018
141
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 12.90 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. // the amount of characters that define ONE utf16 char
  5. #define UTF16_CHARS 2
  6.  
  7. // the maximal amount of utf16 characters used to describe a newline
  8. #define MAX_NEWLINE_CHARS 2
  9.  
  10. typedef char bool;
  11. #define true 1
  12. #define false 0
  13.  
  14. // a struct that represents a UTF16 character
  15. typedef struct {
  16.     char chars[UTF16_CHARS];
  17. } UTF16Char;
  18.  
  19. /* little endian representation(the exercise source files are only in little endian) */
  20. #define NEWLINE { 0x0a, 0 }
  21. #define CARRIAGE_RETURN { 0x0d, 0 }
  22.  
  23. // a struct that defines the newline format for each operating system
  24. typedef struct {
  25.     // the amount of utf16 characters that define the newline
  26.     int newlineCharsCount;
  27.     // the actual characters
  28.     UTF16Char newlineChars[MAX_NEWLINE_CHARS];
  29.  
  30.     // the name of the operating system(as command line arguments)
  31.     const char* flag;
  32. } OSFormat;
  33.  
  34. typedef struct {
  35.     // the maximum capacity of this queue
  36.     int capacity;
  37.  
  38.     // the amount of characters inside
  39.     int count;
  40.  
  41.     UTF16Char chars[MAX_NEWLINE_CHARS];
  42. } UTF16Queue;
  43.  
  44. // define os newline format
  45. const OSFormat unixOS = { 1, { NEWLINE }, "-unix" };
  46. const OSFormat macOS = { 1, { CARRIAGE_RETURN }, "-mac" };
  47. const OSFormat windowsOS = { 2, { CARRIAGE_RETURN, NEWLINE }, "-win" };
  48.  
  49. #define OS_COUNT 3
  50. // list of operating systems format
  51. const OSFormat* operatingSystems[] = {
  52.     &unixOS, &macOS, &windowsOS
  53. };
  54.  
  55. /*
  56.  * function name: SwapInnerOrder
  57.  * input:
  58.  *  character - the source character
  59.  *  out - the output character
  60.  * output: none
  61.  * function operation: swaps the inner order of a given utf16 character
  62.  *      and puts the result in an output parameter
  63.  */
  64. void SwapInnerOrder(const UTF16Char* character, UTF16Char* out) {
  65.     int i;
  66.     for (i = 0; i < UTF16_CHARS; i++) {
  67.         out->chars[i] = character->chars[UTF16_CHARS - 1 - i];
  68.     }
  69. }
  70.  
  71. /*
  72.  * function name: CharEquals
  73.  * input:
  74.  *  c1, c2 - the characters
  75.  * output: false if not equal, true if equal
  76.  * function operation: checks whether two characters equal to each other
  77.  */
  78. bool CharEquals(const UTF16Char* c1, const UTF16Char* c2) {
  79.     int i;
  80.     for (i = 0; i < UTF16_CHARS; i++) {
  81.         if (c1->chars[i] != c2->chars[i]) {
  82.             return false;
  83.         }
  84.     }
  85.  
  86.     return true;
  87. }
  88.  
  89. /*
  90.  * function name: StringsEqual
  91.  * input:
  92.  *  s1, s2 - the strings
  93.  *  length - the length of the strings
  94.  * output: true if equal. false if not equal.
  95.  * function operation: compares two strings and checks whether they are equal
  96.  */
  97. bool StringsEqual(const UTF16Char* s1, const UTF16Char* s2, int length) {
  98.     int i, j;
  99.     for (i = 0; i < length; i++) {
  100.         if (!CharEquals(&s1[i], &s2[i])) {
  101.             // if the characters are different in one character
  102.             return false;
  103.         }
  104.     }
  105.  
  106.     return true;
  107. }
  108.  
  109. /*
  110.  * function name: WriteCharacters
  111.  * input:
  112.  *  src, dest - the OS newline format for the source and destination operating system.
  113.  *      if SRC=NULL will not be used.
  114.  *  chars - a string that was read
  115.  *  charsCount - the length of the string read
  116.  *  switchByteOrder - whether to switch the inner order for the UTF16 characters
  117.  *  destFile - a file to write the new characters into
  118.  * output: none
  119.  * function operation: according to given parameters,
  120.  *      the function chooses whether to read one or two characters
  121.  *      and write one or two characters.
  122.  *      it can also switch the inner order of UTF16 characters.
  123.  */
  124. void WriteCharacters(const OSFormat* src, const OSFormat* dest,
  125.     const UTF16Char* chars, int charsCount, bool switchByteOrder, FILE* destFile) {
  126.     #define MAX_CHARS_WRITE MAX_NEWLINE_CHARS
  127.  
  128.     const UTF16Char* stringNotSwitched;
  129.     int writtenCount;
  130.  
  131.     if (src != NULL && dest != NULL &&
  132.         charsCount == src->newlineCharsCount &&
  133.         StringsEqual(chars, src->newlineChars, src->newlineCharsCount)) {
  134.         // if the characters read should be replaced with other newline chars
  135.  
  136.         stringNotSwitched = dest->newlineChars;
  137.         writtenCount = dest->newlineCharsCount;
  138.     } else {
  139.         // if there's no need to replace newline character
  140.         stringNotSwitched = chars;
  141.         writtenCount = charsCount;
  142.     }
  143.  
  144.     UTF16Char output[MAX_CHARS_WRITE];
  145.  
  146.     int i;
  147.  
  148.     for (i = 0; i < writtenCount; i++) {
  149.         if (switchByteOrder) {
  150.             // swap byte order for each byte
  151.             SwapInnerOrder(&stringNotSwitched[i], &output[i]);
  152.         } else {
  153.             output[i] = stringNotSwitched[i];
  154.         }
  155.     }
  156.  
  157.     fwrite(output, sizeof(UTF16Char), writtenCount, destFile);
  158. }
  159.  
  160. /**
  161.  * function name: EndsWith
  162.  * input:
  163.  *  chars - a string to get the prefix of
  164.  *  prefixLength - the length of the prefix of 'chars'
  165.  *  toCheck - the string to check the ending of
  166.  *  toCheckLength - the length of the 'toCheck' string
  167.  * output:
  168.  *  true if the last 'prefixLength' characters of 'toCheck'
  169.  *  are the first 'prefixLength' characters of 'chars'.
  170.  *  otherwise false.
  171.  */
  172. bool EndsWith(UTF16Char* chars, int prefixLength, UTF16Char* toCheck, int toCheckLength) {
  173.     if (prefixLength > toCheckLength) {
  174.         return false;
  175.     }
  176.  
  177.     return StringsEqual(chars, toCheck + toCheckLength - prefixLength, prefixLength);
  178. }
  179.  
  180. /*
  181.  * function name: ShiftQueue
  182.  * input:
  183.  *  queue - a UTF16Queue
  184.  *  shift - an amount to shift the queue by
  185.  * output: none
  186.  * function operation:
  187.  *  the function shifts all the elements inside the queue towards the beginning
  188.  *  overwriting all first 'shift' elements.
  189.  */
  190. void ShiftQueue(UTF16Queue* queue, int shift) {
  191.     int i = shift;
  192.  
  193.     for (i = shift; i < queue->count; i++) {
  194.         // shift i-th element 'shift' elements towards the beginning
  195.         queue->chars[i - shift] = queue->chars[i];
  196.     }
  197.  
  198.     queue->count = queue->count - shift;
  199.  
  200.     if (queue->count < 0) {
  201.         // make sure the queue count doesn't fall under 0
  202.         queue->count = 0;
  203.     }
  204. }
  205.  
  206. /*
  207.  * function name: Fill
  208.  * input:
  209.  *  queue - a UTF16Queue to fill(and overwrite the content of)
  210.  *  sourceFile - a file where UTF16Chars will be read from
  211.  * output: true if read anything. false if didn't.
  212.  * function operation:
  213.  *  the function overwrites the contents of queue and fills it all with
  214.  *  the maximal amount of characters that can be read from the file
  215.  *  and yet be saved inside the queue
  216.  */
  217. bool Fill(UTF16Queue* queue, FILE* sourceFile) {
  218.     // read the maximal amount of characters and put them inside the queue
  219.     int charsRead = fread(queue->chars, sizeof(UTF16Char), queue->capacity, sourceFile);
  220.  
  221.     // change the count accordingly
  222.     queue->count = charsRead;
  223.  
  224.     return charsRead > 0;
  225. }
  226.  
  227. /*
  228.  * function name: Pop
  229.  * input:
  230.  *  queue - a UTF16Queue
  231.  *  output - a pointer to an output character
  232.  * output: none
  233.  * function operation:
  234.  *  the function pops(as defined by a normal queue)
  235.  *  the first character in the queue and puts its value inside 'output'
  236.  */
  237. void Pop(UTF16Queue* queue, UTF16Char* output) {
  238.     if (queue->count == 0) {
  239.         return;
  240.     }
  241.  
  242.     *output = queue->chars[0];
  243.  
  244.     // shift the elements inside the queue
  245.     ShiftQueue(queue, 1);
  246. }
  247.  
  248.  
  249. #define END_OF_FILE 1
  250. #define QUEUE_FULL 2
  251. #define READ_SUCCESS 0
  252.  
  253. /*
  254.  * function name: Push
  255.  * input:
  256.  *  queue - a UTF16Queue to push into
  257.  *  srcFile - a file to read from a UTF16Char and push into the queue
  258.  * output:
  259.  *  one of three defined codes above
  260.  * function operation:
  261.  *  the function reads a character from the source file into the queue
  262.  *  if it succeeds, returns READ_SUCCESS
  263.  *  if end of file reached, returns END_OF_FILE
  264.  *  if the queue is full, returns QUEUE_FULL
  265.  */
  266. int Push(UTF16Queue* queue, FILE* srcFile) {
  267.     if (queue->capacity == queue->count) {
  268.         // don't allow over-inputting
  269.         return QUEUE_FULL;
  270.     }
  271.  
  272.     // read a character from the file into the right position in the queue
  273.     int charsRead = fread(&queue->chars[queue->count], sizeof(UTF16Char), 1, srcFile);
  274.  
  275.     if (charsRead == 0) {
  276.         return END_OF_FILE;
  277.     }
  278.  
  279.     // if read, increase count
  280.     queue->count++;
  281.  
  282.     return READ_SUCCESS;
  283. }
  284.  
  285. /*
  286.  * function name: Clear
  287.  * input:
  288.  *  queue - a UTF16Queue
  289.  * output: none
  290.  * function operation:
  291.  *  the function clears the queue from its contents
  292.  */
  293. void Clear(UTF16Queue* queue) {
  294.     queue->count = 0;
  295. }
  296.  
  297. /**
  298.  * function name: TransferAllFileData
  299.  * input:
  300.  *  src, dest - source and destination files
  301.  *  srcFormat, destFormat - formats for source OS and destination OS
  302.  *  switchByteOrder - whether to switch the inner order of every UTF character
  303.  * output: none
  304.  * function operation:
  305.  *  the function will transfer all the data from the source file to the destination file
  306.  *  according to given parameters
  307.  */
  308. void TransferAllFileData(FILE* src, FILE* dest,
  309.         const OSFormat* srcFormat, const OSFormat *destFormat,
  310.         bool switchByteOrder) {
  311.  
  312.     // the amount of UTF16 characters that make a newline character
  313.     int countNewlineChars = srcFormat == NULL ? 1 : srcFormat->newlineCharsCount;
  314.  
  315.     // this will be used to identify newline characters
  316.     UTF16Queue characterQueue;
  317.     characterQueue.capacity = countNewlineChars;
  318.     Clear(&characterQueue);
  319.  
  320.     // insert all possible characters into the queue
  321.     Fill(&characterQueue, src);
  322.  
  323.     while (characterQueue.count > 0) {
  324.         if (srcFormat == NULL || characterQueue.count != countNewlineChars ||
  325.             !StringsEqual(srcFormat->newlineChars, characterQueue.chars, countNewlineChars)) {
  326.             // if the characters read shouldn't be replaced with another newline character
  327.  
  328.             // just write the first character as is into the file
  329.             UTF16Char character;
  330.             Pop(&characterQueue, &character);
  331.             WriteCharacters(NULL, NULL, &character, 1, switchByteOrder, dest);
  332.  
  333.             // and push a new character into the queue
  334.             Push(&characterQueue, src);
  335.         } else {
  336.             // if the character should be switched with a newline character, write it
  337.             WriteCharacters(srcFormat, destFormat, characterQueue.chars,
  338.                 countNewlineChars, switchByteOrder, dest);
  339.  
  340.             // and overwrite the content of the queue with new characters
  341.             Fill(&characterQueue, src);
  342.         }
  343.     }
  344. }
  345.  
  346. /*
  347.  * function name: GetOSFormat
  348.  * input:
  349.  *  str - the flag given by a user
  350.  * output: a matching operating system if found. if not found, returns NULL.
  351.  * function operation: gets an operating system from a given flag
  352.  */
  353. const OSFormat* GetOSFormat(char* str) {
  354.     int i;
  355.     for (i = 0; i < OS_COUNT; i++) {
  356.         if (strcmp(operatingSystems[i]->flag, str) == 0) {
  357.             // if an operating system matches the given string, return it
  358.             return operatingSystems[i];
  359.         }
  360.     }
  361.  
  362.     return NULL;
  363. }
  364.  
  365. /*
  366.  * function name: main
  367.  * input:
  368.  *  argc - the amount of arguments
  369.  *  argv - the values of the arguments
  370.  * output: 0 if no errors. otherwise there are.
  371.  * function operation: the main function
  372.  */
  373. int main(int argc, char* argv[]) {
  374.     // amounts of arguments needed for each operation
  375.     #define ONLY_SOURCE_DEST 3
  376.     #define ONLY_OS 5
  377.     #define WITH_SWITCH 6
  378.  
  379.     FILE* src = NULL;
  380.     FILE* dest = NULL;
  381.  
  382.     const OSFormat* sourceFormat = NULL;
  383.     const OSFormat* destFormat = NULL;
  384.  
  385.     bool switchByteOrder = false;
  386.  
  387.     switch(argc) {
  388.         case WITH_SWITCH: {
  389.             char* swapFlag = argv[5];
  390.  
  391.             #define SWAP "-swap"
  392.             #define KEEP "-keep"
  393.  
  394.             if (strcmp(swapFlag, SWAP) == 0) {
  395.                 // if should swap
  396.                 switchByteOrder = true;
  397.             } else {
  398.                 if (strcmp(swapFlag, KEEP) == 0) {
  399.                     // if shouldn't swap
  400.                     switchByteOrder = false;
  401.                 } else {
  402.                     // if invalid arguments were entered
  403.                     return 0;
  404.                 }
  405.             }
  406.         }
  407.         case ONLY_OS: {
  408.             sourceFormat = GetOSFormat(argv[3]);
  409.             destFormat = GetOSFormat(argv[4]);
  410.         }
  411.         case ONLY_SOURCE_DEST: {
  412.             src = fopen(argv[1], "rb");
  413.  
  414.             if (src == NULL) {
  415.                 // if the source doesn't exist
  416.                 return 0;
  417.             }
  418.  
  419.             dest = fopen(argv[2], "wb");
  420.             if (dest == NULL) {
  421.                 // if failed to open dest
  422.                 fclose(src);
  423.                 return 1;
  424.             }
  425.  
  426.             // write all the data from the source file into the destination file
  427.             TransferAllFileData(src, dest, sourceFormat, destFormat, switchByteOrder);
  428.  
  429.             fclose(dest);
  430.             fclose(src);
  431.  
  432.             return 0;
  433.         } // end of case ONLY_SOURCE_DEST
  434.  
  435.         default: {
  436.             // no matching arguments were found. aborting.
  437.             return 0;
  438.         }
  439.     } // end of switch
  440. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement