简体   繁体   中英

Excluding lines containing a specific string from REGEX REPLACE in CMake

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:

  • when running config with cmake, absolute paths are set according to the system
  • when installing, all files are copied into a folder and relative paths are set instead

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM