/* Copyright (c) 2021, la-ninpre * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * ************************************************************************* * * this file contains main code for nimisewi. * * nimisewi is a small program that generates random toki pona noun phrase. * toki pona is a small constructed language created by sonja lang * (see https://tokipona.org). * * functions and variables here a primarily named in tokipona, just because * i can. but just in case there are annotations in english. * * sona nanpa li ike. taso ona li pali e ilo pona. */ #include #include #include #include #include #include #include #ifdef HAVE_BSD_STDLIB_H #include #else #include #endif #ifdef HAVE_BSD_STRING_H #include #else #include #endif #include "nimisewi.h" #include "nimitoki.h" /* nimi_toki, suli_pi_nimi_toki */ /* struct to hold stuff useful for random index generation */ struct nanpa_nimi { int nanpa_nimi; /* number of words - 1 */ int pi_li_lon; /* whether to insert 'pi' or not */ int nanpa_pi; /* index to insert 'pi', if pi_li_lon is 1 */ int *nanpa_sewi_nimi; /* random indices of words */ size_t suli_pi_nimi_sewi; /* length of generated phrase */ }; static uint32_t nsrand(uint32_t limit) { #ifdef HAVE_ARC4RANDOM_UNIFORM return arc4random_uniform(limit); #else pid_t pid; struct timeval time; gettimeofday(&time, NULL); pid = getpid(); srand(pid * time.tv_usec * time.tv_sec); return rand() % limit; #endif } static size_t catstr(char *dst, const char *src, size_t size) { #ifdef HAVE_STRLCAT return strlcat(dst, src, size); #else strncat(dst, src, size); return strlen(dst); #endif } static const char *pana_e_nimi(const int nanpa_nimi) { /* wrapper function to get word from array * * noun phrases in toki pona could have arbitrary amount of words and they * are left grouped (the leftmost word is main, and words to the right * are modifying it: * * ((nimi) sewi) * * special word 'pi' could be used to alter this grouping order to achieve * something like english preposition 'of' * * ((suli) pi ((nimi) mute)) * * this functions inserts 'pi' in the middle to avoid generating * very heavy phrases. */ if (nanpa_nimi == -1) { return "pi"; } else if ((unsigned long) nanpa_nimi > suli_pi_nimi_toki) { err(EXIT_FAILURE, "index out of bounds"); } else { return nimi_toki[nanpa_nimi]; } } static void nanpa_nimi_pana_e_pi(struct nanpa_nimi *nn) { /* handle a 'pi' instertion */ if (nn->nanpa_nimi == 2) { /* this is made to allow for phrases with following structures: * * - word1 word2 word3 * - word1 pi word2 word3 */ nn->pi_li_lon = nsrand(2); } else if (nn->nanpa_nimi > 2) { nn->pi_li_lon = 1; } if (nn->pi_li_lon) { /* since we insert whole word, number of words must be increased too */ nn->nanpa_nimi++; nn->nanpa_pi = (nn->nanpa_nimi / 2); } } static struct nanpa_nimi *pana_e_nanpa_nimi(unsigned int nanpa_nimi_sewi) { /* generate nanpa_nimi with all the values useful for phrase generation * * when used, one should call weka_e_nanpa_nimi(); */ int i; struct nanpa_nimi *nn; nn = malloc(sizeof(struct nanpa_nimi)); if (nn == NULL) { return NULL; } /* initialize nanpa_nimi with default values */ nn->pi_li_lon = 0; nn->nanpa_pi = -1; nn->nanpa_sewi_nimi = NULL; nn->suli_pi_nimi_sewi = 0; nn->nanpa_nimi = (nsrand(nanpa_nimi_sewi)); /* to use with arbitrary wordlist, remove following function call */ nanpa_nimi_pana_e_pi(nn); nn->nanpa_sewi_nimi = calloc(nn->nanpa_nimi + 1, sizeof(int)); if (nn->nanpa_sewi_nimi == NULL) { free(nn); return NULL; } for (i = 0; i <= nn->nanpa_nimi; i++) { nn->nanpa_sewi_nimi[i] = nsrand(suli_pi_nimi_toki); } if (nn->pi_li_lon) { nn->nanpa_sewi_nimi[nn->nanpa_pi] = -1; } for (i = 0; i <= nn->nanpa_nimi; i++) { nn->suli_pi_nimi_sewi += sizeof(char); nn->suli_pi_nimi_sewi += strlen(pana_e_nimi(nn->nanpa_sewi_nimi[i])); } return nn; } static void weka_e_nanpa_nimi(struct nanpa_nimi *nn) { if (nn != NULL) { free(nn->nanpa_sewi_nimi); free(nn); } } char *nimi_sewi(unsigned int nanpa_nimi_sewi) { int i; char *nimi_pana; struct nanpa_nimi *nn; nn = pana_e_nanpa_nimi(nanpa_nimi_sewi); nimi_pana = calloc(nn->suli_pi_nimi_sewi + 1, sizeof(char)); if (nimi_pana == NULL) { weka_e_nanpa_nimi(nn); err(EXIT_FAILURE, "memory allocation failed"); } for (i = 0; i < nn->nanpa_nimi; i++) { catstr(nimi_pana, pana_e_nimi(nn->nanpa_sewi_nimi[i]), nn->suli_pi_nimi_sewi); catstr(nimi_pana, " ", nn->suli_pi_nimi_sewi); } catstr(nimi_pana, pana_e_nimi(nn->nanpa_sewi_nimi[i]), nn->suli_pi_nimi_sewi); weka_e_nanpa_nimi(nn); return nimi_pana; } void weka_e_nimi_sewi(char *nimi_sewi) { if (nimi_sewi != NULL) { free(nimi_sewi); } }