22# The .NET Foundation licenses this file to you under the Apache 2.0 License.
33# See the LICENSE file in the project root for more information.
44
5+ import re
56from generate import generate
67from collections import OrderedDict
78
1617darwin_aliases = {'EWOULDBLOCK' : 'EAGAIN' }
1718aliases = {** linux_aliases , ** darwin_aliases }
1819
20+
1921def set_value (codeval , name , value , index ):
2022 if name not in codeval :
2123 codeval [name ] = [None ] * len (systems )
2224 codeval [name ][index ] = value
2325
26+
2427def collect_errornames ():
2528 errorval = {}
2629 for code in errorcode_linux :
@@ -102,6 +105,7 @@ def darwin_code_expr(codes, fmt):
102105def linux_code_expr (codes , fmt ):
103106 return fmt (codes [linux_idx ])
104107
108+
105109common_errno_codes = ['ENOENT' , 'E2BIG' , 'ENOEXEC' , 'EBADF' , 'ECHILD' , 'EAGAIN' , 'ENOMEM' , 'EACCES' , 'EEXIST' , 'EXDEV' , 'ENOTDIR' , 'EMFILE' , 'ENOSPC' , 'EPIPE' , 'ENOTEMPTY' , 'EILSEQ' , 'EINVAL' ]
106110
107111def generate_common_errno_codes (cw ):
@@ -114,6 +118,7 @@ def generate_common_errno_codes(cw):
114118 else :
115119 cw .write (f"internal static int { name } => { value } ;" )
116120
121+
117122def generate_errno_names (cw ):
118123 def is_windows_alias (name ):
119124 return "WSA" + name in errorvalues and name in errorvalues and errorvalues ["WSA" + name ][windows_idx ] == errorvalues [name ][windows_idx ]
@@ -178,13 +183,17 @@ def collect_codes():
178183
179184O_flagvalues = collect_codes ()
180185
181- def generate_O_flags (cw , flagvalues , access ):
182- for name in flagvalues .keys ():
183- codes = flagvalues [name ]
186+
187+ def generate_codes (cw , codeval , access , fmt , unix_only = False ):
188+ for name in codeval .keys ():
189+ codes = codeval [name ]
190+ all_systems = set (systems )
191+ if unix_only :
192+ all_systems .discard (systems [windows_idx ])
184193 hidden_on = []
185- supported_on = set (systems )
194+ supported_on = set (all_systems )
186195 cw .writeline ()
187- if codes [windows_idx ] is None :
196+ if codes [windows_idx ] is None and not unix_only :
188197 hidden_on = ["PlatformsAttribute.PlatformFamily.Windows" ]
189198 supported_on .discard (systems [windows_idx ])
190199 if codes [linux_idx ] is None and codes [darwin_idx ] is None :
@@ -201,20 +210,80 @@ def generate_O_flags(cw, flagvalues, access):
201210 supported_on .discard (systems [darwin_idx ])
202211 if hidden_on and (access == 'public' or access == 'protected' or access == 'protected internal' ):
203212 cw .write (f"[PythonHidden({ ', ' .join (hidden_on )} )]" )
204- if len (supported_on ) != len (systems ):
213+ if len (supported_on ) != len (all_systems ):
205214 for s in sorted (supported_on ):
206215 cw .write (f'[SupportedOSPlatform("{ s } ")]' )
207216
208- value = windows_code_expr (codes , fmt = hex )
209- cw .write (f"{ access } static int { name } => { value } ;" )
217+ value = windows_code_expr (codes , fmt )
218+ typ = "int"
219+ if (all (c .isdigit () for c in value ) or re .match (r'^0x[0-9a-fA-F]+$' , value )):
220+ n = eval (value )
221+ if n > 2 ** 31 - 1 or n < - 2 ** 31 :
222+ typ = "long"
223+ cw .write (f"{ access } static { typ } { name } => { value } ;" )
224+
210225
211226def generate_all_O_flags (cw ):
212- generate_O_flags (cw , O_flagvalues , 'public' )
227+ generate_codes (cw , O_flagvalues , 'public' , hex )
228+
213229
214230common_O_flags = ['O_RDONLY' , 'O_WRONLY' , 'O_RDWR' , 'O_APPEND' , 'O_CREAT' , 'O_TRUNC' , 'O_EXCL' , 'O_CLOEXEC' , 'O_BINARY' , 'O_NOINHERIT' ]
215231
216232def generate_common_O_flags (cw ):
217- generate_O_flags (cw , OrderedDict ((f , O_flagvalues [f ]) for f in common_O_flags ), 'private' )
233+ generate_codes (cw , OrderedDict ((f , O_flagvalues [f ]) for f in common_O_flags ), 'private' , hex )
234+
235+
236+ # python3 -c 'import fcntl;print(dict(sorted((s, getattr(fcntl, s)) for s in dir(fcntl) if s.startswith("F_"))))'
237+ # Python 3.6.15 [GCC 12.2.0] on linux 6.10.14
238+ FD_commands_linux = {'F_ADD_SEALS' : 1033 , 'F_DUPFD' : 0 , 'F_DUPFD_CLOEXEC' : 1030 , 'F_EXLCK' : 4 , 'F_GETFD' : 1 , 'F_GETFL' : 3 , 'F_GETLEASE' : 1025 , 'F_GETLK' : 5 , 'F_GETLK64' : 5 , 'F_GETOWN' : 9 , 'F_GETPIPE_SZ' : 1032 , 'F_GETSIG' : 11 , 'F_GET_SEALS' : 1034 , 'F_NOTIFY' : 1026 , 'F_OFD_GETLK' : 36 , 'F_OFD_SETLK' : 37 , 'F_OFD_SETLKW' : 38 , 'F_RDLCK' : 0 , 'F_SEAL_GROW' : 4 , 'F_SEAL_SEAL' : 1 , 'F_SEAL_SHRINK' : 2 , 'F_SEAL_WRITE' : 8 , 'F_SETFD' : 2 , 'F_SETFL' : 4 , 'F_SETLEASE' : 1024 , 'F_SETLK' : 6 , 'F_SETLK64' : 6 , 'F_SETLKW' : 7 , 'F_SETLKW64' : 7 , 'F_SETOWN' : 8 , 'F_SETPIPE_SZ' : 1031 , 'F_SETSIG' : 10 , 'F_SHLCK' : 8 , 'F_UNLCK' : 2 , 'F_WRLCK' : 1 }
239+ # Unsupported by Mono.Unix 7.1.0-final.1.21458.1 on linux
240+ FD_commands_linux_unsupported = ['F_DUPFD_CLOEXEC' , 'F_GETPIPE_SZ' , 'F_SETPIPE_SZ' ]
241+ # Python 3.7.0 [Clang 4.0.1 ] on darwin 24.2.0
242+ FD_commands_darwin = {'F_DUPFD' : 0 , 'F_DUPFD_CLOEXEC' : 67 , 'F_FULLFSYNC' : 51 , 'F_GETFD' : 1 , 'F_GETFL' : 3 , 'F_GETLK' : 7 , 'F_GETOWN' : 5 , 'F_NOCACHE' : 48 , 'F_RDLCK' : 1 , 'F_SETFD' : 2 , 'F_SETFL' : 4 , 'F_SETLK' : 8 , 'F_SETLKW' : 9 , 'F_SETOWN' : 6 , 'F_UNLCK' : 2 , 'F_WRLCK' : 3 }
243+ # Unsupported by Mono.Unix 7.1.0-final.1.21458.1 on darwin
244+ FD_commands_darwin_unsupported = ['F_DUPFD_CLOEXEC' , 'F_FULLFSYNC' ]
245+
246+ def generate_FD_commands (cw ):
247+ codeval = {}
248+ for name in FD_commands_linux :
249+ if name not in FD_commands_linux_unsupported :
250+ set_value (codeval , name , FD_commands_linux [name ], linux_idx )
251+ for name in FD_commands_darwin :
252+ if name not in FD_commands_darwin_unsupported :
253+ set_value (codeval , name , FD_commands_darwin [name ], darwin_idx )
254+ codeval = OrderedDict (sorted (codeval .items ()))
255+ generate_codes (cw , codeval , 'public' , str , unix_only = True )
256+
257+
258+ # python3 -c 'import fcntl;print(dict(sorted((s, getattr(fcntl, s)) for s in dir(fcntl) if s.startswith("DN_"))))'
259+ # Python 3.6.15 [GCC 12.2.0] on linux 6.10.14
260+ # Python 3.12.3 [GCC 13.2.0] on linux 6.8.0
261+ DN_flags_linux = {'DN_ACCESS' : 1 , 'DN_ATTRIB' : 32 , 'DN_CREATE' : 4 , 'DN_DELETE' : 8 , 'DN_MODIFY' : 2 , 'DN_MULTISHOT' : 2147483648 , 'DN_RENAME' : 16 }
262+
263+ def generate_DN_flags (cw ):
264+ codeval = {}
265+ for name in DN_flags_linux :
266+ set_value (codeval , name , DN_flags_linux [name ], linux_idx )
267+ codeval = OrderedDict (sorted (codeval .items ()))
268+ generate_codes (cw , codeval , 'public' , hex , unix_only = True )
269+
270+
271+ # python3 -c 'import fcntl;print(dict(sorted((s, getattr(fcntl, s)) for s in dir(fcntl) if s.startswith("LOCK_"))))'
272+ # Python 3.6.15 [GCC 12.2.0] on linux 6.10.14
273+ # Python 3.12.3 [GCC 13.2.0] on linux 6.8.0
274+ LOCK_flags_linux = {'LOCK_EX' : 2 , 'LOCK_MAND' : 32 , 'LOCK_NB' : 4 , 'LOCK_READ' : 64 , 'LOCK_RW' : 192 , 'LOCK_SH' : 1 , 'LOCK_UN' : 8 , 'LOCK_WRITE' : 128 }
275+ # Python 3.7.0 [Clang 4.0.1 ] on darwin 24.2.0
276+ # Python 3.12.0 [Clang 14.0.6 ] on darwin 24.2.0
277+ LOCK_flags_darwin = {'LOCK_EX' : 2 , 'LOCK_NB' : 4 , 'LOCK_SH' : 1 , 'LOCK_UN' : 8 }
278+
279+ def generate_LOCK_flags (cw ):
280+ codeval = {}
281+ for name in LOCK_flags_linux :
282+ set_value (codeval , name , LOCK_flags_linux [name ], linux_idx )
283+ for name in LOCK_flags_darwin :
284+ set_value (codeval , name , LOCK_flags_darwin [name ], darwin_idx )
285+ codeval = OrderedDict (sorted (codeval .items ()))
286+ generate_codes (cw , codeval , 'public' , hex , unix_only = True )
218287
219288
220289def main ():
@@ -224,6 +293,9 @@ def main():
224293 ("Errno Names" , generate_errno_names ),
225294 ("O_Flags" , generate_all_O_flags ),
226295 ("Common O_Flags" , generate_common_O_flags ),
296+ ("FD Commands" , generate_FD_commands ),
297+ ("Directory Notify Flags" , generate_DN_flags ),
298+ ("LOCK Flags" , generate_LOCK_flags ),
227299 )
228300
229301if __name__ == "__main__" :
0 commit comments