BRL-CAD
rtcheck.c
Go to the documentation of this file.
1 /* R T C H E C K . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2008-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 /** @file libged/rtcheck.c
21  *
22  * The rtcheck command.
23  *
24  */
25 
26 #include "common.h"
27 
28 #include <stdlib.h>
29 
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif
33 
34 #ifdef HAVE_SYS_WAIT_H
35 # include <sys/wait.h>
36 #endif
37 
38 
39 #include "bu/cmd.h"
40 
41 
42 #include "./ged_private.h"
43 
44 
45 struct ged_rtcheck {
46 #ifdef _WIN32
47  HANDLE fd;
48  HANDLE hProcess;
49  DWORD pid;
50 #ifdef TCL_OK
51  Tcl_Channel chan;
52 #else
53  void *chan;
54 #endif
55 #else
56  int fd;
57  int pid;
58 #endif
59  FILE *fp;
60  struct bn_vlblock *vbp;
61  struct bu_list *vhead;
62  double csize;
63  struct ged *gedp;
64  Tcl_Interp *interp;
65 };
66 
68 #ifdef _WIN32
69  HANDLE fd;
70  Tcl_Channel chan;
71 #else
72  int fd;
73 #endif
74  struct ged *gedp;
75  Tcl_Interp *interp;
76 };
77 
78 
79 void
80 _ged_wait_status(struct bu_vls *logstr,
81  int status)
82 {
83  int sig = status & 0x7f;
84  int core = status & 0x80;
85  int ret = status >> 8;
86 
87  if (status == 0) {
88  bu_vls_printf(logstr, "Normal exit\n");
89  return;
90  }
91 
92  bu_vls_printf(logstr, "Abnormal exit x%x", status);
93 
94  if (core)
95  bu_vls_printf(logstr, ", core dumped");
96 
97  if (sig)
98  bu_vls_printf(logstr, ", terminating signal = %d", sig);
99  else
100  bu_vls_printf(logstr, ", return (exit) code = %d", ret);
101 }
102 
103 
104 #ifndef _WIN32
105 static void
106 rtcheck_vector_handler(ClientData clientData, int UNUSED(mask))
107 {
108  int value;
109  struct ged_rtcheck *rtcp = (struct ged_rtcheck *)clientData;
110 
111  /* Get vector output from rtcheck */
112  if ((value = getc(rtcp->fp)) == EOF) {
113  int retcode;
114  int rpid;
115 
116  Tcl_DeleteFileHandler(rtcp->fd);
117  fclose(rtcp->fp);
118 
120 
121  /* Add overlay */
122  _ged_cvt_vlblock_to_solids(rtcp->gedp, rtcp->vbp, "OVERLAPS", 0);
123  rt_vlblock_free(rtcp->vbp);
124 
125  /* wait for the forked process */
126  while ((rpid = wait(&retcode)) != rtcp->pid && rpid != -1) {
127 
128  _ged_wait_status(rtcp->gedp->ged_result_str, retcode);
129  }
130 
131  BU_PUT(rtcp, struct ged_rtcheck);
132 
133  return;
134  }
135 
136  (void)rt_process_uplot_value(&rtcp->vhead,
137  rtcp->vbp,
138  rtcp->fp,
139  value,
140  rtcp->csize,
142 }
143 
144 static void
145 rtcheck_output_handler(ClientData clientData, int UNUSED(mask))
146 {
147  int count;
148  char line[RT_MAXLINE] = {0};
149  struct rtcheck_output *rtcop = (struct rtcheck_output *)clientData;
150 
151  /* Get textual output from rtcheck */
152  count = read((int)rtcop->fd, line, RT_MAXLINE);
153  if (count <= 0) {
154  if (count < 0) {
155  perror("READ ERROR");
156  }
157  Tcl_DeleteFileHandler(rtcop->fd);
158  close(rtcop->fd);
159 
160  if (rtcop->gedp->ged_gdp->gd_rtCmdNotify != (void (*)())0)
161  rtcop->gedp->ged_gdp->gd_rtCmdNotify(0);
162 
163  BU_PUT(rtcop, struct rtcheck_output);
164  return;
165  }
166 
167  line[count] = '\0';
168  if (rtcop->gedp->ged_output_handler != (void (*)())0)
169  rtcop->gedp->ged_output_handler(rtcop->gedp, line);
170  else
171  bu_vls_printf(rtcop->gedp->ged_result_str, "%s", line);
172 }
173 
174 #else
175 
176 void
177 rtcheck_vector_handler(ClientData clientData, int mask)
178 {
179  int value;
180  struct ged_rtcheck *rtcp = (struct ged_rtcheck *)clientData;
181 
182  /* Get vector output from rtcheck */
183  if (feof(rtcp->fp)) {
184  Tcl_DeleteChannelHandler(rtcp->chan,
185  rtcheck_vector_handler,
186  (ClientData)rtcp);
187  Tcl_Close(rtcp->interp, rtcp->chan);
188 
190 
191  /* Add overlay */
192  _ged_cvt_vlblock_to_solids(rtcp->gedp, rtcp->vbp, "OVERLAPS", 0);
193  rt_vlblock_free(rtcp->vbp);
194 
195  /* wait for the forked process */
196  WaitForSingleObject( rtcp->hProcess, INFINITE );
197 
198  BU_PUT(rtcp, struct ged_rtcheck);
199 
200  return;
201  }
202 
203  value = getc(rtcp->fp);
204  (void)rt_process_uplot_value(&rtcp->vhead,
205  rtcp->vbp,
206  rtcp->fp,
207  value,
208  rtcp->csize,
210 }
211 
212 void
213 rtcheck_output_handler(ClientData clientData, int mask)
214 {
215  DWORD count;
216  char line[RT_MAXLINE];
217  struct rtcheck_output *rtcop = (struct rtcheck_output *)clientData;
218 
219  /* Get textual output from rtcheck */
220  if (Tcl_Eof(rtcop->chan) ||
221  (!ReadFile(rtcop->fd, line, RT_MAXLINE, &count, 0))) {
222 
223  Tcl_DeleteChannelHandler(rtcop->chan,
224  rtcheck_output_handler,
225  (ClientData)rtcop);
226  Tcl_Close(rtcop->interp, rtcop->chan);
227 
228  if (rtcop->gedp->ged_gdp->gd_rtCmdNotify != (void (*)(int))0)
229  rtcop->gedp->ged_gdp->gd_rtCmdNotify(0);
230 
231  BU_PUT(rtcop, struct rtcheck_output);
232 
233  return;
234  }
235 
236  line[count] = '\0';
237  if (rtcop->gedp->ged_output_handler != (void (*)(struct ged *, char *))0)
238  rtcop->gedp->ged_output_handler(rtcop->gedp, line);
239  else
240  bu_vls_printf(rtcop->gedp->ged_result_str, "%s", line);
241 }
242 
243 #endif
244 
245 
246 /*
247  * Check for overlaps in the current view.
248  *
249  * Usage:
250  * rtcheck options
251  *
252  */
253 int
254 ged_rtcheck(struct ged *gedp, int argc, const char *argv[])
255 {
256  char **vp;
257  int i;
258 #ifndef _WIN32
259  int ret;
260  int pid;
261  int i_pipe[2]; /* object reads results for building vectors */
262  int o_pipe[2]; /* object writes view parameters */
263  int e_pipe[2]; /* object reads textual results */
264 #else
265  HANDLE i_pipe[2], pipe_iDup; /* READS results for building vectors */
266  HANDLE o_pipe[2], pipe_oDup; /* WRITES view parameters */
267  HANDLE e_pipe[2], pipe_eDup; /* READS textual results */
268  STARTUPINFO si;
269  PROCESS_INFORMATION pi;
270  SECURITY_ATTRIBUTES sa;
271  char line[2048];
272  char name[256];
273 #endif
274  FILE *fp;
275  struct ged_rtcheck *rtcp;
276  struct rtcheck_output *rtcop;
277  vect_t eye_model;
278 
279  const char *bin;
280  char rtcheck[256] = {0};
281  size_t args = 0;
282 
285  GED_CHECK_VIEW(gedp, GED_ERROR);
286  GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
287 
288  /* initialize result */
289  bu_vls_trunc(gedp->ged_result_str, 0);
290 
291  bin = bu_brlcad_root("bin", 1);
292  if (bin) {
293 #ifdef _WIN32
294  snprintf(rtcheck, 256, "\"%s/%s\"", bin, argv[0]);
295 #else
296  snprintf(rtcheck, 256, "%s/%s", bin, argv[0]);
297 #endif
298  }
299 
300  args = argc + 7 + 2 + ged_count_tops(gedp);
301  gedp->ged_gdp->gd_rt_cmd = (char **)bu_calloc(args, sizeof(char *), "alloc gd_rt_cmd");
302 
303  vp = &gedp->ged_gdp->gd_rt_cmd[0];
304  *vp++ = rtcheck;
305  *vp++ = "-M";
306  for (i = 1; i < argc; i++)
307  *vp++ = (char *)argv[i];
308 
309 #ifndef _WIN32
310  *vp++ = gedp->ged_wdbp->dbip->dbi_filename;
311 #else
312  {
313  char buf[512];
314  snprintf(buf, 512, "\"%s\"", gedp->ged_wdbp->dbip->dbi_filename);
315  *vp++ = buf;
316  }
317 #endif
318 
319  /*
320  * Now that we've grabbed all the options, if no args remain,
321  * append the names of all stuff currently displayed.
322  * Otherwise, simply append the remaining args.
323  */
324  if (i == argc) {
325  gedp->ged_gdp->gd_rt_cmd_len = vp - gedp->ged_gdp->gd_rt_cmd;
326  gedp->ged_gdp->gd_rt_cmd_len += ged_build_tops(gedp, vp, &gedp->ged_gdp->gd_rt_cmd[args]);
327  } else {
328  while (i < argc)
329  *vp++ = (char *)argv[i++];
330  *vp = 0;
331  vp = &gedp->ged_gdp->gd_rt_cmd[0];
332  while (*vp)
333  Tcl_AppendResult(brlcad_interp, *vp++, " ", (char *)NULL);
334 
335  Tcl_AppendResult(brlcad_interp, "\n", (char *)NULL);
336  }
337 
338 #ifndef _WIN32
339 
340  ret = pipe(i_pipe);
341  if (ret < 0)
342  perror("pipe");
343  ret = pipe(o_pipe);
344  if (ret < 0)
345  perror("pipe");
346  ret = pipe(e_pipe);
347  if (ret < 0)
348  perror("pipe");
349 
350  if ((pid = fork()) == 0) {
351  /* Redirect stdin, stdout and stderr */
352  (void)close(0);
353  ret = dup(o_pipe[0]);
354  if (ret < 0)
355  perror("dup");
356  (void)close(1);
357  ret = dup(i_pipe[1]);
358  if (ret < 0)
359  perror("dup");
360  (void)close(2);
361  ret = dup(e_pipe[1]);
362  if (ret < 0)
363  perror("dup");
364 
365  /* close pipes */
366  (void)close(i_pipe[0]);
367  (void)close(i_pipe[1]);
368  (void)close(o_pipe[0]);
369  (void)close(o_pipe[1]);
370  (void)close(e_pipe[0]);
371  (void)close(e_pipe[1]);
372 
373  for (i = 3; i < 20; i++)
374  (void)close(i);
375 
376  (void)execvp(gedp->ged_gdp->gd_rt_cmd[0], gedp->ged_gdp->gd_rt_cmd);
377  perror(gedp->ged_gdp->gd_rt_cmd[0]);
378  exit(16);
379  }
380 
381  /* As parent, send view information down pipe */
382  (void)close(o_pipe[0]);
383  fp = fdopen(o_pipe[1], "w");
384 
385  _ged_rt_set_eye_model(gedp, eye_model);
386  _ged_rt_write(gedp, fp, eye_model);
387  (void)fclose(fp);
388 
389  /* close write end of pipes */
390  (void)close(i_pipe[1]);
391  (void)close(e_pipe[1]);
392 
393  BU_GET(rtcp, struct ged_rtcheck);
394 
395  /* initialize the rtcheck struct */
396  rtcp->fd = i_pipe[0];
397  rtcp->fp = fdopen(i_pipe[0], "r");
398  rtcp->pid = pid;
399  rtcp->vbp = rt_vlblock_init();
400  rtcp->vhead = rt_vlblock_find(rtcp->vbp, 0xFF, 0xFF, 0x00);
401  rtcp->csize = gedp->ged_gvp->gv_scale * 0.01;
402  rtcp->gedp = gedp;
403  rtcp->interp = brlcad_interp;
404 
405  /* file handlers */
406  Tcl_CreateFileHandler(i_pipe[0], TCL_READABLE,
407  rtcheck_vector_handler, (ClientData)rtcp);
408 
409  BU_GET(rtcop, struct rtcheck_output);
410  rtcop->fd = e_pipe[0];
411  rtcop->gedp = gedp;
412  rtcop->interp = brlcad_interp;
413  Tcl_CreateFileHandler(rtcop->fd,
414  TCL_READABLE,
415  rtcheck_output_handler,
416  (ClientData)rtcop);
417 
418 #else
419  /* _WIN32 */
420 
421  memset((void *)&si, 0, sizeof(STARTUPINFO));
422  memset((void *)&pi, 0, sizeof(PROCESS_INFORMATION));
423  memset((void *)&sa, 0, sizeof(SECURITY_ATTRIBUTES));
424 
425  sa.nLength = sizeof(SECURITY_ATTRIBUTES);
426  sa.bInheritHandle = TRUE;
427  sa.lpSecurityDescriptor = NULL;
428 
429  /* Create a pipe for the child process's STDERR. */
430  CreatePipe( &e_pipe[0], &e_pipe[1], &sa, 0);
431 
432  /* Create noninheritable read handle and close the inheritable read handle. */
433  DuplicateHandle( GetCurrentProcess(), e_pipe[0],
434  GetCurrentProcess(), &pipe_eDup,
435  0, FALSE,
436  DUPLICATE_SAME_ACCESS );
437  CloseHandle( e_pipe[0]);
438 
439  /* Create a pipe for the child process's STDOUT. */
440  CreatePipe( &o_pipe[0], &o_pipe[1], &sa, 0);
441 
442  /* Create noninheritable write handle and close the inheritable writehandle. */
443  DuplicateHandle( GetCurrentProcess(), o_pipe[1],
444  GetCurrentProcess(), &pipe_oDup ,
445  0, FALSE,
446  DUPLICATE_SAME_ACCESS );
447  CloseHandle( o_pipe[1]);
448 
449  /* Create a pipe for the child process's STDIN. */
450  CreatePipe(&i_pipe[0], &i_pipe[1], &sa, 0);
451 
452  /* Duplicate the read handle to the pipe so it is not inherited. */
453  DuplicateHandle(GetCurrentProcess(), i_pipe[0],
454  GetCurrentProcess(), &pipe_iDup,
455  0, FALSE, /* not inherited */
456  DUPLICATE_SAME_ACCESS );
457  CloseHandle(i_pipe[0]);
458 
459 
460  si.cb = sizeof(STARTUPINFO);
461  si.lpReserved = NULL;
462  si.lpReserved2 = NULL;
463  si.cbReserved2 = 0;
464  si.lpDesktop = NULL;
465  si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
466  si.hStdInput = o_pipe[0];
467  si.hStdOutput = i_pipe[1];
468  si.hStdError = e_pipe[1];
469  si.wShowWindow = SW_HIDE;
470 
471  snprintf(line, sizeof(line), "%s ", gedp->ged_gdp->gd_rt_cmd[0]);
472  for (i = 1; i < gedp->ged_gdp->gd_rt_cmd_len; i++) {
473  snprintf(name, sizeof(name), "%s ", gedp->ged_gdp->gd_rt_cmd[i]);
474  bu_strlcat(line, name, sizeof(line));
475  }
476 
477  CreateProcess(NULL, line, NULL, NULL, TRUE,
478  DETACHED_PROCESS, NULL, NULL,
479  &si, &pi);
480 
481  /* close read end of pipe */
482  CloseHandle(o_pipe[0]);
483 
484  /* close write end of pipes */
485  (void)CloseHandle(i_pipe[1]);
486  (void)CloseHandle(e_pipe[1]);
487 
488  /* As parent, send view information down pipe */
489  fp = _fdopen(_open_osfhandle((intptr_t)pipe_oDup, _O_TEXT), "wb");
490  setmode(_fileno(fp), O_BINARY);
491 
492  _ged_rt_set_eye_model(gedp, eye_model);
493  _ged_rt_write(gedp, fp, eye_model);
494  (void)fclose(fp);
495 
496  BU_GET(rtcp, struct ged_rtcheck);
497 
498  /* initialize the rtcheck struct */
499  rtcp->fd = pipe_iDup;
500  rtcp->fp = _fdopen( _open_osfhandle((intptr_t)pipe_iDup, _O_TEXT), "rb" );
501  setmode(_fileno(rtcp->fp), O_BINARY);
502  rtcp->hProcess = pi.hProcess;
503  rtcp->pid = pi.dwProcessId;
504  rtcp->vbp = rt_vlblock_init();
505  rtcp->vhead = rt_vlblock_find(rtcp->vbp, 0xFF, 0xFF, 0x00);
506  rtcp->csize = gedp->ged_gvp->gv_scale * 0.01;
507  rtcp->gedp = gedp;
508  rtcp->interp = brlcad_interp;
509 
510  rtcp->chan = Tcl_MakeFileChannel(pipe_iDup, TCL_READABLE);
511  Tcl_CreateChannelHandler(rtcp->chan, TCL_READABLE,
512  rtcheck_vector_handler,
513  (ClientData)rtcp);
514 
515  BU_GET(rtcop, struct rtcheck_output);
516  rtcop->fd = pipe_eDup;
517  rtcop->chan = Tcl_MakeFileChannel(pipe_eDup, TCL_READABLE);
518  rtcop->gedp = gedp;
519  rtcop->interp = brlcad_interp;
520  Tcl_CreateChannelHandler(rtcop->chan,
521  TCL_READABLE,
522  rtcheck_output_handler,
523  (ClientData)rtcop);
524 #endif
525 
526  bu_free(gedp->ged_gdp->gd_rt_cmd, "free gd_rt_cmd");
527  gedp->ged_gdp->gd_rt_cmd = NULL;
528 
529  return GED_OK;
530 }
531 
532 
533 /*
534  * Local Variables:
535  * tab-width: 8
536  * mode: C
537  * indent-tabs-mode: t
538  * c-file-style: "stroustrup"
539  * End:
540  * ex: shiftwidth=4 tabstop=8
541  */
#define GED_OK
Definition: ged.h:55
#define FALSE
void rt_vlblock_free(struct bn_vlblock *vbp)
Definition: vlist.c:78
Definition: list.h:118
double csize
Definition: rtcheck.c:62
struct bn_vlblock * vbp
Definition: rtcheck.c:60
Definition: ged.h:338
struct db_i * dbip
Definition: raytrace.h:1266
Definition: clone.c:90
size_t ged_count_tops(struct ged *gedp)
Definition: rt.c:409
#define RT_MAXLINE
Definition: raytrace.h:1255
int ged_rtcheck(struct ged *gedp, int argc, const char *argv[])
Definition: rtcheck.c:254
void _ged_rt_set_eye_model(struct ged *gedp, vect_t eye_model)
Definition: rt.c:88
void bu_vls_trunc(struct bu_vls *vp, int len)
Definition: vls.c:198
int rt_process_uplot_value(struct bu_list **vhead, struct bn_vlblock *vbp, FILE *fp, int c, double char_size, int mode)
#define GED_CHECK_ARGC_GT_0(_gedp, _argc, _flags)
Definition: ged.h:202
struct rt_wdb * ged_wdbp
Definition: ged.h:340
Header file for the BRL-CAD common definitions.
Tcl_Interp * interp
Definition: rtcheck.c:75
struct bn_vlblock * rt_vlblock_init(void)
Definition: vlist.c:71
struct bu_list * gd_headDisplay
head of display list
Definition: ged.h:307
struct ged * gedp
Definition: rtcheck.c:74
#define GED_ERROR
Definition: ged.h:61
void _ged_rt_write(struct ged *gedp, FILE *fp, vect_t eye_model)
Definition: rt.c:54
struct bview * ged_gvp
Definition: ged.h:361
struct bu_list * rt_vlblock_find(struct bn_vlblock *vbp, int r, int g, int b)
Definition: vlist.c:98
void * memset(void *s, int c, size_t n)
#define GED_CHECK_VIEW(_gedp, _flags)
Definition: ged.h:140
#define GED_CHECK_DATABASE_OPEN(_gedp, _flags)
Definition: ged.h:114
int gd_rt_cmd_len
Definition: ged.h:313
FILE * fdopen(int, const char *)
void * bu_calloc(size_t nelem, size_t elsize, const char *str)
Definition: malloc.c:321
fastf_t gv_scale
Definition: bview.h:211
#define BU_GET(_ptr, _type)
Definition: malloc.h:201
int pid
Definition: rtcheck.c:57
char ** gd_rt_cmd
Definition: ged.h:312
#define GED_CHECK_DRAWABLE(_gedp, _flags)
Definition: ged.h:129
#define UNUSED(parameter)
Definition: common.h:239
#define BU_PUT(_ptr, _type)
Definition: malloc.h:215
FILE * fp
Definition: rtcheck.c:59
struct bu_vls * ged_result_str
Definition: ged.h:357
struct ged_drawable * ged_gdp
Definition: ged.h:360
int gd_uplotOutputMode
output mode for unix plots
Definition: ged.h:318
void _ged_cvt_vlblock_to_solids(struct ged *gedp, struct bn_vlblock *vbp, const char *name, int copy)
Definition: draw.c:554
struct ged * gedp
Definition: rtcheck.c:63
HIDDEN fastf_t bin(fastf_t val, fastf_t step)
Definition: nmg_tri_mc.c:461
struct bu_list * vhead
Definition: rtcheck.c:61
Tcl_Interp * interp
Definition: rtcheck.c:64
void bu_vls_printf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:694
void(* ged_output_handler)(struct ged *, char *)
function for handling output
Definition: ged.h:368
void(* gd_rtCmdNotify)(int aborted)
function called when rt command completes
Definition: ged.h:316
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
void _ged_wait_status(struct bu_vls *logstr, int status)
Definition: rtcheck.c:80
void dl_set_flag(struct bu_list *hdlp, int flag)
#define DOWN
Definition: bview.h:42
const char * bu_brlcad_root(const char *rhs, int fail_quietly)
Definition: brlcad_path.c:292
Definition: vls.h:56
char * dbi_filename
file name
Definition: raytrace.h:805
int ged_build_tops(struct ged *gedp, char **start, char **end)
Definition: rt.c:424
Tcl_Interp * brlcad_interp
Definition: tcl.c:41
#define TRUE
#define bu_strlcat(dst, src, size)
Definition: str.h:50
int fd
Definition: rtcheck.c:56