📄 i18n.c
字号:
*/
ex_error("DoCommand: ct_results() returned unexpected result type");
return CS_FAIL;
}
}
/*
** We're done processing results. Let's check the
** return value of ct_results() to see if everything
** went ok.
*/
switch ((int)retcode)
{
case CS_END_RESULTS:
/*
** Everything went fine.
*/
break;
case CS_FAIL:
/*
** Something went wrong.
*/
ex_error("DoCommand: ct_results() failed");
return retcode;
default:
/*
** We got an unexpected return value.
*/
ex_error("DoCommand: ct_results() returned unexpected result code");
return retcode;
}
/*
** Drop our command structure
*/
if ((retcode = ct_cmd_drop(cmd)) != CS_SUCCEED)
{
ex_error("DoCommand: ct_cmd_drop() failed");
return retcode;
}
return retcode;
}
/*
** FetchData()
**
** Type of function:
** International example program internal api
**
** Purpose:
** This function processes fetchable results sets. The results include:
**
** CS_ROW_RESULT
** CS_CURSOR_RESULT
** CS_PARAM_RESULT
** CS_STATUS_RESULT
** CS_COMPUTE_RESULT
**
** Since the Client-Library result model has been unified, the same
** apis are used for each of the above result types.
**
** One caveat is the processing of CS_COMPUTE_RESULTs. The name field
** sent from the server is typically zero length. To display a meaningful
** header, the aggregate compute operator name should be found for the
** column, and that name used instead. The compute example program has
** code which demonstrates this.
**
** This routine is essentially the same as the utility function
** ex_fetch_data(), with modifications to support MY_MONEY_CHAR_TYPE
** datatypes. If the user installed function had replaced the Sybase
** money to char conversion routine, this function would not be
** needed.
**
** Parameters:
** cmd - Pointer to command structure
**
** Return:
** CS_MEM_ERROR If an memory allocation failed.
** CS_SUCCEED If the data was displayed.
** CS_FAIL If no columns were present.
** <retcode> Result of the Client-Library function if a failure was
** returned.
**
*/
CS_STATIC CS_RETCODE CS_INTERNAL
FetchData(cmd)
CS_COMMAND *cmd;
{
CS_RETCODE retcode;
CS_INT num_cols;
CS_INT i;
CS_INT j;
CS_INT row_count = 0;
CS_INT rows_read;
CS_INT disp_len;
CS_DATAFMT *datafmt;
EX_COLUMN_DATA *coldata;
/*
** Find out how many columns there are in this result set.
*/
retcode = ct_res_info(cmd, CS_NUMDATA, &num_cols, CS_UNUSED, NULL);
if (retcode != CS_SUCCEED)
{
ex_error("FetchData: ct_res_info() failed");
return retcode;
}
/*
** Make sure we have at least one column
*/
if (num_cols <= 0)
{
ex_error("FetchData: ct_res_info() returned zero columns");
return CS_FAIL;
}
/*
** Our program variable, called 'coldata', is an array of
** EX_COLUMN_DATA structures. Each array element represents
** one column. Each array element will re-used for each row.
**
** First, allocate memory for the data element to process.
*/
coldata = (EX_COLUMN_DATA *)malloc(num_cols * sizeof (EX_COLUMN_DATA));
if (coldata == NULL)
{
ex_error("FetchData: malloc() failed");
return CS_MEM_ERROR;
}
datafmt = (CS_DATAFMT *)malloc(num_cols * sizeof (CS_DATAFMT));
if (datafmt == NULL)
{
ex_error("FetchData: malloc() failed");
free(coldata);
return CS_MEM_ERROR;
}
/*
** Loop through the columns getting a description of each one
** and binding each one to a program variable.
**
** We're going to bind each column to a character string;
** this will show how conversions from server native datatypes
** to strings can occur via bind.
**
** We're going to use the same datafmt structure for both the describe
** and the subsequent bind.
**
** If an error occurs within the for loop, a break is used to get out
** of the loop and the data that was allocated is free'd before
** returning.
*/
for (i = 0; i < num_cols; i++)
{
/*
** Get the column description. ct_describe() fills the
** datafmt parameter with a description of the column.
*/
retcode = ct_describe(cmd, (i + 1), &datafmt[i]);
if (retcode != CS_SUCCEED)
{
ex_error("FetchData: ct_describe() failed");
break;
}
/*
** update the datafmt structure to indicate that we want the
** results in a null terminated character string.
**
** First, update datafmt.maxlength to contain the maximum
** possible length of the column. To do this, call
** ex_display_len() to determine the number of bytes needed
** for the character string representation, given the
** datatype described above. Add one for the null
** termination character.
*/
/*
** Set datatype and format to tell bind we want things
** converted to null terminated strings
*/
if (datafmt[i].datatype == CS_MONEY_TYPE)
{
datafmt[i].maxlength = 30;
datafmt[i].datatype = MY_MONEY_CHAR_TYPE;
datafmt[i].format = CS_FMT_NULLTERM;
}
else
{
datafmt[i].maxlength = ex_display_dlen(&datafmt[i]) + 1;
datafmt[i].datatype = CS_CHAR_TYPE;
datafmt[i].format = CS_FMT_NULLTERM;
}
/*
** Allocate memory for the column string
*/
coldata[i].value = (CS_CHAR *)malloc(datafmt[i].maxlength);
if (coldata[i].value == NULL)
{
ex_error("FetchData: malloc() failed");
retcode = CS_MEM_ERROR;
break;
}
/*
** Now bind.
*/
retcode = ct_bind(cmd, (i + 1), &datafmt[i],
coldata[i].value, &coldata[i].valuelen,
(CS_SMALLINT *)&coldata[i].indicator);
if (retcode != CS_SUCCEED)
{
ex_error("FetchData: ct_bind() failed");
break;
}
}
if (retcode != CS_SUCCEED)
{
for (j = 0; j < i; j++)
{
free(coldata[j].value);
}
free(coldata);
free(datafmt);
return retcode;
}
/*
** Display column header
*/
ex_display_header(num_cols, datafmt);
/*
** Fetch the rows. Loop while ct_fetch() returns CS_SUCCEED or
** CS_ROW_FAIL
*/
while (((retcode = ct_fetch(cmd, CS_UNUSED, CS_UNUSED, CS_UNUSED,
&rows_read)) == CS_SUCCEED) || (retcode == CS_ROW_FAIL))
{
/*
** Increment our row count by the number of rows just fetched.
*/
row_count = row_count + rows_read;
/*
** Check if we hit a recoverable error.
*/
if (retcode == CS_ROW_FAIL)
{
fprintf(stdout, "Error on row %d.\n", row_count);
fflush(stdout);
}
/*
** NOTE: There is a bug with cs_setnull() and user defined types (btsid
** 45825) To work around this bug, code has been added to display
** a value of "NULL" whenever the column indicator is set to
** CS_NULLDATA. Since this example should demonstrate the
** cs_setnull() functionality that is available, the code has been
** conditionally #if'd with the following define. Once the bug has
** been fixed, this example should be updated.
*/
#define EX_BTSID_45825 1
/*
** We have a row. Loop through the columns displaying the
** column values.
*/
for (i = 0; i < num_cols; i++)
{
/*
** Display the column value.
**
** NOTE: See EX_BTSID_45825 note above
*/
#if EX_BTSID_45825
if (coldata[i].indicator == CS_NULLDATA)
{
fprintf(stdout, "NULL");
disp_len = datafmt[i].maxlength;
disp_len -= strlen("NULL");
}
else
{
fprintf(stdout, "%s", coldata[i].value);
disp_len = datafmt[i].maxlength;
disp_len -= coldata[i].valuelen - 1;
}
fflush(stdout);
/*
** If not last column, Print out spaces between this
** column and next one.
*/
if (i != num_cols - 1)
{
for (j = 0; j < disp_len; j++)
{
fputc(' ', stdout);
}
}
#else /* EX_BTSID_45825 */
fprintf(stdout, "%s", coldata[i].value);
fflush(stdout);
/*
** If not last column, Print out spaces between this
** column and next one.
*/
if (i != num_cols - 1)
{
disp_len = ex_display_dlen(&datafmt[i]);
disp_len -= coldata[i].valuelen - 1;
for (j = 0; j < disp_len; j++)
{
fputc(' ', stdout);
}
}
#endif /* EX_BTSID_45825 */
}
fprintf(stdout, "\n");
fflush(stdout);
}
/*
** Free allocated space.
*/
for (i = 0; i < num_cols; i++)
{
free(coldata[i].value);
}
free(coldata);
free(datafmt);
/*
** We're done processing rows. Let's check the final return
** value of ct_fetch().
*/
switch ((int)retcode)
{
case CS_END_DATA:
/*
** Everything went fine.
*/
fprintf(stdout, MSG(MSG_ROW_DONE));
fflush(stdout);
retcode = CS_SUCCEED;
break;
case CS_FAIL:
/*
** Something terrible happened.
*/
ex_error("FetchData: ct_fetch() failed");
return retcode;
/*NOTREACHED*/
break;
default:
/*
** We got an unexpected return value.
*/
ex_error("FetchData: ct_fetch() returned an expected retcode");
return retcode;
/*NOTREACHED*/
break;
}
return retcode;
}
/*
** MyMoneyToChar()
**
** Type of function:
** Installed conversion function for international example program
**
** Purpose:
** This function does a crude attempt at supporting multiple monetary
** formats.
**
** Note that this routine may be called from interrupt level. This
** means that the any code within this routine must be interrupt safe.
**
** Parameters:
** context - Pointer to context structure
** srcfmt - Pointer to source datafmt structure.
** srcdata - Pointer to source data buffer.
** destfmt - Pointer to destination datafmt structure.
** destdata - Pointer to destination data buffer.
** destlen - Pointer to length variable (might be NULL).
**
** Return:
** CS_SUCCEED If conversion was successful.
** CS_EOVERFLOW If destination buffer is too small.
** <retcode> Result of the Client-Library function if a failure
** was returned.
**
*/
CS_STATIC CS_RETCODE CS_INTERNAL
MyMoneyToChar(context, srcfmt, srcdata, destfmt, destdata, destlen)
CS_CONTEXT *context;
CS_DATAFMT *srcfmt;
CS_VOID *srcdata;
CS_DATAFMT *destfmt;
CS_VOID *destdata;
CS_INT *destlen;
{
CS_RETCODE retcode;
CS_RETCODE convcode;
CS_DATAFMT tmpfmt;
CS_FLOAT flt;
CS_CHAR locbuf[EX_MAXSTRINGLEN];
CS_CHAR tmpbuf[EX_MAXSTRINGLEN];
/*
** First, convert it to float. Be careful when calling conversion
** routines from within a conversion routine, since recursion
** might occur (e.g. float->int calling float->char and
** float->char calling float->int would spin forever).
*/
memset(&tmpfmt, 0, sizeof(tmpfmt));
tmpfmt.datatype = CS_FLOAT_TYPE;
retcode = cs_convert(context, srcfmt, srcdata, &tmpfmt, &flt, NULL);
if (retcode != CS_SUCCEED)
{
ex_error("MyMoneyToChar: cs_convert() failed");
return retcode;
}
/*
** Get the language defined for the destination locale. Using
** this approach allows multiple locales to be supported within
** one application.
**
** Another approach that can be used is to store multiple
** monetary values within one table, differentiating them with a
** unique usertype field in the database. They can then be
** displayed based on the usertype. To determine the usertype for
** the column in the database, look at the srcfmt "usertype"
** field.
*/
retcode = cs_locale(context, CS_GET, destfmt->locale, CS_SYB_LANG,
locbuf, CS_SIZEOF(locbuf), NULL);
if (retcode != CS_SUCCEED)
{
ex_error("MyMoneyToChar: cs_locale(CS_GET) failed");
return retcode;
}
/*
** Based on Sybase language name, do conversion.
*/
switch ((int)LookupLanguage(locbuf))
{
case M_FRENCH:
sprintf(tmpbuf, "FF %-d,%02d", (int)flt,
(int)((flt - (int)flt + .005) * 100));
break;
case M_GERMAN:
sprintf(tmpbuf, "DM %-d,%02d", (int)flt,
(int)((flt - (int)flt + .005) * 100));
break;
case M_ENGLISH:
sprintf(tmpbuf, "$ %-.2f", flt);
break;
case M_UNKNOWN:
sprintf(tmpbuf, "?? %-.2f", flt);
break;
}
/*
** Fill in dest if there is room. Note that the destlen value
** should contain all the data written to the buffer, including
** the null terminator.
*/
if (destfmt->maxlength > strlen(tmpbuf))
{
strcpy(destdata, tmpbuf);
if (destlen != NULL)
{
*destlen = strlen(tmpbuf) + 1;
}
convcode = CS_SUCCEED;
}
else
{
convcode = CS_EOVERFLOW;
}
return convcode;
}
/*
** LookupLanguage(lang)
**
** Type of function:
** International example program internal api
**
** Purpose:
** This function will return a language define based on the
** character string passed in. It assumes the input string is a
** Sybase language string found in locales.dat.
**
** Parameters:
** lang - Pointer to string
**
** Return:
** M_ENGLISH - If english is to be used
** M_GERMAN - If german is to be used
** M_FRENCH - If french is to be used
** M_UNKNOWN - If language is not known
*/
CS_STATIC CS_INT CS_INTERNAL
LookupLanguage(lang)
CS_CHAR *lang;
{
CS_INT retlang;
if (strcmp(lang, "french") == 0)
{
retlang = M_FRENCH;
}
else if (strcmp(lang, "german") == 0)
{
retlang = M_GERMAN;
}
else if (strcmp(lang, "us_english") == 0)
{
retlang = M_ENGLISH;
}
else
{
retlang = M_UNKNOWN;
}
return retlang;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -