Merge "Remove BUILD.bazel files" into main
diff --git a/ci/build_test_suites.py b/ci/build_test_suites.py
index b67ecec..343a177 100644
--- a/ci/build_test_suites.py
+++ b/ci/build_test_suites.py
@@ -112,6 +112,7 @@
           get_metrics_agent().report_optimized_target(target)
         except Exception as e:
           logging.error(f'unable to parse test discovery output: {repr(e)}')
+          get_metrics_agent().report_unoptimized_target(target, f'Error in parsing test discovery output for {target}: {repr(e)}')
 
     for target in preliminary_build_targets:
       target_optimizer_getter = self.target_optimizations.get(target, None)
diff --git a/core/Makefile b/core/Makefile
index e106dad..9728b52 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -970,12 +970,27 @@
 
 # -----------------------------------------------------------------
 
+.PHONY: event-log-tags
+
+# Produce an event logs tag file for everything we know about, in order
+# to properly allocate numbers.  Then produce a file that's filtered
+# for what's going to be installed.
+
+all_event_log_tags_file := $(TARGET_OUT_COMMON_INTERMEDIATES)/all-event-log-tags.txt
+
 event_log_tags_file := $(TARGET_OUT)/etc/event-log-tags
 
 # Include tags from all packages that we know about
 all_event_log_tags_src := \
     $(sort $(foreach m, $(ALL_MODULES), $(ALL_MODULES.$(m).EVENT_LOG_TAGS)))
 
+$(all_event_log_tags_file): PRIVATE_SRC_FILES := $(all_event_log_tags_src)
+$(all_event_log_tags_file): $(all_event_log_tags_src) $(MERGETAGS) build/make/tools/event_log_tags.py
+	$(hide) mkdir -p $(dir $@)
+	$(hide) $(MERGETAGS) -o $@ $(PRIVATE_SRC_FILES)
+
+$(call declare-0p-target,$(all_event_log_tags_file))
+
 # Include tags from all packages included in this product, plus all
 # tags that are part of the system (ie, not in a vendor/ or device/
 # directory).
@@ -987,13 +1002,13 @@
       $(filter-out vendor/% device/% out/%,$(all_event_log_tags_src)))
 
 $(event_log_tags_file): PRIVATE_SRC_FILES := $(event_log_tags_src)
-$(event_log_tags_file): $(event_log_tags_src) $(MERGETAGS)
+$(event_log_tags_file): PRIVATE_MERGED_FILE := $(all_event_log_tags_file)
+$(event_log_tags_file): $(event_log_tags_src) $(all_event_log_tags_file) $(MERGETAGS) build/make/tools/event_log_tags.py
 	$(hide) mkdir -p $(dir $@)
-	$(hide) $(MERGETAGS) -o $@ $(PRIVATE_SRC_FILES)
+	$(hide) $(MERGETAGS) -o $@ -m $(PRIVATE_MERGED_FILE) $(PRIVATE_SRC_FILES)
 
 $(eval $(call declare-0p-target,$(event_log_tags_file)))
 
-.PHONY: event-log-tags
 event-log-tags: $(event_log_tags_file)
 
 ALL_DEFAULT_INSTALLED_MODULES += $(event_log_tags_file)
diff --git a/core/config.mk b/core/config.mk
index f30298d..d62b86d 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -731,7 +731,7 @@
 PROGUARD := $(PROGUARD_HOME)/bin/proguard.sh
 PROGUARD_DEPS := $(PROGUARD) $(PROGUARD_HOME)/lib/proguard.jar
 JAVATAGS := build/make/tools/java-event-log-tags.py
-MERGETAGS := $(HOST_OUT_EXECUTABLES)/merge-event-log-tags
+MERGETAGS := build/make/tools/merge-event-log-tags.py
 APPEND2SIMG := $(HOST_OUT_EXECUTABLES)/append2simg
 VERITY_SIGNER := $(HOST_OUT_EXECUTABLES)/verity_signer
 BUILD_VERITY_METADATA := $(HOST_OUT_EXECUTABLES)/build_verity_metadata
diff --git a/core/definitions.mk b/core/definitions.mk
index 1ab6388..adb35e0 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -1555,7 +1555,7 @@
 define transform-logtags-to-java
 @mkdir -p $(dir $@)
 @echo "logtags: $@ <= $<"
-$(hide) $(JAVATAGS) -o $@ $<
+$(hide) $(JAVATAGS) -o $@ $< $(PRIVATE_MERGED_TAG)
 endef
 
 
diff --git a/core/java.mk b/core/java.mk
index 35026db..5fbc916 100644
--- a/core/java.mk
+++ b/core/java.mk
@@ -140,6 +140,7 @@
 logtags_java_sources := $(patsubst %.logtags,%.java,$(addprefix $(intermediates.COMMON)/logtags/, $(logtags_sources)))
 logtags_sources := $(addprefix $(LOCAL_PATH)/, $(logtags_sources))
 
+$(logtags_java_sources): PRIVATE_MERGED_TAG := $(TARGET_OUT_COMMON_INTERMEDIATES)/all-event-log-tags.txt
 $(logtags_java_sources): $(intermediates.COMMON)/logtags/%.java: $(LOCAL_PATH)/%.logtags $(TARGET_OUT_COMMON_INTERMEDIATES)/all-event-log-tags.txt $(JAVATAGS) build/make/tools/event_log_tags.py
 	$(transform-logtags-to-java)
 
diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs
index 6674d02..0d528d2 100644
--- a/tools/aconfig/aconfig/src/codegen/java.rs
+++ b/tools/aconfig/aconfig/src/codegen/java.rs
@@ -875,6 +875,195 @@
     }
 
     #[test]
+    fn test_generate_java_code_new_exported() {
+        let parsed_flags = crate::test::parse_test_flags();
+        let mode = CodegenMode::Exported;
+        let modified_parsed_flags =
+            crate::commands::modify_parsed_flags_based_on_mode(parsed_flags, mode).unwrap();
+        let flag_ids =
+            assign_flag_ids(crate::test::TEST_PACKAGE, modified_parsed_flags.iter()).unwrap();
+        let generated_files = generate_java_code(
+            crate::test::TEST_PACKAGE,
+            modified_parsed_flags.into_iter(),
+            mode,
+            flag_ids,
+            true,
+            5801144784618221668,
+            true,
+        )
+        .unwrap();
+
+        let expect_flags_content = r#"
+        package com.android.aconfig.test;
+        /** @hide */
+        public final class Flags {
+            /** @hide */
+            public static final String FLAG_DISABLED_RW_EXPORTED = "com.android.aconfig.test.disabled_rw_exported";
+            /** @hide */
+            public static final String FLAG_ENABLED_FIXED_RO_EXPORTED = "com.android.aconfig.test.enabled_fixed_ro_exported";
+            /** @hide */
+            public static final String FLAG_ENABLED_RO_EXPORTED = "com.android.aconfig.test.enabled_ro_exported";
+            public static boolean disabledRwExported() {
+                return FEATURE_FLAGS.disabledRwExported();
+            }
+            public static boolean enabledFixedRoExported() {
+                return FEATURE_FLAGS.enabledFixedRoExported();
+            }
+            public static boolean enabledRoExported() {
+                return FEATURE_FLAGS.enabledRoExported();
+            }
+            private static FeatureFlags FEATURE_FLAGS = new FeatureFlagsImpl();
+        }
+        "#;
+
+        let expect_feature_flags_content = r#"
+        package com.android.aconfig.test;
+        /** @hide */
+        public interface FeatureFlags {
+            boolean disabledRwExported();
+            boolean enabledFixedRoExported();
+            boolean enabledRoExported();
+        }
+        "#;
+
+        let expect_feature_flags_impl_content = r#"
+        package com.android.aconfig.test;
+        import android.os.flagging.AconfigPackage;
+        import android.util.Log;
+        /** @hide */
+        public final class FeatureFlagsImpl implements FeatureFlags {
+            private static final String TAG = "com.android.aconfig.test.FeatureFlagsImpl_exported";
+            private static volatile boolean isCached = false;
+            private static boolean disabledRwExported = false;
+            private static boolean enabledFixedRoExported = false;
+            private static boolean enabledRoExported = false;
+            private void init() {
+                try {
+                    AconfigPackage reader = AconfigPackage.load("com.android.aconfig.test");
+                    disabledRwExported = reader.getBooleanFlagValue("disabled_rw_exported", false);
+                    enabledFixedRoExported = reader.getBooleanFlagValue("enabled_fixed_ro_exported", false);
+                    enabledRoExported = reader.getBooleanFlagValue("enabled_ro_exported", false);
+                } catch (Exception e) {
+                    // pass
+                    Log.e(TAG, e.toString());
+                } catch (NoClassDefFoundError e) {
+                    // for mainline module running on older devices.
+                    // This should be replaces to version check, after the version bump.
+                    Log.e(TAG, e.toString());
+                }
+                isCached = true;
+            }
+            @Override
+            public boolean disabledRwExported() {
+                if (!isCached) {
+                    init();
+                }
+                return disabledRwExported;
+            }
+            @Override
+            public boolean enabledFixedRoExported() {
+                if (!isCached) {
+                    init();
+                }
+                return enabledFixedRoExported;
+            }
+            @Override
+            public boolean enabledRoExported() {
+                if (!isCached) {
+                    init();
+                }
+                return enabledRoExported;
+            }
+        }"#;
+
+        let expect_custom_feature_flags_content = r#"
+        package com.android.aconfig.test;
+
+        import java.util.Arrays;
+        import java.util.HashSet;
+        import java.util.List;
+        import java.util.Set;
+        import java.util.function.BiPredicate;
+        import java.util.function.Predicate;
+
+        /** @hide */
+        public class CustomFeatureFlags implements FeatureFlags {
+
+            private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl;
+
+            public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) {
+                mGetValueImpl = getValueImpl;
+            }
+
+            @Override
+            public boolean disabledRwExported() {
+                return getValue(Flags.FLAG_DISABLED_RW_EXPORTED,
+                    FeatureFlags::disabledRwExported);
+            }
+            @Override
+            public boolean enabledFixedRoExported() {
+                return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED,
+                    FeatureFlags::enabledFixedRoExported);
+            }
+            @Override
+            public boolean enabledRoExported() {
+                return getValue(Flags.FLAG_ENABLED_RO_EXPORTED,
+                    FeatureFlags::enabledRoExported);
+            }
+
+            protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) {
+                return mGetValueImpl.test(flagName, getter);
+            }
+
+            public List<String> getFlagNames() {
+                return Arrays.asList(
+                    Flags.FLAG_DISABLED_RW_EXPORTED,
+                    Flags.FLAG_ENABLED_FIXED_RO_EXPORTED,
+                    Flags.FLAG_ENABLED_RO_EXPORTED
+                );
+            }
+
+            private Set<String> mReadOnlyFlagsSet = new HashSet<>(
+                Arrays.asList(
+                    ""
+                )
+            );
+        }
+    "#;
+
+        let mut file_set = HashMap::from([
+            ("com/android/aconfig/test/Flags.java", expect_flags_content),
+            ("com/android/aconfig/test/FeatureFlags.java", expect_feature_flags_content),
+            ("com/android/aconfig/test/FeatureFlagsImpl.java", expect_feature_flags_impl_content),
+            (
+                "com/android/aconfig/test/CustomFeatureFlags.java",
+                expect_custom_feature_flags_content,
+            ),
+            (
+                "com/android/aconfig/test/FakeFeatureFlagsImpl.java",
+                EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT,
+            ),
+        ]);
+
+        for file in generated_files {
+            let file_path = file.path.to_str().unwrap();
+            assert!(file_set.contains_key(file_path), "Cannot find {}", file_path);
+            assert_eq!(
+                None,
+                crate::test::first_significant_code_diff(
+                    file_set.get(file_path).unwrap(),
+                    &String::from_utf8(file.contents).unwrap()
+                ),
+                "File {} content is not correct",
+                file_path
+            );
+            file_set.remove(file_path);
+        }
+
+        assert!(file_set.is_empty());
+    }
+
+    #[test]
     fn test_generate_java_code_test() {
         let parsed_flags = crate::test::parse_test_flags();
         let mode = CodegenMode::Test;
diff --git a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
index b605e72..8b3d3e1 100644
--- a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
+++ b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
@@ -65,6 +65,45 @@
 {{ endfor }}
 }
 {{ -else- }}{#- device config for exproted mode #}
+{{ -if new_exported }}
+import android.os.flagging.AconfigPackage;
+import android.util.Log;
+/** @hide */
+public final class FeatureFlagsImpl implements FeatureFlags \{
+    private static final String TAG = "{package_name}.FeatureFlagsImpl_exported";
+    private static volatile boolean isCached = false;
+{{ for flag in flag_elements }}
+    private static boolean {flag.method_name} = {flag.default_value};
+{{ -endfor }}
+    private void init() \{
+        try \{
+            AconfigPackage reader = AconfigPackage.load("{package_name}");
+            {{ -for namespace_with_flags in namespace_flags }}
+            {{ -for flag in namespace_with_flags.flags }}
+            {flag.method_name} = reader.getBooleanFlagValue("{flag.flag_name}", {flag.default_value});
+            {{ -endfor }}
+            {{ -endfor }}
+        } catch (Exception e) \{
+            // pass
+            Log.e(TAG, e.toString());
+        } catch (NoClassDefFoundError e) \{
+            // for mainline module running on older devices.
+            // This should be replaces to version check, after the version bump.
+            Log.e(TAG, e.toString());
+        }
+        isCached = true;
+    }
+{{ -for flag in flag_elements }}
+    @Override
+    public boolean {flag.method_name}() \{
+        if (!isCached) \{
+            init();
+        }
+        return {flag.method_name};
+    }
+{{ endfor }}
+}
+{{ else }}
 import android.os.Binder;
 import android.provider.DeviceConfig;
 import android.provider.DeviceConfig.Properties;
@@ -116,6 +155,7 @@
     }
 {{ endfor }}
 }
+{{ -endif- }} {#- end new_exported mode #}
 {{ -endif- }} {#- end exported mode #}
 {{ else }} {#- else for allow_instrumentation is not enabled #}
 {{ if not library_exported- }}
diff --git a/tools/event_log_tags.py b/tools/event_log_tags.py
index e859b6b..a6ae9f1 100644
--- a/tools/event_log_tags.py
+++ b/tools/event_log_tags.py
@@ -14,21 +14,21 @@
 
 """A module for reading and parsing event-log-tags files."""
 
-import dataclasses
 import re
 import sys
-from typing import Optional
 
-@dataclasses.dataclass
-class Tag:
-  tagnum: int
-  tagname: str
-  description: Optional[str]
-  filename: str
-  linenum: int
+class Tag(object):
+  __slots__ = ["tagnum", "tagname", "description", "filename", "linenum"]
+
+  def __init__(self, tagnum, tagname, description, filename, linenum):
+    self.tagnum = tagnum
+    self.tagname = tagname
+    self.description = description
+    self.filename = filename
+    self.linenum = linenum
 
 
-class TagFile:
+class TagFile(object):
   """Read an input event-log-tags file."""
   def AddError(self, msg, linenum=None):
     if linenum is None:
@@ -76,11 +76,14 @@
           self.options[parts[1]] = parts[2:]
           continue
 
-        try:
-          tag = int(parts[0])
-        except ValueError:
-          self.AddError("\"%s\" isn't an integer tag" % (parts[0],))
-          continue
+        if parts[0] == "?":
+          tag = None
+        else:
+          try:
+            tag = int(parts[0])
+          except ValueError:
+            self.AddError("\"%s\" isn't an integer tag or '?'" % (parts[0],))
+            continue
 
         tagname = parts[1]
         if len(parts) == 3:
@@ -125,8 +128,8 @@
       out = sys.stdout
       output_file = "<stdout>"
     else:
-      out = open(output_file, "w")
-    out.write(data)
+      out = open(output_file, "wb")
+    out.write(str.encode(data))
     out.close()
   except (IOError, OSError) as e:
     print("failed to write %s: %s" % (output_file, e), file=sys.stderr)
diff --git a/tools/java-event-log-tags.py b/tools/java-event-log-tags.py
index e3dc07e..bbd65fa 100755
--- a/tools/java-event-log-tags.py
+++ b/tools/java-event-log-tags.py
@@ -15,12 +15,16 @@
 # limitations under the License.
 
 """
+Usage: java-event-log-tags.py [-o output_file] <input_file> <merged_tags_file>
+
 Generate a java class containing constants for each of the event log
 tags in the given input file.
+
+-h to display this usage message and exit.
 """
 
 from io import StringIO
-import argparse
+import getopt
 import os
 import os.path
 import re
@@ -28,14 +32,57 @@
 
 import event_log_tags
 
-parser = argparse.ArgumentParser(description=__doc__)
-parser.add_argument('-o', dest='output_file')
-parser.add_argument('file')
-args = parser.parse_args()
+output_file = None
 
-fn = args.file
+try:
+  opts, args = getopt.getopt(sys.argv[1:], "ho:")
+except getopt.GetoptError as err:
+  print(str(err))
+  print(__doc__)
+  sys.exit(2)
+
+for o, a in opts:
+  if o == "-h":
+    print(__doc__)
+    sys.exit(2)
+  elif o == "-o":
+    output_file = a
+  else:
+    print("unhandled option %s" % (o,), file=sys.stderr)
+    sys.exit(1)
+
+if len(args) != 1 and len(args) != 2:
+  print("need one or two input files, not %d" % (len(args),))
+  print(__doc__)
+  sys.exit(1)
+
+fn = args[0]
 tagfile = event_log_tags.TagFile(fn)
 
+if len(args) > 1:
+  # Load the merged tag file (which should have numbers assigned for all
+  # tags.  Use the numbers from the merged file to fill in any missing
+  # numbers from the input file.
+  merged_fn = args[1]
+  merged_tagfile = event_log_tags.TagFile(merged_fn)
+  merged_by_name = dict([(t.tagname, t) for t in merged_tagfile.tags])
+  for t in tagfile.tags:
+    if t.tagnum is None:
+      if t.tagname in merged_by_name:
+        t.tagnum = merged_by_name[t.tagname].tagnum
+      else:
+        # We're building something that's not being included in the
+        # product, so its tags don't appear in the merged file.  Assign
+        # them all an arbitrary number so we can emit the java and
+        # compile the (unused) package.
+        t.tagnum = 999999
+else:
+  # Not using the merged tag file, so all tags must have manually assigned
+  # numbers
+  for t in tagfile.tags:
+    if t.tagnum is None:
+      tagfilef.AddError("tag \"%s\" has no number" % (tagname,), tag.linenum)
+
 if "java_package" not in tagfile.options:
   tagfile.AddError("java_package option not specified", linenum=0)
 
@@ -94,11 +141,11 @@
 for t in tagfile.tags:
   methodName = javaName("write_" + t.tagname)
   if t.description:
-    fn_args = [arg.strip("() ").split("|") for arg in t.description.split(",")]
+    args = [arg.strip("() ").split("|") for arg in t.description.split(",")]
   else:
-    fn_args = []
-  argTypesNames = ", ".join([javaTypes[int(arg[1])] + " " + javaName(arg[0]) for arg in fn_args])
-  argNames = "".join([", " + javaName(arg[0]) for arg in fn_args])
+    args = []
+  argTypesNames = ", ".join([javaTypes[int(arg[1])] + " " + javaName(arg[0]) for arg in args])
+  argNames = "".join([", " + javaName(arg[0]) for arg in args])
   buffer.write("\n  public static void %s(%s) {" % (methodName, argTypesNames))
   buffer.write("\n    android.util.EventLog.writeEvent(%s%s);" % (t.tagname.upper(), argNames))
   buffer.write("\n  }\n")
@@ -106,8 +153,8 @@
 
 buffer.write("}\n");
 
-output_dir = os.path.dirname(args.output_file)
+output_dir = os.path.dirname(output_file)
 if not os.path.exists(output_dir):
   os.makedirs(output_dir)
 
-event_log_tags.WriteOutput(args.output_file, buffer)
+event_log_tags.WriteOutput(output_file, buffer)
diff --git a/tools/merge-event-log-tags.py b/tools/merge-event-log-tags.py
index 600a441..292604c 100755
--- a/tools/merge-event-log-tags.py
+++ b/tools/merge-event-log-tags.py
@@ -15,14 +15,21 @@
 # limitations under the License.
 
 """
+Usage: merge-event-log-tags.py [-o output_file] [input_files...]
+
 Merge together zero or more event-logs-tags files to produce a single
 output file, stripped of comments.  Checks that no tag numbers conflict
 and fails if they do.
+
+-h to display this usage message and exit.
 """
 
 from io import StringIO
-import argparse
-import hashlib
+import getopt
+try:
+  import hashlib
+except ImportError:
+  import md5 as hashlib
 import struct
 import sys
 
@@ -31,10 +38,32 @@
 errors = []
 warnings = []
 
-parser = argparse.ArgumentParser(description=__doc__)
-parser.add_argument('-o', dest='output_file')
-parser.add_argument('files', nargs='*')
-args = parser.parse_args()
+output_file = None
+pre_merged_file = None
+
+# Tags with a tag number of ? are assigned a tag in the range
+# [ASSIGN_START, ASSIGN_LIMIT).
+ASSIGN_START = 900000
+ASSIGN_LIMIT = 1000000
+
+try:
+  opts, args = getopt.getopt(sys.argv[1:], "ho:m:")
+except getopt.GetoptError as err:
+  print(str(err))
+  print(__doc__)
+  sys.exit(2)
+
+for o, a in opts:
+  if o == "-h":
+    print(__doc__)
+    sys.exit(2)
+  elif o == "-o":
+    output_file = a
+  elif o == "-m":
+    pre_merged_file = a
+  else:
+    print("unhandled option %s" % (o,), file=sys.stderr)
+    sys.exit(1)
 
 # Restrictions on tags:
 #
@@ -48,7 +77,12 @@
 by_tagname = {}
 by_tagnum = {}
 
-for fn in args.files:
+pre_merged_tags = {}
+if pre_merged_file:
+  for t in event_log_tags.TagFile(pre_merged_file).tags:
+    pre_merged_tags[t.tagname] = t
+
+for fn in args:
   tagfile = event_log_tags.TagFile(fn)
 
   for t in tagfile.tags:
@@ -59,6 +93,12 @@
     if t.tagname in by_tagname:
       orig = by_tagname[t.tagname]
 
+      # Allow an explicit tag number to define an implicit tag number
+      if orig.tagnum is None:
+        orig.tagnum = t.tagnum
+      elif t.tagnum is None:
+        t.tagnum = orig.tagnum
+
       if (t.tagnum == orig.tagnum and
           t.description == orig.description):
         # if the name and description are identical, issue a warning
@@ -100,6 +140,38 @@
   for fn, ln, msg in warnings:
     print("%s:%d: warning: %s" % (fn, ln, msg), file=sys.stderr)
 
+# Python's hash function (a) isn't great and (b) varies between
+# versions of python.  Using md5 is overkill here but is the same from
+# platform to platform and speed shouldn't matter in practice.
+def hashname(str):
+  d = hashlib.md5(str).digest()[:4]
+  return struct.unpack("!I", d)[0]
+
+# Assign a tag number to all the entries that say they want one
+# assigned.  We do this based on a hash of the tag name so that the
+# numbers should stay relatively stable as tags are added.
+
+# If we were provided pre-merged tags (w/ the -m option), then don't
+# ever try to allocate one, just fail if we don't have a number
+
+for name, t in sorted(by_tagname.items()):
+  if t.tagnum is None:
+    if pre_merged_tags:
+      try:
+        t.tagnum = pre_merged_tags[t.tagname]
+      except KeyError:
+        print("Error: Tag number not defined for tag `%s'. Have you done a full build?" % t.tagname,
+              file=sys.stderr)
+        sys.exit(1)
+    else:
+      while True:
+        x = (hashname(name) % (ASSIGN_LIMIT - ASSIGN_START - 1)) + ASSIGN_START
+        if x not in by_tagnum:
+          t.tagnum = x
+          by_tagnum[x] = t
+          break
+        name = "_" + name
+
 # by_tagnum should be complete now; we've assigned numbers to all tags.
 
 buffer = StringIO()
@@ -109,4 +181,4 @@
   else:
     buffer.write("%d %s\n" % (t.tagnum, t.tagname))
 
-event_log_tags.WriteOutput(args.output_file, buffer)
+event_log_tags.WriteOutput(output_file, buffer)