RoBoard魔人的機器人日誌

2012/3/5

[RoBoRC第四回] 介紹程式碼fileio

接下來要介紹的是fileio.h / fileio.cpp
主要就是讀取資料
以及一些將字串分割的函式

而且fileio也可以直接讀取壓縮黨(zip)內的內容


fileio.h
#ifndef __FILEIO_H
#define __FILEIO_H

#include "defines.h"

#if defined(RB_MSVC_WIN32)
 //#define USE_ZZIP
#endif

#ifdef USE_ZZIP                     //定義讀取檔案的格式型態
    #include <zzip/zzip.h>
    typedef ZZIP_FILE   FILEIO;
 typedef zzip_size_t FILEIO_SIZE_T;
 typedef zzip_off_t  FILEIO_OFF_T;
#else
    #include <stdio.h>
    typedef FILE   FILEIO;
 typedef size_t FILEIO_SIZE_T;
 typedef long   FILEIO_OFF_T;
#endif


#define INI_MAXLINESIZE     (1024)
#define INI_MAXELEMSIZE     (256)

typedef struct
{
    int  type;
    char itemname[INI_MAXELEMSIZE+1];
    char itemvalue[INI_MAXELEMSIZE+1];

} INI_ITEM_t; // type : INI_GROUPTITLE , INI_GROUPITEM or UNKNOW. itemname = itemvalue <==> cmd = XXXX.cmd
//-- values for INI_ITEM_t.type
     #define  INI_GROUPTITLE   (0)
     #define  INI_GROUPITEM    (1)
     #define  INI_UNKNOWNITEM  (2)


#ifdef __cplusplus
extern "C" {                     //讓C++' 將以下內容用C語言讀取
#endif

int  ini_ReadNextItem(FILEIO* ini_fp, INI_ITEM_t* iniitem);
bool  ini_IsGroup(INI_ITEM_t* item, const char* title);
bool  ini_IsItem(INI_ITEM_t* item, const char* name);
bool  ini_IsNumber(char* str);
void  ini_InitialItem(INI_ITEM_t* item);
char* ini_RemoveSpace(char* str);              //may break str's content
int   ini_ParseNumber_pre(char *str, const char *prefix, int *data);
int   ini_ParseNumber_post(char *str, const char *postfix, int *data);
int   ini_DivideString(char *str, char **str1, char **str2, const char *fix);
int   ini_GetCH(char *str, int *ch);
int   ini_GetValue(char *str, int *value);


FILEIO*    ini_FileOpen(char* filename);
void    ini_FileClose(FILEIO* fp);
FILEIO*       fileio_FileOpen(char* filename, const char* mode);
void          fileio_FileClose(FILEIO* fp);
FILEIO_SIZE_T fileio_Read(void* buf, FILEIO_SIZE_T size, FILEIO_SIZE_T count, FILEIO* fp);
char*         fileio_ReadLine(FILEIO* fp, char* buf, int maxcnt);
int           fileio_GetChar(FILEIO* fp);
int           fileio_Seek(FILEIO* fp, FILEIO_OFF_T offset, int origin);
FILEIO_OFF_T  fileio_GetPos(FILEIO* fp);
FILEIO_SIZE_T fileio_GetSize(FILEIO* fp);
bool          fileio_Exist(char* filename);
int           fileio_IsFileEnd(FILEIO* fp);





#ifdef __cplusplus
}
#endif

#endif






fileio.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "fileio.h"
#include "errcode.h"

#if defined(RB_LINUX)
    #define _stricmp  strcasecmp
    #define _strnicmp strncasecmp
#elif defined(RB_BC_DOS) || defined(RB_DJGPP)
    #define _stricmp  stricmp
    #define _strnicmp strnicmp
#endif


/***********************  Functions for .ini Files  ***************************/

void ini_InitialItem(INI_ITEM_t* item)               //預設值
{
 item->itemname[0] = item->itemvalue[0] = '\0';
 item->type = INI_UNKNOWNITEM;
}

int ini_GetValue(char *str, int *value)               //將字串轉為數字   非數字則回傳'無效值'
{
 if(!ini_IsNumber(str))
  return INI_INVALID_VALUE;
 *value = atol(str);
 return SUCCESS;
}

static char* ini_RemoveComment(char* str) {              //將程式寫法改為電腦讀取方法   即int a; >> "int a\0"
 if (str != NULL)
  str[strcspn(str, ";")] = '\0';                //strcspn   尋找字元位置
 return str;
}

int ini_DivideString(char *str, char **str1, char **str2, const char *fix)      //分割字串以fix為分割點
{
 int i;
 i = (int)strcspn(str, fix);
 if(str[i] == '\0')
  return INI_DIVIDE_FAIL;
 str[i] = '\0';
 *str1 = ini_RemoveSpace(str);
 *str2 = ini_RemoveSpace(&str[i+1]);
 if(strlen(*str1) == 0)
  return INI_DIVIDE_STR1;
 if(strlen(*str2) == 0)
  return INI_DIVIDE_STR2;
 return SUCCESS;
}

char* ini_RemoveSpace(char* str) {                //刪除前後的無意義字元  ex: ' ' , '\t'
 int i;

 if (str == NULL) return str;

    i = (int)strlen(str);
    if (i == 0) return str; else i--; //ignore empty string

    //remove tail space chars
 while((i >= 0) && ((str[i] == ' ') || (str[i] == '\t')))
  i--;

    str[i + 1] = '\0';
    //remove head space chars
    i = 0;
 while ((str[i] == ' ') || (str[i] == '\t')) i++;
    return &(str[i]);
 /*
 //remove all space in the string
 int i = 0, j = 0;
 while ((str[i] = str[j++]) != '\0')
  if (str[i] != ' ') i++;
 */
}

bool ini_IsNumber(char* str) {                 //判斷是否為正整數
 if (*str == '\0') return false;

 while (*str != '\0')
 {
        if ((*str < '0') || (*str > '9')) return false;
  str++;
 }
    return true;
}

int ini_ParseNumber_pre(char *str, const char *prefix, int *data)        //分析字首
{
 int i;
// ini_RemoveSpace(str);
 i = (int)strlen(prefix);
 if (str == NULL)
  return INI_NUMPRE_NULL;                 //若str為空值   回傳INI_NUMPRE_NULL
 if((strlen(str) <= (unsigned)i) || (_strnicmp(str, prefix, i) != 0))
  return INI_NUMPRE_INVALID;                //若prefix字數大於str 或 prefix與str的前 i 個數不同 回傳INI_NUMPRE_INVALID
 str = ini_RemoveSpace(&str[i]);                //刪除前後的無意義字元  ex: ' ' , '\t'
 if(!ini_IsNumber(str))
  return INI_NUMPRE_FAIL;                 //不為數字回傳INI_NUMPRE_FAIL
 *data = atol(str);                   //轉為long
 return SUCCESS;
}

int ini_ParseNumber_post(char *str, const char *postfix, int *data)        //分析字尾
{
 int i;
 char *str2;
 if(str == NULL)
  return INI_NUMPOST_NULL;                //若str為空值   回INI_NUMPOST_NULL
 i = (int)strcspn(str, postfix);                //尋找字元相同位置   相同的前一個
 if(str[i] != '\0'){                   //要判斷不為\0     因為\0就已經是結尾了
  str2 = ini_RemoveSpace(&str[i]);              //刪除前後的無意義字元  ex: ' ' , '\t'
  if(_stricmp(str2, postfix) != 0)              
   return INI_NUMPRE_INVALID;               //判斷字串若不相同回傳INI_NUMPRE_INVALID  不區分大小寫
 }
 str[i] = '\0';                    //簡單的說就是保留前 i 個與postfix不同的字
 str = ini_RemoveSpace(str);
 if(!ini_IsNumber(str))                  
  return INI_NUMPRE_FAIL;                 //刪除前後的無意義字元  ex: ' ' , '\t'
 *data = atoi(str);                   //轉換為數字
 return SUCCESS;
}

FILEIO* ini_FileOpen(char* filename) {               //呼叫fileio_FileOpen  然後回傳檔案位置   在205行
 return fileio_FileOpen(filename, "r");
}

void ini_FileClose(FILEIO* fp) {                //把檔案關掉
 fileio_FileClose(fp);
}


int ini_ReadNextItem(FILEIO* fp, INI_ITEM_t* iniitem) {           //讀取檔案
    char buf[INI_MAXLINESIZE+1];
    char *str = "";
 char *str1, *str2;
 ini_InitialItem(iniitem);                 //把iniitem設為預設值  在20行
 
 iniitem->itemname[0] = iniitem->itemvalue[0] = '\0';
    //read a line
 

    while (!fileio_IsFileEnd(fp))                //判斷檔案室否已經到達結尾  在318行
    {
  str = fileio_ReadLine(fp, buf, INI_MAXLINESIZE);          //讀取一行檔案內容  在232行
        str = ini_RemoveSpace(ini_RemoveComment(str));           //改成電腦讀取方式  並且去除空格等無意義字元
  if (strlen(str) != 0) break;               //如果字串長度為零   就再重讀一行
    }
 if(strlen(str) == 0)                  //如果出來還是為零  代表檔案是空的
  return INI_FILEEND;                  //回傳INI_FILEEND

 errcode_SetErrStr(str);
    //parse the line
     // [XXXXXXXX]
 if ((str[0] == '[') && (str[strlen(str)-1] == ']')){          //如果讀取的檔案前後有[]   代表為itemname
  errcode_SetErrGroup(str);
  str[strlen(str)-1] = '\0';
  strcpy(iniitem->itemname, ini_RemoveSpace(&str[1]));         //把讀進來的字放到itemname去
  iniitem->type = INI_GROUPTITLE;               //型態設為INI_GROUPTITLE
    }
    // XXXX = YYYYY
 else if((ini_DivideString(str, &str1, &str2, "=")) != INI_DIVIDE_FAIL){      //分割字串以"="為分割點  在40行
   strcpy(iniitem->itemname,  str1);              //前面為itemname
   strcpy(iniitem->itemvalue, str2);              //後面為itemvalue
   iniitem->type = INI_GROUPITEM;              //型態設為INI_GROUPITEM
 }
 else
   iniitem->type = INI_UNKNOWNITEM;              //其他設定為INI_UNKNOWNITEM
 return SUCCESS;
}


//====================   Parsing Functions  ====================>:
bool ini_IsGroup(INI_ITEM_t* item, const char* title) {           //判斷itemname是否為title
 if (_stricmp(item->itemname, title) == 0) return true;
 return false;
}

bool ini_IsItem(INI_ITEM_t* item, const char* name) {           //判斷itemname是否為name
 if (_stricmp(item->itemname, name) == 0) return true;
 return false;
}

int ini_GetCH(char *str, int *ch)                //抓出channel的編號
{
 int status;
 status = ini_ParseNumber_pre(str, "CH", ch);            //分析字首  在92行
 if(status != SUCCESS)                  
  status = ini_ParseNumber_pre(str, "Channel", ch);
 if(status == SUCCESS)
 if((*ch <= 31) && (*ch >= 0))               
  return SUCCESS;

 return INI_INVALIDCHANNEL;
}

/*---------------------  end of Func. for .ini Files  ------------------------*/



FILEIO* fileio_FileOpen(char* filename, const char* mode) {          //可以開啟zip檔   也可以正常開啟
    #ifdef USE_ZZIP
  char str[256];

  strcpy(str, mode);
        return zzip_fopen(filename, strcat(str, "i")); //mode | ZZIP_CASELESS
    #else
        return fopen(filename, mode);
    #endif
}

void fileio_FileClose(FILEIO* fp) {                   //關閉檔案用
    #ifdef USE_ZZIP
        zzip_fclose(fp);
    #else
        fclose(fp);
    #endif
}

FILEIO_SIZE_T fileio_Read(void* buf, FILEIO_SIZE_T size, FILEIO_SIZE_T count, FILEIO* fp) {  //一次讀取count個大小為size的資料
    #ifdef USE_ZZIP
        return zzip_fread(buf, size, count, fp);
    #else
        return fread(buf, size, count, fp);
    #endif
}

char* fileio_ReadLine(FILEIO* fp, char* buf, int maxcnt) {          //先讀取字元  排成一行回傳一行字
    int i = 0, c;
  
    for (i=0; i<maxcnt; i++)
    {
        if ((c=fileio_GetChar(fp)) == EOF) break;             //讀取檔案的字元  如果讀到EOF跳出  在298行
        if ((c == '\r') || (c == '\n')) break;             //如果遇到\r或\n也跳出
        buf[i] = c;                    //其他正常字元  放入buf
    }
    buf[i] = '\0';                    //遇到結尾 給一個結尾符號
  
    //clear remaining chars in the current line
    if (i == maxcnt)                   //如果上面的迴圈不是因為遇到條件跳出的話
    {
        while((c=fileio_GetChar(fp)) != EOF)             //向後把特殊符號拿掉  不然後造成下一次讀取的錯誤
            if ((c == '\r') || (c == '\n')) break;
    }
  
    return buf;
}

/*
#ifdef USE_ZZIP
 static char INI_ReadBuf[256];
 static int  INI_CurChar = -1;
#endif
int ini_GetChar(INIFILE* fp) {
    #ifdef USE_ZZIP

        int i;
      
        if ((INI_CurChar == -1) || (INI_ReadBuf[INI_CurChar] == '\0'))
        {
            i = (int)zzip_fread(INI_ReadBuf, sizeof(INI_ReadBuf[0]), 255, fp);
            if (i <= 0) return EOF;

            INI_ReadBuf[i] = '\0';
            INI_CurChar = 0;
        }

        return INI_ReadBuf[INI_CurChar++];
    #else
        return fgetc(fp);
    #endif
}

int ini_IsFileEnd(INIFILE* fp) {
    #ifdef USE_ZZIP
  long cur_offset, end_offset;

  if ((INI_CurChar == -1) || (INI_ReadBuf[INI_CurChar] == '\0'))
  {
   cur_offset = zzip_tell(fp);
   zzip_seek(fp, 0L, SEEK_END);
   end_offset = zzip_tell(fp);

   if (cur_offset >= end_offset) return 1;
   zzip_seek(fp, cur_offset, SEEK_SET);
  }
  return 0;
 #else
        return feof(fp);
    #endif
}
*/

int fileio_GetChar(FILEIO* fp) {                //讀取檔案的字元
    #ifdef USE_ZZIP
  char buf[1];
  int  i = (int)zzip_fread(buf, sizeof(buf[0]), 1, fp);

  if (i <= 0) return EOF; else return (int)buf[0];
    #else
        return fgetc(fp);
    #endif
}

bool fileio_Exist(char* filename) {                //檢查檔案室否存在
 FILEIO* fp;

 if ((fp = fileio_FileOpen(filename, "r")) == NULL) return false;

 fileio_FileClose(fp);
    return true;
}

int fileio_IsFileEnd(FILEIO* fp) {                //判斷檔案室否已經到達結尾
    #ifdef USE_ZZIP
  FILEIO_OFF_T cur_offset, end_offset;

  cur_offset = zzip_tell(fp);
  zzip_seek(fp, 0L, SEEK_END);
  end_offset = zzip_tell(fp);

  if (cur_offset >= end_offset) return 1;
  zzip_seek(fp, cur_offset, SEEK_SET);

  return 0;
 #else
        return feof(fp);
    #endif
}

FILEIO_SIZE_T fileio_GetSize(FILEIO* fp) {              //取得檔案結尾用
 FILEIO_OFF_T cur_offset, end_offset;

 #ifdef USE_ZZIP
  cur_offset = zzip_tell(fp);
  zzip_seek(fp, 0L, SEEK_END);
  end_offset = zzip_tell(fp);
  zzip_seek(fp, cur_offset, SEEK_SET);
 #else
  cur_offset = ftell(fp);                 //cur_offset現在的位置
  fseek(fp, 0L, SEEK_END);
  end_offset = ftell(fp);                 //end_offset為檔案結尾
  fseek(fp, cur_offset, SEEK_SET);              
    #endif

 return end_offset;
}

int fileio_Seek(FILEIO* fp, FILEIO_OFF_T offset, int origin) {         //fseek  也可用於zzip
 #ifdef USE_ZZIP
  if (zzip_seek(fp, offset, origin) >= 0L) return 0;
  return -1;
 #else
  return fseek(fp, offset, origin);              //改變檔案所在位置
    #endif
}

FILEIO_OFF_T  fileio_GetPos(FILEIO* fp) {              //ftell  也可用於zzip
 #ifdef USE_ZZIP
  return zzip_tell(fp);
 #else
  return ftell(fp);                   //回傳檔案目前位置
    #endif
}

Share:

0 留言:

張貼留言

技術提供:Blogger.

追蹤者