This is my first post but I have been using StackOverflow for years. Thanks for helping me every time.
I am writing a script in CMake that is supposed to rewrite a portion of a .cfg file (it is the resources.cfg file from Ogre 3D engine) so that:
I will focus only on the first part, since they are both similar. This is the resource file I am working on:
# Resources required by the sample browser and most samples.
[Essential]
Zip=stufftochange/media/packs/SdkTrays.zip
# Resource locations to be added to the default path
[General]
FileSystem=../media #local
FileSystem=stufftochange/media/materials/scripts
FileSystem=stufftochange/media/materials/textures
FileSystem=stufftochange/media/models
FileSystem=stufftochange/media/materials/programs/HLSL_Cg
FileSystem=stufftochange/media/materials/programs/GLSL
My current strategy is that only lines without the #local identifier should be affected by the REGEX REPLACE
statement. My current code is:
file(READ ${CMAKE_SOURCE_DIR}/cfg/resources.cfg RESOURCES_FILE)
string(REGEX REPLACE
"/media"
"${OGRE_HOME_BACKSLASHES}/media"
RESOURCES_FILE_MODIFIED ${RESOURCES_FILE})
file(WRITE ${CMAKE_SOURCE_DIR}/cfg/resources.cfg ${RESOURCES_FILE_MODIFIED})
which basically replaces all /media
occurrences. I need to replace the stufftochange
(that can be ANYTHING that is before string media
) only if #local
is not at the end of the line. I tried to modify the matching expression in lots of ways but, when I do, only the first and last line are replaced properly. I suspect that it has to do with the line endings.
These are some of the expressions I tried, without luck:
([^ #]*)=[^ ]*/media([^#\n$]*)
=[^ ]*/media([^#\n$]*)
/media([^# ]*)
/media([^#\n ]*)
Of course I used \\\\1
and \\\\2
to save the parts of the string that I want to keep.
I did a few searches on google and stackoverflow but couldn't find a proper solution or guide for using CMake's regex replace (and documentation is very basic). Any idea what my holy grail match expression would be?
CMake's regex syntax and documentation are pretty limited. I'd favour turning the file's contents into a list of strings, each string being a line in the file. Iterating these makes the regex much simpler:
set(SourceFile "${CMAKE_SOURCE_DIR}/cfg/resources.cfg")
file(READ ${SourceFile} Contents)
# Set the variable "Esc" to the ASCII value 27 - basically something
# which is unlikely to conflict with anything in the file contents.
string(ASCII 27 Esc)
# Turn the contents into a list of strings, each ending with an Esc.
# This allows us to preserve blank lines in the file since CMake
# automatically prunes empty list items during a foreach loop.
string(REGEX REPLACE "\n" "${Esc};" ContentsAsList "${Contents}")
unset(ModifiedContents)
foreach(Line ${ContentsAsList})
# Don't modify the line if it contains #local at the end.
if(NOT "${Line}" MATCHES "#local${Esc}$")
string(REGEX REPLACE "=.*/media" "=${OGRE_HOME_BACKSLASHES}/media" Line ${Line})
endif()
# Swap the appended Esc character back out in favour of a line feed
string(REGEX REPLACE "${Esc}" "\n" Line ${Line})
set(ModifiedContents "${ModifiedContents}${Line}")
endforeach()
file(WRITE ${SourceFile} ${ModifiedContents})
If you don't care about preserving blank lines, you can use file(STRINGS ...)
to read in the file, which makes life a bit simpler:
set(SourceFile "${CMAKE_SOURCE_DIR}/cfg/resources.cfg")
file(STRINGS ${SourceFile} Contents)
unset(ModifiedContents)
foreach(Line ${Contents})
# Don't modify the line if it contains #local at the end.
if(NOT "${Line}" MATCHES "#local$")
string(REGEX REPLACE
"=.*/media"
"=${OGRE_HOME_BACKSLASHES}/media"
Line ${Line})
endif()
set(ModifiedContents "${ModifiedContents}${Line}\n")
endforeach()
file(WRITE ${SourceFile} ${ModifiedContents})
Probably the best description of CMake's regex syntax is found in the docs for string
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.