/* ************************************************************************ * File: house.c Part of CircleMUD * * Usage: Handling of player houses * * * * All rights reserved. See license.doc for complete information. * * * * Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University * * CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. * ************************************************************************ */ #include "conf.h" #include "sysdep.h" #include "structs.h" #include "comm.h" #include "handler.h" #include "db.h" #include "interpreter.h" #include "utils.h" #include "house.h" #include "constants.h" /* external functions */ struct obj_data *Obj_from_store(struct obj_file_elem object, int *location); int Obj_to_store(struct obj_data *obj, FILE *fl, int location); /* local globals */ struct house_control_rec house_control[MAX_HOUSES]; int num_of_houses = 0; /* local functions */ int House_get_filename(room_vnum vnum, char *filename, size_t maxlen); int House_load(room_vnum vnum); int House_save(struct obj_data *obj, FILE *fp, int location); void House_restore_weight(struct obj_data *obj); void House_delete_file(room_vnum vnum); int find_house(room_vnum vnum); void House_save_control(void); void hcontrol_list_houses(struct char_data *ch); void hcontrol_build_house(struct char_data *ch, char *arg); void hcontrol_destroy_house(struct char_data *ch, char *arg); void hcontrol_pay_house(struct char_data *ch, char *arg); int Crash_load_house_xapobjs(room_vnum rvnum); ACMD(do_hcontrol); ACMD(do_house); #define MAX_BAG_ROWS 5 extern int xap_objs; /* First, the basics: finding the filename; loading/saving objects */ /* Return a filename given a house vnum */ int House_get_filename(room_vnum vnum, char *filename, size_t maxlen) { if (vnum == NOWHERE) return (0); snprintf(filename, maxlen, LIB_HOUSE"%d.house", vnum); return (1); } /* Load all objects for a house */ int House_load(room_vnum vnum) { FILE *fl; char filename[MAX_STRING_LENGTH]; struct obj_file_elem object; room_rnum rnum; int i; if(xap_objs) { return (Crash_load_house_xapobjs(vnum)); } if ((rnum = real_room(vnum)) == NOWHERE) return (0); if (!House_get_filename(vnum, filename, sizeof(filename))) return (0); if (!(fl = fopen(filename, "r+b"))) /* no file found */ return (0); while (!feof(fl)) { fread(&object, sizeof(struct obj_file_elem), 1, fl); if (ferror(fl)) { perror("SYSERR: Reading house file in House_load"); fclose(fl); return (0); } if (!feof(fl)) obj_to_room(Obj_from_store(object, &i), rnum); } fclose(fl); return (1); } /* Save all objects for a house (recursive; initial call must be followed by a call to House_restore_weight) Assumes file is open already. */ int House_save(struct obj_data *obj, FILE *fp, int location) { struct obj_data *tmp; int result; if (obj) { House_save(obj->next_content, fp, location); House_save(obj->contains, fp, MIN(0, location) - 1); result = Obj_to_store(obj, fp, location); if (!result) return (0); for (tmp = obj->in_obj; tmp; tmp = tmp->in_obj) GET_OBJ_WEIGHT(tmp) -= GET_OBJ_WEIGHT(obj); } return (1); } /* restore weight of containers after House_save has changed them for saving */ void House_restore_weight(struct obj_data *obj) { if (obj) { House_restore_weight(obj->contains); House_restore_weight(obj->next_content); if (obj->in_obj) GET_OBJ_WEIGHT(obj->in_obj) += GET_OBJ_WEIGHT(obj); } } /* Save all objects in a house */ void House_crashsave(room_vnum vnum) { int rnum; char buf[MAX_STRING_LENGTH]; FILE *fp; if ((rnum = real_room(vnum)) == NOWHERE) return; if (!House_get_filename(vnum, buf, sizeof(buf))) return; if (!(fp = fopen(buf, "wb"))) { perror("SYSERR: Error saving house file"); return; } if (!House_save(world[rnum].contents, fp, 0)) { fclose(fp); return; } fclose(fp); House_restore_weight(world[rnum].contents); REMOVE_BIT_AR(ROOM_FLAGS(rnum), ROOM_HOUSE_CRASH); } /* Delete a house save file */ void House_delete_file(room_vnum vnum) { char filename[MAX_INPUT_LENGTH]; FILE *fl; if (!House_get_filename(vnum, filename, sizeof(filename))) return; if (!(fl = fopen(filename, "rb"))) { if (errno != ENOENT) log("SYSERR: Error deleting house file #%d. (1): %s", vnum, strerror(errno)); return; } fclose(fl); if (remove(filename) < 0) log("SYSERR: Error deleting house file #%d. (2): %s", vnum, strerror(errno)); } /* List all objects in a house file */ void House_listrent(struct char_data *ch, room_vnum vnum) { FILE *fl; char filename[MAX_STRING_LENGTH]; char buf[MAX_STRING_LENGTH]; struct obj_file_elem object; struct obj_data *obj; int i; if (!House_get_filename(vnum, filename, sizeof(filename))) return; if (!(fl = fopen(filename, "rb"))) { send_to_char(ch, "No objects on file for house #%d.\r\n", vnum); return; } *buf = '\0'; while (!feof(fl)) { fread(&object, sizeof(struct obj_file_elem), 1, fl); if (ferror(fl)) { fclose(fl); return; } if (!feof(fl) && (obj = Obj_from_store(object, &i)) != NULL) { send_to_char(ch, " [%5d] (%5dau) %s\r\n", GET_OBJ_VNUM(obj), GET_OBJ_RENT(obj), obj->short_description); free_obj(obj); } } fclose(fl); } /****************************************************************** * Functions for house administration (creation, deletion, etc. * *****************************************************************/ int find_house(room_vnum vnum) { int i; for (i = 0; i < num_of_houses; i++) if (house_control[i].vnum == vnum) return (i); return (NOWHERE); } /* Save the house control information */ void House_save_control(void) { FILE *fl; if (!(fl = fopen(HCONTROL_FILE, "wb"))) { perror("SYSERR: Unable to open house control file."); return; } /* write all the house control recs in one fell swoop. Pretty nifty, eh? */ fwrite(house_control, sizeof(struct house_control_rec), num_of_houses, fl); fclose(fl); } /* call from boot_db - will load control recs, load objs, set atrium bits */ /* should do sanity checks on vnums & remove invalid records */ void House_boot(void) { struct house_control_rec temp_house; room_rnum real_house, real_atrium; FILE *fl; memset((char *)house_control,0,sizeof(struct house_control_rec)*MAX_HOUSES); if (!(fl = fopen(HCONTROL_FILE, "rb"))) { if (errno == ENOENT) log(" House control file '%s' does not exist.", HCONTROL_FILE); else perror("SYSERR: " HCONTROL_FILE); return; } while (!feof(fl) && num_of_houses < MAX_HOUSES) { fread(&temp_house, sizeof(struct house_control_rec), 1, fl); if (feof(fl)) break; if (get_name_by_id(temp_house.owner) == NULL) continue; /* owner no longer exists -- skip */ if ((real_house = real_room(temp_house.vnum)) == NOWHERE) continue; /* this vnum doesn't exist -- skip */ if (find_house(temp_house.vnum) != NOWHERE) continue; /* this vnum is already a house -- skip */ if ((real_atrium = real_room(temp_house.atrium)) == NOWHERE) continue; /* house doesn't have an atrium -- skip */ if (temp_house.exit_num < 0 || temp_house.exit_num >= NUM_OF_DIRS) continue; /* invalid exit num -- skip */ if (TOROOM(real_house, temp_house.exit_num) != real_atrium) continue; /* exit num mismatch -- skip */ house_control[num_of_houses++] = temp_house; SET_BIT_AR(ROOM_FLAGS(real_house), ROOM_HOUSE); SET_BIT_AR(ROOM_FLAGS(real_house), ROOM_PRIVATE); SET_BIT_AR(ROOM_FLAGS(real_atrium), ROOM_ATRIUM); House_load(temp_house.vnum); } fclose(fl); House_save_control(); } /* "House Control" functions */ const char *HCONTROL_FORMAT = "Usage: hcontrol build <house vnum> <exit direction> <player name>\r\n" " hcontrol destroy <house vnum>\r\n" " hcontrol pay <house vnum>\r\n" " hcontrol show\r\n"; void hcontrol_list_houses(struct char_data *ch) { int i; char *timestr, *temp; char built_on[128], last_pay[128], own_name[MAX_NAME_LENGTH + 1]; if (!num_of_houses) { send_to_char(ch, "No houses have been defined.\r\n"); return; } send_to_char(ch, "Address Atrium Build Date Guests Owner Last Paymt\r\n" "------- ------ ---------- ------ ------------ ----------\r\n"); for (i = 0; i < num_of_houses; i++) { /* Avoid seeing <UNDEF> entries from self-deleted people. -gg 6/21/98 */ if ((temp = get_name_by_id(house_control[i].owner)) == NULL) continue; if (house_control[i].built_on) { timestr = asctime(localtime(&(house_control[i].built_on))); *(timestr + 10) = '\0'; strlcpy(built_on, timestr, sizeof(built_on)); } else strcpy(built_on, "Unknown"); /* strcpy: OK (for 'strlen("Unknown") < 128') */ if (house_control[i].last_payment) { timestr = asctime(localtime(&(house_control[i].last_payment))); *(timestr + 10) = '\0'; strlcpy(last_pay, timestr, sizeof(built_on)); } else strcpy(last_pay, "None"); /* strcpy: OK (for 'strlen("None") < 128') */ /* Now we need a copy of the owner's name to capitalize. -gg 6/21/98 */ strcpy(own_name, temp); /* strcpy: OK (names guaranteed <= MAX_NAME_LENGTH+1) */ send_to_char(ch, "%7d %7d %-10s %2d %-12s %s\r\n", house_control[i].vnum, house_control[i].atrium, built_on, house_control[i].num_of_guests, CAP(own_name), last_pay); House_list_guests(ch, i, TRUE); } } void hcontrol_build_house(struct char_data *ch, char *arg) { char arg1[MAX_INPUT_LENGTH]; struct house_control_rec temp_house; room_vnum virt_house, virt_atrium; room_rnum real_house, real_atrium; sh_int exit_num; long owner; if (num_of_houses >= MAX_HOUSES) { send_to_char(ch, "Max houses already defined.\r\n"); return; } /* first arg: house's vnum */ arg = one_argument(arg, arg1); if (!*arg1) { send_to_char(ch, "%s", HCONTROL_FORMAT); return; } virt_house = atoi(arg1); if ((real_house = real_room(virt_house)) == NOWHERE) { send_to_char(ch, "No such room exists.\r\n"); return; } if ((find_house(virt_house)) != NOWHERE) { send_to_char(ch, "House already exists.\r\n"); return; } /* second arg: direction of house's exit */ arg = one_argument(arg, arg1); if (!*arg1) { send_to_char(ch, "%s", HCONTROL_FORMAT); return; } if ((exit_num = search_block(arg1, dirs, FALSE)) < 0 && (exit_num = search_block(arg1, abbr_dirs, FALSE)) < 0) { send_to_char(ch, "'%s' is not a valid direction.\r\n", arg1); return; } if (TOROOM(real_house, exit_num) == NOWHERE) { send_to_char(ch, "There is no exit %s from room %d.\r\n", dirs[exit_num], virt_house); return; } real_atrium = TOROOM(real_house, exit_num); virt_atrium = GET_ROOM_VNUM(real_atrium); if (TOROOM(real_atrium, rev_dir[exit_num]) != real_house) { send_to_char(ch, "A house's exit must be a two-way door.\r\n"); return; } /* third arg: player's name */ one_argument(arg, arg1); if (!*arg1) { send_to_char(ch, "%s", HCONTROL_FORMAT); return; } if ((owner = get_id_by_name(arg1)) < 0) { send_to_char(ch, "Unknown player '%s'.\r\n", arg1); return; } temp_house.mode = HOUSE_PRIVATE; temp_house.vnum = virt_house; temp_house.atrium = virt_atrium; temp_house.exit_num = exit_num; temp_house.built_on = time(0); temp_house.last_payment = 0; temp_house.owner = owner; temp_house.num_of_guests = 0; house_control[num_of_houses++] = temp_house; SET_BIT_AR(ROOM_FLAGS(real_house), ROOM_HOUSE); SET_BIT_AR(ROOM_FLAGS(real_house), ROOM_PRIVATE); SET_BIT_AR(ROOM_FLAGS(real_atrium), ROOM_ATRIUM); House_crashsave(virt_house); send_to_char(ch, "House built. Mazel tov!\r\n"); House_save_control(); } void hcontrol_destroy_house(struct char_data *ch, char *arg) { int i, j; room_rnum real_atrium, real_house; if (!*arg) { send_to_char(ch, "%s", HCONTROL_FORMAT); return; } if ((i = find_house(atoi(arg))) == NOWHERE) { send_to_char(ch, "Unknown house.\r\n"); return; } if ((real_atrium = real_room(house_control[i].atrium)) == NOWHERE) log("SYSERR: House %d had invalid atrium %d!", atoi(arg), house_control[i].atrium); else REMOVE_BIT_AR(ROOM_FLAGS(real_atrium), ROOM_ATRIUM); if ((real_house = real_room(house_control[i].vnum)) == NOWHERE) log("SYSERR: House %d had invalid vnum %d!", atoi(arg), house_control[i].vnum); else { REMOVE_BIT_AR(ROOM_FLAGS(real_house), ROOM_HOUSE); REMOVE_BIT_AR(ROOM_FLAGS(real_house), ROOM_PRIVATE); REMOVE_BIT_AR(ROOM_FLAGS(real_house), ROOM_HOUSE_CRASH); } House_delete_file(house_control[i].vnum); for (j = i; j < num_of_houses - 1; j++) house_control[j] = house_control[j + 1]; num_of_houses--; send_to_char(ch, "House deleted.\r\n"); House_save_control(); /* * Now, reset the ROOM_ATRIUM flag on all existing houses' atriums, * just in case the house we just deleted shared an atrium with another * house. --JE 9/19/94 */ for (i = 0; i < num_of_houses; i++) if ((real_atrium = real_room(house_control[i].atrium)) != NOWHERE) SET_BIT_AR(ROOM_FLAGS(real_atrium), ROOM_ATRIUM); } void hcontrol_pay_house(struct char_data *ch, char *arg) { int i; if (!*arg) send_to_char(ch, "%s", HCONTROL_FORMAT); else if ((i = find_house(atoi(arg))) == NOWHERE) send_to_char(ch, "Unknown house.\r\n"); else { mudlog(NRM, MAX(LVL_IMMORT, GET_INVIS_LEV(ch)), TRUE, "Payment for house %s collected by %s.", arg, GET_NAME(ch)); house_control[i].last_payment = time(0); House_save_control(); send_to_char(ch, "Payment recorded.\r\n"); } } /* The hcontrol command itself, used by imms to create/destroy houses */ ACMD(do_hcontrol) { char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH]; half_chop(argument, arg1, arg2); if (is_abbrev(arg1, "build")) hcontrol_build_house(ch, arg2); else if (is_abbrev(arg1, "destroy")) hcontrol_destroy_house(ch, arg2); else if (is_abbrev(arg1, "pay")) hcontrol_pay_house(ch, arg2); else if (is_abbrev(arg1, "show")) hcontrol_list_houses(ch); else send_to_char(ch, "%s", HCONTROL_FORMAT); } /* The house command, used by mortal house owners to assign guests */ ACMD(do_house) { char arg[MAX_INPUT_LENGTH]; int i, j, id; one_argument(argument, arg); if (!ROOM_FLAGGED(IN_ROOM(ch), ROOM_HOUSE)) send_to_char(ch, "You must be in your house to set guests.\r\n"); else if ((i = find_house(GET_ROOM_VNUM(IN_ROOM(ch)))) == NOWHERE) send_to_char(ch, "Um.. this house seems to be screwed up.\r\n"); else if (GET_IDNUM(ch) != house_control[i].owner) send_to_char(ch, "Only the primary owner can set guests.\r\n"); else if (!*arg) House_list_guests(ch, i, FALSE); else if ((id = get_id_by_name(arg)) < 0) send_to_char(ch, "No such player.\r\n"); else if (id == GET_IDNUM(ch)) send_to_char(ch, "It's your house!\r\n"); else { for (j = 0; j < house_control[i].num_of_guests; j++) if (house_control[i].guests[j] == id) { for (; j < house_control[i].num_of_guests; j++) house_control[i].guests[j] = house_control[i].guests[j + 1]; house_control[i].num_of_guests--; House_save_control(); send_to_char(ch, "Guest deleted.\r\n"); return; } if (house_control[i].num_of_guests == MAX_GUESTS) { send_to_char(ch, "You have too many guests.\r\n"); return; } j = house_control[i].num_of_guests++; house_control[i].guests[j] = id; House_save_control(); send_to_char(ch, "Guest added.\r\n"); } } /* Misc. administrative functions */ /* crash-save all the houses */ void House_save_all(void) { int i; room_rnum real_house; for (i = 0; i < num_of_houses; i++) if ((real_house = real_room(house_control[i].vnum)) != NOWHERE) if (ROOM_FLAGGED(real_house, ROOM_HOUSE_CRASH)) House_crashsave(house_control[i].vnum); } /* note: arg passed must be house vnum, so there. */ int House_can_enter(struct char_data *ch, room_vnum house) { int i, j; if (GET_LEVEL(ch) >= LVL_GRGOD || (i = find_house(house)) == NOWHERE) return (1); switch (house_control[i].mode) { case HOUSE_PRIVATE: if (GET_IDNUM(ch) == house_control[i].owner) return (1); for (j = 0; j < house_control[i].num_of_guests; j++) if (GET_IDNUM(ch) == house_control[i].guests[j]) return (1); } return (0); } void House_list_guests(struct char_data *ch, int i, int quiet) { int j, num_printed; char *temp; if (house_control[i].num_of_guests == 0) { if (!quiet) send_to_char(ch, " Guests: None\r\n"); return; } send_to_char(ch, " Guests: "); for (num_printed = j = 0; j < house_control[i].num_of_guests; j++) { /* Avoid <UNDEF>. -gg 6/21/98 */ if ((temp = get_name_by_id(house_control[i].guests[j])) == NULL) continue; num_printed++; send_to_char(ch, "%c%s ", UPPER(*temp), temp + 1); } if (num_printed == 0) send_to_char(ch, "all dead"); send_to_char(ch, "\r\n"); } int Crash_load_house_xapobjs(room_vnum rvnum) { FILE *fl; char fname[MAX_STRING_LENGTH]; char buf1[MAX_STRING_LENGTH]; char buf2[MAX_STRING_LENGTH]; char line[256]; int t[13],danger,zwei=0; struct obj_data *temp; int locate=0, j, nr,k,num_objs=0; struct obj_data *obj1; struct obj_data *cont_row[MAX_BAG_ROWS]; struct extra_descr_data *new_descr; room_rnum rrnum; if ((rrnum = real_room(rvnum)) == NOWHERE) return 0; if (!House_get_filename(rvnum, fname, sizeof(fname))) return 0; if (!(fl = fopen(fname, "r+b"))) { if (errno != ENOENT) { /* if it fails, NOT because of no file */ sprintf(buf1, "SYSERR: READING HOUSE FILE %s (5)", fname); perror(buf1); } return 0; } for (j = 0;j < MAX_BAG_ROWS;j++) cont_row[j] = NULL; /* empty all cont lists (you never know ...) */ if(!feof(fl)) get_line(fl, line); while (!feof(fl)) { temp=NULL; /* first, we get the number. Not too hard. */ if(*line == '#') { if (sscanf(line, "#%d", &nr) != 1) { continue; } /* we have the number, check it, load obj. */ if (nr == NOTHING) { /* then it is unique */ temp = create_obj(); temp->item_number=NOTHING; } else if (nr < 0) { continue; } else { if(nr >= 999999) continue; temp=read_object(nr,VIRTUAL); if (!temp) { get_line(fl, line); continue; } } get_line(fl,line); sscanf(line,"%d %d %d %d %d %d %d %d %d %d %d %d %d",t, t + 1, t + 2, t + 3, t + 4, t + 5, t + 6, t + 7, t + 8, t + 9, t + 10, t + 11, t + 12); locate=t[0]; GET_OBJ_VAL(temp,0) = t[1]; GET_OBJ_VAL(temp,1) = t[2]; GET_OBJ_VAL(temp,2) = t[3]; GET_OBJ_VAL(temp,3) = t[4]; GET_OBJ_VAL(temp,4) = t[5]; GET_OBJ_VAL(temp,5) = t[6]; GET_OBJ_VAL(temp,6) = t[7]; GET_OBJ_VAL(temp,7) = t[8]; GET_OBJ_EXTRA(temp)[0] = t[9]; GET_OBJ_EXTRA(temp)[1] = t[10]; GET_OBJ_EXTRA(temp)[2] = t[11]; GET_OBJ_EXTRA(temp)[3] = t[12]; get_line(fl,line); /* read line check for xap. */ if(!strcmp("XAP",line)) { /* then this is a Xap Obj, requires special care */ if ((temp->name = fread_string(fl, buf2)) == NULL) { temp->name = "undefined"; } if ((temp->short_description = fread_string(fl, buf2)) == NULL) { temp->short_description = "undefined"; } if ((temp->description = fread_string(fl, buf2)) == NULL) { temp->description = "undefined"; } if ((temp->action_description = fread_string(fl, buf2)) == NULL) { temp->action_description=0; } if (!get_line(fl, line) || (sscanf(line, "%d %d %d %d %d %d %d %d", t,t+1,t+2,t+3,t+4,t+5,t+6,t+7) != 8)) { fprintf(stderr, "Format error in first numeric line (expecting _x_ args)"); return 0; } temp->obj_flags.type_flag = t[0]; temp->obj_flags.wear_flags[0] = t[1]; temp->obj_flags.wear_flags[1] = t[2]; temp->obj_flags.wear_flags[2] = t[3]; temp->obj_flags.wear_flags[3] = t[4]; temp->obj_flags.weight = t[5]; temp->obj_flags.cost = t[6]; temp->obj_flags.cost_per_day = t[7]; /* buf2 is error codes pretty much */ strcat(buf2, ", after numeric constants (expecting E/#xxx)"); /* we're clearing these for good luck */ for (j = 0; j < MAX_OBJ_AFFECT; j++) { temp->affected[j].location = APPLY_NONE; temp->affected[j].modifier = 0; } free_extra_descriptions(temp->ex_description); temp->ex_description = NULL; get_line(fl,line); for (k=j=zwei=0;!zwei && !feof(fl);) { switch (*line) { case 'E': CREATE(new_descr, struct extra_descr_data, 1); new_descr->keyword = fread_string(fl, buf2); new_descr->description = fread_string(fl, buf2); new_descr->next = temp->ex_description; temp->ex_description = new_descr; get_line(fl,line); break; case 'A': if (j >= MAX_OBJ_AFFECT) { log("SYSERR: Too many object affectations in loading house file"); danger=1; } get_line(fl, line); sscanf(line, "%d %d", t, t + 1); temp->affected[j].location = t[0]; temp->affected[j].modifier = t[1]; j++; get_line(fl,line); break; case '$': case '#': zwei=1; break; default: zwei=1; break; } } /* exit our for loop */ } /* exit our xap loop */ if(temp != NULL) { num_objs++; obj_to_room(temp, rrnum); } else { continue; } /*No need to check if its equipped since rooms can't equip things --firebird_223*/ for (j = MAX_BAG_ROWS-1;j > -locate;j--) if (cont_row[j]) { /* no container -> back to ch's inventory */ for (;cont_row[j];cont_row[j] = obj1) { obj1 = cont_row[j]->next_content; obj_to_room(cont_row[j], rrnum); } cont_row[j] = NULL; } if (j == -locate && cont_row[j]) { /* content list existing */ if (GET_OBJ_TYPE(temp) == ITEM_CONTAINER) { /* take item ; fill ; give to char again */ obj_from_room(temp); temp->contains = NULL; for (;cont_row[j];cont_row[j] = obj1) { obj1 = cont_row[j]->next_content; obj_to_obj(cont_row[j], temp); } obj_to_room(temp, rrnum); /* add to inv first ... */ } else { /* object isn't container -> empty content list */ for (;cont_row[j];cont_row[j] = obj1) { obj1 = cont_row[j]->next_content; obj_to_room(cont_row[j], rrnum); } cont_row[j] = NULL; } } if (locate < 0 && locate >= -MAX_BAG_ROWS) { /* let obj be part of content list but put it at the list's end thus having the items in the same order as before renting */ obj_from_room(temp); if ((obj1 = cont_row[-locate-1])) { while (obj1->next_content) obj1 = obj1->next_content; obj1->next_content = temp; } else cont_row[-locate-1] = temp; } } else { get_line(fl, line); } } fclose(fl); return 1; }