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}