Обернуть ungetc() без put () gets() и потоков в целом

Я портирую net-snmp на встроенную платформу, которая имеет ограниченный доступ к файловой системе, и наткнулась на большую проблему. Есть часть основного кода, которая использует функцию ungetc(), которой у меня нет. Есть, конечно, 2 решения:

А) написать свой собственный ungetc(), используя то, что у меня есть

B) изменить код net-snmp для достижения того же результата без ungetc()

Решение (B) будет в конечном итоге обсуждаться в списке рассылки net-snmp coders, так как требует глубокого понимания внутренних особенностей библиотеки, поэтому давайте сосредоточимся на возможности (A)

Что у меня есть на моей встроенной системе:

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

Основное отличие состоит в том, что мои файловые функции работают с файловыми дескрипторами INT32* вместо типов FILE*. У меня нет типа FILE*.

Функция ungetc() в основном "помещает символ в поток", либо только что прочитанный символ, либо другой.

В первом случае решение простое, я перематываю указатель с помощью fseek() на одну позицию назад.

Но во втором случае у меня проблема. Я бы изменил поток, а не файл, за исключением того, что у меня нет потоков! Я читаю файл напрямую.

С ungetc() вы можете сделать что-то вроде

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

Если "file.txt" содержит "abcdefghi", последующее чтение с помощью gets() будет читать "bbcdefghi", а не "abcdefghi", потому что содержимое IN THE STREAM было изменено, но не файл!

Как я могу повторить это поведение, если у меня нет "потоков"? Мои getc () и gets() читаются из файлового дескриптора INT32*, и у меня нет эквивалента put () или putc().

Я могу писать только с помощью fwrite(), но это изменяет содержимое памяти NV.

Спасибо за ваше понимание

1 ответ

Вот как я это решил. Я создал более сложную структуру для дескриптора файла, которая содержит не только сам дескриптор, но также имя файла, размер файла и буфер, который содержит все содержимое файла. Он должен загружать только ту часть файла, которая мне нужна, но у меня есть встроенное приложение, и я знаю, что не буду открывать большие файлы, поэтому я не стал беспокоиться.

Затем, когда у вас есть "поток", тривиально вводить и выводить символы.

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;
    }
}
Другие вопросы по тегам