Tom's Guide | Tom's Hardware | Tom's Games
![]() |
![]() |
![]() |
new to batch scripting. would it be possible to have a script that can read a list of file names from a directory and determine if there is a series ie. file1.txt file2.txt then append a line to a configuration file that points to the next file name in the series?
like file1.cfg would have the following line added:
nextmap file2
---
loosely this will type a list of file names.
for %%x in (*.bsp) do echo %%x--- strip file extensions
--- look at %current and %next file name
--- is it a series
--- echo nextmap %next >> %current + .cfgany help will be appreciated, tia
background and purpose:
Half-Life mod Sven Co-op
recent updates to the steam(content distribution system) have uncovered a changelevel bug in the Sven Co-op mod.this bug prevents the server from automaticaly changing to the next map, when a trigger_changelevel is encountered.
a workaround is to include a nextmap statement in each maps config file.a script would help to do this for hundreds of maps on hundreds of computers most running xp or xp pro.
single or non series maps can be skipped.
like auspices.bspa series would have the cfg files updated.
for example, the map series.
toonrun1.bsp
toonrun2.bsp
toonrun3.bsptoonrun1.cfg add nextmap toonrun2
toonrun2.cfg add nextmap toonrun3
toonrun3.cfg no changehostage.bsp
hostage2a.bsp
hostage2b.bspafrikakorps1.bsp
afrikakorps2.bsp
afrikakorps3.bspthis will not fix the half-life single player maps. since the correct sequence cannot be determined by the map name.
c1a0c.bsp no change
c1a0d.bsp no change
c1a4j.bsp no change
c1a0c runs after c1a0d in the sequence.It's OK, I've already done them.

here is what I've got.
@echo off
setlocal enabledelayedexpansion
if exist filenames.txt del filenames.txt
for %%x in (*.bsp) do echo %%x >>filenames.txt
for /f "tokens=* delims=" %%a in (filenames.txt) do (
set txtline=%%a
set txtline=!txtline:.bsp=!
echo !txtline!>>tmp.txt)
del filenames.txt & ren tmp.txt filenames.txt
endlocalreads file names from a directory into text file. strips off the file name extension.
I don't know how to compare the file names or
do sub string manipulation.

this batch script will quickly generate mapnames.txt
@echo off
if exist mapnames.txt del mapnames.txt
@FOR /f "delims=" %%? IN ('DIR/b *.bsp') DO @ECHO/%%~n? >>filenames.txthere I attempt to describe the problem differently.
map names are sequential. typically map1 map2 map3, sometimes map map2a map2b map3
made up of a mapname and an extension or modifier as the number and everything following it.
ie. map2a is mapname = map plus a modifier = 2a
mapnames.txt is sorted directory listing of map names with the .bsp extension stripped.read a line from mapnames.txt
mapname = line
process mapname one character at a time
if a number is found save the number and everything after it.
modifier = "whatever"
no number found
modifier = ""
mapname = line - modifierread the nextline from mapnames.txt
mapname2 = line
process mapname2 one character at a time
if a number is found save the number and everything after it.
modifier2 = "whatever"
no number found
modifier2 = ""
mapname2 = line - modifier2if mapname is like mapname2
append one line of text to the file: mapname + modifier + .cfg
the line would be: nextmap mapname + modifier2read the nextline from mapnames.txt
mapname3 = line
process mapname3 one character at a time
if a number is found save the number and everything after it.
modifier3 = "whatever"
no number found
modifier3 = ""
mapname3 = line - modifier3if mapname is like mapname3
append one line of text to the file: mapname + modifier2 + .cfg
the line would be: nextmap mapname + modifier3keep doing this until mapname is not like mapname?n

here is what I've got so far. a little broken when it comes to the odd case hostage hostage2a hostage2b. and for opening the correct file to append a line.
any help?Option Explicit
Dim objFSO
Dim ofolder
Dim objStreamDim intCounter
Dim arrTestNames ()
Dim dicBaseNames
Dim strBase
Dim strName
Dim strNumber
Dim nUBound
Dim arrTemp
Dim strOutputSet objFSO = CreateObject("Scripting.FileSystemObject")
'create the output file
Set objStream = objFSO.createtextfile("search.log", True)
CheckFolder (objFSO.getfolder(".")), objStream
ReDim Preserve arrTestNames (intCounter)
FillArray(objFSO.getfolder(".")), objStream, arrTestNames'Start by making a dictionary of all the base names. The value will be an array of the numerals
Set dicBaseNames = CreateObject("Scripting.Dictionary")
For Each strName In arrTestNames
strBase = GetBaseName(strName)
strNumber = GetSequenceNumber(strName)
If dicBaseNames.Exists(strBase) Then
nUBound = UBound(dicBaseNames(strBase)) + 1
arrTemp = dicBaseNames(strBase)
ReDim Preserve arrTemp(nUBound)
arrTemp(nUBound) = strNumber
dicBaseNames(strBase) = arrTemp
Else
dicBaseNames.Add strBase, Array(strNumber)
End If
Next'now step through the dictionary using basenames.
StepThruDic(objFSO.getfolder(".")), objStreamMsgBox "File Search Completed." + vbCr + "Please check search.log for details."
Function GetSequenceNumber(strName)
Dim oRE
Dim colMatches
Dim oMatch
Set oRE = New Regexp
oRE.Pattern = "\D*(\d*)(\D*)"
oRE.IgnoreCase = True
Set colMatches = oRE.Execute(strName)
For Each oMatch In colMatches
GetSequenceNumber = oMatch.Submatches(0)
Exit Function
Next
GetSequenceNumber = ""
End FunctionFunction GetBaseName(strName)
Dim oRE
Dim colMatches
Dim oMatch
Set oRE = New Regexp
oRE.Pattern = "(\D*)\d*(\D*)"
oRE.IgnoreCase = True
Set colMatches = oRE.Execute(strName)
For Each oMatch In colMatches
GetBaseName = oMatch.SubMatches(0)
Exit Function
Next
GetBaseName = "ERROR"
End FunctionSub CheckFolder(objCurrentFolder, objLogFile)
Dim strTemp
Dim strSearch
Dim strOutput
Dim objNewFolder
Dim objFile
Dim objStream
dim a
strSearch = ".bsp"
For Each objFile In objCurrentFolder.Files
strTemp = Right(objFile.Name, 4)
If UCase(strTemp) = UCase(strSearch) Then
'Got one
'a=Split(CStr(objFile.Name),".")
intCounter = intCounter + 1
'strOutput = CStr(intCounter) & " " & a(0)
'objLogFile.writeline strOutput
End If
Next
End SubSub FillArray(objCurrentFolder, objLogFile, arrTestNames)
Dim strTemp
Dim strSearch
Dim strOutput
Dim objNewFolder
Dim objFile
Dim objStream
dim a
dim intIndex
strSearch = ".bsp"
intIndex = 0
For Each objFile In objCurrentFolder.Files
strTemp = Right(objFile.Name, 4)
If UCase(strTemp) = UCase(strSearch) Then
'Got one
a=Split(CStr(objFile.Name),".")
'populate database
arrTestNames (intIndex) = a(0)
'strOutput = arrTestNames (intIndex)
'objLogFile.writeline strOutput
intIndex = intIndex + 1
End If
Next
End SubSub StepThruDic(objCurrentFolder, objLogFile)
Dim strTemp
Dim strSearch
Dim strOutput
Dim objNewFolder
Dim objFile
Dim objStream
dim a
dim intIndex
dim strName2
dim strBase2
dim strNumber2
dim strName3
dim strBase3
dim strNumber3
dim i
For i = 0 to intCounter - 1
strName = arrTestNames(i)
strBase = GetBaseName(strName)
strNumber = GetSequenceNumber(strName)
If strNumber = "" Then
strName2 = arrTestNames(i + 1)
strBase2 = GetBaseName(strName2)
If StrComp(strBase2, strBase) = 0 Then
strNumber2 = GetSequenceNumber(strName2)
strOutput = "nextmap" & " " & strbase2 & strnumber2 & " " & strname & ".cfg"
objLogFile.writeline strOutput
End If
If strNumber2 = "1" Then
strName3 = arrTestNames(i + 2)
strBase3 = GetBaseName(strName3)
If StrComp(strBase3, strBase) = 0 Then
strNumber3 = GetSequenceNumber(strName3)
strOutput = "nextmap" & " " & strbase3 & strnumber3 & " " & strname2 & ".cfg"
objLogFile.writeline strOutput
End If
End If
End If
If strNumber = "1" Then
strName2 = arrTestNames(i + 1)
strBase2 = GetBaseName(strName2)
If StrComp(strBase2, strBase) = 0 Then
strNumber2 = GetSequenceNumber(strName2)
strOutput = "nextmap" & " " & strbase2 & strnumber2 & " " & strname & ".cfg"
objLogFile.writeline strOutput
End If
If strNumber2 = "2" Then
strName3 = arrTestNames(i + 2)
strBase3 = GetBaseName(strName3)
If StrComp(strBase3, strBase) = 0 Then
strNumber3 = GetSequenceNumber(strName3)
strOutput = "nextmap" & " " & strbase3 & strnumber3 & " " & strname2 & ".cfg"
objLogFile.writeline strOutput
End If
End If
End If
Next
End Sub

hello, thanks for your help. here is the near final vbscript. it still has a little trouble with some filename series projectg, projectg1 ... project8 does not get the nonnumber one first.
tweaked the regex to better split the filenames into character / number parts. found and online regex tester that helped.
it is updated to sort the dictionary by the key. and when an item is a number it sorts the rest of the items as numbers.
had to include special case stuf to handle names starting with numbers and names that are one number.
if anyone is real smart with vbscript. have a look. if not maybe something here will help you. thanks.
[code][codebox]Option Explicit
Dim objFSO
Dim ofolder
Dim objStream
Dim objStream2
Dim intCounter
Dim arrTestNames ()
Dim dicBaseNames
Dim strBase
Dim strName
Dim strNumber
Dim nUBound
Dim arrTemp
Dim strOutput, a
Const dictKey = 1
Const dictItem = 2Set objFSO = CreateObject("Scripting.FileSystemObject")
'create the output file
Set objStream = objFSO.CreateTextFile("search3.log", True)
CheckFolder (objFSO.GetFolder(".")), objStream
ReDim Preserve arrTestNames (intCounter)
FillArray(objFSO.GetFolder(".")), objStream, arrTestNamesConst TextCompare = 1
'Start by making a dictionary of all the base names. The value will be an array of the numerals
Set dicBaseNames = CreateObject("Scripting.Dictionary")
dicBaseNames.CompareMode = TextCompare
For Each strName In arrTestNames
strBase = GetBaseName(strName)
strNumber = GetSequenceNumber(strName)
'workaround for single number names.
If strbase = "1" Then
strbase = "jam"
strNumber = "1"
End If
If strbase = "2" Then
strbase = "jam"
strNumber = "2"
End If
If strbase = "3" Then
strbase = "jam"
strNumber = "3"
End If
If strbase = "4" Then
strbase = "jam"
strNumber = "4"
End If
If strbase = "5" Then
strbase = "jam"
strNumber = "5"
End If
If strbase = "6" Then
strbase = "jam"
strNumber = "6"
End If
If dicBaseNames.Exists(strBase) Then
nUBound = UBound(dicBaseNames(strBase)) + 1
arrTemp = dicBaseNames(strBase)
ReDim Preserve arrTemp(nUBound)
arrTemp(nUBound) = strNumber
dicBaseNames(strBase) = arrTemp
Else
dicBaseNames.Add strBase, Array(strNumber)
End If
Nextset dicbasenames = SortDictionary(dicBaseNames, dictKey)
'set dicbasenames = sortdict(dicbasenames,objFSO.getfolder("."), objStream)
'step through the dictionary using basenames and numbers to update config files.
StepThruDic(objFSO.GetFolder(".")), objStreamMsgBox "Series Map Search Completed." + vbCr + "Please check updated map.cfg's." + vbCr + "See search.log for details " + CStr(Date)
Function SortDictionary(ByVal objDict, intSort)
' declare our variables
Dim strDict()
Dim arrTmp()
Dim objKey
Dim strKey, strItem
Dim X, Y, Z, i, j, temp' get the dictionary count
Z = objDict.Count' we need more than one item to warrant sorting
If Z > 1 Then
' create an array to store dictionary information
ReDim strDict(Z, 2)
X = 0
' populate the string array
For Each objKey In objDict
ReDim arrTmp(UBound(objdict(objkey)))
For i = 0 To UBound(objdict(objkey)) '- 1
arrTmp(i) = objDict.Item(objKey)(i)
Next
For i = UBound(objdict(objkey)) - 1 To 0 step -1
For j = 0 To i
If objKey <> "c" Then
If Len(arrTmp(j)) <> 0 And Len(arrTmp(j + 1)) <> 0 Then
If IsNumeric(arrTmp(j)) And IsNumeric(arrTmp(j + 1)) Then
If CInt(arrTmp(j)) > CInt(arrTmp(j + 1)) Then
Wscript.Echo CStr(Join(arrTmp))
temp = arrTmp(j + 1)
arrTmp(j + 1) = arrTmp(j)
arrTmp(j) = temp
End If
End If
End If
End If
Next
Next
strDict(X, dictKey) = CStr(objKey)
strDict(X, dictItem) = CStr(Join(arrTmp))
X = X + 1
Next' perform a a shell sort of the string array
For X = 0 To (Z - 2)
For Y = X To (Z - 1)
If StrComp(strDict(X, intSort), strDict(Y, intSort), vbTextCompare) > 0 Then
strKey = strDict(X, dictKey)
strItem = strDict(X, dictItem)
strDict(X, dictKey) = strDict(Y, dictKey)
strDict(X, dictItem) = strDict(Y, dictItem)
strDict(Y, dictKey) = strKey
strDict(Y, dictItem) = strItem
End If
Next
Next' erase the contents of the dictionary object
objDict.RemoveAll' repopulate the dictionary with the sorted information
For X = 0 To (Z - 1)
objDict.Add strDict(X, dictKey), Split(strDict(X, dictItem))
NextEnd If
Set SortDictionary = objDict
End Function
Function GetSequenceNumber(strName)
Dim oRE
Dim colMatches
Dim oMatch, ISet oRE = New Regexp
'oRE.Pattern = "\D*(\d*)(.*$)"
oRE.Pattern = "[^\D]*\D*(\d*.*$)"
oRE.IgnoreCase = True
Set colMatches = oRE.Execute(strName)
If colMatches.Count > 0 Then
Set omatch = colMatches(0)
If oMatch.SubMatches.Count > 0 Then
For I = 0 To oMatch.SubMatches.Count -1
GetSequenceNumber = GetSequenceNumber & oMatch.SubMatches(I)
Next
End If
Else
GetSequenceNumber = ""
End If
'For Each oMatch In colMatches
' GetSequenceNumber = oMatch.SubMatches(0) & oMatch.SubMatches(1)
' Exit Function
'Next
'GetSequenceNumber = ""
End FunctionFunction GetBaseName(strName)
Dim oRE
Dim colMatches
Dim oMatch, ISet oRE = New Regexp
'oRE.Pattern = "(\D*)\d*"
oRE.Pattern = "^(\d*\D*)\d*"
oRE.IgnoreCase = True
Set colMatches = oRE.Execute(strName)
If colMatches.Count > 0 Then
Set oMatch = colMatches(0)
If oMatch.Submatches.Count > 0 Then
For I = 0 To oMatch.SubMatches.Count -1
GetBaseName = GetBaseName & oMatch.SubMatches(I)
Next
End If
End If
'For Each oMatch In colMatches
' GetBaseName = oMatch.SubMatches(0)
' Exit Function
'Next
'GetBaseName = "ERROR"
End FunctionSub CheckFolder(objCurrentFolder, objLogFile)
Dim strTemp
Dim strSearch
Dim strOutput
Dim objNewFolder
Dim objFile
Dim objStream
Dim astrSearch = ".bsp"
For Each objFile In objCurrentFolder.Files
strTemp = Right(objFile.Name, 4)
If UCase(strTemp) = UCase(strSearch) Then
intCounter = intCounter + 1
End If
NextEnd Sub
Sub FillArray(objCurrentFolder, objLogFile, arrTestNames)
Dim strTemp
Dim strSearch
Dim strOutput
Dim objNewFolder
Dim objFile
Dim objStream
Dim a
Dim intIndexstrSearch = ".bsp"
intIndex = 0
For Each objFile In objCurrentFolder.Files
strTemp = Right(objFile.Name, 4)
If UCase(strTemp) = UCase(strSearch) Then
arrTestNames (intIndex) = Split(objFile.Name, ".")(0)
intIndex = intIndex + 1
End If
NextEnd Sub
Sub StepThruDic(objCurrentFolder, objLogFile)
Dim strTemp
Dim strSearch
Dim strOutput
Dim objNewFolder
Dim objFile
Dim objStream
Dim i, j, temp, num1, num2
Dim strNextmapstrOutput = "changelevel bug squished. Summary of changes:"
objLogFile.WriteLine strOutput
For Each strBase in dicBaseNames.Keys
For i = 0 To UBound(dicBaseNames(strBase)) - 1
If strbase = "jam" Then
strOutput = dicBaseNames(strBase)(i) & ".cfg"
objLogFile.WriteLine strOutput
strOutput = " nextmap " & dicBaseNames(strBase)(i + 1)
objLogFile.WriteLine strOutput
'update the config file.
If objFSO.FileExists(dicBaseNames(strBase)(i) & ".cfg") Then
objFSO.OpenTextFile(dicBaseNames(strBase)(i) & ".cfg", 8).WriteLine _
vbCrLf & "nextmap " & dicBaseNames(strBase)(i + 1)
Else
'create the config file.
strTemp = dicBaseNames(strBase)(i) & ".cfg"
Set objStream = objFSO.CreateTextFile(strTemp, True)
objStream.WriteLine _
"nextmap " & dicBaseNames(strBase)(i + 1)
End IfElse
'skip c1,c2,c3 series, blank records, special case
If strBase <> "c" _
And "nextmap " & strbase & dicBaseNames(strBase)(i) <> "nextmap " Then
strNextmap = strbase & dicBaseNames(strBase)(i + 1)
If strBase & dicBaseNames(strBase)(i) = "assaultmesa2-2" Then
strOutput = strBase & dicBaseNames(strBase)(i + 1) & ".cfg"
objLogFile.WriteLine strOutput
strOutput = " nextmap " & strBase & dicBaseNames(strBase)(i)
objLogFile.WriteLine strOutput
If objFSO.FileExists(strBase & dicBaseNames(strBase)(i + 1) & ".cfg") Then
objFSO.OpenTextFile(strBase & dicBaseNames(strBase)(i + 1) & ".cfg", 8).WriteLine _
vbCrLf & "nextmap " & strbase & dicBaseNames(strBase)(i)
End If
Else
' write to the search log.
strOutput = strBase & dicBaseNames(strBase)(i) & ".cfg"
objLogFile.WriteLine strOutput
strOutput = " nextmap " & strNextmap
objLogFile.WriteLine strOutput'update the config file.
If objFSO.FileExists(strBase & dicBaseNames(strBase)(i) & ".cfg") Then
objFSO.OpenTextFile(strBase & dicBaseNames(strBase)(i) & ".cfg", 8).WriteLine _
vbCrLf & "nextmap " & strbase & dicBaseNames(strBase)(i + 1)
Else
'create the config file.
strTemp = strBase & dicBaseNames(strBase)(i) & ".cfg"
Set objStream = objFSO.CreateTextFile(strTemp, True)
objStream.WriteLine _
"nextmap" & " " & strbase & dicBaseNames(strBase)(i + 1)
End If
End If
End If
End If
Next
Next
End Sub[/code][/codebox]

![]() |
![]() |
![]() |

This post is quite old and has been locked from receiving new replies. Please create a new posting instead.
| Ads by Google |