Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <string.h>
- // the amount of characters that define ONE utf16 char
- #define UTF16_CHARS 2
- // the maximal amount of utf16 characters used to describe a newline
- #define MAX_NEWLINE_CHARS 2
- typedef char bool;
- #define true 1
- #define false 0
- // a struct that represents a UTF16 character
- typedef struct {
- char chars[UTF16_CHARS];
- } UTF16Char;
- /* little endian representation(the exercise source files are only in little endian) */
- #define NEWLINE { 0x0a, 0 }
- #define CARRIAGE_RETURN { 0x0d, 0 }
- // a struct that defines the newline format for each operating system
- typedef struct {
- // the amount of utf16 characters that define the newline
- int newlineCharsCount;
- // the actual characters
- UTF16Char newlineChars[MAX_NEWLINE_CHARS];
- // the name of the operating system(as command line arguments)
- const char* flag;
- } OSFormat;
- typedef struct {
- // the maximum capacity of this queue
- int capacity;
- // the amount of characters inside
- int count;
- UTF16Char chars[MAX_NEWLINE_CHARS];
- } UTF16Queue;
- // define os newline format
- const OSFormat unixOS = { 1, { NEWLINE }, "-unix" };
- const OSFormat macOS = { 1, { CARRIAGE_RETURN }, "-mac" };
- const OSFormat windowsOS = { 2, { CARRIAGE_RETURN, NEWLINE }, "-win" };
- #define OS_COUNT 3
- // list of operating systems format
- const OSFormat* operatingSystems[] = {
- &unixOS, &macOS, &windowsOS
- };
- /*
- * function name: SwapInnerOrder
- * input:
- * character - the source character
- * out - the output character
- * output: none
- * function operation: swaps the inner order of a given utf16 character
- * and puts the result in an output parameter
- */
- void SwapInnerOrder(const UTF16Char* character, UTF16Char* out) {
- int i;
- for (i = 0; i < UTF16_CHARS; i++) {
- out->chars[i] = character->chars[UTF16_CHARS - 1 - i];
- }
- }
- /*
- * function name: CharEquals
- * input:
- * c1, c2 - the characters
- * output: false if not equal, true if equal
- * function operation: checks whether two characters equal to each other
- */
- bool CharEquals(const UTF16Char* c1, const UTF16Char* c2) {
- int i;
- for (i = 0; i < UTF16_CHARS; i++) {
- if (c1->chars[i] != c2->chars[i]) {
- return false;
- }
- }
- return true;
- }
- /*
- * function name: StringsEqual
- * input:
- * s1, s2 - the strings
- * length - the length of the strings
- * output: true if equal. false if not equal.
- * function operation: compares two strings and checks whether they are equal
- */
- bool StringsEqual(const UTF16Char* s1, const UTF16Char* s2, int length) {
- int i, j;
- for (i = 0; i < length; i++) {
- if (!CharEquals(&s1[i], &s2[i])) {
- // if the characters are different in one character
- return false;
- }
- }
- return true;
- }
- /*
- * function name: WriteCharacters
- * input:
- * src, dest - the OS newline format for the source and destination operating system.
- * if SRC=NULL will not be used.
- * chars - a string that was read
- * charsCount - the length of the string read
- * switchByteOrder - whether to switch the inner order for the UTF16 characters
- * destFile - a file to write the new characters into
- * output: none
- * function operation: according to given parameters,
- * the function chooses whether to read one or two characters
- * and write one or two characters.
- * it can also switch the inner order of UTF16 characters.
- */
- void WriteCharacters(const OSFormat* src, const OSFormat* dest,
- const UTF16Char* chars, int charsCount, bool switchByteOrder, FILE* destFile) {
- #define MAX_CHARS_WRITE MAX_NEWLINE_CHARS
- const UTF16Char* stringNotSwitched;
- int writtenCount;
- if (src != NULL && dest != NULL &&
- charsCount == src->newlineCharsCount &&
- StringsEqual(chars, src->newlineChars, src->newlineCharsCount)) {
- // if the characters read should be replaced with other newline chars
- stringNotSwitched = dest->newlineChars;
- writtenCount = dest->newlineCharsCount;
- } else {
- // if there's no need to replace newline character
- stringNotSwitched = chars;
- writtenCount = charsCount;
- }
- UTF16Char output[MAX_CHARS_WRITE];
- int i;
- for (i = 0; i < writtenCount; i++) {
- if (switchByteOrder) {
- // swap byte order for each byte
- SwapInnerOrder(&stringNotSwitched[i], &output[i]);
- } else {
- output[i] = stringNotSwitched[i];
- }
- }
- fwrite(output, sizeof(UTF16Char), writtenCount, destFile);
- }
- /**
- * function name: EndsWith
- * input:
- * chars - a string to get the prefix of
- * prefixLength - the length of the prefix of 'chars'
- * toCheck - the string to check the ending of
- * toCheckLength - the length of the 'toCheck' string
- * output:
- * true if the last 'prefixLength' characters of 'toCheck'
- * are the first 'prefixLength' characters of 'chars'.
- * otherwise false.
- */
- bool EndsWith(UTF16Char* chars, int prefixLength, UTF16Char* toCheck, int toCheckLength) {
- if (prefixLength > toCheckLength) {
- return false;
- }
- return StringsEqual(chars, toCheck + toCheckLength - prefixLength, prefixLength);
- }
- /*
- * function name: ShiftQueue
- * input:
- * queue - a UTF16Queue
- * shift - an amount to shift the queue by
- * output: none
- * function operation:
- * the function shifts all the elements inside the queue towards the beginning
- * overwriting all first 'shift' elements.
- */
- void ShiftQueue(UTF16Queue* queue, int shift) {
- int i = shift;
- for (i = shift; i < queue->count; i++) {
- // shift i-th element 'shift' elements towards the beginning
- queue->chars[i - shift] = queue->chars[i];
- }
- queue->count = queue->count - shift;
- if (queue->count < 0) {
- // make sure the queue count doesn't fall under 0
- queue->count = 0;
- }
- }
- /*
- * function name: Fill
- * input:
- * queue - a UTF16Queue to fill(and overwrite the content of)
- * sourceFile - a file where UTF16Chars will be read from
- * output: true if read anything. false if didn't.
- * function operation:
- * the function overwrites the contents of queue and fills it all with
- * the maximal amount of characters that can be read from the file
- * and yet be saved inside the queue
- */
- bool Fill(UTF16Queue* queue, FILE* sourceFile) {
- // read the maximal amount of characters and put them inside the queue
- int charsRead = fread(queue->chars, sizeof(UTF16Char), queue->capacity, sourceFile);
- // change the count accordingly
- queue->count = charsRead;
- return charsRead > 0;
- }
- /*
- * function name: Pop
- * input:
- * queue - a UTF16Queue
- * output - a pointer to an output character
- * output: none
- * function operation:
- * the function pops(as defined by a normal queue)
- * the first character in the queue and puts its value inside 'output'
- */
- void Pop(UTF16Queue* queue, UTF16Char* output) {
- if (queue->count == 0) {
- return;
- }
- *output = queue->chars[0];
- // shift the elements inside the queue
- ShiftQueue(queue, 1);
- }
- #define END_OF_FILE 1
- #define QUEUE_FULL 2
- #define READ_SUCCESS 0
- /*
- * function name: Push
- * input:
- * queue - a UTF16Queue to push into
- * srcFile - a file to read from a UTF16Char and push into the queue
- * output:
- * one of three defined codes above
- * function operation:
- * the function reads a character from the source file into the queue
- * if it succeeds, returns READ_SUCCESS
- * if end of file reached, returns END_OF_FILE
- * if the queue is full, returns QUEUE_FULL
- */
- int Push(UTF16Queue* queue, FILE* srcFile) {
- if (queue->capacity == queue->count) {
- // don't allow over-inputting
- return QUEUE_FULL;
- }
- // read a character from the file into the right position in the queue
- int charsRead = fread(&queue->chars[queue->count], sizeof(UTF16Char), 1, srcFile);
- if (charsRead == 0) {
- return END_OF_FILE;
- }
- // if read, increase count
- queue->count++;
- return READ_SUCCESS;
- }
- /*
- * function name: Clear
- * input:
- * queue - a UTF16Queue
- * output: none
- * function operation:
- * the function clears the queue from its contents
- */
- void Clear(UTF16Queue* queue) {
- queue->count = 0;
- }
- /**
- * function name: TransferAllFileData
- * input:
- * src, dest - source and destination files
- * srcFormat, destFormat - formats for source OS and destination OS
- * switchByteOrder - whether to switch the inner order of every UTF character
- * output: none
- * function operation:
- * the function will transfer all the data from the source file to the destination file
- * according to given parameters
- */
- void TransferAllFileData(FILE* src, FILE* dest,
- const OSFormat* srcFormat, const OSFormat *destFormat,
- bool switchByteOrder) {
- // the amount of UTF16 characters that make a newline character
- int countNewlineChars = srcFormat == NULL ? 1 : srcFormat->newlineCharsCount;
- // this will be used to identify newline characters
- UTF16Queue characterQueue;
- characterQueue.capacity = countNewlineChars;
- Clear(&characterQueue);
- // insert all possible characters into the queue
- Fill(&characterQueue, src);
- while (characterQueue.count > 0) {
- if (srcFormat == NULL || characterQueue.count != countNewlineChars ||
- !StringsEqual(srcFormat->newlineChars, characterQueue.chars, countNewlineChars)) {
- // if the characters read shouldn't be replaced with another newline character
- // just write the first character as is into the file
- UTF16Char character;
- Pop(&characterQueue, &character);
- WriteCharacters(NULL, NULL, &character, 1, switchByteOrder, dest);
- // and push a new character into the queue
- Push(&characterQueue, src);
- } else {
- // if the character should be switched with a newline character, write it
- WriteCharacters(srcFormat, destFormat, characterQueue.chars,
- countNewlineChars, switchByteOrder, dest);
- // and overwrite the content of the queue with new characters
- Fill(&characterQueue, src);
- }
- }
- }
- /*
- * function name: GetOSFormat
- * input:
- * str - the flag given by a user
- * output: a matching operating system if found. if not found, returns NULL.
- * function operation: gets an operating system from a given flag
- */
- const OSFormat* GetOSFormat(char* str) {
- int i;
- for (i = 0; i < OS_COUNT; i++) {
- if (strcmp(operatingSystems[i]->flag, str) == 0) {
- // if an operating system matches the given string, return it
- return operatingSystems[i];
- }
- }
- return NULL;
- }
- /*
- * function name: main
- * input:
- * argc - the amount of arguments
- * argv - the values of the arguments
- * output: 0 if no errors. otherwise there are.
- * function operation: the main function
- */
- int main(int argc, char* argv[]) {
- // amounts of arguments needed for each operation
- #define ONLY_SOURCE_DEST 3
- #define ONLY_OS 5
- #define WITH_SWITCH 6
- FILE* src = NULL;
- FILE* dest = NULL;
- const OSFormat* sourceFormat = NULL;
- const OSFormat* destFormat = NULL;
- bool switchByteOrder = false;
- switch(argc) {
- case WITH_SWITCH: {
- char* swapFlag = argv[5];
- #define SWAP "-swap"
- #define KEEP "-keep"
- if (strcmp(swapFlag, SWAP) == 0) {
- // if should swap
- switchByteOrder = true;
- } else {
- if (strcmp(swapFlag, KEEP) == 0) {
- // if shouldn't swap
- switchByteOrder = false;
- } else {
- // if invalid arguments were entered
- return 0;
- }
- }
- }
- case ONLY_OS: {
- sourceFormat = GetOSFormat(argv[3]);
- destFormat = GetOSFormat(argv[4]);
- }
- case ONLY_SOURCE_DEST: {
- src = fopen(argv[1], "rb");
- if (src == NULL) {
- // if the source doesn't exist
- return 0;
- }
- dest = fopen(argv[2], "wb");
- if (dest == NULL) {
- // if failed to open dest
- fclose(src);
- return 1;
- }
- // write all the data from the source file into the destination file
- TransferAllFileData(src, dest, sourceFormat, destFormat, switchByteOrder);
- fclose(dest);
- fclose(src);
- return 0;
- } // end of case ONLY_SOURCE_DEST
- default: {
- // no matching arguments were found. aborting.
- return 0;
- }
- } // end of switch
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement