Link problems for libical MWE - c

I am trying to build an MWE using libical with an example pretty much cut-and-pasted from the libical docs as follows:
#include <stdlib.h>
#include <libical/ical.h>
const char* calendar_file = "orage_export.ics";
//*****************************************************************************
char* read_stream(char* s, size_t size, void* d)
{
return fgets(s, size, (FILE*)d);
} // read_stream()
//*****************************************************************************
int main()
{
char* line;
icalcomponent* component;
icalparser* parser = icalparser_new();
// open file (first command-line argument)
FILE* stream = fopen(calendar_file, "r");
if(stream == NULL)
{
printf("unable to open %s\n", calendar_file);
exit(-1);
}
// Associate the FILE with the parser so that read_stream will have access to it
icalparser_set_gen_data(parser, stream);
do
{
// Read the file, line-by-line, and parse the data
line = icalparser_get_line(parser, read_stream);
component = icalparser_add_line(parser, line);
// If icalparser has finished parsing a component, it will return it
if(component != 0)
{
// Print the parsed component
printf("%s", icalcomponent_as_ical_string(component));
icalparser_clean(parser);
printf("\n---------------\n");
icalcomponent_free(component);
}
}
while(line != 0);
fclose(stream);
return 0;
}
But I am getting link issues that I cannot resolve. Obviously, I am linking against (the latest version of) libical + pthreads. I then got an undefined reference to ucal_getKeywordValuesForLocale_66 which I can resolve by adding libicui18n.a. But then I get undefined reference errors for "vtable for icu_66::UnicodeString", "icu_66::UnicodeString::setTo" and "icu_66::~UnicodeString" so on, which look very much like C++ errors associated with ICU components. But I am building a plain C program?
What is the set of libraries I need to get the MWE above working? And why am I getting what seem to be class-based link errors when building a vanilla C program?
I am on Linux Mint 20.2, and using the repo versions of all libraries other than libical itself.
Peter
EDIT: In fact, answered my own question!
Looking carefully (properly?) at the output, the undefined issues were connected to libicui18n, so not really an iCal problem at all. Doh!
The fix was to notice that the iCal folks had provided a pkg-config script so adding pkg-config --libs --cflags libical to the compiler line worked. (I guess the ICU dependencies are fixed implicitly.)

Related

C Unit Testing - Mock (In Check Framework)

I'm trying to "mock" some things in my unit testing of a C project.
I am using the Check framework for testing and I have a function that reads from a file on disk to verify the contents.
My function is:
#include "verifier.h"
#include <stdio.h>
int verify_content(char *path, char *verify_string) {
File *fptr
fptr = fopen(path, "r")
// Do verification
return 0
and my test is
START_TEST (verify_content_test)
{
char *test_path = "test_path";
char *test_string = "unique_string_content_here";
ck_assert_str_eq(verify_content(test_path, test_string), 0);
}
END_TEST
However, I don't want this to read from disk, because that would be slow, and I'd have to have multiple static files just for testing against.
Is there a way to "mock"/"fake" the fopen?
I'm still new to C development and super new to unit testing in C so if I should approach this problem differently, please point me in the right direction.
You can write your own fopen() and put anything you like into it. Link this module with all other modules that need the mocked version.
The function will only be linked from the standard library if there are unresolved references. Providing your own implementation resolves all references and so the standard version will not be used.
With GCC you also have another alternative: use the linker's --wrap option. For example --wrap=fopen will change all references of fopen() into __wrap_fopen() and change the defined symbols of fopen() into __real_fopen(). This way you can "intercept" the call and massage it to you liking:
FILE* __wrap_fopen(const char* filename, const char* mode) {
/* Do anthing you want, including changing arguments or not calling __real_fopen() at all. */
FILE* result = __real_fopen(filename, mode);
/* Do anthing you want, including changing the result. */
return result;
}

Can't find a source file at" /getc.c" eclipse c ubuntu

just installed eclipse on my linux and trying working with files.
I wanted to use fgetc function but it seems that its not working..
while debugging: even if Im using step over its crush, and while letting it run its just dont do anything.
its happen also for every function related to files like fscanf,fgets etc..
the error messege is:
Can't find a source file at "/build/glibc-OTsEL5/glibc-2.27/libio/getc.c"
Locate the file or edit the source lookup path to include its location.
any ideas?
thnk's in advanced
and this is my code:
#include <stdio.h>
#include <stdlib.h>
int main(){
func();
return 0;
}
void func(){
int ch;
int fd = open("out.txt", O_RDONLY);
if(fd < 0)
perror("fd");
ch = fgetc(fd);
printf("%d",ch);
}
The error message comes from the debugger. It indicates that whoever built glibc for your system did not add source files to the debugging information. As a result, stepping through system library functions such as fgetc is very confusing. But this is independent of your actual problem.
You cannot mix file descriptor functions like open with file stream functions like fgetc. The compiler will have print a type mismatch warning; you really should not ignore these.
Something like this should fix the type error:
File *fp = fopen("out.txt", "r");
if (fp == NULL) {
perror("fopen");
return 1;
}
ch = fgetc(fp);
If you want to keep using unbuffered I/O and open, you will have to use the read function instead of fgetc to read bytes.

Function for loading data from binary files to array of structs

This is my code for loading data from binary file to array of structs but I get error that file is not found. File is there and it works with other functions.
void ispis2(void) {
float data_num = brojanje();
int N = data_num / 3;
ARTIKL artikl[120];
FILE *fp = NULL;
fp = fopen("artikli.bin", "rb");
if (fp == NULL) {
fprintf(stderr, "Pogreska: %s\n", strerror(errno));
}
else {
for (int i = 0; i < N; i++) {
fread(&artikl[i].ime, sizeof(artikl), 1, fp);
fread(&artikl[i].cijena, sizeof(artikl), 1, fp);
fread(&artikl[i].ID, sizeof(artikl), 1, fp);
}
for (int i = 0; i < N; i++) {
printf("Ime: %s", artikl[i].ime);
printf("Cijena: %f", artikl[i].cijena);
printf("ID: %d", artikl[i].ID);
}
}
}
You probably are not running your program in the environment (notably check the current working directory) you want.
Of course your fread-s smell bad. Read again the documentation of standard C input/output functions, in particular of fread. The sizeof(artikl) argument is surely wrong (but since your question don't explain what an ARTIKL really is, we cannot help more).
The notion of directory is unknown by the C11 standard n1570. See also this. But if you are on a POSIX system, you could query it with getcwd(3). Other operating systems have different ways of querying it (e.g. GetCurrentDirectory on Windows). Read Operating Systems: Three Easy Pieces to understand more about operating systems, and read also a good C programming book.
So you could perhaps improve the error handling:
if (fp == NULL) {
fprintf(stderr, "Pogreska: %s\n", strerror(errno));
char wdbuf[128];
memset(wdbuf, 0, sizeof(cwdbuf));
fprintf(stderr, "working directory: %s\n",
getcwd(wdbuf, sizeof(wdbuf));
}
(the above code don't handle failure of getcwd; a robust program should handle that)
BTW, I am not sure that handling binary files like you do is worthwhile (a binary format is very brittle, and you need to document its format very precisely; remember that most of the time, data is more valuable than the application processing it). You might consider instead storing the data in some textual format (like JSON, YAML, ....) or in some sqlite database. Consider using appropriate libraries (e.g. jansson for JSON, libsqlite for sqlite)
Don't forget to compile your code with all warnings and debug info (so gcc -Wall -Wextra -g with GCC). Read the documentation of your compiler (e.g. how to invoke it) and of your debugger. Use the debugger to understand the behavior of your program.

Exclude file types expect txt files in C

Hello and Happy new Year ,
I have to accept juste txt files in my C programme ,
I don't have any idea to how to made it .. any ideas?
And I don't know if text file contain Header or something which characterize it..
PS: I'm using Ubuntu so file extension is not seen.
Thank you
In a Linux environment, I would personally go with libmagic, which is the core of the utility program file. The purpose of this library is to do exactly what you are trying to accomplish: identify the type of a file based on it content.
Example usage would look like this.
/* identify.c */
#define _POSIX_SOURCE /* required for fileno() */
#include <magic.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
const char *description;
magic_t cookie;
FILE *fp;
fp = fopen("example.txt", "r");
if(fp == NULL) {
fprintf(stderr, "error: cannot open file\n");
exit(EXIT_FAILURE);
}
cookie = magic_open(MAGIC_NONE);
if(cookie == NULL) {
fprintf(stderr, "error: cannot initialize library\n");
fclose(fp);
exit(EXIT_FAILURE);
}
if( magic_load(cookie, NULL) != 0 ) {
fprintf(stderr, "error: cannot load database : %s\n",
magic_error(cookie));
magic_close(cookie);
fclose(fp);
exit(EXIT_FAILURE);
}
description = magic_descriptor(cookie, fileno(fp));
printf("%s\n", description);
magic_close(cookie);
fclose(fp);
return EXIT_SUCCESS;
}
Name this source file identify.c, create a text file name example.txt with some content in the same directory, and compile with:
gcc -Wall -std=c99 -pedantic -lmagic -o identify identify.c
Then run it.
./identify
And you get something like this printed:
UTF-8 Unicode text
This library can be used in a few different ways, so you should probably have a look at the man page. For example, you can get a MIME type instead of a description like the one above.
The file package of which libmagic is a part is probably already installed on your machine. However, if you are using a distribution such as RHEL of CentOS that splits development headers into a separate package, make sure you have file-devel installed.

How can I write commands to the vxworks shell with a c program

If I wanted to run a shell command in linux with a c program, I would use
system("ls");
Is there a way I can accomplish this in Wind River vxworks?
I found the below example but I'm wondering do I need to include vxworks header files for this to work? I assume I do, but how do I figure out which one?
Example:
// This function runs a shell command and captures the output to the
// specified file
//
extern int consoleFd;
typedef unsigned int (*UINTFUNCPTR) ();
extern "C" int shellToFile(char * shellCmd, char * outputFile)
{
int rtn;
int STDFd;
int outFileFd;
outFileFd = creat( outputFile, O_RDWR);
printf("creat returned %x as a file desc\n",outFileFd);
if (outFileFd != -1)
{
STDFd=ioGlobalStdGet(STD_OUT);
ioGlobalStdSet(STD_OUT,outFileFd);
rtn=execute(shellCmd);
if (rtn !=0)
printf("execute returned %d \n",outFileFd);
ioGlobalStdSet(STD_OUT,STDFd);
}
close(outFileFd);
return (rtn);
}
I found the code segment below worked for me. For some reason changing the globalStdOut didn't work. Also the execute function did not work for me. But my setting the specific task out to my file, I was able to obtain the data I needed.
/* This function directs the output from the devs command into a new file*/
int devsToFile(const char * outputFile)
{
int stdTaskFd;
int outputFileFd;
outputFileFd = creat( outputFile, O_RDWR);
if (outputFileFd != ERROR)
{
stdTaskFd = ioTaskStdGet(0,1);
ioTaskStdSet(0,1,outputFileFd);
devs();
ioTaskStdSet(0,1,stdTaskFd);
close(outputFileFd);
return (OK);
}
else
return (ERROR);
}
If this is a target/kernel shell (i.e. running on the target itself), then remember that all the shell commands are simply translated to function calls.
Thus "ls" really is a call to ls(), which I believe is declared in dirLib.h
I think that the ExecCmd function is what you are looking for.
http://www.dholloway.com/vxworks/6.5/man/cat2/ExecCmd.shtml
As ever, read the documentation. ioLib.h is required for most of the functions used in that example, and stdio.h of course for printf().
As to the general question of whether you need to include any particular headers for any code to compile, you do need to declare all symbols used, and generally that means including appropriate headers. The compiler will soon tell you about any undefined symbols, either by warning or error (in C89/90 undefined functions are not an error, just a bad idea).

Resources