Skip to content

Instantly share code, notes, and snippets.

@mej
Created October 29, 2024 18:05
Show Gist options
  • Select an option

  • Save mej/e5ed8726f3561eea8b2db9ccb22262a0 to your computer and use it in GitHub Desktop.

Select an option

Save mej/e5ed8726f3561eea8b2db9ccb22262a0 to your computer and use it in GitHub Desktop.
Python script to create Bash hashmaps for, and/or provide translations among, `errno`, symbolic error identifiers, and `strerror()`-provided error strings
#!/bin/python3
### -*- Mode: Python; fill-column: 132; comment-auto-fill-only-comments: t; tab-width: 4; eval: (local-set-key "\C-i" 'indent-according-to-mode); eval: (auto-fill-mode 1); -*-
#
# Map `errno` names or codes to num+name+strerror tuples and/or generate Bash
# arrays that do the same mappings. For use in MEJSH, NHC, and/or daily life.
#
# Michael Jennings <[email protected]>
# 23 Sep 2024
#
import argparse as ap
import errno
import os
import sys
global verbose
### Function Definitions
def error_resolve(error: str) -> list:
global verbose
if error.isdigit():
num = int(error)
else:
error = error.upper()
try:
if not errno.__dict__.__contains__(error):
if errno.__dict__.__contains__("E" + error):
error = 'E' + error
except:
pass
try:
num = int(errno.__dict__[error])
except KeyError:
print("Invalid errno value: %s" % (error))
raise KeyError
message = os.strerror(num)
symname = errno.errorcode[num]
if verbose >= 1:
print('%s(): Resolved "%s" to errno tuple: [ num = %d, symname = "%s", message = "%s" ]' % ('error_resolve', error, num, symname, message), file=sys.stderr)
return [num, symname, message]
def main() -> int:
global verbose
codes = []
errinfo = {}
maxnum = 0
maxsym = 0
### Command-Line Arguments
parser = ap.ArgumentParser(prog='errno', description='Resolve errno numeric constants, symbolic names, and canonical messages in various ways',
allow_abbrev=True, epilog='', fromfile_prefix_chars='@', prefix_chars='-+') # NOPE: argument_default=ap.SUPPRESS
parser.add_argument('--version', '-V', action='version', version='%(prog)s 0.2')
parser.add_argument('--verbose', '-v', action='count', default=0)
parser.add_argument('--bash', '-b', action=ap.BooleanOptionalAction, default=False, help='Output shell code to generate assoc. arrays (maps/dicts) in Bash')
parser.add_argument('--sort', '-s', action=ap.BooleanOptionalAction, default=True, dest='sorted', help='Sort output lines by numeric `errno` value')
parser.add_argument('--symsort', '-S', action=ap.BooleanOptionalAction, default=False, help='Sort output lines by symbolic error names (e.g., EPERM)')
parser.add_argument('--tabs', '-t', action=ap.BooleanOptionalAction, default=False, help='Generate TSV output (format: code<TAB>symbol<TAB>strerror<EOL>)')
parser.add_argument('errors', nargs='*')
opts = parser.parse_args()
verbose = opts.verbose
args = opts.errors
# Remove the script/command path from the arg list.
#args = sys.argv
#args.pop(0)
#print(args)
if len(args) <= 0:
args = sorted(errno.errorcode)
for arg in args:
if verbose >= 2:
print('Looping over %d args; now processing "%s"' % (args.__len__(), arg), file=sys.stderr)
try:
(e, c, m) = error_resolve(str(arg))
except KeyError:
continue
if opts.symsort:
codes.append(c)
errinfo[c] = (e, c, m)
else:
codes.append(e)
errinfo[e] = (e, c, m)
maxnum = max(maxnum, len(str(e)))
maxsym = max(maxsym, len(c))
if opts.sorted or opts.symsort:
codes.sort()
if opts.bash:
sh_err = "typeset -A ERRNO=(\n"
sh_str = "typeset -A STRERR=(\n"
for key in codes:
(e, c, m) = errinfo[key]
if opts.bash:
sh_err += (" [%d]='%s' ['%s']=%d\n" % (e, c, c, e))
sh_str += (" ['%s']='%s' ['%s']='%s'\n" % (e, m, c, m))
elif opts.tabs:
print("%d\t%s\t%s" % (e, c, m))
else:
fmt = '%' + str(maxnum) + 'd %-' + str(maxsym) + 's => "%s"'
print(fmt % (e, c, m))
if opts.bash:
sh_err += ")"
sh_str += ")"
#print("%s\n%s\n\n" % (sh_err, sh_str))
print("%s %s\n\n" % (sh_err, sh_str.removeprefix('typeset -A ')))
return 0
if __name__ == '__main__':
sys.exit(main())
@mej
Copy link
Author

mej commented Oct 29, 2024

This is the first time I've ever attempted to write something useful, by myself, from scratch, in Python. Please be gentle!
๐Ÿ˜‰ ๐Ÿ˜†

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment