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