C Struct read/ write garbage value to file - c

I am diving into C after long time and struggling with reading and writing struct to the simple text file. I debuged this prog and I found out its reading and writing garbage value to the file. Can someone help me. Here is my code
#define MAX_UserName_LEN 16
#define MAX_Password_LEN 8
#define MAX_FileName_LEN 32
struct userDetails
{
char userName[MAX_UserName_LEN];
char password[MAX_Password_LEN];
};
int registration(struct userDetails userInfo)
{
FILE *userDb;
userDb= fopen("UserDataBase.txt","a");
if(fwrite(&userInfo,sizeof(userInfo),1,userDb))
{
fclose(userDb);
return 1;
}
else
{
return 0;
}
}
int authenicate(struct userDetails userInfo)
{
FILE *userDb;
struct userDetails temp;
userDb = fopen("UserDataBase.txt","r");
while(!feof(userDb))
{
fread(&temp,sizeof(temp),1,userDb);
if (temp.userName==userInfo.userName && temp.password==userInfo.password)
{
printf("Logged In Sucessfully");
return 1;
}
}
return 0;
}
In main function, I an just declaring one struct variable and accepting user input into that struct and passing it to both above mentioned functions.

The first major problem I see is here:
if (temp.userName==userInfo.userName && temp.password==userInfo.password)
You are trying to compare strings with ==. You need to use strcmp() instead:
if (strcmp(temp.userName, userInfo.userName) == 0 &&
strcmp(temp.password, userInfo.password) == 0)
I'm not sure if this has anything to do with the "garbage" you're getting, but it's definitely an error.
As your code stands right now, it will never enter the if-statement.

Write a short code, which prints the userlist, so you'll see wheter the file contains garbage or not.
Anyway, passwords should be scrambled somehow. Even a dumb solution is better than nothing, just to make it non-readable for human eyes. Say, for (n = 0; n < strlen(pwd); n++) pwd[n] ^= 0x55;.

Related

Reading structure tags from a header file?

So I wanted to configure different structures for which I have a header file such as:
header.h
typedef struct
{
uint32_t hola;
uint32_t adios;
}Signal_t;
typedef struct
{
bool goodbye;
uint32_t hello;
} FrameTx_t;
In order to do so, at some point, within my source code, I will need to detect which kind of structure is to be configured by the received text.
id. est: If I have a JSON file that goes somewhere along:
JSON_File.txt
{"Signal_t" :
{
"hola" : 1024,
"adios" : 555555
}
}
I need to recognize that the to-be-configured structure is of type Signal_t.
For now I have developed a simple code in which, after parsing the text, I can obtain the name of the structure in a string format, and then I created the following function to determine which structure is to be configured:
Code.c
int structure_Select(char* structName, int sizeOfStructName) {
char Signal_tName[] = "Signal_t";
char FrameTx_tName[] = "FrameTx_t";
int idx=0;
if ((sizeof(Signal_tName) - 1) == sizeOfStructName) {
for (idx = 0;idx < sizeOfStructName;idx++) {
if (Signal_tName[idx] != structName[idx]) {
break;
}
}
if (idx == sizeOfStructName) {
printf("%s", Signal_tName);
return 0;
}
}
if ((sizeof(FrameTx_tName) - 1) == sizeOfStructName) {
for (idx = 0;idx < sizeOfStructName;idx++) {
if (FrameTx_tName[idx] != structName[idx]) {
break;
}
}
if (idx == sizeOfStructName) {
printf("%s", FrameTx_tName);
return 1;
}
}
}
I can assure you it works; it just does not go as "automatic" as I would like it to be...
I would like for the program to be able to read the header file and automatically recognize: "Oh okay, so I'm dealing with a Signal_t data type, I'm gonna then read two different data from the stream and assign data1 to Signal_t.hola and data2 to Signal_t.adios"
The assignation is clearly not a problem; only determining from an existing structure within a file the name of it or a way to differentiate between structs.
So far I've thought about the following possibilities outside of what I already have, but I'm cycled within it:
o Create a mini "C-structure parser" function
o Is there ANY way to get the name of a structure tag within C that I don't know of?
I'm open to suggestions, whether it's just ideas that I could work on and I'm not seeing or if any of you has dealed with a similar issue in the past and instead of using a list of char variables, actually reads the header file for the structure names... thanks in advance!
.
.
.
TL;DR: Is there any way to read structures' tags from a header file as a string?
Edit: This is what I mean with structure tag/type alias:
//structure to get a rectangle
typedef struct {
int left;
int bottom;
int right;
int top;
} rect_t; //this rect_t is what I mean by structure tag...
//I checked the name and it should be type alias***

Strategy for cycling trough preexisting set of variables in c

I’m trying to program a HMI console to read a file from an USB pen drive and display its data on the screen. This is a csv file and the objective is to store the interpreted data to HMI console memory, which the HMI console later interprets. The macros on these consoles run in C (not C++).
I have no issue with both reading and interpreting the file, the issue that the existing function (not accessible to me, shown below) to write in the console memory only interprets char.
int WriteLocal( const char *type, int addr, int nRegs, void *buf , int flag );
Parameter: type is the string of "LW","LB" etc;
address is the Operation address ;
nRegs is the length of read or write ;
buf is the buffer which store the reading or writing data
flag is 0,then codetype is BIN,is 1 then codetype is BCD;
return value : 1 , Operation success
0 , Operation fail.
As my luck would have it I need to write integer values. What are available to me are the variables for each memory position. These are preexisting and are named individually such as:
int WR_LW200;
int WR_LW202;
int WR_LW204;
...
int WR_LW20n;
Ideally we could have a vector with all the names of the variables but unfortunately this is not possible. I could manually write every single variable but I need to do 300 of these…
must be a better way, right?
Just to give you a look on how it ended up looking:
int* arr[50][5] = { {&WR_LW200, &WR_LW400, &WR_LW600, &WR_LW800, &WR_LW1000},
{&WR_LW202, &WR_LW402, &WR_LW602, &WR_LW802, &WR_LW1002},
{&WR_LW204, &WR_LW404, &WR_LW604, &WR_LW804, &WR_LW1004},
{&WR_LW206, &WR_LW406, &WR_LW606, &WR_LW806, &WR_LW1006},
{&WR_LW208, &WR_LW408, &WR_LW608, &WR_LW808, &WR_LW1008},
{&WR_LW210, &WR_LW410, &WR_LW610, &WR_LW810, &WR_LW1010},
{&WR_LW212, &WR_LW412, &WR_LW612, &WR_LW812, &WR_LW1012},
{&WR_LW214, &WR_LW414, &WR_LW614, &WR_LW814, &WR_LW1014},
{&WR_LW216, &WR_LW416, &WR_LW616, &WR_LW816, &WR_LW1016},
{&WR_LW218, &WR_LW418, &WR_LW618, &WR_LW818, &WR_LW1018},
{&WR_LW220, &WR_LW420, &WR_LW620, &WR_LW820, &WR_LW1020},
{&WR_LW222, &WR_LW422, &WR_LW622, &WR_LW822, &WR_LW1022},
{&WR_LW224, &WR_LW424, &WR_LW624, &WR_LW824, &WR_LW1024},
{&WR_LW226, &WR_LW426, &WR_LW626, &WR_LW826, &WR_LW1026},
{&WR_LW228, &WR_LW428, &WR_LW628, &WR_LW828, &WR_LW1028},
{&WR_LW230, &WR_LW430, &WR_LW630, &WR_LW830, &WR_LW1030},
{&WR_LW232, &WR_LW432, &WR_LW632, &WR_LW832, &WR_LW1032},
{&WR_LW234, &WR_LW434, &WR_LW634, &WR_LW834, &WR_LW1034},
{&WR_LW236, &WR_LW436, &WR_LW636, &WR_LW836, &WR_LW1036},
{&WR_LW238, &WR_LW438, &WR_LW638, &WR_LW838, &WR_LW1038},
{&WR_LW240, &WR_LW440, &WR_LW640, &WR_LW840, &WR_LW1040},
{&WR_LW242, &WR_LW442, &WR_LW642, &WR_LW842, &WR_LW1042},
{&WR_LW244, &WR_LW444, &WR_LW644, &WR_LW844, &WR_LW1044},
{&WR_LW246, &WR_LW446, &WR_LW646, &WR_LW846, &WR_LW1046},
{&WR_LW248, &WR_LW448, &WR_LW648, &WR_LW848, &WR_LW1048},
{&WR_LW250, &WR_LW450, &WR_LW650, &WR_LW850, &WR_LW1050},
{&WR_LW252, &WR_LW452, &WR_LW652, &WR_LW852, &WR_LW1052},
{&WR_LW254, &WR_LW454, &WR_LW654, &WR_LW854, &WR_LW1054},
{&WR_LW256, &WR_LW456, &WR_LW656, &WR_LW856, &WR_LW1056},
{&WR_LW258, &WR_LW458, &WR_LW658, &WR_LW858, &WR_LW1058},
{&WR_LW260, &WR_LW460, &WR_LW660, &WR_LW860, &WR_LW1060},
{&WR_LW262, &WR_LW462, &WR_LW662, &WR_LW862, &WR_LW1062},
{&WR_LW264, &WR_LW464, &WR_LW664, &WR_LW864, &WR_LW1064},
{&WR_LW266, &WR_LW466, &WR_LW666, &WR_LW866, &WR_LW1066},
{&WR_LW268, &WR_LW468, &WR_LW668, &WR_LW868, &WR_LW1068},
{&WR_LW270, &WR_LW470, &WR_LW670, &WR_LW870, &WR_LW1070},
{&WR_LW272, &WR_LW472, &WR_LW672, &WR_LW872, &WR_LW1072},
{&WR_LW274, &WR_LW474, &WR_LW674, &WR_LW874, &WR_LW1074},
{&WR_LW276, &WR_LW476, &WR_LW676, &WR_LW876, &WR_LW1076},
{&WR_LW278, &WR_LW478, &WR_LW678, &WR_LW878, &WR_LW1078},
{&WR_LW280, &WR_LW480, &WR_LW680, &WR_LW880, &WR_LW1080},
{&WR_LW282, &WR_LW482, &WR_LW682, &WR_LW882, &WR_LW1082},
{&WR_LW284, &WR_LW484, &WR_LW684, &WR_LW884, &WR_LW1084},
{&WR_LW286, &WR_LW486, &WR_LW686, &WR_LW886, &WR_LW1086},
{&WR_LW288, &WR_LW488, &WR_LW688, &WR_LW888, &WR_LW1088},
{&WR_LW290, &WR_LW490, &WR_LW690, &WR_LW890, &WR_LW1090},
{&WR_LW292, &WR_LW492, &WR_LW692, &WR_LW892, &WR_LW1092},
{&WR_LW294, &WR_LW494, &WR_LW694, &WR_LW894, &WR_LW1094},
{&WR_LW296, &WR_LW496, &WR_LW696, &WR_LW896, &WR_LW1096},
{&WR_LW298, &WR_LW498, &WR_LW698, &WR_LW898, &WR_LW1098} };
Big right? I had consurns that this HMI would have issues with such an approach but it did the job. The code below runs trough a string that comes from the csv file. This code runs inside another while cycle to cycle trough the multi dimensional array.
it's a little crude but works.
while (i<=5)
{
memset(lineTemp, 0, sizeof lineTemp); // clear lineTemp array
while (lineFromFile[index] != delimiter)
{
if (lineFromFile[index] != delimiter && lineFromFile[index] != '\0') { lineTemp[j] = lineFromFile[index]; index++; j++; }
if (lineFromFile[index] == '\0') { i = 5; break; }
}
index++;
lineTemp[j] = '\0'; // NULL TERMINATION
j = 0;
if (i == -1) { WriteLocal("LW",temp,3,lineTemp,0); }
if (i >= 0 && i<=5) { *(arr[x][i]) = atoi(lineTemp); }
i++;
}
Thanks again for the tip.
Cheers

C - Linked List Segmentation Fault During Display

Edit 2: I realized that I did not have a "Not found" result for any query not in the database. Changes have been made to introduce this feature. Here is the current test and test output:
Input:
3
sam
99912222
tom
11122222
harry
12299933
sam
edward
harry
Output:
Not found
=0
Not found
=0
Not found
=0
Not found
=0
sam
=99912222
Not found
=0
Not found
=0
Not found
[Infinite loop continues]
Edit: I have changed a few things in the while loop in display(). I am now getting an infinite loop printing "=0" except for the third or fourth cycle through the search. Hmmm...
By the way, thanks for the reminder of testing strings with ==. Seems like a no-brainer now.
I have done some searching and have yet to be able to understand where I have gone wrong with my code. I am working on a challenge which will result in a simple phone-book program. It will take input of a number (the number of entries to be added) then the names and associated phone numbers (no dashes or periods). After the entries have been added then the user can search for entries by name and have the number displayed in the format "name=number".
The code throws a segmentation fault with the while loop in the display() function. I assume that I am attempting to print something assigned as NULL, but I cannot figure out where I have gone wrong. Any help would be very appreciated.
Lastly, the challenge calls for me to read queries until EOF; however, this confuses me since I am to accept user input from stdin. What does EOF look like with stdin, just a register return (\n)?
(PS: This is my first attempt at linked lists, so any pointers would be greatly appreciated.)
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
void add_entry(void);
void display(void);
struct phonebook {
char name[50];
int number;
struct phonebook *next;
};
struct phonebook *firstp, *currentp, *newp;
char tempname[50];
int main() {
int N;
firstp = NULL;
scanf("%d", &N);
for (int i = 0; i < N; i++) {
add_entry();
}
display();
return 0;
}
void add_entry(void) {
newp = (struct phonebook*)malloc(sizeof(struct phonebook));
if (firstp == NULL) firstp = currentp = newp;
else {
currentp = firstp;
while (currentp->next != NULL)
currentp = currentp->next;
currentp->next = newp;
currentp = newp;
}
fgets(currentp->name, 50, stdin);
scanf("%d", &currentp->number);
currentp->next = NULL;
}
void display(void) {
while (strcmp(tempname, "\n") != 0) {
currentp = firstp;
fgets(tempname, 50, stdin);
while (strcmp(currentp->name, tempname) != 0) {
if (currentp->next == NULL) {
printf("Not found\n");
break;
}
currentp = currentp->next;
}
printf("%s=%d\n", currentp->name, currentp->number);
}
}
Your problem is that you never find the entry you're looking for. The expression currentp->name != tempname will always be true, since those are always unequal. In C, this equality test will not compile into a character-by-character comparison, but into a comparison of pointers to currentp->name and tempname. Since those are never at the same addresses, they will never be equal.
Try !strcmp(currentp->name, tempname) instead.
The reason you crash, then, is because you reach the end of the list, so that currentp will be NULL after your loop, and then you try to print NULL->name and NULL->number, actually causing the crash.
Also, on another note, you may want to start using local variables instead of using global variables for everything.
Not sure if this solves the problem, but you can't directly compare strings with != in C. You need to use if( strcmp( string1, string2 ) == 0 ) to check.
fgets doesn't take EOF (= -1) like getchar does, but it does include '\n' and pad the rest with NULL (= 0) so checking for EOF is not really helpful, but yes you can stop after \n or NULL.

Segfault thrown on one line of code

I am using this library for libgps and having a few issues with it getting it to run properly.
The error from my debugger after it says segfault is:
Cannot find bounds of current function
The line of code throwing this is located in this file, on line 132.
uint8_t checksum= (uint8_t)strtol(strchr(message, '*')+1, NULL, 16);
I don't know the context of this at all, and I dont know why it would / wouldn't throw a segfault.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <gps.h>
#include <math.h>
/*
*
*/
int main(int argc, char** argv) {
// Open
gps_init();
gps_on();
loc_t data;
gps_location(&data);
printf("%lf %lf\n", data.latitude, data.longitude);
return (EXIT_SUCCESS);
}
The function gps_location() takes you into gps.c and from there it runs into serial.c, once it runs:
void serial_readln(char *buffer, int len)
{
char c;
char *b = buffer;
int rx_length = -1;
while(1) {
rx_length = read(uart0_filestream, (void*)(&c), 1);
if (rx_length <= 0) {
//wait for messages
sleep(1);
} else {
if (c == '\n') {
*b++ = '\0';
break;
}
*b++ = c;
}
}
}
On the break it returns to gps.c goes into:
switch (nmea_get_message_type(buffer)) {
which takes it into nmea.c for nmea_get_message_type above.
It then runs the line:
if ((checksum = nmea_valid_checksum(message)) != _EMPTY)
taking it down to: uint8_t checksum= (uint8_t)strtol(strchr(message, '*')+1, NULL, 16); which is where the error is.
What is causing this?
Edit:
uint8_t is defined as: typedef unsigned char uint8_t;
Segmentation fault is not a "thrown exception" per se, it is a hardware-issued problem ("you said go there, but I don't see anything named 'there'").
As for your problem: what happens when strchr() does not find the specified character? I suggest you try it and find out.
The code you are working with is horrible and has no error checking anywhere. So it may go haywire for any unexpected input. This could be a potential security vulnerability too.
To fix this particular instance, change the code to:
if ( !message )
return NMEA_CHECKSUM_ERR; // possibly `exit` or something, this shouldn't happen
char *star = strchr(message, '*');
if ( !star )
return NMEA_CHECKSUM_ERR;
uint8_t checksum = strtol(star, NULL, 16);
The nmea_parse_gpgga and nmea_parse_gprmc also have multiple instances of a similar problem.
These functions might be acceptable if there was a parser or a regexp check that sanitizes the input before calling these functions. However, based on your question (I didn't check the codebase), it seems data is passed directly from read which is inexcusable.
The segfaulting function was not designed to handle an empty message or in fact any message not matching the expected form.
Another disastrous blunder is that the serial_readln function never checks that it does not write beyond len.

bilingual program in console application in C

I have been trying to implement a way to make my program bilingual : the user could chose if the program should display French or English (in my case).
I have made lots of researches and googling but I still cannot find a good example on how to do that :/
I read about gettext, but since this is for a school's project we are not allowed to use external libraries (and I must admit I have nooo idea how to make it work even though I tried !)
Someone also suggested to me the use of arrays one for each language, I could definitely make this work but I find the solution super ugly.
Another way I thought of is to have to different files, with sentences on each line and I would be able to retrieve the right line for the right language when I need to. I think I could make this work but it also doesn't seem like the most elegant solution.
At last, a friend said I could use DLL for that. I have looked up into that and it indeed seems to be one of the best ways I could find... the problem is that most resources I could find on that matter were coded for C# and C++ and I still have no idea how I would do to implement in C :/
I can grasp the idea behind it, but have no idea how to handle it in C (at all ! I do not know how to create the DLL, call it, retrieve the right stuff from it or anything >_<)
Could someone point me to some useful resources that I could use, or write a piece of code to explain the way things work or should be done ?
It would be seriously awesome !
Thanks a lot in advance !
(Btw, I use visual studio 2012 and code in C) ^^
If you can't use a third party lib then write your own one! No need for a dll.
The basic idea is the have a file for each locale witch contains a mapping (key=value) for text resources.
The name of the file could be something like
resources_<locale>.txt
where <locale> could be something like en, fr, de etc.
When your program stars it reads first the resource file for specified locale.
Preferably you will have to store each key/value pair in a simple struct.
Your read function reads all key/value pair into a hash table witch offers a very good access speed. An alternative would be to sort the array containing the key/value pairs by key and then use binary search on lookup (not the best option, but far better than iterating over all entries each time).
Then you'll have to write a function get_text witch takes as argument the key of the text resource to be looked up an return the corresponding text in as read for the specified locale. You have to handle keys witch have no mapping, the simplest way would be to return key back.
Here is some sample code (using qsort and bsearch):
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define DEFAULT_LOCALE "en"
#define NULL_ARG "[NULL]"
typedef struct localized_text {
char* key;
char* value;
} localized_text_t;
localized_text_t* localized_text_resources = NULL;
int counter = 0;
char* get_text(char*);
void read_localized_text_resources(char*);
char* read_line(FILE*);
void free_localized_text_resources();
int compare_keys(const void*, const void*);
void print_localized_text_resources();
int main(int argc, char** argv)
{
argv++;
argc--;
char* locale = DEFAULT_LOCALE;
if(! *argv) {
printf("No locale provided, default to %s\n", locale);
} else {
locale = *argv;
printf("Locale provided is %s\n", locale);
}
read_localized_text_resources(locale);
printf("\n%s, %s!\n", get_text("HELLO"), get_text("WORLD"));
printf("\n%s\n", get_text("foo"));
free_localized_text_resources();
return 0;
}
char* get_text(char* key)
{
char* text = NULL_ARG;
if(key) {
text = key;
localized_text_t tmp;
tmp.key = key;
localized_text_t* result = bsearch(&tmp, localized_text_resources, counter, sizeof(localized_text_t), compare_keys);
if(result) {
text = result->value;
}
}
return text;
}
void read_localized_text_resources(char* locale)
{
if(locale) {
char localized_text_resources_file_name[64];
sprintf(localized_text_resources_file_name, "resources_%s.txt", locale);
printf("Read localized text resources from file %s\n", localized_text_resources_file_name);
FILE* localized_text_resources_file = fopen(localized_text_resources_file_name, "r");
if(! localized_text_resources_file) {
perror(localized_text_resources_file_name);
exit(1);
}
int size = 10;
localized_text_resources = malloc(size * sizeof(localized_text_t));
if(! localized_text_resources) {
perror("Unable to allocate memory for text resources");
}
char* line;
while((line = read_line(localized_text_resources_file))) {
if(strlen(line) > 0) {
if(counter == size) {
size += 10;
localized_text_resources = realloc(localized_text_resources, size * sizeof(localized_text_t));
}
localized_text_resources[counter].key = line;
while(*line != '=') {
line++;
}
*line = '\0';
line++;
localized_text_resources[counter].value = line;
counter++;
}
}
qsort(localized_text_resources, counter, sizeof(localized_text_t), compare_keys);
// print_localized_text_resources();
printf("%d text resource(s) found in file %s\n", counter, localized_text_resources_file_name);
}
}
char* read_line(FILE* p_file)
{
int len = 10, i = 0, c = 0;
char* line = NULL;
if(p_file) {
line = malloc(len * sizeof(char));
c = fgetc(p_file);
while(c != EOF) {
if(i == len) {
len += 10;
line = realloc(line, len * sizeof(char));
}
line[i++] = c;
c = fgetc(p_file);
if(c == '\n' || c == '\r') {
break;
}
}
line[i] = '\0';
while(c == '\n' || c == '\r') {
c = fgetc(p_file);
}
if(c != EOF) {
ungetc(c, p_file);
}
if(strlen(line) == 0 && c == EOF) {
free(line);
line = NULL;
}
}
return line;
}
void free_localized_text_resources()
{
if(localized_text_resources) {
while(counter--) {
free(localized_text_resources[counter].key);
}
free(localized_text_resources);
}
}
int compare_keys(const void* e1, const void* e2)
{
return strcmp(((localized_text_t*) e1)->key, ((localized_text_t*) e2)->key);
}
void print_localized_text_resources()
{
int i = 0;
for(; i < counter; i++) {
printf("Key=%s value=%s\n", localized_text_resources[i].key, localized_text_resources[i].value);
}
}
Used with the following resource files
resources_en.txt
WORLD=World
HELLO=Hello
resources_de.txt
HELLO=Hallo
WORLD=Welt
resources_fr.txt
HELLO=Hello
WORLD=Monde
run
(1) out.exe /* default */
(2) out.exe en
(3) out.exe de
(4) out.exe fr
output
(1) Hello, World!
(2) Hello, World!
(3) Hallo, Welt!
(4) Hello, Monde!
gettext is the obvious answer but it seems it's not possible in your case. Hmmm. If you really, really need a custom solution... throwing out a wild idea here...
1: Create a custom multilingual string type. The upside is that you can easily add new languages afterwards, if you want. The downside you'll see in #4.
//Terrible name, change it
typedef struct
{
char *french;
char *english;
} MyString;
2: Define your strings as needed.
MyString s;
s.french = "Bonjour!";
s.english = "Hello!";
3: Utility enum and function
enum
{
ENGLISH,
FRENCH
};
char* getLanguageString(MyString *myStr, int language)
{
switch(language)
{
case ENGLISH:
return myStr->english;
break;
case FRENCH:
return myStr->french;
break;
default:
//How you handle other values is up to you. You could decide on a default, for instance
//TODO
}
}
4: Create wrapper functions instead of using plain old C standard functions. For instance, instead of printf :
//Function should use the variable arguments and allow a custom format, too
int myPrintf(const char *format, MyString *myStr, int language, ...)
{
return printf(format, getLanguageString(myStr, language));
}
That part is the painful one : you'll need to override every function you use strings with to handle custom strings. You could also specify a global, default language variable to use when one isn't specified.
Again : gettext is much, much better. Implement this only if you really need to.
the main idea of making programs translatable is using in all places you use texts any kind of id. Then before displaying the test you get the text using the id form the appropriate language-table.
Example:
instead of writing
printf("%s","Hello world");
You write
printf("%s",myGetText(HELLO_WORLD));
Often instead of id the native-language string itself is used. e.g.:
printf("%s",myGetText("Hello world"));
Finally, the myGetText function is usually implemented as a Macro, e.g.:
printf("%s", tr("Hello world"));
This macro could be used by an external parser (like in gettext) for identifying texts to be translated in source code and store them as list in a file.
The myGetText could be implemented as follows:
std::map<std::string, std::map<std::string, std::string> > LangTextTab;
std::string GlobalVarLang="en"; //change to de for obtaining texts in German
void readLanguagesFromFile()
{
LangTextTab["de"]["Hello"]="Hallo";
LangTextTab["de"]["Bye"]="Auf Wiedersehen";
LangTextTab["en"]["Hello"]="Hello";
LangTextTab["en"]["Bye"]="Bye";
}
const char * myGetText( const char* origText )
{
return LangTextTab[GlobalVarLang][origText ].c_str();
}
Please consider the code as pseudo-code. I haven't compiled it. Many issues are still to mention: unicode, thread-safety, etc...
I hope however the example will give you the idea how to start.

Resources