I want to get file extensions without using standart libraries in C. so basically i want to search for .txt files in a folder which includes .png, .txt, .jpg files.
I don't have a certain code to show, although while I was searching I found a code which includes <dirent.h> and everybody was saying this code cannot be done without that library. Can't I do it without that? and also in some websites they were saying <dirent.h> is only a library for Linux. I'm using MacOS.
code was this: How can I get only txt files from directory in c?
error is this:
Member reference base type 'char [1024]' is not a structure or union.
Can you help me?
If it is supposed to work on macOS only, you can use macOS native frameworks instead of standard libraries, like this:
#include "CoreFoundation/CoreFoundation.h"
int main(int argc, const char * argv[]) {
CFStringRef extension = CFStringCreateWithCString(NULL, ".txt", CFStringGetSystemEncoding());
CFStringRef folderURLString = CFStringCreateWithCString(NULL, "file:///Users/mousetail/Downloads/", CFStringGetSystemEncoding());
CFURLRef folderURL = CFURLCreateWithString(NULL, folderURLString, NULL);
CFURLEnumeratorRef enumerator = CFURLEnumeratorCreateForDirectoryURL(NULL, folderURL, kCFURLEnumeratorDefaultBehavior, NULL);
while (true) {
CFURLRef fileURL = NULL;
CFURLEnumeratorResult enumeratorResult = CFURLEnumeratorGetNextURL(enumerator, &fileURL, NULL);
if (kCFURLEnumeratorSuccess == enumeratorResult) {
CFStringRef fileURLString = CFURLGetString(fileURL);
if (CFStringHasSuffix(fileURLString, extension)) {
CFShow(fileURLString);
}
} else if (kCFURLEnumeratorEnd == enumeratorResult) {
break;
}
}
CFRelease(enumerator);
CFRelease(folderURL);
CFRelease(folderURLString);
CFRelease(extension);
return 0;
}
Related
How can I get file path to Desktop directory as a string on macOS.
I need it to be done in pure C or with some C-level framework.
If you insist on using only C (why?), then your only choice is to use deprecated APIs:
#include <limits.h>
#include <CoreServices/CoreServices.h>
...
FSRef fsref;
UInt8 path[PATH_MAX];
if (FSFindFolder(kUserDomain, kDesktopFolderType, kDontCreateFolder, &fsref) == noErr &&
FSRefMakePath(&fsref, path, sizeof(path)) == noErr)
{
// Make use of path
}
If you need a CFURL rather than a path, you can use CFURLCreateFromFSRef() rather than FSRefMakePath().
Actually, while researching this, I found an API I hadn't known about. Apparently, you can use this, which apparently comes from Cocoa but uses only C types:
#include <limits.h>
#include <NSSystemDirectories.h>
char path[PATH_MAX];
NSSearchPathEnumerationState state = NSStartSearchPathEnumeration(NSDesktopDirectory, NSUserDomainMask);
while (state = NSGetNextSearchPathEnumeration(state, path))
{
// Handle path
}
The form of the API is that it may return multiple results (one on each iteration of the loop), but you should get only one for the specific use here. In that case, you can change the while to and if.
Note that, with this API, returned paths for directories in the user domain may use "~" rather than the absolute path to the user's home directory. You'll have to resolve that yourself.
Here's a short function, which works on more Unix based systems than just macOS and returns the current user's desktop folder:
#include <limits.h>
#include <stdlib.h>
/**
* Returns the path to the current user's desktop.
*/
char *path2desktop(void) {
static char real_public_path[PATH_MAX + 1] = {0};
if (real_public_path[0])
return real_public_path;
strcpy(real_public_path, getenv("HOME"));
memcpy(real_public_path + strlen(real_public_path), "/Desktop", 8);
return real_public_path;
}
The path will only be computed once.
If the function is called more than once, the old result will be returned (not thread-safe, unless the first call was protected).
I ended with usage of Objective-C in such way:
//
// main.m
// search_path_for_dir
//
// Created by Michal Ziobro on 23/09/2016.
// Copyright © 2016 Michal Ziobro. All rights reserved.
//
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
if(argc != 3)
return 1;
#autoreleasepool {
NSArray *paths = NSSearchPathForDirectoriesInDomains(atoi(argv[1]), atoi(argv[2]), YES);
NSString *path = [paths objectAtIndex:0];
[path writeToFile:#"/dev/stdout" atomically:NO encoding:NSUTF8StringEncoding error:nil];
}
return 0;
}
And than from command line I can execute this program in that way:
./search_path_for_dir 12 1
12 - NSDesktopDirectory
1 - NSUserDomainMask
I am using script in C that executes this program from command line and retrieves its output.
Here's C example calling this mini Cocoa App:
CFStringRef FSGetFilePath(int directory, int domainMask) {
CFStringRef scheme = CFSTR("file:///");
CFStringRef absolutePath = FSGetAbsolutePath(directory, domainMask);
CFMutableStringRef filePath = CFStringCreateMutable(NULL, 0);
if (filePath) {
CFStringAppend(filePath, scheme);
CFStringAppend(filePath, absolutePath);
}
CFRelease(scheme);
CFRelease(absolutePath);
return filePath;
}
CFStringRef FSGetAbsolutePath(int directory, int domainMask) {
char path_cmd[BUF_SIZE];
sprintf(path_cmd, "./tools/search_path_for_dir %d %d", directory, domainMask);
char *path = exec_cmd(path_cmd);
return CFStringCreateWithCString(kCFAllocatorDefault, path, kCFStringEncodingUTF8);
}
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;
}
I tried to list imported DLL of PE file using following code, but it didn't work and windows says that exe has stopped working when I run it. In code, I simply mapped given exe file into memory using CreateFileMapping function and then explorer each section using appropriate structures given in Win32 API. How can I correct it?
#include <stdio.h>
#include <windows.h>
//add Pointer Values
#define MakePtr( cast, ptr, addValue ) (cast)( (unsigned long)(ptr)+(unsigned long)(addValue))
int main(int argc , char ** argv) //main method
{
HANDLE hMapObject, hFile;//File Mapping Object
LPVOID lpBase;//Pointer to the base memory of mapped
PIMAGE_DOS_HEADER dosHeader;//Pointer to DOS Header
PIMAGE_NT_HEADERS ntHeader;//Pointer to NT Header
PIMAGE_IMPORT_DESCRIPTOR importDesc;//Pointer to import descriptor
hFile = CreateFile(argv[1],GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);//Open the Exe File
if(hFile == INVALID_HANDLE_VALUE){
printf("\nERROR : Could not open the file specified\n");
}
hMapObject = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,0,NULL);
lpBase = MapViewOfFile(hMapObject,FILE_MAP_READ,0,0,0);//Mapping Given EXE file to Memory
dosHeader = (PIMAGE_DOS_HEADER)lpBase;//Get the DOS Header Base
//verify dos header
if ( dosHeader->e_magic == IMAGE_DOS_SIGNATURE)
{
ntHeader = MakePtr(PIMAGE_NT_HEADERS, dosHeader, dosHeader->e_lfanew);//Get the NT Header
//verify NT header
if (ntHeader->Signature == IMAGE_NT_SIGNATURE ){
importDesc = MakePtr(PIMAGE_IMPORT_DESCRIPTOR, dosHeader,ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
while (importDesc->Name)
{
printf("%s\n",MakePtr(char*, dosHeader,importDesc->Name));
importDesc++;
}
}
}
getchar();
}
The content of the list you are looking for is contained in a section (like almost everything in a PE image). You must access the section where the directory is pointing to. Take a look at the code of Matt Pietrek (PeDump) to see how it works.
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! :)
I'm having trouble getting libsndfile-1.dll to work in my MSVC project. I can load the library and retrieve the version string from the dll by calling sf_command() from my code. However, I can't seem to get sf__open() to return a SNDFILE pointer.
I've also noticed that I can't get fopen() to return a FILE pointer either (maybe this is related, I think sf_open() uses fopen()!?).
I'm pretty new to MSVC, C/C++ and windows in general so I'm probably missing something really obvious.
My main.cpp looks like this:
#include <windows.h>
#include <stdio.h>
#include "sndfile.hh"
// create some function pointers to point to the dll function addresses
// I'm winging this a bit. hopefully it's right!? seems to work!
typedef int (*SF_COMMAND)(SNDFILE*, int, void*, int);
typedef SNDFILE* (*SF_OPEN)(const char*, int, SF_INFO*);
int main()
{
// dll handle
HINSTANCE hDLL = NULL;
// create some vars to store the dll funcs in
SF_COMMAND sf_command;
SF_OPEN sf_open;
// load the dll
hDLL = LoadLibrary(L"libsndfile-1.dll");
// check the dll loaded
if( NULL == hDLL )
{
printf("Error, Could not load library \n");
return 1;
}
// get the dll funcs
sf_command = (SF_COMMAND)GetProcAddress(hDLL, "sf_command");
sf_open = (SF_OPEN)GetProcAddress(hDLL, "sf_open");
// check we got the funcs
if(!(sf_command && sf_open)){
printf("Error exporting dll functions \n");
return 2;
}
// all good so far!
// try the first function
char* version_string[sizeof(char*)*4];
int res = sf_command(NULL, SFC_GET_LIB_VERSION, &version_string, sizeof(version_string));
if(res){
// all good!
printf("Version: %s \n", version_string);
}
// now try and create a SNDFILE pointer
SF_INFO info;
SNDFILE* sfp = sf_open("c:\\Godspeed.aif", SFM_READ, &info);
if(sfp){
printf("Hurray! successfully opened the SNDFILE!! \n");
}else{
printf("Doh! couldn't open the SNDFILE!! \n");
// Grr!!
return 3;
}
return 0;
}
The project builds and exits with code 3 (couldn't open the file! (I'm pretty sure the file is there!!)).
When I run the exe the output is:
Version: libsndfile-1.0.17
Doh! couldn't open the SNDFILE
Does anyone have any suggestions as to where I'm going wrong?
Many thanks,
Josh.
Hmm, I really should learn not to post to forums late at night!
I had another attempt this morning and had the file open within minutes.
I was getting my paths all wrong (not used to these weird windows paths)!
I tried using a relative path and bingo!
Hope that helps someone!