FreeImage include in c - c

Is there any way to include http://freeimage.sourceforge.net/index.html in my c test program without first installing the library? It fails to compile because of some memset..
Here is my C code. Is there any way to make it work? Please try compiling it and tell me how to do it if it works?
#define NAZIV_DATOTEKE 50
#include <stdio.h>
#include "FreeImage.h"
void FreeImageErrorHandler(FREE_IMAGE_FORMAT fif, const char *message);
FIBITMAP* GenericLoader(const char* lpszPathName, int flag);
int main(){
FreeImage_Initialise();
FIBITMAP *dib, *ptr;
char ulaz_slika[NAZIV_DATOTEKE] = "bmp_24.bmp";
char izlaz_slika[NAZIV_DATOTEKE] = "free.bmp"; //podrazumevana vrednost
dib = GenericLoader(ulaz_slika, 0);
//slika = FreeImage_Load(FIF_BMP, "bmp_24.bmp", BMP_DEFAULT);
FreeImage_SetOutputMessage(FreeImageErrorHandler);
if (dib) {
printf("Ucitan \"%s\".\n", ulaz_slika);
}
FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(ulaz_slika, 0);
if ((fif != FIF_BMP) && (fif != FIF_ICO) && (fif != FIF_JPEG) && (fif != FIF_PNG) && (fif != FIF_TIFF)){
printf("Format slike nije podrzan.\n");
return 1;
}
ptr = FreeImage_ConvertTo24Bits(dib);
FreeImage_SetOutputMessage(FreeImageErrorHandler);
FreeImage_Unload(dib);
FreeImage_SetOutputMessage(FreeImageErrorHandler);
dib = ptr;
if (dib) {
printf("Konvertovan u RGB.\n");
}
const char *slika = (const char*)FreeImage_GetBits(dib);
if (FreeImage_Save(fif, dib, izlaz_slika, BMP_DEFAULT)) {
printf("Snimljen \"%s\".\n", izlaz_slika);
}
if (dib) {
FreeImage_Unload(dib);
}
FreeImage_DeInitialise();
return 0;
}
void FreeImageErrorHandler(FREE_IMAGE_FORMAT fif, const char *message){
printf("\n*** ");
if(fif != FIF_UNKNOWN) {
if (FreeImage_GetFormatFromFIF(fif))
printf("%s Format\n", FreeImage_GetFormatFromFIF(fif));
}
printf(message);
printf(" ***\n");
}
FIBITMAP* GenericLoader(const char* lpszPathName, int flag) {
FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
// check the file signature and deduce its format
// (the second argument is currently not used by FreeImage)
fif = FreeImage_GetFileType(lpszPathName, 0);
if(fif == FIF_UNKNOWN) {
// no signature ?
// try to guess the file format from the file extension
fif = FreeImage_GetFIFFromFilename(lpszPathName);
}
// check that the plugin has reading capabilities ...
if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) {
// ok, let's load the file
FIBITMAP *dib = FreeImage_Load(fif, lpszPathName, flag);
// unless a bad file format, we are done !
return dib;
}
return NULL;
}

No you cannot. To compile your source, the linker needs the library.

Related

Using pcre_get_substring_list, match all pattern inside of string and return in array in C with PCRE?

I need to use C in Linux with PCRE to match in this string "<test>a</test> <test>b</test> <test>c</Test>" to get the letters a, b, and c.
I found this script in stackoverflow, it is good but does not work for all the matches. Only the first matches. Why?
/*
* gcc pcre1.c -lpcre
*/
#include <pcre.h>
#include <stdio.h>
#include <string.h>
int main()
{
pcre* compile;
pcre_extra* extra;;
int res;
int ovector[30];
const char* pattern="(?i)<test>(.*?)</test>";
const char* errptr;
const char* match[30];
const char** match_list = match;
int erroffset;
char* test_str = "<test>a</test> <test>b</test> <test>c</Test>";
compile = pcre_compile(pattern, PCRE_MULTILINE,&errptr,&erroffset,NULL);
if ( compile == NULL ) {
fprintf(stderr, "ERROR: Could not compile '%s' : %s\n", pattern, errptr);
exit(1);
}
extra = pcre_study(compile, 0, &errptr);
if ( errptr != NULL ) {
fprintf(stderr, "ERROR: Could not study '%s' : %s\n", pattern, errptr);
exit(1);
}
res = pcre_exec(compile,extra,test_str,strlen(test_str),0,0,ovector,sizeof(ovector));
if ( res == 0 ) {
res = 30/3;
}
if ( res > 0 ) {
pcre_get_substring_list(test_str, ovector, res, &match_list);
printf("buffer : %s\n", test_str);
printf("match :\n");
for ( int i = 0; match_list[i]; ++ i ) {
printf("%9s%s\n", " ", match_list[i]);
printf("\n");
}
if ( match_list )
pcre_free_substring_list(match_list);
}
printf("\n");
if (compile)
pcre_free(compile);
if (extra)
pcre_free(extra);
}```
thanks
I changed your code slightly, but this works as you expect now:
% ./pcre1
a
b
c
I'll list the changes and why I made them:
We will be using ovector before it it is set initially, so zero out.
int ovector[30] = {0};
The pcre_get_substring() will be easier for you to use for this purpose, so I switched away from pcre_get_substring_list().
We didn't need match[], as pcre_get_substring() calls pcre_malloc().
The variable match_list must be char* as we are passing it as &match_list.
const char* match_list;
The function pcre_exec() expects ovecsize to be a multiple of 3.
3*(sizeof(ovector)/3)
I wrapped the pcre_exec() call in a while loop.
I used pcre_get_substring(), printf(), and pcre_free_substring() instead.
// gcc pcre1.c -lpcre
#include <pcre.h>
#include <stdio.h>
#include <string.h>
int main()
{
pcre* compile;
pcre_extra* extra;;
int res;
int ovector[30] = {0};
const char* pattern="(?i)<test>(.*?)</test>";
const char* errptr;
const char* match_list;
int erroffset;
char* test_str = "<test>a</test> <test>b</test> <test>c</Test>";
compile = pcre_compile(pattern, PCRE_MULTILINE,&errptr,&erroffset,NULL);
if ( compile == NULL ) {
fprintf(stderr, "ERROR: Could not compile '%s' : %s\n", pattern, errptr);
exit(1);
}
extra = pcre_study(compile, 0, &errptr);
if ( errptr != NULL ) {
fprintf(stderr, "ERROR: Could not study '%s' : %s\n", pattern, errptr);
exit(1);
}
while ((res = pcre_exec(compile, extra, test_str, strlen(test_str), ovector[1], 0, ovector, 3*(sizeof(ovector)/3))) >= 0) {
if (pcre_get_substring(test_str, ovector, res, 1, &match_list) >= 0) {
printf("%s\n", match_list);
pcre_free_substring(match_list);
}
}
if (compile)
pcre_free(compile);
if (extra)
pcre_free(extra);
}

Fatfs string comparison for fno.fname

I have an issue regarding reading the size of a file on my SD card. The sizes of these files will vary in the application, I therefore, need to get the size of the file. If I run the below code I can see the files in my directory along with their size.
What I need to do is store the size of the DATA.CSV file as a variable.
How do I add a comparision to get the fno.fsize when the listing is "data.csv
This prints out:
00> Listing directory: /00> 0 EVENTLOG.CSV <DIR> SYSTEM~1 183600 DATA.CSV ```
void Get_data_csv_file_size()//of the data csv
{
if(Logging_UART_SD_CARD == true){NRF_LOG_INFO("\r\n Listing directory: /");}
ff_result = f_opendir(&dir, "/");
if (ff_result)
{
if(Logging_UART_SD_CARD == true){NRF_LOG_INFO("Directory listing failed!");}
}
do
{
ff_result = f_readdir(&dir, &fno);
if (ff_result != FR_OK)
{
if(Logging_UART_SD_CARD == true){NRF_LOG_INFO("Directory read failed.");}
}
if (fno.fname[0])
{
if (fno.fattrib & AM_DIR)
{
if(Logging_UART_SD_CARD == true){NRF_LOG_RAW_INFO(" <DIR> %s",(uint32_t)fno.fname);}
}
else
{
if(Logging_UART_SD_CARD == true){NRF_LOG_RAW_INFO("%9lu %s", fno.fsize, (uint32_t)fno.fname);}
if(strcmp((uint32_t)fno.fname, "data.csv")==0)//Convert both to a uint32_t
{
Size_of_file = fno.fsize;//Set the size of the file
//Does not get to here
}
}
}
}
while (fno.fname[0]);
}
Note this is programmed in C using a arm board. What operation do I need to do so I can get the file size?
I want something like:
if(fno.name == "data.csv")
{
Size_of_file = fno.fsize;//Set the size of the file
}
Just in case you determine using an implementation of stricmp() would be useful, here is one that I have used:
//case insensitive string compare
int cb_stricmp(const char *a, const char *b)
{
if(!a) return -1;
if(!b) return -1;
int ch_a = 0;
int ch_b = 0;
while ( ch_a != '\0' &&ch_a == ch_b)
{
ch_a = (unsigned char) *a++;
ch_b = (unsigned char) *b++;
ch_a = tolower(toupper(ch_a));
ch_b = tolower(toupper(ch_b));
}
return ch_a - ch_b;
}
Found a solution using snprintf neeeded to convert fno.fname to a string to compare the result.
char string_test[9] = "DATA.CSV";
char name_test[9]={0};
snprintf(name_test, sizeof(name_test),"%s",(uint32_t)fno.fname);
NRF_LOG_INFO("Result is: %s",name_test);
int result = strcmp(name_test, string_test);
if(result==0)//Convert both to a uint32_t
{
Size_of_file = fno.fsize;//Set the size of the file
NRF_LOG_INFO("Size of file using is: %9lu",Size_of_file);
}

How to create AT Commands Parser in C to get the incoming string from USART1?

I want to get the string from USART1 of STM32VLDiscovery (STM32F100X4) and write an AT Command Parser from the string received from USART1.
Below are the concept that I have developed but I am not sure whether it's correct or not.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dosomethinga.h"
void dosomethingB();
void GET_AT_COMMAND(char*);
void takecommand(char *, char *);
int quit;
int main()
{ char buff[15];
char command = '\0';
quit = 0;
while(!quit)
{
printf("Enter your command: ");
scanf("%s", &buff);
if (buff[0] == 'A' && buff[1] == 'T' && buff[2] == '+')
{
GET_AT_COMMAND(buff);
}
}
}
void dosomethingB()
{
printf("dosomethingB called \n");
}
void GET_AT_COMMAND(char *text)
{
int command;
char temp[10] = "";
/*if(text[3] == 'A')
command = 1;
else if(text[3] == 'B')
command = 2;
else if(text[3] == 'Z')
command = 3;
*/
takecommand(text,temp);
if (strcmp(temp, "CALLA") == 0)
command = 1;
if (strcmp(temp, "CALLB") == 0)
command = 2;
if (strcmp(temp, "Z") == 0)
command = 3;
switch(command)
{
case 1:
dosomethingA();
break;
case 2:
printf("herehere.... \n");
dosomethingB();
break;
case 3:
printf("Exiting program.... \n");
quit = 1;
break;
default:
printf("Nothing to do here \n");
}
}
void takecommand(char *mycmd, char *hold)
{
int i;
for(i = 0; i < 10 ; i++)
{
hold[i] = mycmd[i+3];
}
}
Can anyone explain on the steps that I should do? Thanks.
Basicly you should wait an attention "AT" from the input and ignore anything before it.
For example inputs "XYZATZ\r" and "AaatZ\r" should be both handled as a "ATZ" command.
There can also be short pause between 'A' and 'T' (and all other chars of commands too), because human may type those commands.
By the default all commands end to "\r" character.
See more about AT commands from ITU-T documentation. For example from V.250 standard.
There are probably many alternative ways to implement that. The best alternative depends on your needs. If you are going to implement all AT-commands of mobile-terminal, then you should spend more time for the parser. If you want make some test application for few commands, then your implementation could be simple as your provided one.
I have developed this AT command parser, this could be use for reference.
When you get data from UART1 just call this method at_wait_msg() to parse the AT message
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
static const char *AT_HEADER = "AT";
static const char *AT_DEVICE_PROFILE = "DR";
static const char *AT_SET_DEVICE = "SD";
static const char AT_EOF = '\r';
typedef enum {
DeviceProfile,
SetDevice,
Error
} AT_Msg_Type;
typedef struct {
char header[3];
char command[3];
char data[128];
} AT_Msg_Data;
static void at_wait_msg(char text);
static void at_wait_msg_complete(char *text);
static void at_parse_msg(AT_Msg_Data *data);
static AT_Msg_Type at_check_format(AT_Msg_Data *data);
static char _rx_data[512];
static uint16_t _rx_index = 0;
int main()
{
//example data getting from UART1
char text[] = "ATDR\rATSD123456abchelloworld\r1123ATssa\r";
for (int i = 0; i < strlen(text) + 1; i++) {
//to simulate getting data from UART1 byte per byte
at_wait_msg(text[i]);
}
return 0;
}
static void at_wait_msg(char text)
{
_rx_data[_rx_index++] = text;
if (text == AT_EOF) {
at_wait_msg_complete(_rx_data);
_rx_index = 0;
}
}
static void at_wait_msg_complete(char *text)
{
AT_Msg_Data data;
int result = sscanf_s(_rx_data, "%2s%2s%s\r",
data.header, sizeof(data.header),
data.command, sizeof(data.command),
data.data, sizeof(data.data));
if (result >= 2) {
at_parse_msg(&data);
}
}
static void at_parse_msg(AT_Msg_Data *data)
{
AT_Msg_Type type = at_check_format(data);
switch (type) {
case DeviceProfile:
printf("device profile\r\n");
break;
case SetDevice:
printf("settings %s\r\n", data->data);
break;
case Error:
default:
printf("Error\r\n");
break;
}
}
static AT_Msg_Type at_check_format(AT_Msg_Data *data)
{
if (strcmp(data->header, AT_HEADER) != 0) {
return Error;
}
if (strcmp(data->command, AT_DEVICE_PROFILE) == 0) {
return DeviceProfile;
}
if (strcmp(data->command, AT_SET_DEVICE) == 0) {
return SetDevice;
}
return Error;
}

The Code doesn't print the expected output, why?

The following code doesn't behave as expected ..
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
struct dest
{
char filename[20], keyword[20];
bool opened;
FILE * file;
};
void display_data(const struct dest p) {
printf("Keyword: %s, Filename: %s, Used: %s\n", p.keyword, p.filename, p.opened ? "Yes" : "No");
}
int main(int argc, char const *argv[])
{
// declaring variables
float lon, lat;
char info[80];
FILE *reader;
// checking required arguments
if ((argc+1) % 2 || argc < 2) {
fprintf(stderr, "Usage: %s file_to_read file_for_unknown type file type file ...\n", argv[0]);
return 2;
}
// opening the reader
if (!(reader = fopen(argv[1], "r"))) {
fprintf(stderr, "File can't be accessed: %s\n", argv[1]);
return 2;
}
// creating important globals
const short pairs = (argc-3)/2;
struct dest data[pairs];
struct dest other;
strcpy(other.filename, argv[2]);
other.opened = false;
// gathering data
short times = 4;
for(short i = 4; i < argc; i += 2) {
data[i-times].opened = false;
strcpy(data[i-times].keyword, argv[i-1]);
strcpy(data[i-times].filename, argv[i]);
times += 1;
}
// finally, scanning the file ..
struct dest *use_f; // pointer for the wanted destination ..
bool known;
while (fscanf(reader, "%f,%f,%79[^\n]", &lat, &lon, info)) {
// deciding which file to use ..
known = false;
for(short i=0; i < pairs; ++i) {
if (strstr(info, data[i].keyword)) {
known = true;
use_f = &data[i];
}
}
if (!(known)) {
use_f = &other;
}
// checking the file ..
if (!((*use_f).opened)) {
(*use_f).file = fopen((*use_f).filename, "w");
(*use_f).opened = true;
}
// writing to the file ..
fprintf((*use_f).file, "%f,%f,%s\n", lat, lon, info);
}
// closing all data streams, and informing user ..
for (short i=0; i < pairs; ++i) {
display_data(data[i]);
if (data[i].opened) {
fclose(data[i].file);
data[i].opened = false;
}
}
fclose(reader);
fclose(other.file);
return 0;
}
The command used to run it is this ..
./categorize spooky.csv other.csv UFO UFOS.csv # I get no output at all
It seems that the while loop doesn't actually end, which is mysterious, because the file (spooky.csv) is only 11 lines !
30.685163,-68.137207,Type=Yeti
28.304380,-74.575195,Type=UFO
29.132971,-71.136475,Type=Ship
28.343065,-62.753906,Type=Elvis
27.868217,-68.005371,Type=Goatsucker
30.496017,-73.333740,Type=Disappearance
26.224447,-71.477051,Type=UFO
29.401320,-66.027832,Type=Ship
37.879536,-69.477539,Type=Elvis
22.705256,-68.192139,Type=Elvis
27.166695,-87.484131,Type=Elvis
It just keeps writing to other.file, yet I don't know why ..
The program simply doesn't end, can anybody explain things to me ?
From the fscanf() manpage: "The value EOF is returned if an input failure occurs before any conversion (such as an end-of-file) occurs."
Here's a hint... EOF isn't equal to 0. Your while-loop never terminates.

Search for a file in $PATH on Linux in C

I would like to test whether GNUPlot is installed on the system on which my program is running.
For that, I figured I'll test for the existence of the gnuplot executable in the user's install locations through stat() call.
However, I don't know how to read the $PATH environment variable in C so I can test for the existence of the file in those locations.
Use the getenv() function.
char *paths = getenv("PATH");
To loop through the parts of the column-separated list of paths, use strchr():
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *dup = strdup(getenv("PATH"));
char *s = dup;
char *p = NULL;
do {
p = strchr(s, ':');
if (p != NULL) {
p[0] = 0;
}
printf("Path in $PATH: %s\n", s);
s = p + 1;
} while (p != NULL);
free(dup);
Use getenv() to inspect the value of a particular environment variable.
To read the PATH environment variable, use getenv("PATH").
However, if you just want to run gnuplot if it's available, and perform some fallback action if it's not, then you should just try to run it (e.g. with fork and execvp or posix_spawnp) and handle the failure case.
Let which do the work for you
if (system("which gnuplot"))
/* not installed or not in path or not executable or some other error */
If you need the full path for some reason, run which with popen.
Or run gnuplot with some flag which makes it return immediately with 0 */
if (system("gnuplot --version"))
/* not installed ... */
I had a similar need and resolved it by copying libc execvp code source. I did in the most cross platform I could think of(I have no guatanty and tested just on linux). If it's not such a matter to you and you care about performances, you should use acess or _acess. Note that there is no error check whatsoever and it will just return NULL or a founded openable file in path.
The accepted answer is sometime not acceptable, when you are willing to run the same small binary over and over, redoing the path search every time by calling execvp can be non negligable overhead.
So here is the code and associated tests, you will be mainely interested in the search_in_path_openable_file function.
.h file:
bool is_openable_file(char* path);
/*Return true if path is a readable file. You can call perror if return false to check what happened*/
char* search_in_path_openable_file(char* file_name);
/*Search into PATH env variable a file_name and return the full path of the first that is openable, NULL if not in path*/
char* search_executable(char* file_name);
/*Search file, if not openable and not absolute path(contain /), look for opennable file in the path. If nothing is openable, return NULL. If something is openable, return it as it is (not guaratented to have a full path, but garatanted to be openable)*/
.c file:
#include "file_info.h"
#include <stdio.h>
#include <string.h> //strcpy
/*I wanted to do a really cross platform way. access or _acess may be better*/
bool is_openable_file(char *path) {
FILE *fp = fopen(path, "r");
if (fp) {
// exists
fclose(fp);
return true;
}
return false;
}
bool is_openable_file_until(char *path_begin, size_t until) {
char old = path_begin[until];
path_begin[until] = 0;
bool res = is_openable_file(path_begin);
path_begin[until] = old;
return res;
}
/*You may thinks that libc would have done this function and use it to implement execp function family, but you would be wrong. They just hardcoded the search in every execp function. Unbelievable.
*
* So this function is a modification of their execvp function.
*
* */
char* search_in_path_openable_file(char* file){
char *path = getenv("PATH");
if (path == NULL)
return NULL;
size_t pathlen = strlen(path);
size_t len = strlen(file) + 1;
int total_max_size=pathlen + len;
char* buf=malloc(sizeof(char)*total_max_size);
if (*file == '\0') {
return NULL;
}
char *name, *p;
/* Copy the file name at the top. */
name = memcpy(buf + pathlen + 1, file, len);
/* And add the slash. */
*--name = '/';
p = path;
do {
char *startp;
path = p;
//Let's avoid this GNU extension.
//p = strchrnul (path, ':');
p = strchr(path, ':');
if (!p)
p = strchr(path, '\0');
if (p == path)
/* Two adjacent colons, or a colon at the beginning or the end
of `PATH' means to search the current directory. */
startp = name + 1;
else
startp = memcpy(name - (p - path), path, p - path);
/* Try to execute this name. If it works, execv will not return. */
if (is_openable_file(startp))
return startp;
} while (*p++ != '\0');
/* We tried every element and none of them worked. */
return NULL;
}
char* search_executable(char* file_name){
if (is_openable_file(file_name)){//See realpath manual bug. Watch out
return file_name;
}
if (strchr (file_name, '/') != NULL) //Don't search when it contains a slash.
return NULL;
return search_in_path_openable_file(file_name);
}
tests (As you see I did not test a lot this function, there may exist some problem, use at your risk):
#include "file_info.h"
#include "munit.h"
#include <stdbool.h>
#include <unistd.h>
static void generate_search_executable(char* test_str, char* expected){
char* res= search_executable(test_str);
if (res==NULL)
munit_assert_ptr(expected,==,NULL );
else
munit_assert_string_equal(expected,res);
}
static void generate_openable(char* test_str, bool expected){
bool res= is_openable_file(test_str);
munit_assert_true(expected==res);
}
static void generate_path_search(char* test_str, char* expected_res){
char* res= search_in_path_openable_file(test_str);
if (res==NULL)
munit_assert_ptr(expected_res,==,NULL );
else
munit_assert_string_equal(expected_res,res);
}
//TODO do for other platform, better test would also set path to a custom folder that we control
#define EXISTING_FILE_NOT_IN_PATH "/usr/include/stdlib.h"
#define EXISTING_FILE_IN_PATH "ls"
#define EXISTING_FILE_IN_PATH_FULL "/bin/ls"
#define NOT_EXISTING_FILE "/usrarfzsvdvwxv/ixvxwvnxcvcelgude/ssdvtdbool.h"
int main() {
generate_openable(EXISTING_FILE_IN_PATH, false);
generate_openable(EXISTING_FILE_NOT_IN_PATH, true);
generate_openable(NOT_EXISTING_FILE, false);
generate_path_search(EXISTING_FILE_IN_PATH, EXISTING_FILE_IN_PATH_FULL);
generate_path_search(NOT_EXISTING_FILE, NULL);
generate_path_search(EXISTING_FILE_NOT_IN_PATH, NULL);
generate_search_executable(EXISTING_FILE_IN_PATH, EXISTING_FILE_IN_PATH_FULL);
generate_search_executable(NOT_EXISTING_FILE, NULL);
generate_search_executable(EXISTING_FILE_NOT_IN_PATH, EXISTING_FILE_NOT_IN_PATH);
generate_search_executable("", NULL );
//test current folder existence(maybe it just depend on path containing .,I am not sure, in that case we should remove thoses tests
generate_search_executable("file_info_test", "file_info_test" );
}
To build on one of the previous answers, you can use getenv to get the contents of PATH and then iterate over its components. Instead of using strchr you can use strsep:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>
bool exists(const char fname[])
{
return access(fname, F_OK | X_OK) != -1;
}
bool find_in_path(const char name[], char *fullpath, size_t sz) {
char *paths = strdup(getenv("PATH"));
char *tmp = paths; // to use in free
const char *item;
bool found = false;
while ((item = strsep(&paths, ":")) != NULL) {
snprintf(fullpath, sz, "%s/%s", item, name);
if (exists(fullpath)) {
found = true;
break;
}
}
free(tmp);
return found;
}
int main() {
char fullpath[512];
bool found = find_in_path("uname", fullpath, sizeof(fullpath));
if (found) {
printf("found: %s\n", fullpath);
}
return 0;
}
Using C++17 to get a vector of path elements.
% a.out ls
/bin/ls
#include <iostream>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
using namespace std;
vector<string> get_paths (string str)
{
vector<string> result;
while(!str.empty())
{
if (auto pos { str.find_first_of (':') }; pos == string::npos)
{
result.push_back(str);
break;
}
else
{
result.emplace_back(str.substr(0, pos));
str.erase(0, pos + 1);
}
}
return move(result);
}
bool exist(const string& fname, int perm=F_OK) { return access(fname.c_str(), perm) == 0; }
int main (int argc, char *argv[])
{
auto result { get_paths(getenv("PATH")) };
for (auto pp : result)
{
string npath { pp };
if (*npath.rbegin() != '/')
npath += '/';
npath += argv[1];
if (exist(npath))
cout << npath << endl;
}
return 0;
}

Resources