/* namespace.c:
*
* vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2
****************************************************************
* Copyright (C) 2003 Tom Lord
*
* See the file "COPYING" for further information about
* the copyright and warranty status of this work.
*/
#include "hackerlab/bugs/panic.h"
#include "hackerlab/fmt/cvt.h"
#include "hackerlab/char/char-class.h"
#include "hackerlab/char/str.h"
#include "hackerlab/sort/qsort.h"
#include "hackerlab/vu/safe.h"
#include "libfsutils/safety.h"
#include "libarch/my.h"
#include "libarch/namespace.h"
/* __STDC__ prototypes for static functions */
static int version_cmp_n (const t_uchar * a, size_t a_l, const t_uchar * b, size_t b_l);
static int ver_order (t_uchar c);
static int ver_cmp_n (const t_uchar * a, size_t a_l, const t_uchar * b, size_t b_l);
static int arch_cmp_by_field (void * va, void * vb, void * vdata);
static int arch_lvl_cmp_by_field (void * va, void * vb, void * vdata);
static t_uchar const * over_opt_archive_prefix (t_uchar const * name);
static t_uchar const * over_archive_name (t_uchar const * in);
static t_uchar const * over_basename (t_uchar const * in);
static t_uchar const * over_separator (t_uchar const * in);
static t_uchar const * over_version (t_uchar const * in);
static t_uchar const * over_patch_level (t_uchar const * in);
static t_uchar const * find_version_start (t_uchar const * name);
static t_uchar const * find_version_end (t_uchar const * version_start);
int
arch_valid_id (t_uchar * id)
{
t_uchar * non_empty_marker;
/* This isn't exactly the same as larch's version --
* it's a superset. Both are wrong, really. :-)
*/
while (char_is_alnum (*id)
|| char_is_space (*id)
|| (char_is_punct (*id) && (*id != '<')))
++id;
if (*id != '<')
return 0;
++id;
non_empty_marker = id;
while (char_is_alnum (*id)
|| (*id == '-')
|| (*id == '+')
|| (*id == '_')
|| (*id == '.'))
++id;
if (id == non_empty_marker)
return 0;
if (*id != '@')
return 0;
++id;
non_empty_marker = id;
while (char_is_alnum (*id)
|| (*id == '-')
|| (*id == '_')
|| (*id == '.'))
++id;
if (*id != '>')
return 0;
++id;
if (*id)
return 0;
return 1;
}
int
arch_valid_archive_name (t_uchar const * name)
{
t_uchar const * end;
if (!name)
return 0;
end = over_archive_name (name);
if (!end || *end)
return 0;
else
return 1;
}
int
arch_valid_patch_level_name (t_uchar const * const name)
{
t_uchar const * lvl;
if (!str_cmp (name, "base-0"))
return 1;
if (str_cmp_prefix ("patch-", name) && str_cmp_prefix ("version-", name) && str_cmp_prefix ("versionfix-", name))
return 0;
lvl = str_chr_index (name, '-');
if (!lvl)
return 0;
++lvl;
if (!*lvl)
return 0;
while (char_is_digit (*lvl))
++lvl;
if (*lvl)
return 0;
else
return 1;
}
int
arch_valid_config_name (t_uchar * name)
{
return is_non_upwards_relative_path (name);
}
/*(c arch_valid_package_name)
* int arch_valid_package_name (t_uchar * name,
* enum arch_valid_package_name_archive archive_disposition,
* enum arch_valid_package_name_types type,
* int tolerant);
*
* Return non-0 if `name' is a valid arch name of the sort described by
* the other arguments.
*
* `archive_disposition' may be any of the values:
*
* arch_no_archive the name must not be fully qualified (must have no
* no archive name component)
*
* arch_maybe_archive the name _may_ be fully qualified
*
* arch_req_archive the name _must_ be fully qualified
*
*
* `type' may be any of the values:
*
* arch_req_category the name must have at least a category
*
* arch_req_package the name must have a category and may
* have a branch label
*
* arch_req_version the name must have a version id
* (and therefore must have a category and
* may have a branch label)
*
* arch_req_patch_level the name must have a category, may have a
* branch label, must have a version id, and
* must have a revision name
*
* `tolerant':
*
* if 0, then the name may not have any components beyond those
* required by `type'. For example, if type is `arch_req_category',
* then the name may not have a branch label or version id.
*
* if 1, then the name may have additional components
*/
int
arch_valid_package_name (t_uchar const * name,
enum arch_valid_package_name_archive archive_disposition,
enum arch_valid_package_name_types type,
int tolerant)
{
int has_archive;
int has_category;
int has_branch;
int has_version;
int has_patch_level;
t_uchar const * next;
if (!name)
return 0;
has_archive = 0;
has_category = 0;
has_branch = 0;
has_version = 0;
has_patch_level = 0;
next = over_opt_archive_prefix (name);
has_archive = (next && (next != name));
switch (archive_disposition)
{
case arch_maybe_archive:
{
if (!next)
return 0;
break;
}
case arch_req_archive:
{
if (!next || (next == name))
return 0;
break;
}
case arch_no_archive:
{
if (!next || (next != name))
return 0;
break;
}
}
name = next;
name = over_basename (name);
if (!name)
return 0;
else
has_category = 1;
if (*name)
{
name = over_separator (name);
if (!name)
return 0;
next = over_basename (name);
if (next)
{
has_branch = 1;
name = next;
if (*name)
{
name = over_separator (name);
if (!name)
return 0;
}
}
if (*name)
{
name = over_version (name);
if (!name)
return 0;
has_version = 1;
if (*name)
{
name = over_separator (name);
if (!name)
return 0;
name = over_patch_level (name);
if (!name || *name)
return 0;
has_patch_level = 1;
}
}
}
switch (type)
{
case arch_req_category:
{
if (tolerant)
return 1;
else
return !has_branch && !has_version;
break;
}
case arch_req_package:
{
if (tolerant)
return 1;
else
return !has_version;
break;
}
case arch_req_version:
{
if (tolerant)
return has_version;
else
return has_version && !has_patch_level;
break;
}
case arch_req_patch_level:
{
return has_patch_level;
}
default:
{
panic ("arch_valid_package_name: bad argument.");
return 0;
}
}
}
/*(c arch_is_system_package_name)
* int arch_is_system_package_name (t_uchar * name);
*
* Return non-0 if `name' is a system package name.
*/
int
arch_is_system_package_name (t_uchar * name)
{
t_uchar * package = 0;
int answer;
package = arch_parse_package_name (arch_ret_package, 0, name);
answer = !!str_chr_index (name, '%');
lim_free (0, package);
return answer;
}
/*(c arch_parse_package_name)
* t_uchar * arch_parse_package_name (enum arch_parse_package_name_type type,
* t_uchar * default_archive,
* t_uchar * name);
*
* Parse a package name.
*
* `type' may be any of the values:
*
* arch_ret_archive Return the archive component of the name,
* or the value `default_archive' if the name
* is not fully qualified.
*
* arch_ret_non_archive Return all of the name except its (optional)
* archive component.
*
* arch_ret_category Return just the category name.
*
* arch_ret_package Return the category--branch if the name has a
* branch label, just category otherwise.
*
* arch_ret_version Return just the version id of the name.
*
* arch_ret_package_version Return the category(--branch)?--version
* of the name
*
* arch_ret_patch_level Return just the revision id of the name
*
* arch_ret_fqversion Return the archive/categry--[branch--]version.
* Panic if no version is provided.
*
* Note that there is no `arch_ret_branch' (since not all names have branch labels)
* and no `arch_ret_package_patch_level' (since `arch_ret_non_archive' will do that
* job).
*
* `default_archive' is the archive name to use for `arch_ret_archive' if the
* name is not fully qualified. Typically, the value of `default_archive'
* is taken from a command-line -A argument or the user's .arch-params/=default-archive
* file.
*
* `name' is the name to parse.
*
*/
/* helpers for parse_package_name */
t_uchar const *
find_version_start (t_uchar const * name)
{
t_uchar const * version_start;
t_uchar const * version_end;
t_uchar const * t;
name = over_opt_archive_prefix (name);
version_end = over_basename (name); /* over category */
version_end = over_separator (version_end);
invariant (!!version_end);
version_start = version_end;
t = over_basename (version_start); /* maybe over explicit branch */
if (t)
{
version_end = over_separator (t);
invariant (!!version_end);
version_start = version_end;
}
return version_start;
}
t_uchar const *
find_version_end (t_uchar const * version_start)
{
t_uchar const * version_end = over_version (version_start);
invariant (!!version_end);
return version_end;
}
/**
* \brief parse a package name
* \param type what parts of the package to acquire
* \param default_archive override a default if the package does not have an archive component
* \param name the package name to parse
* \return t_uchar * parsed, heap allocated value
*/
t_uchar *
arch_parse_package_name (enum arch_parse_package_name_type type,
t_uchar const * default_archive,
t_uchar const * name)
{
invariant (arch_valid_package_name (name, arch_maybe_archive, arch_req_package, 1));
return arch_parse_name (type, default_archive, name);
}
/**
* \brief parse a package name
* \param type what parts of the package to acquire
* \param default_archive override a default if the package does not have an archive component
* \param name the package name to parse
* \return t_uchar * parsed, heap allocated value
*/
t_uchar *
arch_parse_name (enum arch_parse_package_name_type type,
t_uchar const * default_archive,
t_uchar const * name)
{
invariant (arch_valid_package_name (name, arch_maybe_archive, arch_req_package, 1)
|| (type == arch_ret_archive && arch_valid_archive_name (name)));
switch (type)
{
default:
panic ("bad argument to arch_parse_package_name");
return 0; /* notreached */
break;
case arch_ret_archive:
{
t_uchar * slash;
if (arch_valid_archive_name (name))
return str_save (0, name);
slash = str_chr_index (name, '/');
if (!slash)
{
t_uchar * answer = 0;
answer = arch_my_default_archive (default_archive);
if (!answer)
{
safe_printfmt (2, "arch: no default archive set\n");
exit (2);
}
return answer;
}
else
{
return str_save_n (0, name, slash - name);
}
break;
}
case arch_ret_non_archive:
{
t_uchar * slash;
slash = str_chr_index (name, '/');
if (!slash)
return str_save (0, name);
else
return str_save (0, slash + 1);
break;
}
case arch_ret_category:
{
t_uchar const * cat_end;
name = over_opt_archive_prefix (name);
cat_end = over_basename (name);
return str_save_n (0, name, cat_end - name);
break;
}
case arch_ret_branch:
{
t_uchar const * branch_end;
name = over_opt_archive_prefix (name);
name = over_basename (name); /* over category */
name = over_separator (name);
if (!name)
return str_save (0, "");
branch_end = over_basename (name);
if (!branch_end)
return str_save (0, "");
return str_save_n (0, name, branch_end - name);
break;
}
case arch_ret_package:
{
t_uchar const * branch_end;
t_uchar const * t;
name = over_opt_archive_prefix (name);
branch_end = over_basename (name);
t = over_separator (branch_end);
if (!t)
return str_save (0, name); /* only category provided */
branch_end = over_basename (t); /* over category */
if (!branch_end)
return str_save_n (0, name, (t - 2) - name); /* category--version */
else
return str_save_n (0, name, branch_end - name);
break;
}
case arch_ret_version:
{
t_uchar const * version_start = find_version_start (name);
t_uchar const * version_end = find_version_end (version_start);
return str_save_n (0, version_start, version_end - version_start);
break;
}
case arch_ret_patch_level:
{
t_uchar const * t;
name = over_opt_archive_prefix (name);
invariant (!!name);
name = over_basename (name);
invariant (!!name);
name = over_separator (name);
invariant (!!name);
t = over_basename (name); /* maybe over explicit branch */
if (t)
{
name = over_separator (t);
invariant (!!name);
}
name = over_version (name);
invariant (!!name);
invariant (name[0]);
name = over_separator (name);
invariant (!!name);
invariant (name[0]);
return str_save (0, name);
break;
}
case arch_ret_package_version:
{
t_uchar const * version_start;
t_uchar const * version_end;
t_uchar const * t;
name = over_opt_archive_prefix (name);
version_end = over_basename (name); /* over category */
version_end = over_separator (version_end);
invariant (!!version_end);
version_start = version_end;
t = over_basename (version_start); /* maybe over explicit branch */
if (t)
{
version_end = over_separator (t);
invariant (!!version_end);
version_start = version_end;
}
version_end = over_version (version_end);
invariant (!!version_end);
return str_save_n (0, name, version_end - name);
break;
}
case arch_ret_fqversion:
{
t_uchar const * version_end = find_version_end (find_version_start (name));
return str_save_n (0, name, version_end - name);
break;
}
}
}
t_uchar *
arch_fully_qualify (t_uchar const * const archive, t_uchar const * const name)
{
invariant (arch_valid_package_name (name, arch_maybe_archive, arch_req_package, 1));
if (archive)
invariant (arch_valid_archive_name (archive));
if (str_chr_index (name, '/'))
return str_save (0, name);
else
{
t_uchar * default_archive = str_save (0, archive);
if (!str_length (default_archive))
default_archive = arch_my_default_archive (NULL);
if (!default_archive)
panic ("arch: no default archive set");
return str_realloc_cat_many (0, default_archive, "/", name, str_end);
}
}
int
arch_names_cmp (t_uchar const * a, t_uchar const * b)
{
t_uchar const * a_nxt;
t_uchar const * b_nxt;
int res;
/* compare archive name
*/
a_nxt = over_opt_archive_prefix (a);
b_nxt = over_opt_archive_prefix (b);
res = str_cmp_n (a, a_nxt - a, b, b_nxt - b);
if (res)
return res;
a = a_nxt;
b = b_nxt;
/* compare category name
*/
a_nxt = over_basename (a);
b_nxt = over_basename (b);
res = str_cmp_n (a, a_nxt - a, b, b_nxt - b);
if (res)
return res;
if (!*a_nxt && !*b_nxt)
return 0;
if (!*a_nxt)
return -1;
if (!*b_nxt)
return 1;
a = over_separator (a_nxt);
b = over_separator (b_nxt);
/* compare branch names
*/
a_nxt = over_basename (a);
b_nxt = over_basename (b);
if (a_nxt && !b_nxt)
{
/* a has a branch, b does not */
return 1;
}
else if (!a_nxt && b_nxt)
{
/* b has a branch, a does not */
return -1;
}
else if (a_nxt && b_nxt)
{
/* both have branch names */
res = str_cmp_n (a, a_nxt - a, b, b_nxt - b);
if (res)
return res;
if (!*a_nxt && !*b_nxt)
return 0;
if (!*a_nxt)
return -1;
if (!*b_nxt)
return 1;
a = over_separator (a_nxt);
b = over_separator (b_nxt);
}
/* compare version names
*/
a_nxt = over_version (a);
b_nxt = over_version (b);
res = version_cmp_n (a, a_nxt - a, b, b_nxt - b);
if (res < 0)
return -1;
else if (res > 0)
return 1;
a = over_separator (a_nxt);
b = over_separator (b_nxt);
if (!a && !b)
return 0;
else if (a && !b)
return 1;
else if (!a && b)
return -1;
/* compare patch level phase
*/
{
t_uchar * a_dash;
t_uchar * b_dash;
a_dash = str_chr_index (a, '-');
b_dash = str_chr_index (b, '-');
invariant (a && b);
res = str_cmp_n (a, a_dash - a, b, b_dash - b);
if (res)
return res;
a = a_dash + 1;
b = b_dash + 1;
}
/* compare patch level numbers
*/
{
int errn;
t_ulong a_lvl;
t_ulong b_lvl;
invariant (!cvt_decimal_to_ulong (&errn, &a_lvl, a, str_length (a)));
invariant (!cvt_decimal_to_ulong (&errn, &b_lvl, b, str_length (b)));
if (a_lvl < b_lvl)
return -1;
else if (a_lvl > b_lvl)
return 1;
else
return 0;
}
}
static int
version_cmp_n (const t_uchar * a, size_t a_l, const t_uchar * b, size_t b_l)
{
t_uchar * a_colon;
t_uchar * b_colon;
t_ulong a_epoch;
t_ulong b_epoch;
int errn;
a_colon = str_chr_index_n (a, a_l, ':');
if (a_colon) {
invariant (!cvt_decimal_to_ulong (&errn, &a_epoch, a, a_colon - a));
a_l -= (a_colon - a) - 1;
a = a_colon + 1;
} else
a_epoch = 0;
b_colon = str_chr_index (b, ':');
if (b_colon) {
invariant (!cvt_decimal_to_ulong (&errn, &b_epoch, b, b_colon - b));
b_l -= (b_colon - b) - 1;
b = b_colon + 1;
} else
b_epoch = 0;
if (a_epoch < b_epoch)
return -1;
else if (a_epoch > b_epoch)
return 1;
else
return ver_cmp_n (a, a_l, b, b_l);
}
static int
ver_order (t_uchar c)
{
if (c == '~')
return -1;
else if (char_is_digit (c))
return 0;
else if (char_is_alpha (c))
return c;
else
return c + 256;
}
static int
ver_cmp_n (const t_uchar * a, size_t a_l, const t_uchar * b, size_t b_l)
{
while ((*a && a_l) || (*b && b_l))
{
int first_diff = 0;
while ((*a && a_l && !char_is_digit (*a))
|| (*b && b_l && !char_is_digit (*b)))
{
int ac, bc;
ac = (*a && a_l) ? ver_order (*a) : 0;
bc = (*b && b_l) ? ver_order (*b) : 0;
if (ac != bc)
return ac - bc;
++a, --a_l;
++b, --b_l;
}
while ((*a == '0') && a_l) ++a, --a_l;
while ((*b == '0') && b_l) ++b, --b_l;
while (a_l && char_is_digit (*a) && b_l && char_is_digit (*b))
{
if (!first_diff)
first_diff = *a - *b;
++a, --a_l;
++b, --b_l;
}
if (a_l && char_is_digit (*a))
return 1;
else if (b_l && char_is_digit (*b))
return -1;
else if (first_diff)
return first_diff;
}
return 0;
}
struct arch_sort_spec
{
int reverse_p;
int field;
};
void
arch_sort_table_by_name_field (int reverse_p, rel_table table, int field)
{
struct arch_sort_spec spec;
spec.reverse_p = reverse_p;
spec.field = field;
quicksort ((void *)table, rel_n_records (table), sizeof (rel_record), arch_cmp_by_field, (void *)&spec);
}
static int
arch_cmp_by_field (void * va, void * vb, void * vdata)
{
rel_record * a;
rel_record * b;
struct arch_sort_spec * spec;
a = (rel_record *)va;
b = (rel_record *)vb;
spec = (struct arch_sort_spec *)vdata;
if (spec->reverse_p)
{
return -arch_names_cmp ((*a)[spec->field], (*b)[spec->field]);
}
else
{
return arch_names_cmp ((*a)[spec->field], (*b)[spec->field]);
}
}
int
arch_patch_lvl_cmp (t_uchar * a, t_uchar * b)
{
t_uchar * a_dash;
t_uchar * b_dash;
int res;
t_ulong a_lvl;
t_ulong b_lvl;
int errn;
a_dash = str_chr_index (a, '-');
b_dash = str_chr_index (b, '-');
invariant (a_dash && b_dash);
res = str_cmp_n (a, a_dash - a, b, b_dash - b);
if (res)
return res;
invariant (!cvt_decimal_to_ulong (&errn, &a_lvl, a_dash + 1, str_length (a_dash + 1)));
invariant (!cvt_decimal_to_ulong (&errn, &b_lvl, b_dash + 1, str_length (b_dash + 1)));
if (a_lvl < b_lvl)
return -1;
else if (a_lvl > b_lvl)
return 1;
else
return 0;
}
void
arch_sort_table_by_patch_level_field (int reverse_p, rel_table table, int field)
{
struct arch_sort_spec spec;
spec.reverse_p = reverse_p;
spec.field = field;
quicksort ((void *)table, rel_n_records (table), sizeof (rel_record), arch_lvl_cmp_by_field, (void *)&spec);
}
static int
arch_lvl_cmp_by_field (void * va, void * vb, void * vdata)
{
rel_record * a;
rel_record * b;
struct arch_sort_spec * spec;
a = (rel_record *)va;
b = (rel_record *)vb;
spec = (struct arch_sort_spec *)vdata;
if (spec->reverse_p)
{
return -arch_patch_lvl_cmp ((*a)[spec->field], (*b)[spec->field]);
}
else
{
return arch_patch_lvl_cmp ((*a)[spec->field], (*b)[spec->field]);
}
}
rel_table
arch_pick_archives_by_field (rel_table in, int field)
{
rel_table answer = 0;
int x;
for (x = 0; x < rel_n_records (in); ++x)
{
if (arch_valid_archive_name (in[x][field]))
rel_add_records (&answer, rel_copy_record (in[x]), 0);
}
return answer;
}
rel_table
arch_pick_categories_by_field (rel_table in, int field)
{
rel_table answer = 0;
int x;
for (x = 0; x < rel_n_records (in); ++x)
{
if (arch_valid_package_name (in[x][field], arch_no_archive, arch_req_category, 0))
rel_add_records (&answer, rel_copy_record (in[x]), 0);
}
return answer;
}
rel_table
arch_pick_branches_by_field (rel_table in, int field)
{
rel_table answer = 0;
int x;
for (x = 0; x < rel_n_records (in); ++x)
{
if (arch_valid_package_name (in[x][field], arch_no_archive, arch_req_package, 0))
rel_add_records (&answer, rel_copy_record (in[x]), 0);
}
return answer;
}
rel_table
arch_pick_versions_by_field (rel_table in, int field)
{
rel_table answer = 0;
int x;
for (x = 0; x < rel_n_records (in); ++x)
{
if (arch_valid_package_name (in[x][field], arch_no_archive, arch_req_version, 0))
rel_add_records (&answer, rel_copy_record (in[x]), 0);
}
return answer;
}
rel_table
arch_pick_revisions_by_field (rel_table in, int field)
{
rel_table answer = 0;
int x;
for (x = 0; x < rel_n_records (in); ++x)
{
if (arch_valid_package_name (in[x][field], arch_no_archive, arch_req_patch_level, 0))
rel_add_records (&answer, rel_copy_record (in[x]), 0);
}
return answer;
}
rel_table
arch_pick_patch_levels_by_field (rel_table in, int field)
{
rel_table answer = 0;
int x;
for (x = 0; x < rel_n_records (in); ++x)
{
if (arch_valid_patch_level_name (in[x][field]))
rel_add_records (&answer, rel_copy_record (in[x]), 0);
}
return answer;
}
enum arch_patch_level_type
arch_analyze_patch_level (t_ulong * n, t_uchar * patch_level)
{
int ign;
enum arch_patch_level_type type;
t_uchar * n_str;
if (!str_cmp ("base-0", patch_level))
{
*n = 0;
return arch_is_base0_level;
}
else if (!str_cmp_prefix ("patch-", patch_level))
{
type = arch_is_patch_level;
n_str = patch_level + sizeof ("patch-") - 1;
}
else if (!str_cmp_prefix ("version-", patch_level))
{
type = arch_is_version_level;
n_str = patch_level + sizeof ("version-") - 1;
}
else if (!str_cmp_prefix ("versionfix-", patch_level))
{
type = arch_is_versionfix_level;
n_str = patch_level + sizeof ("versionfix-") - 1;
}
else
panic ("illegal patch_level in arch_analyze_patch_level");
if (cvt_decimal_to_ulong (&ign, n, n_str, str_length (n_str)))
panic ("illegal patch_level in arch_analyze_patch_level");
return type;
}
int
arch_cmp_revision (t_uchar *a, t_uchar *b)
{
enum arch_patch_level_type a_type;
enum arch_patch_level_type b_type;
t_ulong a_level;
t_ulong b_level;
a_type = arch_analyze_patch_level (&a_level, a);
b_type = arch_analyze_patch_level (&b_level, b);
if (a_type != b_type)
return arch_cmp_patch_level_type (a_type, b_type);
else
if (a_level < b_level)
return -1;
if (b_level == a_level)
return 0;
else return 1;
}
int
arch_cmp_patch_level_type (enum arch_patch_level_type a, enum arch_patch_level_type b)
{
if (a == b)
return 0;
else if (a < b)
return -1;
else
return 1;
}
t_uchar *
arch_form_patch_level (enum arch_patch_level_type type, t_ulong n)
{
t_uchar n_buf[64];
cvt_ulong_to_decimal (n_buf, n);
switch (type)
{
case arch_is_base0_level:
{
return str_save (0, "base-0");
}
case arch_is_patch_level:
{
return str_alloc_cat (0, "patch-", n_buf);
}
case arch_is_version_level:
{
return str_alloc_cat (0, "version-", n_buf);
}
case arch_is_versionfix_level:
{
return str_alloc_cat (0, "versionfix-", n_buf);
}
default:
{
panic ("not reached in arch_form_patch_level");
return 0;
}
}
}
static t_uchar const *
over_opt_archive_prefix (t_uchar const * name)
{
t_uchar * slash;
t_uchar const * archive_name_end;
slash = str_chr_index (name, '/');
if (!slash)
return name;
archive_name_end = over_archive_name (name);
if (archive_name_end != slash)
return 0;
return slash + 1;
}
#define char_is_alnum_or_dash(c) (char_is_alnum (c) || (c == '-'))
static t_uchar const *
over_archive_name (t_uchar const * in)
{
if (!char_is_alnum_or_dash (*in))
return 0;
while (1)
{
while (char_is_alnum_or_dash (*in))
++in;
if (*in != '.' && *in != '_')
break;
if (!char_is_alnum_or_dash (in[1]))
return 0;
++in;
}
if (*in != '@')
return 0;
++in;
while (char_is_alnum_or_dash(*in) || (*in == '.'))
{
if ((*in == '-') && (in[1] == '-'))
break;
++in;
}
if (!*in || (*in == '/'))
return in;
if ((in[0] != '-') || (in[1] != '-'))
return 0;
in += 2;
while (char_is_alnum_or_dash(*in) || (*in == '.'))
++in;
if (*in && (*in != '/'))
return 0;
return in;
}
static t_uchar const *
over_basename (t_uchar const * in)
{
if (!char_is_alpha (*in))
return 0;
++in;
while (1)
{
if (!*in)
return in;
else if ((char_is_alnum (*in)) || (*in == '%') || (*in == ','))
++in;
else if (*in == '-')
{
if (in[1] == '-')
return in;
else
++in;
}
else
break;
}
return 0;
}
static t_uchar const *
over_separator (t_uchar const * in)
{
if ((*in == '-') && (in[1] == '-'))
return in + 2;
else
return 0;
}
static t_uchar const *
over_version (t_uchar const * in)
{
if (!char_is_digit (*in))
return 0;
++in;
while (1)
{
if (!*in)
return in;
else if ((char_is_alnum (*in)) || (*in == '.') || (*in == '+')
|| (*in == ':') || (*in == '~'))
++in;
else if (*in == '-')
{
if (in[1] == '-')
return in;
else
++in;
}
else
break;
}
return 0;
}
static t_uchar const *
over_patch_level (t_uchar const * in)
{
if (!str_cmp (in, "base-0"))
return in + sizeof ("base-0") - 1;
else
{
int prefix_len;
if (!str_cmp_prefix ("patch-", in))
prefix_len = sizeof ("patch-") - 1;
else if (!str_cmp_prefix ("version-", in))
prefix_len = sizeof ("version-") - 1;
else if (!str_cmp_prefix ("versionfix-", in))
prefix_len = sizeof ("versionfix-") - 1;
else
return 0;
in += prefix_len;
if (!char_is_digit (*in))
return 0;
while (char_is_digit (*in))
++in;
if (*in)
return 0;
return in;
}
}
/* tag: Tom Lord Mon May 12 10:17:47 2003 (namespace.c)
*/
syntax highlighted by Code2HTML, v. 0.9.1