/** * Compute character mask "hash", using one bit per letter of the alphabet, * plus one for any digit. */ static guint32 mask_hash(const char *s) { guchar c; guint32 mask = 0; while ((c = (guchar) *s++)) { if (is_ascii_space(c)) continue; else if (is_ascii_digit(c)) mask |= MASK_DIGIT; else { int idx = ascii_tolower(c) - 97; if (idx >= 0 && idx < 26) mask |= MASK_LETTER(idx); } } return mask; }
/** * Parse gtk-gnutella's version number in User-Agent/Server string `str' * and extract relevant information into `ver'. * * @param str the version string to be parsed * @param ver the structure filled with parsed information * @param end filled with a pointer to the first unparsed character * * @returns TRUE if we parsed a gtk-gnutella version correctly, FALSE if we * were not facing a gtk-gnutella version, or if we did not recognize it. */ static bool version_parse(const char *str, version_t *ver, const char **end) { const char *v; int error; /* * Modern version numbers are formatted like this: * * gtk-gnutella/0.85 (04/04/2002; X11; FreeBSD 4.6-STABLE i386) * gtk-gnutella/0.90u (24/06/2002; X11; Linux 2.4.18-pre7 i686) * gtk-gnutella/0.90b (24/06/2002; X11; Linux 2.4.18-2emi i686) * gtk-gnutella/0.90b2 (24/06/2002; X11; Linux 2.4.18-2emi i686) * * The letter after the version number is either 'u' for unstable, 'a' * for alpha, 'b' for beta, or nothing for a stable release. It can be * followed by digits when present. * * In prevision for future possible extensions, we also parse * * gtk-gnutella/0.90.1b2 (24/06/2002; X11; Linux 2.4.18-2emi i686) * * where the third number is the "patchlevel". * * Starting 2006-08-26, the user-agent string includes the SVN revision * at the time of the build. To be compatible with the servents out * there, the version is included as an optional tag following the date. * * gtk-gnutella/0.85 (04/04/2002; r3404; X11; FreeBSD 4.6-STABLE i386) * * However, we also start parsing the new format that we shall use when * all current GTKG out there have expired: * * gtk-gnutella/0.85-3404 (04/04/2002; X11; FreeBSD 4.6-STABLE i386) * gtk-gnutella/0.90b2-3404 (04/04/2002; X11; FreeBSD 4.6-STABLE i386) * * where the '-3404' introduces the build number. * * Since switching to git (2011-09-11), the SVN build is no longer present * but rather the output of "git describe" is used to show any difference * with the latest release tag. * * A release would be described as: * * gtk-gnutella/0.97.1 (2011-09-11; GTK1; Linux i686) * * but any change on top of that would be seen as: * * gtk-gnutella/0.97.1-24-g844b7 (2011-09-11; GTK1; Linux i686) * * to indicate that 24 commits were made after the release, and the commit * ID is 844b7... (only enough hexadecimal digits are output to make the * string unique at the time it was generated. * * If furthermore a build is done from a dirty git repository, the string * "-dirty" is appended after the commit ID: * * gtk-gnutella/0.97.1-24-g844b7-dirty (2011-09-11; GTK1; Linux i686) */ if (NULL == (v = is_strprefix(str, GTA_PRODUCT_NAME "/"))) return FALSE; /* * Parse "major.minor", followed by optional ".patchlevel". */ ver->major = parse_uint32(v, &v, 10, &error); if (error) return FALSE; if (*v++ != '.') return FALSE; ver->minor = parse_uint32(v, &v, 10, &error); if (error) return FALSE; if ('.' == *v) { v++; ver->patchlevel = parse_uint32(v, &v, 10, &error); if (error) return FALSE; } else ver->patchlevel = 0; /* * Parse optional tag letter "x" followed by optional "taglevel". */ if (is_ascii_alpha(*v)) { ver->tag = *v++; if (is_ascii_digit(*v)) { ver->taglevel = parse_uint32(v, &v, 10, &error); if (error) return FALSE; } else ver->taglevel = 0; } else { ver->tag = '\0'; ver->taglevel = 0; } /* * Parse optional "-build" (legacy SVN) or "-change-bxxxxxxxx" (git * version scheme) to be able to sort identical versions with distinct * changes applied to them. */ if ('-' == *v) { v++; if (!is_strprefix(v, "dirty")) { ver->build = parse_uint32(v, &v, 10, &error); if (error) return FALSE; } } else ver->build = 0; if (end != NULL) *end = v; if (GNET_PROPERTY(version_debug) > 1) version_dump(str, ver, "#"); return TRUE; }