Пример #1
0
/*=export_func  optionMakePath
 * private:
 *
 * what:  translate and construct a path
 * arg:   + char *       + p_buf     + The result buffer +
 * arg:   + int          + b_sz      + The size of this buffer +
 * arg:   + char const * + fname     + The input name +
 * arg:   + char const * + prg_path  + The full path of the current program +
 *
 * ret-type: bool
 * ret-desc: true if the name was handled, otherwise false.
 *           If the name does not start with ``$'', then it is handled
 *           simply by copying the input name to the output buffer and
 *           resolving the name with either
 *           @code{canonicalize_file_name(3GLIBC)} or @code{realpath(3C)}.
 *
 * doc:
 *
 *  This routine will copy the @code{pzName} input name into the
 *  @code{pzBuf} output buffer, not exceeding @code{bufSize} bytes.  If the
 *  first character of the input name is a @code{'$'} character, then there
 *  is special handling:
 *  @*
 *  @code{$$} is replaced with the directory name of the @code{pzProgPath},
 *  searching @code{$PATH} if necessary.
 *  @*
 *  @code{$@} is replaced with the AutoGen package data installation directory
 *  (aka @code{pkgdatadir}).
 *  @*
 *  @code{$NAME} is replaced by the contents of the @code{NAME} environment
 *  variable.  If not found, the search fails.
 *
 *  Please note: both @code{$$} and @code{$NAME} must be at the start of the
 *     @code{pzName} string and must either be the entire string or be followed
 *     by the @code{'/'} (backslash on windows) character.
 *
 * err:  @code{false} is returned if:
 *       @*
 *       @bullet{} The input name exceeds @code{bufSize} bytes.
 *       @*
 *       @bullet{} @code{$$}, @code{$@@} or @code{$NAME} is not the full string
 *                 and the next character is not '/'.
 *       @*
 *       @bullet{} libopts was built without PKGDATADIR defined and @code{$@@}
 *                 was specified.
 *       @*
 *       @bullet{} @code{NAME} is not a known environment variable
 *       @*
 *       @bullet{} @code{canonicalize_file_name} or @code{realpath} return
 *                 errors (cannot resolve the resulting path).
=*/
bool
optionMakePath(char * p_buf, int b_sz, char const * fname, char const * prg_path)
{
    {
        size_t len = strlen(fname);

        if (((size_t)b_sz <= len) || (len == 0))
            return false;
    }

    /*
     *  IF not an environment variable, just copy the data
     */
    if (*fname != '$') {
        char   const * src = fname;
        char * dst = p_buf;
        int    ct  = b_sz;

        for (;;) {
            if ( (*(dst++) = *(src++)) == NUL)
                break;
            if (--ct <= 0)
                return false;
        }
    }

    /*
     *  IF the name starts with "$$", then it must be "$$" or
     *  it must start with "$$/".  In either event, replace the "$$"
     *  with the path to the executable and append a "/" character.
     */
    else switch (fname[1]) {
    case NUL:
        return false;

    case '$':
        if (! add_prog_path(p_buf, b_sz, fname, prg_path))
            return false;
        break;

    case '@':
        if (program_pkgdatadir[0] == NUL)
            return false;

        if (snprintf(p_buf, (size_t)b_sz, "%s%s",
                     program_pkgdatadir, fname + 2) >= b_sz)
            return false;
        break;

    default:
        if (! add_env_val(p_buf, b_sz, fname))
            return false;
    }

    return get_realpath(p_buf, b_sz);
}
Пример #2
0
/*=export_func  optionMakePath
 * private:
 *
 * what:  translate and construct a path
 * arg:   + char*       + pzBuf      + The result buffer +
 * arg:   + int         + bufSize    + The size of this buffer +
 * arg:   + char const* + pzName     + The input name +
 * arg:   + char const* + pzProgPath + The full path of the current program +
 *
 * ret-type: bool
 * ret-desc: true if the name was handled, otherwise false.
 *           If the name does not start with ``$'', then it is handled
 *           simply by copying the input name to the output buffer and
 *           resolving the name with either
 *           @code{canonicalize_file_name(3GLIBC)} or @code{realpath(3C)}.
 *
 * doc:
 *
 *  This routine will copy the @code{pzName} input name into the
 *  @code{pzBuf} output buffer, not exceeding @code{bufSize} bytes.  If the
 *  first character of the input name is a @code{'$'} character, then there
 *  is special handling:
 *  @*
 *  @code{$$} is replaced with the directory name of the @code{pzProgPath},
 *  searching @code{$PATH} if necessary.
 *  @*
 *  @code{$@} is replaced with the AutoGen package data installation directory
 *  (aka @code{pkgdatadir}).
 *  @*
 *  @code{$NAME} is replaced by the contents of the @code{NAME} environment
 *  variable.  If not found, the search fails.
 *
 *  Please note: both @code{$$} and @code{$NAME} must be at the start of the
 *     @code{pzName} string and must either be the entire string or be followed
 *     by the @code{'/'} (backslash on windows) character.
 *
 * err:  @code{false} is returned if:
 *       @*
 *       @bullet{} The input name exceeds @code{bufSize} bytes.
 *       @*
 *       @bullet{} @code{$$}, @code{$@@} or @code{$NAME} is not the full string
 *                 and the next character is not '/'.
 *       @*
 *       @bullet{} libopts was built without PKGDATADIR defined and @code{$@@}
 *                 was specified.
 *       @*
 *       @bullet{} @code{NAME} is not a known environment variable
 *       @*
 *       @bullet{} @code{canonicalize_file_name} or @code{realpath} return
 *                 errors (cannot resolve the resulting path).
=*/
bool
optionMakePath(char * pzBuf, int bufSize, char const * pzName,
               char const * pzProgPath)
{
    size_t name_len = strlen(pzName);

    if (((size_t)bufSize <= name_len) || (name_len == 0))
        return false;

    /*
     *  IF not an environment variable, just copy the data
     */
    if (*pzName != '$') {
        char const*  pzS = pzName;
        char* pzD = pzBuf;
        int   ct  = bufSize;

        for (;;) {
            if ( (*(pzD++) = *(pzS++)) == NUL)
                break;
            if (--ct <= 0)
                return false;
        }
    }

    /*
     *  IF the name starts with "$$", then it must be "$$" or
     *  it must start with "$$/".  In either event, replace the "$$"
     *  with the path to the executable and append a "/" character.
     */
    else switch (pzName[1]) {
    case NUL:
        return false;

    case '$':
        if (! add_prog_path(pzBuf, bufSize, pzName, pzProgPath))
            return false;
        break;

    case '@':
        if (program_pkgdatadir[0] == NUL)
            return false;

        if (snprintf(pzBuf, bufSize, "%s%s", program_pkgdatadir, pzName + 2)
            >= bufSize)
            return false;
        break;

    default:
        if (! add_env_val(pzBuf, bufSize, pzName))
            return false;
    }

#if defined(HAVE_CANONICALIZE_FILE_NAME)
    {
        char * pz = canonicalize_file_name(pzBuf);
        if (pz == NULL)
            return false;

        name_len = strlen(pz);
        if (name_len >= (size_t)bufSize) {
            free(pz);
            return false;
        }

        memcpy(pzBuf, pz, name_len + 1);
        free(pz);
    }

#elif defined(HAVE_REALPATH)
    {
        char z[PATH_MAX+1];

        if (realpath(pzBuf, z) == NULL)
            return false;

        name_len = strlen(z);
        if (name_len >= bufSize)
            return false;

        memcpy(pzBuf, z, name_len + 1);
    }
#endif

    return true;
}