/* Copyright © 2001, Oracle Corporation. All Rights Reserved. */ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * * SQL_SPLIT.C * *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * * Facility: * * Oracle SQL sample program * * Abstract: * * Split lines in a .SC (SQL$PRE/CC) source file * * Modification History: * * Version 7.0 * 26-JUL-01 03613 (NJL) Initial entry. * 1-DEC-95 Jack Raitto - Created as a workaround for bug #324102 * *------------------------------------------------------------------------------ */ /* ** ** SPLIT.C -- Split lines in a .SC (SQL$PRE/CC) source file such that no ** line is longer than 255 characters. ** ** To build and use: ** OpenVMS VAX or OpenVMS AXP, DEC C or VAX C: ** ** $ cc split ** $ link split ** $ split :== $sys$disk:[]split ** $ split input_filespec output_filespec ** ** If you compile SPLIT with the same C compiler that SQL$PRE/CC uses ** (i.e., DEC C or VAX C), that's all there is to it. ** ** However, if you build SPLIT with DEC C (or any ANSI C), and wish to use ** SPLIT's output with SQL$PRE/CC=VAXC, you must compile SPLIT as follows: ** ** $ cc split/define=C_LITERAL_CONCAT=0 ** ** Conversely, if you build SPLIT with VAX C (or any non-ANSI C) and wish ** to use SPLIT's output with SQL$PRE/CC=DECC, it can be helpful ** (although it is not essencial) to compile SPLIT as follows: ** ** $ cc split/define=C_LITERAL_CONCAT=1 ** ** The C_LITERAL_CONCAT variant controls whether SPLIT uses ANSI C ** string literal concatenation when continuing lines with long string ** literals. VAX C does not support ANSI C string literal ** concatenation. DEC C does. Where ANSI C string literal ** concatenation is available, it is good to use it because it results in ** a number of shorter literals that are acceptable to SQL$PRE. Without ** ANSI C string literal concatenation, SPLIT continues lines with long ** literals using a backslash at the end of each continuation line. ** While just about every C implementation since K&R 1st edition supports ** this method, you may get a "string literal too long" diagnostic from ** SQL$PRE, even though the long string literal is not part of a SQL ** statement. ** */ #ifndef C_LITERAL_CONCAT #define C_LITERAL_CONCAT 0 #ifdef __STDC__ #if __STDC__ #undef C_LITERAL_CONCAT #define C_LITERAL_CONCAT 1 #endif #endif #endif /* ** Internal notes: ** ** Any C line can be split and continued by inserting a backslash ** followed by a newline. However, since SQL cannot recognize the ** declaration of a host variable name that is split in the middle, ** it is best to split at a separator. In this case, the backslash is ** not needed prior to the newline. Exceptions: In C string literals, ** we must use backslash/newline rather than just newline, and we have ** to be sure we're not splitting an escape sequence. Alternatively, we ** can use ANSI C literal concatenation with DEC C. This is better with ** SQL since SQL doesn't accept long, unbroken literals. Also, C ** preprocessing directives must use backslash/newline rather than just ** newline. I've never seen anyone actually use trigraphs. If they are ** used, they may be split but they must use backslash/newline rather than ** just newline. However, I don't bother to split trigraphs. If the trigraph ** won't fit on the line, I continue the line just before the trigraph. ** ** SQL lines can be split at any separator by simply inserting a ** newline. If there is no separator, we'll try to split and continue ** by preceding the newline with a dash -- this works in SQL string literals ** provided the total length of the literal isn't too long. */ #define K 1024 #define MAXIN (32*K) #define MAXOUT 255 #include #include #include #include #define MAX_MATCH 100 static char buf [MAXIN]; static char *ch, *l, *separator; static FILE *in, *out; int eof = 0; #define ISOCTAL(c) (((c) >= '0') && ((c) <= '7')) static void usage (void) { fprintf (stderr, "Usage is SPLIT input_filespec output_filespec\n\n"); fprintf (stderr, "You must first define a foreign command symbol for SPLIT:\n"); fprintf (stderr, "\t$ SPLIT :== $SYS$DISK:[]SPLIT\n"); exit (EXIT_FAILURE); } static int getin (void) { eof = fgets(buf,sizeof(buf),in) == NULL; if (!eof) l = ch = buf; else l = ch = NULL; separator = NULL; return !eof; } static void putout (void) { fputs (buf, out); l = ch = separator = NULL; } static void continue_line (char *endseq, char *startseq) { char *c; char save[100]; int i,j,len,endseqlen,startseqlen; c = ch; len = strlen(c); endseqlen = strlen(endseq); for (i=0; (i MAX_MATCH) { fprintf (stderr, "Internal error: match(%s) exceeds tbuf size\n", str); exit (EXIT_FAILURE); } while (isspace(*c)) c++; if (isalnum(c[len])) return 0; for (i=0; i= MAXOUT-1) { esc_len = next_ch - ch; continue_line("\\\n", NULL); ch += esc_len; } else ch = next_ch; } else if (*next_ch == 'x') /* hex escape -- 2 hex digits */ { if (((ch - l) + 4) >= MAXOUT-1) { continue_line("\\\n", NULL); ch += 2; /* skip \x */ if (isxdigit(*ch)) ch++; if (isxdigit(*ch)) ch++; } else ch += 4; } else if ((*next_ch == '\n') || (*next_ch == '\0')) /* continuation */ { putout(); if (!getin()) return; } else /* some other escape seq -- 1 char */ { ch = next_ch + 1; } } static void c_trigraph () { if (((ch - l) + 3) >= MAXOUT-1) continue_line ("\\\n", NULL); ch += 3; } static void continue_c_literal (void) { #if C_LITERAL_CONCAT continue_line("\"\n", "\""); #else continue_line("\\\n", NULL); #endif } static void c_literal (void) { char match_char; char *next_ch; match_char = *ch++; if (*ch == match_char) { if ((ch - l) >= MAXOUT-1) continue_c_literal(); ch++; return; } do { if (is_c_escape()) c_escape(); else ch++; if ((ch - l) >= MAXOUT-1) continue_c_literal(); } while ((*ch != match_char) && (*ch != '\0') && (*ch != '\n')); if (*ch == match_char) ch++; } static void sql_literal (void) { char match_char; match_char = *ch++; if ((ch[0] == match_char) && (ch[1] != match_char)) { if ((ch - l) >= MAXOUT-1) continue_line("-\n", NULL); ch++; return; } do { if ((ch[0] == '-') && ((ch[1] == '\n') || (ch[1] == '\0'))) { putout(); if (!getin()) return; } else if ((ch[0] == match_char) && (ch[1] == match_char)) { if (((ch - l) + 2) >= MAXOUT-1) continue_line("-\n", NULL); ch += 2; } else ch++; if ((ch - l) >= MAXOUT-1) continue_line("-\n", NULL); } while ((*ch != match_char) && (*ch != '\0') && (*ch != '\n')); if (*ch == match_char) ch++; } static void c_preproc (void) { while ((*ch != '\0') && (*ch != '\n')) { if (is_literal()) c_literal(); else if (is_c_escape()) c_escape(); /* covers line continuation */ else ch++; if ((ch - l) >= MAXOUT-1) continue_line("\\\n", NULL); } } static void sql_stmt (void) { while (*ch != ';') { if ((*ch == '\0') || (*ch == '\n')) { putout(); if (!getin()) return; } if (!isalnum(*ch)) separator = ch; if (is_literal()) sql_literal(); else ch++; if ((ch - l) >= MAXOUT-1) break_line("-\n", NULL); } ch++; } int main (int argc, char *argv[]) { if (argc != 3) usage(); in = fopen(argv[1],"r"); if (in == NULL) { fprintf (stderr,"?cannot open input file: %s\n", argv[1]); usage(); } out = fopen(argv[2],"w"); if (out == NULL) { fprintf (stderr,"?cannot open output file: %s\n", argv[2]); usage(); } while (getin()) { /* ** The line may need to be split. Look for SQL statments and c literals ** and character constants and handle appropriately. Split everything ** else at the previous separator when the limit is reached. */ while (!eof && (*ch != '\0')) { if (!isalnum(*ch)) separator = ch; if (is_c_preproc()) c_preproc(); else if (is_sql_stmt()) sql_stmt(); else if (is_literal()) c_literal(); else if (is_c_trigraph()) c_trigraph(); else ch++; if ((ch - l) >= MAXOUT-1) break_line("\\\n", NULL); } if (!eof) putout(); } }