#include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef size_t typedef __SIZE_TYPE__ size_t; #endif #ifndef pid_t #ifdef __pid_t_defined typedef __pid_t pid_t; #else typedef int pid_t; #endif /* __pid_t_defined */ #endif /* pid_t */ /* DEFINING DATA TYPES */ /* black magic - https://stackoverflow.com/q/16989730 */ /** * #define STR2(x) #x * #define STR(X) STR2(X) */ #define FILENAME "igyal_komam.txt" #define WORKDAY_COUNT 6 #define BUF_LEN 256 /* Used for reading from stdin, 1 less than `BUF_LEN` to accomodate for `\0` */ #define BUF_SCAN_STR "%255s" key_t key; /* ottegyemegafene */ typedef struct { long mtype; int n; } msg_t; static const char* WORKDAY_NAMES[WORKDAY_COUNT] = { "hétfő", "kedd", "szerda", "csütörtök", "péntek", "szombat" }; typedef enum { MONDAY = 1 << 0, TUESDAY = 1 << 1, WEDNESDAY = 1 << 2, THURSDAY = 1 << 3, FRIDAY = 1 << 4, SATURDAY = 1 << 5 } workday_t; typedef int workdays_t; typedef struct { char* name; workdays_t available; } person_t; typedef struct { person_t* list; size_t count; size_t capacity; } people_t; workday_t dayofweek(unsigned int i) { return 1 << i; } void free_people(people_t people) { size_t i; for(i = 0; i < people.count; ++i) if(people.list[i].name) free(people.list[i].name); free(people.list); } /* MISCELLANEOUS FUNCTIONS */ void left_seek(int file, int n) { if(file) { lseek(file, -n, SEEK_CUR); return; } /* stdin */ int i; for(i = 0; i < n; ++i) ungetc(' ', stdin); /* szóköz hack */ } void flush_stdin(void) { int c; while ((c = getchar()) != '\n' && c != EOF); } void flush_file(int file) { if(!file) { flush_stdin(); return; } char c = 0; while(read(file, &c, 1) > 0 && isspace(c)); left_seek(file, 2); } size_t workday_index(workday_t workday) { /* floor(log2(workday)) */ unsigned int ret = -1; if (workday < 0) return -1; if (workday == 0) return ULONG_MAX; while(workday) { ++ret; workday >>= 1; } return ret; } /* INPUT-OUTPUT */ char peek(int file) { /** * Flushes file identified by `file` and returns * the next character to be read. */ char c = 0; int n = 0; do { n = read(file, &c, 1); } while(n > 0 && isspace(c)); if (n <= 0) return 0; left_seek(file, 1); return c; } char* read_until_space(int file) { /** * Allocates BUF_LEN characters to a new char* * and reads contents of a file identified by `file` * until it encounters a space, a control character * or EOF. * If it reaches the end of the buffer before encountering * any of the above, it returns 0 instead. * Assumes valid `file`. */ char* ret = (char*)calloc(BUF_LEN, sizeof(char)); char input = 0; int i; for(i = 0; i < BUF_LEN; ++i) { int n = read(file, &input, 1); if (n <= 0 || iscntrl(input) || isspace(input)) return ret; ret[i] = input; } free(ret); return 0; } char* stdin_until_space(void) { char* ret = (char*)calloc(BUF_LEN, sizeof(char)); char input = 0; int i; for(i = 0; i < BUF_LEN; ++i) { input = getchar(); if (input <= 0 || iscntrl(input) || isspace(input)) return ret; ret[i] = input; } free(ret); return 0; } workday_t str_to_workday(char* workday_str) { size_t i; for(i = 0; i < WORKDAY_COUNT; ++i) { if (strcmp(WORKDAY_NAMES[i], workday_str) == 0) { return dayofweek(i); break; } } return 0; } workday_t read_workday(int file) { char* workday_str; if(file) workday_str = read_until_space(file); else workday_str = stdin_until_space(); workday_t ret = str_to_workday(workday_str); free(workday_str); return ret; } workdays_t stdin_workdays() { workdays_t ret = 0; int c = 1; while(c != '\n' && c > 0) { int i = 0; char buf[BUF_LEN]; while((c = getchar()) > 0 && !isspace(c)) { buf[i++] = c; } buf[i] = 0; printf("%s\n", buf); ret |= str_to_workday(buf); } return ret; } workdays_t read_workdays(int file) { if(!file) return stdin_workdays(); workday_t workday = read_workday(file); workdays_t ret = workday; char input = 0; int n = 0; flush_file(file); n = read(file, &input, 1); while(n > 0 && (input == ' ' || input == '\t')) { workday = read_workday(file); ret |= workday; flush_file(file); n = read(file, &input, 1); } return ret; } person_t read_person(int file) { person_t ret; ret.name = read_until_space(file); ret.available = read_workdays(file); return ret; } people_t read_all(int file) { people_t ret; ret.count = 0; ret.capacity = 4; ret.list = (person_t*)malloc(ret.capacity * sizeof(person_t)); while(peek(file)) { if (ret.count >= ret.capacity) { ret.capacity <<= 1; ret.list = (person_t*)realloc(ret.list, ret.capacity * sizeof(person_t)); } ret.list[ret.count] = read_person(file); ++ret.count; } return ret; } void save_people(people_t people) { size_t i, j; int file = open(FILENAME, O_WRONLY | O_TRUNC | O_NONBLOCK); fcntl(file, F_SETFD, FD_CLOEXEC); for(i = 0; i < people.count; ++i) { write(file, people.list[i].name, strlen(people.list[i].name)); for(j = 0; j < WORKDAY_COUNT; ++j) { if(people.list[i].available & dayofweek(j)){ write(file, " ", 1); write(file, WORKDAY_NAMES[j], strlen(WORKDAY_NAMES[j])); } } write(file, "\n", 1); } } /* DATA MANAGMENT */ person_t* find_person(people_t* people, char* name) { size_t i; for(i = 0; i < people->count; ++i) if(strcmp(people->list[i].name, name) == 0) return people->list + i; return 0; } workday_t workday_after(workday_t workday) { size_t idx = workday_index(workday); if(idx >= WORKDAY_COUNT - 1) return MONDAY; return 1 << (idx + 1); } char* stringify_persons(person_t persons[], size_t count) { char* ret = (char*)calloc(BUF_LEN, sizeof(char)); size_t i, p = 0; for(i = 0; i < count; ++i) { strcpy(ret + p, persons[i].name); p += strlen(persons[i].name); ret[p++] = ','; ret[p++] = ' '; } if (i > 0) { ret[p-2] = ' '; /* ez kelleni fog */ ret[p-1] = 0; } return ret; } char* stringify_people(people_t* people) { return stringify_persons(people->list, people->count); } size_t count_space(char* buf) { size_t ret = 0; while(*buf) if(*(buf++) == ' ') ++ret; return ret; } void print_day(people_t* people, int worker_limit, workday_t day) { size_t i; int remaining = worker_limit; printf("%s: ", WORKDAY_NAMES[workday_index(day)]); for(i = 0; i < people->count; ++i) { if (people->list[i].available & day) { printf("%s, ", people->list[i].name); if(--remaining <= 0) break; } } printf("\b\b \n"); } void print_all_days(people_t people, int worker_limit) { int i; for(i = 0; i < WORKDAY_COUNT; ++i) print_day(&people, worker_limit, dayofweek(i)); } void add_entry(people_t* people, person_t person) { if (people->count >= people->capacity) { people->capacity <<= 1; people->list = (person_t*)realloc(people->list, people->capacity * sizeof(person_t)); } people->list[people->count] = person; ++people->count; } void remove_entry(people_t* people, char* name) { char* free_name = 0; size_t i, j; for(i = 0; i < people->count; ++i) { if(strcmp(name, people->list[i].name) == 0) { if (!free_name) free_name = people->list[i].name; --people->count; /* shift list */ for(j = i; j < people->count; ++j) { people->list[j] = people->list[j+1]; } if (people->count < people->capacity >> 1) { people->capacity >>= 1; people->list = (person_t*)realloc(people->list, people->capacity * sizeof(person_t)); } } } if(free_name) free(free_name); } /* BUSINESS */ void siginfo_handler(int signo, siginfo_t *info, void *context) {} void execute_people(people_t* people, workday_t workday) { static const size_t BUS_CAPACITY = 5; size_t i, j; pid_t parent = getpid(); pid_t child1, child2; /* initalize signal stuff */ struct sigaction sigact; sigact.sa_flags = SA_SIGINFO; sigact.sa_sigaction = siginfo_handler; sigemptyset(&sigact.sa_mask); sigaction(SIGUSR1, &sigact, NULL); sigaction(SIGUSR2, &sigact, NULL); /* pipe stuff */ int pipe_fd[2][2]; pipe(pipe_fd[0]); pipe(pipe_fd[1]); int msqid = msgget(key, 0600 | IPC_CREAT); if (msqid < 0) { fprintf(stderr, "Üzenetsor létrehozása sikertelen\n"); exit(-1); } child1 = fork(); if(child1 < 0) { fprintf(stderr, "Child 1 error\n"); /* cleanup */ close(pipe_fd[0][0]); close(pipe_fd[0][1]); close(pipe_fd[1][0]); close(pipe_fd[1][1]); exit(child1); } if(child1) { child2 = fork(); if(child2 < 0) { fprintf(stderr, "Child 2 error\n"); /* cleanup */ close(pipe_fd[0][0]); close(pipe_fd[0][1]); close(pipe_fd[1][0]); close(pipe_fd[1][1]); exit(child2); } if(child2) { /* parent */ sigset_t sigset; siginfo_t siginfo; person_t bus1[BUS_CAPACITY], bus2[BUS_CAPACITY]; /* minibuszok feltöltése */ j = 0; for(i = 0; i < people->count; ++i) { if(people->list[i].available & workday) { if (j < BUS_CAPACITY) bus1[j++] = people->list[i]; else if (j < 2*BUS_CAPACITY) bus2[j++ - BUS_CAPACITY] = people->list[i]; else break; } } char *bus1_str = stringify_persons(bus1, j < BUS_CAPACITY ? j : BUS_CAPACITY), *bus2_str = stringify_persons(bus2, j <= BUS_CAPACITY ? 0 : j - BUS_CAPACITY); printf("Mai nap: %s\n", WORKDAY_NAMES[workday_index(workday)]); char buf[BUF_LEN]; sigwaitinfo(&sigset, &siginfo); // child 1 sigwaitinfo(&sigset, &siginfo); // child 2 write(pipe_fd[0][1], bus1_str, BUF_LEN); write(pipe_fd[1][1], bus2_str, BUF_LEN); usleep(50); msg_t msg; int res = msgrcv(msqid, &msg, BUF_LEN, 42, 1); printf("Az első busz %d embert hozott\n", msg.n); res = msgrcv(msqid, &msg, BUF_LEN, 42, 2); printf("A második busz %d embert hozott\n", msg.n); waitpid(child1, 0, 0); waitpid(child2, 0, 0); free(bus1_str); free(bus2_str); } else { /* child 2 */ usleep(50); union sigval sigval; sigval.sival_int = 69420; sigqueue(parent, SIGUSR1, sigval); usleep(50); char buf[BUF_LEN]; read(pipe_fd[1][0], buf, BUF_LEN); printf("Busz 2: %s\n", buf); msg_t msg = {42, count_space(buf)}; msgsnd(msqid, &msg, sizeof(int), 2); exit(0); } } else { /* child 1 */ usleep(50); union sigval sigval; sigval.sival_int = 69420; sigqueue(parent, SIGUSR1, sigval); usleep(50); char buf[BUF_LEN]; read(pipe_fd[0][0], buf, BUF_LEN); printf("Busz 1: %s\n", buf); msg_t msg = {42, count_space(buf)}; msgsnd(msqid, &msg, sizeof(int), 1); exit(0); } /* cleanup */ close(pipe_fd[0][0]); close(pipe_fd[0][1]); close(pipe_fd[1][0]); close(pipe_fd[1][1]); } int main(int argc, char* argv[]) { people_t people; bool need_save = false; workday_t current_day = MONDAY; workdays_t new_avail; char buffer[BUF_LEN]; int file = open(FILENAME, O_RDONLY | O_CREAT | O_NONBLOCK, 0666); fcntl(file, F_SETFD, FD_CLOEXEC); setlocale(LC_ALL, ""); if (file == -1) { fprintf(stderr, "Hiba a fájl megnyitása közben!\n"); return -1; } key = ftok(argv[0], 'x'); people = read_all(file); close(file); printf("Jelentkezők száma: %lu\n", people.count); while(true) { bool exit = false; printf("Válassz egy lehetőséget (írj be egy számot):\n\n"); printf("1. Új jelentkező felvétele\n"); printf("2. Meglévő jelentkező módosítása\n"); printf("3. Következő napi busz indítása\n"); printf("4. Kilépés\n\n"); switch(getchar()) { case '1': printf("Új jelentkező neve: "); person_t person; person.available = 0; person.name = malloc(BUF_LEN); scanf(BUF_SCAN_STR, person.name); printf("Milyen napokon ér rá %s? (ékezetes kisbetűvel, szóközzel elválasztva)\n", person.name); new_avail = read_workdays(stdin->_fileno /* 0 */ ); person.available = new_avail; add_entry(&people, person); need_save = true; printf("%s hozzáadva\n", person.name); break; case '2': printf("Jelentkezők listája: "); char* ppl_str = stringify_people(&people); printf("%s\n", ppl_str); free(ppl_str); printf("\n\nJelentkező neve: "); char name[BUF_LEN]; scanf(BUF_SCAN_STR, name); person_t* person_p = find_person(&people, name); if(!person_p) { fprintf(stderr, "Nincs %s nevű jelentkező\n", name); break; } printf("Milyen napokon ér rá %s? (ékezetes kisbetűvel, szóközzel elválasztva)\n", name); new_avail = read_workdays(stdin->_fileno /* 0 */ ); person_p->available = new_avail; need_save = true; break; case '3': printf("\n\n"); execute_people(&people, current_day); printf("\n\n"); current_day = workday_after(current_day); break; case -1: fprintf(stderr, "Received EOF\n"); exit = true; break; case '4': printf("Kilépés...\n"); exit = true; break; default: continue; } flush_stdin(); if(exit) break; } if(need_save) save_people(people); free_people(people); return 0; }