BRL-CAD
cmdhist.c
Go to the documentation of this file.
1 /* C M D H I S T . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1998-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 
21 #include "common.h"
22 
23 #include <string.h>
24 
25 #include "bu/cmd.h"
26 #include "bu/malloc.h"
27 #include "bu/str.h"
28 
29 /**
30  * Stores the given command with start and finish times in the
31  * history vls'es. 'status' is either BRLCAD_OK or BRLCAD_ERROR.
32  */
33 HIDDEN void
34 cmdhist_record(struct bu_cmdhist_obj *chop, struct bu_vls *cmdp, struct timeval *start, struct timeval *finish, int status)
35 {
36  struct bu_cmdhist *new_hist;
37  const char *eol = "\n";
38 
39  if (UNLIKELY(BU_STR_EQUAL(bu_vls_addr(cmdp), eol)))
40  return;
41 
42  BU_ALLOC(new_hist, struct bu_cmdhist);
43  bu_vls_init(&new_hist->h_command);
44  bu_vls_vlscat(&new_hist->h_command, cmdp);
45  new_hist->h_start = *start;
46  new_hist->h_finish = *finish;
47  new_hist->h_status = status;
48  BU_LIST_INSERT(&chop->cho_head.l, &new_hist->l);
49 
50  chop->cho_curr = &chop->cho_head;
51 }
52 
53 
54 HIDDEN int
55 cmdhist_timediff(struct timeval *tvdiff, struct timeval *start, struct timeval *finish)
56 {
57  if (UNLIKELY(finish->tv_sec == 0 && finish->tv_usec == 0))
58  return -1;
59  if (UNLIKELY(start->tv_sec == 0 && start->tv_usec == 0))
60  return -1;
61 
62  tvdiff->tv_sec = finish->tv_sec - start->tv_sec;
63  tvdiff->tv_usec = finish->tv_usec - start->tv_usec;
64  if (tvdiff->tv_usec < 0) {
65  --tvdiff->tv_sec;
66  tvdiff->tv_usec += 1000000L;
67  }
68 
69  return 0;
70 }
71 
72 
73 int
74 bu_cmdhist_history(void *data, int argc, const char *argv[])
75 {
76  FILE *fp;
77  int with_delays = 0;
78  struct bu_cmdhist *hp, *hp_prev;
79  struct bu_vls str = BU_VLS_INIT_ZERO;
80  struct timeval tvdiff;
81  struct bu_cmdhist_obj *chop = (struct bu_cmdhist_obj *)data;
82 
83  if (argc < 2 || 5 < argc) {
84  bu_log("Usage: %s -delays\nList command history.\n", argv[0]);
85  return BRLCAD_ERROR;
86  }
87 
88  fp = NULL;
89  while (argc >= 3) {
90  const char *delays = "-delays";
91  const char *outfile = "-outfile";
92 
93  if (BU_STR_EQUAL(argv[2], delays))
94  with_delays = 1;
95  else if (BU_STR_EQUAL(argv[2], outfile)) {
96  if (fp != NULL) {
97  fclose(fp);
98  bu_log("%s: -outfile option given more than once\n", argv[0]);
99  return BRLCAD_ERROR;
100  } else if (argc < 4 || BU_STR_EQUAL(argv[3], delays)) {
101  bu_log("%s: I need a file name\n", argv[0]);
102  return BRLCAD_ERROR;
103  } else {
104  fp = fopen(argv[3], "ab+");
105  if (UNLIKELY(fp == NULL)) {
106  bu_log("%s: error opening file", argv[0]);
107  return BRLCAD_ERROR;
108  }
109  --argc;
110  ++argv;
111  }
112  } else {
113  bu_log("Invalid option %s\n", argv[2]);
114  }
115  --argc;
116  ++argv;
117  }
118 
119  for (BU_LIST_FOR(hp, bu_cmdhist, &chop->cho_head.l)) {
120  bu_vls_trunc(&str, 0);
121  hp_prev = BU_LIST_PREV(bu_cmdhist, &hp->l);
122  if (with_delays && BU_LIST_NOT_HEAD(hp_prev, &chop->cho_head.l)) {
123  if (cmdhist_timediff(&tvdiff, &(hp_prev->h_finish), &(hp->h_start)) >= 0)
124  bu_vls_printf(&str, "delay %ld %ld\n", (long)tvdiff.tv_sec,
125  (long)tvdiff.tv_usec);
126 
127  }
128 
129  if (hp->h_status == BRLCAD_ERROR)
130  bu_vls_printf(&str, "# ");
131  bu_vls_vlscat(&str, &(hp->h_command));
132 
133  if (fp != NULL)
134  bu_vls_fwrite(fp, &str);
135  else
136  bu_log("%s\n", bu_vls_addr(&str));
137  }
138 
139  if (fp != NULL)
140  fclose(fp);
141 
142  return BRLCAD_OK;
143 }
144 
145 
146 int
147 bu_cmdhist_add(void *clientData, int argc, const char **argv)
148 {
149  struct bu_cmdhist_obj *chop = (struct bu_cmdhist_obj *)clientData;
150  struct bu_vls vls = BU_VLS_INIT_ZERO;
151  struct timeval zero;
152 
153  if (argc != 3) {
154  bu_log("ERROR: expecting only three arguments\n");
155  return BRLCAD_ERROR;
156  }
157 
158  if (UNLIKELY(argv[2][0] == '\n' || argv[2][0] == '\0'))
159  return BRLCAD_OK;
160 
161  bu_vls_strcpy(&vls, argv[2]);
162  if (argv[2][strlen(argv[2])-1] != '\n')
163  bu_vls_putc(&vls, '\n');
164 
165  zero.tv_sec = zero.tv_usec = 0L;
166  cmdhist_record(chop, &vls, &zero, &zero, BRLCAD_OK);
167 
168  bu_vls_free(&vls);
169 
170  /* newly added command is in chop->cho_curr */
171  return BRLCAD_OK;
172 }
173 
174 
175 int
176 bu_cmdhist_prev(void *clientData, int argc, const char **UNUSED(argv))
177 {
178  struct bu_cmdhist_obj *chop = (struct bu_cmdhist_obj *)clientData;
179  struct bu_cmdhist *hp;
180 
181  if (argc != 2) {
182  bu_log("ERROR: expecting only two arguments\n");
183  return BRLCAD_ERROR;
184  }
185 
186  hp = BU_LIST_PLAST(bu_cmdhist, chop->cho_curr);
187  if (BU_LIST_NOT_HEAD(hp, &chop->cho_head.l))
188  chop->cho_curr = hp;
189 
190  /* result is in chop->cho_curr */
191  return BRLCAD_OK;
192 }
193 
194 
195 int
196 bu_cmdhist_curr(void *clientData, int argc, const char **UNUSED(argv))
197 {
198  struct bu_cmdhist_obj *chop = (struct bu_cmdhist_obj *)clientData;
199 
200  if (argc != 2) {
201  bu_log("ERROR: expecting only two arguments\n");
202  return BRLCAD_ERROR;
203  }
204 
205  if (BU_LIST_NOT_HEAD(chop->cho_curr, &chop->cho_head.l)) {
206  /* result is in chop->cho_curr */
207  return BRLCAD_OK;
208  }
209 
210  /* no commands exist yet */
211  return BRLCAD_ERROR;
212 }
213 
214 
215 int
216 bu_cmdhist_next(void *clientData, int argc, const char **UNUSED(argv))
217 {
218  struct bu_cmdhist_obj *chop = (struct bu_cmdhist_obj *)clientData;
219 
220  if (argc != 2) {
221  bu_log("ERROR: expecting only two arguments\n");
222  return BRLCAD_ERROR;
223  }
224 
225  if (BU_LIST_IS_HEAD(chop->cho_curr, &chop->cho_head.l))
226  return BRLCAD_ERROR;
227 
228  chop->cho_curr = BU_LIST_PNEXT(bu_cmdhist, chop->cho_curr);
229  if (BU_LIST_IS_HEAD(chop->cho_curr, &chop->cho_head.l))
230  return BRLCAD_ERROR;
231 
232  /* result is in chop->cho_curr */
233  return BRLCAD_OK;
234 }
235 
236 
237 /*
238  * Local Variables:
239  * mode: C
240  * tab-width: 8
241  * indent-tabs-mode: t
242  * c-file-style: "stroustrup"
243  * End:
244  * ex: shiftwidth=4 tabstop=8
245  */
HIDDEN void cmdhist_record(struct bu_cmdhist_obj *chop, struct bu_vls *cmdp, struct timeval *start, struct timeval *finish, int status)
Definition: cmdhist.c:34
void bu_vls_init(struct bu_vls *vp)
Definition: vls.c:56
#define BU_LIST_FOR(p, structure, hp)
Definition: list.h:365
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
#define BU_LIST_INSERT(old, new)
Definition: list.h:183
struct bu_list l
Definition: cmd.h:54
struct bu_cmdhist * cho_curr
Definition: cmd.h:66
void bu_vls_trunc(struct bu_vls *vp, int len)
Definition: vls.c:198
struct timeval h_start
Definition: cmd.h:56
Header file for the BRL-CAD common definitions.
struct timeval h_finish
Definition: cmd.h:57
int bu_cmdhist_curr(void *clientData, int argc, const char **argv)
Definition: cmdhist.c:196
#define HIDDEN
Definition: common.h:86
int bu_cmdhist_prev(void *clientData, int argc, const char **argv)
Definition: cmdhist.c:176
void bu_vls_free(struct bu_vls *vp)
Definition: vls.c:248
COMPLEX data[64]
Definition: fftest.c:34
HIDDEN int cmdhist_timediff(struct timeval *tvdiff, struct timeval *start, struct timeval *finish)
Definition: cmdhist.c:55
#define BU_LIST_IS_HEAD(p, hp)
Definition: list.h:322
struct bu_cmdhist cho_head
Definition: cmd.h:65
#define BU_LIST_PLAST(structure, p)
Definition: list.h:424
int bu_cmdhist_add(void *clientData, int argc, const char **argv)
Add a command to the history list.
Definition: cmdhist.c:147
#define BU_ALLOC(_ptr, _type)
Definition: malloc.h:223
#define BRLCAD_OK
Definition: defines.h:71
void bu_vls_fwrite(FILE *fp, const struct bu_vls *vp)
Definition: vls.c:544
#define BU_LIST_PNEXT(structure, p)
Definition: list.h:422
#define UNUSED(parameter)
Definition: common.h:239
char * bu_vls_addr(const struct bu_vls *vp)
Definition: vls.c:111
int bu_cmdhist_history(void *data, int argc, const char *argv[])
Definition: cmdhist.c:74
int h_status
Definition: cmd.h:58
struct bu_vls h_command
Definition: cmd.h:55
Definition: cmd.h:53
void bu_vls_printf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:694
void bu_vls_strcpy(struct bu_vls *vp, const char *s)
Definition: vls.c:310
#define BU_VLS_INIT_ZERO
Definition: vls.h:84
void bu_vls_vlscat(struct bu_vls *dest, const struct bu_vls *src)
Definition: vls.c:415
Definition: vls.h:56
#define BRLCAD_ERROR
Definition: defines.h:72
void bu_vls_putc(struct bu_vls *vp, int c)
Definition: vls.c:666
#define BU_LIST_NOT_HEAD(p, hp)
Definition: list.h:324
#define BU_LIST_PREV(structure, hp)
Definition: list.h:310
int bu_cmdhist_next(void *clientData, int argc, const char **argv)
Definition: cmdhist.c:216
#define UNLIKELY(expression)
Definition: common.h:282
#define BU_STR_EQUAL(s1, s2)
Definition: str.h:126