1 /* pk-cmd-misc.c - Miscellaneous commands. */
2
3 /* Copyright (C) 2019, 2020, 2021 Jose E. Marchesi */
4
5 /* This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <config.h>
20 #include <assert.h>
21 #include <time.h>
22 #include <stdlib.h> /* For system. */
23 #include "xalloc.h"
24
25 #include "findprog.h"
26 #include "readline.h"
27
28 #include "poke.h"
29 #include "pk-cmd.h"
30 #include "pk-utils.h"
31
32 static int
pk_cmd_exit(int argc,struct pk_cmd_arg argv[],uint64_t uflags)33 pk_cmd_exit (int argc, struct pk_cmd_arg argv[], uint64_t uflags)
34 {
35 /* exit CODE */
36
37 int code;
38 assert (argc == 1);
39 if (PK_CMD_ARG_TYPE (argv[0]) == PK_CMD_ARG_NULL)
40 code = 0;
41 else
42 code = (int) PK_CMD_ARG_INT (argv[0]);
43
44 poke_exit_p = 1;
45 poke_exit_code = code;
46 return 1;
47 }
48
49 static int
pk_cmd_version(int argc,struct pk_cmd_arg argv[],uint64_t uflags)50 pk_cmd_version (int argc, struct pk_cmd_arg argv[], uint64_t uflags)
51 {
52 /* version */
53 pk_print_version (1 /* hand_p */);
54 return 1;
55 }
56
57 /* Call the info command for the poke documentation, using
58 the requested node. */
59 static int
pk_cmd_doc(int argc,struct pk_cmd_arg argv[],uint64_t uflags)60 pk_cmd_doc (int argc, struct pk_cmd_arg argv[], uint64_t uflags)
61 {
62 int ret = 1;
63
64 /* This command is inherently interactive. So if we're not
65 supposed to be in interactive mode, then do nothing. */
66 if (poke_interactive_p)
67 {
68 char *cmd = NULL;
69
70 /* Unless the doc viewer is set to `less', try first to use
71 `info'. */
72
73 if (STRNEQ (poke_doc_viewer, "less"))
74 {
75 const char info_prog_name[] = "info";
76 const char *ip = find_in_path (info_prog_name);
77 if (STRNEQ (ip, info_prog_name))
78 {
79 int size = 0;
80 int bytes = 64;
81 do
82 {
83 size = bytes + 1;
84 cmd = xrealloc (cmd, size);
85 bytes = snprintf (cmd, size, "info -f \"%s/poke.info\"",
86 poke_infodir);
87 }
88 while (bytes >= size);
89
90 if (argv[0].type == PK_CMD_ARG_STR)
91 {
92 const char *node = argv[0].val.str;
93 cmd = xrealloc (cmd, bytes + 7 + strlen (node));
94 strcat (cmd, " -n \"");
95 strcat (cmd, node);
96 strcat (cmd, "\"");
97 }
98 }
99 }
100
101 /* Fallback to `less' if no `info' was found. */
102 if (cmd == NULL)
103 {
104 const char info_prog_name[] = "less";
105 const char *ip = find_in_path (info_prog_name);
106 if (STREQ (ip, info_prog_name))
107 {
108 pk_term_class ("error");
109 pk_puts ("error: ");
110 pk_term_end_class ("error");
111 pk_puts ("a suitable documentation viewer is not installed.\n");
112 return 0;
113 }
114
115 asprintf (&cmd, "less -p '%s' %s/poke.text",
116 argv[0].val.str, poke_docdir);
117 assert (cmd != NULL);
118 }
119
120 /* Open the documentation at the requested page. */
121 ret = (0 == system (cmd));
122 free (cmd);
123 }
124
125 return ret;
126 }
127
128 static int
pk_cmd_jmd(int argc,struct pk_cmd_arg argv[],uint64_t uflags)129 pk_cmd_jmd (int argc, struct pk_cmd_arg argv[], uint64_t uflags)
130 {
131 assert (argc == 0);
132
133 static const char *strings[] =
134 {
135 "<jmd> I never win on the pokies.",
136 "<jmd> \"poke\" is an anagram of \"peok\" which is the "
137 "Indonesian word for \"dent\".",
138 "<jmd> Good morning poke(wo)men!",
139 "<jmd> jemarch: I though it was a dismissal for a golden duck.",
140 "<jmd> Just have a .do-what-i-want command and be done "
141 "with it.",
142 "<jmd> It looks as if Jose was poking late into the night!",
143 "<jmd> I inadvertently pushed some experimental crap.",
144 "<jmd> Whey are they called \"pickles\"? They ought to be "
145 "called \"pokles\".",
146 "<jmd> I thought I'd just poke my nose in here and see what's "
147 "going on.",
148 "[jmd wonders if jemarch has \"export EDITOR=poke\" in his .bashrc]",
149 "<jmd> everytime I type \"killall -11 poke\", poke segfaults.",
150 "<jemarch> a bugfix a day keeps jmd away",
151 "<jmd> Did you know that \"Poke\" is a Hawaiian salad?",
152 "<jmd> I never place periods after my strncpy.",
153 "<jmd> pokie pokie!",
154 "<jmd> Hokus Pokus",
155 "<mnabipoor> I wanted making a zero-length array for a long (!) time",
156 NULL
157 };
158 static int num_strings = 0;
159
160 if (num_strings == 0)
161 {
162 srand (time (NULL));
163 const char **p = strings;
164 while (*p++ != NULL)
165 num_strings++;
166 }
167
168 pk_printf ("%s\n", strings[rand () % num_strings]);
169 return 1;
170 }
171
172 /* A completer to provide the node names of the info
173 documentation. */
174 char *
doc_completion_function(const char * x,int state)175 doc_completion_function (const char *x, int state)
176 {
177 static char **nodelist = NULL;
178 if (nodelist == NULL)
179 {
180 int n_nodes = 0;
181 char nlfile[256];
182 snprintf (nlfile, 256, "%s/nodelist", poke_docdir);
183 FILE *fp = fopen (nlfile, "r");
184 if (fp == NULL)
185 return NULL;
186 char *lineptr = NULL;
187 size_t size = 0;
188 while (!feof (fp))
189 {
190 int x = getline (&lineptr, &size, fp);
191 if (x != -1)
192 {
193 nodelist = xrealloc (nodelist, ++n_nodes * sizeof (*nodelist));
194 lineptr [strlen (lineptr) - 1] = '\0';
195 nodelist[n_nodes - 1] = xstrdup (lineptr);
196 }
197 }
198 fclose (fp);
199 free (lineptr);
200 nodelist = xrealloc (nodelist, ++n_nodes * sizeof (*nodelist));
201 nodelist[n_nodes - 1] = NULL;
202 }
203
204 static int idx = 0;
205 if (state == 0)
206 idx = 0;
207 else
208 ++idx;
209
210 int len = strlen (x);
211 while (1)
212 {
213 const char *name = nodelist[idx];
214 if (name == NULL)
215 break;
216
217 if (strncmp (name, x, len) == 0)
218 return xstrdup (name);
219
220 idx++;
221 }
222
223 return NULL;
224 }
225
226
227 const struct pk_cmd quit_cmd =
228 {"quit", "?i", "", 0, NULL, pk_cmd_exit, "quit [CODE]", NULL};
229
230 const struct pk_cmd exit_cmd =
231 {"exit", "?i", "", 0, NULL, pk_cmd_exit, "exit [CODE]", NULL};
232
233 const struct pk_cmd version_cmd =
234 {"version", "", "", 0, NULL, pk_cmd_version, "version", NULL};
235
236 const struct pk_cmd jmd_cmd =
237 {"jmd", "", "", 0, NULL, pk_cmd_jmd, "jmd", NULL};
238
239 const struct pk_cmd doc_cmd =
240 {"doc", "?s", "", 0, NULL, pk_cmd_doc, "doc [section]", doc_completion_function};
241