📄 gqlplus.c
字号:
{ int len; char *xtr = (char *) 0; if (str) { len = strlen(str)-1; while (str[len] == ' ') str[len--] = '\0'; xtr = strdup(str+strspn(str, " ")); } return xtr;}/* Returns 1 if a string szOrg starts with szPrefix. Note that leading blanks/tabs are ignored. Returns 0 otherwise. @param szOrg can be NULL. @param szPrefix can be NULL. */int startsWith(char* szOrg, const char* szPrefix){ int iMatch = 0; if ( (szOrg == (char*) 0) || (szPrefix == (char*) 0) ) { /* do nothing. */ } else { char* szOrgTrimmed = trim(szOrg); if (strstr(szOrgTrimmed, szPrefix) == szOrgTrimmed) { iMatch = 1; } } return iMatch;}/* Return 1 if the following conditions satisfy: a) current line startsWith szPrefix AND b) the remaining part after szPrefix in szOrg starts with szCmd Return 0 otherwise.*/int matchCommand(char* szOrg, char* szPrefix, char* szCmd){ int iMatch = 0; if ( (szOrg == (char*) 0) || (szPrefix == (char*) 0) || (szCmd == (char*) 0) ) { /* do nothing. */ } else { char* szOrgTrimmed = trim(szOrg); if (strstr(szOrgTrimmed, szPrefix) == szOrgTrimmed) { char* szRemaining = szOrgTrimmed + strlen(szPrefix); iMatch = startsWith(szRemaining, szCmd); } } return iMatch;}/* Return lowercase and trimmed version of 'str'.*/char *tl(const char *str){ int i; char *xtr = (char *) 0; char *lline = (char *) 0; if (str) { lline = strdup(str); for (i = 0; i < strlen(str); i++) lline[i] = tolower((int) lline[i]); } xtr = trim(lline); free(lline); return xtr;}/* Set 'str' to lowercase.*/static void tl2(char *str){ int i = 0; if (str) while (str[i] != '\0') { str[i] = tolower((int) str[i]); i++; }}/* Utility function for check_numeric_prompt().*/static int check_numeric(const char *str){ int check_prompt = 0; if (strlen(str) == 5) if (isspace((int) str[4])) if (isspace((int) str[3]) || (str[3] == '*') || (str[3] == 'i')) if (isdigit((int) str[2])) { check_prompt = 1; if (isdigit((int) str[0]) && isspace((int) str[1])) check_prompt = 0; } return check_prompt;}/* Return 1 if 'str' is a correct Oracle numeric prompt. The numeric prompt has up to three numeric characters, followed by a space, or an asterisk, or an 'i' (for Insert command). ljb, 06/16/2004: there is another version of a numeric prompt, when 'time' is set. The prompt looks like this: SQL> set time on 19:41:37 SQL> select * from scott.salgrade 19:41:42 2 ;*/static int check_numeric_prompt(const char *str){ int check_prompt = 0; if (str) { /* Check for the short version of the numeric prompt: */ if (strlen(str) == 5) check_prompt = check_numeric(str); /* Check for the long version of the numeric prompt (when time is set): */ else if (strlen(str) == 14) { if (isdigit((int) str[0]) && isdigit((int) str[1]) && str[2] == ':' && isdigit((int) str[3]) && isdigit((int) str[4]) && str[5] == ':' && isdigit((int) str[6]) && isdigit((int) str[7]) && isspace((int) str[8])) check_prompt = check_numeric(str+9); } } return check_prompt;}/* Return 1 if 'str' is a correct Oracle time prompt. The time prompt has time followed by a space followed by `sqlprompt', like this: 19:41:37 SQL>*/static int check_time_prompt(char *str, char *sqlprompt){ int check_prompt = 0; if (str) { if (isdigit((int) str[0]) && isdigit((int) str[1]) && str[2] == ':' && isdigit((int) str[3]) && isdigit((int) str[4]) && str[5] == ':' && isdigit((int) str[6]) && isdigit((int) str[7]) && isspace((int) str[8]) && !strcmp(&str[9], sqlprompt)) check_prompt = 1; } return check_prompt;}void ignore_sigint(){ sigemptyset(&iact.sa_mask); iact.sa_flags = 0;#ifdef SA_RESTART iact.sa_flags |= SA_RESTART;#endif iact.sa_handler = SIG_IGN; sigaction(SIGINT, &iact, (struct sigaction *) 0);}static void ignore_sigpipe(){ sigemptyset(&pact.sa_mask); pact.sa_flags = 0;#ifdef SA_RESTART pact.sa_flags |= SA_RESTART;#endif pact.sa_handler = SIG_IGN; sigaction(SIGPIPE, &pact, (struct sigaction *) 0);}/* SIGINT handler. Passes the signal to the child (i.e., sqlplus) unless we are in the middle of an editing session (edit_pid != 0). The reason is this: Emacs redefines Ctrl-G to be SIGINT-generating key (instead of Ctrl-C). So, during Emacs editing session, Ctrl-G generates SIGINT which we don't want to pass to sqlplus because it disrupts its' operation and does not make sense anyway (that is not the interrupt we want to catch; we only care about Ctrl-C typed at gqlplus prompt).*/static void sigint_handler(int signo){ if (edit_pid == 0) { kill(sqlplus_pid, SIGINT); /*ignore_sigint();*/ }}/* SIGQUIT handler.*/static void sigquit_handler(int signo){ kill(sqlplus_pid, signo); printf("Quit\n"); _exit(0);}void install_sigint_handler(){ sigemptyset(&iact.sa_mask); iact.sa_flags = 0;#ifdef SA_RESTART iact.sa_flags |= SA_RESTART;#endif/* Use sigaction(), for portability and reliability.*/ iact.sa_handler = sigint_handler; sigaction(SIGINT, &iact, (struct sigaction *) 0);}void install_sigquit_handler(){ sigemptyset(&qact.sa_mask); qact.sa_flags = 0;#ifdef SA_RESTART qact.sa_flags |= SA_RESTART;#endif/* Use sigaction(), for portability and reliability.*/ qact.sa_handler = sigquit_handler; sigaction(SIGQUIT, &qact, (struct sigaction *) 0);}/* Install signal handlers.*/void sig_init(void){ install_sigint_handler(); install_sigquit_handler(); ignore_sigpipe();}static void kill_sqlplus(){ kill(sqlplus_pid, SIGTERM);}/* Return 1 if 'str' is one of the Oracle password prompts.*/static int check_password_prompt(char *str){ int check_prompt = 0; if (str) { if (!strcmp(str, PASSWORD_PROMPT) || !strcmp(str, OLD_PASSWORD) || !strcmp(str, NEW_PASSWORD) || !strcmp(str, RETYPE_PASSWORD)) check_prompt = 1; } return check_prompt;}/* Get sqlplus output from `fd' and display it (*outstr is NULL) without prompt, or store it in *outstr. The prompt is returned and will be displayed later, by readline() (if we display it here, it would get overwritten by readline()).*/static char *get_sqlplus(int fd, char *line, char **outstr){ int done; int cntr; int nread = 0; int plen; int llen; int olen; int capacity; int ocapacity; int pdiff; char *lline; char *xtr; char *last_line; char *otr = (char *) 0; char *ptr = (char *) 0; char *prompt = (char *) 0; done = 0; cntr = 0; capacity = INIT_LINE_LENGTH; ocapacity = INIT_LINE_LENGTH; /* lline has the current undisplayed sqlplus content. llen is the length of the content. */ lline = malloc((capacity+1)*sizeof(char)); lline[0] = '\0'; llen = 0; olen = 0; if (outstr != (char **) 0) { otr = malloc((ocapacity+1)*sizeof(char)); ptr = otr; } /* Read sqlplus output. We read until sqlplus sends a prompt. We recognize the following prompts: 'SQL> ' 'Enter user-name: ' 'Enter password: ' 'Disconnected from Oracle...' 'Enter value for ...' 'Specify log: {<RET>=suggested | filename | AUTO | CANCEL}' numeric prompt (for multi-line SQL statements) user-defined prompt (see function set_sql_prompt()) So far looks like these are the only prompts. If sqlplus sends anything else, we are doomed. ljb, 05/20/2002 */ while (done == 0) { nread = read(fd, line, pipe_size); if (nread > 0) { line[nread] = '\0'; fflush(stdout); if (nread+llen > capacity) { while (nread+llen > capacity) capacity += capacity; lline = realloc(lline, capacity+1); } if ((outstr != (char **) 0) && (nread+olen > ocapacity)) { while (nread+olen > ocapacity) ocapacity += ocapacity; pdiff = ptr-otr; otr = realloc(otr, ocapacity+1); ptr = otr+pdiff; } memcpy(&lline[llen], line, nread); llen += nread; lline[llen] = '\0'; if ((!strncmp(lline, QUIT_PROMPT_1, strlen(QUIT_PROMPT_1)) && (state == STARTUP)) || (strstr(lline, QUIT_PROMPT_1) && (state == STARTUP)) || strstr(lline, QUIT_PROMPT_2) || strstr(lline, USAGE_PROMPT)) { done = 1; quit_sqlplus = 1; } /* The following change is to address in ADE view gqlplus invocation problem. */ if ((!strncmp(lline, VALUE_PROMPT, strlen(VALUE_PROMPT))) || strstr(lline, SQL_PROMPT) || strstr(lline, RECOVER_PROMPT) ) done = 1; /* Display everything up to the last newline. */ xtr = strrchr(lline, '\n'); if (xtr) { last_line = strdup(xtr+1); plen = xtr-lline; if (!outstr) { if (plen > 0) write(STDOUT_FILENO, lline, plen); } else { memcpy(ptr, lline, plen); ptr[plen] = '\0'; ptr += plen; olen += plen; } /* Adjust lline. After adjustment, only the last line received from sqlplus, so far, remains in lline. */ llen -= plen; memcpy(lline, xtr, llen); lline[llen] = '\0'; if ((sql_prompt && !strcmp(last_line, sql_prompt)) || !strcmp(last_line, USER_PROMPT) || !strncmp(last_line, VALUE_PROMPT, strlen(VALUE_PROMPT)) || check_time_prompt(last_line, sql_prompt) || check_password_prompt(last_line)) done = 1; free(last_line); } else if ((sql_prompt && !strcmp(lline, sql_prompt)) || check_numeric_prompt(lline) || check_time_prompt(lline, sql_prompt) || check_password_prompt(lline)) done = 1; } else { if (nread < 0) perror((char *) 0); } } /* Display the remaining content, up to the last newline. Everything beyond that is the prompt. */ xtr = strrchr(lline, '\n'); if (xtr) { xtr++; prompt = strdup(xtr); llen -= strlen(prompt); if (!outstr) { if (llen > 0) write(STDOUT_FILENO, lline, llen); } else { memcpy(ptr, lline, llen); ptr[llen] = '\0'; } } else prompt = strdup(lline); free(lline); if (outstr != (char **) 0) *outstr = otr; /*install_sigint_handler();*/ return prompt;}/* A special version of get_sqlplus() supporting the 'set sqlprompt' command. This function is retrieving one line from sqlplus, and that line is the new sql_prompt.*/static char *set_sql_prompt(int fd, char *line){ int cntr; int nread = 0; int llen; char *lline; cntr = 0; /* lline has the current undisplayed sqlplus content. llen is the length of the content. */ lline = malloc((MAX_PROMPT_LEN+1)*sizeof(char)); lline[0] = '\0'; llen = 0; /* Get bytes from sqlplus. We gamble here that everything will come from sqlplus in one read(), since 'set sqlprompt' is a simple and quick operation. If it doesn't, we are doomed. */ nread = read(fd, line, pipe_size); if (nread > 0) { line[nread] = '\0';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -