| /********************************************************************** |
| // @@@ START COPYRIGHT @@@ |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| // @@@ END COPYRIGHT @@@ |
| // |
| **********************************************************************/ |
| /* -*-C++-*- |
| ***************************************************************************** |
| * |
| * File: ParserMsg.C |
| * RCS: $Id: ParserMsg.cpp,v 1.13 1998/08/25 17:19:09 Exp $ |
| * Description: This file contains the shared routines for the parsers in sqlci |
| * and compiler (i.e. parser directory) |
| * |
| * Created: 12/11/96 |
| * Modified: $ $Date: 1998/08/25 17:19:09 $ (GMT) |
| * Language: C++ |
| * Status: $State: Exp $ |
| * |
| * |
| ***************************************************************************** |
| */ |
| |
| #include <ctype.h> |
| #include <string.h> |
| #if !defined(__GNUC__) || __GNUC__ < 3 |
| #include <strstream.h> |
| #endif |
| #include "NAWinNT.h" |
| #include "ComDiags.h" |
| #include "wstr.h" |
| #include "nawstring.h" |
| #include "NLSConversion.h" |
| #include "ErrorMessage.h" |
| #include "ParserMsg.h" // header for StoreSyntaxError, implemented herein |
| #include "csconvert.h" |
| |
| |
| // This function takes as an argument a pointer to a ComCondition object. |
| // This function accesses the global variables: input_str, input_pos in |
| // order to format a string indicating where in the given SQL statement |
| // a syntax error occurred. |
| // |
| // This routine prints out each format-line of the buffer until the line |
| // is reached which contains the error position. That line is the last |
| // line printed. |
| // |
| // Then the next line output consists of a sequence of zero or more spaces |
| // and then a caret. This gives the appearance of the caret indicating |
| // where in the buffer's text the error has been detected. |
| // |
| // Finally, if there is even one more format-line in the buffer then |
| // a line is output saying "further output omitted," rather than actually |
| // continually printing the lines. |
| // |
| // A format-line is determined as follows. It is a line ending at a newline |
| // character. It is a line ending at the end of the buffer (that would |
| // be the last format-line of the buffer). It is a line that ends after |
| // running for some number of characters, MAX_FORMAT_LINE. Therefore, |
| // in effect, you can see that the final rule defining a format-line |
| // is due to the line-wrapping effect on a terminal or printer, and essentially |
| // inserts artificial linebreaks into the buffer. If the user doesn't |
| // like this, then the work around is to supply input that has newlines to |
| // the user's liking in the first place. |
| // |
| // Implementation Tricks: |
| // In the case that the input_pos was at the end of |
| // the buffer, we slide it back by a single character. This should have no |
| // ill-effects on the user detecting where the problem is, and it eliminates |
| // us having to specially handle this case beyond what we are doing here. |
| // |
| // The rest of the routine is fairly straightforward --- particularly if you |
| // read above about the purpose of this function. |
| |
| |
| void StoreSyntaxError(const char *input_str, Int32 input_pos, |
| ComDiagsArea& diags, Int32 dgStrNum, |
| CharInfo::CharSet input_str_cs, |
| CharInfo::CharSet terminal_cs) |
| { |
| if (!input_str) return; |
| |
| NAWchar wCharBuffer[ErrorMessage::MSG_BUF_SIZE+1]; // extra space for NULL |
| Int32 slen = strlen(input_str); |
| |
| Int32 input_pos_in_numOfNAWchars = input_pos; |
| if (input_str_cs != CharInfo::ISO88591) |
| { |
| // Compute to get the input position in number of NAWcharacters |
| enum cnv_charset eCnvCS = convertCharsetEnum((Int32)input_str_cs); |
| char * p1stUnstranslatedChar = NULL; |
| UInt32 outputOctetLen = 0; |
| UInt32 translatedCharCount = 0; |
| Int32 cnvErrStatus = LocaleToUTF16( |
| cnv_version1 // in - const enum cnv_version version |
| , input_str // in - const char *in_bufr |
| , input_pos // in - const int input_str_octet_len |
| , (const char *)wCharBuffer // out - const char *out_bufr |
| , ErrorMessage::MSG_BUF_SIZE * sizeof(NAWchar) // no NULL terminator |
| // in - const int out_bufr_max_octet_len |
| , eCnvCS // in - enum cnv_charset charset |
| , p1stUnstranslatedChar // out - char * & first_untranslated_char |
| , &outputOctetLen // out - unsigned int *output_data_len_p |
| , 0 // in - const int cnv_flags |
| , (const Int32)FALSE // in - const int addNullAtEnd_flag |
| , &translatedCharCount // out - unsigned int * translated_char_cnt_p |
| ); |
| if (outputOctetLen > 0) |
| input_pos_in_numOfNAWchars = (Int32)((outputOctetLen - 1) / sizeof(NAWchar)); |
| } |
| |
| Int32 ulen = LocaleStringToUnicode(input_str_cs, input_str, slen, |
| wCharBuffer, ErrorMessage::MSG_BUF_SIZE+1, TRUE); |
| |
| if ( ulen == 0 || ( input_str_cs == CharInfo::ISO88591 && ulen < slen ) ) |
| cerr << input_str << endl; |
| else |
| StoreSyntaxError(wCharBuffer, input_pos_in_numOfNAWchars, diags, dgStrNum, terminal_cs); |
| |
| } // StoreSyntaxError, single-byte version |
| |
| static const size_t MAX_FORMAT_LINE = 79; |
| static const size_t MAX_DGSTRING_SIZE = |
| MINOF(ErrorMessage::MSG_BUF_SIZE,1024) - MAX_FORMAT_LINE; |
| |
| void StoreSyntaxError(const NAWchar *input_str, Int32 input_pos, |
| ComDiagsArea& diags, Int32 dgStrNum, |
| CharInfo::CharSet charset) |
| { |
| if (!input_str) return; |
| |
| NAWString errMsg; |
| NABoolean internalError = FALSE; |
| |
| Int32 buffLen = na_wcslen(input_str); |
| if (buffLen == 0) { |
| errMsg.append(WIDE_("\n;\n^")); |
| } |
| else { |
| if (input_pos > buffLen) { |
| if (input_pos > buffLen+1) { |
| cerr << "*** StoreSyntaxError: (input_pos > buffLen): " |
| << input_pos << " " << buffLen; |
| internalError = TRUE; |
| } |
| input_pos = buffLen; |
| } |
| else if (input_pos < 0) |
| input_pos = 0; |
| |
| // in case there was any text prior on the current line |
| errMsg.append(WIDE_("\n")); // Start errMsg with a '\n' |
| const NAWchar *errPos = input_str+input_pos; |
| if (input_pos == buffLen) |
| errPos--; |
| |
| const NAWchar *right = input_str; |
| const NAWchar *left = NULL; |
| |
| while (errPos >= right) { |
| left = right; |
| size_t charCount = 0; |
| while ( 1 ) { |
| charCount++; |
| right++; |
| if (*right == '\n' || |
| *right == 0 || |
| charCount == MAX_FORMAT_LINE) |
| break; |
| } |
| |
| // At this point, *right is a null char, a newline char, or |
| // the char at (MAX_FORMAT_LINE+1). We want to print the chars |
| // from left up to but not include right. That's very easy to write |
| // as a loop! Then, we want to output a newline char. Finally, |
| // if (*right == newline char) then increment right. |
| // |
| // We are careful not to touch (left) in here because we may need |
| // it later in order to determine the number of chars to space over |
| // from the start of the final line to where the caret belongeth. |
| |
| // 3/20/98: Replaced this codeblock: |
| // const char *currency = left; |
| // while (currency != right) |
| // errMsg << *currency++; |
| // with this: |
| errMsg.append(left, right - left); |
| errMsg.append(WIDE_("\n")); |
| |
| if (*right == '\n') |
| right++; |
| } |
| // The number given by (errPos - left) tells us exactly how many |
| // characters we must space over before printing the caret. |
| // We print the spaces, the caret, and then a newline. |
| { |
| |
| size_t charCount = errPos - left; |
| assert(charCount < MAX_FORMAT_LINE); |
| |
| // 3/20/98: Since the WCHAR version of the SQl text can contain |
| // half or full width characters, we need to get the exact length |
| // of the last WCHAR string segment in current locale, then pump that |
| // many of WCHAR space characters into the buffer. |
| // Assumption: the fonts used are fixed width! |
| // Thus, replaced this codeblock: |
| // while (charCount-- != 0) |
| // errMsg << ' '; |
| // with this: |
| |
| char bufferInLocale[(MAX_FORMAT_LINE+1)*8]; // allow for utf8 characters |
| Int32 byteCount = UnicodeStringToLocale(charset, (NAWchar*)left, charCount, |
| bufferInLocale, (MAX_FORMAT_LINE+1)*8 |
| ); |
| |
| |
| for (Int32 i=0; i<byteCount; i++) |
| errMsg.append(WIDE_(" ")); |
| |
| errMsg.append(WIDE_("^ (")); |
| char bytestr_str[10]; |
| // get the size of the error offset as a string input_pos is 0 based |
| str_itoa( input_pos+1, bytestr_str); |
| NAWString wBytestr_str(CharInfo::ISO88591,bytestr_str); |
| errMsg.append(wBytestr_str); |
| errMsg.append(L" characters from start of SQL statement)"); |
| } |
| |
| // Don't do this; it looks crappy: |
| //if (right-input_str != buffLen) |
| // errMsg << endl << "..."; // to indicate rest of SQL stmt not shown |
| } |
| |
| NAWchar * const entireBuf = (NAWchar *)errMsg.data(); |
| NAWchar *diagBuf = entireBuf; |
| |
| // If this is too big, truncate to fit. |
| // Align to next newline if at least two complete lines will still appear. |
| // |
| size_t len = errMsg.length(); |
| if (len > MAX_DGSTRING_SIZE) |
| { |
| diagBuf += len - MAX_DGSTRING_SIZE; |
| NAWchar *newline = na_wcschr(diagBuf, L'\n'); |
| if (newline && na_wcschr(newline, L'\n')) |
| diagBuf = newline; // Start errMsg with a '\n' |
| else |
| diagBuf[0] = L'\n'; // Start errmsg with a '\n' |
| diagBuf[1] = L'.'; // Interpolate an ellipsis |
| diagBuf[2] = L'.'; |
| diagBuf[3] = L'.'; |
| } |
| |
| // convert tabs (but not newlines) to spaces so the caret aligns correctly |
| for (NAWchar *d = diagBuf; *d; d++) |
| if (*d == NAWchar('\t')) |
| *d = ' '; |
| |
| if (dgStrNum == 0) |
| diags << DgWString0(diagBuf); |
| else |
| diags << DgWString1(diagBuf); |
| |
| if (internalError) { |
| |
| char bufferInLocale[MAX_DGSTRING_SIZE]; |
| Lng32 len = UnicodeStringToLocale(charset, entireBuf, na_wcslen(entireBuf), |
| bufferInLocale, MAX_DGSTRING_SIZE |
| ); |
| |
| if (len>0) { |
| cerr << bufferInLocale << endl; |
| } |
| } |
| |
| } // StoreSyntaxError, Unicode version |
| |