Strategy for cycling trough preexisting set of variables in c - 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

Related

C Program to count keywords from a keyword text file in a fake resume and display the result

#EDIT: I think the problem is that I put my 2 text files on desktop. Then, I move them to the same place as the source file and it works. But the program cannot run this time, the line:
cok = 0;
shows "exception thrown".
// end EDIT
I have the assignment at school to write a C program to create 2 text files. 1 file stores 25 keywords, and 1 file stores the fake resume. The problem is, my program cannot read my keywords.txt file. Anyone can help me? Thank you so much.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//*****************************************************
// MAIN FUNCTION
int main()
{
//File pointer for resume.txt file declared
FILE *fpR;
//File pointer for keywords.txt file declared and open it in read mode
FILE* fpK = fopen("keywords.txt", "r");
//To store character extracted from keyword.txt file
char cK;
//To store character extracted from resume.txt file
char cR;
//To store word extracted from keyword.txt file
char wordK[50];
//To store word extracted from resume.txt file
char wordR[50];
//To store the keywords
char keywords[10][50];
//To store the keywords counter and initializes it to zero
int keywordsCount[10] = { 0, 0, 0, 0 };
int coK, coR, r, r1;
coK = coR = r = r1 = 0;
//Checks if file is unable to open then display error message
if (fpK == NULL)
{
printf("Could not open files");
exit(0);
}//End of if
//Extracts a character from keyword.txt file and stores it in cK variable and Loops till end of file
while ((cK = fgetc(fpK)) != EOF)
{
//Checks if the character is comma
if (cK != ',')
{
//Store the character in wordK coK index position
wordK[coK] = cK;
//Increase the counter coK by one
coK++;
}//End of if
//If it is comma
else
{
//Stores null character
wordK[coK] = '\0';
//Copies the wordK to the keywords r index position and increase the counter r by one
strcpy(keywords[r++], wordK);
//Re initializes the counter to zero for next word
coK = 0;
fpR = fopen("resume.txt", "r");
//Extracts a character from resume.txt file and stores it in cR variable and Loops till end of file
while ((cR = fgetc(fpR)) != EOF)
{
//Checks if the character is space
if (cR != ' ')
{
//Store the character in wordR coR index position
wordR[coR] = cR;
//Increase the counter coR by one
coR++;
}//End of if
else
{
//Stores null character
wordR[coR] = '\0';
//Re initializes the counter to zero for next word
coR = 0;
//Compares word generated from keyword.txt file and word generated from resume.txt file
if (strcmp(wordK, wordR) == 0)
{
//If both the words are same then increase the keywordCounter arrays r1 index position value by one
keywordsCount[r1] += 1;
}//End of if
}//End of else
}//End of inner while loop
//Increase the counter by one
r1++;
//Close the file for resume
fclose(fpR);
}//End of else
}//End of outer while loop
//Close the file for keyword
fclose(fpK);
//Display the result
printf("\n Result \n");
for (r = 0; r < r1; r++)
printf("\n Keyword: %s %d time available", keywords[r], keywordsCount[r]);
}//End of main
I think the problem is the text files, aren't they?
The name of my 1st test file is "keywords.txt", and its content is:
Java, CSS, HTML, XHTML, MySQL, College, University, Design, Development, Security, Skills, Tools, C, Programming, Linux, Scripting, Network, Windows, NT
The name of my 2nd test file is "resume.txt", and its content is:
Junior Web developer able to build a Web presence from the ground up -- from concept, navigation, layout, and programming to UX and SEO. Skilled at writing well-designed, testable, and efficient code using current best practices in Web development. Fast learner, hard worker, and team player who is proficient in an array of scripting languages and multimedia Web tools. (Something like this).
I don't see any problem with these 2 files. But my program still cannot open the file and the output keeps showing "Could not open files".
while ((cK = fgetc(fpK)) != EOF)
If you check the documentation, you can see that fgets returns an int. But since cK is a char, you force a conversion to char, which can change its value. You then compare the possibly changed value to EOF, which is not correct. You need to compare the value that fgets returns to EOF since fgetc returns an EOF on end of file.

Inserting word from a text file into a tree in C

I have been encountering a weird problem for the past 2 days and I can't get to solve it yet. I am trying to get words from 2 texts files and add those words to a tree. The methods I choose to get the words are refereed here:
Splitting a text file into words in C.
The function that I use to insert words into a tree is the following:
void InsertWord(typosWords Words, char * w)
{
int error ;
DataType x ;
x.word = w ;
printf(" Trying to insert word : %s \n",x.word );
Tree_Insert(&(Words->WordsRoot),x, &error) ;
if (error)
{
printf("Error Occured \n");
}
}
As mentioned in the link posted , when I am trying to import the words from a text file into the tree , I am getting "Error Occured". For once again the function:
the text file :
a
aaah
aaahh
char this_word[15];
while (fscanf(wordlist, "%14s", this_word) == 1)
{
printf("Latest word that was read: '%s'\n", this_word);
InsertWord(W,this_word);
}
But when I am inserting the exact same words with the following way , it works just fine.
for (i = 0 ; i <=2 ; i++)
{
if (i==0)
InsertWord(W,"a");
if (i==1)
InsertWord(W,"aaah");
if (i==2)
InsertWord(W,"aaahh");
}
That proves the tree's functions works fine , but I can't understand what's happening then.I am debugging for straight 2 days and still can't figure it. Any ideas ?
When you read the words using
char this_word[15];
while (fscanf(wordlist, "%14s", this_word) == 1)
{
printf("Latest word that was read: '%s'\n", this_word);
InsertWord(W,this_word);
}
you are always reusing the same memory buffer for the strings. This means when you do
x.word = w ;
you are ALWAYS storing the SAME address. And every read redefine ALL already stored words, basically corrupting the data structure.
Try changing the char this_word[15]; to char *this_word; and placing a this_word = malloc(15);in the beggining of thewhile` loop instead, making it allocate a new buffer for each iteration. So looking like
char *this_word;
while (fscanf(wordlist, "%14s", this_word) == 1)
{
this_word = malloc(15);
printf("Latest word that was read: '%s'\n", this_word);
InsertWord(W,this_word);
}
As suggested by Michael Walz a strdup(3) also solves the immediate problem.
Of course you will also have do free up the .word elements when finished with the tree.
Seems like the problem was in the assignment of the strings.Strdup seemed to solve the problem !

fgetc not starting at beginning of file - c [duplicate]

This question already has an answer here:
fgetc not starting at beginning of large txt file
(1 answer)
Closed 9 years ago.
Problem solved here:
fgetc not starting at beginning of large txt file
I am working in c and fgetc isn't getting chars from the beginning of the file. It seems to be starting somewhere randomly within the file after a \n. The goal of this function is to modify the array productsPrinted. If "More Data Needed" or "Hidden non listed" is encountered, the position in the array, productsPrinted[newLineCount], will be changed to 0. Any help is appreciated.
Update: It works on smaller files, but doesn't start at the beginning of the larger,617kb, file.
function calls up to category:
findNoPics(image, productsPrinted);
findVisible(visible, productsPrinted);
removeCategories(category, productsPrinted);
example input from fgetc():
Category\n
Diagnostic & Testing /Scan Tools\n
Diagnostic & Testing /Scan Tools\n
Hidden non listed\n
Diagnostic & Testing /Scan Tools\n
Diagnostic & Testing /Scan Tools\n
Hand Tools/Open Stock\n
Hand Tools/Sockets and Drive Sets\n
More Data Needed\n
Hand Tools/Open Stock\n
Hand Tools/Open Stock\n
Hand Tools/Open Stock\n
Shop Supplies & Equip/Tool Storage\n
Hidden non listed\n
Shop Supplies & Equip/Heaters\n
Code:
void removeCategories(FILE *category, int *prodPrinted){
char more[17] = { '\0' }, hidden[18] = { '\0' };
int newLineCount = 0, i, ch = 'a', fix = 0;
while ((ch = fgetc(category)) != EOF){ //if fgetc is outside while, it works//
more[15] = hidden[16] = ch;
printf("%c", ch);
/*shift char in each list <- one*/
for (i = 0; i < 17; i++){
if (i < 17){
hidden[i] = hidden[i + 1];
}
if (i < 16){
more[i] = more[i + 1];
}
}
if (strcmp(more, "More Data Needed") == 0 || strcmp(hidden, "Hidden non listed") == 0){
prodPrinted[newLineCount] = 0;
/*printf("%c", more[0]);*/
}
if (ch == '\n'){
newLineCount++;
}
}
}
Let computers do the counting. You have not null terminated your strings properly. The fixed strings (mdn and hdl are initialized but do not have null terminators, so string comparisons using them are undefined.
Given this sample data:
Example 1
More Data Needed
Hidden non listed
Example 2
Keeping lines short.
But as they get longer, the overwrite is worse...or is it?
Hidden More Data Needed in a longer line.
Lines containing "Hidden non listed" are zapped.
Example 3
This version of the program:
#include <stdio.h>
#include <string.h>
static
void removeCategories(FILE *category, int *prodPrinted)
{
char more[17] = { '0' };
char hidden[18] = { '0' };
char mdn[17] = { "More Data Needed" };
char hnl[18] = { "Hidden non listed" };
int newLineCount = 0, i, ch = '\0';
do
{
/*shift char in each list <- one*/
for (i = 0; i < 18; i++)
{
if (i < 17)
hidden[i] = hidden[i + 1];
if (i < 16)
more[i] = more[i + 1];
}
more[15] = hidden[16] = ch = fgetc(category);
if (ch == EOF)
break;
printf("%c", ch); /*testing here, starts rndmly in file*/
//printf("<<%c>> ", ch); /*testing here, starts rndmly in file*/
//printf("more <<%s>> hidden <<%s>>\n", more, hidden);
if (strcmp(more, mdn) == 0 || strcmp(hidden, hnl) == 0)
{
prodPrinted[newLineCount] = 0;
}
if (ch == '\n')
{
newLineCount++;
}
} while (ch != EOF);
}
int main(void)
{
int prod[10];
for (int i = 0; i < 10; i++)
prod[i] = 37;
removeCategories(stdin, prod);
for (int i = 0; i < 10; i++)
printf("%d: %d\n", i, prod[i]);
return 0;
}
produces this output:
Example 1
More Data Needed
Hidden non listed
Example 2
Keeping lines short.
But as they get longer, the overwrite is worse...or is it?
Hidden More Data Needed in a longer line.
Lines containing "Hidden non listed" are zapped.
Example 3
0: 37
1: 0
2: 0
3: 37
4: 37
5: 37
6: 0
7: 0
8: 37
9: 37
You may check which mode you opened the file, and you may have some error-check to make sure you have got the right return value.
Here you can refer to man fopen to get which mode to cause the stream position.
The fopen() function opens the file whose name is the string pointed to
by path and associates a stream with it.
The argument mode points to a string beginning with one of the follow‐
ing sequences (Additional characters may follow these sequences.):
r Open text file for reading. The stream is positioned at the
beginning of the file.
r+ Open for reading and writing. The stream is positioned at the
beginning of the file.
w Truncate file to zero length or create text file for writing.
The stream is positioned at the beginning of the file.
w+ Open for reading and writing. The file is created if it does
not exist, otherwise it is truncated. The stream is positioned
at the beginning of the file.
a Open for appending (writing at end of file). The file is cre‐
ated if it does not exist. The stream is positioned at the end
of the file.
a+ Open for reading and appending (writing at end of file). The
file is created if it does not exist. The initial file position
for reading is at the beginning of the file, but output is
always appended to the end of the file.
And there is another notice, that the file you operated should not more than 2G, or there maybe problem.
And you can use fseek to set the file position indicator.
And you can use debugger to watch these variables to see why there are random value. I think debug is efficient than trace output.
Maybe you can try rewinding the file pointer at the beginning of your function.
rewind(category);
Most likely another function is reading from the same file. If this solves your problem, it would be better to find which other function (or previous call to this function) is reading from the same file and make sure rewinding the pointer won't break something else.
EDIT:
And just to be sure, maybe you could change the double assignment to two different statements. Based on this post, your problem might as well be caused by a compiler optimization of that line. I haven't checked with the standard, but according to best answer the behavior in c and c++ might be undefined, therefore your strange results. Good luck

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.

Splitting a comma-delimited string of integers

My background is not in C (it's in Real Studio - similar to VB) and I'm really struggling to split a comma-delimited string since I'm not used to low-level string handling.
I'm sending strings to an Arduino over serial. These strings are commands in a certain format. For instance:
#20,2000,5!
#10,423,0!
'#' is the header indicating a new command and '!' is the terminating footer marking the end of a command. The first integer after '#' is the command id and the remaining integers are data (the number of integers passed as data may be anywhere from 0 - 10 integers).
I've written a sketch that gets the command (stripped of the '#' and '!') and calls a function called handleCommand() when there is a command to handle. The problem is, I really don't know how to split this command up to handle it!
Here's the sketch code:
String command; // a string to hold the incoming command
boolean commandReceived = false; // whether the command has been received in full
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// main loop
handleCommand();
}
void serialEvent(){
while (Serial.available()) {
// all we do is construct the incoming command to be handled in the main loop
// get the incoming byte from the serial stream
char incomingByte = (char)Serial.read();
if (incomingByte == '!')
{
// marks the end of a command
commandReceived = true;
return;
}
else if (incomingByte == '#')
{
// marks the start of a new command
command = "";
commandReceived = false;
return;
}
else
{
command += incomingByte;
return;
}
}
}
void handleCommand() {
if (!commandReceived) return; // no command to handle
// variables to hold the command id and the command data
int id;
int data[9];
// NOT SURE WHAT TO DO HERE!!
// flag that we've handled the command
commandReceived = false;
}
Say my PC sends the Arduino the string "#20,2000,5!". My sketch ends up with a String variable (called command) that contains "20,2000,5" and the commandRecieved boolean variable is set to True so the handleCommand() function is called.
What I would like to do in the (currently useless) handleCommand() function is assign 20 to a variable called id and 2000 and 5 to an array of integers called data, i.e: data[0] = 2000, data[1] = 5, etc.
I've read about strtok() and atoi() but frankly I just can't get my head around them and the concept of pointers. I'm sure my Arduino sketch could be optimised too.
Since you're using the Arduino core String type, strtok and other string.h functions aren't appropriate. Note that you can change your code to use standard C null-terminated strings instead, but using Arduino String will let you do this without using pointers.
The String type gives you indexOf and substring.
Assuming a String with the # and ! stripped off, finding your command and arguments would look something like this:
// given: String command
int data[MAX_ARGS];
int numArgs = 0;
int beginIdx = 0;
int idx = command.indexOf(",");
String arg;
char charBuffer[16];
while (idx != -1)
{
arg = command.substring(beginIdx, idx);
arg.toCharArray(charBuffer, 16);
// add error handling for atoi:
data[numArgs++] = atoi(charBuffer);
beginIdx = idx + 1;
idx = command.indexOf(",", beginIdx);
}
data[numArgs++] = command.substring(beginIdx);
This will give you your entire command in the data array, including the command number at data[0], while you've specified that only the args should be in data. But the necessary changes are minor.
seems to work, could be buggy:
#include<stdio.h>
#include <string.h>
int main(){
char string[]="20,2000,5";
int a,b,c;
sscanf(string,"%i,%i,%i",&a,&b,&c);
printf("%i %i %i\n",a,b,c);
a=b=c=0;
a=atoi(strtok(string,","));
b=atoi(strtok(0,","));
c=atoi(strtok(0,","));
printf("%i %i %i\n",a,b,c);
return 0;
}

Resources