The id(1)-parsing is real fun.
Jarkko Hietaniemi [Mon, 2 Nov 1998 12:58:13 +0000 (12:58 +0000)]
p4raw-id: //depot/cfgperl@2183

t/op/groups.t

index 1eef0bf..6f7f8c4 100755 (executable)
@@ -8,7 +8,17 @@ $ENV{PATH} = '/usr/xpg4/bin:/bin:/usr/bin:/usr/ucb';
 # id -Gn
 # id -a
 # Beware 1: some systems do just 'id -G' even when 'id -Gn' is used.
-# Beware 2: the 'id -a' output format is tricky.
+# Beware 2: id -Gn or id -a format might be id(name) or name(id).
+# Beware 3: the groups= might be anywhere in the id output.
+#
+# That is, we might meet the following:
+#
+# foo bar zot                  # accept
+# 1 2 3                                # reject
+# groups=foo(1),bar(2),zot(3)  # parse
+# groups=1(foo),2(bar),3(zot)  # parse
+#
+# and the groups= might be after, before, or between uid=... and gid=...
 
 GROUPS: {
     last GROUPS if ($groups = `groups 2>/dev/null`) ne '';
@@ -16,16 +26,33 @@ GROUPS: {
        last GROUPS unless $groups =~ /^(\d+)(\s+\d)*$/;
     }
     if ($groups = `id -a 2>/dev/null` ne '') {
-       if (/groups=/g && (@g = /\((.+?)\)/g)) {
-           $groups = join(" ", @g);
-           last GROUPS;
-       }
+       # Grok format soon.
+       last GROUPS;
     }
     # Okay, not today.
     print "1..0\n";
     exit 0;
 }
 
+# Remember that group names can contain whitespace, '-', et cetera.
+# That is: do not \w, do not \S.
+if ($groups =~ /groups=((.+?\(.+?\))(,.+?\(.+?\))*)( [ug]id=|$)/) {
+    my $gr = $1;
+    my @g0 = $gr =~ /(.+?)\((.+?)\),?/g;
+    my @g1 = @g0[ map { $_ * 2     } 0..$#g0/2 ];
+    my @g2 = @g0[ map { $_ * 2 + 1 } 0..$#g0/2 ];
+    print "# g0 = @g0\n";
+    print "# g1 = @g1\n";
+    print "# g2 = @g2\n";
+    if (grep /\D/, @g1) {
+       $groups = join(" ", @g1);
+    } elsif (grep /\D/, @g2) {
+       $groups = join(" ", @g2);
+    } else {
+       # Let's fail.  We want to parse the output.  Really.
+    }
+}
+
 print "1..2\n";
 
 $pwgid = $( + 0;