Skip to content

Commit 37efc07

Browse files
committed
[cmake/generate_header_and_source_from_header_only.cmake] Minor improvements to handling multiline #if and multiline comments on #endif
1 parent 3c880df commit 37efc07

File tree

2 files changed

+145
-71
lines changed

2 files changed

+145
-71
lines changed

acquire/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ else ()
107107
set(gen_source_file "${CMAKE_BINARY_DIR}/gen/gen_${name_no_ext}.c")
108108

109109
generate_header_and_source_from_header_only(
110+
"LIBACQUIRE_IMPLEMENTATION"
110111
"${CMAKE_CURRENT_SOURCE_DIR}/${header_file}"
111112
"${gen_header_file}"
112113
"${gen_source_file}"
Lines changed: 144 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
# Function to split header-only .h into separate header .h and source .c files
2-
function(generate_header_and_source_from_header_only input_file output_header output_source)
1+
# Function to split header-only .h file into separate header .h and source .c files
2+
function(generate_header_and_source_from_header_only guard_name input_file output_header output_source)
33
# limitations:
44
# - expects a comment on endif, like `#endif /* LIBACQUIRE_IMPLEMENTATION */`
55
# - only handles the first `LIBACQUIRE_IMPLEMENTATION` impl
66
# - doesn't evaluate macros, so `!defined(LIBACQUIRE_IMPLEMENTATION)` will still move that block to .c file
7+
8+
# implementation
9+
# - superior to basic find, as it parses string literals, char literals, comments (both kinds)
10+
711
if (NOT EXISTS "${input_file}")
812
message(FATAL_ERROR "Input file not found: ${input_file}")
913
elseif (IS_DIRECTORY "${input_file}")
@@ -29,8 +33,6 @@ function(generate_header_and_source_from_header_only input_file output_header ou
2933
set(macro_finish_end -1)
3034
set(guard_start -1)
3135

32-
set(guard_name "LIBACQUIRE_IMPLEMENTATION")
33-
3436
set(prev_ch "")
3537
set(line "")
3638
set(line_starts_idx 0)
@@ -42,94 +44,165 @@ function(generate_header_and_source_from_header_only input_file output_header ou
4244
string(SUBSTRING "${content}" ${i} 1 char)
4345
math(EXPR i_plus_1 "${i} + 1")
4446

45-
if (in_char)
46-
if (char STREQUAL "'" AND NOT prev_ch STREQUAL "\\")
47-
set(in_char OFF)
48-
endif (char STREQUAL "'" AND NOT prev_ch STREQUAL "\\")
49-
elseif (in_str)
50-
if (char STREQUAL "\"" AND NOT prev_ch STREQUAL "\\")
51-
set(in_str OFF)
52-
endif (char STREQUAL "\"" AND NOT prev_ch STREQUAL "\\")
53-
elseif (in_c_comment)
54-
if ("${prev_ch}${char}" STREQUAL "*/")
55-
set(in_c_comment OFF)
56-
endif ("${prev_ch}${char}" STREQUAL "*/")
57-
elseif (in_cpp_comment)
58-
if (char STREQUAL "\n")
59-
set(in_cpp_comment OFF)
60-
set(clear_line ON)
61-
set(line_starts_idx ${i_plus_1})
62-
endif (char STREQUAL "\n")
63-
elseif (in_macro)
64-
if (char STREQUAL "\n" AND NOT prev_ch STREQUAL "\\")
65-
set(in_macro OFF)
66-
if (macro_finish_start EQUAL -1)
67-
set(macro_begin_end ${i})
68-
math(EXPR macro_begin_len "${macro_begin_end} - ${macro_begin_start}")
69-
string(SUBSTRING "${content}" ${macro_begin_start} ${macro_begin_len} macro_begin)
70-
else ()
71-
set(macro_finish_end ${i})
72-
math(EXPR macro_finish_len "${macro_finish_end} - ${macro_finish_start}")
73-
string(SUBSTRING "${content}" ${macro_finish_start} ${macro_finish_len} macro_finish)
74-
if (macro_finish MATCHES "^[ \t]*#[ \t]*if.*${guard_name}")
47+
if (in_char AND char STREQUAL "'" AND NOT prev_ch STREQUAL "\\")
48+
set(in_char OFF)
49+
elseif (in_str AND char STREQUAL "\"" AND NOT prev_ch STREQUAL "\\")
50+
set(in_str OFF)
51+
elseif (in_c_comment AND "${prev_ch}${char}" STREQUAL "*/")
52+
message(STATUS "C comment finished, line ${line}")
53+
set(in_c_comment OFF)
54+
elseif (in_cpp_comment AND char STREQUAL "\n")
55+
set(in_cpp_comment OFF)
56+
set(clear_line ON)
57+
message(STATUS "[newline] \"${line}\"")
58+
set(line_starts_idx ${i_plus_1})
59+
elseif (in_macro AND char STREQUAL "\n" AND NOT prev_ch STREQUAL "\\")
60+
set(in_macro OFF)
61+
if (macro_finish_start EQUAL -1)
62+
set(macro_begin_end ${i})
63+
math(EXPR macro_begin_len "${macro_begin_end} - ${macro_begin_start}")
64+
string(SUBSTRING "${content}" ${macro_begin_start} ${macro_begin_len} macro_begin)
65+
else ()
66+
set(macro_finish_end ${i})
67+
math(EXPR macro_finish_len "${macro_finish_end} - ${macro_finish_start}")
68+
string(SUBSTRING "${content}" ${macro_finish_start} ${macro_finish_len} macro_finish)
69+
if (macro_finish MATCHES ".*${guard_name}.*")
70+
message(STATUS "Analysing \"${line}\"")
71+
if (macro_finish MATCHES "^[ \t]*#[ \t]*(ifdef[ \t]+${guard_name}|if[ \t]+.*)")
7572
set(macro_begin_start ${macro_finish_start})
7673
set(macro_begin_end ${macro_finish_end})
7774
set(macro_finish_start -1)
7875
set(macro_finish_end -1)
79-
elseif (macro_finish MATCHES "^[ \t]*#[ \t]*endif.*${guard_name}")
76+
elseif (macro_finish MATCHES "^[ \t]*#[ \t]*endif.*")
8077
set(end_guard_found ON)
78+
string(LENGTH "${macro_finish}" endif_len)
79+
set(endif_len ${endif_len})
8180
break()
81+
else ()
82+
message(STATUS "Odd Unrelated macro: ${line}")
8283
endif ()
84+
else ()
85+
message(STATUS "Unrelated macro: ${line}")
8386
endif ()
87+
endif ()
88+
set(clear_line ON)
89+
set(line_starts_idx ${i_plus_1})
90+
else ()
91+
if (prev_ch STREQUAL "\\")
92+
set(i ${i_plus_1})
93+
set(prev_ch "${char}")
94+
continue()
95+
elseif (char STREQUAL "'")
96+
set(in_char ON)
97+
elseif (char STREQUAL "\"")
98+
set(in_str ON)
99+
elseif ("${prev_ch}${char}" STREQUAL "/*")
100+
message(STATUS "C comment started, line ${line}")
101+
set(in_c_comment ON)
102+
elseif ("${prev_ch}${char}" STREQUAL "//")
103+
set(in_cpp_comment ON)
104+
elseif (char STREQUAL "\n")
84105
set(clear_line ON)
85106
set(line_starts_idx ${i_plus_1})
86-
endif (char STREQUAL "\n" AND NOT prev_ch STREQUAL "\\")
87-
else ()
88-
if (NOT prev_ch STREQUAL "\\")
89-
if (char STREQUAL "'")
90-
set(in_char ON)
91-
elseif (char STREQUAL "\"")
92-
set(in_str ON)
93-
elseif ("${prev_ch}${char}" STREQUAL "/*")
94-
set(in_c_comment ON)
95-
elseif ("${prev_ch}${char}" STREQUAL "//")
96-
set(in_cpp_comment ON)
97-
elseif (char STREQUAL "\n")
98-
set(clear_line ON)
99-
set(line_starts_idx ${i_plus_1})
107+
elseif (char STREQUAL "#" AND (line STREQUAL "" OR line MATCHES "^[ \t\r]+#+"))
108+
set(in_macro ON)
109+
if (macro_begin_start EQUAL -1)
110+
set(macro_begin_start ${i})
100111
else ()
101-
if (char STREQUAL "#")
102-
string(REGEX REPLACE "^[ \t\r]+" "" whitespace_free_line "${line}")
103-
string(LENGTH "${whitespace_free_line}" whitespace_free_line_len)
104-
if (whitespace_free_line_len EQUAL 0)
105-
set(in_macro ON)
106-
if (macro_begin_start EQUAL -1)
107-
set(macro_begin_start ${i})
112+
set(macro_finish_start ${i})
113+
endif ()
114+
math(EXPR i_plus_12 "${i} + 12")
115+
if (i_plus_12 LESS content_len)
116+
string(SUBSTRING "${content}" ${i} 12 macro_first_12_chars)
117+
if (macro_first_12_chars MATCHES "^[ \t\r]*#[ \t\r]*endif[ \t\r]*\\/\\*")
118+
# read until end of comment, even if it has new lines and \
119+
# len("#endif /*") == 9
120+
set(macro_finish_start ${i})
121+
set(macro_finish_end -1)
122+
math(EXPR j "${i} + 9")
123+
math(EXPR prev_j "${i} + 8")
124+
while (j LESS content_len)
125+
string(SUBSTRING "${content}" ${prev_j} 2 this_and_prev)
126+
if (this_and_prev STREQUAL "*/")
127+
math(EXPR j "${j} + 1")
128+
set(macro_finish_end ${j})
129+
break()
130+
endif (this_and_prev STREQUAL "*/")
131+
set(prev_j "${j}")
132+
math(EXPR j "${j} + 1")
133+
endwhile (j LESS content_len)
134+
if (NOT macro_finish_end EQUAL -1)
135+
math(EXPR macro_finish_len "${macro_finish_end} - ${macro_finish_start}")
136+
string(SUBSTRING "${content}" ${macro_finish_start} ${macro_finish_len} macro_finish)
137+
138+
if (macro_finish MATCHES ".*${guard_name}.*")
139+
message(STATUS "[matches] macro_finish \"${macro_finish}\"")
140+
set(end_guard_found ON)
141+
break()
108142
else ()
109-
set(macro_finish_start ${i})
143+
message(STATUS "[nomatch] macro_finish \"${macro_finish}\"")
110144
endif ()
111-
endif ()
145+
endif (NOT macro_finish_end EQUAL -1)
146+
elseif (macro_first_12_chars MATCHES "^[ \t]*#[ \t]*(ifdef|if)[ \t]+.*")
147+
math(EXPR j "${i} + 3")
148+
math(EXPR prev_j "${i} + 2")
149+
set(in_c_comment0 OFF)
150+
math(EXPR j "${i} + 9")
151+
math(EXPR prev_j "${i} + 8")
152+
while (j LESS content_len)
153+
string(SUBSTRING "${content}" ${prev_j} 1 the_prev_char)
154+
string(SUBSTRING "${content}" ${j} 1 this_char)
155+
if (this_char STREQUAL "\n" AND NOT the_prev_char STREQUAL "\\")
156+
math(EXPR len "${j} - ${i}")
157+
string(SUBSTRING "${content}" ${i} ${len} macro_start)
158+
message(STATUS "content[the_prev_char = \"${the_prev_char}\",${i}:${j}] = \"${macro_start}\"")
159+
if (macro_start MATCHES ".*${guard_name}.*")
160+
set(macro_begin_start ${i})
161+
set(macro_begin_end ${j})
162+
break()
163+
endif (macro_start MATCHES ".*${guard_name}.*")
164+
endif (this_char STREQUAL "\n" AND NOT the_prev_char STREQUAL "\\")
165+
166+
set(prev_j "${j}")
167+
math(EXPR j "${j} + 1")
168+
endwhile (j LESS content_len)
112169
endif ()
113-
endif ()
114-
endif (NOT prev_ch STREQUAL "\\")
115-
endif ()
170+
endif (i_plus_12 LESS content_len)
171+
endif ()
116172

117-
set(line "${line}${char}")
173+
set(line "${line}${char}")
118174

119-
if (clear_line)
120-
set(line "")
121-
set(clear_line OFF)
122-
endif (clear_line)
175+
if (clear_line)
176+
set(line "")
177+
set(clear_line OFF)
178+
endif (clear_line)
123179

124-
set(i ${i_plus_1})
125-
set(prev_ch "${char}")
180+
set(i ${i_plus_1})
181+
set(prev_ch "${char}")
182+
endif ()
126183
endwhile (i LESS content_len)
127184

128185
file(WRITE "${output_header}" "${header_lines}")
129186
if (end_guard_found)
130-
string(LENGTH "${line}" line_len)
131-
math(EXPR impl_length "${macro_finish_end} - ${macro_begin_end} - ${line_len}")
187+
#string(LENGTH "${line}" line_len)
188+
#math(EXPR impl_length "${macro_finish_end} - ${macro_begin_end} - ${line_len}")
189+
#set(impl_length "${line_len}")
190+
math(EXPR impl_length "${macro_finish_end} - ${macro_begin_end}")
132191
string(SUBSTRING "${content}" "${macro_begin_end}" "${impl_length}" impl_content)
192+
193+
# Remove the `#endif` line
194+
if (DEFINED endif_len)
195+
string(LENGTH "${impl_content}" impl_content_len)
196+
math(EXPR trimmed_len "${impl_content_len} - ${endif_len}")
197+
if (trimmed_len LESS 0)
198+
set(trimmed_len 0)
199+
endif ()
200+
string(SUBSTRING "${impl_content}" 0 "${trimmed_len}" impl_content)
201+
else ()
202+
string(FIND "${impl_content}" "\n" last_nl REVERSE)
203+
string(SUBSTRING "${impl_content}" 0 "${last_nl}" impl_content)
204+
endif ()
205+
133206
string(SUBSTRING "${content}" 0 "${macro_begin_start}" head_start)
134207
string(SUBSTRING "${content}" "${macro_finish_end}" -1 head_end)
135208

@@ -139,4 +212,4 @@ function(generate_header_and_source_from_header_only input_file output_header ou
139212
else ()
140213
file(WRITE "${output_header}" "${content}")
141214
endif ()
142-
endfunction(generate_header_and_source_from_header_only input_file output_header output_source)
215+
endfunction(generate_header_and_source_from_header_only guard_name input_file output_header output_source)

0 commit comments

Comments
 (0)