Exemple #1
0
  Full documentation can be found at (graphv section):\n\
  http://oss.oetiker.ch/rrdtool/doc/rrdgraph.en.html";

static PyObject *
_rrdtool_graphv(PyObject *Py_UNUSED(self), PyObject *args)
{
    PyObject *ret;
    rrd_info_t *data;

    if (convert_args("graphv", args) == -1)
        return NULL;

    Py_BEGIN_ALLOW_THREADS
    data = rrd_graph_v(rrdtool_argc, rrdtool_argv);
    Py_END_ALLOW_THREADS

    if (data == NULL) {
        PyErr_SetString(rrdtool_OperationalError, rrd_get_error());
        rrd_clear_error();
        ret = NULL;
    } else {
        ret = _rrdtool_util_info2dict(data);
        rrd_info_free(data);
    }

    destroy_args();
    return ret;
}
Exemple #2
0
static PyObject *
_rrdtool_updatev(PyObject *Py_UNUSED(self), PyObject *args)
{
    PyObject *ret;
    rrd_info_t *data;

    if (convert_args("updatev", args) == -1)
        return NULL;

    Py_BEGIN_ALLOW_THREADS
    data = rrd_update_v(rrdtool_argc, rrdtool_argv);
    Py_END_ALLOW_THREADS

    if (data == NULL) {
        PyErr_SetString(rrdtool_OperationalError, rrd_get_error());
        rrd_clear_error();
        ret = NULL;
    } else {
        ret = _rrdtool_util_info2dict(data);
        rrd_info_free(data);
    }

    destroy_args();
    return ret;
}
Exemple #3
0
translation_unit& index::create_translation_unit(const std::string& filename, const std::vector<std::string>& args, const std::vector<unsaved_file>& unsaved)
{
    auto argv = convert_args(args);
    auto unsaved_files = convert_unsaved_files(unsaved);
    auto tu = clang_createTranslationUnitFromSourceFile(idx, filename.c_str(), argv.size(), argv.data(), unsaved_files.size(), unsaved_files.data());
    if(!tu)
        throw error("unable to parse tu");
    
    tus.emplace_back(tu);
    return tus.back();
}
Exemple #4
0
bool process::launch(const std::string &cmd,
                     const std::vector<std::string> &args) {

  PROCESS_INFORMATION proc_info;
  STARTUPINFO startup_info;
  ZeroMemory(&proc_info, sizeof(PROCESS_INFORMATION));
  ZeroMemory(&startup_info, sizeof(STARTUPINFO));

  char *c_arglist = convert_args(cmd, args);

  BOOL ret;
  // For Windows, we include the cmd with the arguments so that a search path
  // is used for any executable without a full path
  ret = CreateProcess(NULL,
      c_arglist,
      NULL,
      NULL,
      FALSE,
      CREATE_NO_WINDOW,
      NULL,
      NULL,
      &startup_info,
      &proc_info);

  if(!ret) {
    auto err = GetLastError();
    logstream(LOG_ERROR) << "Failed to launch process: " <<
      get_last_err_str(err) << std::endl;
    delete[] c_arglist;
    return false;
  } else {
    // Don't need to have a thread handle. We'll just cancel the process if
    // need be
    CloseHandle(proc_info.hThread);
    m_launched = true;
  }

  // Used for killing the process
  m_proc_handle = proc_info.hProcess;
  m_pid = proc_info.dwProcessId;

  logstream(LOG_INFO) << "Launched process with pid: " << m_pid << std::endl;

  return true;
}
static int console_loop(void)
{
	cmd_args args[16];
	char buffer[256];

	printf("entering main console loop\n");

	for (;;) {
		puts("] ");

		int len = read_line(buffer, sizeof(buffer));
		if (len == 0)
			continue;

//		printf("line = '%s'\n", buffer);

		/* tokenize the line */
		int argc = tokenize_command(buffer, args, 16);
		if (argc < 0) {
			printf("syntax error\n");
			continue;
		} else if (argc == 0) {
			continue;
		}

//		printf("after tokenize: argc %d\n", argc);
//		for (int i = 0; i < argc; i++)
//			printf("%d: '%s'\n", i, args[i].str);

		/* convert the args */
		convert_args(argc, args);

		/* try to match the command */
		const cmd *command = match_command(args[0].str);
		if (!command) {
			printf("command not found\n");
			continue;
		}

		int result = command->cmd_callback(argc, args);
                return result;
		// XXX do something with the result
	}
}
Exemple #6
0
int exec(const std::string& wd, const std::vector<std::string>& args)
{
    auto argv = convert_args(args);
    
    pid_t pid = fork();
    switch(pid)
    {
        case -1:
        {
            throw std::system_error(errno, std::system_category(), "fork");
        }
        case 0:
        {
            if(!wd.empty())
            {
                int err = chdir(wd.c_str());
                if(err)
                {
                    std::string cmd;
                    cmd += "chdir(" + wd + ")";
                    perror(cmd.c_str());
                    abort();
                }
            }
            
            execvp(argv[0], argv.data());
            abort();
        }
        default:
        {
            int status;
            waitpid(pid, &status, 0);
            
            if(WIFEXITED(status))
                return WEXITSTATUS(status);
            
            throw std::runtime_error("Abnormal child termination.");
        }
    }
    
    throw std::logic_error("exec");
}
Exemple #7
0
void panic_shell_start(void)
{
    dprintf(INFO, "entering panic shell loop\n");
    char input_buffer[PANIC_LINE_LEN];
    cmd_args args[MAX_NUM_ARGS];

    // panic_fd allows us to do I/O using the polling drivers.
    // These drivers function even if interrupts are disabled.
    FILE _panic_fd = get_panic_fd();
    FILE *panic_fd = &_panic_fd;

    for (;;) {
        fputs("! ", panic_fd);
        read_line_panic(input_buffer, PANIC_LINE_LEN, panic_fd);

        int argc;
        char* tok = strtok(input_buffer, WHITESPACE);
        for (argc = 0; argc < MAX_NUM_ARGS; argc++) {
            if (tok == NULL) {
                break;
            }
            args[argc].str = tok;
            tok = strtok(NULL, WHITESPACE);
        }

        if (argc == 0) {
            continue;
        }

        convert_args(argc, args);

        const cmd* command = match_command(args[0].str, CMD_AVAIL_PANIC);
        if (!command) {
            fputs("command not found\n", panic_fd);
            continue;
        }

        command->cmd_callback(argc, args);
    }
}
Exemple #8
0
translation_unit& index::parse_translation_unit(const std::vector<std::string>& args, const std::vector<unsaved_file>& unsaved)
{
    auto argv = convert_args(args);
    auto unsaved_files = convert_unsaved_files(unsaved);
    unsigned options = CXTranslationUnit_DetailedPreprocessingRecord | 
                        CXTranslationUnit_CacheCompletionResults;
    
    auto tu = clang_parseTranslationUnit(idx, nullptr, argv.data(), argv.size(), unsaved_files.data(), unsaved_files.size(), options);
    if(!tu)
        throw error("unable to parse tu");

    // Have to reparse to cache completion results.
    int err = clang_reparseTranslationUnit(tu, unsaved_files.size(), unsaved_files.data(), clang_defaultReparseOptions(tu));
    if(err)
    {
        clang_disposeTranslationUnit(tu);
        throw error("unable to reparse tu");
    }
    
    tus.emplace_back(tu);
    return tus.back();
}
Exemple #9
0
static Port *
open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump)
{
    Sint i;
    Eterm option;
    Uint arity;
    Eterm* tp;
    Uint* nargs;
    erts_driver_t* driver;
    char* name_buf = NULL;
    SysDriverOpts opts;
    Sint linebuf;
    Eterm edir = NIL;
    byte dir[MAXPATHLEN];
    erts_aint32_t sflgs = 0;
    Port *port;

    /* These are the defaults */
    opts.packet_bytes = 0;
    opts.use_stdio = 1;
    opts.redir_stderr = 0;
    opts.read_write = 0;
    opts.hide_window = 0;
    opts.wd = NULL;
    opts.envir = NULL;
    opts.exit_status = 0;
    opts.overlapped_io = 0; 
    opts.spawn_type = ERTS_SPAWN_ANY; 
    opts.argv = NULL;
    opts.parallelism = erts_port_parallelism;
    linebuf = 0;

    *err_nump = 0;

    if (is_not_list(settings) && is_not_nil(settings)) {
	goto badarg;
    }
    /*
     * Parse the settings.
     */

    if (is_not_nil(settings)) {
	nargs = list_val(settings);
	while (1) {
	    if (is_tuple_arity(*nargs, 2)) {
		tp = tuple_val(*nargs);
		arity = *tp++;
		option = *tp++;
		if (option == am_packet) {
		    if (is_not_small(*tp)) {
			goto badarg;
		    }
		    opts.packet_bytes = signed_val(*tp);
		    switch (opts.packet_bytes) {
		    case 1:
		    case 2:
		    case 4:
			break;
		    default:
			goto badarg;
		   }
		} else if (option == am_line) {
		    if (is_not_small(*tp)) {
			goto badarg;
		    }
		    linebuf = signed_val(*tp);
		    if (linebuf <= 0) {
			goto badarg;
		    }
		} else if (option == am_env) {
		    byte* bytes;
		    if ((bytes = convert_environment(p, *tp)) == NULL) {
			goto badarg;
		    }
		    opts.envir = (char *) bytes;
		} else if (option == am_args) {
		    char **av;
		    char **oav = opts.argv;
		    if ((av = convert_args(*tp)) == NULL) {
			goto badarg;
		    }
		    opts.argv = av;
		    if (oav) {
			opts.argv[0] = oav[0];
			oav[0] = erts_default_arg0;
			free_args(oav);
		    }

		} else if (option == am_arg0) {
		    char *a0;

		    if ((a0 = erts_convert_filename_to_native(*tp, NULL, 0, ERTS_ALC_T_TMP, 1, 1, NULL)) == NULL) {
			goto badarg;
		    }
		    if (opts.argv == NULL) {
			opts.argv = erts_alloc(ERTS_ALC_T_TMP, 
					       2 * sizeof(char **));
			opts.argv[0] = a0;
			opts.argv[1] = NULL;
		    } else {
			if (opts.argv[0] != erts_default_arg0) {
			    erts_free(ERTS_ALC_T_TMP, opts.argv[0]);
			}
			opts.argv[0] = a0;
		    }
		} else if (option == am_cd) {
		    edir = *tp;
		} else if (option == am_parallelism) {
		    if (*tp == am_true)
			opts.parallelism = 1;
		    else if (*tp == am_false)
			opts.parallelism = 0;
		    else
			goto badarg;
		} else {
		    goto badarg;
		}
	    } else if (*nargs == am_stream) {
		opts.packet_bytes = 0;
	    } else if (*nargs == am_use_stdio) {
		opts.use_stdio = 1;
	    } else if (*nargs == am_stderr_to_stdout) {
		opts.redir_stderr = 1;
	    } else if (*nargs == am_line) {
		linebuf = 512;
	    } else if (*nargs == am_nouse_stdio) {
		opts.use_stdio = 0;
	    } else if (*nargs == am_binary) {
		sflgs |= ERTS_PORT_SFLG_BINARY_IO;
	    } else if (*nargs == am_in) {
		opts.read_write |= DO_READ;
	    } else if (*nargs == am_out) {
		opts.read_write |= DO_WRITE;
	    } else if (*nargs == am_eof) {
		sflgs |= ERTS_PORT_SFLG_SOFT_EOF;
	    } else if (*nargs == am_hide) {
		opts.hide_window = 1;
	    } else if (*nargs == am_exit_status) {
		opts.exit_status = 1;
	    } else if (*nargs == am_overlapped_io) {
		opts.overlapped_io = 1;
	    } else {
		goto badarg;
	    }
	    if (is_nil(*++nargs)) 
		break;
	    if (is_not_list(*nargs)) {
		goto badarg;
	    }
	    nargs = list_val(*nargs);
	}
    }
    if (opts.read_write == 0)	/* implement default */
	opts.read_write = DO_READ|DO_WRITE;

    /* Mutually exclusive arguments. */
    if((linebuf && opts.packet_bytes) || 
       (opts.redir_stderr && !opts.use_stdio)) {
	goto badarg;
    }

    /*
     * Parse the first argument and start the appropriate driver.
     */
    
    if (is_atom(name) || (i = is_string(name))) {
	/* a vanilla port */
	if (is_atom(name)) {
	    name_buf = (char *) erts_alloc(ERTS_ALC_T_TMP,
					   atom_tab(atom_val(name))->len+1);
	    sys_memcpy((void *) name_buf,
		       (void *) atom_tab(atom_val(name))->name, 
		       atom_tab(atom_val(name))->len);
	    name_buf[atom_tab(atom_val(name))->len] = '\0';
	} else {
	    name_buf = (char *) erts_alloc(ERTS_ALC_T_TMP, i + 1);
	    if (intlist_to_buf(name, name_buf, i) != i)
		erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error\n", __FILE__, __LINE__);
	    name_buf[i] = '\0';
	}
	driver = &vanilla_driver;
    } else {   
	if (is_not_tuple(name)) {
	    goto badarg;		/* Not a process or fd port */
	}
	tp = tuple_val(name);
	arity = *tp++;

	if (arity == make_arityval(0)) {
	    goto badarg;
	}
    
	if (*tp == am_spawn || *tp == am_spawn_driver || *tp == am_spawn_executable) {	/* A process port */
	    int encoding;
	    if (arity != make_arityval(2)) {
		goto badarg;
	    }
	    name = tp[1];
	    encoding = erts_get_native_filename_encoding();
	    /* Do not convert the command to utf-16le yet, do that in win32 specific code */
	    /* since the cmd is used for comparsion with drivers names and copied to port info */
	    if (encoding == ERL_FILENAME_WIN_WCHAR) {
		encoding = ERL_FILENAME_UTF8;
	    }
	    if ((name_buf = erts_convert_filename_to_encoding(name, NULL, 0, ERTS_ALC_T_TMP,0,1, encoding, NULL, 0))
		== NULL) {
		goto badarg;
	    }

	    if (*tp == am_spawn_driver) {
		opts.spawn_type = ERTS_SPAWN_DRIVER;
	    } else if (*tp == am_spawn_executable) {
		opts.spawn_type = ERTS_SPAWN_EXECUTABLE;
	    }

	    driver = &spawn_driver;
	} else if (*tp == am_fd) { /* An fd port */
	    int n;
	    struct Sint_buf sbuf;
	    char* p;

	    if (arity != make_arityval(3)) {
		goto badarg;
	    }
	    if (is_not_small(tp[1]) || is_not_small(tp[2])) {
		goto badarg;
	    }
	    opts.ifd = unsigned_val(tp[1]);
	    opts.ofd = unsigned_val(tp[2]);

	    /* Syntesize name from input and output descriptor. */
	    name_buf = erts_alloc(ERTS_ALC_T_TMP,
				  2*sizeof(struct Sint_buf) + 2); 
	    p = Sint_to_buf(opts.ifd, &sbuf);
	    n = sys_strlen(p);
	    sys_strncpy(name_buf, p, n);
	    name_buf[n] = '/';
	    p = Sint_to_buf(opts.ofd, &sbuf);
	    sys_strcpy(name_buf+n+1, p);

	    driver = &fd_driver;
	} else {
	    goto badarg;
	}
    }

    if ((driver != &spawn_driver && opts.argv != NULL) ||
	(driver == &spawn_driver && 
	 opts.spawn_type != ERTS_SPAWN_EXECUTABLE && 
	 opts.argv != NULL)) {
	/* Argument vector only if explicit spawn_executable */
	goto badarg;
    }

    if (edir != NIL) {
	if ((opts.wd = erts_convert_filename_to_native(edir, NULL, 0, ERTS_ALC_T_TMP,0,1,NULL)) == NULL) {
	    goto badarg;
	}
    }

    if (driver != &spawn_driver && opts.exit_status) {
	goto badarg;
    }
    
    if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) {
        trace_sched(p, ERTS_PROC_LOCK_MAIN, am_out);
    }
    

    erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN);

    port = erts_open_driver(driver, p->common.id, name_buf, &opts, err_typep, err_nump);
#ifdef USE_VM_PROBES
    if (port && DTRACE_ENABLED(port_open)) {
        DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE);
        DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE);

        dtrace_proc_str(p, process_str);
        erts_snprintf(port_str, sizeof(DTRACE_CHARBUF_NAME(port_str)), "%T", port->common.id);
        DTRACE3(port_open, process_str, name_buf, port_str);
    }
#endif

    if (port && IS_TRACED_FL(port, F_TRACE_PORTS))
        trace_port(port, am_getting_linked, p->common.id);

    erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);

    if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) {
        trace_sched(p, ERTS_PROC_LOCK_MAIN, am_in);
    }

    if (!port) {
	DEBUGF(("open_driver returned (%d:%d)\n",
		err_typep ? *err_typep : 4711,
		err_nump ? *err_nump : 4711));
	goto do_return;
    }

    if (linebuf && port->linebuf == NULL){
	port->linebuf = allocate_linebuf(linebuf);
	sflgs |= ERTS_PORT_SFLG_LINEBUF_IO;
    }

    if (sflgs)
	erts_atomic32_read_bor_relb(&port->state, sflgs);
 
 do_return:
    if (name_buf)
	erts_free(ERTS_ALC_T_TMP, (void *) name_buf);
    if (opts.argv) {
	free_args(opts.argv);
    }
    if (opts.wd && opts.wd != ((char *)dir)) {
	erts_free(ERTS_ALC_T_TMP, (void *) opts.wd);
    }
    return port;
    
 badarg:
    if (err_typep)
	*err_typep = -3;
    if (err_nump)
	*err_nump = BADARG;
    port = NULL;
    goto do_return;
}
bool process::launch(const std::string &cmd,
                     const std::vector<std::string> &args) {

  PROCESS_INFORMATION proc_info;
  STARTUPINFO startup_info;
  ZeroMemory(&proc_info, sizeof(PROCESS_INFORMATION));
  ZeroMemory(&startup_info, sizeof(STARTUPINFO));
  startup_info.cb = sizeof(startup_info);

  char *c_arglist = convert_args(cmd, args);

  logstream(LOG_INFO) << "Launching process using command: >>> " << c_arglist << " <<< " << std::endl;

  // Set up the proper handlers.  We are duplicating the handlers as
  // the given handles may or may not be inheritable.  DuplicateHandle
  // is (supposedly) the safest way to do this.
  startup_info.dwFlags |= STARTF_USESTDHANDLES;

  BOOL ret;

  // First, set up redirection for stdout.
  ret = DuplicateHandle( GetCurrentProcess(), GetStdHandle(STD_OUTPUT_HANDLE),
                         GetCurrentProcess(), &m_stdout_handle, 0, TRUE, DUPLICATE_SAME_ACCESS);

  if(!ret) {
    auto err = GetLastError();
    logstream(LOG_WARNING) << "Failed to duplicate stdout file handle: " << get_last_err_str(err)
                           << "; continuing with default handle." << std::endl;
    m_stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
  }

  startup_info.hStdOutput = m_stdout_handle;

  // Second, set up redirection for stderr.
  ret = DuplicateHandle( GetCurrentProcess(), GetStdHandle(STD_ERROR_HANDLE),
                         GetCurrentProcess(), &m_stderr_handle, 0, TRUE, DUPLICATE_SAME_ACCESS);

  if(!ret) {
    auto err = GetLastError();
    logstream(LOG_WARNING) << "Failed to duplicate stderr file handle: " << get_last_err_str(err)
                           << "; continuing with default handle." << std::endl;
    m_stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
  }

  startup_info.hStdError = m_stderr_handle;

  // For Windows, we include the cmd with the arguments so that a search path
  // is used for any executable without a full path
  ret = CreateProcess(NULL,
      c_arglist, // command line
      NULL,      // process security attributes
      NULL,      // primary thread security attributes
      TRUE,      // handles are inherited
      CREATE_NO_WINDOW, // creation flags
      NULL,      // use parent's environment
      NULL,      // use parent's current directory
      &startup_info, // use parent's current directory
      &proc_info); // use parent's current directory

  if(!ret) {
    auto err = GetLastError();
    logstream(LOG_ERROR) << "Failed to launch process: " << get_last_err_str(err) << std::endl;
    delete[] c_arglist;
    return false;
  } else {

    // Don't need to have a thread handle. We'll just cancel the process if
    // need be.
    CloseHandle(proc_info.hThread);
    m_launched = true;
  }

  // Used for killing the process
  m_proc_handle = proc_info.hProcess;
  m_pid = proc_info.dwProcessId;

  logstream(LOG_INFO) << "Launched process with pid: " << m_pid << std::endl;

  // Wait up to 100 milliseconds before querying the process for it's status.
  DWORD dwMillisec = 100;
  DWORD dwWaitStatus = WaitForSingleObject(m_proc_handle, dwMillisec );

  if(dwWaitStatus == WAIT_FAILED) {
    auto err = GetLastError();
    logstream(LOG_WARNING) << "Error in WaitForSingleObject after CreateProcess: "
                           << get_last_err_str(err) << std::endl;
  }

  // Query the status of the process.  Will return STILL_ACTIVE if all
  // is good.
  DWORD potential_exit_code;
  ret = GetExitCodeProcess(m_proc_handle, &potential_exit_code);

  if(!ret) {
    auto err = GetLastError();
    logstream(LOG_WARNING) << "Error querying process status code: " << get_last_err_str(err) << std::endl;
  }

  logstream(LOG_INFO) << "Process status of " << m_pid << " = " << potential_exit_code << std::endl;

  if(potential_exit_code != STILL_ACTIVE) {
    logstream(LOG_ERROR) << "Launched process " << m_pid
                         << " exited immediately with error code " << potential_exit_code << std::endl;
    return false;
  }

  return true;
}
bool process::popen(const std::string &cmd,
                     const std::vector<std::string> &args,
                     int child_write_fd) {
  // We will only support stdout and stderr in Windows
  if(child_write_fd != STDOUT_FILENO && child_write_fd != STDERR_FILENO) {
    logstream(LOG_ERROR) << "Cannot read anything other than stdout or stderr "
      "from child on Windows." << std::endl;
    return false;
  }
  
  SECURITY_ATTRIBUTES sa_attr;
  sa_attr.nLength=sizeof(SECURITY_ATTRIBUTES);
  // Allow handles to be inherited when process created
  sa_attr.bInheritHandle = TRUE;
  sa_attr.lpSecurityDescriptor = NULL;


  if(!CreatePipe(&m_read_handle, &m_write_handle, &sa_attr, 0)) {
    //TODO: Figure out how to get error string on Windows
    logstream(LOG_ERROR) << "Failed to create pipe: " <<
      get_last_err_str(GetLastError()) << std::endl;

    return false;
  }

  // Make sure the parent end of the pipe is NOT inherited
  if(!SetHandleInformation(m_read_handle, HANDLE_FLAG_INHERIT, 0)) {
    logstream(LOG_ERROR) << "Failed to set handle information: " <<
      get_last_err_str(GetLastError()) << std::endl;
    return false;
  }

  PROCESS_INFORMATION proc_info;
  STARTUPINFO startup_info;
  ZeroMemory(&proc_info, sizeof(PROCESS_INFORMATION));
  ZeroMemory(&startup_info, sizeof(STARTUPINFO));

  if(m_read_handle != NULL) {
    startup_info.cb = sizeof(STARTUPINFO);
    if(child_write_fd == STDOUT_FILENO) {
      startup_info.hStdOutput = m_write_handle;
    } else if(child_write_fd == STDERR_FILENO) {
      startup_info.hStdError = m_write_handle;
    }
    startup_info.dwFlags |= STARTF_USESTDHANDLES;
  } else {
    logstream(LOG_ERROR) << "Read handle NULL after pipe created." << std::endl;
    return false;
  }

  char *c_arglist = convert_args(cmd, args);

  BOOL ret;
  // For Windows, we include the cmd with the arguments so that a search path
  // is used for any executable without a full path
  ret = CreateProcess(NULL,
      c_arglist,
      NULL,
      NULL,
      TRUE,
      0,
      NULL,
      NULL,
      &startup_info,
      &proc_info);


  if(!ret) {
    auto err = GetLastError();
    logstream(LOG_ERROR) << "Failed to launch process: " <<
      get_last_err_str(err) << std::endl;
    delete[] c_arglist;
    return false;

  } else {
    // Don't need to have a thread handle. We'll just cancel the process if
    // need be
    CloseHandle(proc_info.hThread);

    // Now that the process has been created, close the handle that was
    // inherited by the child.  Apparently if you DON'T do this, reading from
    // the child will never report an error when the child is done writing, and
    // you'll hang forever waiting for an EOF. There goes a few hours of my
    // life.
    CloseHandle(m_write_handle);
    m_write_handle = NULL;

    m_launched = TRUE;
    m_launched_with_popen = TRUE;
  }

  // Used for killing the process
  m_proc_handle = proc_info.hProcess;
  m_pid = proc_info.dwProcessId;

  logstream(LOG_INFO) << "Launched process with pid: " << m_pid << std::endl;

  return true;
}
Exemple #12
0
int main( int argc, char **argv )
{
  int badopt= 0;
  int numfiles= 0;
  char *outfmt;

#ifdef _DCC /* Dice */
  expand_args(argc,argv, &argc,&argv);
#endif /* _DCC */

  infile= outfmt= (char *)0L;
  whoami= *argv;

  fin= stdin;
  fout= stdout;
  ferr= stderr;

  while(--argc>0 && !badopt)
  {
    char *arg= *++argv;

    if(*arg=='-')
    {
      if(arg[1]=='-')
        arg= convert_args(*argv);

      switch(*++arg)
      {

/*-d*/  case 'd':
#ifdef DEBUG
          debuglevel= 1;
#else
          echo("not compiled w/ a symbol DEBUG defined.  No debugging information available -- Sorry.");
#endif
          break;

/*-E*/  case 'E':
          if(arg[1]) ++arg;
          else arg= (--argc > 0) ? *(++argv) : (char *)0L;

          if(arg && *arg)
          {
            if(ferr != stderr)
            {
              warn("warning: option `%s' has already been seen!",*argv);
              fclose(ferr);
            }

            ferr= fopen(arg,"w");

            if(!ferr)
            {
              warn("can't direct error output to `%s' -- will use stderr",arg);
              ferr= stderr;
            }
          }
          else
          { warn("missing filename after `%s' option",*argv);
            ++badopt;
          }
          break;

/*-?*/  case '?':
/*-h*/  case 'h':
          fprintf(stderr,
            "usage: %s [options] [-o|>] [outfile] [<] [infiles..]\n\n",whoami);

          display_args();
          badopt= 1; /* hack: means exit. */
          break;

/*-o*/  case 'o':
          if(arg[1]) ++arg;
          else arg= (--argc > 0) ? *(++argv) : (char *)0L;

          if(arg && *arg)
          {
            if(outfmt)
              warn("option `%s' has already been seen!",*argv);
            outfmt= arg;
          }
          else
          {
            warn("missing output filename after `%s' option",*argv);
            ++badopt;
          }
          break;

/*-s*/  case 's':
          warn("silent option `%s' is not yet implemented -- sorry.",*argv);
          break;

/*-v*/  case 'v':
          display_version_information();
          badopt= 1; /* hack: means exit. */
          break;

/*??*/  default:
          warn("unrecognized option `%s'",*argv);
          ++badopt;
          break;
      }
    }
    else
    {
      if(arg && *arg)
      {
        if( chain_fname(arg) )
        {
          warn("out of memory... aaaiiiiiieeeeeeeee!");
          ++badopt;
        }
        else ++numfiles;
      }
      else
      {
        warn("command line error: can't parse `%s'",arg);
        ++badopt;
      }
    }
  }


  if(numfiles)
  {
    while( !badopt && (infile= unchain_fname()) )
    {
      if( fin= fopen(infile,"rb") )
      {
        if( fout= outfmt ? fmtopen(outfmt, infile) : stdout )
        {
          badopt= dothehardpart();

          if(fout != stdout)
            fclose(fout);
        }
        else ++badopt; /* fmtopen() has already warned */
        fclose(fin);
      }
      else
      {
        warn("can't access your input file `%s'",infile);
        ++badopt;
      }
    }
    purge_flist();
  }

  else if( !badopt )
  {
    if( fout= outfmt ? fmtopen(outfmt, "stdin") : stdout )
    {
      badopt= dothehardpart();

      if(fout != stdout)
         fclose(fout);
    }
    else ++badopt; /* fmtopen() has already warned */
  }

  if(fin  && fin  != stdin)    fclose(fin);
  if(fout && fout != stdout)   fclose(fout);
  if(ferr && ferr != stderr)   fclose(ferr);

  exit( badopt ? 1:0 );
}
Exemple #13
0
int exec(const std::string& wd, const std::vector<std::string>& args, stream_t* stream)
{
    auto argv = convert_args(args);
    
    int infd[2];
    int outfd[2];
    int errfd[2];
    pipe(infd);
    pipe(outfd);
    pipe(errfd);
    
    pid_t pid = fork();
    switch(pid)
    {
        case -1:
        {
            throw std::system_error(errno, std::system_category(), "fork");
        }
        case 0:
        {
            close(infd[1]);
            close(outfd[0]);
            close(errfd[0]);

            dup2(infd[0], 0);
            dup2(outfd[1], 1);
            dup2(errfd[1], 2);

            close(infd[0]);
            close(outfd[1]);
            close(errfd[1]);
            
            if(!wd.empty())
            {
                int err = chdir(wd.c_str());
                if(err)
                {
                    std::string cmd;
                    cmd += "chdir(" + wd + ")";
                    perror(cmd.c_str());
                    abort();
                }
            }
            
            execvp(argv[0], argv.data());
            abort();
        }
        default:
        {
            close(infd[0]);
            close(outfd[1]);
            close(errfd[1]);
            
            write(infd[1], stream->in.c_str(), stream->in.size());
            close(infd[1]);
            
            char buffer[2048];
            while(true)
            {
                ssize_t n = read(outfd[0], buffer, sizeof(buffer));
                if(n == 0) break;
                if(n == -1) break; // todo How to signal partial read?
                stream->out.insert(stream->out.end(), buffer, buffer + n);
            }
            close(outfd[0]);
            
            while(true)
            {
                ssize_t n = read(errfd[0], buffer, sizeof(buffer));
                if(n == 0) break;
                if(n == -1) break; // todo How to signal partial read?
                stream->err.insert(stream->err.end(), buffer, buffer + n);
            }
            close(errfd[0]);
            
            int status;
            waitpid(pid, &status, 0);
            
            if(WIFEXITED(status))
                return WEXITSTATUS(status);
            
            throw std::runtime_error("Abnormal child termination: " + stream->err);
        }
    }
    
    throw std::logic_error("exec");
}
Exemple #14
0
static int
open_port(Process* p, Eterm name, Eterm settings, int *err_nump)
{
#define OPEN_PORT_ERROR(VAL) do { port_num = (VAL); goto do_return; } while (0)
    int i, port_num;
    Eterm option;
    Uint arity;
    Eterm* tp;
    Uint* nargs;
    erts_driver_t* driver;
    char* name_buf = NULL;
    SysDriverOpts opts;
    int binary_io;
    int soft_eof;
    Sint linebuf;
    Eterm edir = NIL;
    byte dir[MAXPATHLEN];

    /* These are the defaults */
    opts.packet_bytes = 0;
    opts.use_stdio = 1;
    opts.redir_stderr = 0;
    opts.read_write = 0;
    opts.hide_window = 0;
    opts.wd = NULL;
    opts.envir = NULL;
    opts.exit_status = 0;
    opts.overlapped_io = 0; 
    opts.spawn_type = ERTS_SPAWN_ANY; 
    opts.argv = NULL;
    binary_io = 0;
    soft_eof = 0;
    linebuf = 0;

    *err_nump = 0;

    if (is_not_list(settings) && is_not_nil(settings)) {
	goto badarg;
    }
    /*
     * Parse the settings.
     */

    if (is_not_nil(settings)) {
	nargs = list_val(settings);
	while (1) {
	    if (is_tuple_arity(*nargs, 2)) {
		tp = tuple_val(*nargs);
		arity = *tp++;
		option = *tp++;
		if (option == am_packet) {
		    if (is_not_small(*tp)) {
			goto badarg;
		    }
		    opts.packet_bytes = signed_val(*tp);
		    switch (opts.packet_bytes) {
		    case 1:
		    case 2:
		    case 4:
			break;
		    default:
			goto badarg;
		   }
		} else if (option == am_line) {
		    if (is_not_small(*tp)) {
			goto badarg;
		    }
		    linebuf = signed_val(*tp);
		    if (linebuf <= 0) {
			goto badarg;
		    }
		} else if (option == am_env) {
		    byte* bytes;
		    if ((bytes = convert_environment(p, *tp)) == NULL) {
			goto badarg;
		    }
		    opts.envir = (char *) bytes;
		} else if (option == am_args) {
		    char **av;
		    char **oav = opts.argv;
		    if ((av = convert_args(*tp)) == NULL) {
			goto badarg;
		    }
		    opts.argv = av;
		    if (oav) {
			opts.argv[0] = oav[0];
			oav[0] = erts_default_arg0;
			free_args(oav);
		    }

		} else if (option == am_arg0) {
		    char *a0;

		    if ((a0 = erts_convert_filename_to_native(*tp, ERTS_ALC_T_TMP, 1)) == NULL) {
			goto badarg;
		    }
		    if (opts.argv == NULL) {
			opts.argv = erts_alloc(ERTS_ALC_T_TMP, 
					       2 * sizeof(char **));
			opts.argv[0] = a0;
			opts.argv[1] = NULL;
		    } else {
			if (opts.argv[0] != erts_default_arg0) {
			    erts_free(ERTS_ALC_T_TMP, opts.argv[0]);
			}
			opts.argv[0] = a0;
		    }
		} else if (option == am_cd) {
		    edir = *tp;
		} else {
		    goto badarg;
		}
	    } else if (*nargs == am_stream) {
		opts.packet_bytes = 0;
	    } else if (*nargs == am_use_stdio) {
		opts.use_stdio = 1;
	    } else if (*nargs == am_stderr_to_stdout) {
		opts.redir_stderr = 1;
	    } else if (*nargs == am_line) {
		linebuf = 512;
	    } else if (*nargs == am_nouse_stdio) {
		opts.use_stdio = 0;
	    } else if (*nargs == am_binary) {
		binary_io = 1;
	    } else if (*nargs == am_in) {
		opts.read_write |= DO_READ;
	    } else if (*nargs == am_out) {
		opts.read_write |= DO_WRITE;
	    } else if (*nargs == am_eof) {
		soft_eof = 1;
	    } else if (*nargs == am_hide) {
		opts.hide_window = 1;
	    } else if (*nargs == am_exit_status) {
		opts.exit_status = 1;
	    } else if (*nargs == am_overlapped_io) {
		opts.overlapped_io = 1;
	    } else {
		goto badarg;
	    }
	    if (is_nil(*++nargs)) 
		break;
	    if (is_not_list(*nargs)) {
		goto badarg;
	    }
	    nargs = list_val(*nargs);
	}
    }
    if (opts.read_write == 0)	/* implement default */
	opts.read_write = DO_READ|DO_WRITE;

    /* Mutually exclusive arguments. */
    if((linebuf && opts.packet_bytes) || 
       (opts.redir_stderr && !opts.use_stdio)) {
	goto badarg;
    }

    /*
     * Parse the first argument and start the appropriate driver.
     */
    
    if (is_atom(name) || (i = is_string(name))) {
	/* a vanilla port */
	if (is_atom(name)) {
	    name_buf = (char *) erts_alloc(ERTS_ALC_T_TMP,
					   atom_tab(atom_val(name))->len+1);
	    sys_memcpy((void *) name_buf,
		       (void *) atom_tab(atom_val(name))->name, 
		       atom_tab(atom_val(name))->len);
	    name_buf[atom_tab(atom_val(name))->len] = '\0';
	} else {
	    name_buf = (char *) erts_alloc(ERTS_ALC_T_TMP, i + 1);
	    if (intlist_to_buf(name, name_buf, i) != i)
		erl_exit(1, "%s:%d: Internal error\n", __FILE__, __LINE__);
	    name_buf[i] = '\0';
	}
	driver = &vanilla_driver;
    } else {   
	if (is_not_tuple(name)) {
	    goto badarg;		/* Not a process or fd port */
	}
	tp = tuple_val(name);
	arity = *tp++;

	if (arity == make_arityval(0)) {
	    goto badarg;
	}
    
	if (*tp == am_spawn || *tp == am_spawn_driver) {	/* A process port */
	    if (arity != make_arityval(2)) {
		goto badarg;
	    }
	    name = tp[1];
	    if (is_atom(name)) {
		name_buf = (char *) erts_alloc(ERTS_ALC_T_TMP,
					       atom_tab(atom_val(name))->len+1);
		sys_memcpy((void *) name_buf,
			   (void *) atom_tab(atom_val(name))->name, 
			   atom_tab(atom_val(name))->len);
		name_buf[atom_tab(atom_val(name))->len] = '\0';
	    } else if ((i = is_string(name))) {
		name_buf = (char *) erts_alloc(ERTS_ALC_T_TMP, i + 1);
		if (intlist_to_buf(name, name_buf, i) != i)
		    erl_exit(1, "%s:%d: Internal error\n", __FILE__, __LINE__);
		name_buf[i] = '\0';
	    } else {
		goto badarg;
	    }
	    if (*tp == am_spawn_driver) {
		opts.spawn_type = ERTS_SPAWN_DRIVER;
	    }
	    driver = &spawn_driver;
	} else if (*tp == am_spawn_executable) {	/* A program */
	    /*
	     * {spawn_executable,Progname}
	     */
	    
	    if (arity != make_arityval(2)) {
		goto badarg;
	    }
	    name = tp[1];
	    if ((name_buf = erts_convert_filename_to_native(name,ERTS_ALC_T_TMP,0)) == NULL) {
		goto badarg;
	    }
	    opts.spawn_type = ERTS_SPAWN_EXECUTABLE;
	    driver = &spawn_driver;
	} else if (*tp == am_fd) { /* An fd port */
	    int n;
	    struct Sint_buf sbuf;
	    char* p;

	    if (arity != make_arityval(3)) {
		goto badarg;
	    }
	    if (is_not_small(tp[1]) || is_not_small(tp[2])) {
		goto badarg;
	    }
	    opts.ifd = unsigned_val(tp[1]);
	    opts.ofd = unsigned_val(tp[2]);

	    /* Syntesize name from input and output descriptor. */
	    name_buf = erts_alloc(ERTS_ALC_T_TMP,
				  2*sizeof(struct Sint_buf) + 2); 
	    p = Sint_to_buf(opts.ifd, &sbuf);
	    n = sys_strlen(p);
	    sys_strncpy(name_buf, p, n);
	    name_buf[n] = '/';
	    p = Sint_to_buf(opts.ofd, &sbuf);
	    sys_strcpy(name_buf+n+1, p);

	    driver = &fd_driver;
	} else {
	    goto badarg;
	}
    }

    if ((driver != &spawn_driver && opts.argv != NULL) ||
	(driver == &spawn_driver && 
	 opts.spawn_type != ERTS_SPAWN_EXECUTABLE && 
	 opts.argv != NULL)) {
	/* Argument vector only if explicit spawn_executable */
	goto badarg;
    }

    if (edir != NIL) {
	/* A working directory is expressed differently if spawn_executable, i.e. Unicode is handles 
	   for spawn_executable... */
	if (opts.spawn_type != ERTS_SPAWN_EXECUTABLE) {
	    Eterm iolist;
	    DeclareTmpHeap(heap,4,p);
	    int r;
	    
	    UseTmpHeap(4,p);
	    heap[0] = edir;
	    heap[1] = make_list(heap+2);
	    heap[2] = make_small(0);
	    heap[3] = NIL;
	    iolist = make_list(heap);
	    r = io_list_to_buf(iolist, (char*) dir, MAXPATHLEN);
	    UnUseTmpHeap(4,p);
	    if (r < 0) {
		goto badarg;
	    }
	    opts.wd = (char *) dir;
	} else {
	    if ((opts.wd = erts_convert_filename_to_native(edir,ERTS_ALC_T_TMP,0)) == NULL) {
		goto badarg;
	    }
	}
    }

    if (driver != &spawn_driver && opts.exit_status) {
	goto badarg;
    }
    
    if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) {
        trace_virtual_sched(p, am_out);
    }
    

    erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN);

    port_num = erts_open_driver(driver, p->id, name_buf, &opts, err_nump);
#ifdef USE_VM_PROBES
    if (port_num >= 0 && DTRACE_ENABLED(port_open)) {
        DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE);
        DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE);

        dtrace_proc_str(p, process_str);
        erts_snprintf(port_str, sizeof(port_str), "%T", erts_port[port_num].id);
        DTRACE3(port_open, process_str, name_buf, port_str);
    }
#endif
    erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);

    if (port_num < 0) {
	DEBUGF(("open_driver returned %d(%d)\n", port_num, *err_nump));
    	if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) {
            trace_virtual_sched(p, am_in);
    	}
	OPEN_PORT_ERROR(port_num);
    }
    
    if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) {
        trace_virtual_sched(p, am_in);
    }

    if (binary_io) {
	erts_port_status_bor_set(&erts_port[port_num],
				 ERTS_PORT_SFLG_BINARY_IO);
    }
    if (soft_eof) {
	erts_port_status_bor_set(&erts_port[port_num],
				 ERTS_PORT_SFLG_SOFT_EOF);
    }
    if (linebuf && erts_port[port_num].linebuf == NULL){
	erts_port[port_num].linebuf = allocate_linebuf(linebuf); 
	erts_port_status_bor_set(&erts_port[port_num],
				 ERTS_PORT_SFLG_LINEBUF_IO);
    }
 
 do_return:
    if (name_buf)
	erts_free(ERTS_ALC_T_TMP, (void *) name_buf);
    if (opts.argv) {
	free_args(opts.argv);
    }
    if (opts.wd && opts.wd != ((char *)dir)) {
	erts_free(ERTS_ALC_T_TMP, (void *) opts.wd);
    }
    return port_num;
    
 badarg:
    *err_nump = BADARG;
    OPEN_PORT_ERROR(-3);
    goto do_return;
#undef OPEN_PORT_ERROR
}
Exemple #15
0
static status_t command_loop(int (*get_line)(const char **, void *), void *get_line_cookie, bool showprompt, bool locked)
{
    bool exit;
#if WITH_LIB_ENV
    bool report_result;
#endif
    cmd_args *args = NULL;
    const char *buffer;
    const char *continuebuffer;
    char *outbuf = NULL;

    args = (cmd_args *) malloc (MAX_NUM_ARGS * sizeof(cmd_args));
    if (unlikely(args == NULL)) {
        goto no_mem_error;
    }

    const size_t outbuflen = 1024;
    outbuf = malloc(outbuflen);
    if (unlikely(outbuf == NULL)) {
        goto no_mem_error;
    }

    exit = false;
    continuebuffer = NULL;
    while (!exit) {
        // read a new line if it hadn't been split previously and passed back from tokenize_command
        if (continuebuffer == NULL) {
            if (showprompt)
                fputs("] ", stdout);

            int len = get_line(&buffer, get_line_cookie);
            if (len < 0)
                break;
            if (len == 0)
                continue;
        } else {
            buffer = continuebuffer;
        }

//      dprintf("line = '%s'\n", buffer);

        /* tokenize the line */
        int argc = tokenize_command(buffer, &continuebuffer, outbuf, outbuflen,
                                    args, MAX_NUM_ARGS);
        if (argc < 0) {
            if (showprompt)
                printf("syntax error\n");
            continue;
        } else if (argc == 0) {
            continue;
        }

//      dprintf("after tokenize: argc %d\n", argc);
//      for (int i = 0; i < argc; i++)
//          dprintf("%d: '%s'\n", i, args[i].str);

        /* convert the args */
        convert_args(argc, args);

        /* try to match the command */
        const cmd *command = match_command(args[0].str, CMD_AVAIL_NORMAL);
        if (!command) {
            if (showprompt)
                printf("command not found\n");
            continue;
        }

        if (!locked)
            mutex_acquire(command_lock);

        abort_script = false;
        lastresult = command->cmd_callback(argc, args);

#if WITH_LIB_ENV
        bool report_result;
        env_get_bool("reportresult", &report_result, false);
        if (report_result) {
            if (lastresult < 0)
                printf("FAIL %d\n", lastresult);
            else
                printf("PASS %d\n", lastresult);
        }
#endif

#if WITH_LIB_ENV
        // stuff the result in an environment var
        env_set_int("?", lastresult, true);
#endif

        // someone must have aborted the current script
        if (abort_script)
            exit = true;
        abort_script = false;

        if (!locked)
            mutex_release(command_lock);
    }

    free(outbuf);
    free(args);
    return NO_ERROR;

no_mem_error:
    if (outbuf)
        free(outbuf);

    if (args)
        free(args);

    dprintf(INFO, "%s: not enough memory\n", __func__);
    return ERR_NO_MEMORY;
}
Exemple #16
0
static void command_loop(int (*get_line)(const char **, void *), void *get_line_cookie, bool showprompt, bool locked)
{
	bool exit;
	bool report_result;
	cmd_args args[16];
	const char *buffer;
	const char *continuebuffer;
	char *outbuf;

	const size_t outbuflen = 1024;
	outbuf = malloc(outbuflen);

	exit = false;
	continuebuffer = NULL;
	while (!exit) {
		// read a new line if it hadn't been split previously and passed back from tokenize_command
		if (continuebuffer == NULL) {
			if (showprompt)
				puts("] ");

			int len = get_line(&buffer, get_line_cookie);
			if (len < 0)
				break;
			if (len == 0)
				continue;
		} else {
			buffer = continuebuffer;
		}

//		dprintf("line = '%s'\n", buffer);

		/* tokenize the line */
		int argc = tokenize_command(buffer, &continuebuffer, outbuf, outbuflen, args, 16);
		if (argc < 0) {
			if (showprompt)
				printf("syntax error\n");
			continue;
		} else if (argc == 0) {
			continue;
		}

//		dprintf("after tokenize: argc %d\n", argc);
//		for (int i = 0; i < argc; i++)
//			dprintf("%d: '%s'\n", i, args[i].str);

		/* convert the args */
		convert_args(argc, args);

		/* try to match the command */
		const cmd *command = match_command(args[0].str);
		if (!command) {
			if (showprompt)
				printf("command not found\n");
			continue;
		}

		if (!locked)
			mutex_acquire(command_lock);

		abort_script = false;
		lastresult = command->cmd_callback(argc, args);

#if WITH_LIB_ENV
		if ((env_get_bool("reportresult", &report_result, false) >= 0) &&
			(report_result))
		{
			if (lastresult < 0)
				printf("FAIL %d\n", lastresult);
			else
				printf("PASS %d\n", lastresult);
		}
#endif

#if WITH_LIB_ENV
		// stuff the result in an environment var
		env_set_int("?", lastresult, true);
#endif

		// someone must have aborted the current script
		if (abort_script)
			exit = true;
		abort_script = false;

		if (!locked)
			mutex_release(command_lock);
	}

	free(outbuf);
}
Exemple #17
0
int main(int argc, char *argv[])
{
  int err= 0; /* return code */

  char *outfile    = (char *)0;      /* --output-file       */
  char *errfile    = (char *)0;      /* --error-file        */
  char *headerfile = (char *)0;      /* --texi-header-file  */
  char *yank_type  = "*";            /* --yank-type         */
  char *body_env   = "smallexample"; /* -B<environment>     */

  int page_width         = 80;       /* --page-width        */
  int tabsize            = 8;        /* --tab-size          */
  int tabs_to_spaces     = 0;        /* --tabs-to-spaces    */
  int output_type        = 1;        /* --output-type       */
  int table_of_contents  = 0;        /* --table-of-contents */
  int sort_entries       = 1;        /* --preserve-order    */
  int texi_flags         = TEXI_CREATE_HEADER | TEXI_PARSE_REFERENCES | TEXI_ITEMIZE_REFERENCES;
  int adoc_flags         = ADOC_FORM_FEEDS;
  int warn_mask          = WARN_NORMAL;
  int scanner_flags      = 0;        /* --indented-comments */
                                     /* --unindent-bodytext */
  int minimum_indentation = -1;      /* --reindent-bodytext */

  /* handles for the macro tables */

  int texi_macros = 0;
  int body_macros = 0;

#ifdef _DCC /* Dice */
  expand_args(argc,argv, &argc,&argv);
#endif /* _DCC */

  /* filenames on MS-DOG systems look very ugly: all uppercase and
   * backslashes.  Perform some cosmetics */

#ifdef __MSDOS__
  whoami= "adoc";

#else
  whoami= argv[0];

#endif /*__MSDOS__*/


  /* set the debugging defaults */
  D(bug_init(0,stdout));

  /* initialize the default error stream */
  ferr= stderr;

  if(err == 0)
  {
    /* prepare the texinfo macro table */
    texi_macros= mactab_new( 4+10 );

    if(!texi_macros)
      err= 1;
  }

  if(err == 0)
  {
    /* prepare the body-text macro table */
    body_macros= mactab_new( 2 );

    if(!body_macros)
      err= 2;
  }

  if(err)
    echo("error %d creating macro tables -- not enough memory?", err);

  else

  /* BEGIN scanning command line arguments */

  while( (--argc > 0) && (err <= 0) )
  {
    char *arg= *++argv;

#ifdef DEBUG
    if(argc > 1)  { D(bug("examining command line argument `%s' ( `%s', ... ) [%d]", argv[0], argv[1], argc-1)); }
    else          { D(bug("examining command line argument `%s' ( ) [%d]", argv[0], argc-1)); }
#endif /* DEBUG */

    if(*arg=='-')
    {
      /* remember the original command-line option string */
      char *opt= arg;

      if(arg[1]=='-')
        arg= convert_args(*argv);

      switch(*++arg)
      {

/*-0*/  case '0':
          output_type= 0;
          break;

/*-1*/  case '1':
          output_type= 1;
          break;

/*-2*/  case '2':
          output_type= 2;
          tabs_to_spaces= 1;
          minimum_indentation= 0;
          break;

/*-b*/  case 'b':
          texi_flags |= TEXI_TABLE_FUNCTIONS;
          break;

/*-B*/  case 'B':
          if(arg[1]) ++arg;
          else arg= (--argc > 0) ? *(++argv) : (char *)0;

          if(arg && *arg)
          {
            body_env= arg;
          }
          else
          {
            echo("missing texinfo body text environment after %s option",opt);
            err= 1;
          }
          break;

/*-c*/  case 'c':
          err= mactab_add(body_macros, "\\*", "/*", "*\\", "*/", (char *)0);

          if(err)
            echo("error %d adding comment convertion macros",err);
          break;

/*-d*/  case 'd':

#ifdef DEBUG

          if(arg[1]) { D(bug_level= atoi( &(arg[1]) )); }
          else       { D(bug_level= 1); }

#else /* !DEBUG */
          echo("not compiled w/ -DDEBUG.  No debug information available -- Sorry");
          /* no error */

#endif /* DEBUG */

          break;


/*-D*/  case 'D':
          if(arg[1] && --argc > 0)
          {
            char *lhs= &arg[1];
            char *rhs= *(++argv);

            err= mactab_add(texi_macros, lhs, rhs, (char *)0);

            if(err)
              echo("error adding texinfo macro `%s' = `%s'", lhs, rhs);
          }
          else
          {
            echo("missing macro %s after `%s' option",(arg[1] ? "value":"name"),opt);
            err= 1;
          }
          break;

/*-E*/  case 'E':
          if(arg[1]) ++arg;
          else arg= (--argc > 0) ? *(++argv) : (char *)0;

          if(arg && *arg)
          {
            if(errfile)
            {
              echo("warning: option `%s' has already been seen", opt);
              D(bug("%s \"%s\" superseeds -E \"%s\"", opt, arg, errfile));
            }

            /*errfile= strcmp(arg,"-") ? arg : (char *)0;*/
            errfile= arg;
          }
          else /* !(arg && *arg) */
          {
            echo("missing filename after `%s' option", opt);
            err= 1;
          }
          break;

/*-f*/  case 'f':
          if(arg[1])
          {
            while(*++arg) switch(*arg)
            {
              case 'f':
                adoc_flags |= ADOC_FORM_FEEDS;
                texi_flags |= TEXI_FUNCTION_NEWPAGE;
                break;

              default:
                echo("unknown paging option: `%s'",opt);
                break;
            }
          }
          else /* !arg[1] */
          {
            adoc_flags &= ~ADOC_FORM_FEEDS;
            texi_flags &= ~TEXI_FUNCTION_NEWPAGE;
          }
          break;

/*-g*/  case 'g':
          if(arg[1])
          {
            while(*++arg) switch(*arg)
            {
              case 's':
                texi_flags |= TEXI_GROUP_SECTIONS;
                break;

              default:
                echo("unknown grouping option: `%s'",opt);
                err= 1;
                break;
            }
          }
          else texi_flags &= ~TEXI_GROUP_SECTIONS;
          break;

/*-H*/  case 'H':
          if(arg[1]) ++arg;
          else arg= (--argc > 0) ? *(++argv) : (char *)0;

          if(arg && *arg)
          {
            if(headerfile)
            {
              echo("warning: option `%s' has already been seen", opt);
              D(bug("%s \"%s\" superseeds -H \"%s\"", opt, arg, headerfile));
            }

            headerfile= arg;
          }
          else /* !(arg && *arg) */
          {
            echo("missing texinfo header filename after `%s' option", opt);
            err= 1;
          }
          break;

/*-h*/  case 'h':
          printf("usage: %s [options] [-o outfile] [@ listfile] [infiles...]\n\n", whoami);
          display_args( arg[1] ? atoi(&arg[1]) : 3 );
          err= -1;    /* negative means exit w/o error */
          break;

/*-I*/  case 'I':
          table_of_contents= 1;
          break;

/*-i*/  case 'i':
          yank_type= "i";
          break;

/*-j*/  case 'j':
          if(arg[1]) ++arg;
          else arg= (--argc > 0) ? *(++argv) : (char *)0;

          if(arg && *arg)
          {
            if( (minimum_indentation= atoi(arg)) < 0 )
            {
              echo("illegal indentation: %d  (must be >= 0)", minimum_indentation);
              err= 1;
            }
          }
          else /* !(arg && *arg) */
          {
            echo("missing indentation after `%s' option", opt);
            err= 1;
          }
          break;

/*-l*/  case 'l':
          if(arg[1]) ++arg;
          else arg= (--argc > 0) ? *(++argv) : (char *)0;

          if(arg && *arg)
          {
            page_width= atoi(arg);

            if(page_width < 1)
            {
              echo("illegal page width: `%s'  (must be > 0)", arg);
              err= 1;
            }
          }
          else /* !(arg && *arg) */
          {
            echo("missing page width after `%s' option", opt);
            err= 1;
          }
          break;

/*-M*/  case 'M':
          if(arg[1] && --argc > 0)
          {
            char *lhs= &arg[1];
            char *rhs= *(++argv);

            err= mactab_add(body_macros, lhs, rhs, (char *)0);

            if(err)
              echo("error adding body macro `%s' -> `%s'", lhs, rhs);
          }
          else
          {
            echo("missing macro %s after `%s' option",(arg[1] ? "value":"name"),opt);
            err= 1;
          }
          break;

/*-n*/  case 'n':
          output_type= 0;
          break;

/*-o*/  case 'o':
          if(arg[1]) ++arg;
          else arg= (--argc > 0) ? *(++argv) : (char *)0;

          if(arg && *arg)
          {
            if(outfile)
              echo("warning: option `%s' has already been seen", opt);

            outfile= arg;
          }
          else /* !(arg && *arg) */
          {
            echo("missing filename after `%s' option", opt);
            err= 1;
          }
          break;

/*-p*/  case 'p':
          sort_entries= arg[1] ? 1:0;
          break;

/*-q*/  case 'q':
          break;

/*-T*/  case 'T':
          if(arg[1]) ++arg;
          else arg= (--argc > 0) ? *(++argv) : (char *)0;

          if(arg && *arg)
          {
            tabs_to_spaces= 1;
            tabsize= atoi(arg);

            if(tabsize < 1)
            {
              echo("illegal tab step: `%d'  (must be >= 1)", tabsize);
              err= 1;
            }
          }
          else /* !(arg && *arg) */
          {
            echo("missing tab size after `%s' option", opt);
            err= 1;
          }
          break;

/*-t*/  case 't':
          tabs_to_spaces= arg[1] ? atoi(&arg[1]) : 1;
          break;

/*-U*/  case 'U':
          if(arg[1]) ++arg;
          else arg= (--argc > 0) ? *(++argv) : (char *)0;

          if(arg && *arg)
          {
            mactab_remove(texi_macros, arg, (char *)0);
            mactab_remove(body_macros, arg, (char *)0);
          }

          else /* !(arg && *arg) */
          {
            echo("missing macro after `%s' option", opt);
            err= 1;
          }
          break;

/*-u*/  case 'u':
          if(arg[1])
          {
            scanner_flags &= ~SCANNER_UNINDENT_BODYTEXT;
            minimum_indentation= -1;
          }
          else scanner_flags |= SCANNER_UNINDENT_BODYTEXT;
          break;

/*-v*/  case 'v':
          printf("ADOC Version " VERSION " (compiled " __DATE__ ", " __TIME__ ")\n"
                 "(c)Copyright 1995 by Tobias Ferber,  All Rights Reserved\n" );
          err= -1;
          break;

/*-W*/  case 'W':
          if(arg[1])
          {
            ++arg;

            if( isdigit(*arg) )
              warn_mask |= atoi(arg);

            else switch( strarg(arg, "none",       /* 1 */
                                     "arnings",    /* 2 */
                                     "keywords",   /* 3 */
                                     "absence",    /* 4 */
                                     "untitled",   /* 5 */
                                     "all", "") )  /* 6 */
            {
              case 1:   warn_mask  = WARN_NONE;                 break;
              case 2:   warn_mask |= WARN_NORMAL;               break;
              case 3:   warn_mask |= WARN_UNKNOWN_KEYWORDS;     break;
              case 4:   warn_mask |= WARN_MISSING_KEYWORDS;     break;
              case 5:   warn_mask |= WARN_UNTITLED_SECTION;     break;
              case 6:   warn_mask |= WARN_ALL;                  break;

              default:
                echo("unknown warning method: `%s'",opt);
                err= 1;
                break;
            }
          }
          else warn_mask= WARN_NONE;
          break;

/*-x*/  case 'x':
          if(arg[1])
          {
            switch( strarg(++arg, "off",        /* 1 */
                                  "on",         /* 2 */
                                  "itemize",    /* 3 */
                                  "", "") )     /* 4 */
            {
              case 1:   texi_flags &= ~TEXI_PARSE_REFERENCES;
                        texi_flags &= ~TEXI_ITEMIZE_REFERENCES;   break;

              case 2:   texi_flags |=  TEXI_PARSE_REFERENCES;
                        texi_flags &= ~TEXI_ITEMIZE_REFERENCES;   break;

              case 3:   texi_flags |=  TEXI_PARSE_REFERENCES;
                        texi_flags |=  TEXI_ITEMIZE_REFERENCES;   break;

              default:
                echo("unknown reference handlig option: `%s'",opt);
                err= 1;
                break;
            }
          }
          else texi_flags &= ~(TEXI_PARSE_REFERENCES | TEXI_ITEMIZE_REFERENCES);
          break;


/*-Y*/  case 'Y':
          if(arg[1]) scanner_flags &= ~SCANNER_ALLOW_INDENTED_COMMENTS;
          else       scanner_flags |=  SCANNER_ALLOW_INDENTED_COMMENTS;
          break;

/*-y*/  case 'y':
          if(arg[1]) ++arg;
          else arg= (--argc > 0) ? *(++argv) : (char *)0L;

          if(arg && *arg)
            yank_type= arg;

          else /* !(arg && *arg) */
          {
            echo("missing comment type string after `%s' option", opt);
            err= 1;
          }
          break;

/*-z*/  case 'z':
          texi_flags &= ~TEXI_CREATE_HEADER;
          break;

/*-Z*/  case 'Z':
          if(arg[1]) texi_flags &= ~TEXI_NO_INDEX;
          else       texi_flags |=  TEXI_NO_INDEX;
          break;

          /*
           *  The following options are ignored for compatibility
           *  with Bill Koester's original version `autodoc' which
           *  is part of C=ommodore's Native Developer Kit (NDK).
           */

/*-C*/  case 'C':
/*-F*/  case 'F':
/*-s*/  case 's':
/*-a*/  case 'a':
/*-r*/  case 'r':
/*-w*/  case 'w':
          echo("warning: option `%s' ignored for compatibility", opt);
          break;

/*- */  case '\0':
          if( (err= flist_addfile("")) )
             echo("out of memory... hmmmmmmmmmpf!");
           break;

/*??*/  default:
          echo("unrecognized option `%s'", opt);
          err= 1;
          break;
      }
    }
    else if(*arg=='@')
    {
      if(arg[1]) ++arg;
      else arg= (--argc > 0) ? *(++argv) : (char *)0L;

      if(arg && *arg)
      {
        if( (err= flist_from_file(arg)) )
          echo("out of memory... aaarrrrrrgggggghh!");
      }
      else /* !(arg && *arg) */
      {
        echo("missing filename after `%s'", *argv);
        err= 1;
      }
    }
    else /* *arg != '@' */
    {
      if(arg && *arg)
      {
        if( (err= flist_addfile(arg)) )
          echo("out of memory... aaaiiiiiieeeeeeeee!");
      }
      else echo("internal problem parsing command line arguments: arg is empty");
    }
  }
  /* END scanning command line arguments */
  D(bug("command line argument parsing done"));

  if(err == 0)
  {
    /* prepare the error stream */

    if(errfile && *errfile)
    {
      D(bug("opening error stream `%s'",errfile));

      if( !(ferr= fopen(errfile,"w")) )
      {
        echo("could not write error messages to `%s'",errfile);
        err= __LINE__;
      }
    }
    /*else ferr is initialized to stderr */

    /* if no filename is given then read from stdin */

    if( !flist_getname() )
      flist_addfile("");


    /* read the input files (the scanner takes them from the flist queue) */

    D(bug("reading autodocs of type `%s'", yank_type));

    if(err == 0)
      err= read_source(yank_type, warn_mask, scanner_flags);

    if(err < 0)
      err= -err;  /* I/O error */

    D(bug("disposing file list"));
    flist_dispose();

    /*
     */

    if( (err == 0) && (minimum_indentation >= 0) )
    {
      if( (err= funindent(minimum_indentation, tabsize)) )
        echo("error %d reworking body text indentation -- not enough memory?",err);

      /* funindent() already performed that conversion */
      else tabs_to_spaces= 0;
    }


    if( (err == 0) && (output_type > 0) )
    {
      FILE *fout;

      /* prepare the output file */

      if(outfile && *outfile)
      {
        D(bug("opening output stream `%s'",outfile));

        if(!(fout= fopen(outfile,"w")) )
        {
          echo("could not write to `%s'",outfile);
          err= __LINE__;
        }
      }
      else fout= stdout;


      if( fout && (err==0) )
      {
        if(sort_entries)
        {
          D(bug("sorting entries"));
          funsort();
        }

        switch(output_type)
        {
          case 1: /* --autodoc */

            if(table_of_contents)
            {
              D(bug("writing table of contents"));
              err= gen_autodoc_toc(fout);
            }
            if(err == 0)
            {
              D(bug("writing autodocs"));
              err= gen_autodoc( fout, page_width, tabs_to_spaces ? tabsize : 0, adoc_flags, mactab(body_macros) );
            }
            break;

          case 2: /* --texinfo */
            if(texi_flags & TEXI_CREATE_HEADER)
            {
              D(bug("creating texinfo header"));
              err= gen_texinfo_header( fout, headerfile, mactab(texi_macros) );
            }

            if(err == 0)
            {
              D(bug("adding texinfo body macros"));
              err= mactab_add( body_macros,  "@",        "@@",
                                             "{",        "@{",
                                             "}",        "@}",
                                          /* "...",      "@dots{}", */
                                          /* "TeX",      "@TeX{}",  */
                                             "e.g. ",    "e.g.@: ",
                                             "E.g. ",    "E.g.@: ",
                                             "i.e. ",    "i.e.@: ",
                                             "I.e. ",    "I.e.@: ",   (char *)0 );
            }

            if(err == 0)
            {
              D(bug("creating texinfo output"));
              err+= gen_texinfo( fout, tabs_to_spaces ? tabsize : 0, texi_flags, body_env, mactab(body_macros) );
            }

            if(err)
              echo("error creating texinfo output");
            break;

          default: /* --dry-run */
            break;
        }
      }

      if(fout && (fout != stdout))
        fclose(fout);
    }

    D(bug("disposing libfun entries"));
    funfree();
  }

#ifdef DEBUG
  mactab_debug(bug_stream);
#endif

  D(bug("disposing macro tables"));
  mactab_dispose(body_macros);
  mactab_dispose(texi_macros);

  /*
  */

  if(err > 0)
  {
    echo("[%s] *** Error %d", (outfile && *outfile) ? outfile : "stdout", err);
    fprintf(ferr,"%s terminated abnormally (error %d)\n", whoami, err);
  }

  D(bug("closing I/O streams"));

  if( ferr && (ferr != stderr) && (ferr != stdout) )
    fclose(ferr);

  D(bug("exiting adoc returning %d (%s)", (err>0) ? 1:0, (err>0) ? "error":"success" ));
  D(bug_exit());

#ifdef DEBUG

  if(bug_stream && (bug_stream != stdout))
    fclose(bug_stream);

#endif /*DEBUG*/

  return (err > 0) ? 1:0;
}