static void read_lines(char *filename, FILE *fp) { // if (verbose > 0) // { fprintf(stderr, "%s: read_lines(%s)\n", prog, filename); } char original[MAXLINE+2]; // from fgets() char expanded[MAXLINE+2]; // after macro expansion char buffer[MAXLINE+2]; // working copy, safe to modify char whsp[] = " \t\n\v\f\r"; // whitespace characters int line_number = 0; int recipe_line_number = 0; bool have_target = false; // recipes must follow targets while (fgets(original, MAXLINE, fp) != NULL) { // it is possible that the input line was too long, so terminate the string cleanly original[MAXLINE] = '\n'; original[MAXLINE+1] = '\0'; line_number++; if (verbose > 0) printf("%s: %s: line %d: %s\n", "prog", filename, line_number, original); // assume original[] is constructed properly // assume expanded[] is large enough macro_expand(original, expanded); if (verbose > 0) printf("%s: %s: line %d: %s\n", "prog", filename, line_number, expanded); strcpy(buffer, expanded); // copy, safe to modify char *buf = buffer; while (*buf == ' ') buf++; // skip past leading spaces (not tabs!) char *p_hash = strchr(buf, '#'); // a comment starts with # if (p_hash != NULL) { *p_hash = '\0'; } // remove the comment int n = 0; // remove trailing whitespace while (buf[n] != '\0') { int n1 = strspn(&buf[n], whsp); // buf[n .. n+n1-1] is whitespace int n2 = strcspn(&buf[n + n1], whsp); // buf[n+n1 .. n+n1+n2-1] is not if (n2 == 0) { buf[n] = '\0'; break; } // remove trailing whitespace n += n1 + n2; } if (buf[0] == '\0') // nothing left? { continue; } char *p_colon = strchr(buf, ':'); // : indicates a target-prerequisite line char *p_equal = strchr(buf, '='); // = indicates a macro definition if (buffer[0] == '\t') { recipe_line_number++; if (verbose > 0) printf(" diagnosis: recipe line %d\n", recipe_line_number); if (have_target == false) { fprintf(stderr, "%s: %s: line %d: recipe but no target\n", prog, filename, line_number); continue; } int count = 0; while(*(buffer+1+count) != '\0') { count++; } char *recipe_temp = malloc((count+1)*sizeof(char)); set_chars(recipe_temp, buffer+1); struct target* temp_update_target = find_target(first_related_target); for(int i = 0; i < target_length; i++) { temp_update_target->target_recipes = add_recipe(temp_update_target->target_recipes, recipe_temp); if(target_length > 1) temp_update_target = temp_update_target->next; } } else if (p_colon != NULL) { first_related_target = NULL; target_length = 0; recipe_line_number = 0; if (verbose > 0) printf(" diagnosis: target-prerequisite\n"); have_target = true; char *source_start = p_colon+1; while(*source_start == ' ') { source_start++; } char *source_end = source_start; struct source *source_head = malloc(sizeof(struct source)); if(source_head == NULL) { printf("Malloc failed to allocate space for a source_head in the main program\n"); return; } if(*source_end == '\n' || *source_end == '\0' || *source_end == '\r') { source_head = add_source(source_head, ""); } while(*source_end != '\n' && *source_end != '\0' && *source_end != '\r') { if(*source_end == ' ' || *source_end == '\0') { *source_end = '\0'; int count = 0; while(*(source_start+count) != '\0') { count++; } char *source_temp = malloc((count+1)*sizeof(char)); set_chars(source_temp, source_start); source_head = add_source(source_head, source_temp); source_start = source_end+1; } if(*(source_end+1) == '\0') { int count = 0; while(*(source_start+count) != '\0') { count++; } char *source_temp = malloc((count+1)*sizeof(char)); set_chars(source_temp, source_start); source_head = add_source(source_head, source_temp); } source_end++; } char *tar_start = buf; while(*tar_start == ' ') { tar_start++; } char *tar_end = tar_start; while(*tar_end != ':' && *tar_end != '\0') { if(*tar_end == ' ' || *tar_end == '\t') { *tar_end = '\0'; if(default_goal == NULL) { int count = 0; while(*(tar_start+count) != '\0') { count++; } default_goal = malloc((count+1)*sizeof(char)); set_chars(default_goal, tar_start); } struct recipe* super_temp = malloc(sizeof(struct recipe)); super_temp->line = "replaceme"; char* temp = malloc(30 * sizeof(char)); set_chars(temp, tar_start); add_target(temp, source_head, super_temp); if(first_related_target == NULL) { int count = 0; while(*(tar_start+count) != '\0') { count++; } first_related_target = malloc((count+1)*sizeof(char)); if (first_related_target == NULL) { printf("malloc failed\n"); } for(int i = 0; i < count+2; i++) { *(first_related_target+i) = *(tar_start+i); } } target_length++; tar_start = (tar_end+1); } if(*(tar_end+1) == ':' ) { if(*(tar_end) != ' ') { int count = 0; while(*(tar_start+count) != ':') { count++; } *(tar_end+1) = '\0'; char *tar_temp = malloc((count+1)*sizeof(char)); set_chars(tar_temp, tar_start); struct recipe* super_temp = malloc(sizeof(struct recipe)); super_temp->line = "replaceme"; add_target(tar_temp, source_head, super_temp); if(first_related_target == NULL) { int count = 0; while(*(tar_start+count) != '\0') { count++; } first_related_target = malloc((count+1)*sizeof(char)); if (first_related_target == NULL) { printf("malloc failed\n"); } set_chars(first_related_target, tar_start); } } } tar_end++; } } else if (p_equal != NULL) { first_related_target = NULL; target_length = 0; if (verbose > 0) printf(" diagnosis: macro definition\n"); have_target = false; // name = body // *p_equal is '=' char *name_start = buf; while (*name_start == ' ' || *name_start == '\t') // skip past spaces and tabs { name_start++; } char *name_end = p_equal-1; while (*name_end == ' ' || *name_end == '\t') { name_end--; } name_end++; *name_end = '\0'; char *body_start = p_equal+1; while (*body_start == ' ' || *body_start == '\t') { body_start++; } char *body_end = body_start; while (*body_end != '\0') // end of string { body_end++; } while (*body_end == ' ' || *body_end == '\t') { body_end--; } body_end++; *body_end = '\0'; if (verbose > 1) macro_list_print(); macro_set(name_start, body_start); if (verbose > 1) macro_list_print(); } else if (strncmp("include", buf, 7) == 0) { first_related_target = NULL; target_length = 0; if (verbose > 0) printf(" diagnosis: include\n"); have_target = false; char *name_start = buf + 7; // skip past "include" while (*name_start == ' ' || *name_start == '\t') // skip past spaces and tabs { name_start++; } if (*name_start == '\0') { // following GNU Make, this is not an error if (verbose > 0) fprintf(stderr, "%s: %s: line %d: include but no filename\n", prog, filename, line_number); continue; } else if (*name_start == '\'' || *name_start == '"') // quoted filename { // find matching quote, remove it char *q = name_start + 1; // skip past ' or " while (*q != *name_start && *q != '\0') q++; // find end of string or line if (*q == '\0') { fprintf(stderr, "%s: %s: line %d: file name error [%s]\n", prog, filename, line_number, name_start); continue; } name_start++; // skip past opening quote *q = '\0'; // remove closing quote } pr8_read(name_start); } else { if (verbose > 0) printf(" diagnosis: something else\n"); have_target = false; // fprintf(stderr, "%s: %s: line %d: not recognized: %s", prog, filename, line_number, original); } } // if (ferror(fp)) // error when reading the file // { fprintf(stderr, "%s: %s: read error: %s\n", prog, filename, strerror(errno)); } return; }
void Recipes::load() { // for documentation, refer to add_recipe() below cout << "\nLoading crafting recipes..."; // add_recipe("recipe name", {}, {}, {}, {}, {}); // materials add_recipe(C::STICK_ID, {}, {}, { { C::TREE_ID, 1 } }, {}, { { C::STICK_ID, 1 } }); add_recipe(C::BRANCH_ID, {}, {}, { { C::TREE_ID, 1 } }, {}, { { C::BRANCH_ID, 1 } }); add_recipe(C::VINE_ID, {}, {}, { { C::TREE_ID, 1 } }, {}, { { C::VINE_ID, 1 } }); add_recipe(C::STONE_ID, {}, {}, {}, {}, { { C::STONE_ID, 1 } }); // you can always get a stone add_recipe(C::ARROW_ID, {}, { { C::ARROWHEAD_ID, 1 }, { C::STICK_ID, 1 } }, {}, {}, { { C::ARROW_ID, 1 } }); // a stick and an arrowhead add_recipe(C::ARROWHEAD_ID, { { C::STONE_ID, 2 } }, { { C::STONE_ID, 1 } }, {}, {}, { { C::ARROWHEAD_ID, 3 } }); // requires two stones but only one is made into arrowheads add_recipe(C::BOARD_ID, { { C::AXE_ID, 1 } }, {}, { {C::TREE_ID, 1} }, {}, { { C::BOARD_ID, 1 } }); // equipment add_recipe(C::STAFF_ID, { { C::AXE_ID, 1 } }, { { C::BRANCH_ID, 1 } }, {}, {}, { { C::STAFF_ID, 1 } }); add_recipe(C::AXE_ID, {}, { { C::BRANCH_ID, 1 }, { C::STONE_ID, 1 }, { C::VINE_ID, 1 } }, {}, {}, { { C::AXE_ID, 1 } }); // maybe need a sharp stone? add_recipe(C::BOW_ID, {}, { { C::BRANCH_ID, 1 }, { C::VINE_ID, 1 } }, {}, {}, { { C::BOW_ID, 1 } }); add_recipe(C::SWORD_ID, {}, { { C::STONE_ID, 2 }, { C::STICK_ID, 1 } }, {}, {}, { { C::SWORD_ID, 1 } }); // other add_recipe(C::FORGE_ID, {}, { { C::STONE_ID, 20 } }, {}, {}, { { C::FORGE_ID, 1 } }); // 20 stones to build a forge (which are immovable) add_recipe(C::SMELTER_ID, {}, { { C::STONE_ID, 30 } }, {}, {}, { { C::SMELTER_ID, 1 } }); // 30 stones to build a smelter (which are immovable) add_recipe(C::CHEST_ID, { { C::AXE_ID, 1 } }, { {C::BOARD_ID, 5} }, {}, {}, { { C::CHEST_ID, 1 } }); }