all repos — nimisewi_c @ 77b56ea88c330f352c7adddf6725d95a44bdc8e2

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 <config.h>
 30#include <err.h>
 31#include <stdio.h>
 32#include <stdlib.h>
 33#include <unistd.h>
 34
 35#ifdef HAVE_BSD_STRING_H
 36#include <bsd/string.h>
 37#else
 38#include <string.h>
 39#endif
 40
 41#include <sys/types.h>
 42#include <sys/time.h>
 43
 44#include "nimisewi.h"
 45#include "nimitoki.h" /* nimi_toki, suli_pi_nimi_toki */
 46
 47/* struct to hold stuff useful for random index generation */
 48struct nanpa_nimi {
 49    int nanpa_nimi; /* number of words - 1 */
 50    int pi_li_lon;  /* whether to insert 'pi' or not */
 51    int nanpa_pi;   /* index to insert 'pi', if pi_li_lon is 1 */
 52    int *nanpa_sewi_nimi; /* random indices of words */
 53    size_t suli_pi_nimi_sewi; /* length of generated phrase */
 54};
 55
 56static void
 57open_e_nanpa_sewi(void)
 58{
 59    /* initialize pseudorandom generator using pid, microseconds and seconds
 60     *
 61     * for such silly program there's no need to implement cryptographically
 62     * secure random number generator.
 63     */
 64
 65    pid_t pid;
 66    struct timeval time;
 67
 68    gettimeofday(&time, NULL);
 69    pid = getpid();
 70    srand(pid * time.tv_usec * time.tv_sec);
 71}
 72
 73static const char
 74*pana_e_nimi(const int nanpa_nimi)
 75{
 76    /* wrapper function to get word from array
 77     *
 78     * noun phrases in toki pona could have arbitrary amount of words and they
 79     * are left grouped (the leftmost word is main, and words to the right
 80     * are modifying it:
 81     *
 82     * ((nimi) sewi)
 83     *
 84     * special word 'pi' could be used to alter this grouping order to achieve
 85     * something like english preposition 'of'
 86     *
 87     * ((suli) pi ((nimi) mute))
 88     *
 89     * this functions inserts 'pi' in the middle to avoid generating
 90     * very heavy phrases.
 91     */
 92
 93    if (nanpa_nimi == -1) {
 94        return "pi";
 95    } else if ((unsigned long) nanpa_nimi > suli_pi_nimi_toki) {
 96        err(EXIT_FAILURE, "index out of bounds");
 97    } else {
 98        return nimi_toki[nanpa_nimi];
 99    }
100}
101
102static void
103nanpa_nimi_pana_e_pi(struct nanpa_nimi *nn)
104{
105    /* handle a 'pi' instertion */
106    if (nn->nanpa_nimi == 2) {
107        /* this is made to allow for phrases with following structures:
108         *
109         * - word1 word2 word3
110         * - word1 pi word2 word3
111         */
112        nn->pi_li_lon = rand() % 2;
113    } else if (nn->nanpa_nimi > 2) {
114        nn->pi_li_lon = 1;
115    }
116    if (nn->pi_li_lon) {
117        /* since we insert whole word, number of words must be increased too */
118        nn->nanpa_nimi++;
119        nn->nanpa_pi = (nn->nanpa_nimi / 2);
120    }
121}
122
123static struct nanpa_nimi
124*pana_e_nanpa_nimi(void)
125{
126    /* generate nanpa_nimi with all the values useful for phrase generation
127     *
128     * when used, one should call weka_e_nanpa_nimi();
129     */
130
131    int i;
132    struct nanpa_nimi *nn;
133
134    nn = malloc(sizeof(struct nanpa_nimi));
135    if (nn == NULL) {
136        return NULL;
137    }
138
139    /* initialize nanpa_nimi with default values */
140    nn->pi_li_lon = 0;
141    nn->nanpa_pi = -1;
142    nn->nanpa_sewi_nimi = NULL;
143    nn->suli_pi_nimi_sewi = 0;
144
145    nn->nanpa_nimi = (rand() % 6);
146
147    /* to use with arbitrary wordlist, remove following function call */
148    nanpa_nimi_pana_e_pi(nn);
149
150    nn->nanpa_sewi_nimi = calloc(nn->nanpa_nimi + 1, sizeof(int));
151    if (nn->nanpa_sewi_nimi == NULL) {
152        free(nn);
153        return NULL;
154    }
155    for (i = 0; i <= nn->nanpa_nimi; i++) {
156        nn->nanpa_sewi_nimi[i] = rand() % suli_pi_nimi_toki;
157    }
158    if (nn->pi_li_lon) {
159        nn->nanpa_sewi_nimi[nn->nanpa_pi] = -1;
160    }
161
162    for (i = 0; i <= nn->nanpa_nimi; i++) {
163        nn->suli_pi_nimi_sewi += sizeof(char);
164        nn->suli_pi_nimi_sewi += strlen(pana_e_nimi(nn->nanpa_sewi_nimi[i]));
165    }
166
167    return nn;
168}
169
170static void
171weka_e_nanpa_nimi(struct nanpa_nimi *nn)
172{
173    if (nn != NULL) {
174        free(nn->nanpa_sewi_nimi);
175        free(nn);
176    }
177}
178
179char
180*nimi_sewi()
181{
182    int i;
183    char *nimi_pana;
184    struct nanpa_nimi *nn;
185
186    open_e_nanpa_sewi();
187
188    nn = pana_e_nanpa_nimi();
189
190    nimi_pana = calloc(nn->suli_pi_nimi_sewi + 1, sizeof(char));
191    if (nimi_pana == NULL) {
192        weka_e_nanpa_nimi(nn);
193        return NULL;
194    }
195
196    for (i = 0; i < nn->nanpa_nimi; i++) {
197#ifdef HAVE_STRLCAT
198        strlcat(nimi_pana,
199                pana_e_nimi(nn->nanpa_sewi_nimi[i]),
200                nn->suli_pi_nimi_sewi);
201        strlcat(nimi_pana, " ", nn->suli_pi_nimi_sewi);
202#else
203        strcat(nimi_pana,
204               pana_e_nimi(nn->nanpa_sewi_nimi[i]));
205        strcat(nimi_pana, " ");
206#endif
207    }
208#ifdef HAVE_STRLCAT
209    strlcat(nimi_pana,
210            pana_e_nimi(nn->nanpa_sewi_nimi[i]),
211            nn->suli_pi_nimi_sewi);
212#else
213    strcat(nimi_pana,
214           pana_e_nimi(nn->nanpa_sewi_nimi[i]));
215#endif
216
217    weka_e_nanpa_nimi(nn);
218
219    return nimi_pana;
220}
221
222void
223weka_e_nimi_sewi(char *nimi_sewi)
224{
225    if (nimi_sewi != NULL) {
226        free(nimi_sewi);
227    }
228}