[ 永遠的UNIX::UNIX技術資料的寶庫 ]   GB | BIG5

首頁 > 編程技術 > 源碼天堂 > 正文
C源碼:通用C語言函數:文本文件有關操作,.CFG/.INI類配置文件讀寫
本文出自:http://mly363.363.net 作者: (2001-08-19 08:05:00)
/*
通用C語言函數:文本文件有關操作,.CFG/.INI類配置文件讀寫。我們知道WINDOWS下的軟件可以使用.INI文件
處理程序配置,那在DOS、UNIX、AS/400上又如何才能讀寫.CFG/.INI類配置文件? 你可以使用本程序的有關函
數很方便地實現。注:AS/400上輸入和顯示[]有些問題,所以用{}代替來將section名括起。

   GCFTXTF.C -- General C functions for Text File Read/Write
   M.L.Y  2000.1.1

   MODIFIED   (YYYY.MM.DD)
    M.L.Y      2000.01.01 -  Creation
*/

#if __OS400__                         /* AS/400 */
  #include "GCFTXTFH"
#else
# include "GCFTXTF.H"
#endif

struct txt_line_flds txt_line_fld[MAX_TXT_LINE_FLD];
char CFG_ssl = '[', CFG_ssr = ']';  /* .CFG/.INI file section symbol */
int  CFG_section_line_no, CFG_key_line_no, CFG_key_lines;

/* ------------------------------------------------------------------------- */
int  fgetline(FILE *fp, USGC *buffer, int maxlen)
/*
   Read 1 line text into *buffer from file *fp, return length actually read.
   maxlen --- max. length of *buffer
   CR or LF is not put into *buffer
   FF(0x0C) is put into *buffer and then return
   Ctrl-Z(0x1A) is put into *buffer and then return
   If EOF was detected then return -1
   If an error occurred then return -2
   M.L.Y  1995.06.09, 07.31, 1998.9.9
*/
{
#if __OS400__                         /* AS/400 */
  int  i;

  memset(buffer, 0x00, maxlen);
  if(fgets(buffer, maxlen, fp) == NULL)
  {
    i = strlen(buffer);
    if(feof(fp) != 0)
    {
      if(i == 0) return -1;                 /* EOF */
    }
    else return -2;                         /* error */
  }
  i = strlen(buffer);
  if(i > 0 && buffer[i-1] == '\n')
    buffer[--i] = '\0';
  return i;
#else
  int  i, j;
  USGC ch1;

  for(i = 0, j = 0; i < maxlen; j++)
  {
    if(fread(&ch1, sizeof(USGC), 1, fp) != 1)
    {
      if(feof(fp) != 0)
      {
        if(j == 0) return -1;               /* EOF */
        else break;
      }
      if(ferror(fp) != 0) return -2;        /* error */
      return -2;
    }
    else
    {
      if(ch1 == '\n' || ch1 == 0x00) break; /* end of line */
      if(ch1 == '\f' || ch1 == 0x1A)        /* '\f': Form Feed */
      {
        buffer[i++] = ch1;
        break;
      }
      if(ch1 != '\r') buffer[i++] = ch1;    /* ignore CR */
    }
  }
  buffer[i] = '\0';
  return i;
#endif
}

/* ------------------------------------------------------------------------- */
int  copy_txt_file(void *source_file, void *dest_file)
/*
   Copy source_file to dest_file
   Return code:
      0 -- Ok
     <0 -- Error
   M.L.Y  1996.7, 2000.11
*/
{
  FILE *fp1, *fp2;
  USGC buf[1024+1];
  int  rc;

  if((fp1 = fopen((char *)source_file, "r")) == NULL)
    return COPYF_ERR_OPEN_FILE;
  rc = COPYF_ERR_CREATE_FILE;
#if __OS400__                         /* AS/400 */
  if((fp2 = fopen((char *)dest_file, "w, lrecl=92, ccsid=935")) == NULL)
    goto copy_end;
#else
  if((fp2 = fopen((char *)dest_file, "w")) == NULL) goto copy_end;
#endif
  while(1)
  {
    rc = COPYF_ERR_READ_FILE;
    memset(buf, 0x00, 1024+1);
    if(fgets((char *)buf, 1024, fp1) == NULL)
    {
      if(mstrlen(buf) == 0)
      {
        if(ferror(fp1) != 0) goto copy_end;
        break;                                   /* EOF */
      }
    }
    rc = COPYF_ERR_WRITE_FILE;
    if(fputs((char *)buf, fp2) == EOF) goto copy_end;
  }
  rc = COPYF_OK;
copy_end:
  if(fp2 != NULL) fclose(fp2);
  if(fp1 != NULL) fclose(fp1);
  return rc;
}

/* ------------------------------------------------------------------------- */
int  split_txt_line_fld(char *txt_line, char *sep_chars)
/*
   Split a text line fields info to struct txt_line_fld
   Return fld number
   e.g.: fld1 = fld2, fld3, "fld4", 'fld5'
         key = value

   M.L.Y  2000.8.2
*/
{
  int  i, j, k, n, stat = 0, quote_stat = 0;
  char quote;

  n = strlen(txt_line);
  for(i = 0, j = 0, k = 0; i <= n; i++)
  {
    if(i >= n ||
       (strchr(sep_chars, txt_line[i]) != NULL && quote_stat == 0))
    {
      if(stat == 0) continue;
      stat = 0;                         /* is separate char */
      txt_line_fld[k].fldsp = j;
      txt_line_fld[k].fldlen = i - j;
      k++;
    }
    else
    {
      if(txt_line[i] == '\'' || txt_line[i] == '\"')
      {
        if(quote_stat == 0)
        {
          quote = txt_line[i];          /* " or ' */
          quote_stat = 1;               /* enter " " or ' ' */
        }
        else
        {
          if(txt_line[i] == quote)
            quote_stat = 0;             /* withdraw from " " or ' ' */
        }
      }
      if(stat == 1) continue;
      stat = 1;                         /* is normal char */
      j = i;                            /* fld start pointer */
    }
  }
  return k;                             /* fld number */
}

/* ------------------------------------------------------------------------- */
char *get_txt_line_fld(char *txt_line, int fldno, char *buf)
/*
   After split a text line fields info to struct txt_line_fld,
   get the fldno fld to buf
   Return buf

   M.L.Y  2000.8.2
*/
{
  memmove(buf, txt_line + txt_line_fld[fldno].fldsp,
          txt_line_fld[fldno].fldlen);
  buf[txt_line_fld[fldno].fldlen] = '\0';
  return buf;
}

/* ------------------------------------------------------------------------- */
int  split_key_val(USGC *buf, USGC **key, USGC **val)
/*
   Split key=val pair:
   xxx    =   yyyyyyyy
   |      |   |
   k1     k2  i
   return:
     1 --- ok
     0 --- blank line
    -1 --- no key, "= val"
    -2 --- only key, no '='

   M.L.Y  2000.8, 2000.11
*/
{
  int  i, k1, k2, n;

  if((n = strlen((char *)buf)) < 1) return 0;
  for(i = 0; i < n; i++)
    if(buf[i] != ' ' && buf[i] != '\t') break;
  if(i >= n) return 0;
  if(buf[i] == '=') return -1;
  k1 = i;
  for(i++; i < n; i++)
    if(buf[i] == '=') break;
  if(i >= n) return -2;
  k2 = i;
  for(i++; i < n; i++)
    if(buf[i] != ' ' && buf[i] != '\t') break;
  buf[k2] = '\0';
  *key = buf + k1;
  *val = buf + i;
  return 1;
}

/* ------------------------------------------------------------------------- */
int  CFG_get_key(void *CFG_file, void *section, void *key, void *buf)
/*
   Note:
    section --- not include [] or {}
    key     --- may include blank space
    blank line or begin with ';' for remarks
    line end with '+' for line to be continued

   Return:
     0 --- ok
    <0 --- error
*/
{
  FILE *fp;
  USGC buf1[MAX_CFG_BUF + 1], buf2[MAX_CFG_BUF + 1];
  USGC *key_ptr, *val_ptr;
  int  line_no, n, rc;

  line_no = 0;
  CFG_section_line_no = 0;
  CFG_key_line_no = 0;
  CFG_key_lines = 0;
#if __OS400__                         /* AS/400 */
  if((fp = fopen((char *)CFG_file, "r")) == NULL) return CFG_ERR_OPEN_FILE;
#else
  if((fp = fopen((char *)CFG_file, "rb")) == NULL) return CFG_ERR_OPEN_FILE;
#endif
  while(1)                                       /* seek section */
  {
    rc = CFG_ERR_READ_FILE;
    n = fgetline(fp, buf1, MAX_CFG_BUF);
    if(n < -1) goto r_cfg_end;
    rc = CFG_SECTION_NOT_FOUND;
    if(n < 0) goto r_cfg_end;                    /* EOF, not found */
    line_no++;
    n = mstrlen(ltrimstr(rtrimstr(buf1)));
    if(n == 0 || buf1[0] == ';') continue;       /* blank/remarks line */
    rc = CFG_ERR_FILE_FORMAT;
    if(n > 2 && ((buf1[0] == '[' && buf1[n-1] != ']') ||
                 (buf1[0] == '{' && buf1[n-1] != '}')))
      goto r_cfg_end;
    if(buf1[0] == '[' || buf1[0] == '{')
    {
      buf1[n-1] = 0x00;
      if(mstrcmp(buf1+1, section) == 0)
        break;                                   /* section found */
    }
  }
  CFG_section_line_no = line_no;
  while(1)                                       /* seek key */
  {
    rc = CFG_ERR_READ_FILE;
    n = fgetline(fp, buf1, MAX_CFG_BUF);
    if(n < -1) goto r_cfg_end;
    rc = CFG_KEY_NOT_FOUND;
    if(n < 0) goto r_cfg_end;                    /* EOF, key not found */
    line_no++;
    CFG_key_line_no = line_no;
    CFG_key_lines = 1;
    n = mstrlen(ltrimstr(rtrimstr(buf1)));
    if(n == 0 || buf1[0] == ';') continue;       /* blank/remarks line */
    rc = CFG_KEY_NOT_FOUND;
    if(buf1[0] == '[' || buf1[0] == '{') goto r_cfg_end;
    if(buf1[n-1] == '+')                         /* to be continued */
    {
      buf1[n-1] = 0x00;
      while(1)
      {
        rc = CFG_ERR_READ_FILE;
        n = fgetline(fp, buf2, MAX_CFG_BUF);
        if(n < -1) goto r_cfg_end;
        if(n < 0) break;                         /* EOF */
        line_no++;
        CFG_key_lines++;
        n = mstrlen(rtrimstr(buf2));
        rc = CFG_ERR_EXCEED_BUF_SIZE;
        if(n > 0 && buf2[n-1] == '+')            /* to be continued */
        {
          buf2[n-1] = 0x00;
          if(mstrlen(buf1) + mstrlen(buf2) > MAX_CFG_BUF)
            goto r_cfg_end;
          mstrcat(buf1, buf2);
          continue;
        }
        if(mstrlen(buf1) + mstrlen(buf2) > MAX_CFG_BUF)
          goto r_cfg_end;
        mstrcat(buf1, buf2);
        break;
      }
    }
    rc = CFG_ERR_FILE_FORMAT;
    if(split_key_val(buf1, &key_ptr, &val_ptr) != 1)
      goto r_cfg_end;
    ltrimstr(rtrimstr(key_ptr));
    if(mstrcmp(key_ptr, key) != 0)
      continue;                                  /* not same key */
    mstrcpy(buf, val_ptr);
    break;
  }
  rc = CFG_OK;
r_cfg_end:
  if(fp != NULL) fclose(fp);
  return rc;
}

/* ------------------------------------------------------------------------- */
int  CFG_set_key(void *CFG_file, void *section, void *key, void *buf)
/*
   Note:
    section --- not include [] or {}
    key     --- may include blank space
    not use '+' for line to be continued

   Return:
     0 --- ok
    <0 --- error
*/
{
  FILE *fp1, *fp2;
  USGC buf1[MAX_CFG_BUF + 1], buf2[MAX_CFG_BUF + 1];
  int  line_no, line_no1, n, rc, rc2;
  char *tmpfname;

  rc = CFG_get_key(CFG_file, section, key, buf1);
  if(rc <= CFG_ERR && rc != CFG_ERR_OPEN_FILE) return rc;
  if(rc == CFG_ERR_OPEN_FILE || rc == CFG_SECTION_NOT_FOUND)
  {
#if __OS400__                         /* AS/400 */
    if((fp1 = fopen((char *)CFG_file, "a, lrecl=92, ccsid=935")) == NULL)
#else
    if((fp1 = fopen((char *)CFG_file, "a")) == NULL)
#endif
      return CFG_ERR_CREATE_FILE;
#if __OS400__                         /* AS/400 */
    CFG_ssl = '{';
    CFG_ssr = '}';  /* .CFG/.INI file section symbol */
#else
    CFG_ssl = '[';
    CFG_ssr = ']';  /* .CFG/.INI file section symbol */
#endif
    if(fprintf(fp1, "%c%s%c\n", CFG_ssl, section, CFG_ssr) == EOF)
    {
      fclose(fp1);
      return CFG_ERR_WRITE_FILE;
    }
    if(fprintf(fp1, "%s=%s\n", key, buf) == EOF)
    {
      fclose(fp1);
      return CFG_ERR_WRITE_FILE;
    }
    fclose(fp1);
    return CFG_OK;
  }
  if((tmpfname = tmpnam(NULL)) == NULL)
    return CFG_ERR_CREATE_FILE;
#if __OS400__                         /* AS/400 */
  if((fp2 = fopen(tmpfname, "w, lrecl=92, ccsid=935")) == NULL)
#else
  if((fp2 = fopen(tmpfname, "w")) == NULL)
#endif
    return CFG_ERR_CREATE_FILE;
  rc2 = CFG_ERR_OPEN_FILE;
#if __OS400__                         /* AS/400 */
  if((fp1 = fopen((char *)CFG_file, "r")) == NULL) goto w_cfg_end;
#else
  if((fp1 = fopen((char *)CFG_file, "rb")) == NULL) goto w_cfg_end;
#endif
  if(rc == CFG_KEY_NOT_FOUND)
    line_no1 = CFG_section_line_no;
  else /* rc = CFG_OK */
    line_no1 = CFG_key_line_no - 1;
  for(line_no = 0; line_no < line_no1; line_no++)
  {
    rc2 = CFG_ERR_READ_FILE;
    n = fgetline(fp1, buf1, MAX_CFG_BUF);
    if(n < 0) goto w_cfg_end;
    rc2 = CFG_ERR_WRITE_FILE;
    if(fprintf(fp2, "%s\n", buf1) == EOF) goto w_cfg_end;
  }
  if(rc != CFG_KEY_NOT_FOUND)
    for( ; line_no < line_no1+CFG_key_lines; line_no++)
    {
      rc2 = CFG_ERR_READ_FILE;
      n = fgetline(fp1, buf1, MAX_CFG_BUF);
      if(n < 0) goto w_cfg_end;
    }
  rc2 = CFG_ERR_WRITE_FILE;
  if(fprintf(fp2, "%s=%s\n", key, buf) == EOF) goto w_cfg_end;
  while(1)
  {
    rc2 = CFG_ERR_READ_FILE;
    n = fgetline(fp1, buf1, MAX_CFG_BUF);
    if(n < -1) goto w_cfg_end;
    if(n < 0) break;
    rc2 = CFG_ERR_WRITE_FILE;
    if(fprintf(fp2, "%s\n", buf1) == EOF) goto w_cfg_end;
  }
  rc2 = CFG_OK;
w_cfg_end:
  if(fp1 != NULL) fclose(fp1);
  if(fp2 != NULL) fclose(fp2);
  if(rc2 == CFG_OK)
  {
    rc = copy_txt_file(tmpfname, CFG_file);
    if(rc != 0) return CFG_ERR_CREATE_FILE;
  }
  remove(tmpfname);
  return rc2;
}

/* ------------------------------------------------------------------------- */
int  CFG_get_sections(void *CFG_file, USGC *sections[])
/*
   取.CFG/.INI等配置文件的所有section名字(用[]或
{}括起的,不返回括弧),返回section個數。若出錯,
返回負數。
*/
{
  FILE *fp;
  USGC buf1[MAX_CFG_BUF + 1];
  int  n, n_sections = 0, rc;

#if __OS400__                         /* AS/400 */
  if((fp = fopen(CFG_file, "r")) == NULL) return CFG_ERR_OPEN_FILE;
#else
  if((fp = fopen(CFG_file, "rb")) == NULL) return CFG_ERR_OPEN_FILE;
#endif
  while(1)                                       /* seek section */
  {
    rc = CFG_ERR_READ_FILE;
    n = fgetline(fp, buf1, MAX_CFG_BUF);
    if(n < -1) goto cfg_scts_end;
    if(n < 0) break;                             /* EOF */
    n = mstrlen(ltrimstr(rtrimstr(buf1)));
    if(n == 0 || buf1[0] == ';') continue;       /* blank/remarks line */
    rc = CFG_ERR_FILE_FORMAT;
    if(n > 2 && ((buf1[0] == '[' && buf1[n-1] != ']') ||
                 (buf1[0] == '{' && buf1[n-1] != '}')))
      goto cfg_scts_end;
    if(buf1[0] == '[' || buf1[0] == '{')
    {
      buf1[n-1] = 0x00;
      mstrcpy(sections[n_sections], buf1+1);
      n_sections++;
    }
  }
  rc = n_sections;
cfg_scts_end:
  if(fp != NULL) fclose(fp);
  return rc;
}

/* ------------------------------------------------------------------------- */
int  CFG_get_keys(void *CFG_file, void *section, USGC *keys[])
/*
   取.CFG/.INI等配置文件的某個section下的所有key的
名字(key=value形式, value可用加號表示續行),返回
key個數。若出錯,返回負數。
*/
{
  FILE *fp;
  USGC buf1[MAX_CFG_BUF + 1], buf2[MAX_CFG_BUF + 1];
  USGC *key_ptr, *val_ptr;
  int  n, n_keys = 0, rc;

#if __OS400__                         /* AS/400 */
  if((fp = fopen(CFG_file, "r")) == NULL) return CFG_ERR_OPEN_FILE;
#else
  if((fp = fopen(CFG_file, "rb")) == NULL) return CFG_ERR_OPEN_FILE;
#endif
  while(1)                                       /* seek section */
  {
    rc = CFG_ERR_READ_FILE;
    n = fgetline(fp, buf1, MAX_CFG_BUF);
    if(n < -1) goto cfg_keys_end;
    rc = CFG_SECTION_NOT_FOUND;
    if(n < 0) goto cfg_keys_end;                 /* EOF, not found */
    n = mstrlen(ltrimstr(rtrimstr(buf1)));
    if(n == 0 || buf1[0] == ';') continue;       /* blank/remarks line */
    rc = CFG_ERR_FILE_FORMAT;
    if(n > 2 && ((buf1[0] == '[' && buf1[n-1] != ']') ||
                 (buf1[0] == '{' && buf1[n-1] != '}')))
      goto cfg_keys_end;
    if(buf1[0] == '[' || buf1[0] == '{')
    {
      buf1[n-1] = 0x00;
      if(mstrcmp(buf1+1, section) == 0)
        break;                                   /* section found */
    }
  }
  while(1)
  {
    rc = CFG_ERR_READ_FILE;
    n = fgetline(fp, buf1, MAX_CFG_BUF);
    if(n < -1) goto cfg_keys_end;
    if(n < 0) break;                             /* EOF */
    n = mstrlen(ltrimstr(rtrimstr(buf1)));
    if(n == 0 || buf1[0] == ';') continue;       /* blank/remarks line */
    rc = CFG_KEY_NOT_FOUND;
    if(buf1[0] == '[' || buf1[0] == '{')
      break;                                     /* another section */
    if(buf1[n-1] == '+')                         /* to be continued */
    {
      buf1[n-1] = 0x00;
      while(1)
      {
        rc = CFG_ERR_READ_FILE;
        n = fgetline(fp, buf2, MAX_CFG_BUF);
        if(n < -1) goto cfg_keys_end;
        if(n < 0) break;                         /* EOF */
        n = mstrlen(rtrimstr(buf2));
        rc = CFG_ERR_EXCEED_BUF_SIZE;
        if(n > 0 && buf2[n-1] == '+')            /* to be continued */
        {
          buf2[n-1] = 0x00;
          if(mstrlen(buf1) + mstrlen(buf2) > MAX_CFG_BUF)
            goto cfg_keys_end;
          mstrcat(buf1, buf2);
          continue;
        }
        if(mstrlen(buf1) + mstrlen(buf2) > MAX_CFG_BUF)
          goto cfg_keys_end;
        mstrcat(buf1, buf2);
        break;
      }
    }
    rc = CFG_ERR_FILE_FORMAT;
    if(split_key_val(buf1, &key_ptr, &val_ptr) != 1)
      goto cfg_keys_end;
    ltrimstr(rtrimstr(key_ptr));
    mstrcpy(keys[n_keys], key_ptr);
    n_keys++;
  }
  rc = n_keys;
cfg_keys_end:
  if(fp != NULL) fclose(fp);
  return rc;
}

/* ------------------------------------------------------------------------- */
int  read_txt_line(void *TXT_file, int line_no, void *buf)
/*
   讀文本文件中指定行號(以1始計)的內容到buf
   返回行內容長度,出錯返回負數。
*/
{
  FILE *fp;
  int  lno, n1;
  USGC buf1[256];

  if((fp = fopen((char *)TXT_file, "r")) == NULL) return TXTF_ERR_OPEN_FILE;
  for(lno = 0; lno < line_no; lno++)
  {
    memset(buf1, 0x00, 256);
    if(fgets((char *)buf1, 255, fp) == NULL)
    {
      n1 = mstrlen(buf1);
      if(n1 == 0)
      {
        if(ferror(fp) != 0)
        {
          fclose(fp);
          return TXTF_ERR_READ_FILE;
        }
        break;
      }
      break;
    }
  }
  if(lno < line_no)
  {
    fclose(fp);
    return TXTF_ERR_NOT_FOUND;
  }
  n1 = mstrlen(buf1);
  if(n1 > 0 && buf1[n1-1] == '\n') buf1[--n1] = 0x00;
  mstrcpy(buf, buf1);
  fclose(fp);
  return n1;
}

/* ------------------------------------------------------------------------- */
int  seek_txt_line(void *TXT_file, void *line_tag, void *buf)
/*
   查找文本文件中以line_tag內容開始的行,讀其內容到
   buf,返回行號(以1始計),出錯返回負數。
*/
{
  FILE *fp;
  int  line_no, n, n1;
  USGC buf1[256];

  n = mstrlen(line_tag);
  if((fp = fopen((char *)TXT_file, "r")) == NULL) return TXTF_ERR_OPEN_FILE;
  for(line_no = 1; ; line_no++)
  {
    memset(buf1, 0x00, 256);
    if(fgets((char *)buf1, 255, fp) == NULL)
    {
      n1 = mstrlen(buf1);
      if(n1 == 0)
      {
        if(ferror(fp) != 0)
        {
          fclose(fp);
          return TXTF_ERR_READ_FILE;
        }
        fclose(fp);            /* eof */
        return TXTF_ERR_NOT_FOUND;
      }
      if(mstrncmp(buf1, line_tag, n) == 0) break;
      fclose(fp);              /* eof */
      return TXTF_ERR_NOT_FOUND;
    }
    if(mstrncmp(buf1, line_tag, n) == 0) break;
  }
  n1 = mstrlen(buf1);
  if(n1 > 0 && buf1[n1-1] == '\n') buf1[--n1] = 0x00;
  mstrcpy(buf, buf1);
  fclose(fp);
  return line_no;
}

/* End of file */
(http://www.fanqiang.com)
    進入【UNIX論壇

相關文章
 

★  樊強制作 歡迎分享  ★