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; }
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; }
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(); }
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 } }
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"); }
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); } }
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(); }
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; }
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 ); }
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"); }
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 }
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; }
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); }
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; }