0

I'm porting net-snmp to an embedded platform that only has limited access to the filesystem and I stumbled upon a big problem. There's a part of the core code that uses the ungetc() function, which I don't have. There are of course 2 solutions:

A) write my own ungetc() using what I have

B) modify net-snmp code in order to achieve the same result without ungetc()

Solution (B) will be eventually discussed in the net-snmp coders mailing list since requires deep understanding of the library's internals, so let's please focus on feasibility of (A)

What I have on my embedded system is:

fopen()
fclose()
fcreate()
fwrite()
fread()
fdelete()
fclear()
fcopy()
ffindfirst()
ffindnext()
frename()
fgetsize()
ftell()
fseek()
fgetc()
fgets()

The main difference is that my file functions work with INT32* file handles instead of FILE* types. I don't have the FILE* type.

What the ungetc() function does is to basically "put back the char in the stream" , either the char that it just read or another one.

In the first case the solution is easy, I rewind the pointer with fseek() one position backwards.

But in the second case I have a problem. I would be modifying the stream and not the file, except I don't have streams! I'm reading the file directly.

With ungetc() you can do something like

FILE *fp = fopen("file.txt", "r");
int c = getc (fp);
if( c == 'a' ) ungetc ('b', fp);

If "file.txt" contains "abcdefghi", a subsequent read with gets() will read "bbcdefghi" and not "abcdefghi" because the content IN THE STREAM has been changed, but not the file!

How can I replicate this behavior if I don't have "streams" ? My getc() and gets() read from an INT32* file handle and I don't have a puts() or putc() equivalent.

I can only write with fwrite() but that alters the content on the NV memory.

Thank you for your insight

1 Answer 1

0

Here is how I solved it. I created a more complex struct for the file handle that contains not only the handle itself but also the file name, the file size and a buffer that holds the whole content of the file. It should only load the part of the file that I need but mine is an embedded application and I know I won't be opening big files so I didn't bother.

Then once you have the "stream" it's trivial to pop chars in and out.

typedef struct _myfile {
      _FS_HANDLE        handle; /* file descriptor */
      CHAR*             fname;  /* file name */
      UINT32            fsize;  /* file size */
      CHAR*             buffer; /* file buffer */
  } *my_FILE;

int my_ungetc(int c, my_FILE stream)
{
    if (stream)
    {
        UINT32 pointer = _fs_tell(stream->handle);
        if (pointer > 0)
        {
            _fs_seek(stream->handle,pointer - 1);
            stream->buffer[pointer - 1] = c;
            return c;
        }
    }
    else
    {
        printf("ERROR! stream is NULL!\r\n");
    }
    return EOF;
}

void *my_fopen(const char *filename, const char *mode)
{
    my_FILE fp = _mem_alloc(sizeof(struct _myfile));
    fp->fname = strdup(filename);
    if (mode == "r")
    {
        fp->handle = _fs_open((CHAR*)filename, OPEN_READ);
        if (fp->handle) fp->fsize = _get_size_with_handle(fp->handle);
        if (fp->fsize)
        {
            fp->buffer = _mem_alloc(fp->fsize);
            if (fp->buffer)
            {
                if (_fs_read(fp->handle,fp->buffer,fp->fsize))
                {
                    _fs_seek(fp->handle,0);
                }
                else
                {
                    printf("ERROR: unable to read %d bytes from %s\r\n",fp->fsize,filename);
                }
            }
            else
            {
                printf("ERROR in my_fopen(\"%s\",\"r\"): could not alloc %d bytes for buffer\r\n",filename,fp->fsize);
            }
        }
        else
        {
            fp->buffer = NULL;
            printf("File \"%s\" is empty\r\n");
        }
        return fp;
    }
    else if (mode == "w")
    {
        fp->handle = _fs_open((CHAR*)filename, OPEN_WRITE);
        if (fp->handle) fp->fsize = _get_size_with_handle(fp->handle);
        fp->buffer = NULL;
        return fp;
    }
    else
    {
        printf("File open mode %s not supported\r\n",mode);
        return NULL;
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.