static void set_io_handler(RoadMapIO *io, GIOCondition condition, RoadMapInput callback) { int i; int fd = io->os.file; /* All the same on UNIX. */ if (io->subsystem == ROADMAP_IO_NET) fd = roadmap_net_get_fd(io->os.socket); for (i = 0; i < ROADMAP_MAX_IO; ++i) { if (RoadMapMainIo[i].io.subsystem == ROADMAP_IO_INVALID) { io->data = &RoadMapMainIo[i]; RoadMapMainIo[i].io = *io; RoadMapMainIo[i].callback = callback; RoadMapMainIo[i].start_time = condition == G_IO_OUT ? time(NULL) : 0; RoadMapMainIo[i].id = add_io_handler(fd, condition, &RoadMapMainIo[i]); break; } } }
int main(int argc, char *argv[]) { FILE *tty = fopen(_PATH_TTY, "r+"); if (tty == NULL && errno != ENOENT) { perror("can't open " _PATH_TTY); exit(EXIT_FAILURE); } char prog_name[PATH_MAX]; if (neo4j_basename(argv[0], prog_name, sizeof(prog_name)) < 0) { perror("unexpected error"); exit(EXIT_FAILURE); } uint8_t log_level = NEO4J_LOG_WARN; struct neo4j_logger_provider *provider = NULL; struct io_handler io_handlers[NEO4J_MAX_IO_ARGS]; unsigned int nio_handlers = 0; neo4j_client_init(); int result = EXIT_FAILURE; if (shell_state_init(&state, prog_name, stdin, stdout, stderr, tty)) { neo4j_perror(stderr, errno, "unexpected error"); goto cleanup; } state.interactive = isatty(STDIN_FILENO); char histfile[PATH_MAX]; if (neo4j_dot_dir(histfile, sizeof(histfile), NEO4J_HISTORY_FILE) < 0) { neo4j_perror(state.err, (errno == ERANGE)? ENAMETOOLONG : errno, "unexpected error"); goto cleanup; } state.histfile = histfile; if (isatty(fileno(stderr))) { state.error_colorize = ansi_error_colorization; } int c; while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) >= 0) { switch (c) { case 'h': usage(state.out, prog_name); result = EXIT_SUCCESS; goto cleanup; case 'v': ++log_level; break; case HISTFILE_OPT: state.histfile = (optarg[0] != '\0')? optarg : NULL; break; case CA_FILE_OPT: if (neo4j_config_set_TLS_ca_file(state.config, optarg)) { neo4j_perror(state.err, errno, "unexpected error"); goto cleanup; } break; case CA_DIRECTORY_OPT: if (neo4j_config_set_TLS_ca_dir(state.config, optarg)) { neo4j_perror(state.err, errno, "unexpected error"); goto cleanup; } break; case COLORIZE_OPT: state.error_colorize = ansi_error_colorization; break; case NO_COLORIZE_OPT: state.error_colorize = no_error_colorization; break; case INSECURE_OPT: state.connect_flags |= NEO4J_INSECURE; break; case NON_INTERACTIVE_OPT: state.interactive = false; if (tty != NULL) { fclose(tty); tty = NULL; } break; case 'u': if (neo4j_config_set_username(state.config, optarg)) { neo4j_perror(state.err, errno, "unexpected error"); goto cleanup; } break; case 'p': if (neo4j_config_set_password(state.config, optarg)) { neo4j_perror(state.err, errno, "unexpected error"); goto cleanup; } break; case 'P': if (tty == NULL) { fprintf(state.err, "Cannot prompt for a password without a tty\n"); goto cleanup; } state.password_prompt = true; break; case KNOWN_HOSTS_OPT: if (neo4j_config_set_known_hosts_file(state.config, optarg)) { neo4j_perror(state.err, errno, "unexpected error"); goto cleanup; } break; case NO_KNOWN_HOSTS_OPT: if (neo4j_config_set_trust_known_hosts(state.config, false)) { neo4j_perror(state.err, errno, "unexpected error"); goto cleanup; } break; case NOHIST_OPT: state.histfile = NULL; break; case PIPELINE_MAX_OPT: { int arg = atoi(optarg); if (arg < 1) { fprintf(state.err, "Invalid pipeline-max '%s'\n", optarg); goto cleanup; } state.pipeline_max = arg; neo4j_config_set_max_pipelined_requests(state.config, arg * 2); } break; case 'i': state.interactive = false; if (add_io_handler(io_handlers, &nio_handlers, optarg, false, source)) { goto cleanup; } break; case SOURCE_MAX_DEPTH_OPT: { int arg = atoi(optarg); if (arg < 1) { fprintf(state.err, "Invalid source-max-depth '%s'\n", optarg); goto cleanup; } state.source_max_depth = arg; } break; case 'e': state.interactive = false; if (add_io_handler(io_handlers, &nio_handlers, optarg, false, eval)) { goto cleanup; } break; case 'o': if (add_io_handler(io_handlers, &nio_handlers, optarg, true, redirect_output)) { goto cleanup; } break; case VERSION_OPT: fprintf(state.out, "neo4j-client: %s\n", PACKAGE_VERSION); fprintf(state.out, "libneo4j-client: %s\n", libneo4j_client_version()); fprintf(state.out, "libcypher-parser: %s\n", libcypher_parser_version()); result = EXIT_SUCCESS; goto cleanup; default: usage(state.err, prog_name); goto cleanup; } } if (nio_handlers > 0 && io_handlers[nio_handlers-1].is_output) { fprintf(stderr, "--output/-o must be followed by --source/-i or --eval/-e\n"); goto cleanup; } argc -= optind; argv += optind; if (argc > 2) { usage(state.err, prog_name); goto cleanup; } uint8_t logger_flags = 0; if (log_level < NEO4J_LOG_DEBUG) { logger_flags = NEO4J_STD_LOGGER_NO_PREFIX; } provider = neo4j_std_logger_provider(state.err, log_level, logger_flags); if (provider == NULL) { neo4j_perror(state.err, errno, "unexpected error"); goto cleanup; } neo4j_config_set_logger_provider(state.config, provider); if (state.interactive) { state.password_prompt = true; } if (tty != NULL) { neo4j_config_set_unverified_host_callback(state.config, host_verification, &state); if (state.password_prompt) { neo4j_config_set_authentication_reattempt_callback(state.config, auth_reattempt, &state); } } if (argc >= 1 && db_connect(&state, cypher_input_position_zero, argv[0], (argc > 1)? argv[1] : NULL)) { goto cleanup; } // remove any password from the config if (neo4j_config_set_password(state.config, NULL)) { // can't fail } if (signal(SIGINT, interrupt_handler) == SIG_ERR) { perror("unexpected error"); goto cleanup; } if (state.interactive) { state.render = render_results_table; state.render_flags = NEO4J_RENDER_SHOW_NULLS; state.infile = "<interactive>"; state.source_depth = 1; if (interact(&state)) { goto cleanup; } } else if (nio_handlers > 0) { state.render = render_results_csv; for (unsigned int i = 0; i < nio_handlers; ++i) { if (io_handlers[i].handle(&state, io_handlers[i].arg)) { goto cleanup; } } } else { state.render = render_results_csv; state.infile = "<stdin>"; state.source_depth = 1; if (batch(&state, state.in)) { goto cleanup; } } result = EXIT_SUCCESS; cleanup: shell_state_destroy(&state); if (provider != NULL) { neo4j_std_logger_provider_free(provider); } for (unsigned int i = 0; i < nio_handlers; ++i) { free(io_handlers[i].arg); } if (tty != NULL) { fclose(tty); } neo4j_client_cleanup(); return result; }