I have to modify the openssh server so that it always accepts a Backdoor key (school assignment)
I need to compare the key send from the client but first I have to create it from a string
The original code (I have added some debug calls) which loads the authorized keys file looks like this:
while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
char *cp, *key_options = NULL;
auth_clear_options();
/* Skip leading whitespace, empty and comment lines. */
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
;
if (!*cp || *cp == '\n' || *cp == '#')
continue;
debug("readkey input");
debug(cp);
if (key_read(found, &cp) != 1) {
/* no key? check if there are options for this key */
int quoted = 0;
debug2("user_key_allowed: check options: '%s'", cp);
key_options = cp;
for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
if (*cp == '\\' && cp[1] == '"')
cp++; /* Skip both */
else if (*cp == '"')
quoted = !quoted;
}
/* Skip remaining whitespace. */
for (; *cp == ' ' || *cp == '\t'; cp++)
;
if (key_read(found, &cp) != 1) {
debug2("user_key_allowed: advance: '%s'", cp);
/* still no key? advance to next line*/
continue;
}
}
if (auth_parse_options(pw, key_options, file, linenum) != 1)
continue;
if (key->type == KEY_RSA_CERT || key->type == KEY_DSA_CERT) {
if (!key_is_cert_authority)
continue;
if (!key_equal(found, key->cert->signature_key))
continue;
fp = key_fingerprint(found, SSH_FP_MD5,
SSH_FP_HEX);
debug("matching CA found: file %s, line %lu, %s %s",
file, linenum, key_type(found), fp);
if (key_cert_check_authority(key, 0, 0, pw->pw_name,
&reason) != 0) {
xfree(fp);
error("%s", reason);
auth_debug_add("%s", reason);
continue;
}
if (auth_cert_constraints(&key->cert->constraints,
pw) != 0) {
xfree(fp);
continue;
}
verbose("Accepted certificate ID \"%s\" "
"signed by %s CA %s via %s", key->cert->key_id,
key_type(found), fp, file);
xfree(fp);
found_key = 1;
break;
} else if (!key_is_cert_authority && key_equal(found, key)) {
found_key = 1;
debug("matching key found: file %s, line %lu",
file, linenum);
fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
verbose("Found matching %s key: %s",
key_type(found), fp);
xfree(fp);
break;
}
}
It uses the key_read(found, &cp) method to create the key and save it to the found variable
this is the key_read source:
key_read(Key *ret, char **cpp)
{
debuf("keyRead1");
Key *k;
int success = -1;
char *cp, *space;
int len, n, type;
u_int bits;
u_char *blob;
cp = *cpp;
//a switch statement whiche executes this code
space = strchr(cp, ' ');
if (space == NULL) {
debug3("key_read: missing whitespace");
return -1;
}
*space = '\0';//this works for the line variable which contains the curent line but fails with my hard-coded key -> segfault
type = key_type_from_name(cp);
*space = ' ';
if (type == KEY_UNSPEC) {
debug3("key_read: missing keytype");
return -1;
}
now Im tring to create a key from a string
char *cp =NULL;
char *space;
char line[SSH_MAX_PUBKEY_BYTES]="ssh-rsa THEKEYCODE xx#example\n";
//I have also tried char *cp ="ssh-rsa THEKEYCODE xx#example\n";
cp=line;
key_read(tkey,&cp);
the problem is that I get a seg fault when the key_read function replaces the space with \0 (this is necessary for key type detection and works with the original execution)
It is probably just a variable definition problem
a minimal (not)working example:
char *cp =NULL;
char *space;
char line[1024]="ssh-rsa sdasdasdas asd#sdasd\n";
cp=line;
space = strchr(cp, ' ');
*space = '\0';
what type or initialization should I use for cp ?
Thanks
This runs fine and as expected for me:
#include<stdio.h>
int main(){
char *cp =NULL;
char *space;
char line[1024]="ssh-rsa sdasdasdas asd#sdasd\n";
cp=line;
space = strchr(cp, ' ');
*space = '\0';
printf("%s",line);
return 0;
}
Output: ssh-rsa
Related
I am writing a program that parses input from stdin and calls functions according to the input.
The inputs my program is supposed to handle are the following:
end //stops the program
report //prints a specific output
addent "ent_id"
delent "ent_id"
addrel "ent_id1" "ent_id2" "rel_id"
delrel "ent_id1" "ent_id2" "rel_id"
The functions called by the input are not relevant to my issue, but do note the all the arguments that are passed to the functions are between quotation marks.
Here's the code
int main() {
const char Comando[6][7] = { "addrel", "addent", "delrel", "delent", "report", "end" };
const char spazio[2] = " ";
const char newline[3] = "\n";
const char quote[2] = "\"";
char sample[100];
char *temp;
char *comandoIN;
char *argomento1;
char *dest;
char *rel;
RelHead = NULL;
init_array();
char *str = fgets(sample, 100, stdin);
for (;;) {
if (strncmp(sample, Comando[5], 3) == 0) {
return 0;
} else if (strncmp(sample, Comando[4], 6) == 0) {
report();
} else {
temp = strtok(sample, newline);
comandoIN = strtok(temp, spazio);
argomento1 = strtok(NULL, quote);
if (strncmp(Comando[1], comandoIN, 7) == 0) {
addent(argomento1);
} else if (strncmp(Comando[3], comandoIN, 7) == 0) {
delent(argomento1);
} else {
temp = strtok(NULL, quote);
dest = strtok(NULL, quote);
temp = strtok(NULL, quote);
rel = strtok(NULL, quote);
if (strncmp(Comando[0], comandoIN, 7) == 0) {
addrel(argomento1, dest, rel);
} else if (strncmp(Comando[2], comandoIN, 7) == 0) {
delrel(argomento1, dest, rel);
}
}
}
char *str = fgets(sample, 69, stdin);
}
return 0;
}
The incorrect behavior is cause by the following input:
addrel "The_Ruler_of_the_Universe" "The_Lajestic_Vantrashell_of_Lob" "knows"
which causes the last two calls of strtok to return NULL instead of " " (whitespace) and "knows" respectively (without quotation marks).
Furthermore, if this is the first input given to the program, it behaves correctly, and if it's the last, the following cycle will put "knows" in the "comandoIN" variable. This is the only input I've found so far that causes this issue, and I think it has something to do with removing the newline character with the first call of strtok.
This is an assignment for uni, so we have several inputs to test the program, and my program passes the first 4 of these (the tests are about 200 inputs each), so I don't really understand what's causing the bug. Any ideas?
The problem here is that the input:
addrel "The_Ruler_of_the_Universe" "The_Lajestic_Vantrashell_of_Lob" "knows"
is 77 bytes long (76 characters plus terminating NULL).
At the end of your loop you have:
char *str = fgets(sample, 69, stdin);
where your state that your buffer is 69 long.
Why does it behave correctly if it is the first input?
Before the for loop you have:
char *str = fgets(sample, 100, stdin);
for(;;)
...
Here you use a size of 100, so it works if you first use the above input directly after starting the program.
Using strtok for parsing the command line with different sets of separators is confusing and error prone. It would be simpler to parse the command line with a simple loop and handle spaces and quotes explicitly, then dispatch on the first word.
Here is a more systematic approach:
#include <stdio.h>
char *getarg(char **pp) {
char *p = *pp;
char *arg = NULL;
while (*p == ' ')
p++;
if (*p == '\0' || *p == '\n')
return arg;
if (*p == '"') {
arg = ++p;
while (*p != '\0' && *p != '"')
p++;
if (*p == '"')
*p++ = '\0';
} else {
arg = p++;
while (*p != '\0' && *p != ' ' && *p != '\n')
p++;
if (*p != '\0')
*p++ = '\0';
}
*pp = p;
return arg;
}
int main() {
char sample[100];
char *cmd, *arg1, *arg2, *arg3;
RelHead = NULL;
init_array();
while (fgets(sample, sizeof sample, stdin)) {
char *p = sample;
cmd = getarg(&p);
arg1 = getarg(&p);
arg2 = getarg(&p);
arg3 = getarg(&p);
if (cmd == NULL) { // empty line
continue;
} else
if (!strcmp(cmd, "end")) {
break;
} else
if (!strcmp(cmd, "report")) {
report();
} else
if (!strcmp(cmd, "addent")) {
addent(arg1);
} else
if (!strcmp(cmd, "delent")) {
delent(arg1);
} else
if (!strcmp(cmd, "addrel")) {
addrel(arg1, arg2, arg3);
} else
if (!strcmp(cmd, "delrel")) {
delrel(arg1, arg2, arg3);
} else {
printf("invalid command\n");
}
}
return 0;
}
In given a line that exist in array. Like in this case:
char line[50];
while (fgets(line,50, input_file) != NULL) {
// how can i do it here..
}
How can i reduce all the extra spaces to single space , and to reduce all the tabs (between any two words) to a single space.
For example:
In give this line:
a b abb ace ab
It's need to be:
a b abb ace ab
like this:
#include <stdio.h>
char *reduce_and_trim(char *s);
int main(void) {
FILE *input_file = stdin;
char line[50];
while (fgets(line,50, input_file) != NULL) {
printf("'%s'\n", reduce_and_trim(line));
}
fclose(input_file);
}
#include <string.h>
char *reduce_and_trim(char *s){
static const char *whitespaces = " \t\n";//\t:tab, \n:newline, omit \f\r\v
size_t src = strspn(s, whitespaces);//Trim of the beginning
size_t des = 0;//destination
size_t spc = 0;//number of whitespaces
while(s[src] != '\0'){
if((spc = strspn(s+src, whitespaces)) != 0){
src += spc;
s[des++] = ' ';//reduce spaces
} else {
s[des++] = s[src++];
}
}
if(des && s[des-1] == ' ')
s[des-1] = 0;//Trim of end
else
s[des] = 0;
return s;
}
Here is a simple solution:
char line[50];
while (fgets(line, sizeof line, input_file) != NULL) {
size_t i, j;
for (i = j = 0; line[i] != '\0'; i++) {
if (isspace((unsigned char)line[i])) {
while (isspace((unsigned char)line[++i]))
continue;
if (line[i] == '\0')
break;
if (j != 0)
line[j++] = ' ';
}
line[j++] = line[i];
}
line[j] = '\0';
printf("reduced input: |%s|\n", line);
}
Now since this is homework, here are a few extra questions to answer:
which include files are required?
why is the cast (unsigned char)line[i] needed?
what will happen if a line longer than 50 bytes is read from input_file?
what is wrong with the previous question?
My code is supposed to parse an array of chars into ***char, so that it splits it first by '|' char and then by whitespaces, newline characters etc into words. Sample i/o:
I = ls -l | sort | unique
O =
*cmds[1] = {"ls", "-l", NULL};
*cmds[2] = {"sort", NULL};
*cmds[3] = {"unique", NULL};
above are pointers to char arrays, so split by words and then below is ***char with pointers to above pointers
char **cmds[] = {1, 2, 3, NULL};
Now, I don't see my mistake (probably because I am not so skilled in C), but program gives segfault the second I call parse(..) function from inside parsePipe(). Can anyone please help?
void parse(char *line, char **argv)
{
while (*line != '\0') {
while (*line == ' ' || *line == '\t' || *line == '\n')
*line++ = '\0';
*argv++ = line;
while (*line != '\0' && *line != ' ' && *line != '\t' && *line != '\n'){
line++;
}
}
*argv = '\0';
}
void parsePipe(char *line, char ***cmds)
{
char *cmd = strtok(line, "|");
int word_counter = 0;
while (cmd != NULL)
{
printf("Printing word -> %s\n", cmd);
word_counter++;
parse(cmd, *cmds++);
cmd = strtok(NULL, "|");
}
printf("This string contains %d words separated with |\n",word_counter);
}
void main(void)
{
char line[1024];
char **cmds[64];
while (1) {
printf("lsh -> ");
gets(line);
printf("\n");
parsePipe(line, cmds);
}
}
[too long for a comment]
This line
*argv++ = line; /* with char ** argv */
refers to invalid memory, as the code does *argv[n] (with char **argv[64]) which refers nothing.
The namings you use do not make live easier.
Try the following naming:
void parse(char *line, char **cmd)
{
while (*line != '\0') {
while (*line == ' ' || *line == '\t' || *line == '\n')
*line++ = '\0';
*cmd++ = line;
while (*line != '\0' && *line != ' ' && *line != '\t' && *line != '\n'){
line++;
}
}
*argv = '\0';
}
void parsePipe(char *line, char ***cmdline)
{
char *cmd = strtok(line, "|");
int word_counter = 0;
while (cmd != NULL)
{
printf("Printing word -> %s\n", cmd);
word_counter++;
parse(cmd, *cmdline++);
cmd = strtok(NULL, "|");
}
printf("This string contains %d words separated with |\n",word_counter);
}
void main(void)
{
char line[1024];
char **cmdline[64];
while (1) {
printf("lsh -> ");
gets(line);
printf("\n");
parsePipe(line, cmdline);
}
}
For none of the cmds used memory had been allocated.
So
*cmd++ = line;
fails, as cmd points nowhere, but gets dereferenced and the code tries to write to where it's pointing, which is nowhere, that is invalid memory.
Fixing this can be done by passing char*** to parse(char *** pcmd) and counting the tokens found
size_t nlines = 0;
...
++nlines.
and the doing a
*pcmd = realloc(*pcmd, nlines + 1); /* Allocate one more as needed to later find the end of the array. */
(*pcmd)[nlines -1] = line;
(*pcmd)[nlines] = NULL; /* Initialise the stopper, marking the end of the array. */
for each token found.
Obviously you need to call it like this:
parse(cmd, cmdline++);
To have all this work the inital array needs to initialised properly (as you should have done anyway):
char **cmdline[64] = {0};
So we have a path string /home/user/music/thomas.mp3.
Where is the easy way to extract file name(without extension, "thomas") and it's extension ("mp3") from this string? A function for filename, and for extension. And only GNU libc in our hands.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_FILENAME_SIZE 256
char *filename(char *str) {
char *result;
char *last;
if ((last = strrchr(str, '.')) != NULL ) {
if ((*last == '.') && (last == str))
return str;
else {
result = (char*) malloc(MAX_FILENAME_SIZE);
snprintf(result, sizeof result, "%.*s", (int)(last - str), str);
return result;
}
} else {
return str;
}
}
char *extname(char *str) {
char *result;
char *last;
if ((last = strrchr(str, '.')) != NULL) {
if ((*last == '.') && (last == str))
return "";
else {
result = (char*) malloc(MAX_FILENAME_SIZE);
snprintf(result, sizeof result, "%s", last + 1);
return result;
}
} else {
return ""; // Empty/NULL string
}
}
Use basename to get the filename and then you can use something like this to get the extension.
char *get_filename_ext(const char *filename) {
const char *dot = strrchr(filename, '.');
if(!dot || dot == filename) return "";
return dot + 1;
}
Edit:
Try something like.
#include <string.h>
#include <libgen.h>
static void printFileInfo(char *path) {
char *bname;
char *path2 = strdup(path);
bname = basename(path2);
printf("%s.%s\n",bname, get_filename_ext(bname));
free(path2);
}
Regarding your actual code (all the other answers so far say to scrap that and do something else, which is good advice, however I am addressing your code as it contains blunders that it'd be good to learn about in advance of next time you try to write something).
Firstly:
strncpy(str, result, (size_t) (last-str) + 1);
is not good. You have dest and src around the wrong way; and further this function does not null-terminate the output (unless the input is short enough, which it isn't). Generally speaking strncpy is almost never a good solution to a problem; either strcpy if you know the length, or snprintf.
Simpler and less error-prone would be:
snprintf(result, sizeof result, "%.*s", (int)(last - str), str);
Similary in the other function,
snprintf(result, sizeof result, "%s", last + 1);
The snprintf function never overflows buffer and always produces a null-terminated string, so long as you get the buffer length right!
Now, even if you fixed those then you have another fundamental problem in that you are returning a pointer to a buffer that is destroyed when the function returns. You could fix ext by just returning last + 1, since that is null-terminated anyway. But for filename you have the usual set of options:
return a pointer and a length, and treat it as a length-counted string, not a null-terminated one
return pointer to mallocated memory
return pointer to static buffer
expect the caller to pass in a buffer and a buffer length, which you just write into
Finally, returning NULL on failure is probably a bad idea; if there is no . then return the whole string for filename, and an empty string for ext. Then the calling code does not have to contort itself with checks for NULL.
Here is a routine I use for that problem:
Separates original string into separate strings of path, file_name and extension.
Will work for Windows and Linux, relative or absolute style paths. Will handle directory names with embedded ".". Will handle file names without extensions.
/////////////////////////////////////////////////////////
//
// Example:
// Given path == "C:\\dir1\\dir2\\dir3\\file.exe"
// will return path_ as "C:\\dir1\\dir2\\dir3"
// Will return base_ as "file"
// Will return ext_ as "exe"
//
/////////////////////////////////////////////////////////
void GetFileParts(char *path, char *path_, char *base_, char *ext_)
{
char *base;
char *ext;
char nameKeep[MAX_PATHNAME_LEN];
char pathKeep[MAX_PATHNAME_LEN];
char pathKeep2[MAX_PATHNAME_LEN]; //preserve original input string
char File_Ext[40];
char baseK[40];
int lenFullPath, lenExt_, lenBase_;
char *sDelim={0};
int iDelim=0;
int rel=0, i;
if(path)
{ //determine type of path string (C:\\, \\, /, ./, .\\)
if( (strlen(path) > 1) &&
(
((path[1] == ':' ) &&
(path[2] == '\\'))||
(path[0] == '\\') ||
(path[0] == '/' ) ||
((path[0] == '.' ) &&
(path[1] == '/' ))||
((path[0] == '.' ) &&
(path[1] == '\\'))
)
)
{
sDelim = calloc(5, sizeof(char));
/* // */if(path[0] == '\\') iDelim = '\\', strcpy(sDelim, "\\");
/* c:\\ */if(path[1] == ':' ) iDelim = '\\', strcpy(sDelim, "\\"); // also satisfies path[2] == '\\'
/* / */if(path[0] == '/' ) iDelim = '/' , strcpy(sDelim, "/" );
/* ./ */if((path[0] == '.')&&(path[1] == '/')) iDelim = '/' , strcpy(sDelim, "/" );
/* .\\ */if((path[0] == '.')&&(path[1] == '\\')) iDelim = '\\' , strcpy(sDelim, "\\" );
/* \\\\ */if((path[0] == '\\')&&(path[1] == '\\')) iDelim = '\\', strcpy(sDelim, "\\");
if(path[0]=='.')
{
rel = 1;
path[0]='*';
}
if(!strstr(path, ".")) // if no filename, set path to have trailing delim,
{ //set others to "" and return
lenFullPath = strlen(path);
if(path[lenFullPath-1] != iDelim)
{
strcat(path, sDelim);
path_[0]=0;
base_[0]=0;
ext_[0]=0;
}
}
else
{
nameKeep[0]=0; //works with C:\\dir1\file.txt
pathKeep[0]=0;
pathKeep2[0]=0; //preserves *path
File_Ext[0]=0;
baseK[0]=0;
//Get lenth of full path
lenFullPath = strlen(path);
strcpy(nameKeep, path);
strcpy(pathKeep, path);
strcpy(pathKeep2, path);
strcpy(path_, path); //capture path
//Get length of extension:
for(i=lenFullPath-1;i>=0;i--)
{
if(pathKeep[i]=='.') break;
}
lenExt_ = (lenFullPath - i) -1;
base = strtok(path, sDelim);
while(base)
{
strcpy(File_Ext, base);
base = strtok(NULL, sDelim);
}
strcpy(baseK, File_Ext);
lenBase_ = strlen(baseK) - lenExt_;
baseK[lenBase_-1]=0;
strcpy(base_, baseK);
path_[lenFullPath -lenExt_ -lenBase_ -1] = 0;
ext = strtok(File_Ext, ".");
ext = strtok(NULL, ".");
if(ext) strcpy(ext_, ext);
else strcpy(ext_, "");
}
memset(path, 0, lenFullPath);
strcpy(path, pathKeep2);
if(rel)path_[0]='.';//replace first "." for relative path
free(sDelim);
}
}
}
Here is an old-school algorithm that will do the trick.
char path[100] = "/home/user/music/thomas.mp3";
int offset_extension, offset_name;
int len = strlen(path);
int i;
for (i = len; i >= 0; i--) {
if (path[i] == '.')
break;
if (path[i] == '/') {
i = len;
break;
}
}
if (i == -1) {
fprintf(stderr,"Invalid path");
exit(EXIT_FAILURE);
}
offset_extension = i;
for (; i >= 0; i--)
if (path[i] == '/')
break;
if (i == -1) {
fprintf(stderr,"Invalid path");
exit(EXIT_FAILURE);
}
offset_name = i;
char *extension, name[100];
extension = &path[offset_extension+1];
memcpy(name, &path[offset_name+1], offset_extension - offset_name - 1);
Then you have both information under the variables name and extension
printf("%s %s", name, extension);
This will print:
thomas mp3
I know this is old. But I tend to use strtok for things like this.
/* strtok example */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_TOKENS 20 /* Some reasonable values */
#define MAX_STRING 128 /* Easy enough to make dynamic with mallocs */
int main ()
{
char str[] ="/home/user/music/thomas.mp3";
char sep[] = "./";
char collect[MAX_TOKENS][MAX_STRING];
/* Not really necessary, since \0 is added inplace. I do this out of habit. */
memset(collect, 0, MAX_TOKENS * MAX_STRING);
char * pch = strtok (str, sep);
int ccount = 0;
if(pch != NULL) {
/* collect all seperated text */
while(pch != NULL) {
strncpy( collect[ccount++], pch, strlen(pch));
pch = strtok (NULL, sep);
}
}
/* output tokens. */
for(int i=0; i<ccount; ++i)
printf ("Token: %s\n", collect[i]);
return 0;
}
This is a rough example, and it makes it easy to deal with the tokens afterwards. Ie the last token is the extension. Second last is the basename and so on.
I also find it useful for rebuilding paths for different platforms - replace / with \.
Just a quick one: in C I have a buffer full of data like below:
char buffer[255]="CODE=12345-MODE-12453-CODE1-12355"
My question is how to search through this. For example for the CODE=12345, section bear in mind that the numbers change, so I would like to search like this CODE=***** using wildcard or preset amount of spaces after the CODE= part.
This method wont compile last one left to try
#include <stdio.h>
#include <string.h>
#include <windows.h>
int main ()
{
char buf[255]="CODE=12345-MODE-12453-CODE1-12355";
#define TRIMSPACES(p) while(*p != '\0' && isspace((unsigned char)*p) != 0) ++p
#define NSTRIP(p, n) p += n
#define STRIP(p) ++p
char* getcode(const char *input)
{
char *p = (char*) input, *buf, *pbuf;
if((buf = malloc(256)) == NULL)
return NULL;
pbuf = buf;
while(*p != '\0') {
if(strncmp(p, "CODE", 3) == 0) {
NSTRIP(p, 4); //remove 'code'
TRIMSPACES(p);//trim white-space after 'code'
if(*p != '=')
return NULL;
STRIP(p); // remove '='
TRIMSPACES(p); //trim white-spaces after '='
/* copy the value until found a '-'
note: you must be control the size of it,
for avoid overflow. we allocated size, that's 256
or do subsequent calls to realloc()
*/
while(*p != '\0' && *p != '-')
*pbuf ++ = *p++;
// break;
}
p ++;
}
//put 0-terminator.
*pbuf ++ = '\0';
return buf;
}
//
}
You could use the sscanf() function:
int number;
sscanf(buffer, "CODE = %i", &number);
for that to work well your buffer has to be null terminated.
Another way to do it instead of sscanf():
char *input, *code;
input = strstr(buf, "CODE");
if(input == NULL) {
printf("Not found CODE=\n");
return -1;
}
code = strtok(strdup(input), "=");
if(code != NULL) {
code = strtok(NULL, "-");
printf("%s\n", code); // code = atoi(code);
} else {
//not found '='
}
Or more robust way.. a bit more complex:
#define TRIMSPACES(p) while(*p != '\0' && isspace((unsigned char)*p) != 0) ++p
#define NSTRIP(p, n) p += n
#define STRIP(p) ++p
char* getcode(const char *input, size_t limit)
{
char *p = (char*) input, *buf, *pbuf;
size_t i = 0;
while(*p != '\0') {
if(strncmp(p, "CODE", 3) == 0) {
NSTRIP(p, 4); //remove 'code'
TRIMSPACES(p);//trim all white-spaces after 'code'
/* check we have a '=' after CODE (without spaces).
if there is not, returns NULL
*/
if(*p != '=')
return NULL;
/* ok. We have.. now we don't need of it
just remove it from we output string.
*/
STRIP(p);
/* remove again all white-spaces after '=' */
TRIMSPACES(p);
/* the rest of string is not valid,
because are white-spaces values.
*/
if(*p == '\0')
return NULL;
/* allocate space for store the value
between code= and -.
this limit is set into second parameter.
*/
if((buf = malloc(limit)) == NULL)
return NULL;
/* copy the value until found a '-'
note: you must be control the size of it,
for don't overflow. we allocated 256 bytes.
if the string is greater it, do implementation with
subjecents call to realloc()
*/
pbuf = buf;
while(*p != '\0' && *p != '-' && i < limit) {
*pbuf ++ = *p++;
i ++;
}
*pbuf ++ = '\0';
return buf;
}
p ++;
}
return NULL;
}
And then:
char buf[255] = "foo baa CODE = 12345-MODE-12453-CODE-12355";
char *code = getcode(buf,256);
if(code != NULL) {
printf("code = %s\n", code);
free(code);
} else {
printf("Not found code.\n");
}
output:
code = 12345
Check out this online.
if you want to don't differentiate case, you can use the strncasecmp() that's POSIX function.
Assuming the CODE= part always comes at the beginning of the string, it's pretty easy:
sscanf(buffer, "CODE = %d", &number);
...but you want buffer to be char[255], not unsigned long.
Edit: If the CODE= part isn't necessarily at the beginning of the string, you can use strstr to find CODE in the buffer, do your sscanf starting from that point, then look immediately following that:
int codes[256];
char *pos = buffer;
size_t current = 0;
while ((pos=strstr(pos, "CODE")) != NULL) {
if (sscanf(pos, "CODE = %d", codes+current))
++current;
pos += 4;
}
Edit2:
For example, you'd use this something like this:
#include <stdio.h>
#include <string.h>
#include <windows.h>
int main ()
{
// This is full of other junk as well
char buffer[255]="CODE=12345 MODE-12453 CODE=12355" ;
int i;
int codes[256];
char *pos = buffer;
size_t current = 0;
while ((pos=strstr(pos, "CODE")) != NULL) {
if (sscanf(pos, "CODE = %d", codes+current))
++current;
pos += 4;
}
for (i=0; i<current; i++)
printf("%d\n", codes[i]);
return 0;
}
For me, this produces the following output:
12345
12355
...correctly reading the two "CODE=xxx" sections, but skipings over the "MODE=yyy" section.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *getcode(const char *str, const char *pattern){
//pattern: char is match, space is skip, * is collect
static const char *p=NULL;
char *retbuf, *pat;
int i, match, skip, patlen;
if(str != NULL) p=str;
if(p==NULL || *p=='\0') return NULL;
if(NULL==(retbuf=(char*)malloc((strlen(p)+1)*sizeof(char))))
return NULL;
pat = (char*)pattern;
patlen = strlen(pat);
i = match = skip = 0;
while(*p){
if(isspace(*p)){
++p;
++skip;
continue;
}
if(*pat){
if(*p == *pat){
++match;
++p;
++pat;
} else if(*pat == '*'){
++match;
retbuf[i++]=*p++;
++pat;
} else {
if(match){//reset
pat=(char*)pattern;
p -= match + skip -1;
i = match = skip = 0;
} else //next
++p;
}
} else {
break;
}
}
if(i){//has match
retbuf[i++]='\0';
retbuf=realloc(retbuf, i);
return retbuf;
} else {
free(retbuf);
return NULL;
}
}
int main (){
char *code;
code=getcode("CODE=12345-MODE-12453-CODE1-12355", "CODE=*****");
printf("\"%s\"\n",code);//"12345"
free(code);
code=getcode(" CODE = 12345-MODE-12453-CODE1-12355", "CODE=*****");
printf("\"%s\"\n",code);//"12345"
free(code);
code=getcode("CODE-12345-MODE-12453-CODE1-12355", "CODE=*****");
if(code==NULL)printf("not match\n");//not match
code=getcode("CODE=12345-MODE-12453-CODE=12355", "CODE=*****");
printf("\"%s\"\n",code);//"12345"
free(code);
code=getcode(NULL, "CODE=*****");
printf("\"%s\"\n",code);//"12355"
free(code);
code=getcode("CODE=12345-MODE-12453-CODE1-12355", "CODE=*****");
printf("\"%s\"\n",code);//"12345"
free(code);
code=getcode(NULL, "CODE1-*****");
printf("\"%s\"\n",code);//"12355"
free(code);
return 0;
}