program define subinfile
	version 14.0
	syntax anything(id="file source" name=filesource), ///
		[from(string asis) to(string asis) replace append ///
		save(string) fromregex dropblank index(string) ///
		indexregex drop(string) dropregex order(string asis) ///
		encoding(string)]

	if `"`replace'"' == "" & `"`save'"' == "" & `"`append'"' == "" {
		di as error "You must specify at least one of the three options replace, save or append."
		exit 498
	}

	if `"`replace'"' != "" & `"`append'"' != "" {
		disp as error "You can not specify both replace and append"
		exit 198
	}

	if `"`from'"' == "" & `"`to'"' != "" {
		di as error "You must specify the substring you want to substitute."
		exit 198
	}

	if `"`index'"' == "" & `"`indexregex'"' != "" {
		di as error "You must specify the option index() if you want to use regular expression to keep lines."
		exit 198
	}

	if `"`drop'"' == "" & `"`dropregex'"' != "" {
		di as error "You must specify the option drop() if you want to use regular expression to keep lines."
		exit 198
	}

	if `"`from'"' == "" & `"`fromregex'"' != "" {
		di as error "You must specify the option from() if you want to use regular expression to substitute strings."
		exit 198
	}

	if !fileexists(`"`filesource'"') {
		di as error `"File `filesource' could not be found"'
		exit 601
	}

	if "`encoding'" != "" {
		mata: st_local("x", strofreal(isvalidconverter("`encoding'")))
		if `x' != 1 {
			disp as error "`encoding' invalid encoding"
			exit 198
		}
	}
	else {
		local encoding utf8
	}

	if `"`from'"' != "" {
		token `"`from'"'
		mata tokennumber(`"`from'"')
		scalar fromnumber = scalar(tokennumber)
		forvalues num = 1/`=scalar(fromnumber)' {
			local from`num' = `"``num''"'
		}

		if `"`to'"' == "" {
			forvalues num = 1/`=scalar(fromnumber)' {
				local to`num' = ""
			}
		}
		else {
			token `"`to'"'
			mata tokennumber(`"`to'"')
			if scalar(tokennumber) != scalar(fromnumber) {
				disp as error "The number of parts specified in to() is unequal to the number of parts specified in from()"
				exit 198
			}
			else {
				scalar tonumber = scalar(tokennumber)
				forvalues num = 1/`=scalar(tonumber)' {
					local to`num' = `"``num''"'
				}
			}
		}
	}

	if `"`order'"' != "" {
		token `"`order'"'
		mata tokennumber(`"`order'"')
		local ordernumber = scalar(tokennumber)
		forvalues num = 1/`ordernumber' {
			if !inlist(`"``num''"', "index", "drop", "from", "dropblank") {
				disp as error "You can only specify the option order() among index, drop, from or dropblank"
				exit 198
			}
			if `"``num''"' == "" {
				disp as error `"You can not specify ``num'' in order() without specify option `order`num''"'
				exit 198
			}
			if `num' > 1 {
				forvalues i = 1/`=`num'-1' {
					if `"``i''"' == `"``num''"' {
						disp as error `"You can only specify ``num'' once in order()"'
						exit 198
					}
				}
			}
		}
	}
	else local order = "index drop from dropblank"
	local orderitem = ""
	foreach item in `order' index drop from dropblank {
		if !strpos(`"`orderitem'"', `"`item'"') & `"``item''"' != "" local orderitem = `"`orderitem'`item' "'
	}
	token `"`orderitem'"'
	mata tokennumber(`"`orderitem'"')
	scalar orderitemnumber = scalar(tokennumber)
	forvalues i = 1/`=scalar(orderitemnumber)' {
		local order`i' = `"``i''"'
	}


	if `"`save'"' == "" local save `"`filesource'"'
	if !strpos(`"`save'"', ".") local save `"`save'.txt"'
	if fileexists(`"`save'"') {
		if "`replace'" == "" & "`append'" == "" {
			di as error `"File `save' have exsited, you need to specify the option replace or append"'
			error 498
		}

		else if `"`save'"' != `"`filesource'"' & "`replace'" != "" {
			cap erase `"`save'"'
			if _rc != 0 {
				! del `"`save'"' /F
			}
		}

		else if `"`save'"' == `"`filesource'"' & "`replace'" != "" {
			tempfile subinfile_temp
			local save `"`subinfile_temp'"'
		}
	}

	qui {
		mata subinfile(`"`filesource'"', `"`encoding'"', `"`save'"')
		if `"`save'"' == `"`subinfile_temp'"' {
			cap erase `"`filesource'"'
			if _rc != 0 {
				! del `"`filesource'"' /F
			}
			copy `"`subinfile_temp'"' `"`filesource'"', replace
		}
	}
end

cap mata mata drop tokennumber()
mata
	function tokennumber(string scalar tokenstring) {
		token = tokens(tokenstring)
		st_numscalar("tokennumber", cols(token))
	}
end

cap mata mata drop subinfile()
mata
	void function subinfile(string scalar filesource, string scalar encoding, string scalar save) {

		string matrix rewritefile
		real scalar i
		real scalar j
		real scalar writefile

		rewritefile = cat(filesource)
		rewritefile = ustrfrom(rewritefile, encoding, 1)

		for (i = 1; i <= st_numscalar("orderitemnumber"); i++) {

			if (st_local(sprintf("order%g", i)) == "index") {
				if (st_local("indexregex") == "indexregex") rewritefile = select(rewritefile, ustrregexm(rewritefile, st_local("index")))
				else rewritefile = select(rewritefile, ustrpos(rewritefile, st_local("index")))
			}

			if (st_local(sprintf("order%g", i)) == "drop") {
				if (st_local("dropregex") == "dropregex") rewritefile = select(rewritefile, !ustrregexm(rewritefile, st_local("drop")))
				else rewritefile = select(rewritefile, !ustrpos(rewritefile, st_local("drop")))
			}

			if (st_local(sprintf("order%g", i)) == "from") {
				if (st_local("fromregex") == "fromregex") {
					for (j = 1; j <= st_numscalar("fromnumber"); j++) {
						rewritefile = ustrregexra(rewritefile, st_local(sprintf("from%g", j)), st_local(sprintf("to%g", j)))
					}
				}
				else {
					for (j = 1; j <= st_numscalar("fromnumber"); j++) {
						rewritefile = usubinstr(rewritefile, st_local(sprintf("from%g", j)), st_local(sprintf("to%g", j)), .)
					}
				}
			}

			if (st_local(sprintf("order%g", i)) == "dropblank") rewritefile = select(rewritefile, ustrregexm(rewritefile, "."))
		}

		if (st_local("replace") == "" & st_local("append") == "" ) {
			writefile = fopen(save, "w")
			for (i = 1; i <= rows(rewritefile); i++) {
				fwrite(writefile, sprintf("%s\r\n", rewritefile[i]))
			}
			fclose(writefile)
		}

		else if (st_local("replace") == "replace") {
			writefile = fopen(save, "rw")
			for (i = 1; i <= rows(rewritefile); i++) {
				fwrite(writefile, sprintf("%s\r\n", rewritefile[i]))
			}
			fclose(writefile)
		}

		else {
			writefile = fopen(save, "a")
			for (i = 1; i <= rows(rewritefile); i++) {
				fwrite(writefile, sprintf("%s\r\n", rewritefile[i]))
			}
			fclose(writefile)
		}
	}
end