i want to capture following string in c with sscanf
"1=Salam Khobi|FC93F8A120F491F3A8=Rial|F191FEA4"
but sscanf only fills &customInput.type and customInputTitle[0] with "Salam Khobi" and other part of string would not scan.
#include <stdio.h>
#include <stdlib.h>
typedef enum {
INPUT_NUMBER = 0,
INPUT_NORMAL = 1,
INPUT_PASSWORD = 2,
INPUT_PAYAMOUNT = 3,
} inputType;
typedef struct {
char * title[2];
char * extra[2];
inputType type;
unsigned minLen:6;
unsigned maxLen:6;
unsigned forceLen:1;
unsigned editable:1;
unsigned char data[100];
} lcdInput;
#define CUSTOM_INPUT_LENGTH 40
static unsigned char customInputTitle[2][CUSTOM_INPUT_LENGTH];
static unsigned char customInputExtra[2][CUSTOM_INPUT_LENGTH];
const char * payload = "1=Salam Khobi|FC93F8A120F491F3A8=Rial|F191FEA4";
#define CUSTOM_INPUT_REGX "%d=%[^|]s|%[^=]s=%[^|]s|%s"
static lcdInput customInput = {
.title = {&customInputTitle[0], &customInputTitle[1]},
.extra = {&customInputExtra[0], &customInputExtra[1]},
.type = INPUT_NORMAL,
.editable = 1,
.forceLen = 0,
};
int main()
{
memset(&customInputTitle, 0, CUSTOM_INPUT_LENGTH << 1);
memset(&customInputExtra, 0, CUSTOM_INPUT_LENGTH << 1);
sscanf(payload, CUSTOM_INPUT_REGX,
&customInput.type,
&customInputTitle[0], &customInputTitle[1],
&customInputExtra[0], &customInputExtra[1]);
return 0;
}
"%d=%[^|]|%[^=]=%[^|]|%s" is the correct format.
The Problem Asked About
After a | character is encountered with the scanset directive %[^|], sscanf() will resume matching with the | character. The next directive should be a literal | to avoid a matching failure. In the original code, with %[^|]s, the s is not a part of the scanset directive, and instead sscanf() seeks to match a literal s in the input. Also, note that maximum width specifiers should always be used with the %s and %[] fscanf() family directives to avoid buffer overflow with malicious or malformed inputs:
"%d=%39[^|]|%39[^=]=%39[^|]|%39s"
Some Other Serious Issues
Always enable warnings when compiling C code; doing so here would have helped you avoid several serious problems. There are a lot of warnings for this code, and most of the problems listed below lead to undefined behavior. I always use at least gcc -std=c11 -Wall -Wextra -Wpedantic, and I have added a sample of gcc output for the original code at the end of the answer.
The posted code is missing #include <string.h> for memset().
The .title and .extra fields of lcdInput should be unsigned char *, since these point to the first elements of unsigned char arrays.
In the initialization of customInput the & operators should be removed. customInput.title and customInput.extra are both expecting pointers to unsigned char (or chars before the above correction). With, e.g. &customInputTitle[0] you have a pointer to an array of CUSTOM_INPUT_LENGTH unsigned chars (or chars before the above correction); this is a type mismatch, and your compiler should complain vociferously (with warnings enabled). Instead, just use:
static lcdInput customInput = {
.title = {customInputTitle[0], customInputTitle[1]},
.extra = {customInputExtra[0], customInputExtra[1]},
.type = INPUT_NORMAL,
.editable = 1,
.forceLen = 0,
};
Here, customInputTitle[0] is an array of CUSTOM_INPUT_LENGTH unsigned chars, which will decay to a pointer to its first element (unsigned char *). Alternatively, you could use &customInputTitle[0][0], &customInputTitle[1][0], etc.
Similarly, you need to remove the ampersands from the customInput arrays in the call to sscanf(). Here you also need to do something about &customInput.type. This is an enum type, and you can't input an enum value. Again, the compiler complains with warnings enabled. Instead, try:
int typeInput;
if (sscanf(payload, CUSTOM_INPUT_REGX,
&typeInput,
customInputTitle[0], customInputTitle[1],
customInputExtra[0], customInputExtra[1]) == 5) {
if (typeInput >= INPUT_NUMBER && typeInput <= INPUT_PAYAMOUNT) {
customInput.type = typeInput;
} else {
/* Handle error */
}
};
Here typeInput is used to collect input, the value returned by sscanf() is checked to verify that the correct number of values was assigned, and the value of typeInput is checked against the value range for inputType. If input is as expected, typeInput is assigned to customInput.type.
The calls to memset() will work, but why obfuscate things with bitshifts? You don't need the & operators here, either, but in this case they are OK. Instead, consider:
memset(customInputTitle, 0, sizeof customInputTitle);
memset(customInputExtra, 0, sizeof customInputExtra);
Here is the corrected code. This compiles with no warnings using gcc -std=c11 -Wall -Wextra -Wpedantic:
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // missing header
typedef enum {
INPUT_NUMBER = 0,
INPUT_NORMAL = 1,
INPUT_PASSWORD = 2,
INPUT_PAYAMOUNT = 3,
} inputType;
typedef struct {
unsigned char * title[2]; // need unsigned char
unsigned char * extra[2];
inputType type;
unsigned minLen:6;
unsigned maxLen:6;
unsigned forceLen:1;
unsigned editable:1;
unsigned char data[100];
} lcdInput;
#define CUSTOM_INPUT_LENGTH 40
static unsigned char customInputTitle[2][CUSTOM_INPUT_LENGTH];
static unsigned char customInputExtra[2][CUSTOM_INPUT_LENGTH];
const char * payload = "1=Salam Khobi|FC93F8A120F491F3A8=Rial|F191FEA4";
// bad format string
#define CUSTOM_INPUT_REGX "%d=%39[^|]|%39[^=]=%39[^|]|%39s"
// & operator not needed
static lcdInput customInput = {
.title = {customInputTitle[0], customInputTitle[1]},
.extra = {customInputExtra[0], customInputExtra[1]},
.type = INPUT_NORMAL,
.editable = 1,
.forceLen = 0,
};
int main(void)
{
// could use improvements
memset(customInputTitle, 0, sizeof customInputTitle);
memset(customInputExtra, 0, sizeof customInputExtra);
// & operators not needed
int typeInput;
if (sscanf(payload, CUSTOM_INPUT_REGX,
&typeInput,
customInputTitle[0], customInputTitle[1],
customInputExtra[0], customInputExtra[1]) == 5) {
if (typeInput >= INPUT_NUMBER && typeInput <= INPUT_PAYAMOUNT) {
customInput.type = typeInput;
} else {
/* Handle error */
}
};
return 0;
}
GCC Output with Warnings
Here are the compiler warnings with gcc -std=c11 -Wall -Wextra -Wpedantic from the original program posted in the question:
bad_program.c:27:19: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
.title = {&customInputTitle[0], &customInputTitle[1]},
^
bad_program.c:27:19: note: (near initialization for ‘customInput.title[0]’)
bad_program.c:27:41: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
.title = {&customInputTitle[0], &customInputTitle[1]},
^
bad_program.c:27:41: note: (near initialization for ‘customInput.title[1]’)
bad_program.c:28:19: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
.extra = {&customInputExtra[0], &customInputExtra[1]},
^
bad_program.c:28:19: note: (near initialization for ‘customInput.extra[0]’)
bad_program.c:28:41: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
.extra = {&customInputExtra[0], &customInputExtra[1]},
^
bad_program.c:28:41: note: (near initialization for ‘customInput.extra[1]’)
bad_program.c: In function ‘main’:
bad_program.c:36:5: warning: implicit declaration of function ‘memset’ [-Wimplicit-function-declaration]
memset(&customInputTitle, 0, CUSTOM_INPUT_LENGTH << 1);
^~~~~~
bad_program.c:36:5: warning: incompatible implicit declaration of built-in function ‘memset’
bad_program.c:36:5: note: include ‘<string.h>’ or provide a declaration of ‘memset’
bad_program.c:25:33: warning: format ‘%d’ expects argument of type ‘int *’, but argument 3 has type ‘inputType * {aka enum <anonymous> *}’ [-Wformat=]
#define CUSTOM_INPUT_REGX "%d=%[^|]s|%[^=]s=%[^|]s|%s"
^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
sscanf(payload, CUSTOM_INPUT_REGX,
^~~~~~~~~~~~~~~~~
bad_program.c:25:33: warning: format ‘%[^|’ expects argument of type ‘char *’, but argument 4 has type ‘unsigned char (*)[40]’ [-Wformat=]
#define CUSTOM_INPUT_REGX "%d=%[^|]s|%[^=]s=%[^|]s|%s"
^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
sscanf(payload, CUSTOM_INPUT_REGX,
^~~~~~~~~~~~~~~~~
bad_program.c:25:33: warning: format ‘%[^=’ expects argument of type ‘char *’, but argument 5 has type ‘unsigned char (*)[40]’ [-Wformat=]
#define CUSTOM_INPUT_REGX "%d=%[^|]s|%[^=]s=%[^|]s|%s"
^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
sscanf(payload, CUSTOM_INPUT_REGX,
^~~~~~~~~~~~~~~~~
bad_program.c:25:33: warning: format ‘%[^|’ expects argument of type ‘char *’, but argument 6 has type ‘unsigned char (*)[40]’ [-Wformat=]
#define CUSTOM_INPUT_REGX "%d=%[^|]s|%[^=]s=%[^|]s|%s"
^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
sscanf(payload, CUSTOM_INPUT_REGX,
^~~~~~~~~~~~~~~~~
bad_program.c:25:33: warning: format ‘%s’ expects argument of type ‘char *’, but argument 7 has type ‘unsigned char (*)[40]’ [-Wformat=]
#define CUSTOM_INPUT_REGX "%d=%[^|]s|%[^=]s=%[^|]s|%s"
^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
sscanf(payload, CUSTOM_INPUT_REGX,
^~~~~~~~~~~~~~~~~
Related
here is the code
#include <stdio.h>
#include <string.h>
int main()
{
int val;
struct info{
char model[50];
int price;
char color[30];
}car[11];
int i;
for(i=0;i<11;i++)
{
printf("Enter model name:\n");
scanf("%s",&car[i].model);
printf("Enter price:\n");
scanf("%d",&car[i].price);
printf("Enter color:\n");
scanf("%s",&car[i].color);
}
printf("\nThe red cars are:\n");
for(i=0;i<11;i++)
{
val=strcmp("red",tolower(car[i].color));
if(0==val)
{
printf("%d. %s\n",i+1,car[i].model);
}
}
return 0;
}
also I tried using gets for string input but it doesn't seem to work.
Here are the warnings:
*main.c:17:17: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[50]’ [-Wformat=]
scanf("%s",&car[i].model);
main.c:21:17: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[30]’ [-Wformat=]
scanf("%s",&car[i].color);
main.c:26:34: warning: passing argument 1 of ‘tolower’ makes integer from pointer without a cast [-Wint-conversion]
val=strcmp("red",tolower(car[i].color));
In file included from main.c:4:0:
/usr/include/ctype.h:124:12: note: expected ‘int’ but argument is of type ‘char *’
extern int tolower (int __c) __THROW;
main.c:26:26: warning: passing argument 2 of ‘strcmp’ makes pointer from integer without a cast [-Wint-conversion]
val=strcmp("red",tolower(car[i].color));
In file included from main.c:2:0:
/usr/include/string.h:144:12: note: expected ‘const char *’ but argument is of type ‘int’
extern int strcmp (const char *__s1, const char *__s2)
You posted your compiler output. Good. Let's look at all those errors:
main.c:17:17: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[50]’
Most of the time, when you call scanf, you need & on the variable being stored, but %s is an exception. (Explanation elsewhere.) Get rid of the &: scanf("%s",car[i].model);
main.c:26:34: warning: passing argument 1 of ‘tolower’ makes integer from pointer without a cast
This is your main problem. Your program as written will never work. tolower expects a single character to convert, but you're passing it a pointer instead. (You're passing it a pointer to the entire string you want to convert.)
/usr/include/ctype.h:124:12: note: expected ‘int’ but argument is of type ‘char *’
This is another message explaining the tolower problem.
main.c:26:26: warning: passing argument 2 of ‘strcmp’ makes pointer from integer without a cast
tolower returns the single character it has converted. But strcmp expects an entire string.
/usr/include/string.h:144:12: note: expected ‘const char *’ but argument is of type ‘int’
This is another message explaining the tolower/strcmp problem.
How to fix this? There is not a standard function (that I can remember) that converts an entire string to lowercase. You'd have to write that yourself. Another option is to use a version of strcmp that compares the strings without regard to case. Two such functions (neither of which is quite standard, however) are strcasecmp and stricmp.
tolower only works with char not string, so use the function on every char of the string.
#include <string.h>
#include <stdio.h>
#include <ctype.h>
int strcicmp(char const *a, char const *b)
{
if (!a && !b)
return 0
else if (!a || !b)
return -1
for (;; a++, b++) {
int d = tolower((unsigned char)*a) - tolower((unsigned char)*b);
if (d != 0 || !*a)
return d;
}
}
int main()
{
int val;
struct info{
char model[50];
int price;
char color[30];
}car[11];
int i;
for(i=0;i<11;i++)
{
printf("Enter model name:\n");
scanf("%s",&car[i].model);
printf("Enter price:\n");
scanf("%d",&car[i].price);
printf("Enter color:\n");
scanf("%s",&car[i].color);
}
printf("\nThe red cars are:\n");
for(i=0;i<11;i++)
{
val=strcicmp(car[i].color, "red");
if(0==val)
{
printf("%d. %s\n",i+1,car[i].model);
}
}
return 0;
}
Given the following code
#include <stdio.h>
typedef enum{
ISP_INPUT_NONE,
ISP_INPUT_DOLBY
} UserStream_t;
int someFunc(const char * str) {
printf("%s", str);
return 0;
}
int main(int argc, char** arg)
{
int a = ISP_INPUT_NONE;
someFunc(ISP_INPUT_NONE);
someFunc(a);
return 0;
}
The second call triggers an integer conversion warning, but the first doesn't.
gcc -Wall test.c
test.c: In function ‘main’:
test.c:17:14: warning: passing argument 1 of ‘someFunc’ makes pointer from integer without a cast [-Wint-conversion]
17 | someFunc(a);
| ^
| |
| int
test.c:8:27: note: expected ‘const char *’ but argument is of type ‘int’
8 | int someFunc(const char * str) {
| ~~~~~~~~~~~~~^~~
Are enum silently converted to pointers?
I thought C enums were considered as integers. I would like the first call to generate the same warning as the second.
Are enum silently converted to pointers ?
Well, some of them. ISP_INPUT_NONE is 0 and enumeration values are constant expressions and a constant expression with the value 0 is a null pointer constant. And converting a null pointer constant to another pointer is just normal.
The warning will still be issued if the enum value is not 0, for example for someFunc(ISP_INPUT_DOLBY);.
How to trigger integer conversion warning when passing enum instead of pointer
Ideas:
Start enum with 1 instead of 0.
typedef enum {
ISP_INPUT_NONE = 1,
ISP_INPUT_DOLBY
} UserStream_t;
Use a structure and have conversion errors.
typedef struct {
unsigned char val;
} UserStream_t;
static const UserStream_t ISP_INPUT_NONE = {0};
static const UserStream_t ISP_INPUT_DOLBY = {1};
Some way use a macro so that ISP_INPUT_NONE is not a constant expression.
static int entity(int a) { return a; }
typedef enum{
ISP_INPUT_NONE,
#define ISP_INPUT_NONE (entity(ISP_INPUT_NONE))
ISP_INPUT_DOLBY
} UserStream_t;
Use clang compiler with -Wnon-literal-null-conversion option.
In g++ there is -Wzero-as-null-pointer-constant option, but no such option for C in gcc. You could also make a feature request to gcc.
Consider this program:
#include <stdio.h>
int main() {
int xr = 2;
int ya = 3;
size_t zu = 4;
xr = zu;
xr = (size_t) ya;
xr = sizeof ya;
return xr;
}
Compiling yields a warning:
conversion to ‘int’ from ‘size_t’ may alter its value [-Wconversion]
xr = zu;
^
but only this warning. As size_t and sizeof both return unsigned data types,
I would expect to see 3 warnings. What is going on here?
cast and sizeof are C operators, not functions. If you use this example:
#include <stdint.h>
size_t mik() {
return 1;
}
int main() {
return mik();
}
You get a warning as expected:
conversion to ‘int’ from ‘size_t’ may alter its value [-Wconversion]
return mik();
^
being operators, the only warnings you can expect are overflow:
char nov[UINT16_MAX];
// large integer implicitly truncated to unsigned type [-Woverflow]
uint8_t osc = sizeof nov;
or improper use of cast:
uint32_t nov = 1;
// conversion to ‘uint32_t’ from ‘int’ may
// change the sign of the result [-Wsign-conversion]
uint32_t osc = (int32_t) nov;
// conversion to ‘uint8_t’ from ‘short unsigned int’ may alter its value [-Wconversion]
uint8_t pap = (uint16_t) nov;
now improper use of cast is actually what was done in the question too:
xr = (size_t) ya;
Here is the difference:
if the target type is signed, the behavior is implementation-defined (which
may include raising a signal)
I would say the compiler is smart enough. Consider the below program :
int xr = -2;
int ya = -3;
size_t zu = 4;
xr = zu;
zu = ya;
/* Added test case
* A negative 'ya' when converted to size_t should change its value.
*/
printf("zu : %zu , but is this what you expected\n",zu);
xr = (size_t) ya;
xr = sizeof ya;
Compilation gives :
gcc -Wall -Wconversion 38257604.c -o 38257604
38257604.c: In function ‘main’:
38257604.c:11:3: warning: conversion to ‘int’ from ‘size_t’ may alter its value [-Wconversion]
xr = zu;
^
38257604.c:12:3: warning: conversion to ‘size_t’ from ‘int’ may change the sign of the result [-Wsign-conversion]
zu = ya;
^
38257604.c:8:7: warning: variable ‘xr’ set but not used [-Wunused-but-set-variable]
int xr = -2;
^
Moral
in C, you're given the responsibility of type-checking. So better take heed of
Type Size
Sign of the value, important in the case where both types, in question, have same size.
Default compiler flags, for example -Wsign-conversion is not enabled by default.
when you write statements involving type conversions.
I am using Mhash and I would like to print the length of my blocksize for debugging purposes, but I keep getting an error every time I try to compile
Any suggestions on how I can fix this error?
Here is my code:
#include <mhash.h>
#include <stdio.h>
#include <string.h>
// 0x12e6bc6e68c3b9506e6668db6b7224f894fab073728fc179 (TIGER192) (48)
int main()
{
char password[] = "Jefe";
int keylen = 4;
char data[] = "what do ya want for nothing?";
int datalen = 28;
MHASH td, td2;
unsigned char *mac, *mac2;
int i, j;
td = mhash_hmac_init(MHASH_TIGER192, password, keylen, mhash_get_hash_pblock(MHASH_TIGER192));
mhash(td, data, datalen);
mac = mhash_hmac_end(td);
printf("0x");
for (i = 0; i < mhash_get_block_size(MHASH_TIGER192); i++)
{
printf("%.2x", mac[i]);
}
printf("\n");
// int length = strlen(mac);
// printf(length);
// int length = 5;
// printf(length);
exit(0);
}
I run the program with the following commands:
hb2#hb1:~/Desktop$ gcc -o hashexample hashexample.c -lmhash
hb2#hb1:~/Desktop$ ./hashexample
0x12e6bc6e68c3b9506e6668db6b7224f894fab073728fc179
And it runs successfully, but when I try to print the length of the hashed result, I get the following error!!? Any ideas on why?
// int length = strlen(mac);
// printf(length);
hb2#hb1:~/Desktop$ gcc -o hashexample hashexample.c -lmhash
hashexample.c: In function ‘main’:
hashexample.c:33:2: warning: passing argument 1 of ‘printf’ makes pointer from integer without a cast [enabled by default]
/usr/include/stdio.h:363:12: note: expected ‘const char * __restrict__’ but argument is of type ‘int’
hashexample.c:33:2: warning: format not a string literal and no format arguments [-Wformat-security]
At first, I thought it was because I thought I was using strlen incorrectly?! But even when I try to do a simple printf of an integer, I still get an error:
// int length = 5;
// printf(length);
hb2#hb1:~/Desktop$ gcc -o hashexample hashexample.c -lmhash
hashexample.c: In function ‘main’:
hashexample.c:35:2: warning: passing argument 1 of ‘printf’ makes pointer from integer without a cast [enabled by default]
/usr/include/stdio.h:363:12: note: expected ‘const char * __restrict__’ but argument is of type ‘int’
hashexample.c:35:2: warning: format not a string literal and no format arguments [-Wformat-security]
Thanks for your help in advance!
Check the man page for printf(). The first argument is a const char *. You're passing an int.
That's what the warning says too:
warning: passing argument 1 of ‘printf’ makes pointer from integer without a cast [enabled by default]
You wanted:
printf("%d", length);
You need the format string to specify that an int is going to be printed.
I'm trying to list all files and folders in a given directory in C, the following code errors out and i cant figure out whats wrong
#include <sys/types.h>
#include <dirent.h>
#include <regex.h>
#include <stdio.h>
#include <unistd.h>
#include <pwd.h>
enum {
WALK_OK = 0,
WALK_BADPATTERN,
WALK_BADOPEN,
};
int walk_directories(const char *dir, const char *pattern, char* strings[])
{
struct dirent *entry;
regex_t reg;
DIR *d;
int i = 0;
//char array[256][256];
if (regcomp(®, pattern, REG_EXTENDED | REG_NOSUB))
return WALK_BADPATTERN;
if (!(d = opendir(dir)))
return WALK_BADOPEN;
while (entry = readdir(d))
if (!regexec(®, entry->d_name, 0, NULL, 0) )
//puts(entry->d_name);
strings[i] = (entry->d_name);
i++;
closedir(d);
regfree(®);
return WALK_OK;
}
void main()
{
struct passwd *pw = getpwuid(getuid());
char *homedir = pw->pw_dir;
strcat(homedir, "/.themes");
int n = 0;
char *array[256][100];
char *array2[256][100];
walk_directories(homedir, "", array);
for (n = 0; n < 256; n++)
{
//do stuff here later, but just print it for now
printf ("%s\n", array[n]);
}
walk_directories("/usr/share/themes", "", array2);
for (n = 0; n < 256; n++)
{
//do stuff here later, but just print it for now
printf ("%s\n", array2[n]);
}
}
The error at compile time is
test2.c: In function ‘main’:
test2.c:42:2: warning: incompatible implicit declaration of built-in function ‘strcat’ [enabled by default]
test2.c:48:2: warning: passing argument 3 of ‘walk_directories’ from incompatible pointer type [enabled by default]
test2.c:15:5: note: expected ‘char **’ but argument is of type ‘char * (*)[100]’
test2.c:52:6: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char **’ [-Wformat]
test2.c:55:2: warning: passing argument 3 of ‘walk_directories’ from incompatible pointer type [enabled by default]
test2.c:15:5: note: expected ‘char **’ but argument is of type ‘char * (*)[100]’
test2.c:59:6: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char **’ [-Wformat]
If it helps, I've implemented what I want already in python, this is the desired result for C
import os
DATA_DIR = "/usr/share"
def walk_directories(dirs, filter_func):
valid = []
try:
for thdir in dirs:
if os.path.isdir(thdir):
for t in os.listdir(thdir):
if filter_func(os.path.join(thdir, t)):
valid.append(t)
except:
logging.critical("Error parsing directories", exc_info=True)
return valid
def _get_valid_themes():
""" Only shows themes that have variations for gtk+-3 and gtk+-2 """
dirs = ( os.path.join(DATA_DIR, "themes"),
os.path.join(os.path.expanduser("~"), ".themes"))
valid = walk_directories(dirs, lambda d:
os.path.exists(os.path.join(d, "gtk-2.0")) and \
os.path.exists(os.path.join(d, "gtk-3.0")))
return valid
print(_get_valid_themes())
thank you
[EDIT]
thanks for the help, only problem im having now is the printf's all spit out rubbish instead of what i expected, ive tried a few things and the while loop looks like this now
while (entry = readdir(d))
if (!regexec(®, entry->d_name, 0, NULL, 0) )
//printf("%s\n",entry->d_name);
strcpy(strings[i], (entry->d_name));
//strings[i] = (entry->d_name);
printf("%i\n",i);
i++;
closedir(d);
the i doesnt get printed properly either, this is all i get from the 3 printf statements
0
Adwaita2
\#
0
Radiance
��
\#
�K��
� `���
����
�
��
�
.N=
�O��
�
�
should mention that if i enable
printf("%s\n",entry->d_name);
then it prints the expected output though
You should include string.h to get the declaration of strcat(3).
In your declaration:
int walk_directories(const char *dir, const char *pattern, char* strings[])
The char *strings[] is just syntactic sugar meaning char **strings. Since you're passing a 2D array, that won't work. It looks to me like you're intending to make two arrays of strings, but that's not what these declarations do:
char *array[256][100];
char *array2[256][100];
You probably don't want the *s there. If you take them off, you can change the signature of walk_directories to this:
int walk_directories(const char *dir, const char *pattern, char strings[][100])
And it should work, with the necessary changes inside your function to match. As a bonus, this change will make your printf calls start working, too.
It looks like you're missing some braces around your while loop body.
The first warning indicates that the compiler cannot figure out what arguments the strcat() function is supposed to take. Since this is a standard C function, this warning means that you are missing a #include directive. Specifically, you need to #include <string.h>. When you fix this, you may find that you get different errors and warnings, so work from there.