kmp_i18n.c

Go to the documentation of this file.
00001 /*
00002  * kmp_i18n.c
00003  * $Revision: 42181 $
00004  * $Date: 2013-03-26 15:04:45 -0500 (Tue, 26 Mar 2013) $
00005  */
00006 
00007 /* <copyright>
00008     Copyright (c) 2007-2013 Intel Corporation.  All Rights Reserved.
00009 
00010     Redistribution and use in source and binary forms, with or without
00011     modification, are permitted provided that the following conditions
00012     are met:
00013 
00014       * Redistributions of source code must retain the above copyright
00015         notice, this list of conditions and the following disclaimer.
00016       * Redistributions in binary form must reproduce the above copyright
00017         notice, this list of conditions and the following disclaimer in the
00018         documentation and/or other materials provided with the distribution.
00019       * Neither the name of Intel Corporation nor the names of its
00020         contributors may be used to endorse or promote products derived
00021         from this software without specific prior written permission.
00022 
00023     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00026     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00027     HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00028     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00029     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00030     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00031     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00033     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034 
00035 
00036 ------------------------------------------------------------------------
00037 
00038     Portions of this software are protected under the following patents:
00039         U.S. Patent 5,812,852
00040         U.S. Patent 6,792,599
00041         U.S. Patent 7,069,556
00042         U.S. Patent 7,328,433
00043         U.S. Patent 7,500,242
00044 
00045 </copyright> */
00046 
00047 
00048 #include "kmp_i18n.h"
00049 
00050 #include "kmp_os.h"
00051 #include "kmp_debug.h"
00052 #include "kmp.h"
00053 #include "kmp_lock.h"
00054 #include "kmp_io.h"          // __kmp_printf.
00055 
00056 #include <stdio.h>
00057 #include <errno.h>
00058 #include <string.h>
00059 #include <locale.h>
00060 #include <stdarg.h>
00061 
00062 #include "kmp_i18n_default.inc"
00063 #include "kmp_str.h"
00064 #include "kmp_environment.h"
00065 
00066 #undef KMP_I18N_OK
00067 
00068 #define get_section( id )  ( (id) >> 16 )
00069 #define get_number( id )   ( (id) & 0xFFFF )
00070 
00071 kmp_msg_t           __kmp_msg_empty = { kmp_mt_dummy, 0, "", 0  };
00072 kmp_msg_t           __kmp_msg_null  = { kmp_mt_dummy, 0, NULL, 0 };
00073 static char const * no_message_available = "(No message available)";
00074 
00075 enum kmp_i18n_cat_status {
00076     KMP_I18N_CLOSED,    // Not yet opened or closed.
00077     KMP_I18N_OPENED,    // Opened successfully, ready to use.
00078     KMP_I18N_ABSENT     // Opening failed, message catalog should not be used.
00079 }; // enum kmp_i18n_cat_status
00080 typedef enum kmp_i18n_cat_status  kmp_i18n_cat_status_t;
00081 static volatile kmp_i18n_cat_status_t  status = KMP_I18N_CLOSED;
00082 
00083 /*
00084     Message catalog is opened at first usage, so we have to synchronize opening to avoid race and
00085     multiple openings.
00086 
00087     Closing does not require synchronization, because catalog is closed very late at library
00088     shutting down, when no other threads are alive.
00089 */
00090 
00091 static void __kmp_i18n_do_catopen();
00092 static kmp_bootstrap_lock_t  lock = KMP_BOOTSTRAP_LOCK_INITIALIZER( lock );
00093     // `lock' variable may be placed into __kmp_i18n_catopen function because it is used only by
00094     // that function. But we afraid a (buggy) compiler may treat it wrongly. So we put it outside of
00095     // function just in case.
00096 
00097 void
00098 __kmp_i18n_catopen(
00099 ) {
00100     if ( status == KMP_I18N_CLOSED ) {
00101         __kmp_acquire_bootstrap_lock( & lock );
00102         if ( status == KMP_I18N_CLOSED ) {
00103             __kmp_i18n_do_catopen();
00104         }; // if
00105         __kmp_release_bootstrap_lock( & lock );
00106     }; // if
00107 } // func __kmp_i18n_catopen
00108 
00109 
00110 /*
00111     ================================================================================================
00112     Linux* OS and OS X* part.
00113     ================================================================================================
00114 */
00115 
00116 #if KMP_OS_UNIX
00117 #define KMP_I18N_OK
00118 
00119 #include <nl_types.h>
00120 
00121 #define KMP_I18N_NULLCAT ((nl_catd)( -1 ))
00122 static nl_catd       cat  = KMP_I18N_NULLCAT;    // !!! Shall it be volatile?
00123 static char const *  name = ( KMP_VERSION_MAJOR == 4 ? "libguide.cat" : "libiomp5.cat" );
00124 
00125 /*
00126     Useful links:
00127         http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html#tag_08_02
00128         http://www.opengroup.org/onlinepubs/000095399/functions/catopen.html
00129         http://www.opengroup.org/onlinepubs/000095399/functions/setlocale.html
00130 */
00131 
00132 void
00133 __kmp_i18n_do_catopen(
00134 ) {
00135     int    english = 0;
00136     char * lang    = __kmp_env_get( "LANG" );
00137     // TODO: What about LC_ALL or LC_MESSAGES?
00138 
00139     KMP_DEBUG_ASSERT( status == KMP_I18N_CLOSED );
00140     KMP_DEBUG_ASSERT( cat    == KMP_I18N_NULLCAT );
00141 
00142     english =
00143     lang == NULL                       ||  // In all these cases English language is used.
00144     strcmp( lang, "" )            == 0 ||
00145         strcmp( lang, " " )           == 0 ||
00146               // Workaround for Fortran RTL bug DPD200137873 "Fortran runtime resets LANG env var
00147               // to space if it is not set".
00148     strcmp( lang, "C" )           == 0 ||
00149     strcmp( lang, "POSIX" )       == 0;
00150 
00151     if ( ! english ) {  // English language is not yet detected, let us continue.
00152         // Format of LANG is: [language[_territory][.codeset][@modifier]]
00153         // Strip all parts except language.
00154         char * tail = NULL;
00155         __kmp_str_split( lang, '@', & lang, & tail );
00156         __kmp_str_split( lang, '.', & lang, & tail );
00157         __kmp_str_split( lang, '_', & lang, & tail );
00158         english = ( strcmp( lang, "en" ) == 0 );
00159     }; // if
00160 
00161     KMP_INTERNAL_FREE( lang );
00162 
00163     // Do not try to open English catalog because internal messages are
00164     // exact copy of messages in English catalog.
00165     if ( english ) {
00166     status = KMP_I18N_ABSENT;  // mark catalog as absent so it will not be re-opened.
00167     return;
00168     }
00169 
00170     cat = catopen( name, 0 );
00171     // TODO: Why do we pass 0 in flags?
00172     status = ( cat == KMP_I18N_NULLCAT ? KMP_I18N_ABSENT : KMP_I18N_OPENED );
00173 
00174     if ( status == KMP_I18N_ABSENT ) {
00175       if (__kmp_generate_warnings > kmp_warnings_low) { // AC: only issue warning in case explicitly asked to
00176         int    error   = errno; // Save errno immediatelly.
00177     char * nlspath = __kmp_env_get( "NLSPATH" );
00178         char * lang    = __kmp_env_get( "LANG" );
00179 
00180     // Infinite recursion will not occur -- status is KMP_I18N_ABSENT now, so
00181     // __kmp_i18n_catgets() will not try to open catalog, but will return default message.
00182     __kmp_msg(
00183         kmp_ms_warning,
00184         KMP_MSG( CantOpenMessageCatalog, name ),
00185         KMP_ERR( error ),
00186         KMP_HNT( CheckEnvVar, "NLSPATH", nlspath ),
00187             KMP_HNT( CheckEnvVar, "LANG", lang ),
00188         __kmp_msg_null
00189     );
00190     KMP_INFORM( WillUseDefaultMessages );
00191         KMP_INTERNAL_FREE( nlspath );
00192         KMP_INTERNAL_FREE( lang );
00193       }
00194     } else { // status == KMP_I18N_OPENED
00195 
00196         int section = get_section( kmp_i18n_prp_Version );
00197         int number  = get_number( kmp_i18n_prp_Version );
00198         char const * expected = __kmp_i18n_default_table.sect[ section ].str[ number ];
00199             // Expected version of the catalog.
00200         kmp_str_buf_t version;   // Actual version of the catalog.
00201         __kmp_str_buf_init( & version );
00202         __kmp_str_buf_print( & version, "%s", catgets( cat, section, number, NULL ) );
00203 
00204             // String returned by catgets is invalid after closing the catalog, so copy it.
00205         if ( strcmp( version.str, expected ) != 0 ) {
00206             __kmp_i18n_catclose();     // Close bad catalog.
00207             status = KMP_I18N_ABSENT;  // And mark it as absent.
00208             if (__kmp_generate_warnings > kmp_warnings_low) { // AC: only issue warning in case explicitly asked to
00209                 // And now print a warning using default messages.
00210                 char const * name    = "NLSPATH";
00211                 char const * nlspath = __kmp_env_get( name );
00212                 __kmp_msg(
00213                     kmp_ms_warning,
00214                     KMP_MSG( WrongMessageCatalog, name, version.str, expected ),
00215                     KMP_HNT( CheckEnvVar, name, nlspath ),
00216                     __kmp_msg_null
00217                 );
00218                 KMP_INFORM( WillUseDefaultMessages );
00219                 KMP_INTERNAL_FREE( (void *) nlspath );
00220             } // __kmp_generate_warnings
00221         }; // if
00222         __kmp_str_buf_free( & version );
00223 
00224     }; // if
00225 
00226 } // func __kmp_i18n_do_catopen
00227 
00228 
00229 void
00230 __kmp_i18n_catclose(
00231 ) {
00232     if ( status == KMP_I18N_OPENED ) {
00233         KMP_DEBUG_ASSERT( cat != KMP_I18N_NULLCAT );
00234         catclose( cat );
00235         cat = KMP_I18N_NULLCAT;
00236     }; // if
00237     status = KMP_I18N_CLOSED;
00238 } // func __kmp_i18n_catclose
00239 
00240 
00241 char const *
00242 __kmp_i18n_catgets(
00243     kmp_i18n_id_t  id
00244 ) {
00245 
00246     int section = get_section( id );
00247     int number  = get_number( id );
00248     char const * message = NULL;
00249 
00250     if ( 1 <= section && section <= __kmp_i18n_default_table.size ) {
00251         if ( 1 <= number && number <= __kmp_i18n_default_table.sect[ section ].size ) {
00252             if ( status == KMP_I18N_CLOSED ) {
00253                 __kmp_i18n_catopen();
00254             }; // if
00255             if ( status == KMP_I18N_OPENED ) {
00256                 message =
00257                     catgets(
00258                         cat,
00259                         section, number,
00260                         __kmp_i18n_default_table.sect[ section ].str[ number ]
00261                     );
00262             }; // if
00263             if ( message == NULL ) {
00264                 message = __kmp_i18n_default_table.sect[ section ].str[ number ];
00265             }; // if
00266         }; // if
00267     }; // if
00268     if ( message == NULL ) {
00269         message = no_message_available;
00270     }; // if
00271     return message;
00272 
00273 } // func __kmp_i18n_catgets
00274 
00275 
00276 #endif // KMP_OS_UNIX
00277 
00278 /*
00279     ================================================================================================
00280     Windows* OS part.
00281     ================================================================================================
00282 */
00283 
00284 #if KMP_OS_WINDOWS
00285 #define KMP_I18N_OK
00286 
00287 #include "kmp_environment.h"
00288 #include <windows.h>
00289 
00290 #define KMP_I18N_NULLCAT  NULL
00291 static HMODULE       cat  = KMP_I18N_NULLCAT;    // !!! Shall it be volatile?
00292 static char const *  name = ( KMP_VERSION_MAJOR == 4 ? "libguide40ui.dll" : "libiomp5ui.dll" );
00293 
00294 static kmp_i18n_table_t  table             = { 0, NULL };
00295     // Messages formatted by FormatMessage() should be freed, but catgets() interface assumes
00296     // user will not free messages. So we cache all the retrieved messages in the table, which
00297     // are freed at catclose().
00298 static UINT const        default_code_page = CP_OEMCP;
00299 static UINT              code_page         = default_code_page;
00300 
00301 static char const * ___catgets( kmp_i18n_id_t  id );
00302 static UINT         get_code_page();
00303 static void         kmp_i18n_table_free( kmp_i18n_table_t * table );
00304 
00305 
00306 static UINT
00307 get_code_page(
00308 ) {
00309 
00310     UINT cp = default_code_page;
00311     char const * value = __kmp_env_get( "KMP_CODEPAGE" );
00312     if ( value != NULL ) {
00313         if ( _stricmp( value, "ANSI" ) == 0 ) {
00314             cp = CP_ACP;
00315         } else if ( _stricmp( value, "OEM" ) == 0 ) {
00316             cp = CP_OEMCP;
00317         } else if ( _stricmp( value, "UTF-8" ) == 0 || _stricmp( value, "UTF8" ) == 0 ) {
00318             cp = CP_UTF8;
00319         } else if ( _stricmp( value, "UTF-7" ) == 0 || _stricmp( value, "UTF7" ) == 0 ) {
00320             cp = CP_UTF7;
00321         } else {
00322             // !!! TODO: Issue a warning?
00323         }; // if
00324     }; // if
00325     KMP_INTERNAL_FREE( (void *) value );
00326     return cp;
00327 
00328 } // func get_code_page
00329 
00330 
00331 static void
00332 kmp_i18n_table_free(
00333     kmp_i18n_table_t * table
00334 ) {
00335     int s;
00336     int m;
00337     for ( s = 0; s < table->size; ++ s ) {
00338         for ( m = 0; m < table->sect[ s ].size; ++ m ) {
00339             // Free message.
00340             KMP_INTERNAL_FREE( (void *) table->sect[ s ].str[ m ] );
00341             table->sect[ s ].str[ m ] = NULL;
00342         }; // for m
00343         table->sect[ s ].size = 0;
00344         // Free section itself.
00345         KMP_INTERNAL_FREE ( (void *) table->sect[ s ].str );
00346         table->sect[ s ].str = NULL;
00347     }; // for s
00348     table->size = 0;
00349     KMP_INTERNAL_FREE( (void *) table->sect );
00350     table->sect = NULL;
00351 } // kmp_i8n_table_free
00352 
00353 
00354 void
00355 __kmp_i18n_do_catopen(
00356 ) {
00357 
00358     LCID          locale_id = GetThreadLocale();
00359     WORD      lang_id = LANGIDFROMLCID( locale_id );
00360     WORD          primary_lang_id = PRIMARYLANGID( lang_id );
00361     kmp_str_buf_t path;
00362 
00363     KMP_DEBUG_ASSERT( status == KMP_I18N_CLOSED );
00364     KMP_DEBUG_ASSERT( cat    == KMP_I18N_NULLCAT );
00365 
00366     __kmp_str_buf_init( & path );
00367 
00368     // Do not try to open English catalog because internal messages are
00369     // exact copy of messages in English catalog.
00370     if ( primary_lang_id == LANG_ENGLISH ) {
00371     status = KMP_I18N_ABSENT;  // mark catalog as absent so it will not be re-opened.
00372     goto end;
00373     }; // if
00374 
00375     // Construct resource DLL name.
00376     /*
00377         Simple
00378             LoadLibrary( name )
00379         is not suitable due to security issue (see
00380         http://www.microsoft.com/technet/security/advisory/2269637.mspx). We have to specify full
00381         path to the message catalog.
00382     */
00383     {
00384 
00385         // Get handle of our DLL first.
00386         HMODULE handle;
00387         BOOL brc =
00388             GetModuleHandleEx(
00389                 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
00390                 reinterpret_cast< LPCSTR >( & __kmp_i18n_do_catopen ),
00391                 & handle
00392             );
00393         if ( ! brc ) {    // Error occured.
00394             status = KMP_I18N_ABSENT;  // mark catalog as absent so it will not be re-opened.
00395             goto end;
00396             // TODO: Enable multiple messages (KMP_MSG) to be passed to __kmp_msg; and print
00397             // a proper warning.
00398         }; // if
00399 
00400         // Now get path to the our DLL.
00401         for ( ; ; ) {
00402             DWORD drc = GetModuleFileName( handle, path.str, path.size );
00403             if ( drc == 0 ) {    // Error occured.
00404                 status = KMP_I18N_ABSENT;
00405                 goto end;
00406             }; // if
00407             if ( drc < path.size ) {
00408                 path.used = drc;
00409                 break;
00410             }; // if
00411             __kmp_str_buf_reserve( & path, path.size * 2 );
00412         }; // forever
00413 
00414         // Now construct the name of message catalog.
00415         kmp_str_fname fname;
00416         __kmp_str_fname_init( & fname, path.str );
00417         __kmp_str_buf_clear( & path );
00418         __kmp_str_buf_print( & path, "%s%lu/%s", fname.dir, (unsigned long)( locale_id ), name );
00419         __kmp_str_fname_free( & fname );
00420 
00421     }
00422 
00423     // For security reasons, use LoadLibraryEx() and load message catalog as a data file.
00424     cat = LoadLibraryEx( path.str, NULL, LOAD_LIBRARY_AS_DATAFILE );
00425     status = ( cat == KMP_I18N_NULLCAT ? KMP_I18N_ABSENT : KMP_I18N_OPENED );
00426 
00427     if ( status == KMP_I18N_ABSENT ) {
00428       if (__kmp_generate_warnings > kmp_warnings_low) { // AC: only issue warning in case explicitly asked to
00429     DWORD error = GetLastError();
00430     // Infinite recursion will not occur -- status is KMP_I18N_ABSENT now, so
00431     // __kmp_i18n_catgets() will not try to open catalog but will return default message.
00432         /*
00433          If message catalog for another architecture found (e.g. OpenMP RTL
00434      for IA-32 architecture opens libiomp5ui.dll for Intel(R) 64)
00435      Windows* OS returns error 193 (ERROR_BAD_EXE_FORMAT). However,
00436          FormatMessage fails to return a message for this error, so user
00437      will see:
00438 
00439          OMP: Warning #2: Cannot open message catalog "1041\libiomp5ui.dll":
00440          OMP: System error #193: (No system error message available)
00441          OMP: Info #3: Default messages will be used.
00442 
00443          Issue a hint in this case to let cause of trouble more understandable.
00444         */
00445     __kmp_msg(
00446         kmp_ms_warning,
00447         KMP_MSG( CantOpenMessageCatalog, path.str ),
00448         KMP_SYSERRCODE( error ),
00449             ( error == ERROR_BAD_EXE_FORMAT ? KMP_HNT( BadExeFormat, path.str, KMP_ARCH_STR ) : __kmp_msg_null ),
00450         __kmp_msg_null
00451     );
00452     KMP_INFORM( WillUseDefaultMessages );
00453       }
00454     } else { // status == KMP_I18N_OPENED
00455 
00456         int section = get_section( kmp_i18n_prp_Version );
00457         int number  = get_number( kmp_i18n_prp_Version );
00458         char const * expected = __kmp_i18n_default_table.sect[ section ].str[ number ];
00459         kmp_str_buf_t version;   // Actual version of the catalog.
00460         __kmp_str_buf_init( & version );
00461         __kmp_str_buf_print( & version, "%s", ___catgets( kmp_i18n_prp_Version ) );
00462             // String returned by catgets is invalid after closing the catalog, so copy it.
00463         if ( strcmp( version.str, expected ) != 0 ) {
00464             // Close bad catalog.
00465             __kmp_i18n_catclose();
00466             status = KMP_I18N_ABSENT;  // And mark it as absent.
00467             if (__kmp_generate_warnings > kmp_warnings_low) {
00468                 // And now print a warning using default messages.
00469                 __kmp_msg(
00470                     kmp_ms_warning,
00471                     KMP_MSG( WrongMessageCatalog, path.str, version.str, expected ),
00472                     __kmp_msg_null
00473                 );
00474                 KMP_INFORM( WillUseDefaultMessages );
00475             } // __kmp_generate_warnings
00476         }; // if
00477         __kmp_str_buf_free( & version );
00478 
00479     }; // if
00480     code_page = get_code_page();
00481 
00482     end:
00483         __kmp_str_buf_free( & path );
00484         return;
00485 
00486 } // func __kmp_i18n_do_catopen
00487 
00488 
00489 void
00490 __kmp_i18n_catclose(
00491 ) {
00492     if ( status == KMP_I18N_OPENED ) {
00493         KMP_DEBUG_ASSERT( cat != KMP_I18N_NULLCAT );
00494         kmp_i18n_table_free( & table );
00495         FreeLibrary( cat );
00496         cat = KMP_I18N_NULLCAT;
00497     }; // if
00498     code_page = default_code_page;
00499     status = KMP_I18N_CLOSED;
00500 } // func __kmp_i18n_catclose
00501 
00502 /*
00503     We use FormatMessage() to get strings from catalog, get system error messages, etc.
00504     FormatMessage() tends to return Windows* OS-style end-of-lines, "\r\n". When string is printed,
00505     printf() also replaces all the occurences of "\n" with "\r\n" (again!), so sequences like
00506     "\r\r\r\n" appear in output. It is not too good.
00507 
00508     Additional mess comes from message catalog: Our catalog source en_US.mc file (generated by
00509     message-converter.pl) contains only "\n" characters, but en_US_msg_1033.bin file (produced by
00510     mc.exe) may contain "\r\n" or just "\n". This mess goes from en_US_msg_1033.bin file to
00511     message catalog, libiomp5ui.dll. For example, message
00512 
00513         Error
00514 
00515     (there is "\n" at the end) is compiled by mc.exe to "Error\r\n", while
00516 
00517         OMP: Error %1!d!: %2!s!\n
00518 
00519     (there is "\n" at the end as well) is compiled to "OMP: Error %1!d!: %2!s!\r\n\n".
00520 
00521     Thus, stripping all "\r" normalizes string and returns it to canonical form, so printf() will
00522     produce correct end-of-line sequences.
00523 
00524     ___strip_crs() serves for this purpose: it removes all the occurences of "\r" in-place and
00525     returns new length of string.
00526 */
00527 static
00528 int
00529 ___strip_crs(
00530     char * str
00531 ) {
00532     int in  = 0;  // Input character index.
00533     int out = 0;  // Output character index.
00534     for ( ; ; ) {
00535         if ( str[ in ] != '\r' ) {
00536             str[ out ] = str[ in ];
00537             ++ out;
00538         }; // if
00539         if ( str[ in ] == 0 ) {
00540             break;
00541         }; // if
00542         ++ in;
00543     }; // forever
00544     return out - 1;
00545 } // func __strip_crs
00546 
00547 
00548 static
00549 char const *
00550 ___catgets(
00551     kmp_i18n_id_t  id
00552 ) {
00553 
00554     char *    result = NULL;
00555     PVOID     addr   = NULL;
00556     wchar_t * wmsg   = NULL;
00557     DWORD     wlen   = 0;
00558     char *    msg    = NULL;
00559     int       len    = 0;
00560     int       rc;
00561 
00562     KMP_DEBUG_ASSERT( cat != KMP_I18N_NULLCAT );
00563     wlen =    // wlen does *not* include terminating null.
00564         FormatMessageW(
00565             FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE |
00566                 FORMAT_MESSAGE_IGNORE_INSERTS,
00567             cat,
00568             id,
00569             0,             // LangId
00570             (LPWSTR) & addr,
00571             0,             // Size in elements, not in bytes.
00572             NULL
00573         );
00574     if ( wlen <= 0 ) {
00575         goto end;
00576     }; // if
00577     wmsg = (wchar_t *) addr;  // Warning: wmsg may be not nul-terminated!
00578 
00579     // Calculate length of multibyte message.
00580     len =     // Since wlen does not include terminating null, len does not include it also.
00581         WideCharToMultiByte(
00582             code_page,
00583             0,                // Flags.
00584             wmsg, wlen,       // Wide buffer and size.
00585             NULL, 0,          // Buffer and size.
00586             NULL, NULL        // Default char and used default char.
00587         );
00588     if ( len <= 0 ) {
00589         goto end;
00590     }; // if
00591 
00592     // Allocate memory.
00593     msg = (char *) KMP_INTERNAL_MALLOC( len + 1 );
00594 
00595     // Convert wide message to multibyte one.
00596     rc =
00597         WideCharToMultiByte(
00598             code_page,
00599             0,                // Flags.
00600             wmsg, wlen,       // Wide buffer and size.
00601             msg, len,         // Buffer and size.
00602             NULL, NULL        // Default char and used default char.
00603         );
00604     if ( rc <= 0 || rc > len ) {
00605         goto end;
00606     }; // if
00607     KMP_DEBUG_ASSERT( rc == len );
00608     len = rc;
00609     msg[ len ] = 0;           // Put terminating null to the end.
00610 
00611     // Stripping all "\r" before stripping last end-of-line simplifies the task.
00612     len = ___strip_crs( msg );
00613 
00614     // Every message in catalog is terminated with "\n". Strip it.
00615     if ( len >= 1 && msg[ len - 1 ] == '\n' ) {
00616         -- len;
00617         msg[ len ] = 0;
00618     }; // if
00619 
00620     // Everything looks ok.
00621     result = msg;
00622     msg    = NULL;
00623 
00624     end:
00625 
00626     if ( msg != NULL ) {
00627         KMP_INTERNAL_FREE( msg );
00628     }; // if
00629     if ( wmsg != NULL ) {
00630         LocalFree( wmsg );
00631     }; // if
00632 
00633     return result;
00634 
00635 } // ___catgets
00636 
00637 
00638 char const *
00639 __kmp_i18n_catgets(
00640     kmp_i18n_id_t  id
00641 ) {
00642 
00643     int section = get_section( id );
00644     int number  = get_number( id );
00645     char const * message = NULL;
00646 
00647     if ( 1 <= section && section <= __kmp_i18n_default_table.size ) {
00648         if ( 1 <= number && number <= __kmp_i18n_default_table.sect[ section ].size ) {
00649             if ( status == KMP_I18N_CLOSED ) {
00650                 __kmp_i18n_catopen();
00651             }; // if
00652             if ( cat != KMP_I18N_NULLCAT ) {
00653                 if ( table.size == 0 ) {
00654                     table.sect = (kmp_i18n_section_t *)
00655                         KMP_INTERNAL_CALLOC(
00656                             ( __kmp_i18n_default_table.size + 2 ),
00657                             sizeof( kmp_i18n_section_t )
00658                         );
00659                     table.size = __kmp_i18n_default_table.size;
00660                 }; // if
00661                 if ( table.sect[ section ].size == 0 ) {
00662                     table.sect[ section ].str = (const char **)
00663                         KMP_INTERNAL_CALLOC(
00664                             __kmp_i18n_default_table.sect[ section ].size + 2,
00665                             sizeof( char const * )
00666                         );
00667                     table.sect[ section ].size = __kmp_i18n_default_table.sect[ section ].size;
00668                 }; // if
00669                 if ( table.sect[ section ].str[ number ] == NULL ) {
00670                     table.sect[ section ].str[ number ] = ___catgets( id );
00671                 }; // if
00672                 message = table.sect[ section ].str[ number ];
00673             }; // if
00674             if ( message == NULL ) {
00675                 // Catalog is not opened or message is not found, return default message.
00676                 message = __kmp_i18n_default_table.sect[ section ].str[ number ];
00677             }; // if
00678         }; // if
00679     }; // if
00680     if ( message == NULL ) {
00681         message = no_message_available;
00682     }; // if
00683     return message;
00684 
00685 } // func __kmp_i18n_catgets
00686 
00687 
00688 #endif // KMP_OS_WINDOWS
00689 
00690 // -------------------------------------------------------------------------------------------------
00691 
00692 #ifndef KMP_I18N_OK
00693     #error I18n support is not implemented for this OS.
00694 #endif // KMP_I18N_OK
00695 
00696 // -------------------------------------------------------------------------------------------------
00697 
00698 void
00699 __kmp_i18n_dump_catalog(
00700     kmp_str_buf_t & buffer
00701 ) {
00702 
00703     struct kmp_i18n_id_range_t {
00704         kmp_i18n_id_t  first;
00705         kmp_i18n_id_t  last;
00706     }; // struct kmp_i18n_id_range_t
00707 
00708     static kmp_i18n_id_range_t ranges[] = {
00709         { kmp_i18n_prp_first, kmp_i18n_prp_last },
00710         { kmp_i18n_str_first, kmp_i18n_str_last },
00711         { kmp_i18n_fmt_first, kmp_i18n_fmt_last },
00712         { kmp_i18n_msg_first, kmp_i18n_msg_last },
00713         { kmp_i18n_hnt_first, kmp_i18n_hnt_last }
00714     }; // ranges
00715 
00716     int           num_of_ranges = sizeof( ranges ) / sizeof( kmp_i18n_id_range_t );
00717     int           range;
00718     kmp_i18n_id_t id;
00719 
00720     for ( range = 0; range < num_of_ranges; ++ range ) {
00721         __kmp_str_buf_print( & buffer, "*** Set #%d ***\n", range + 1 );
00722         for ( id = kmp_i18n_id_t( ranges[ range ].first + 1 ); id < ranges[ range ].last; id = kmp_i18n_id_t( id + 1 ) ) {
00723              __kmp_str_buf_print( & buffer, "%d: <<%s>>\n", id, __kmp_i18n_catgets( id ) );
00724         }; // for id
00725     }; // for range
00726 
00727     __kmp_printf( "%s", buffer.str );
00728 
00729 } // __kmp_i18n_dump_catalog
00730 
00731 // -------------------------------------------------------------------------------------------------
00732 
00733 kmp_msg_t
00734 __kmp_msg_format(
00735     kmp_i18n_id_t id,
00736     ...
00737 ) {
00738 
00739     kmp_msg_t      msg;
00740     va_list        args;
00741     kmp_str_buf_t  buffer;
00742     __kmp_str_buf_init( & buffer );
00743 
00744     va_start( args, id );
00745     #if KMP_OS_UNIX
00746         // On Linux* OS and OS X*, printf() family functions process parameter numbers, for example:
00747         // "%2$s %1$s".
00748         __kmp_str_buf_vprint( & buffer, __kmp_i18n_catgets( id ), args );
00749     #elif KMP_OS_WINDOWS
00750         // On Winodws, printf() family functions does not recognize GNU style parameter numbers,
00751         // so we have to use FormatMessage() instead. It recognizes parameter numbers, e. g.:
00752         // "%2!s! "%1!s!".
00753         {
00754             LPTSTR str = NULL;
00755             int    len;
00756             FormatMessage(
00757                 FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
00758                 __kmp_i18n_catgets( id ),
00759                 0, 0,
00760                 (LPTSTR)( & str ),
00761                 0,
00762                 & args
00763             );
00764             len = ___strip_crs( str );
00765             __kmp_str_buf_cat( & buffer, str, len );
00766             LocalFree( str );
00767         }
00768     #else
00769         #error
00770     #endif
00771     va_end( args );
00772     __kmp_str_buf_detach( & buffer );
00773 
00774     msg.type = (kmp_msg_type_t)( id >> 16 );
00775     msg.num  = id & 0xFFFF;
00776     msg.str  = buffer.str;
00777     msg.len  = buffer.used;
00778 
00779     return msg;
00780 
00781 } // __kmp_msg_format
00782 
00783 // -------------------------------------------------------------------------------------------------
00784 
00785 static
00786 char *
00787 sys_error(
00788     int err
00789 ) {
00790 
00791     char * message = NULL;
00792 
00793     #if KMP_OS_WINDOWS
00794 
00795         LPVOID  buffer = NULL;
00796         int     len;
00797         DWORD   rc;
00798         rc =
00799             FormatMessage(
00800                 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
00801                 NULL,
00802                 err,
00803                 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language.
00804                 (LPTSTR) & buffer,
00805                 0,
00806                 NULL
00807             );
00808         if ( rc > 0 ) {
00809             // Message formatted. Copy it (so we can free it later with normal free().
00810             message = __kmp_str_format( "%s", (char *) buffer );
00811             len = ___strip_crs( message ); // Delete carriage returns if any.
00812             // Strip trailing newlines.
00813             while ( len > 0 && message[ len - 1 ] == '\n' ) {
00814                 -- len;
00815             }; // while
00816             message[ len ] = 0;
00817         } else {
00818             // FormatMessage() failed to format system error message. GetLastError() would give us
00819             // error code, which we would convert to message... this it dangerous recursion, which
00820             // cannot clarify original error, so we will not even start it.
00821         }; // if
00822         if ( buffer != NULL ) {
00823             LocalFree( buffer );
00824         }; // if
00825 
00826     #else // Non-Windows* OS: Linux* OS or OS X*
00827 
00828         /*
00829             There are 2 incompatible versions of strerror_r:
00830 
00831                 char * strerror_r( int, char *, size_t );  // GNU version
00832                 int    strerror_r( int, char *, size_t );  // XSI version
00833         */
00834 
00835         #if KMP_OS_LINUX
00836 
00837             // GNU version of strerror_r.
00838 
00839             char   buffer[ 2048 ];
00840             char * const err_msg = strerror_r( err, buffer, sizeof( buffer ) );
00841                 // Do not eliminate this assignment to temporary variable, otherwise compiler would
00842                 // not issue warning if strerror_r() returns `int' instead of expected `char *'.
00843             message = __kmp_str_format( "%s", err_msg );
00844 
00845         #else // OS X*
00846 
00847             // XSI version of strerror_r.
00848 
00849             int    size   = 2048;
00850             // TODO: Add checking result of malloc().
00851             char * buffer = (char *) KMP_INTERNAL_MALLOC( size );
00852             int    rc;
00853             rc = strerror_r( err, buffer, size );
00854             if ( rc == -1 ) {
00855                 rc = errno;            // XSI version sets errno.
00856             }; // if
00857             while ( rc == ERANGE ) {   // ERANGE means the buffer is too small.
00858                 KMP_INTERNAL_FREE( buffer );
00859                 size *= 2;
00860                 buffer = (char *) KMP_INTERNAL_MALLOC( size );
00861                 rc = strerror_r( err, buffer, size );
00862                 if ( rc == -1 ) {
00863                     rc = errno;        // XSI version sets errno.
00864                 }; // if
00865             }; // while
00866             if ( rc == 0 ) {
00867                 message = buffer;
00868             } else {
00869                 // Buffer is unused. Free it.
00870                 KMP_INTERNAL_FREE( buffer );
00871             }; // if
00872 
00873         #endif
00874 
00875     #endif /* KMP_OS_WINDOWS */
00876 
00877     if ( message == NULL ) {
00878         // TODO: I18n this message.
00879         message = __kmp_str_format( "%s", "(No system error message available)" );
00880     }; // if
00881     return message;
00882 
00883 } // sys_error
00884 
00885 // -------------------------------------------------------------------------------------------------
00886 
00887 kmp_msg_t
00888 __kmp_msg_error_code(
00889     int  code
00890 ) {
00891 
00892     kmp_msg_t      msg;
00893     msg.type = kmp_mt_syserr;
00894     msg.num  = code;
00895     msg.str  = sys_error( code );
00896     msg.len  = strlen( msg.str );
00897     return msg;
00898 
00899 } // __kmp_msg_error_code
00900 
00901 // -------------------------------------------------------------------------------------------------
00902 
00903 kmp_msg_t
00904 __kmp_msg_error_mesg(
00905     char const * mesg
00906 ) {
00907 
00908     kmp_msg_t      msg;
00909     msg.type = kmp_mt_syserr;
00910     msg.num  = 0;
00911     msg.str  = __kmp_str_format( "%s", mesg );
00912     msg.len  = strlen( msg.str );
00913     return msg;
00914 
00915 } // __kmp_msg_error_mesg
00916 
00917 // -------------------------------------------------------------------------------------------------
00918 
00919 void
00920 __kmp_msg(
00921     kmp_msg_severity_t  severity,
00922     kmp_msg_t           message,
00923     ...
00924 ) {
00925 
00926     va_list        args;
00927     kmp_i18n_id_t  format;      // format identifier
00928     kmp_msg_t      fmsg;        // formatted message
00929     kmp_str_buf_t  buffer;
00930 
00931     if ( severity != kmp_ms_fatal && __kmp_generate_warnings == kmp_warnings_off )
00932         return; // no reason to form a string in order to not print it
00933 
00934     __kmp_str_buf_init( & buffer );
00935 
00936     // Format the primary message.
00937     switch ( severity ) {
00938         case kmp_ms_inform : {
00939             format = kmp_i18n_fmt_Info;
00940         } break;
00941         case kmp_ms_warning : {
00942             format = kmp_i18n_fmt_Warning;
00943         } break;
00944         case kmp_ms_fatal : {
00945             format = kmp_i18n_fmt_Fatal;
00946         } break;
00947         default : {
00948             KMP_DEBUG_ASSERT( 0 );
00949         };
00950     }; // switch
00951     fmsg = __kmp_msg_format( format, message.num, message.str );
00952     KMP_INTERNAL_FREE( (void *) message.str );
00953     __kmp_str_buf_cat( & buffer, fmsg.str, fmsg.len );
00954     KMP_INTERNAL_FREE( (void *) fmsg.str );
00955 
00956     // Format other messages.
00957     va_start( args, message );
00958     for ( ; ; ) {
00959         message = va_arg( args, kmp_msg_t );
00960         if ( message.type == kmp_mt_dummy && message.str == NULL ) {
00961             break;
00962         }; // if
00963         if ( message.type == kmp_mt_dummy && message.str == __kmp_msg_empty.str ) {
00964             continue;
00965         }; // if
00966         switch ( message.type ) {
00967             case kmp_mt_hint : {
00968                 format = kmp_i18n_fmt_Hint;
00969             } break;
00970             case kmp_mt_syserr : {
00971                 format = kmp_i18n_fmt_SysErr;
00972             } break;
00973             default : {
00974                 KMP_DEBUG_ASSERT( 0 );
00975             };
00976         }; // switch
00977         fmsg = __kmp_msg_format( format, message.num, message.str );
00978         KMP_INTERNAL_FREE( (void *) message.str );
00979         __kmp_str_buf_cat( & buffer, fmsg.str, fmsg.len );
00980         KMP_INTERNAL_FREE( (void *) fmsg.str );
00981     }; // forever
00982     va_end( args );
00983 
00984     // Print formatted messages.
00985     // This lock prevents multiple fatal errors on the same problem.
00986     // __kmp_acquire_bootstrap_lock( & lock );    // GEH - This lock causing tests to hang on OS X*.
00987     __kmp_printf( "%s", buffer.str );
00988     __kmp_str_buf_free( & buffer );
00989 
00990     if ( severity == kmp_ms_fatal ) {
00991         #if KMP_OS_WINDOWS
00992         __kmp_thread_sleep( 500 );   /* Delay to give message a chance to appear before reaping */
00993         #endif
00994         __kmp_abort_process();
00995     }; // if
00996 
00997     // __kmp_release_bootstrap_lock( & lock );  // GEH - this lock causing tests to hang on OS X*.
00998 
00999 } // __kmp_msg
01000 
01001 // -------------------------------------------------------------------------------------------------
01002 
01003 // end of file //

Generated on 25 Aug 2013 for libomp_oss by  doxygen 1.6.1