Formatting Sqlite table to string (char) in C? - c

I'm really new to Sqlite and I want to write a text file (xml actually) from an sqlite database table automatically using C. How can I do that? I got these to select some data from database and print in terminal:
int callback(void * ptr, int resultados, char ** STR1, char **STR2) {
int i;
for(i = 0; STR1[i] != NULL; i++) {
printf("%s = %s\n", STR2[i], STR1[i]);
}
return 0;
}
and inside of main:
/* Open database */
rc = sqlite3_open("test.db", &db);
if( rc ){
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
exit(0);
}else{
fprintf(stderr, "Opened database successfully\n");
}
/* Create SQL statement */
sql = "SELECT * from COMPANY";
/* Execute SQL statement */
rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
if( rc != SQLITE_OK ){
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}else{
fprintf(stdout, "Operation done successfully\n");
}
sqlite3_close(db);
and then I tried to change the callback, to get STR1 and STR2 to write a text file, something like this:
int callback(void * ptr, int resultados, char ** STR1, char **STR2) {
int i;
char teste[1024];
FILE *pFile;
pFile = fopen ("test.txt", "a+");
for(i = 0; STR1[i] != NULL; i++) {
printf("%s = %s\n", STR2[i], STR1[i]);
snprintf (teste, sizeof(teste), "%s %s\n", STR2[i], STR1[i]);
fwrite (teste, 1, sizeof(teste), pFile);
fflush(pFile);
}
return 0;
}
but when I try to open the test.txt, gedit says 'There was a problem opening the file /home/kdan/test/test.txt. The file you opened has some invalid characters', and the text contains a bunch of random characters, numbers and symbols. So I'm not being able to get the selected data and convert to string D: should I try to use something like sqlite_mprintf, sqlite_vmprintf, sqlite_exec_printf or sqlite_get_table_printf? Would it be right? Or is there another way to select the data and format it to a variable char? Sorry for my rusty english.
Edited: It is working now, just needed to use fputs instead of fwrite, here is the code working:
int callback(void * ptr, int resultados, char ** STR1, char **STR2) {
int i;
char teste[1024];
FILE *pFile;
pFile = fopen ("test.txt", "a");
for(i = 0; STR1[i] != NULL; i++) {
printf("%s = %s\n", STR2[i], STR1[i]);
snprintf (teste, sizeof(teste), "%s %s\n", STR2[i], STR1[i]);
fputs (teste, pFile);
fflush(pFile);
}
return 0;
}

Haven't tested your code but I think the problem is with the fwrite() call.
From the linux manpages:
NAME
fread, fwrite - binary stream input/output
SYNOPSIS
[...]
size_t fwrite(const void *ptr, size_t size, size_t nmemb,
FILE *stream);
DESCRIPTION
[...]
The function fwrite() writes nmemb elements of data, each size bytes
long, to the stream pointed to by stream, obtaining them from the loca‐
tion given by ptr.
STR2[i] and STR1[i] may have a total length less than sizeof teste. For illustrative purpose, let's say STR2[i] is "foo" and STR1[i] is "bar". After the snprintf() call, teste will have the following contents:
teste[0] 'f'
teste[1] 'o'
teste[2] 'o'
teste[3] ' '
teste[4] 'b'
teste[5] 'a'
teste[6] 'r'
teste[7] '\n'
teste[8] '\0'
teste[9] onwards uninitialised
Since fwrite is for writing to a binary stream, it will NOT stop writing after reaching the '\0' byte. Instead it will keep writing all the uninitialised characters in teste. In this case it will write 1015 uninitialised characters.
The proper way to write to a text stream is to use either fputs() (in which case you should remove the '\n' in your string) or fprintf(). Or, if you really want to use fwrite(), ask it to print strlen(teste) bytes (which will be 8 in this case) instead of sizeof teste which is 1024.
Finally, although not related to your problem, if you are not reading from the file you should fopen() it with "a" instead of "a+".

Related

How to read from a file and parse it

I have a file .txt containing some values formatted like this:
0,30,25,10
Now, I open up the file and store it into an array
char imposta_tratt[300];
FILE *fp;
fp = fopen("/home/pi/Documents/imposta_trattamento.txt", "r");
if (fp == 0) return;
fread(imposta_tratt, sizeof(imposta_tratt), 1, fp);
fclose(fp);
Now I expect to have the array filled with my data. I have the values separated by a , so I go on and parse it:
const char delim[2] = ",";
int t=0;
char *token = strtok(imposta_tratt, delim);
while (token!=NULL){
strcpy(tratt[t],token);
token = strtok(NULL, delim);
tratt[t]=token;
t++;
}
Here, referring to what's in the file .txt, I expect to have tratt[0]=0; tratt[1]=30; tratt[2]=25; and so on, but seems like I am missing something since it's not like this.
All I want is to have the values of the txt file stored in single variables. Can someone help?
What you are trying to achieve can simply be done using fgets():
bool read_file_content(const char *filename, const size_t tsizemax, int tratt[tsizemax], size_t *tsize, const char *delim)
{
// Attempt to open filename.
FILE *fp = fopen(filename, "r");
if (!fp) return false; // Return false upon failure.
// Try to read one line. If you have more, you need a while loop.
char imposta_tratt[300];
if (!fgets(imposta_tratt, sizeof imposta_tratt, fp)) {
fclose(fp);
return false;
}
*tsize = 0;
char tmp[300]; // Temporary buffer. Used for conversion into int.
char *token = strtok(imposta_tratt, delim);
while (token && *tsize < tsizemax) {
strncpy(tmp, token, sizeof tmp);
tratt[(*tsize)++] = atoi(tmp);
token = strtok(NULL, delim);
}
fclose(fp);
return true;
}
const char *filename: The file you want to parse.
const size_t tsizemax: The maximum size of your tratt array. It is important to control the size, otherwise your code will have buffer overflow (think of when your file has more than 100 tokens, for example).
int tratt[tsizemax]: The array that will hold the values.
size_t *tsize: The number of tokens read (used in combination of tsizemax).
const char *delim: The delimiter(s), in your case a ,.
This is your main():
int main(void)
{
int tratt[100];
size_t size = 0;
if (!read_file_content("in.txt", 100, tratt, &size, ",")) {
puts("Failed");
return 1;
}
for (size_t i = 0; i < size; ++i)
printf("%d\n", tratt[i]);
}
Output:
0
30
25
10
Suppose "in.txt" has contents
0,30,25,10
The below program uses fscanf to read the integers into the tratt array, one-by-one. As we read integers using fscanf, we make sure it's return value is as expected. If not, we close the file and exit. In the event that the return value of fscanf is not as expected, the program also prints which type of error occurred. Currently, if any error occurs, the program stops. However, you can make the program behave differently depending on the error that occurred if you like.
As output, the program prints all of the integers read into the tratt array. The output is
0
30
25
10
Now this program assumes we know the number of elements we want to read into tratt. If we do not, we could allow for dynamically allocating more memory should the array need more elements or perhaps "in.txt" could contain a data structure, say, at the beginning/end of the file that records information about the file, such as the number of numbers in the file and the data type (a binary file would be best suited for this). These are just a couple of the possibilities.
A better approach might be to read characters in one-by-one (say, using getc) and use strtol to convert a sequence of character digits to a long int (I would have taken an approach similar to this).
Nevertheless, this approach is more succinct and should suffice.
#include <stdio.h>
#include <stdlib.h>
#define FILE_NAME "in.txt"
#define MAX_LEN 4
int main(void) {
int i, tratt[MAX_LEN];
FILE *fp = fopen(FILE_NAME, "r"); /* open file for reading */
/* if cannot open file */
if (fp == NULL) {
printf("Cannot open %s\n", FILE_NAME);
exit(EXIT_FAILURE);
}
/* read integer, checking return value of scanf as expected */
if (fscanf(fp, "%d", &tratt[0]) != 1) {
if (ferror(fp))
printf("fscanf: read error\n");
else if (feof(fp))
printf("fscanf: end of file\n");
else
printf("fscanf: matching failure\n");
fclose(fp);
exit(EXIT_FAILURE);
}
for (i = 1; i < MAX_LEN; i++)
/* read comma plus integer, checking return value of scanf */
if (fscanf(fp, ",%d", &tratt[i]) != 1) {
if (ferror(fp))
printf("fscanf: read error\n");
else if (feof(fp))
printf("fscanf: end of file\n");
else
printf("fscanf: matching failure\n");
fclose(fp);
exit(EXIT_FAILURE);
}
fclose(fp); /* close file */
/* print integers stored in tratt */
for (i = 0; i < MAX_LEN; i++)
printf("%d\n", tratt[i]);
return 0;
}

How can I get my C program to read more than one line of text from a file?

I am trying to write a program that reads lines of texts from an input file, rearrange the letters in the words and then writes them to an output file. So far I have this:
void processFile(FILE* ifp, FILE* ofp) {
char line[1024];
char word[1024];
char* lineptr = line;
char temp;
printf("Begin file processing\n");
while (fgets(line, BIGLINE, ifp) != NULL){
while(sscanf(lineptr,"%s",word) == true)
{
if (strlen(word) >= 4){
temp = word[1];
word[1] = word[2];
word[2] = temp;
}
fputs(word,stdout);
fputs(word,ofp);
fputs(" ",stdout);
fputs(" ", ofp);
lineptr += strlen(word) + 1;
}
}/*while*/
printf("End file processing\n");} /* processFile */
Right now the output file reads:
<rpe><div calss="text_to_html">Project Gtuenberg The Avdentures of Sehrlock Hlomes, by Atrhur Cnoan Dyole
But I need it to read all of the lines in my test file
<pre><div class="text_to_html">Project Gutenberg The Adventures of Sherlock Holmes, by Arthur Conan Doyle
This eBook is for the use of anyone anywhere at no cost and with
almost no restrictions whatsoever. You may copy it, give it away or
re-use it under the terms of the Project Gutenberg License included
with this eBook or online at <a href="http://www.gutenberg.net"
class="_blanktarget">www.gutenberg.net</a>
</div></pre>
I also need to make sure that if I put any text file as the input file it would read all of the lines instead of just the first. How can I do this with what I have already?
As I noted in a comment, your primary problem is that you need to reset lineptr inside the while (fgets(…) != NULL) loop before starting the inner loop. You'd be less likely to run into this problem if you placed all variables so they had the minimum possible scope — so temp should be defined inside the if block, while word and lineptr should be defined between the outer and inner loops. You're marginally unlucky that the first line you're processing is the longest line; it means that lineptr is left pointing at a null byte.
You should use sizeof(line) rather than BIGLINE in the call to fgets(). The use of true where the count is 1 is not appropriate either (though not technically incorrect).
Those changes yield:
#include <stdio.h>
#include <string.h>
static void processFile(FILE *ifp, FILE *ofp)
{
char line[1024];
printf("Begin file processing\n");
while (fgets(line, sizeof(line), ifp) != NULL)
{
char word[1024];
char *lineptr = line;
while (sscanf(lineptr, "%s", word) == 1)
{
if (strlen(word) >= 4)
{
char temp = word[1];
word[1] = word[2];
word[2] = temp;
}
fputs(word, stdout);
fputs(word, ofp);
fputs(" ", stdout);
fputs(" ", ofp);
lineptr += strlen(word) + 1;
}
putchar('\n');
}
printf("End file processing\n");
}
int main(void)
{
processFile(stdin, stderr);
return 0;
}
When compiled from rf79.c into rf79 and run with standard error redirected to /dev/null, I get the output:
$ ./rf79 < data 2>/dev/null
Begin file processing
<rpe><div calss="text_to_html">Project Gtuenberg The Avdentures of Sehrlock Hlomes, by Atrhur Cnoan Dyole
Tihs eoBok is for the use of aynone aynwhere at no csot and wtih
amlost no rsetrictions wahtsoever. You u may cpoy it, gvie it aawy or
r-euse it udner the trems of the Porject Gtuenberg Lciense icnluded
wtih tihs eoBok or olnine at <a herf="http://www.gutenberg.net"
calss="_blanktarget">www.gutenberg.net</a>
<d/iv></pre>
End file processing
$
This looks like what you want.

Reading a text file line by line and saving to an array (C Language)

Here's my issue:
I'm currently working on a project for university. We're suppose to do a program that receives .pbm and .pgm files as input, and then we're suppose to handle them in some ways. But for now the main thing is to successfully receive them.
Each .pbm and .pgm file's first line is a "magic number". A set of characters like P1, P2 (...) P6.
Our goal is to receive a .pbm file as input, save the first line, dynamically allocate a string so it is just as big as its content (P6\n, for example), so we can then detect the magic number. The same applies to every other line. We basically just want a way to save each line into an array, making them just as big as their content.
Me and my project partner are both beginners: file handling, pointers, dynamic memory and headers are still pretty hard to us. Thank you in advance.
---EDIT--- (Forgot the code, as an user pointed out)
int main(int argc, char const *argv[])
{
readFile(argv[1], "EI_2012-13_ascii.pbm");
return 0;
}
void readFile (const char* input_file, char* filename){
char *line_buffer, *line;
FILE *file_stream = NULL;
if(!check_extension(filename, ".pbm") &&
!check_extension(filename, ".pgm") && !check_extension(filename, ".ppm"))
ERROR(ERR_EXT, "Invalid file extension!\n");
file_stream = fopen(input_file, "r");
if (file_stream == NULL)
ERROR(ERR_EXT, "Couldn't open the file for reading");
line_buffer = malloc(sizeof(2));
fscanf(file_stream, "%s", line_buffer);
//line = strchr(line_buffer, '\n');
printf("%s\n", line_buffer);
printf("%d\n", sizeof(line_buffer));
fclose(file_stream);
}
With this code we were attempting to output a string and its size underneath it. Strangely we keep getting the same output: 4. We needed that the malloc received a proper argument, the size of the line until the '\n'.
You can detect the magic number reading the file line by line using Linux function getline() as shown below,
void readFile (const char* input_file, char* filename){
char *line;
FILE *file_stream = NULL;
ssize_t read; size_t len = 0;
file_stream = fopen(input_file, "r");
if (file_stream == NULL)
ERROR(ERR_EXT, "Couldn't open the file for reading");
while((read = getline(&line, &len, file_stream)) != 1){
printf("%s", line);
printf("length of line: %zu\n", read);
}
if (line)
free(line);
fclose(file_stream);
}

How do I make a token parser in C?

I have seen "config" files(yes, text files) for various console applications that look like the following
<token> <value>
How would I go about parsing such a thing in C, where < value > could be a string, a letter or even an integer/float/double?
I read this question " How do I parse a token from a string in C? " where it is mostly recommended to use strtok, but also that it's not thread-safe, and I am planning on spawning multiple threads(provided I am able to finish my application)
P.S
Here is an example of a token and a value
user username123
pass 123456
Ah, I forgot the tricky part. I must also be able to parse a token, which has multiple values either separated by a comma.
I think that fgets() and sscanf() are your friend:
int parseTokens(FILE *filePtr, char **tokens, char **values)
{
int i = 0;
char line[128];
while (fgets(line, 127, filePtr)) {
tokens[i] = malloc(64);
values[i] = malloc(64);
sscanf(line, "%s %s", tokens[i], values[i]);
i++;
}
return i;
}
int main(void)
{
char *tokens[20];
char *values[20];
FILE *filePtr = fopen("~/test.txt", "r");
if (!filePtr)
{
fprintf(stderr, "Error opening file: %s", strerror(errno));
}
int count = parseTokens(filePtr, tokens, values);
for (int i = 0; i < count; i++) {
printf("%s %s\n", tokens[i], values[i]);
free(tokens[i]);
free(values[i]);
}
fclose(filePtr);
}
Using getc(), read characters from an input stream into a per-line buffer. Once you hit a token delimiter, you strncpy() or strdup() the per-line buffer into a token char*. If needed, parse the token again on a within-token delimiter (such as a comma), grabbing a character at a time and storing it in a per-token buffer, until you hit a within-token delimiter. Once you hit a line delimiter, copy the per-line buffer into a value char*. If you know the value is an int, float, etc., use C functions for converting a char* into those primitives (e.g., strtol(), etc.). If you have multiple token-value pairs, either keep an array of or pointers to token and value char* variables. Repeat until EOF (end-of-file).
Try this:
FILE* fp;
fp = fopen("in.txt","r");
if(fp == NULL)
{
printf("Can't open/read file.\n");
exit(1);
}
char* buf = NULL;
char* key = malloc(64);
char* val = malloc(64);
size_t read;
size_t len = 0;
if(key == NULL || val == NULL)
{
printf("malloc failed.\n");
exit(1);
}
while((read = getline(&buf, &len, fp)) != -1)
{
sscanf(buf,"%s %s", key, val);
printf("<%s> <%s>\n", key, val);
}
if(buf != NULL)
{
free(buf);
}
free(key);
free(val);
fclose(fp);
in.txt file:
key value
key1 value1
C application output:
<key> <value>
<key1> <value1>
I hope this help you.
how about use regexp? if you are in linux, you can just #include <regexp.h> to use it. andman regexp.hwill get how to use it. store them by string. and, it they are number, use sprintf to trans them to unmber.

Going through a text file line by line in C

I have been working on a small exercise for my CIS class and am very confused by the methods C uses to read from a file. All that I really need to do is read through a file line by line and use the information gathered from each line to do a few manipulations. I tried using the getline method and others with no luck.
My code is currently as follows:
int main(char *argc, char* argv[]){
const char *filename = argv[0];
FILE *file = fopen(filename, "r");
char *line = NULL;
while(!feof(file)){
sscanf(line, filename, "%s");
printf("%s\n", line);
}
return 1;
}
Right now I am getting a seg fault with the sscanf method and I am not sure why. I am a total C noob and just wondering if there was some big picture thing that I was missing.
Thanks
So many problems in so few lines. I probably forget some:
argv[0] is the program name, not the first argument;
if you want to read in a variable, you have to allocate its memory
one never loops on feof, one loops on an IO function until it fails, feof then serves to determinate the reason of failure,
sscanf is there to parse a line, if you want to parse a file, use fscanf,
"%s" will stop at the first space as a format for the ?scanf family
to read a line, the standard function is fgets,
returning 1 from main means failure
So
#include <stdio.h>
int main(int argc, char* argv[])
{
char const* const fileName = argv[1]; /* should check that argc > 1 */
FILE* file = fopen(fileName, "r"); /* should check the result */
char line[256];
while (fgets(line, sizeof(line), file)) {
/* note that fgets don't strip the terminating \n, checking its
presence would allow to handle lines longer that sizeof(line) */
printf("%s", line);
}
/* may check feof here to make a difference between eof and io failure -- network
timeout for instance */
fclose(file);
return 0;
}
To read a line from a file, you should use the fgets function: It reads a string from the specified file up to either a newline character or EOF.
The use of sscanf in your code would not work at all, as you use filename as your format string for reading from line into a constant string literal %s.
The reason for SEGV is that you write into the non-allocated memory pointed to by line.
In addition to the other answers, on a recent C library (Posix 2008 compliant), you could use getline. See this answer (to a related question).
Say you're dealing with some other delimiter, such as a \t tab, instead of a \n newline.
A more general approach to delimiters is the use of getc(), which grabs one character at a time.
Note that getc() returns an int, so that we can test for equality with EOF.
Secondly, we define an array line[BUFFER_MAX_LENGTH] of type char, in order to store up to BUFFER_MAX_LENGTH-1 characters on the stack (we have to save that last character for a \0 terminator character).
Use of an array avoids the need to use malloc and free to create a character pointer of the right length on the heap.
#define BUFFER_MAX_LENGTH 1024
int main(int argc, char* argv[])
{
FILE *file = NULL;
char line[BUFFER_MAX_LENGTH];
int tempChar;
unsigned int tempCharIdx = 0U;
if (argc == 2)
file = fopen(argv[1], "r");
else {
fprintf(stderr, "error: wrong number of arguments\n"
"usage: %s textfile\n", argv[0]);
return EXIT_FAILURE;
}
if (!file) {
fprintf(stderr, "error: could not open textfile: %s\n", argv[1]);
return EXIT_FAILURE;
}
/* get a character from the file pointer */
while(tempChar = fgetc(file))
{
/* avoid buffer overflow error */
if (tempCharIdx == BUFFER_MAX_LENGTH) {
fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n");
return EXIT_FAILURE;
}
/* test character value */
if (tempChar == EOF) {
line[tempCharIdx] = '\0';
fprintf(stdout, "%s\n", line);
break;
}
else if (tempChar == '\n') {
line[tempCharIdx] = '\0';
tempCharIdx = 0U;
fprintf(stdout, "%s\n", line);
continue;
}
else
line[tempCharIdx++] = (char)tempChar;
}
return EXIT_SUCCESS;
}
If you must use a char *, then you can still use this code, but you strdup() the line[] array, once it is filled up with a line's worth of input. You must free this duplicated string once you're done with it, or you'll get a memory leak:
#define BUFFER_MAX_LENGTH 1024
int main(int argc, char* argv[])
{
FILE *file = NULL;
char line[BUFFER_MAX_LENGTH];
int tempChar;
unsigned int tempCharIdx = 0U;
char *dynamicLine = NULL;
if (argc == 2)
file = fopen(argv[1], "r");
else {
fprintf(stderr, "error: wrong number of arguments\n"
"usage: %s textfile\n", argv[0]);
return EXIT_FAILURE;
}
if (!file) {
fprintf(stderr, "error: could not open textfile: %s\n", argv[1]);
return EXIT_FAILURE;
}
while(tempChar = fgetc(file))
{
/* avoid buffer overflow error */
if (tempCharIdx == BUFFER_MAX_LENGTH) {
fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n");
return EXIT_FAILURE;
}
/* test character value */
if (tempChar == EOF) {
line[tempCharIdx] = '\0';
dynamicLine = strdup(line);
fprintf(stdout, "%s\n", dynamicLine);
free(dynamicLine);
dynamicLine = NULL;
break;
}
else if (tempChar == '\n') {
line[tempCharIdx] = '\0';
tempCharIdx = 0U;
dynamicLine = strdup(line);
fprintf(stdout, "%s\n", dynamicLine);
free(dynamicLine);
dynamicLine = NULL;
continue;
}
else
line[tempCharIdx++] = (char)tempChar;
}
return EXIT_SUCCESS;
}

Resources