11# ----------------------------------------------------------------------------
2- # Copyright 2019-2022 Diligent Graphics LLC
2+ # Copyright 2019-2026 Diligent Graphics LLC
33#
44# Licensed under the Apache License, Version 2.0 (the "License");
55# you may not use this file except in compliance with the License.
2525# ----------------------------------------------------------------------------
2626
2727import sys
28+ import io
29+ import argparse
30+
31+ def strip_c_comments (text ):
32+ result = []
33+ current_line = []
34+
35+ in_line_comment = False
36+ in_block_comment = False
37+ in_string = False
38+ in_char = False
39+ escape = False
40+
41+ line_has_comment = False
42+ line_has_noncomment_code = False
43+
44+ def append_char (c ):
45+ nonlocal line_has_noncomment_code
46+ current_line .append (c )
47+ if not c .isspace ():
48+ line_has_noncomment_code = True
49+
50+ def flush_line (add_newline ):
51+ nonlocal current_line , line_has_comment , line_has_noncomment_code
52+
53+ # Remove lines that contain only a comment (possibly with whitespace around it)
54+ if not (line_has_comment and not line_has_noncomment_code and "" .join (current_line ).strip () == "" ):
55+ result .extend (current_line )
56+ if add_newline :
57+ result .append ("\n " )
58+
59+ current_line = []
60+ line_has_noncomment_code = False
61+
62+ # If we are still inside a block comment, the next physical line is also comment-only so far
63+ line_has_comment = in_block_comment
64+
65+ i = 0
66+ n = len (text )
67+
68+ while i < n :
69+ c = text [i ]
70+ nxt = text [i + 1 ] if i + 1 < n else ""
71+
72+ if in_line_comment :
73+ if c == "\n " :
74+ in_line_comment = False
75+ flush_line (True )
76+ i += 1
77+ continue
78+
79+ if in_block_comment :
80+ if c == "*" and nxt == "/" :
81+ in_block_comment = False
82+ i += 2
83+ continue
84+
85+ if c == "\n " :
86+ flush_line (True )
87+ i += 1
88+ continue
89+
90+ if in_string :
91+ append_char (c )
92+ if escape :
93+ escape = False
94+ elif c == "\\ " :
95+ escape = True
96+ elif c == '"' :
97+ in_string = False
98+ i += 1
99+ continue
100+
101+ if in_char :
102+ append_char (c )
103+ if escape :
104+ escape = False
105+ elif c == "\\ " :
106+ escape = True
107+ elif c == "'" :
108+ in_char = False
109+ i += 1
110+ continue
111+
112+ if c == "/" and nxt == "/" :
113+ line_has_comment = True
114+ in_line_comment = True
115+ i += 2
116+ continue
117+
118+ if c == "/" and nxt == "*" :
119+ line_has_comment = True
120+ in_block_comment = True
121+ i += 2
122+ continue
123+
124+ if c == '"' :
125+ append_char (c )
126+ in_string = True
127+ i += 1
128+ continue
129+
130+ if c == "'" :
131+ append_char (c )
132+ in_char = True
133+ i += 1
134+ continue
135+
136+ if c == "\n " :
137+ flush_line (True )
138+ i += 1
139+ continue
140+
141+ append_char (c )
142+ i += 1
143+
144+ if current_line :
145+ if not (line_has_comment and not line_has_noncomment_code and "" .join (current_line ).strip () == "" ):
146+ result .extend (current_line )
147+
148+ return "" .join (result )
28149
29150
30151def main ():
31- try :
32- if len (sys .argv ) < 3 :
33- raise ValueError ("Incorrect number of command line arguments. Expected arguments: src file, dst file" )
152+ parser = argparse .ArgumentParser (
153+ description = "Convert a file into quoted string lines."
154+ )
155+ parser .add_argument ("src" , help = "source file" )
156+ parser .add_argument ("dst" , help = "destination file" )
157+ parser .add_argument (
158+ "--strip-comments" ,
159+ action = "store_true" ,
160+ help = "strip // and /* */ comments before converting" ,
161+ )
162+
163+ args = parser .parse_args ()
34164
35- if sys .argv [1 ] == sys .argv [2 ]:
165+ try :
166+ if args .src == args .dst :
36167 raise ValueError ("Source and destination files must be different" )
37168
38- with open (sys . argv [ 1 ] , "r" ) as src_file , open (sys . argv [ 2 ] , "w" ) as dst_file :
169+ with open (args . src , "r" ) as src_file , open (args . dst , "w" ) as dst_file :
39170 special_chars = "\' \" \\ "
40171
41- for line in src_file :
172+ if args .strip_comments :
173+ content = strip_c_comments (src_file .read ())
174+ src_iter = io .StringIO (content )
175+ else :
176+ src_iter = src_file
177+
178+ for line in src_iter :
42179 dst_file .write ('\" ' )
43180
44181 for i , c in enumerate (line .rstrip ()):
@@ -48,7 +185,8 @@ def main():
48185
49186 dst_file .write ('\\ n\" \n ' )
50187
51- print ("File2String: successfully converted {} to {}" .format (sys .argv [1 ], sys .argv [2 ]))
188+ print ("File2String: successfully converted {} to {}" .format (args .src , args .dst ))
189+
52190 except (ValueError , IOError ) as error :
53191 print (error )
54192 sys .exit (1 )
0 commit comments