2 9f7d7167 2018-04-29 stsp * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
4 9f7d7167 2018-04-29 stsp * Permission to use, copy, modify, and distribute this software for any
5 9f7d7167 2018-04-29 stsp * purpose with or without fee is hereby granted, provided that the above
6 9f7d7167 2018-04-29 stsp * copyright notice and this permission notice appear in all copies.
8 9f7d7167 2018-04-29 stsp * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 9f7d7167 2018-04-29 stsp * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 9f7d7167 2018-04-29 stsp * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 9f7d7167 2018-04-29 stsp * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 9f7d7167 2018-04-29 stsp * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 9f7d7167 2018-04-29 stsp * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 9f7d7167 2018-04-29 stsp * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 80ddbec8 2018-04-29 stsp #include <sys/queue.h>
19 9f7d7167 2018-04-29 stsp #include <curses.h>
20 9f7d7167 2018-04-29 stsp #include <panel.h>
21 9f7d7167 2018-04-29 stsp #include <locale.h>
22 9f7d7167 2018-04-29 stsp #include <stdlib.h>
23 9f7d7167 2018-04-29 stsp #include <getopt.h>
24 9f7d7167 2018-04-29 stsp #include <string.h>
25 9f7d7167 2018-04-29 stsp #include <err.h>
26 80ddbec8 2018-04-29 stsp #include <unistd.h>
28 9f7d7167 2018-04-29 stsp #include "got_error.h"
29 80ddbec8 2018-04-29 stsp #include "got_object.h"
30 80ddbec8 2018-04-29 stsp #include "got_reference.h"
31 80ddbec8 2018-04-29 stsp #include "got_repository.h"
32 80ddbec8 2018-04-29 stsp #include "got_diff.h"
34 9f7d7167 2018-04-29 stsp #ifndef nitems
35 9f7d7167 2018-04-29 stsp #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
38 9f7d7167 2018-04-29 stsp enum tog_view_id {
39 9f7d7167 2018-04-29 stsp TOG_VIEW_LOG,
40 9f7d7167 2018-04-29 stsp TOG_VIEW_DIFF,
41 9f7d7167 2018-04-29 stsp TOG_VIEW_BLAME,
44 9f7d7167 2018-04-29 stsp struct tog_cmd {
45 9f7d7167 2018-04-29 stsp const char *cmd_name;
46 9f7d7167 2018-04-29 stsp const struct got_error *(*cmd_main)(int, char *[]);
47 9f7d7167 2018-04-29 stsp void (*cmd_usage)(void);
48 9f7d7167 2018-04-29 stsp enum tog_view_id view;
49 9f7d7167 2018-04-29 stsp const char *cmd_descr;
52 9f7d7167 2018-04-29 stsp __dead void usage(void);
53 9f7d7167 2018-04-29 stsp __dead void usage_log(void);
54 9f7d7167 2018-04-29 stsp __dead void usage_diff(void);
55 9f7d7167 2018-04-29 stsp __dead void usage_blame(void);
57 9f7d7167 2018-04-29 stsp const struct got_error* cmd_log(int, char *[]);
58 9f7d7167 2018-04-29 stsp const struct got_error* cmd_diff(int, char *[]);
59 9f7d7167 2018-04-29 stsp const struct got_error* cmd_blame(int, char *[]);
61 9f7d7167 2018-04-29 stsp struct tog_cmd tog_commands[] = {
62 9f7d7167 2018-04-29 stsp { "log", cmd_log, usage_log, TOG_VIEW_LOG,
63 9f7d7167 2018-04-29 stsp "show repository history" },
64 9f7d7167 2018-04-29 stsp { "diff", cmd_diff, usage_diff, TOG_VIEW_DIFF,
65 9f7d7167 2018-04-29 stsp "compare files and directories" },
66 9f7d7167 2018-04-29 stsp { "blame", cmd_blame, usage_blame, TOG_VIEW_BLAME,
67 9f7d7167 2018-04-29 stsp "show line-by-line file history" },
70 9f7d7167 2018-04-29 stsp /* globals */
71 9f7d7167 2018-04-29 stsp WINDOW *tog_main_win;
72 9f7d7167 2018-04-29 stsp PANEL *tog_main_panel;
73 80ddbec8 2018-04-29 stsp static struct tog_log_view {
74 80ddbec8 2018-04-29 stsp WINDOW *window;
75 80ddbec8 2018-04-29 stsp PANEL *panel;
76 80ddbec8 2018-04-29 stsp } tog_log_view;
79 9f7d7167 2018-04-29 stsp usage_log(void)
82 80ddbec8 2018-04-29 stsp fprintf(stderr, "usage: %s log [-c commit] [repository-path]\n",
83 9f7d7167 2018-04-29 stsp getprogname());
87 80ddbec8 2018-04-29 stsp static const struct got_error *
88 80ddbec8 2018-04-29 stsp draw_commit(struct got_commit_object *commit, struct got_object_id *id,
89 80ddbec8 2018-04-29 stsp struct got_repository *repo)
91 80ddbec8 2018-04-29 stsp const struct got_error *err = NULL;
92 80ddbec8 2018-04-29 stsp char *logmsg0 = NULL, *logmsg = NULL;
93 80ddbec8 2018-04-29 stsp char *newline;
94 80ddbec8 2018-04-29 stsp char *line = NULL;
95 80ddbec8 2018-04-29 stsp char *id_str;
98 80ddbec8 2018-04-29 stsp err = got_object_id_str(&id_str, id);
100 80ddbec8 2018-04-29 stsp return err;
101 80ddbec8 2018-04-29 stsp logmsg0 = strdup(commit->logmsg);
102 80ddbec8 2018-04-29 stsp if (logmsg0 == NULL)
103 80ddbec8 2018-04-29 stsp return got_error_from_errno();
104 80ddbec8 2018-04-29 stsp logmsg = logmsg0;
105 80ddbec8 2018-04-29 stsp while (*logmsg == '\n')
107 80ddbec8 2018-04-29 stsp newline = strchr(logmsg, '\n');
108 80ddbec8 2018-04-29 stsp if (newline != NULL)
109 80ddbec8 2018-04-29 stsp *newline = '\0';
111 80ddbec8 2018-04-29 stsp if (asprintf(&line, "%.8s %.35s %s", id_str, commit->author,
112 80ddbec8 2018-04-29 stsp logmsg) == -1) {
113 80ddbec8 2018-04-29 stsp err = got_error_from_errno();
117 80ddbec8 2018-04-29 stsp waddstr(tog_log_view.window, line);
118 80ddbec8 2018-04-29 stsp len = strlen(line);
119 80ddbec8 2018-04-29 stsp while (len < COLS - 1) {
120 80ddbec8 2018-04-29 stsp waddch(tog_log_view.window, ' ');
123 80ddbec8 2018-04-29 stsp waddch(tog_log_view.window, '\n');
125 80ddbec8 2018-04-29 stsp free(logmsg0);
126 80ddbec8 2018-04-29 stsp free(line);
127 80ddbec8 2018-04-29 stsp return err;
129 80ddbec8 2018-04-29 stsp struct commit_queue_entry {
130 80ddbec8 2018-04-29 stsp TAILQ_ENTRY(commit_queue_entry) entry;
131 80ddbec8 2018-04-29 stsp struct got_object_id *id;
132 80ddbec8 2018-04-29 stsp struct got_commit_object *commit;
135 80ddbec8 2018-04-29 stsp static const struct got_error *
136 80ddbec8 2018-04-29 stsp draw_commits(struct got_object *root_obj, struct got_object_id *root_id,
137 80ddbec8 2018-04-29 stsp struct got_repository *repo, int selected)
139 80ddbec8 2018-04-29 stsp const struct got_error *err;
140 80ddbec8 2018-04-29 stsp struct got_commit_object *root_commit;
141 80ddbec8 2018-04-29 stsp TAILQ_HEAD(, commit_queue_entry) commits;
142 80ddbec8 2018-04-29 stsp struct commit_queue_entry *entry;
143 80ddbec8 2018-04-29 stsp int ncommits = 0;
145 80ddbec8 2018-04-29 stsp TAILQ_INIT(&commits);
147 80ddbec8 2018-04-29 stsp err = got_object_commit_open(&root_commit, repo, root_obj);
149 80ddbec8 2018-04-29 stsp return err;
151 80ddbec8 2018-04-29 stsp entry = calloc(1, sizeof(*entry));
152 80ddbec8 2018-04-29 stsp if (entry == NULL)
153 80ddbec8 2018-04-29 stsp return got_error_from_errno();
154 80ddbec8 2018-04-29 stsp entry->id = got_object_id_dup(root_id);
155 80ddbec8 2018-04-29 stsp if (entry->id == NULL) {
156 80ddbec8 2018-04-29 stsp err = got_error_from_errno();
157 80ddbec8 2018-04-29 stsp free(entry);
158 80ddbec8 2018-04-29 stsp return err;
160 80ddbec8 2018-04-29 stsp entry->commit = root_commit;
161 80ddbec8 2018-04-29 stsp TAILQ_INSERT_HEAD(&commits, entry, entry);
163 80ddbec8 2018-04-29 stsp wclear(tog_log_view.window);
165 80ddbec8 2018-04-29 stsp while (!TAILQ_EMPTY(&commits) && ncommits < LINES) {
166 80ddbec8 2018-04-29 stsp struct got_parent_id *pid;
167 80ddbec8 2018-04-29 stsp struct got_object *obj;
168 80ddbec8 2018-04-29 stsp struct got_commit_object *pcommit;
169 80ddbec8 2018-04-29 stsp struct commit_queue_entry *pentry;
171 80ddbec8 2018-04-29 stsp entry = TAILQ_FIRST(&commits);
173 80ddbec8 2018-04-29 stsp if (ncommits == selected)
174 80ddbec8 2018-04-29 stsp wstandout(tog_log_view.window);
175 80ddbec8 2018-04-29 stsp err = draw_commit(entry->commit, entry->id, repo);
176 80ddbec8 2018-04-29 stsp if (ncommits == selected)
177 80ddbec8 2018-04-29 stsp wstandend(tog_log_view.window);
180 80ddbec8 2018-04-29 stsp ncommits++;
182 80ddbec8 2018-04-29 stsp if (entry->commit->nparents == 0)
185 80ddbec8 2018-04-29 stsp /* Follow the first parent (TODO: handle merge commits). */
186 80ddbec8 2018-04-29 stsp pid = SIMPLEQ_FIRST(&entry->commit->parent_ids);
187 80ddbec8 2018-04-29 stsp err = got_object_open(&obj, repo, pid->id);
190 80ddbec8 2018-04-29 stsp if (got_object_get_type(obj) != GOT_OBJ_TYPE_COMMIT) {
191 80ddbec8 2018-04-29 stsp err = got_error(GOT_ERR_OBJ_TYPE);
195 80ddbec8 2018-04-29 stsp err = got_object_commit_open(&pcommit, repo, obj);
196 80ddbec8 2018-04-29 stsp got_object_close(obj);
200 80ddbec8 2018-04-29 stsp pentry = calloc(1, sizeof(*pentry));
201 80ddbec8 2018-04-29 stsp if (pentry == NULL) {
202 80ddbec8 2018-04-29 stsp err = got_error_from_errno();
203 80ddbec8 2018-04-29 stsp got_object_commit_close(pcommit);
206 80ddbec8 2018-04-29 stsp pentry->id = got_object_id_dup(pid->id);
207 80ddbec8 2018-04-29 stsp if (pentry->id == NULL) {
208 80ddbec8 2018-04-29 stsp err = got_error_from_errno();
209 80ddbec8 2018-04-29 stsp got_object_commit_close(pcommit);
212 80ddbec8 2018-04-29 stsp pentry->commit = pcommit;
213 80ddbec8 2018-04-29 stsp TAILQ_INSERT_TAIL(&commits, pentry, entry);
215 80ddbec8 2018-04-29 stsp TAILQ_REMOVE(&commits, entry, entry);
216 80ddbec8 2018-04-29 stsp got_object_commit_close(entry->commit);
217 80ddbec8 2018-04-29 stsp free(entry->id);
218 80ddbec8 2018-04-29 stsp free(entry);
221 80ddbec8 2018-04-29 stsp while (!TAILQ_EMPTY(&commits)) {
222 80ddbec8 2018-04-29 stsp entry = TAILQ_FIRST(&commits);
223 80ddbec8 2018-04-29 stsp TAILQ_REMOVE(&commits, entry, entry);
224 80ddbec8 2018-04-29 stsp got_object_commit_close(entry->commit);
225 80ddbec8 2018-04-29 stsp free(entry->id);
226 80ddbec8 2018-04-29 stsp free(entry);
229 80ddbec8 2018-04-29 stsp update_panels();
230 80ddbec8 2018-04-29 stsp doupdate();
231 80ddbec8 2018-04-29 stsp return err;
235 80ddbec8 2018-04-29 stsp static const struct got_error *
236 80ddbec8 2018-04-29 stsp show_log_view(struct got_object_id *start_id, struct got_repository *repo)
238 80ddbec8 2018-04-29 stsp const struct got_error *err = NULL;
239 80ddbec8 2018-04-29 stsp struct got_object *obj;
240 80ddbec8 2018-04-29 stsp int ch, done = 0, selected = 0;
241 80ddbec8 2018-04-29 stsp struct got_object_id *id = start_id;
243 80ddbec8 2018-04-29 stsp if (tog_log_view.window == NULL) {
244 80ddbec8 2018-04-29 stsp tog_log_view.window = newwin(0, 0, 0, 0);
245 80ddbec8 2018-04-29 stsp if (tog_log_view.window == NULL)
246 80ddbec8 2018-04-29 stsp return got_error_from_errno();
248 80ddbec8 2018-04-29 stsp if (tog_log_view.panel == NULL) {
249 80ddbec8 2018-04-29 stsp tog_log_view.panel = new_panel(tog_log_view.window);
250 80ddbec8 2018-04-29 stsp if (tog_log_view.panel == NULL)
251 80ddbec8 2018-04-29 stsp return got_error_from_errno();
254 80ddbec8 2018-04-29 stsp err = got_object_open(&obj, repo, id);
256 80ddbec8 2018-04-29 stsp return err;
257 80ddbec8 2018-04-29 stsp if (got_object_get_type(obj) != GOT_OBJ_TYPE_COMMIT) {
258 80ddbec8 2018-04-29 stsp err = got_error(GOT_ERR_OBJ_TYPE);
263 80ddbec8 2018-04-29 stsp err = draw_commits(obj, id, repo, selected);
265 80ddbec8 2018-04-29 stsp return err;
267 80ddbec8 2018-04-29 stsp nodelay(stdscr, FALSE);
268 80ddbec8 2018-04-29 stsp ch = wgetch(tog_log_view.window);
269 80ddbec8 2018-04-29 stsp switch (ch) {
274 80ddbec8 2018-04-29 stsp case KEY_UP:
275 80ddbec8 2018-04-29 stsp if (selected > 0)
276 80ddbec8 2018-04-29 stsp selected--;
279 80ddbec8 2018-04-29 stsp case KEY_DOWN:
280 80ddbec8 2018-04-29 stsp if (selected < LINES - 1)
281 80ddbec8 2018-04-29 stsp selected++;
286 80ddbec8 2018-04-29 stsp nodelay(stdscr, TRUE);
287 80ddbec8 2018-04-29 stsp } while (!done);
289 80ddbec8 2018-04-29 stsp got_object_close(obj);
290 80ddbec8 2018-04-29 stsp return err;
293 9f7d7167 2018-04-29 stsp const struct got_error *
294 9f7d7167 2018-04-29 stsp cmd_log(int argc, char *argv[])
296 80ddbec8 2018-04-29 stsp const struct got_error *error;
297 80ddbec8 2018-04-29 stsp struct got_repository *repo;
298 80ddbec8 2018-04-29 stsp struct got_object_id *id = NULL;
299 80ddbec8 2018-04-29 stsp char *repo_path = NULL;
300 80ddbec8 2018-04-29 stsp char *start_commit = NULL;
303 80ddbec8 2018-04-29 stsp #ifndef PROFILE
304 80ddbec8 2018-04-29 stsp if (pledge("stdio rpath wpath cpath flock proc tty", NULL) == -1)
305 80ddbec8 2018-04-29 stsp err(1, "pledge");
308 80ddbec8 2018-04-29 stsp while ((ch = getopt(argc, argv, "c:")) != -1) {
309 80ddbec8 2018-04-29 stsp switch (ch) {
311 80ddbec8 2018-04-29 stsp start_commit = optarg;
315 80ddbec8 2018-04-29 stsp /* NOTREACHED */
319 80ddbec8 2018-04-29 stsp argc -= optind;
320 80ddbec8 2018-04-29 stsp argv += optind;
322 80ddbec8 2018-04-29 stsp if (argc == 0) {
323 80ddbec8 2018-04-29 stsp repo_path = getcwd(NULL, 0);
324 80ddbec8 2018-04-29 stsp if (repo_path == NULL)
325 80ddbec8 2018-04-29 stsp return got_error_from_errno();
326 80ddbec8 2018-04-29 stsp } else if (argc == 1) {
327 80ddbec8 2018-04-29 stsp repo_path = realpath(argv[0], NULL);
328 80ddbec8 2018-04-29 stsp if (repo_path == NULL)
329 80ddbec8 2018-04-29 stsp return got_error_from_errno();
331 80ddbec8 2018-04-29 stsp usage_log();
333 80ddbec8 2018-04-29 stsp error = got_repo_open(&repo, repo_path);
334 80ddbec8 2018-04-29 stsp free(repo_path);
335 80ddbec8 2018-04-29 stsp if (error != NULL)
336 80ddbec8 2018-04-29 stsp return error;
338 80ddbec8 2018-04-29 stsp if (start_commit == NULL) {
339 80ddbec8 2018-04-29 stsp struct got_reference *head_ref;
340 80ddbec8 2018-04-29 stsp error = got_ref_open(&head_ref, repo, GOT_REF_HEAD);
341 80ddbec8 2018-04-29 stsp if (error != NULL)
342 80ddbec8 2018-04-29 stsp return error;
343 80ddbec8 2018-04-29 stsp error = got_ref_resolve(&id, repo, head_ref);
344 80ddbec8 2018-04-29 stsp got_ref_close(head_ref);
345 80ddbec8 2018-04-29 stsp if (error != NULL)
346 80ddbec8 2018-04-29 stsp return error;
348 80ddbec8 2018-04-29 stsp struct got_object *obj;
349 80ddbec8 2018-04-29 stsp error = got_object_open_by_id_str(&obj, repo, start_commit);
350 80ddbec8 2018-04-29 stsp if (error == NULL) {
351 80ddbec8 2018-04-29 stsp id = got_object_get_id(obj);
352 80ddbec8 2018-04-29 stsp if (id == NULL)
353 80ddbec8 2018-04-29 stsp error = got_error_from_errno();
356 80ddbec8 2018-04-29 stsp if (error != NULL)
357 80ddbec8 2018-04-29 stsp return error;
358 80ddbec8 2018-04-29 stsp error = show_log_view(id, repo);
360 80ddbec8 2018-04-29 stsp got_repo_close(repo);
361 80ddbec8 2018-04-29 stsp return error;
364 9f7d7167 2018-04-29 stsp __dead void
365 9f7d7167 2018-04-29 stsp usage_diff(void)
368 9f7d7167 2018-04-29 stsp fprintf(stderr, "usage: %s diff [repository-path] object1 object2\n",
369 9f7d7167 2018-04-29 stsp getprogname());
373 9f7d7167 2018-04-29 stsp const struct got_error *
374 9f7d7167 2018-04-29 stsp cmd_diff(int argc, char *argv[])
376 9f7d7167 2018-04-29 stsp return got_error(GOT_ERR_NOT_IMPL);
379 9f7d7167 2018-04-29 stsp __dead void
380 9f7d7167 2018-04-29 stsp usage_blame(void)
383 9f7d7167 2018-04-29 stsp fprintf(stderr, "usage: %s blame [repository-path] blob-object\n",
384 9f7d7167 2018-04-29 stsp getprogname());
388 9f7d7167 2018-04-29 stsp const struct got_error *
389 9f7d7167 2018-04-29 stsp cmd_blame(int argc, char *argv[])
391 9f7d7167 2018-04-29 stsp return got_error(GOT_ERR_NOT_IMPL);
394 9f7d7167 2018-04-29 stsp static const struct got_error *
395 9f7d7167 2018-04-29 stsp init_curses(void)
401 9f7d7167 2018-04-29 stsp intrflush(stdscr, FALSE);
402 9f7d7167 2018-04-29 stsp keypad(stdscr, TRUE);
404 9f7d7167 2018-04-29 stsp tog_main_win = newwin(0, 0, 0, 0);
405 9f7d7167 2018-04-29 stsp if (tog_main_win == NULL)
406 9f7d7167 2018-04-29 stsp return got_error_from_errno();
407 9f7d7167 2018-04-29 stsp tog_main_panel = new_panel(tog_main_win);
408 9f7d7167 2018-04-29 stsp if (tog_main_panel == NULL)
409 9f7d7167 2018-04-29 stsp return got_error_from_errno();
411 9f7d7167 2018-04-29 stsp return NULL;
414 9f7d7167 2018-04-29 stsp __dead void
415 9f7d7167 2018-04-29 stsp usage(void)
419 9f7d7167 2018-04-29 stsp fprintf(stderr, "usage: %s [-h] command [arg ...]\n\n"
420 9f7d7167 2018-04-29 stsp "Available commands:\n", getprogname());
421 9f7d7167 2018-04-29 stsp for (i = 0; i < nitems(tog_commands); i++) {
422 9f7d7167 2018-04-29 stsp struct tog_cmd *cmd = &tog_commands[i];
423 9f7d7167 2018-04-29 stsp fprintf(stderr, " %s: %s\n", cmd->cmd_name, cmd->cmd_descr);
429 9f7d7167 2018-04-29 stsp main(int argc, char *argv[])
431 9f7d7167 2018-04-29 stsp const struct got_error *error = NULL;
432 9f7d7167 2018-04-29 stsp struct tog_cmd *cmd = NULL;
433 9f7d7167 2018-04-29 stsp int ch, hflag = 0;
435 9f7d7167 2018-04-29 stsp setlocale(LC_ALL, "");
437 9f7d7167 2018-04-29 stsp while ((ch = getopt(argc, argv, "h")) != -1) {
438 9f7d7167 2018-04-29 stsp switch (ch) {
444 9f7d7167 2018-04-29 stsp /* NOTREACHED */
448 9f7d7167 2018-04-29 stsp argc -= optind;
449 9f7d7167 2018-04-29 stsp argv += optind;
450 9f7d7167 2018-04-29 stsp optind = 0;
452 9f7d7167 2018-04-29 stsp if (argc == 0)
453 9f7d7167 2018-04-29 stsp cmd = &tog_commands[0];
457 9f7d7167 2018-04-29 stsp for (i = 0; i < nitems(tog_commands); i++) {
458 9f7d7167 2018-04-29 stsp if (strncmp(tog_commands[i].cmd_name, argv[0],
459 9f7d7167 2018-04-29 stsp strlen(argv[0])) == 0) {
460 9f7d7167 2018-04-29 stsp cmd = &tog_commands[i];
462 9f7d7167 2018-04-29 stsp tog_commands[i].cmd_usage();
466 9f7d7167 2018-04-29 stsp if (cmd == NULL) {
467 9f7d7167 2018-04-29 stsp fprintf(stderr, "%s: unknown command '%s'\n",
468 9f7d7167 2018-04-29 stsp getprogname(), argv[0]);
473 9f7d7167 2018-04-29 stsp error = init_curses();
474 9f7d7167 2018-04-29 stsp if (error) {
475 80ddbec8 2018-04-29 stsp fprintf(stderr, "cannot initialize ncurses: %s\n", error->msg);
479 9f7d7167 2018-04-29 stsp error = cmd->cmd_main(argc, argv);
485 9f7d7167 2018-04-29 stsp fprintf(stderr, "%s: %s\n", getprogname(), error->msg);