📄 i18n.c
字号:
/*
**
** Description
** -----------
** This example demonstrates some of the international features that
** are available in Client Library. It installs a custom conversion
** routine to handle multiple monetary formats. When processing
** results, any conversions that are needed during a fetch of a row
** will automatically call the installed routine when needed.
**
** To demonstrate the fetch processing, the example sends user SQL
** commands to the server via a language command. It processes the
** results using the standard ct_results() while loop. It binds the
** column values to program variables. It then fetches and displays
** the rows in the standard ct_fetch() while loop.
**
** The example also demonstrate the use of cs_locale() to set
** localization, and supports a simplistic method of displaying
** messages to the user based on language.
**
** Routines Used
** -------------
** cs_ctx_alloc()
** ct_init()
** ct_config()
** ct_callback()
** ct_con_alloc()
** ct_con_props()
** ct_connect()
** ct_cmd_alloc()
** ct_send()
** ct_results()
** ct_res_info()
** ct_describe()
** ct_bind()
** ct_fetch()
** ct_cmd_drop()
** ct_close()
** ct_con_drop()
** ct_exit()
** ct_ctx_drop()
** cs_loc_alloc()
** cs_locale()
** cs_config()
** cs_set_convert()
** cs_setnull()
** cs_loc_drop()
** cs_convert()
**
**
** Input
** -----
** This example can use a hard-coded query of the titles table in
** the pubs2 database. The query is defined by EX_SELECT. If
** EX_USE_SELECT is not defined, stdin is used to prompt the user.
**
**
** Output
** ------
** This example displays the rows as they are returned from the server.
**
**
** Server Dependencies
** -------------------
** To have server messages in the defined language requires that
** langinstall has been run against the server for the language.
**
**
** Server Tables
** -------------
** This example relies on the pubs2 database and the titles table.
**
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctpublic.h>
#include "example.h"
#include "exutils.h"
#if !lint
static char Sccsid[] = {"%Z% %M% %I% %G%"};
#endif /* !lint */
/*****************************************************************************
**
** defines and globals used.
**
*****************************************************************************/
/*
** Global names used in this module
*/
CS_CHAR *Ex_appname = "i18n";
CS_CHAR *Ex_dbname = "pubs2";
CS_CHAR *Ex_server = EX_SERVER;
CS_CHAR *Ex_username = EX_USERNAME;
CS_CHAR *Ex_password = EX_PASSWORD;
/*
** Global context structure
*/
CS_CONTEXT *Ex_context;
/*
** Uncomment the following if a hard coded select statment is desired for
** this example program. Otherwise, we will prompt for a query using
** stdin.
**
** #define EX_USE_SELECT 1
*/
#define EX_SELECT "select title_id, total_sales, price from titles \
where type like \"%cook\""
/*
** If a hard coded locale is desired, uncomment the defined below.
** Otherwise, the example program will use the environment for the
** locale. For a complete list of possible values for EX_LOCALE, please
** refer to the file $SYBASE/locales/locales.dat for valid entries for
** your particular platform.
**
** #define EX_USE_LOCALE 1
*/
#define EX_LOCALE "fr"
/*
** Define an index for the custom conversion routine that
** we will install in this example.
*/
#define MY_MONEY_CHAR_TYPE (CS_USER_TYPE + 1)
/*
** The following defines a very simplistic method of managing a
** set of messages which can work with multiple languages. The
** SetupLocale() function will initialize the Ex_language variable
** to the correct language.
**
** Normally, these messages would be in an external resource file.
*/
#define M_UNKNOWN (CS_INT)-1
#define M_ENGLISH (CS_INT)0
#define M_GERMAN (CS_INT)1
#define M_FRENCH (CS_INT)2
#define M_MAX_LANG (CS_INT)(M_FRENCH + 1)
#define MSG_STARTUP (CS_INT)0
#define MSG_QUERY (CS_INT)1
#define MSG_ROW_DONE (CS_INT)2
#define MSG_CMD_FAIL (CS_INT)3
#define MSG_MAX_MSG (CS_INT)(MSG_CMD_FAIL + 1)
CS_CHAR *Ex_messages[][MSG_MAX_MSG] = {
{
"International Example Program\n",
"\nEnter query to send or type quit: ",
"\nAll done processing rows.\n",
"\nSQL command failed. Check the Server messages for possible errors.\n",
},
{
"DM: International Example Program\n",
"\nDM: Enter query to send or type quit: ",
"\nDM: All done processing rows.\n",
"\nDM: SQL command failed. Check the Server messages for possible errors.\n",
},
{
"FF: International Example Program\n",
"\nFF: Enter query to send or type quit: ",
"\nFF: All done processing rows.\n",
"\nFF: SQL command failed. Check the Server messages for possible errors.\n",
},
};
CS_INT Ex_language = M_ENGLISH;
#define MSG(X) Ex_messages[Ex_language][(X)]
/*
** Prototypes for routines in sample code
*/
CS_STATIC CS_RETCODE CS_INTERNAL SetupLocale PROTOTYPE((
CS_CONTEXT *context
));
CS_STATIC CS_RETCODE CS_INTERNAL DoCommand PROTOTYPE((
CS_CONNECTION *connection,
CS_BOOL *p_domore
));
CS_STATIC CS_RETCODE CS_INTERNAL FetchData PROTOTYPE((
CS_COMMAND *cmd
));
CS_STATIC CS_RETCODE CS_INTERNAL MyMoneyToChar PROTOTYPE((
CS_CONTEXT *context,
CS_DATAFMT *srcfmt,
CS_VOID *srcdata,
CS_DATAFMT *destfmt,
CS_VOID *destdata,
CS_INT *destlen
));
CS_STATIC CS_INT CS_INTERNAL LookupLanguage PROTOTYPE((
CS_CHAR *lang
));
/*
** main()
**
** Purpose:
** Entry point for example program.
**
** Parameters:
** None, argc and argv will not be used.
**
** Returns:
** EX_EXIT_ERROR or EX_EXIT_SUCCEED
**
*/
int
main()
{
CS_CONNECTION *connection;
CS_RETCODE retcode;
CS_BOOL anothercmd = CS_TRUE;
/*
** Allocate a context structure and initialize Client-Library
*/
retcode = ex_init(&Ex_context);
if (retcode != CS_SUCCEED)
{
ex_panic("ex_init failed");
}
/*
** Setup up our locale for desired language and charset
*/
retcode = SetupLocale(Ex_context);
fprintf(stdout, MSG(MSG_STARTUP));
fflush(stdout);
/*
** Allocate a connection structure, set its properties, and
** establish a connection. Since the locale has already been
** defined in the context structure, the connection will inherit
** the context localization.
*/
if (retcode == CS_SUCCEED)
{
retcode = ex_connect(Ex_context, &connection, Ex_appname,
Ex_username, Ex_password, Ex_server);
}
/*
** Use the pubs2 database
*/
if (retcode == CS_SUCCEED)
{
if ((retcode = ex_use_db(connection, Ex_dbname)) != CS_SUCCEED)
{
ex_error("ex_use_db(pubs2) failed");
}
}
/*
** In a loop, execute the routines for the international example
** program until anothercmd is set to CS_FALSE or a failure was
** detected.
*/
while (retcode == CS_SUCCEED && anothercmd == CS_TRUE)
{
retcode = DoCommand(connection, &anothercmd);
}
/*
** Deallocate the allocated structures, close the connection,
** and exit Client-Library.
*/
if (connection != NULL)
{
retcode = ex_con_cleanup(connection, retcode);
}
if (Ex_context != NULL)
{
retcode = ex_ctx_cleanup(Ex_context, retcode);
}
return (retcode == CS_SUCCEED) ? EX_EXIT_SUCCEED : EX_EXIT_FAIL;
}
/*
** SetupLocale(context)
**
** Type of function:
** International example program internal api
**
** Purpose:
** This function setups up locale related information for the
** example program. This includes configuring the language, and
** installing custom conversion routines.
**
** Parameters:
** context - Pointer to context structure
**
** Return:
** CS_SUCCEED If locale was setup up correctly.
** <retcode> Result of the Client-Library function if a failure
** was returned.
**
*/
CS_STATIC CS_RETCODE CS_INTERNAL
SetupLocale(context)
CS_CONTEXT *context;
{
CS_RETCODE retcode;
CS_LOCALE *locale;
CS_DATAFMT tmpfmt;
CS_CONV_FUNC myfunc;
CS_CHAR locbuf[EX_MAXSTRINGLEN];
/*
** Get a locale handle.
*/
retcode = cs_loc_alloc(context, &locale);
if (retcode != CS_SUCCEED)
{
ex_error("SetupLocale: cs_loc_alloc() failed");
return retcode;
}
#if EX_USE_LOCALE
/*
** Set locale to the language/charset that we want
*/
retcode = cs_locale(context, CS_SET, locale, CS_LC_ALL, EX_LOCALE,
CS_NULLTERM, NULL);
if (retcode != CS_SUCCEED)
{
ex_error("SetupLocale: cs_locale(CS_SET) failed");
return retcode;
}
/*
** set context locale to the one we just defined
*/
retcode = cs_config(context, CS_SET, CS_LOC_PROP, locale,
CS_UNUSED, NULL);
if (retcode != CS_SUCCEED)
{
ex_error("SetupLocale: cs_config(CS_LOC_PROP) failed");
return retcode;
}
#endif /* EX_USE_LOCALE */
/*
** In order for our application program to work with the
** multitude of locales that could be defined, we will get the
** Sybase representation of the language and standardize on that.
*/
retcode = cs_locale(context, CS_GET, locale, CS_SYB_LANG,
locbuf, CS_SIZEOF(locbuf), NULL);
if (retcode != CS_SUCCEED)
{
ex_error("SetupLocale: cs_locale(CS_GET) failed");
return retcode;
}
/*
** Based on locale name, Set up global messages
*/
Ex_language = LookupLanguage(locbuf);
if (Ex_language == M_UNKNOWN)
{
fprintf(stdout,
"SetupLocale: Unknown language '%s', using English\n",
locbuf);
fflush(stdout);
Ex_language = M_ENGLISH;
}
/*
** Install a custom conversion routine that we can use whenever
** we want to display money values. cs_set_convert() can also be
** used to override Sybase conversion routines (e.g. the Sybase
** CS_MONEY_TYPE to CS_CHAR_TYPE conversion routine could be
** replaced with MyMoneyToChar()). Since cs_set_convert()
** requires a pointer to a pointer to a function, we use the temp
** variable "myfunc" to hold the location of the routine.
*/
myfunc = MyMoneyToChar;
retcode = cs_set_convert(context, CS_SET, CS_MONEY_TYPE,
MY_MONEY_CHAR_TYPE, (CS_VOID *)&myfunc);
if (retcode != CS_SUCCEED)
{
ex_error("SetupLocale: cs_set_convert() failed");
return retcode;
}
/*
** When a NULL value is received from the server, the conversion
** routine is not called. Instead, a default null value is placed
** in the destination buffer. In our case, we will display the
** string "NULL" when this occurs.
*/
memset(&tmpfmt, 0, sizeof(tmpfmt));
tmpfmt.datatype = MY_MONEY_CHAR_TYPE;
retcode = cs_setnull(context, &tmpfmt, "NULL", strlen("NULL"));
if (retcode != CS_SUCCEED)
{
ex_error("SetupLocale: cs_set_convert() failed");
return retcode;
}
/*
** drop locale handle.
*/
retcode = cs_loc_drop(context, locale);
if (retcode != CS_SUCCEED)
{
ex_error("SetupLocale: cs_loc_drop() failed");
return retcode;
}
return retcode;
}
/*
** DoCommand(connection, p_domore)
**
** Type of function:
** International example program internal api
**
** Purpose:
** This function is the core of the international example. It sends
** a sql statement to the server. It then processes the results in
** the standard ct_results() loop, calling FetchData() when the
** type of result is "fetchable".
**
** Parameters:
** connection - Pointer to connection structure
** p_domore - Pointer to a bool which is set to CS_TRUE if
** another command should be issued.
**
** Return:
** CS_SUCCEED If the result set was processed correctly.
** <retcode> Result of the Client-Library function if a failure
** was returned.
*/
CS_STATIC CS_RETCODE CS_INTERNAL
DoCommand(connection, p_domore)
CS_CONNECTION *connection;
CS_BOOL *p_domore;
{
CS_RETCODE retcode;
CS_COMMAND *cmd;
CS_INT res_type; /* result type from ct_results */
CS_CHAR buf[MAX_CHAR_BUF];
/*
** Allocate a command handle to send the query with
*/
if ((retcode = ct_cmd_alloc(connection, &cmd)) != CS_SUCCEED)
{
ex_error("DoCommand: ct_cmd_alloc() failed");
return retcode;
}
/*
** Define a language command that contains a sql statement to
** execute. EX_SELECT is a select statment which may be defined
** above in this file. This routine will set p_domore to CS_FALSE
** if a select was defined, or the user wants to exit the
** application.
*/
#if EX_USE_SELECT
strcpy(buf, EX_SELECT);
*p_domore = CS_FALSE;
#else
fprintf(stdout, MSG(MSG_QUERY));
fflush(stdout);
fgets(buf, sizeof (buf), stdin);
*p_domore = CS_TRUE;
#endif /* EX_USE_SELECT */
if (strncmp(buf, "quit", 4) == 0)
{
*p_domore = CS_FALSE;
return CS_SUCCEED;
}
retcode = ct_command(cmd, CS_LANG_CMD, buf, CS_NULLTERM, CS_UNUSED);
if (retcode != CS_SUCCEED)
{
ex_error("DoCommand: ct_command() failed");
return retcode;
}
/*
** Send the command to the server
*/
if (ct_send(cmd) != CS_SUCCEED)
{
ex_error("DoCommand: ct_send() failed");
return retcode;
}
/*
** Process the results. Loop while ct_results() returns CS_SUCCEED.
*/
while ((retcode = ct_results(cmd, &res_type)) == CS_SUCCEED)
{
switch ((int)res_type)
{
case CS_CMD_SUCCEED:
/*
** This means no rows were returned.
*/
break;
case CS_CMD_DONE:
/*
** This means we're done with one result set.
*/
break;
case CS_CMD_FAIL:
/*
** This means that the server encountered an error
** while processing our command.
*/
fprintf(stdout, MSG(MSG_CMD_FAIL));
fflush(stdout);
break;
case CS_ROW_RESULT:
case CS_PARAM_RESULT:
case CS_STATUS_RESULT:
case CS_COMPUTE_RESULT:
retcode = FetchData(cmd);
if (retcode != CS_SUCCEED)
{
ex_error("DoCommand: FetchData() failed");
return retcode;
}
break;
default:
/*
** We got an unexpected result type.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -