branch: use ref-filter printing APIs
[gitweb.git] / ref-filter.c
index ffa29446cfb92cda6087196313a232972fe87f8c..01b5c18ef084c1548822f41c14abfb36383a5e1b 100644 (file)
 #include "trailer.h"
 #include "wt-status.h"
 
+static struct ref_msg {
+       const char *gone;
+       const char *ahead;
+       const char *behind;
+       const char *ahead_behind;
+} msgs = {
+        /* Untranslated plumbing messages: */
+       "gone",
+       "ahead %d",
+       "behind %d",
+       "ahead %d, behind %d"
+};
+
+void setup_ref_filter_porcelain_msg(void)
+{
+       msgs.gone = _("gone");
+       msgs.ahead = _("ahead %d");
+       msgs.behind = _("behind %d");
+       msgs.ahead_behind = _("ahead %d, behind %d");
+}
+
 typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
 typedef enum { COMPARE_EQUAL, COMPARE_UNEQUAL, COMPARE_NONE } cmp_status;
 
@@ -33,8 +54,8 @@ struct if_then_else {
 };
 
 struct refname_atom {
-       enum { R_NORMAL, R_SHORT, R_STRIP } option;
-       unsigned int strip;
+       enum { R_NORMAL, R_SHORT, R_LSTRIP, R_RSTRIP } option;
+       int lstrip, rstrip;
 };
 
 /*
@@ -91,10 +112,14 @@ static void refname_atom_parser_internal(struct refname_atom *atom,
                atom->option = R_NORMAL;
        else if (!strcmp(arg, "short"))
                atom->option = R_SHORT;
-       else if (skip_prefix(arg, "strip=", &arg)) {
-               atom->option = R_STRIP;
-               if (strtoul_ui(arg, 10, &atom->strip) || atom->strip <= 0)
-                       die(_("positive value expected refname:strip=%s"), arg);
+       else if (skip_prefix(arg, "lstrip=", &arg)) {
+               atom->option = R_LSTRIP;
+               if (strtol_i(arg, 10, &atom->lstrip))
+                       die(_("Integer value expected refname:lstrip=%s"), arg);
+       } else if (skip_prefix(arg, "rstrip=", &arg)) {
+               atom->option = R_RSTRIP;
+               if (strtol_i(arg, 10, &atom->rstrip))
+                       die(_("Integer value expected refname:rstrip=%s"), arg);
        } else
                die(_("unrecognized %%(%s) argument: %s"), name, arg);
 }
@@ -1091,21 +1116,68 @@ static inline char *copy_advance(char *dst, const char *src)
        return dst;
 }
 
-static const char *strip_ref_components(const char *refname, unsigned int len)
+static const char *lstrip_ref_components(const char *refname, int len)
 {
        long remaining = len;
        const char *start = refname;
 
-       while (remaining) {
+       if (len < 0) {
+               int i;
+               const char *p = refname;
+
+               /* Find total no of '/' separated path-components */
+               for (i = 0; p[i]; p[i] == '/' ? i++ : *p++)
+                       ;
+               /*
+                * The number of components we need to strip is now
+                * the total minus the components to be left (Plus one
+                * because we count the number of '/', but the number
+                * of components is one more than the no of '/').
+                */
+               remaining = i + len + 1;
+       }
+
+       while (remaining > 0) {
                switch (*start++) {
                case '\0':
-                       die(_("ref '%s' does not have %ud components to :strip"),
-                           refname, len);
+                       return "";
                case '/':
                        remaining--;
                        break;
                }
        }
+
+       return start;
+}
+
+static const char *rstrip_ref_components(const char *refname, int len)
+{
+       long remaining = len;
+       char *start = xstrdup(refname);
+
+       if (len < 0) {
+               int i;
+               const char *p = refname;
+
+               /* Find total no of '/' separated path-components */
+               for (i = 0; p[i]; p[i] == '/' ? i++ : *p++)
+                       ;
+               /*
+                * The number of components we need to strip is now
+                * the total minus the components to be left (Plus one
+                * because we count the number of '/', but the number
+                * of components is one more than the no of '/').
+                */
+               remaining = i + len + 1;
+       }
+
+       while (remaining-- > 0) {
+               char *p = strrchr(start, '/');
+               if (p == NULL)
+                       return "";
+               else
+                       p[0] = '\0';
+       }
        return start;
 }
 
@@ -1113,8 +1185,10 @@ static const char *show_ref(struct refname_atom *atom, const char *refname)
 {
        if (atom->option == R_SHORT)
                return shorten_unambiguous_ref(refname, warn_ambiguous_refs);
-       else if (atom->option == R_STRIP)
-               return strip_ref_components(refname, atom->strip);
+       else if (atom->option == R_LSTRIP)
+               return lstrip_ref_components(refname, atom->lstrip);
+       else if (atom->option == R_RSTRIP)
+               return rstrip_ref_components(refname, atom->rstrip);
        else
                return refname;
 }
@@ -1128,15 +1202,15 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
        else if (atom->u.remote_ref.option == RR_TRACK) {
                if (stat_tracking_info(branch, &num_ours,
                                       &num_theirs, NULL)) {
-                       *s = xstrdup("gone");
+                       *s = xstrdup(msgs.gone);
                } else if (!num_ours && !num_theirs)
                        *s = "";
                else if (!num_ours)
-                       *s = xstrfmt("behind %d", num_theirs);
+                       *s = xstrfmt(msgs.behind, num_theirs);
                else if (!num_theirs)
-                       *s = xstrfmt("ahead %d", num_ours);
+                       *s = xstrfmt(msgs.ahead, num_ours);
                else
-                       *s = xstrfmt("ahead %d, behind %d",
+                       *s = xstrfmt(msgs.ahead_behind,
                                     num_ours, num_theirs);
                if (!atom->u.remote_ref.nobracket && *s[0]) {
                        const char *to_free = *s;