*! Version 1.0, Dirk Enzmann (20-Aug-2026)
*!
*! Shared subroutine used by loevh2_compare, loevh2_boot_compare, and
*! loevh2_svy_compare to implement the meta() option (see loevh2).

program define loevh2_meta_save

   version 16.0
   syntax , metaspec(string) source(string) setype(string) ///
      [ hsen(string) labels(string) label(string) hval(real -999999999) ///
        seval(real -999999999) nval(real -999999999) ///
        svywtype(string) svywexp(string) svycluster(string) ///
        svystrata(string) svyfpc(string) suffix(string) ///
        origframe(string) origchanged(integer -1) ]

   // Exactly one of the two calling conventions (hsen() vs. the
   // label()/hval()/seval()/nval() quartet) must be used.
   local _have_hsen = ("`hsen'" != "")
   local _have_single = ("`label'" != "" | `hval' != -999999999 | ///
                          `seval' != -999999999 | `nval' != -999999999)
   if `_have_hsen' & `_have_single' {
      di as error "loevh2_meta_save: specify either hsen() or " ///
                   "label()/hval()/seval()/nval(), not both"
      exit 198
   }
   if !`_have_hsen' & !`_have_single' {
      di as error "loevh2_meta_save: must specify either hsen() or " ///
                   "label()/hval()/seval()/nval()"
      exit 198
   }
   if `_have_single' & ("`label'" == "" | `hval' == -999999999 | ///
                         `seval' == -999999999 | `nval' == -999999999) {
      di as error "loevh2_meta_save: label(), hval(), seval(), and " ///
                   "nval() must all be supplied together"
      exit 198
   }

   // Single-row (no-compare) case: build a small one-row matrix with
   // the same shape/rowname convention as a caller-supplied hsen(),
   // then fall through to exactly the same code path below.
   //
   // Matrix rownames must be valid Stata names (letters, digits,
   // underscores only, <=32 chars) -- so the caller's `label()' text
   // is sanitized (special characters replaced with "_") ONLY for use
   // as the matrix rowname `_rowlab'. The ORIGINAL, unsanitized label
   // text is separately preserved in `_singlelab' and is what actually
   // gets stored in the saved .dta's "label" column below (see the
   // forvalues loop), so a descriptive label such as "West &
   // Farrington (1973) [1]" is NOT mangled into
   // "West___Farrington__1973___1_" merely because the single-row
   // calling convention needs a valid matrix rowname internally.
   local _singlelab ""
   if `_have_single' {
      tempname _single_hsen
      matrix `_single_hsen' = J(1, 3, .)
      matrix `_single_hsen'[1,1] = `hval'
      matrix `_single_hsen'[1,2] = `seval'
      matrix `_single_hsen'[1,3] = `nval'
      matrix colnames `_single_hsen' = H SE N
      local _rowlab = substr(ustrregexra(`"`label'"', "[^A-Za-z0-9_]", "_"), 1, 32)
      if "`_rowlab'" == "" local _rowlab = "_"
      matrix rownames `_single_hsen' = `_rowlab'
      local hsen "`_single_hsen'"
      local _singlelab `"`label'"'
   }

   // ---- Parse metaspec into filename + replace|append ----------------
   // metaspec is expected to be "filename, replace" or "filename, append"
   // (whitespace around the comma is tolerated). No default mode is
   // assumed: if the mode is missing or is anything other than exactly
   // "replace" or "append", loevh2_meta_save aborts with a clear error,
   // per the design decision that the user must always explicitly
   // choose between overwriting and appending.
   gettoken _mf _mm : metaspec, parse(",")
   local _mf = trim("`_mf'")
   local _mm = trim(subinstr("`_mm'", ",", "", 1))
   local _mm = lower("`_mm'")

   if "`_mf'" == "" {
      di as error "meta(): a filename is required, e.g. meta(myfile, replace)"
      exit 198
   }
   if "`_mm'" != "replace" & "`_mm'" != "append" {
      di as error "meta(): a mode of exactly replace or append " ///
                   "is required, e.g. meta(myfile, replace) or " ///
                   "meta(myfile, append)"
      exit 198
   }

   // Strip a trailing .dta extension (case-insensitive) from the user-
   // supplied filename, if present, so that both the .dta and .do
   // outputs share exactly the same base name regardless of whether the
   // user wrote meta(results) or meta(results.dta).
   local _base = "`_mf'"
   local _extpos = strlen("`_base'") - 4
   if `_extpos' > 0 {
      local _ext4 = lower(substr("`_base'", `_extpos'+1, 4))
      if "`_ext4'" == ".dta" local _base = substr("`_base'", 1, `_extpos')
   }

   // Append the caller-supplied suffix (may be empty, e.g. for plain
   // loevh2 calls) to the base name -- see the file header note above.
   local _base "`_base'`suffix'"

   local _dta "`_base'.dta"
   local _do  "`_base'.do"

   // Safety guard: the companion .do file at `_do' is always fully
   // (re)written from scratch by loevh2_meta_writedo (see that .ado's
   // own header for why it is unconditionally regenerated on every
   // call). If the user's meta() filename happens to coincide with an
   // unrelated, pre-existing .do file (e.g., a currently open/important
   // script of their own -- not one loevh2_meta_save itself wrote
   // earlier), silently overwriting it would be destructive. Guard
   // against this by refusing to proceed -- BEFORE any .dta is written
   // or appended to, in either mode -- unless `_do' does not yet exist,
   // or its very first line already carries loevh2_meta_writedo's own
   // "Auto-generated by loevh2_meta_save" marker comment.
   capture confirm file "`_do'"
   if _rc == 0 {
      tempname _doguard
      local _do_firstline ""
      capture noisily file open `_doguard' using "`_do'", read text
      if _rc == 0 {
         file read `_doguard' _do_firstline
         file close `_doguard'
      }
      if !strpos(`"`_do_firstline'"', "Auto-generated by loevh2_meta_save") {
         di _n as error "meta(): " as res "`_do' " _n as error ///
            "already exists and does not appear to be a companion file previously written by " _n ///
            "loevh2_meta_save (its first line does not carry the expected " as res `""Auto-generated by "' _n ///
            `"by loevh2_meta_save" "' as error "marker comment) -- refusing to overwrite it. Choose a " _n ///
            "different meta() filename, or remove/rename " _n ///
            as res "`_do' " as error "and/or " _n as res ///
            "`_dta' " _n as error ///
            "yourself first if you are certain it is safe to replace." as txt
         exit 602
      }
   }

   if "`_mm'" == "append" {
      capture confirm file "`_dta'"
      if _rc {
         di _n as error "meta(): append requested but" _n as res ///
            "`_dta '" _n as error ///
            "does not exist -- use " as res "meta(`_mf', replace) " ///
            as error "first." as txt
         exit 601
      }
   }

   // ---- append-mode only: peek at the MAXIMUM run_id already present
   // in the existing `_dta', so that the new run_id computed below
   // (whole-second clock resolution) can be nudged to be strictly
   // greater than it whenever both calls happen to land in the same
   // wall-clock second (e.g. two "loevh2 ..., compare meta()" calls --
   // the first with replace, the second with append -- executed back
   // to back). Without this, two such calls produce byte-for-byte
   // IDENTICAL run_id values (clock() truncates to whole seconds), so
   // rows contributed by genuinely different runs become
   // indistinguishable in the saved .dta (they'd wrongly appear as a
   // SINGLE run to -meta- / any later analysis keyed on run_id).
   //
   // On "replace" (a fresh, logically independent file/history), no
   // such check is made -- see the design note directly below where
   // `_now' is computed.
   tempname _prev_runid
   scalar `_prev_runid' = .
   if "`_mm'" == "append" {
      tempname _peekframe
      frame create `_peekframe'
      frame `_peekframe' {
         quietly use "`_dta'", clear
         capture confirm numeric variable run_id
         if _rc == 0 {
            quietly summarize run_id, meanonly
            if r(N) > 0 scalar `_prev_runid' = r(max)
         }
      }
      frame drop `_peekframe'
   }


   // ---- Build the rows to add, from the (caller-supplied or just-
   // built single-row) H_SE_N matrix -------------------------------
   // `hsen' is a k x 3 matrix (columns H, SE, N) with sanitized row
   // names (sub-sample labels), exactly as built by loevh2_compare /
   // loevh2_boot_compare / loevh2_svy_compare (or the single-row block
   // above). Only rows with non-missing H and SE are written (matching
   // the on-screen -compare- table, which already excludes degenerate
   // sub-samples).
   local _k = rowsof(`hsen')
   local _rn : rowfullnames `hsen'

   // run_id: a single timestamp (to the second), shared by every row
   // added in THIS call, so that rows contributed by different
   // loevh2/loevh2_boot/loevh2_svy invocations (even to the same file)
   // can be distinguished from one another later.
   local _now = clock(c(current_date) + " " + c(current_time), "DMYhms")

   // Append-mode tie-breaker: if this call's whole-second run_id would
   // not be strictly greater than the MAXIMUM run_id already present
   // in the existing `_dta' (peeked above, into `_prev_runid'), nudge
   // `_now' up by a tiny sub-second fractional increment (0.001 %tc
   // units = 1 millisecond) so the two runs remain distinguishable by
   // run_id -- e.g. for -meta-'s own subgroup()/by-run analyses, or any
   // later "list run_id ..." / "bysort run_id:" style inspection of the
   // saved .dta. Since %tc's default display format rounds/shows only
   // whole seconds, both runs still visually DISPLAY as the identical
   // second (as one would expect/want), even though their underlying
   // stored numeric values now differ. Only relevant on "append" --
   // see the note above `_prev_runid' for why "replace" is exempt.
   if "`_mm'" == "append" & !missing(scalar(`_prev_runid')) {
      if `_now' <= scalar(`_prev_runid') {
         local _now = scalar(`_prev_runid') + 0.001
      }
   }


   tempname _addframe
   frame create `_addframe' ///
      double(run_id H SE N) ///
      str32 label str32 source str40 se_type ///
      str40 svy_wtype str80 svy_wexp str32 svy_cluster ///
      str32 svy_strata str32 svy_fpc

   // Pre-split the caller-supplied labels() string (one compound-
   // quoted label per hsen() row, e.g.
   // `" "West & Farrington (1973) [1]"' "Farrington (1979) [1]"' ... "')
   // into positional locals 1, 2, 3, ... via -tokenize-, done ONCE
   // here, before the forvalues loop below. This is NOT equivalent to
   // the (broken) alternative of using `: word `_i' of `labels'' inside
   // the loop: by the time `labels' reaches this point (having been
   // passed through syntax's string(asis) option handling), its
   // embedded `"..."' sequences are literal quote/backtick CHARACTERS
   // stored inside the macro's text, not live nested compound quotes.
   // `: word of` (an extended macro function) splits purely on
   // whitespace and does NOT re-interpret literal embedded quote
   // characters as quoting, so a multi-word label such as "West &
   // Farrington (1973) [1]" was being split into several separate
   // "words" at each internal space -- with sometimes bizarre
   // downstream consequences (e.g. an isolated word like "Farrington"
   // later being treated as a variable/command name, triggering
   // "Farrington not found"). By contrast, -tokenize-, when handed
   // `"`labels'"' (i.e. re-wrapped in ITS OWN fresh pair of compound
   // double quotes), has that whole expression evaluated by Stata's
   // parser at expansion time, which DOES correctly re-interpret the
   // embedded `"..."' sequences as live nested compound quotes -- so
   // each label, however many internal words/special characters it
   // contains, is correctly delivered as its own single positional
   // token (1, 2, 3, ...), matching hsen() row order.
   if `"`labels'"' != "" {
      tokenize `"`labels'"'
   }


   local _added = 0
   frame `_addframe' {
      forvalues _i = 1/`_k' {
         local _hv = `hsen'[`_i',1]
         local _sv = `hsen'[`_i',2]
         local _nv = `hsen'[`_i',3]
         if missing(`_hv') | missing(`_sv') continue
         local ++_added
         qui set obs `_added'
         // Prefer the caller-supplied full descriptive label (from
         // labels(), one quoted word per hsen() row, in row order) over
         // the hsen matrix's own rowname -- the latter is, as of this
         // version, a short, non-descriptive "group N" placeholder (see
         // loevh2.ado's loevh2_compare header comment for the
         // rationale). For the single-row calling convention (where
         // labels() is never supplied), prefer the ORIGINAL, unsanitized
         // `_singlelab' preserved above over the matrix rowname `_rn'
         // (which is sanitized, since matrix rownames must be valid
         // Stata names) -- so a descriptive label such as "West &
         // Farrington (1973) [1]" is stored in the "label" column
         // exactly as supplied, not mangled into
         // "West___Farrington__1973___1_". The sanitized rowname
         // remains only a final fallback, for the (unexpected) case
         // where `_singlelab' is somehow empty.
         if `"`labels'"' != "" {
            local _lab `"``_i''"'
         }
         else if `"`_singlelab'"' != "" {
            local _lab `"`_singlelab'"'
         }
         else {
            local _lab : word `_i' of `_rn'
         }

         qui replace run_id      = `_now'          in `_added'
         qui replace H           = `_hv'           in `_added'
         qui replace SE          = `_sv'           in `_added'
         qui replace N           = `_nv'           in `_added'
         qui replace label       = "`_lab'"        in `_added'
         qui replace source      = "`source'"      in `_added'
         qui replace se_type     = `"`setype'"'    in `_added'
         qui replace svy_wtype   = `"`svywtype'"'  in `_added'
         qui replace svy_wexp    = `"`svywexp'"'   in `_added'
         qui replace svy_cluster = `"`svycluster'"' in `_added'
         qui replace svy_strata  = `"`svystrata'"' in `_added'
         qui replace svy_fpc     = `"`svyfpc'"'    in `_added'
      }
      format run_id %tc
   }

   if `_added' == 0 {
      di as error "meta(): no valid (non-missing H/SE) sub-samples to " ///
                   "save -- nothing written to `_dta'"
      frame drop `_addframe'
      exit
   }

   di _n
   if "`_mm'" == "replace" {
      frame `_addframe': save "`_dta'", replace
      di as txt _n "meta(): " as res `_added' as txt ///
         " sub-sample row(s) written to " as res "`_dta'"
   }
   else {
      // Append mode: load the existing .dta into its own frame, append
      // the newly-built rows onto it there, then save back to the same
      // file -- all via a save-to-tempfile + "append using" so that no
      // preserve/restore of the CALLER's dataset in the default frame
      // is ever needed.
      tempfile _addfile
      frame `_addframe': save "`_addfile'"

      tempname _master
      frame create `_master'
      frame `_master' {
         quietly use "`_dta'", clear
         quietly append using "`_addfile'"
         quietly save "`_dta'", replace
      }
      frame drop `_master'
      di as txt _n "meta(): " as res `_added' as txt ///
         " sub-sample row(s) appended to " as res "`_dta'"
   }
   frame drop `_addframe'

   // ---- (Re)build a numeric `study' variable + value label from the
   // just-saved .dta's own (string) `label' column, so that Stata's
   // -meta- suite and any user code that prefers a numeric study
   // identifier (e.g. meta forestplot, meta summarize, subgroup(study))
   // has one available alongside the original descriptive string. Value
   // codes are assigned by first appearance, in the order rows CURRENTLY
   // occur in the .dta (i.e. essentially by run_id/insertion order), and
   // are always freshly (re)computed from the CURRENTLY complete file --
   // both on a plain replace() and after an append() -- so that the same
   // descriptive label text is guaranteed to always map to the very same
   // numeric code throughout the file's history, and codes never grow
   // unboundedly across repeated append() calls beyond the number of
   // distinct labels actually present.
   tempname _studyframe
   frame create `_studyframe'
   frame `_studyframe' {
      quietly use "`_dta'", clear
      capture confirm variable study
      if _rc == 0 {
         quietly drop study
      }
      quietly gen long study = .
      local _nextcode = 0
      quietly levelsof label, local(_uniquelabs)
      // levelsof sorts alphabetically, which is fine here: it merely
      // needs to be a fixed, deterministic order so that re-running
      // this block on an unchanged .dta reproduces identical codes.
      foreach _ulab of local _uniquelabs {
         local ++_nextcode
         quietly replace study = `_nextcode' if label == `"`_ulab'"'
         label define _loevh2_study_lbl `_nextcode' `"`_ulab'"', modify
      }
      label values study _loevh2_study_lbl

      // ---- (Re)build a numeric `run' variable + value label from the
      // .dta's own `run_id' column, exactly parallel to `study' above.
      // Each DISTINCT run_id value present in the (now-complete) file
      // gets its own small integer code (1, 2, 3, ... in run_id/
      // insertion order, i.e. chronological order of the original
      // loevh2/loevh2_boot/loevh2_svy ..., compare meta() calls that
      // contributed rows to this file), value-labelled with that run's
      // own human-readable %tc timestamp string. This gives users a
      // short, easy-to-type numeric handle (e.g. "keep if run==2",
      // "drop if run==1", "keep if inlist(run,2,3)") for selecting/
      // combining/excluding specific runs in their OWN later, custom
      // meta-analyses -- without ever having to type out a raw run_id
      // double literal. Always freshly (re)computed from the complete
      // .dta, exactly like `study', so codes stay stable and never grow
      // unboundedly across repeated append() calls.
      capture confirm variable run
      if _rc == 0 {
         quietly drop run
      }
      quietly gen long run = .
      local _nextrun = 0
      quietly levelsof run_id, local(_uniqueruns)
      // levelsof sorts numerically ascending for a numeric variable,
      // i.e. exactly chronological run_id order -- run=1 is always the
      // EARLIEST call that ever contributed rows to this file.
      foreach _urun of local _uniqueruns {
         local ++_nextrun
         local _rundisp : display %tc `_urun'
         local _rundisp = trim(`"`_rundisp'"')
         quietly replace run = `_nextrun' if run_id == `_urun'
         label define _loevh2_run_lbl `_nextrun' `"Run `_nextrun': `_rundisp'"', modify
      }
      label values run _loevh2_run_lbl

      // Format N
      qui sum N, meanonly
      local dig = ceil(log10(max(1,scalar(r(max))))) + 2
      format N %`dig'.0fc

      quietly save "`_dta'", replace
   }
   frame drop `_studyframe'

   // ---- (Re)write the companion .do file ------------------------------
   // Always regenerated fresh (it is small, deterministic, and derived
   // entirely from the .dta's own fixed column layout) -- it is NOT
   // itself append/replace-mode-sensitive: no matter whether THIS call
   // replaced or appended rows, the .do file always simply reflects
   // "pool whatever is currently in <base>.dta", so a freshly rewritten
   // copy is always correct and current. (See loevh2_meta_writedo.ado,
   // a separate helper .ado, for the actual line-by-line writing --
   // kept separate so its generated-code lines can use plain double
   // quotes without any nested-quote escaping.)
   loevh2_meta_writedo "`_dta'" "`_do'" "`origframe'" `origchanged'

end