all repos — nimisewi_c @ e7e4e22b69a0c9965c2d4f96903ae647165e99d3

simple random toki pona phrase generator

nimisewi.c (view raw)

  1/* Copyright (c) 2021, la-ninpre
  2 * 
  3 * Permission to use, copy, modify, and/or distribute this software for any
  4 * purpose with or without fee is hereby granted, provided that the above
  5 * copyright notice and this permission notice appear in all copies.
  6 * 
  7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 13 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 14 *
 15 * *************************************************************************
 16 * 
 17 * this file contains main code for nimisewi.
 18 * 
 19 * nimisewi is a small program that generates random toki pona noun phrase.
 20 * toki pona is a small constructed language created by sonja lang 
 21 * (see https://tokipona.org).
 22 *
 23 * functions and variables here a primarily named in tokipona, just because
 24 * i can. but just in case there are annotations in english.
 25 *
 26 * sona nanpa li ike. taso ona li pali e ilo pona.
 27 */
 28
 29#include <err.h>
 30#include <stdio.h>
 31#include <stdlib.h>
 32#include <unistd.h>
 33
 34#include <string.h>
 35#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined( _NetBSD__) || defined(__DragonFly__)
 36#define HAS_STRLCAT
 37#endif
 38
 39#include <sys/types.h>
 40#include <sys/time.h>
 41
 42#include "nimisewi.h"
 43#include "nimitoki.h" /* nimi_toki, suli_pi_nimi_toki */
 44
 45static void
 46open_e_nanpa_sewi(void)
 47{
 48    /* initialize pseudorandom generator using pid, microseconds and seconds
 49     *
 50     * for such silly program there's no need to implement cryptographically
 51     * secure random number generator.
 52     */
 53
 54    pid_t pid;
 55    struct timeval time;
 56
 57    gettimeofday(&time, NULL);
 58    pid = getpid();
 59    srand(pid * time.tv_usec * time.tv_sec);
 60}
 61
 62static const char
 63*pana_e_nimi(const int nanpa_nimi)
 64{
 65    /* wrapper function to get word from array
 66     *
 67     * noun phrases in toki pona could have arbitrary amount of words and they
 68     * are left grouped (the leftmost word is main, and words to the right
 69     * are modifying it:
 70     *
 71     * ((nimi) sewi)
 72     *
 73     * special word 'pi' could be used to alter this grouping order to achieve
 74     * something like english preposition 'of'
 75     *
 76     * ((suli) pi ((nimi) mute))
 77     *
 78     * this functions inserts 'pi' in the middle to avoid generating
 79     * very heavy phrases.
 80     */
 81
 82    if (nanpa_nimi == -1) {
 83        return "pi";
 84    } else if ((unsigned long) nanpa_nimi > suli_pi_nimi_toki) {
 85        err(EXIT_FAILURE, "index out of bounds");
 86    } else {
 87        return nimi_toki[nanpa_nimi];
 88    }
 89}
 90
 91static void
 92nanpa_nimi_pana_e_pi(struct nanpa_nimi *nn)
 93{
 94    /* handle a 'pi' instertion */
 95    if (nn->nanpa_nimi == 2) {
 96        /* this is made to allow for phrases with following structures:
 97         *
 98         * - word1 word2 word3
 99         * - word1 pi word2 word3
100         */
101        nn->pi_li_lon = rand() % 2;
102    } else if (nn->nanpa_nimi > 2) {
103        nn->pi_li_lon = 1;
104    }
105    if (nn->pi_li_lon) {
106        /* since we insert whole word, number of words must be increased too */
107        nn->nanpa_nimi++;
108        nn->nanpa_pi = (nn->nanpa_nimi / 2);
109    }
110}
111
112static struct nanpa_nimi
113*pana_e_nanpa_nimi(void)
114{
115    /* generate nanpa_nimi with all the values useful for phrase generation
116     *
117     * when used, one should call weka_e_nanpa_nimi();
118     */
119
120    int i;
121    struct nanpa_nimi *nn;
122
123    nn = malloc(sizeof(struct nanpa_nimi));
124    if (nn == NULL) {
125        return NULL;
126    }
127
128    /* initialize nanpa_nimi with default values */
129    nn->pi_li_lon = 0;
130    nn->nanpa_pi = -1;
131    nn->nanpa_sewi_nimi = NULL;
132    nn->suli_pi_nimi_sewi = 0;
133
134    nn->nanpa_nimi = (rand() % 6);
135
136    /* to use with arbitrary wordlist, remove following function call */
137    nanpa_nimi_pana_e_pi(nn);
138
139    nn->nanpa_sewi_nimi = calloc(nn->nanpa_nimi + 1, sizeof(int));
140    if (nn->nanpa_sewi_nimi == NULL) {
141        free(nn);
142        return NULL;
143    }
144    for (i = 0; i <= nn->nanpa_nimi; i++) {
145        nn->nanpa_sewi_nimi[i] = rand() % suli_pi_nimi_toki;
146    }
147    if (nn->pi_li_lon) {
148        nn->nanpa_sewi_nimi[nn->nanpa_pi] = -1;
149    }
150
151    for (i = 0; i <= nn->nanpa_nimi; i++) {
152        nn->suli_pi_nimi_sewi += sizeof(char);
153        nn->suli_pi_nimi_sewi += strlen(pana_e_nimi(nn->nanpa_sewi_nimi[i]));
154    }
155
156    return nn;
157}
158
159static void
160weka_e_nanpa_nimi(struct nanpa_nimi *nn)
161{
162    if (nn != NULL) {
163        free(nn->nanpa_sewi_nimi);
164        free(nn);
165    }
166}
167
168static void
169string_cat(char *dst, const char *src, size_t size) {
170#ifdef HAS_STRLCAT
171    strlcat(dst, src, size);
172#else
173    strcat(dst, src);
174#endif
175}
176
177char
178*nimi_sewi()
179{
180    int i;
181    char *nimi_pana;
182    struct nanpa_nimi *nn;
183
184    open_e_nanpa_sewi();
185
186    nn = pana_e_nanpa_nimi();
187
188    nimi_pana = calloc(nn->suli_pi_nimi_sewi + 1, sizeof(char));
189    if (nimi_pana == NULL) {
190        weka_e_nanpa_nimi(nn);
191        return NULL;
192    }
193
194    for (i = 0; i < nn->nanpa_nimi; i++) {
195        string_cat(nimi_pana,
196                pana_e_nimi(nn->nanpa_sewi_nimi[i]),
197                nn->suli_pi_nimi_sewi);
198        string_cat(nimi_pana, " ", nn->suli_pi_nimi_sewi);
199    }
200    string_cat(nimi_pana,
201            pana_e_nimi(nn->nanpa_sewi_nimi[i]),
202            nn->suli_pi_nimi_sewi);
203
204    weka_e_nanpa_nimi(nn);
205
206    return nimi_pana;
207}
208
209void
210weka_e_nimi_sewi(char *nimi_sewi)
211{
212    if (nimi_sewi != NULL) {
213        free(nimi_sewi);
214    }
215}