Files
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

832 lines
15 KiB
C

#ifndef lint
static char sccsid[] = "@(#)pipe.c 1.1 94/10/31 Copyr 1987 Sun Micro";
#endif
/*
* Copyright (c) 1987 by Sun Microsystems, Inc.
*/
#include <suntool/sunview.h>
#include <suntool/textsw.h>
#include <suntool/ttysw.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <sys/wait.h>
#include <setjmp.h>
#include "defs.h"
#include "pipeout.h"
#include "typedefs.h"
#include "dbxlib.h"
#include "dbxtool.h"
#include "cmd.h"
#include "pipe.h"
#include "src.h"
#define PARENT_READ 0
#define PARENT_WRITE 1
#define CHILD_READ 0
#define CHILD_WRITE 1
#define SLOTS 2 /* # of arguments added */
#define DEBUGGER "dbx"
#define STRBUF 256
typedef struct Use *Use;
struct Use {
char *dir;
Use next;
};
/*
* There are three types of files and line numbers:
* 1) current (cur) - this is the name and line number of
* the file currently being displayed in
* the source window.
* 2) breakpoint (brk) - this is the name and line number of
* the current stopping point. If there is
* is source code available, a solid arrow
* will be displayed at 'brkline' in 'brkfile'.
* 3) hollow - this is the name and line number of the hollow arrow.
* If the hollow and breakpoint files and line
* numbers refer to different locations, then
* a hollow arrow will be displayed at 'hollowline'
* of 'hollowfile'.
*/
private Boolean initdone; /* Have we seen I_INITDONE? */
private Boolean isstopped; /* Have we hit a break point? */
private Boolean istracing; /* Are we tracing */
private int pipein; /* Pipe from debugger */
private char curfile[STRBUF]; /* Current source file, simple name */
private char fullcurfile[STRBUF]; /* Current source file, full name */
private char curfunc[STRBUF]; /* Current function */
private int curline; /* Current source line */
private char brkfile[STRBUF]; /* Stopped point file, simple name */
private char fullbrkfile[STRBUF]; /* Stopped point file, full name */
private char brkfunc[STRBUF]; /* Function of stopped point */
private int brkline; /* Line number of stopped point */
private char hollowfile[STRBUF]; /* Hollow source file, simple name */
private char fullhollowfile[STRBUF]; /* Hollow source file, full name */
private int hollowline; /* Line number of the hollow arrow */
private Use sourcepath; /* List of 'use' directories */
private jmp_buf env; /* Setjmp buffer for error recovery */
private Intermed rdtype();
private Notify_value wait3_handler();
private char *inter_type[] = {
"I_BADTYPE",
"I_INITDONE",
"I_STOPPED",
"I_STRING",
"I_INT",
"I_QUIT",
"I_PRINTLINES",
"I_BRKSET",
"I_BRKDEL",
"I_RESUME",
"I_USE",
"I_REINIT",
"I_KILL",
"I_CHDIR",
"I_EMPHASIZE",
"I_TRACE",
"I_DISPLAY",
"I_VERSION",
"I_TOOLENV",
"I_WIDTH",
"I_SRCLINES",
"I_CMDLINES",
"I_DISPLINES",
"I_FONT",
"I_TOPMARGIN",
"I_BOTMARGIN",
"I_UNBUTTON",
"I_BUTTON",
"I_CALLSTACK",
"I_NEWINITDONE",
"I_MENU",
"I_UNMENU",
};
/*
* The versions specify the version of dbx that this dbxtool
* is compatible with. When the interface between dbx and
* dbxtool is extended in an upwards compatible way, only
* the high version need be adjusted. If the interface changes
* in a non-compatible way the low version should be set to
* the new incompatible version.
*/
#define DBXTOOL_LOWVERSION 2
private low_version = DBXTOOL_LOWVERSION;
private high_version = DBXTOOL_VERSION;
/*
* Start up the debugger process.
* Create a pipe between ourselves and the debugger.
* Pass the file descriptor of the writable end of the
* pipe to dbx as "-P nn".
* Dbx will be responsible for closing the readable end
* of the pipe. In fact, dbx will close everything but
* stdin, stdout, stderr, and the pipe.
* The argv passed in here points to the first argument
* not the command name. Argc has been adjusted accordingly.
*/
public create_pipe(argc, argv)
int argc;
char *argv[];
{
char pout[10];
char **nargv;
int pid;
int parent_in[2];
int i;
pipe(parent_in);
sprintf(pout, "%d", parent_in[CHILD_WRITE]);
/*
* Duplicate the argument vector.
* Change the command name to that of the debugger and
* leave SLOTS empty spots to add arguments. We add
* the "-P xx" argument to tell the debugger where the
* pipe is.
*/
nargv = (char **) malloc((argc + 1 + SLOTS + 1) * sizeof(char *));
nargv[0] = DEBUGGER;
for (i = 0; i < argc; i++) {
nargv[i + 1 + SLOTS] = argv[i];
}
nargv[i + 1 + SLOTS] = nil;
nargv[1] = "-P";
nargv[2] = pout;
ioctl(parent_in[CHILD_READ], FIONCLEX, 0);
ioctl(parent_in[PARENT_WRITE], FIONCLEX, 0);
/*
* Fork, and exec the child, close the parent's output
* side of the pipe and remember the parent's input side.
*/
if (debugpipe) {
for(i = 0; nargv[i] != nil; i++) {
fprintf(stderr, "%s ", nargv[i]);
}
fprintf(stderr, "\n");
}
pid = ttysw_start(get_cmd_sw_h(), nargv);
notify_set_wait3_func(get_cmd_sw_h(), wait3_handler, pid);
close(parent_in[PARENT_WRITE]);
pipein = parent_in[PARENT_READ];
}
/*
* Notify proc for child termination.
* ARGSUSED
*/
private Notify_value wait3_handler(me, pid, status, rusage)
caddr_t me;
int pid;
union wait *status;
struct rusage *rusage;
{
if (WIFSIGNALED(*status)) {
fprintf(stderr, "Child dbx killed by signal %d\n",
status->w_termsig);
exit(1);
} else if (WIFEXITED(*status)) {
fprintf(stderr, "Child dbx exited with status %d\n",
status->w_retcode);
exit(1);
}
}
/*
* Read from the pipe and process operators until the I_INITDONE
* operator comes thru.
*/
public wait_initdone()
{
union wait status;
if (setjmp(env) == 0) {
check_version();
initdone = false;
while (not initdone) {
pipe_input();
}
} else {
wait(&status);
wait3_handler(nil, 0, &status, nil);
}
}
/*
* See if the dbx and this dbxtool are compatible.
*/
public check_version()
{
Intermed type;
int version;
type = rdtype();
if (type == I_VERSION) {
version = rdint();
if (version >= low_version and version <= high_version) {
return;
}
}
fprintf(stderr, "Incompatible versions of dbx and dbxtool\n");
exit(0);
}
/*
* We have some input from the pipe.
* Read and process one operator.
* ARGSUSED
*/
public Notify_value pipe_input(client, fd)
Notify_client client;
int fd;
{
Intermed type;
if (setjmp(env) == 1) {
initdone = true;
return;
}
type = rdtype();
istracing = false;
switch(type) {
case I_PRINTLINES:
curline = rd_filefuncline(curfile, fullcurfile, nil, STRBUF);
rdint();
dbx_printlines(fullcurfile, curline);
break;
case I_INITDONE:
curline = rd_filefuncline(curfile, fullcurfile, curfunc,STRBUF);
if (initdone) {
dbx_display_source(fullcurfile, curline);
} else {
initdone = true;
}
break;
case I_NEWINITDONE:
curline = rd_filefuncline(curfile, fullcurfile, curfunc,STRBUF);
brkline = rd_filefuncline(brkfile, fullbrkfile, brkfunc,STRBUF);
set_hollow_to_cur();
if (initdone) {
dbx_display_source(fullhollowfile, hollowline);
} else {
initdone = true;
}
break;
case I_KILL:
isstopped = false;
curfile[0] = '\0';
fullcurfile[0] = '\0';
curline = 0;
brkfile[0] = '\0';
fullbrkfile[0] = '\0';
brkline = 0;
hollowfile[0] = '\0';
fullhollowfile[0] = '\0';
hollowline = 0;
dbx_reinit(false);
break;
case I_REINIT:
isstopped = false;
curfile[0] = '\0';
fullcurfile[0] = '\0';
dbx_reinit(true);
check_version();
break;
case I_CHDIR: {
char dir[256];
rdstring(dir, sizeof(dir));
chdir(dir);
remember_curdir();
break;
}
case I_QUIT: {
int exit_status;
exit_status = rdint();
dbx_cleanup();
exit(exit_status);
/* NOTREACHED */
}
case I_BRKSET: {
char filename[256];
int lineno;
rdstring(filename, sizeof(filename));
lineno = rdint();
dbx_setbreakpoint(filename, lineno);
break;
}
case I_BRKDEL: {
char filename[256];
int lineno;
rdstring(filename, sizeof(filename));
lineno = rdint();
dbx_delbreakpoint(filename, lineno);
break;
}
case I_RESUME:
dbx_resume();
break;
case I_USE: {
int n;
char dir[100];
n = rdint();
del_uses(sourcepath);
sourcepath = nil;
while (n--) {
rdstring(dir, sizeof(dir));
add_use(dir);
}
strcpy(fullcurfile, findsource(curfile));
break;
}
case I_EMPHASIZE:
curline = rd_filefuncline(curfile, fullcurfile, nil, STRBUF);
dbx_emphasize(fullcurfile, curline);
break;
case I_CALLSTACK:
hollowline = rd_filefuncline(hollowfile, fullhollowfile,
nil, STRBUF);
dbx_display_source(fullhollowfile, hollowline);
break;
case I_TRACE:
isstopped = false;
istracing = true;
curline = rd_filefuncline(curfile, fullcurfile, curfunc,STRBUF);
set_brk_to_cur();
set_hollow_to_cur();
dbx_resume();
dbx_display_source(fullhollowfile, hollowline);
break;
case I_FONT: {
char filename[256];
rdstring(filename, sizeof(filename));
dbx_setfont(filename);
break;
}
case I_TOOLENV:
dbx_prtoolenv();
break;
case I_WIDTH: {
int width;
width = rdint();
dbx_setwidth(width, true);
break;
}
case I_SRCLINES: {
int srclines;
srclines = rdint();
dbx_setsrclines(srclines, true);
break;
}
case I_CMDLINES: {
int cmdlines;
cmdlines = rdint();
dbx_setcmdlines(cmdlines, true);
break;
}
case I_DISPLINES: {
int displines;
displines = rdint();
dbx_setdisplines(displines, true);
break;
}
case I_TOPMARGIN: {
int topmargin;
topmargin = rdint();
dbx_settopmargin(topmargin);
break;
}
case I_BOTMARGIN: {
int botmargin;
botmargin = rdint();
dbx_setbotmargin(botmargin);
break;
}
case I_BUTTON: {
int seltype;
char str[512];
seltype = rdint();
rdstring(str, sizeof(str));
dbx_new_button((Seltype) seltype, str);
break;
}
case I_UNBUTTON: {
char str[512];
rdstring(str, sizeof(str));
dbx_unbutton(str);
break;
}
case I_MENU: {
int seltype;
char str[512];
seltype = rdint();
rdstring(str, sizeof(str));
dbx_new_menu((Seltype) seltype, str);
break;
}
case I_UNMENU: {
char str[512];
rdstring(str, sizeof(str));
dbx_unmenu(str);
break;
}
case I_STOPPED:
isstopped = true;
curline = rd_filefuncline(curfile, fullcurfile, curfunc,STRBUF);
brkline = rd_filefuncline(brkfile, fullbrkfile, brkfunc,STRBUF);
set_hollow_to_cur();
dbx_display_source(fullhollowfile, hollowline);
break;
case I_DISPLAY: {
char display_file[256];
rdstring(display_file, sizeof(display_file));
dbx_display(display_file);
break;
}
default:
fprintf(stderr, "pipe_input: bad type %d\n", type);
exit(1);
}
return(NOTIFY_DONE);
}
/*
* Read a type descriptor from the pipe.
*/
private Intermed rdtype()
{
Intermed type;
int r;
union wait status;
extern int errno;
type = I_BADOP;
r = myread(pipein, (char *) &type, sizeof(type));
if (ord(type) < ord(I_FIRST) or ord(type) > ord(I_LAST)) {
fprintf(stderr, "rdtype: bad type %d\n", ord(type));
exit(1);
}
if (debugpipe) {
fprintf(stderr, "pipe input: %s\n", inter_type[ord(type)]);
}
return(type);
}
/*
* Read a string from the pipe.
*/
private rdstring(buf, maxlen)
char *buf;
int maxlen;
{
Intermed type;
char dummy[512];
int len;
int readlen;
int extralen;
type = rdtype();
if (type != I_STRING) {
fprintf(stderr, "expected I_STRING but got %s",
inter_type[ord(type)]);
exit(1);
}
myread(pipein, (char *) &len, sizeof(len));
if (maxlen == 0) {
readlen = 0;
extralen = len;
} else if (len > maxlen - 1) {
readlen = maxlen - 1;
extralen = len - maxlen + 1;
} else {
readlen = len;
extralen = 0;
}
if (readlen > 0) {
myread(pipein, buf, readlen);
}
buf[readlen] = '\0';
while (extralen > 0) {
if (extralen > sizeof(dummy)) {
readlen = sizeof(dummy);
} else {
readlen = extralen;
}
myread(pipein, dummy, readlen);
extralen -= readlen;
}
if (debugpipe) {
fprintf(stderr, "\t%s\n", buf);
}
}
/*
* Read an integer. Here we are looking for both the type
* indicator and the integer value. Return the value.
*/
private rdint()
{
Intermed type;
int i;
type = rdtype();
if (type != I_INT) {
fprintf(stderr, "expected I_INT but got %s\n",
inter_type[ord(type)]);
exit(1);
}
myread(pipein, (char *) &i, sizeof(i));
if (debugpipe) {
fprintf(stderr, "\t%d\n", i);
}
return(i);
}
/*
* Front-end to the read() system call that does
* error checking. If we read zero bytes this implies
* that the pipe was closed by dbx. This usually indicates
* that dbx died. In this case longjmp out of here.
*/
private int myread(fd, buf, nbytes)
int fd;
char *buf;
int nbytes;
{
int r;
r = read(fd, buf, nbytes);
if (r == 0) {
longjmp(env, 1);
}
if (r == -1) {
perror("dbxtool read from pipe failed");
exit(1);
}
if (r != nbytes) {
fprintf( stderr,
"dbxtool read from pipe failed: read %d bytes\n", r);
exit(1);
}
return(r);
}
/*
* Delete a list.
*/
private del_uses(uses)
Use uses;
{
Use u;
Use next;
for (u = uses; u != nil; u = next) {
next = u->next;
dispose(u->dir);
dispose(u);
}
}
/*
* Add an element to the uses list.
*/
private add_use(dir)
char *dir;
{
Use u;
Use *bpatch;
bpatch = &sourcepath;
for (u = sourcepath; u != nil; u = u->next) {
bpatch = &u->next;
}
u = new(Use);
u->dir = strdup(dir);
u->next = nil;
*bpatch = u;
}
/*
* Look for a file by applying the 'uses' list.
*/
public String findsource(filename)
String filename;
{
register File f;
register String src;
Use use;
static char filenamebuf[256];
if (filename == nil || filename[0] == '\0') {
return("");
}
if (filename[0] == '/') {
src = filename;
} else {
src = "";
for (use = sourcepath; use != nil; use = use->next) {
sprintf(filenamebuf, "%s/%s", use->dir, filename);
f = fopen(filenamebuf, "r");
if (f != nil) {
fclose(f);
src = filenamebuf;
break;
}
}
}
return src;
}
/*
* Return whether we are stopped or not
*/
public Boolean get_isstopped()
{
return(isstopped);
}
/*
* Return whether we are tracing or not.
*/
public Boolean get_istracing()
{
return(istracing);
}
/*
* Return the current breakpoint line number.
*/
public get_brkline()
{
return(brkline);
}
/*
* Return the current breakpoint function name
*/
public char *get_brkfunc()
{
return(brkfunc);
}
/*
* Return the current breakpoint file name
*/
public char *get_brkfile()
{
return(findsource(brkfile));
}
/*
* Read a file, function, and line number
*/
private rd_filefuncline(file, fullfile, func, strbuf)
char *file;
char *fullfile;
char *func;
int strbuf;
{
int line;
if (file != nil) {
rdstring(file, strbuf);
if (fullfile != nil) {
strcpy(fullfile, findsource(file));
}
}
if (func != nil) {
rdstring(func, strbuf);
}
line = rdint();
return(line);
}
/*
* Return the current file name
*/
public char *get_curfile()
{
return(fullcurfile);
}
/*
* Return the current line number
*/
public get_curline()
{
return(curline);
}
/*
* Return the current file name unmodified
*/
public char *get_simple_curfile()
{
return(curfile);
}
/*
* Return the pipe input file descriptor.
*/
public get_pipein()
{
return(pipein);
}
/*
* Return the hollow file name.
*/
public char *get_hollowfile()
{
return(fullhollowfile);
}
/*
* Return the hollow line number
*/
public get_hollowline()
{
return(hollowline);
}
/*
* Set the 'hollow' attributes to the same as the 'cur' ones.
*/
private set_hollow_to_cur()
{
strcpy(hollowfile, curfile);
strcpy(fullhollowfile, fullcurfile);
hollowline = curline;
}
/*
* Set the 'brk' attributes to the same as the 'cur' ones.
*/
private set_brk_to_cur()
{
strcpy(brkfile, curfile);
strcpy(fullbrkfile, fullcurfile);
strcpy(brkfunc, curfunc);
brkline = curline;
}