⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 config_file.c

📁 linux subdivision ying gai ke yi le ba
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * config_file.c :  parsing configuration files
 *
 * ====================================================================
 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.  The terms
 * are also available at http://subversion.tigris.org/license-1.html.
 * If newer versions of this license are posted there, you may use a
 * newer version instead, at your option.
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://subversion.tigris.org/.
 * ====================================================================
 */



#include <apr_lib.h>
#include <apr_md5.h>
#include "config_impl.h"
#include "svn_io.h"
#include "svn_types.h"
#include "svn_path.h"
#include "svn_auth.h"
#include "svn_md5.h"
#include "svn_hash.h"
#include "svn_utf.h"



/* File parsing context */
typedef struct parse_context_t
{
  /* This config struct and file */
  svn_config_t *cfg;
  const char *file;

  /* The file descriptor */
  FILE *fd;

  /* The current line in the file */
  int line;

  /* Temporary strings, allocated from the temp pool */
  svn_stringbuf_t *section;
  svn_stringbuf_t *option;
  svn_stringbuf_t *value;

  /* Temporary pool parsing */
  apr_pool_t *pool;
} parse_context_t;


/* Eat chars from FD until encounter non-whitespace, newline, or EOF.
   Set *PCOUNT to the number of characters eaten, not counting the
   last one, and return the last char read (the one that caused the
   break).  */
static APR_INLINE int
skip_whitespace (FILE* fd, int *pcount)
{
  int ch = getc (fd);
  int count = 0;
  while (ch != EOF && ch != '\n' && apr_isspace (ch))
    {
      ++count;
      ch = getc (fd);
    }
  *pcount = count;
  return ch;
}


/* Skip to the end of the line (or file).  Returns the char that ended
   the line; the char is either EOF or newline. */
static APR_INLINE int
skip_to_eoln (FILE *fd)
{
  int ch = getc (fd);
  while (ch != EOF && ch != '\n')
    ch = getc (fd);
  return ch;
}


/* Parse a single option value */
static svn_error_t *
parse_value (int *pch, parse_context_t *ctx)
{
  svn_error_t *err = SVN_NO_ERROR;
  svn_boolean_t end_of_val = FALSE;
  int ch;

  /* Read the first line of the value */
  svn_stringbuf_setempty (ctx->value);
  for (ch = getc (ctx->fd); /* last ch seen was ':' or '=' in parse_option. */
       ch != EOF && ch != '\n';
       ch = getc (ctx->fd))
    {
      const char char_from_int = ch;
      svn_stringbuf_appendbytes (ctx->value, &char_from_int, 1);
    }
  /* Leading and trailing whitespace is ignored. */
  svn_stringbuf_strip_whitespace (ctx->value);

  /* Look for any continuation lines. */
  for (;;)
    {
      if (ch == EOF || end_of_val)
        {
          if (!ferror (ctx->fd))
            {
              /* At end of file. The value is complete, there can't be
                 any continuation lines. */
              svn_config_set (ctx->cfg, ctx->section->data,
                              ctx->option->data, ctx->value->data);
            }
          break;
        }
      else
        {
          int count;
          ++ctx->line;
          ch = skip_whitespace (ctx->fd, &count);

          switch (ch)
            {
            case '\n':
              /* The next line was empty. Ergo, it can't be a
                 continuation line. */
              ++ctx->line;
              end_of_val = TRUE;
              continue;

            case EOF:
              /* This is also an empty line. */
              end_of_val = TRUE;
              continue;

            default:
              if (count == 0)
                {
                  /* This line starts in the first column.  That means
                     it's either a section, option or comment.  Put
                     the char back into the stream, because it doesn't
                     belong to us. */
                  ungetc (ch, ctx->fd);
                  end_of_val = TRUE;
                }
              else
                {
                  /* This is a continuation line. Read it. */
                  svn_stringbuf_appendbytes (ctx->value, " ", 1);

                  for (;
                       ch != EOF && ch != '\n';
                       ch = getc (ctx->fd))
                    {
                      const char char_from_int = ch;
                      svn_stringbuf_appendbytes (ctx->value,
                                                 &char_from_int, 1);
                    }
                  /* Trailing whitespace is ignored. */
                  svn_stringbuf_strip_whitespace (ctx->value);
                }
            }
        }
    }

  *pch = ch;
  return err;
}


/* Parse a single option */
static svn_error_t *
parse_option (int *pch, parse_context_t *ctx)
{
  svn_error_t *err = SVN_NO_ERROR;
  int ch;

  svn_stringbuf_setempty (ctx->option);
  for (ch = *pch;               /* Yes, the first char is relevant. */
       ch != EOF && ch != ':' && ch != '=' && ch != '\n';
       ch = getc (ctx->fd))
    {
      const char char_from_int = ch;
      svn_stringbuf_appendbytes (ctx->option, &char_from_int, 1);
    }

  if (ch != ':' && ch != '=')
    {
      ch = EOF;
      err = svn_error_createf (SVN_ERR_MALFORMED_FILE, NULL,
                               "%s:%d: Option must end with ':' or '='",
                               ctx->file, ctx->line);
    }
  else
    {
      /* Whitespace around the name separator is ignored. */
      svn_stringbuf_strip_whitespace (ctx->option);
      err = parse_value (&ch, ctx);
    }

  *pch = ch;
  return err;
}


/* Read chars until enounter ']', then skip everything to the end of
 * the line.  Set *PCH to the character that ended the line (either
 * newline or EOF), and set CTX->section to the string of characters
 * seen before ']'.
 * 
 * This is meant to be called immediately after reading the '[' that
 * starts a section name.
 */
static svn_error_t *
parse_section_name (int *pch, parse_context_t *ctx)
{
  svn_error_t *err = SVN_NO_ERROR;
  int ch;

  svn_stringbuf_setempty (ctx->section);
  for (ch = getc (ctx->fd);
       ch != EOF && ch != ']' && ch != '\n';
       ch = getc (ctx->fd))
    {
      const char char_from_int = ch;
      svn_stringbuf_appendbytes (ctx->section, &char_from_int, 1);
    }

  if (ch != ']')
    {
      ch = EOF;
      err = svn_error_createf (SVN_ERR_MALFORMED_FILE, NULL,
                               "%s:%d: Section header must end with ']'",
                               ctx->file, ctx->line);
    }
  else
    {
      /* Everything from the ']' to the end of the line is ignored. */
      ch = skip_to_eoln (ctx->fd);
      if (ch != EOF)
        ++ctx->line;
    }

  *pch = ch;
  return err;
}


svn_error_t *
svn_config__sys_config_path (const char **path_p,
                             const char *fname,
                             apr_pool_t *pool)
{
  /* ### This never actually returns error in practice.  Perhaps the
     prototype should change? */

  *path_p = NULL;

  /* Note that even if fname is null, svn_path_join_many will DTRT. */

#ifdef WIN32
  {
    const char *folder;
    SVN_ERR (svn_config__win_config_path (&folder, TRUE, pool));
    *path_p = svn_path_join_many (pool, folder,
                                  SVN_CONFIG__SUBDIRECTORY, fname, NULL);
  }

#else  /* ! WIN32 */

 *path_p = svn_path_join_many (pool, SVN_CONFIG__SYS_DIRECTORY, fname, NULL);

#endif /* WIN32 */

  return SVN_NO_ERROR;
}


svn_error_t *
svn_config__user_config_path (const char *config_dir,
                              const char **path_p,
                              const char *fname,
                              apr_pool_t *pool)
{
  /* ### This never actually returns error in practice.  Perhaps the
     prototype should change? */

  *path_p = NULL;

  /* Note that even if fname is null, svn_path_join_many will DTRT. */

  if (config_dir)
    {
      *path_p = svn_path_join_many(pool, config_dir, fname, NULL);
      return SVN_NO_ERROR;
    }
  
#ifdef WIN32
  {
    const char *folder;
    SVN_ERR (svn_config__win_config_path (&folder, FALSE, pool));
    *path_p = svn_path_join_many (pool, folder,
                                  SVN_CONFIG__SUBDIRECTORY, fname, NULL);
  }

#else  /* ! WIN32 */
  {
    apr_status_t apr_err;
    apr_uid_t uid;
    apr_gid_t gid;
    char *username, *homedir;
    const char *homedir_utf8;

    apr_err = apr_uid_current (&uid, &gid, pool);
    if (apr_err)
      return SVN_NO_ERROR;
    
    apr_err = apr_uid_name_get (&username, uid, pool);
    if (apr_err)
      return SVN_NO_ERROR;
    
    apr_err = apr_uid_homepath_get (&homedir, username, pool);
    if (apr_err)
      return SVN_NO_ERROR;

    SVN_ERR (svn_utf_cstring_to_utf8 (&homedir_utf8, homedir, pool));

    *path_p = svn_path_join_many (pool,
                                  svn_path_canonicalize (homedir_utf8, pool),
                                  SVN_CONFIG__USR_DIRECTORY, fname, NULL);
    
  }
#endif /* WIN32 */

  return SVN_NO_ERROR;
}



/*** Exported interfaces. ***/

#ifndef WIN32
svn_error_t *
svn_config__open_file (FILE **pfile,
                       const char *filename,
                       const char *mode,
                       apr_pool_t *pool)
{
  const char *filename_native;
  SVN_ERR (svn_utf_cstring_from_utf8 (&filename_native, filename, pool));
  *pfile = fopen (filename_native, mode);
  return SVN_NO_ERROR;
}
#endif /* WIN32 */


svn_error_t *
svn_config__parse_file (svn_config_t *cfg, const char *file,
                        svn_boolean_t must_exist)
{
  apr_pool_t *pool = svn_pool_create (cfg->pool);
  svn_error_t *err = SVN_NO_ERROR;
  parse_context_t ctx;
  int ch, count;
  FILE *fd;
  /* "Why," you ask yourself, "is he using stdio FILE's instead of
     apr_file_t's?"  The answer is simple: newline translation.  For
     all that it has an APR_BINARY flag, APR doesn't do newline
     translation in files.  The only portable way I know to get
     translated text files is to use the standard stdio library. */

  SVN_ERR (svn_config__open_file (&fd, file, "rt", pool));
  if (fd == NULL)
    {
      if (errno != ENOENT)
        return svn_error_createf (SVN_ERR_BAD_FILENAME, NULL,
                                  "Can't open config file '%s'", file);
      else if (must_exist && errno == ENOENT)
        return svn_error_createf (SVN_ERR_BAD_FILENAME, NULL,
                                  "Can't find config file '%s'", file);
      else
        return SVN_NO_ERROR;
    }

  ctx.cfg = cfg;
  ctx.file = file;
  ctx.fd = fd;
  ctx.line = 1;
  ctx.pool = pool;
  ctx.section = svn_stringbuf_create("", ctx.pool);
  ctx.option = svn_stringbuf_create("", ctx.pool);
  ctx.value = svn_stringbuf_create("", ctx.pool);

  do
    {
      ch = skip_whitespace (fd, &count);
      switch (ch)
        {
        case '[':               /* Start of section header */
          if (count == 0)
            err = parse_section_name (&ch, &ctx);
          else
            {
              ch = EOF;
              err = svn_error_createf (SVN_ERR_MALFORMED_FILE, NULL,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -