C newbie. Needs help and pointers(no pun intended).

I've recently created a C program that uses the remedy api from bmc to open a trouble ticket.  Since I am a complete C newbie(This is literally the first time I've coded C), I'm not sure if I'm going to have memory problems down the road(spoiled by languages that manage memory for me).  The script works, and does what I want it to do, but it's going to be running several hundred times a day, so I don't want to eat up all the memory.

Also, I'd like to store the fields,values in a text file(hard coded right now) in the following format:
field=value

I was able to accomplish this using strtok, but if I came across this:
fieldname="the return code  is = 12"

I would only get "the return code is" for the value.  How do I grab the rest of the information behind the delimiter?

Thanks for all your help.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ar.h>
#include <arextern.h>
 
 
 
int main()
{
        ARControlStruct ctrl;
        ARNameType schema;
        ARStatusList status;
        ARFieldValueList fields;
        ARFieldValueStruct *field;
        AREntryIdType entryID;
        int errorCode;
 
        ctrl.cacheId = 0;
        ctrl.sessionId = 0;
        strcpy(ctrl.user, "username");
        strcpy(ctrl.password, "password");
        strcpy(ctrl.authString, "");
        strcpy(ctrl.server, "servername");
        strcpy(schema, "schemaname");
        if(ARInitialization(&ctrl, &status) >= AR_RETURN_ERROR)
        {
                printf(status.statusList[0].messageText);
                printf("\n");
                exit(1);
        }
        FreeARStatusList(&status, FALSE);
 
        fields.numItems = 30;
        fields.fieldValueList = malloc(30*sizeof(ARFieldValueStruct));
        field = fields.fieldValueList;
        /* this marks the beginning of the items */
        /* fieldID and charVal are the values I need to pull from a text file */
        field[0].fieldId = 700000000;
        field[0].value.dataType = AR_DATA_TYPE_CHAR;
        field[0].value.u.charVal = "Tivoli Event ID";
        /* repeat about 30 times ... snip */
 if(ARCreateEntry(&ctrl, schema, &fields, entryID, &status) >= AR_RETURN_
ERROR)
        {
                printf(status.statusList[0].messageText);
                printf("\n");
                exit(2);
        }
        printf(entryID);
        printf("\n");
        ARTermination(&ctrl, &status);

Open in new window

LVL 18
MorcalavinAsked:
Who is Participating?
 
bpmurrayConnect With a Mentor Commented:
An area to watch out for is the use of strcpy - can you be certain that the string lengths are such that they will always fit in the fields? I think you'll probably need to allocate memory for the charVal string from the text file. However, here you only have one allocation:
    fields.fieldValueList = malloc(30*sizeof(ARFieldValueStruct));
so before exiting, remember to call free(fields.fieldValueList);

Another point - you have a hard-coded number of fields, i.e. 30. It is usual to use a manifest constant to make this easier to maintain.

Putting this all together, your code should have something like this:



 #define  AR_FIELD_COUNT 30
 
  int iX;
 
        fields.numItems = AR_FIELD_COUNT;
        fields.fieldValueList = malloc(AR_FIELD_COUNT*sizeof(ARFieldValueStruct));
        field = fields.fieldValueList;
        /* this marks the beginning of the items */
        /* fieldID and charVal are the values I need to pull from a text file */
        for (iX=0; iX<AR_FIELD_COUNT; iX++)
        {
           /* Read data from text file:
                 ID is a pointer to the string value of the fieldID
                 TXT is a pointer to the NULL-terminated text
           */
           field[iX].fieldId = atol(ID);
           field[iX].value.dataType = AR_DATA_TYPE_CHAR;
           field[iX].value.u.charVal = malloc(strlen(TXT)+1); /* Allocate +1 for the NULL */
           strcpy(field[iX].value.u.charVal, TXT);
        }
        
        if(ARCreateEntry(&ctrl, schema, &fields, entryID, &status) >= AR_RETURN_ERROR)
        {
            /* Put your message on one line, and write it to stderr */
            fprintf(stderr, "Error: %s\n", status.statusList[0].messageText);
            exit(2);
        }
        /* Can you do this: printf(entryID)? It seems unlikely! */
        printf("ID: %ld\n", entryID.value); /* Assuming it's numberic */
        ARTermination(&ctrl, &status);
 
        /* Finally, free up the memory used - 
             First, free up the allocated strings
        */
        for (iX=0; iX<AR_FIELD_COUNT; iX++)
        {
            free(fields.fieldValueList[iX].value.u.charVal);
        }
        /* Now free the allocated table of entries */
        free(fields.fieldValueList);

Open in new window

0
 
Kent OlsenData Warehouse Architect / DBACommented:
Hi Morcalavin,

For the most part, unless you call malloc (alloc, realloc, etc.) you don't have dynamic memory so there can't be a memory leak.

Of course, any function that the program calls can assign dynamic memory.  If the function returns a pointer to a structure, you need to know if the buffer is static, or if the calling function (your program) needs to free the memory when it's done with the structure.

Your code looks pretty good.  Nothing there leaps out and screams "Memory Leak".

Also, no matter how much memory you allocate, when the program ends, it ALL goes back to the operating system.  This program doesn't loop so there's no chance of a serious memory leak.



Good Luck,
Kent
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> I was able to accomplish this using strtok, but if I came across this:
>> fieldname="the return code  is = 12"
>> I would only get "the return code is" for the value.  How do I grab the rest of the information behind the delimiter?

This is a little tricky. You'll need to check to make sure the = isn't in the middle of a pair of ", if it is you know you are in the middle of a value. To do this check from the last strtok result to the current, looking for an odd number of ". If you have an odd number you must be in the middle of a string (unless the string can also have escaped " (\"), in which case you will also need to allow for that). There is no short cut to this really, unless you specify that = is not allowed in a value! Welcome to the wonderful world of lexical parsing :)
0
Managing Security Policy in a Changing Environment

The enterprise network environment is evolving rapidly as companies extend their physical data centers to embrace cloud computing and software-defined networking. This new reality means that the challenge of managing the security policy is much more dynamic and complex.

 
Infinity08Commented:
>> fieldname="the return code  is = 12"

Since they all will be of the format :

        field=value

you just have to find the first =. Everything before it is the field, everything after it is the value. In other words, you have to call strtok only once for each line.
0
 
bpmurrayConnect With a Mentor Commented:
And for the strtok stuff, assuming the file contains only one name-value pair per line, you can use:

     ID = strtok(buffer, "=");
     TXT = ID + strlen(ID) + 1;

This will work since strtok puts a NULL into the buffer instead of the delimiter, and you simply point after the first delimiter. This will work even with something like:

   MySillyValue=six equals = "======"

where ID will be 'MySillyValue', and TXT will be 'six equals = "======"'
0
 
MorcalavinAuthor Commented:
@bpmurray

I am implementing some of your suggestions.  Currently, the number 30 will NOT be a hard coded value(it's hard coded now).  The reason for this is that if we want to add/remove fields later, we would be able to edit the text file(or the script(s) that create it), and not have to recompile the entire program.  Still figuring out where and how to to pull that data,  but that's another topic.

Oh and this works fine:
printf(entryID);
It's actually a char valued defined in one of the headers:
typedef char          AREntryIdType[AR_MAX_ENTRYID_SIZE + 1];
0
 
MorcalavinAuthor Commented:
Ok, having a slight issue.  Probably relatively simple.  fieldID is a pointer, so when I try to get the fieldValue, I get and error saying I'm trying to convert a pointer to an integer without an implicit cast.   How do I properly cast it?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
FILE *fh;
char line[];
int len;
const char delimiter[] = "=";
char *fieldID;
char fieldValue;
 
int main()
{
        fh = fopen("ARRemedyFieldList.config", "rt");
        if(fh == NULL)
        {
                printf("Error opening ARRemedyFieldList.config file!");
                exit(1);
        }
        while(fgets(line, 80, fh) != NULL)
        {
                len = strlen(line);
                if(line[len - 1 ] == '\n')
                {
                        line[len - 1] = '\0';
                }
                fieldID = strtok(line, delimiter);
                fieldValue = fieldID + strlen(fieldID) + 1;
        }
        close(fh);
}

Open in new window

0
 
evilrixSenior Software Engineer (Avast)Commented:
fieldValue is a char. SO you just want to convert the pointer to a char?

fieldValue = *(fieldID + strlen(fieldID) + 1);
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> you just have to find the first =. Everything before it is the field, everything after it is the value. In other words, you have to call strtok only once for each line.
I assumed it was a stream of fields rather than one value one field, but good point :)
0
 
MorcalavinAuthor Commented:
Hrmm...doesn't seem to be working.

Input file is this:
7000000001="msg=test"
7000000002="classname"

output is this:
user@xubuntu:~/bin$ ./test
7000000001 = "7000000001
7000000002 = "7000000002


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
FILE *fh;
char line[];
int len;
const char delimiter[] = "=";
char *fieldID;
char fieldValue;
 
int main()
{
        fh = fopen("ARRemedyFieldList.config", "rt");
        if(fh == NULL)
        {
                printf("Error opening ARRemedyFieldList.config file!");
                exit(1);
        }
        while(fgets(line, 80, fh) != NULL)
        {
                len = strlen(line);
                if(line[len - 1 ] == '\n')
                {
                        line[len - 1] = '\0';
                }
                fieldID = strtok(line, delimiter);
                fieldValue = *(fieldID + strlen(fieldID) + 1);
                printf("%s", fieldID);
                printf(" = ");
                printf(&fieldValue);
                printf("\n");
        }
        close(fh);
}

Open in new window

0
 
evilrixConnect With a Mentor Senior Software Engineer (Avast)Commented:
Try this...

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
FILE *fh;
char line[81];
int len;
const char delimiter[] = "=";
char *fieldID;
char *fieldValue;
 
int main()
{
	fh = fopen("C:\\Documents and Settings\\Ricky Cormier\\My Documents\\Visual Studio 2005\\Projects\\clrtest\\debug\\ARRemedyFieldList.config", "rt");
	if(fh == NULL)
	{
		printf("Error opening ARRemedyFieldList.config file!");
		exit(1);
	}
	while(fgets(line, 80, fh) != NULL)
	{
		len = strlen(line);
		if(line[len - 1 ] == '\n')
		{
			line[len - 1] = '\0';
		}
		fieldID = strtok(line, delimiter);
		if(NULL == fieldID) { break; }
		fieldValue = (fieldID + strlen(fieldID) + 1);
		printf("%s", fieldID);
		printf(" = ");
		printf("%s", fieldValue);
		printf("\n");
	}
	fclose(fh);
}

Open in new window

0
 
evilrixSenior Software Engineer (Avast)Commented:
Obviously, you'll need to change the path for the file.. because I forgot to :)
0
 
MorcalavinAuthor Commented:
Ahh.  That seems to work.  Thanks.  I'll play around with it a bit more and award the points in the next few days.
0
 
evilrixSenior Software Engineer (Avast)Commented:
Sure, no worries. Let us know if you have any more questions.

Have fun :)
0
All Courses

From novice to tech pro — start learning today.