#include "libcgc.h" #include "cgc_service.h" uint16_t entry_count; uint16_t chapter_count; uint16_t cgc_read_short() { uint16_t val; //cgc_size_t rx; //if ( receive( STDIN, &val, sizeof(val), &rx ) != 0 ) if (cgc_receive_bytes( (uint8_t*)&val, sizeof(val) ) != 2 ) { return 0; } return val; } void cgc_populate_entry(int entry, int num, char* str, int str_len, uint8_t req, uint8_t mult, uint8_t type) { entry_info_table[entry][num] = (Entry_Info*)cgc_malloc(sizeof(Entry_Info)); entry_info_table[entry][num]->format = type; entry_info_table[entry][num]->mult_ok = mult; entry_info_table[entry][num]->required = req; entry_info_table[entry][num]->str_len = str_len; cgc_strncpy(entry_info_table[entry][num]->entry_str, str, str_len); cgc_bzero(str, NAME_LEN_MAX); } void cgc_populate_sub_entry(int entry, int num, char* str, int str_len, uint8_t req, uint8_t mult, uint8_t type) { sub_entry_info_list[entry][num] = (Entry_Info*)cgc_malloc(sizeof(Entry_Info)); sub_entry_info_list[entry][num]->format = type; sub_entry_info_list[entry][num]->mult_ok = mult; sub_entry_info_list[entry][num]->required = req; sub_entry_info_list[entry][num]->str_len = str_len; cgc_strncpy(sub_entry_info_list[entry][num]->entry_str, str, str_len); cgc_bzero(str, NAME_LEN_MAX); } #define REQ 1 #define REQ_NO 0 #define MULT_OK 1 #define MULT_NO 0 // populate the entry_info_table with valid fields void cgc_populateEntryInfo() { char ss[NAME_LEN_MAX]; cgc_bzero(ss, NAME_LEN_MAX); int num, entry; // IDENTITY num = 0; entry = IDENTITY; cgc_strcpy(ss, "first name"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, STR); cgc_strcpy(ss, "middle name"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, STR); cgc_strcpy(ss, "last name"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, STR); cgc_strcpy(ss, "age"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, CHAR); cgc_strcpy(ss, "weight"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, SHORT); cgc_strcpy(ss, "birth country"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, STR); cgc_strcpy(ss, "birth state"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, STR); cgc_strcpy(ss, "birth city"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, STR); cgc_strcpy(ss, "married"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, BOOL); // MOVIE num = 0; entry = MOVIES; cgc_strcpy(ss, "title"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, STR); cgc_strcpy(ss, "actor"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, MULT_OK, STR); cgc_strcpy(ss, "director"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, MULT_OK, STR); cgc_strcpy(ss, "producer"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, MULT_OK, STR); cgc_strcpy(ss, "year released"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, SHORT); cgc_strcpy(ss, "plot summary"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, STR); // VEHICLES num = 0; entry = VEHICLES; cgc_strcpy(ss, "make"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, STR); cgc_strcpy(ss, "model"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, STR); cgc_strcpy(ss, "color"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, MULT_OK, STR); cgc_strcpy(ss, "displacement"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, SHORT); cgc_strcpy(ss, "displacement units"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, CHAR); cgc_strcpy(ss, "doors"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, CHAR); // BOOKS num = 0; entry = BOOKS; cgc_strcpy(ss, "author"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), REQ, MULT_OK, STR); cgc_strcpy(ss, "year"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, CHAR); cgc_strcpy(ss, "summary"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, STR); cgc_strcpy(ss, "publisher"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, STR); cgc_strcpy(ss, "character"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, MULT_OK, STR); cgc_strcpy(ss, "made into a movie"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, BOOL); // SONG num = 0; entry = SONGS; cgc_strcpy(ss, "writer"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), REQ, MULT_OK, STR); cgc_strcpy(ss, "year"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, CHAR); cgc_strcpy(ss, "genre"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, STR); cgc_strcpy(ss, "publisher"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, STR); cgc_strcpy(ss, "free online"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, BOOL); // JOB num = 0; entry = JOBS; cgc_strcpy(ss, "title"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), REQ, MULT_OK, STR); cgc_strcpy(ss, "years"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, CHAR); cgc_strcpy(ss, "job category"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, STR); cgc_strcpy(ss, "company"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, STR); cgc_strcpy(ss, "have a best friend"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, BOOL); cgc_strcpy(ss, "salary"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, INT); num = 0; entry = HOBBIES; cgc_strcpy(ss, ""); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, PTR); cgc_strcpy(ss, ""); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, PTR); cgc_strcpy(ss, ""); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, PTR); cgc_strcpy(ss, ""); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, PTR); cgc_strcpy(ss, ""); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, PTR); cgc_strcpy(ss, ""); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, PTR); num = 0; entry = PETS; cgc_strcpy(ss, "name"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), REQ, MULT_OK, STR); cgc_strcpy(ss, "species"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, STR); cgc_strcpy(ss, "legs"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, CHAR); cgc_strcpy(ss, "inside only"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, BOOL); cgc_strcpy(ss, "age"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, CHAR); cgc_strcpy(ss, "shots updated"); cgc_populate_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, BOOL); } void cgc_populateSubEntryInfo() { char ss[NAME_LEN_MAX]; cgc_bzero(ss, NAME_LEN_MAX); int num, entry; // HOBBIES // SHOOTING num = 0; entry = SHOOTING; cgc_strcpy(ss, "make"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, MULT_OK, STR); cgc_strcpy(ss, "model"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, MULT_OK, STR); cgc_strcpy(ss, "league"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, STR); cgc_strcpy(ss, "length"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, CHAR); cgc_strcpy(ss, "length units"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, STR); cgc_strcpy(ss, "years experience"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, CHAR); cgc_strcpy(ss, "injury"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, BOOL); // KNIVES num = 0; entry = KNIVES; cgc_strcpy(ss, "make"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, STR); cgc_strcpy(ss, "model"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, STR); cgc_strcpy(ss, "value"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, SHORT); cgc_strcpy(ss, "style"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, STR); cgc_strcpy(ss, "blade length"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, CHAR); cgc_strcpy(ss, "length units"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, STR); cgc_strcpy(ss, "comes with sheath"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, BOOL); cgc_strcpy(ss, "injury"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, BOOL); // STAMPS num = 0; entry = STAMPS; cgc_strcpy(ss, "name"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, STR); cgc_strcpy(ss, "value"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, SHORT); cgc_strcpy(ss, "seller"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, STR); cgc_strcpy(ss, "mint"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, BOOL); cgc_strcpy(ss, "count"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, CHAR); // KAYAKING num = 0; entry = KAYAKING; cgc_strcpy(ss, "make"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, STR); cgc_strcpy(ss, "model"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, STR); cgc_strcpy(ss, "length"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, CHAR); cgc_strcpy(ss, "style"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, STR); cgc_strcpy(ss, "initial stability"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, CHAR); cgc_strcpy(ss, "years experience"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, CHAR); cgc_strcpy(ss, "highest class"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, CHAR); cgc_strcpy(ss, "touring"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, BOOL); cgc_strcpy(ss, "surfing"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, BOOL); cgc_strcpy(ss, "tricking"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, BOOL); cgc_strcpy(ss, "injury"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, BOOL); // COINS num = 0; entry = COINS; cgc_strcpy(ss, "name"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, STR); cgc_strcpy(ss, "seller"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, STR); cgc_strcpy(ss, "value"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, INT); cgc_strcpy(ss, "mint"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, BOOL); cgc_strcpy(ss, "count"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, CHAR); // EXERCISES num = 0; entry = EXERCISES; cgc_strcpy(ss, "name"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, MULT_OK, STR); cgc_strcpy(ss, "max weight"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, SHORT); cgc_strcpy(ss, "reps"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, CHAR); cgc_strcpy(ss, "sets"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, CHAR); cgc_strcpy(ss, "injury"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, BOOL); // SPORTS num = 0; entry = SPORTS; cgc_strcpy(ss, "name"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, STR); cgc_strcpy(ss, "position"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, MULT_OK, STR); cgc_strcpy(ss, "years experience"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), REQ, 0, CHAR); cgc_strcpy(ss, "injury"); cgc_populate_sub_entry(entry, num++, ss, cgc_strlen(ss), 0, 0, BOOL); } // return an entry_info with the proper title field name uint8_t cgc_getEntryInfo(uint16_t title, uint8_t entry, uint8_t is_sub, Entry_Info *entry_info) { if (is_sub) {cgc_memcpy(entry_info,sub_entry_info_list[title][entry], sizeof(Entry_Info));} else {cgc_memcpy(entry_info,entry_info_table[title][entry], sizeof(Entry_Info));} if (entry_info->mult_ok > 1 || entry_info->required > 1) { cgc_printf("WRONG FORMAT in getEntryInfo\n"); } return 1; } int buffer_length; int cgc_verify_entry(Entry *entry) { if (!entry) {return 1;} if (entry->entry > MAX_ENTRY_PER_TITLE) {return 2;} if (entry->format > PTR) {return 3;} if (entry->format == STR || entry->format == INT) {if (entry->offset_data >= buffer_length) {return 4;}} if (entry->len > NAME_LEN_MAX) {return 5;} if (entry->offset_next_entry >= buffer_length) {return 6;} return 0; } int cgc_verify_chapter(Chapter *chap) { if (!chap) {return 1;} if (chap->title >= TITLE_COUNT) {return 2;} if (chap->entry_count > MAX_ENTRY_PER_TITLE) {return 3;} if (chap->offset_first_entry >= buffer_length) {return 4;} if (chap->offset_next_chapter >= buffer_length) {return 5;} return 0; } int cgc_parse_book(uint8_t* buff, int rcv_len, int first_offset) { Entry *entry; uint16_t next_offset = first_offset; int first = 1; // used for checking required entries in a chapter char is_subtitle = 0; uint16_t parent_of_subtitle = 0; char **names; char is_initial_subtitle = 0; Entry_Info *(*entry_table)[MAX_ENTRY_PER_TITLE]; Chapter *chapter = NULL; do { // start parsing a new chapter if (chapter) { if (!chapter->offset_next_chapter && !is_initial_subtitle) { // this is the end of this chapter if (is_subtitle) { // reverting to chapter after hobby is_subtitle = 0; if (!parent_of_subtitle) {continue;} chapter = (Chapter*)(buff+parent_of_subtitle); } } else { chapter = (Chapter*)(buff+next_offset); // normal flow after a chapter is done is_initial_subtitle = 0; } } else { // first chapter handled here chapter = (Chapter*)(buff+next_offset); } int t = 0; //if (chapter->title >= NUM_TITLES-1 && !is_subtitle) if (chapter->title == HOBBIES && !is_subtitle) { // we just found HOBBIES, change over cgc_printf("Title: @s\n", titles[chapter->title]); cgc_printf("Entry Count: 0x@x\n", chapter->entry_count); names = subtitles; entry_table = sub_entry_info_list; next_offset = (chapter->offset_first_entry); parent_of_subtitle = (chapter->offset_next_chapter); is_subtitle = 1; is_initial_subtitle = 1; // Problem: this chapter is over, need to point to the next chapter continue; } else {if (!is_subtitle) { // this is a normal chapter, so point to titles names = titles; entry_table = entry_info_table; if ((t = cgc_verify_chapter(chapter)) != 0) { cgc_printf("Malformed chapter found! @d Exiting.\n", t); cgc__terminate(-2); } }} cgc_printf("Title: @s\n", names[chapter->title]); if (chapter->entry_count > MAX_NUM_ENTRIES) { cgc_printf("ERROR: Too many entries: @d\n", chapter->entry_count); cgc__terminate(-1); } cgc_printf("Entry Count: 0x@x\n", chapter->entry_count); if (!chapter->offset_first_entry || !chapter->entry_count) { // go to the next chapter. no entries here next_offset = (chapter->offset_next_chapter); cgc_printf("NO entries found\n"); continue; } int req_cnt = 1; int prev_read_counter = 0; first = 1; entry = (Entry*)(buff+((chapter->offset_first_entry))); //int t = 0; if ((t = cgc_verify_entry(entry)) != 0) { cgc_printf("Malformed entry found! @d Exiting.\n", t); cgc__terminate(-1); } do { // parse a chapter. all of its entries int data_offset = 0; Entry_Info entry_info; if (names == subtitles) {cgc_getEntryInfo(chapter->title, entry->entry, 1, &entry_info);} else {cgc_getEntryInfo(chapter->title, entry->entry, 0, &entry_info);} // once per chapter, check the required entries if (first) { cgc_memset(prev_read_entries, -1, chapter->entry_count); cgc_memset(required_entries, -1, MAX_ENTRY_PER_TITLE); // record the required entries for this chapter // later, make sure that these are populated first = 0; prev_read_counter = 0; required_entries[0] = 0; for (int i = 0; i < MAX_ENTRY_PER_TITLE; i++) { if (entry_table[chapter->title][i] != NULL) { // check all entries for required entries if (entry_table[chapter->title][i]->required == 1) { // this is a required entry required_entries[req_cnt++] = i; } } } req_cnt--; required_entries[0] = req_cnt; } // if this entry was in the required_entry list, remove it (it has been satisfied) for (uint8_t i = 1; i <= req_cnt; i++) { if (entry->entry == required_entries[i]) { // remove this from the required_entries list required_entries[i] = 70; required_entries[0] -= 1; } } for (uint8_t i = 1; i <= prev_read_counter; i++) { if (entry->entry == prev_read_entries[i]) { if (entry_info.mult_ok != MULT_OK) { // Duplicate! Not allowed. cgc_printf("Duplicate entry found! Exiting...\n"); cgc__terminate(-1); } } } prev_read_entries[prev_read_counter++] = entry->entry; if (entry_info.format != entry->format) { // they sent us the wrong format. cgc_exit cgc_printf("WRONG FORMAT: @d vs @d\n", entry_info.format, entry->format); cgc__terminate(-2); } if (chapter->title == PETS) { if (entry->entry == 0) { // 2 pets are required to set successful[3] to 1 if (successful[3] == -1) { successful[3] = 1; } if (successful[3] == 0) {successful[3] = -1;} } } if (chapter->title == JOBS) { if (entry->entry == 1) { if (entry->offset_data > 20) { // more than 20 years on this job successful[4] = 1; } } } if (entry_info.format == STR) { // go to the offset and retrieve the string char str[NAME_LEN_MAX]; cgc_memcpy(str, (char*)&buff[(entry->offset_data)], entry->len); if (entry->len < NAME_LEN_MAX) {str[entry->len] = '\0';} else {str[NAME_LEN_MAX-1] = '\0';} cgc_printf("@s: @s\n", entry_info.entry_str, str); data_offset += entry->len; } else {if (entry_info.format == INT) { uint32_t num = *(uint32_t*)&buff[(entry->offset_data)]; cgc_printf("@s: 0x@x\n", entry_info.entry_str, num); data_offset += 4; } else {if (entry_info.format == BOOL) { short num = *(short*)&entry->offset_data; if (num == 1) {cgc_printf("@s: true\n", entry_info.entry_str);} else {if (num == 0) {cgc_printf("@s: false\n", entry_info.entry_str);} else {cgc_printf("@s!!: 0x@x\n", entry_info.entry_str, num);}} data_offset += 0; } else {cgc_printf("@s: 0x@x\n", entry_info.entry_str, (entry->offset_data));}}} if (chapter->title == IDENTITY) { if (entry->entry == 8) { // this ID is married if (successful[0] == 1) { success_info[1][0] = entry->offset_data; success_info[1][1] = entry->len; successful[1] = 1; } else { success_info[0][0] = entry->offset_data; success_info[0][1] = entry->len; successful[0] = 1; } } else { if (entry->entry == 3 && entry->offset_data < 11) { // ID with age less than 11 successful[2] = 1; success_info[2][0] = entry->offset_data; success_info[2][1] = entry->len; } } } if ((entry->offset_next_entry) == 0) {break;} entry = (Entry*)(buff+((entry->offset_next_entry))); if ((t = cgc_verify_entry(entry)) != 0) { cgc_printf("Malformed entry found! @d @d Exiting..\n", t, entry->format); cgc__terminate(-1); } } while (entry != NULL); next_offset = (chapter->offset_next_chapter); // if there are any left in 'required_entries', fail if (required_entries[0] != 0) { cgc_printf("DIDN'T SEND ME ALL THE REQUIRED ENTRIES! @c ", required_entries[0]); return -1; } } while ((chapter->offset_next_chapter) || is_subtitle); return 1; } void cgc_init() { cgc_populateEntryInfo(); cgc_populateSubEntryInfo(); } void cgc_test_win() { int success = 0; for (int i = 0; i < 5; i++) { if (successful[i] == 1) {success += 1;} } if (success == 5) { char buff[10]; int max_len = 25; // WIN cgc_printf("What is your family's last name?\n"); int len = cgc_receive_until(buff, '\n', max_len); buff[len] = 0; // names of two parents and kid put together cgc_printf("Congratulations, @s family! You have a great diary!\n",buff); } } // cgc_read the file // parse and print the content int main(int cgc_argc, char *cgc_argv[]) { cgc_init(); cgc_memset(successful, 0, 5); cgc_memset(success_info, 0, 10*sizeof(uint16_t)); int current_buffer_offset = 0; cgc_printf("Welcome to the diary logger!\n"); // cgc_read the size of the input (uint16) uint16_t buffer_size = cgc_read_short(); buffer_length = buffer_size; if (buffer_size < 1) { cgc_printf("Buffer length is too small.\n"); cgc__terminate(-3); } // create a buffer of 'size' size uint8_t *buffer = (uint8_t*)cgc_malloc( buffer_size ); if (buffer == NULL) { cgc_printf("Failed to allocate enough space for this buffer.\n"); cgc__terminate(-3); } int rcv_len = cgc_receive_bytes(buffer, buffer_size); if (rcv_len != buffer_size) { cgc_printf("Buffer received is not correct size.\n"); cgc__terminate(-3); } if (buffer_size < sizeof(Header)) { cgc_printf("Buffer received is not correct size.\n"); cgc__terminate(-3); } // cgc_read in the HEADER Header *header = (Header*)(buffer+current_buffer_offset); current_buffer_offset += sizeof(Header); // print header info cgc_printf("Length: @d\n", buffer_size); cgc_printf("Magic number: 0x@x\n", header->magic_number); cgc_printf("Future: 0x@x\n", header->future); cgc_printf("Offset: 0x@x\n", header->offset_to_first_chapter); int ret = cgc_parse_book(buffer, rcv_len, header->offset_to_first_chapter); if (ret == -1) { cgc_printf("bad book.\n"); return -1; } cgc_test_win(); cgc_free(buffer); cgc_printf("good book.\n"); return 0; }