include UNIX utility 'file' in C program - c

I'm writing a program in C, and I need to known the mime-type of a file.
I have yet searched with Google, and I found that I must include the 'file' UNIX utility in my project.
The source code of file need configure and make. How I can include this in my project? Do I have to crop a part of the source code into a new file.c and file.h?

Do you want to guess the MIME type based on the extension, or do something like file and examine the headers?
To get functionality similar to file, you don't need to include file in your project. Instead, you'll want to use libmagic which file is based on. Unfortunately I'm not aware of a good source of documentation for this, but it's pretty straightforward.
magic_t magic = magic_open(MAGIC_MIME_TYPE);
magic_load(magic, NULL);
char *mime_type = magic_file(magic, "/path/to/file");
magic_close(magic);

Thanks for yours answers and comments.
I solved with this:
const char *w_get_mime(const char *arg, const char *file, int line_no)
{
const char *magic_full;
magic_t magic_cookie;
if(arg == NULL)
w_report_error("called with NULL argument.",file,line_no,__func__,0,1,error);
else if ((magic_cookie = magic_open(MAGIC_MIME) ) == NULL)
report_error("unable to initialize magic library.",0,1,error);
else if (magic_load(magic_cookie, NULL) != 0)
{
magic_close(magic_cookie);
snprintf(globals.err_buff,MAX_BUFF,"cannot load magic database - %s .",magic_error(magic_cookie));
report_error(globals.err_buff,0,1,error);
}
magic_full = magic_file(magic_cookie, arg);
magic_close(magic_cookie);
return magic_full;
}
thanks a lot! :)

Related

Properties file reading in C (no C# or C++) compiled with minGW

I need to say that i am Newbie at C and i only wrote about 100-150 lines of code in C.
I need to read a .properties file with entries like the following:
Value1 = Hello
Value2 = Bye
I would like to get to the Values like this:
bla.getValue("Value1");
So i can work with it like this:
foo = bla.getValue("Value1");
bar = bla.getValue("Value2");
printf("%s - %s",foo,bar);
I don't need them for anything else, than printing them to the screen.
I found two questions here, which went into the right direction, but they couldn't help me in my task:
How to read configuration/properties file in C?
Properties file library for C (or C++)
I tried multiple of the answers of the thread above, but either way my compiler(minGW) doesn't like one of these lines:
using foo::bar;
or
using namespace foo;
When i try to compile my code, i get an error saying:
error: unknown type name 'using'
This is the code where i tried to implement the given solution of the thread above:
#include <windows.h>
#include <stdio.h>
#include <string.h>
using platformstl::properties_file;
int WINAPI WinMain(HINSTANCE a,HINSTANCE b,LPSTR c,int d)
{
char *tPath, *tWindow;
char *search = " ";
tWindow = strtok(c, search);
tPath = strtok(NULL, search);
properties_file properties("%s",tPath);
properties::value_type value1 = properties["Value1"];
properties::value_type value2 = properties["Value2"];
printf("Window: %s; Path: %s; %s %s",tWindow,tPath,value0,value1);
}
I use a WinMain, because the programm is about finding an open Window. I haven't included those parts of the code, because they are irrelevant for my question and worked completely fine. The strtok(); parts are working fine for me too. I need them, because the title of the window to find and the Path of the properties file are both given as commandline arguments:
programm.exe windowtitle path/to/properties/file
As i tried with other answers, which told me to load some libraries, i got to a point, where the needed libraries didn't contain the needed header files. Some of the libraries are even for c++, which i have a restriction on, so i can't use it.
I hope that made things a little clearer, as you may know that i am not used to ask questions here. :)
I solved my Problem with a big Workaround.
This is my final code:
if(vn != NULL){
for(i = 0; i < 1; i++){
if(fgets(temp, BUF, vn) == NULL){
printf("Line is empty");
return 2;
}
}
if(fgets(puffer, BUF, vn) == NULL){
printf("Line is empty");
return 2;
}
tVariable = strtok(puffer, find);
tValue = strtok(NULL, find);
}else {
printf("Unable to read File");
return 2;
}
I just read the second Line of the given file and cut it at the = sign.
I know, that i need to read the second line, because the Property i need is always found in the second line of the .properties file.
I now have my wanted Value in tValue, so i can use it to print it out with printf("%s", tValue).

How to get normalized (canonical) file path on Linux "even if the filepath is not existing on the file system"? (In a C program))

I have researched a lot on this topic but could not get anything substantial.
By normalize/canonicalize I mean to remove all the "..", ".", multiple slashes etc from a file path and get a simple absolute path.
e.g.
"/rootdir/dir1/dir2/dir3/../././././dir4//////////" to
"/rootdir/dir1/dir2/dir4"
On windows I have GetFullPathName() and I can get the canonical filepath name, but for Linux I cannot find any such API which can do the same work for me,
realpath() is there, but even realpath() needs the filepath to be present on the file system to be able to output normalized path, e.g. if the path /rootdir/dir1/dir2/dir4 is not on file system - realpath() will throw error on the above specified complex filepath input.
Is there any way by which one could get the normalized file path even if it is not existing on the file system?
realpath(3) does not resolve missing filenames.
But GNU core utilities (https://www.gnu.org/software/coreutils/) have a program realpath(1) which is similar to realpath(3) function, but have option:
-m, --canonicalize-missing no components of the path need exist
And your task can be done by canonicalize_filename_mode() function from file lib/canonicalize.c of the coreutils source.
canonicalize_filename_mode() from Gnulib is a great option but cannot be used in commercial software (GPL License)
We use the following implementation that depends on cwalk library:
#define _GNU_SOURCE
#include <unistd.h>
#include <stdlib.h>
#include "cwalk.h"
/* extended version of canonicalize_file_name(3) that can handle non existing paths*/
static char *canonicalize_file_name_missing(const char *path) {
char *resolved_path = canonicalize_file_name(path);
if (resolved_path != NULL) {
return resolved_path;
}
/* handle missing files*/
char *cwd = get_current_dir_name();
if (cwd == NULL) {
/* cannot detect current working directory */
return NULL;
}
size_t resolved_path_len = cwk_path_get_absolute(cwd, path, NULL, 0);
if (resolved_path_len == 0) {
return NULL;
}
resolved_path = malloc(resolved_path_len + 1);
cwk_path_get_absolute(cwd, path, resolved_path, resolved_path_len + 1);
free(cwd);
return resolved_path;
}

play .wav file using c language

I was asked to play .wav files using C language, the compiler I'm using is Devcpp.
I was trying to use the function PlaySound() as below:
PlaySound("C:/Users/wavfiles/13.1.wav", NULL, SND_FILENAME);
If I directly input the directory to the function like this, it is able to successfully play the sound.
However, I want to set the directory as a variable. I create a text file with a list of directory and extract the one that I want, then put it into PlaySound() function. Here is part of my code:
FILE *fw;
char addr[1000]
char schapter[50];
while(fgets(addr, 1000, fw) != NULL) {
if((strstr(addr, schapter)) != NULL) {
printf("\n%s", addr);
PlaySound(addr, NULL, SND_FILENAME);
}
}
In this case, the directory is assigned to addr (addr = "C:/Users/wavfiles/13.1.wav") and then I put addr into PlaySound(), but it doesn't work.
I have been stuck on this problem for a long time and cannot move on.
I would really appreciate it if anyone can give me suggestions or solutions.
Thank you.
The string returned by fgets() contains the terminal newline. You'll need to remove that to get the filename.
An easy way to do this is to use strchr() to locate the newline:
while (fgets(addr, 1000, fw) != NULL) {
char *nl = strchr(addr, '\n');
if (nl) *nl = 0;
…
}

How to get values from a config file

I have the following Config.cfg
[DD]
user=**
password=***
database=***
IPServidor=****
port=***
[Controller]
Control1=8
Temp=5
Hum=7
Link=8
Volt=9
[Controller]
Control2=10
Temp=5
Hum=7
Link=8
Volt=9
I would like to read the values of the controllers only and print them to the screen like
Controller_8: 5,7,8,9
I do not want to use libconfig or glib because I have problem with undefined functions. I did the installation, I have the headers but I do not know why it does not work. So I want another solution. My first thought is with the usage of strchr to find the lines which I want (to ignore [DD] table in my case) and with the usage of strtok to get only the values of temp,hum,link,volt
char buffer1[100];
FILE *f = fopen("/home/pi/Desktop/Config.cfg","r");
while(fgets(buffer1, sizeof(buffer1), f))
{
printf("%s",buffer1);
char *pos1 = strchr(buffer1,'Controller');
if (pos1)
{
item = strtok (buffer1,"Control");
printf("Results: %s\n", buffer1);
}
}
The above code is not correct. Is just a thought. Is there any better way?
Don't try parsing ini files, use some existing library.
Ini file parsing is included in a number of "frameworks", for instance in Gtk+ or on Windows. If you can't access those, you can still use some standalone library, for instance: http://ndevilla.free.fr/iniparser/

Check if a file is a specific type in C

I'm writing my first C program, though I come from a C++ background.
I need to iterate through a directory of files and check to see if the file is a header file, and then return the count.
My code is as follows, it's pretty rudimentary I think:
static int CountHeaders( const char* dirname ) {
int header_count = 0;
DIR* dir_ptr;
struct dirent* entry;
dir_ptr = opendir( dirname );
while( ( entry = readdir( dir_ptr ) ) )
{
if ( entry->d_type == DT_REG )
{
//second if statement to verify the file is a header file should be???
++header_count;
}
}
closedir( dir_ptr );
return header_count;
}
What would be a good if statement to check to see if the file is a header?
Simply check if the file extension is .h, something like:
const char *ext = strrchr (entry->d_name, '.');
if ((ext != NULL) && (!strcmp (ext+1, "h"))) {
// header file
}
Ofcourse, note that this assumes all your header files have an .h extension, which may or may not be true, the C standard does not mandate that header files must have an .h extension.
Each dirent structure has a d_name containing the name of the file, so I'd be looking to see if that followed some pattern, like ending in .h or .hpp.
That would be code along the lines of:
int len = strlen (entry->d_name);
if ((len >= 2) && strcmp (&(entry->d_name[len - 2]), ".h") == 0))
header_count++;
if ((len >= 4) && strcmp (&(entry->d_name[len - 4]), ".hpp") == 0))
header_count++;
Of course, that won't catch truly evil people from calling their executables ha_ha_fooled_you.hpp but thanfkfully they're in the minority.
You may even want to consider an endsWith() function to make your life easier:
int endsWith (char *str, char *end) {
size_t slen = strlen (str);
size_t elen = strlen (end);
if (slen < elen)
return 0;
return (strcmp (&(str[slen-elen]), end) == 0);
}
:
if (endsWith (entry->d_name, ".h")) header_count++;
if (endsWith (entry->d_name, ".hpp")) header_count++;
There are some much better methods than checking the file extension.
Wikipedia has a good article here and here. The latter idea is called the magic number database which essentially means that if a file contains blah sequence then it is the matching type listed in the database. Sometimes the number has restrictions on locations and sometimes it doesnt. This method IMO is more accurate albeit slower than file extension detection.
But then again, for something as simple as checking to see if its a header, this may be a bit of overkill XD
You could check if the last few characters are one of the header-file extensions, .h, .hpp, etc. Use the dirent struct's d_name for the name of the file.
Or, you could run the 'file' command and parse its result.
You probably just want to check the file extension. Using dirent, you would want to look at d_name.
That's up to you.
The easiest way is to just look at the filename (d_name), and check whether it ends with something like ".h" or ".hpp" or whatever.
Opening the file and actually reading it to see if it's valid c/c++, on the other hand, will be A LOT more complex... you could run it through a compiler, but not every header works on its own, so that test will give you a lot of false negatives.

Resources