diff --git a/docs/parsers/proc_consoles.md b/docs/parsers/proc_consoles.md
index 72093124..e3441ec1 100644
--- a/docs/parsers/proc_consoles.md
+++ b/docs/parsers/proc_consoles.md
@@ -3,7 +3,7 @@
# jc.parsers.proc\_consoles
-jc - JSON Convert `/proc/consoles` command output parser
+jc - JSON Convert `/proc/consoles` file parser
Usage (cli):
diff --git a/docs/parsers/proc_cpuinfo.md b/docs/parsers/proc_cpuinfo.md
new file mode 100644
index 00000000..3bf9c967
--- /dev/null
+++ b/docs/parsers/proc_cpuinfo.md
@@ -0,0 +1,247 @@
+[Home](https://kellyjonbrazil.github.io/jc/)
+
+
+# jc.parsers.proc\_cpuinfo
+
+jc - JSON Convert `/proc/cpuinfo` file parser
+
+Usage (cli):
+
+ $ cat /proc/cpuinfo | jc --proc
+
+or
+
+ $ cat /proc/cpuinfo | jc --proc-cpuinfo
+
+Usage (module):
+
+ import jc
+ result = jc.parse('proc', proc_cpuinfo_file)
+
+or
+
+ import jc
+ result = jc.parse('proc_cpuinfo', proc_cpuinfo_file)
+
+Schema:
+
+Integer, float, and boolean ("yes"/"no") conversions are attempted. Blank
+strings are converted to `null`.
+
+"Well-known" keys like `cache size`, `address types`, `bugs`, and `flags`
+are processed into sensible data types. (see below)
+
+If this is not desired, then use the `--raw` (CLI) or `raw=True` (Module)
+option.
+
+ [
+ {
+ "processor": integer,
+ "address sizes": string,
+ "address_size_physical": integer, # in bits
+ "address_size_virtual": integer, # in bits
+ "cache size": string,
+ "cache_size_num": integer,
+ "cache_size_unit": string,
+ "flags": string,
+ "flag_list": [
+ string
+ ],
+ "bugs": string,
+ "bug_list": [
+ string
+ ],
+ "bogomips": float,
+ : string/int/float/boolean/null
+ }
+ ]
+
+Examples:
+
+ $ cat /proc/cpuinfo | jc --proc -p
+ [
+ {
+ "processor": 0,
+ "vendor_id": "GenuineIntel",
+ "cpu family": 6,
+ "model": 142,
+ "model name": "Intel(R) Core(TM) i5-8279U CPU @ 2.40GHz",
+ "stepping": 10,
+ "cpu MHz": 2400.0,
+ "cache size": "6144 KB",
+ "physical id": 0,
+ "siblings": 1,
+ "core id": 0,
+ "cpu cores": 1,
+ "apicid": 0,
+ "initial apicid": 0,
+ "fpu": true,
+ "fpu_exception": true,
+ "cpuid level": 22,
+ "wp": true,
+ "flags": "fpu vme de pse tsc msr pae mce cx8 apic sep mtrr ...",
+ "bugs": "cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass ...",
+ "bogomips": 4800.0,
+ "clflush size": 64,
+ "cache_alignment": 64,
+ "address sizes": "45 bits physical, 48 bits virtual",
+ "power management": null,
+ "address_size_physical": 45,
+ "address_size_virtual": 48,
+ "cache_size_num": 6144,
+ "cache_size_unit": "KB",
+ "flag_list": [
+ "fpu",
+ "vme",
+ "de",
+ "pse",
+ "tsc",
+ "msr",
+ "pae",
+ "mce",
+ "cx8",
+ "apic",
+ "sep",
+ "mtrr",
+ "pge",
+ "mca",
+ "cmov",
+ "pat",
+ "pse36",
+ "clflush",
+ "mmx",
+ "fxsr",
+ "sse",
+ "sse2",
+ "ss",
+ "syscall",
+ "nx",
+ "pdpe1gb",
+ "rdtscp",
+ "lm",
+ "constant_tsc",
+ "arch_perfmon",
+ "nopl",
+ "xtopology",
+ "tsc_reliable",
+ "nonstop_tsc",
+ "cpuid",
+ "pni",
+ "pclmulqdq",
+ "ssse3",
+ "fma",
+ "cx16",
+ "pcid",
+ "sse4_1",
+ "sse4_2",
+ "x2apic",
+ "movbe",
+ "popcnt",
+ "tsc_deadline_timer",
+ "aes",
+ "xsave",
+ "avx",
+ "f16c",
+ "rdrand",
+ "hypervisor",
+ "lahf_lm",
+ "abm",
+ "3dnowprefetch",
+ "cpuid_fault",
+ "invpcid_single",
+ "pti",
+ "ssbd",
+ "ibrs",
+ "ibpb",
+ "stibp",
+ "fsgsbase",
+ "tsc_adjust",
+ "bmi1",
+ "avx2",
+ "smep",
+ "bmi2",
+ "invpcid",
+ "rdseed",
+ "adx",
+ "smap",
+ "clflushopt",
+ "xsaveopt",
+ "xsavec",
+ "xgetbv1",
+ "xsaves",
+ "arat",
+ "md_clear",
+ "flush_l1d",
+ "arch_capabilities"
+ ],
+ "bug_list": [
+ "cpu_meltdown",
+ "spectre_v1",
+ "spectre_v2",
+ "spec_store_bypass",
+ "l1tf",
+ "mds",
+ "swapgs",
+ "itlb_multihit",
+ "srbds"
+ ]
+ },
+ ...
+ ]
+
+ $ proc_cpuinfo | jc --proc_cpuinfo -p -r
+ [
+ {
+ "processor": "0",
+ "vendor_id": "GenuineIntel",
+ "cpu family": "6",
+ "model": "142",
+ "model name": "Intel(R) Core(TM) i5-8279U CPU @ 2.40GHz",
+ "stepping": "10",
+ "cpu MHz": "2400.000",
+ "cache size": "6144 KB",
+ "physical id": "0",
+ "siblings": "1",
+ "core id": "0",
+ "cpu cores": "1",
+ "apicid": "0",
+ "initial apicid": "0",
+ "fpu": "yes",
+ "fpu_exception": "yes",
+ "cpuid level": "22",
+ "wp": "yes",
+ "flags": "fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge ...",
+ "bugs": "cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass ...",
+ "bogomips": "4800.00",
+ "clflush size": "64",
+ "cache_alignment": "64",
+ "address sizes": "45 bits physical, 48 bits virtual",
+ "power management": ""
+ },
+ ...
+ ]
+
+
+
+### parse
+
+```python
+def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict]
+```
+
+Main text parsing function
+
+Parameters:
+
+ data: (string) text data to parse
+ raw: (boolean) unprocessed output if True
+ quiet: (boolean) suppress warning messages if True
+
+Returns:
+
+ List of Dictionaries. Raw or processed structured data.
+
+### Parser Information
+Compatibility: linux
+
+Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com)
diff --git a/docs/parsers/proc_modules.md b/docs/parsers/proc_modules.md
index 7497d141..6fda08cc 100644
--- a/docs/parsers/proc_modules.md
+++ b/docs/parsers/proc_modules.md
@@ -3,7 +3,7 @@
# jc.parsers.proc\_modules
-jc - JSON Convert `/proc/modules` command output parser
+jc - JSON Convert `/proc/modules` file parser
Usage (cli):
diff --git a/jc/lib.py b/jc/lib.py
index 76bd1000..9cecbe5d 100644
--- a/jc/lib.py
+++ b/jc/lib.py
@@ -87,6 +87,7 @@ parsers = [
'proc',
'proc-buddyinfo',
'proc-consoles',
+ 'proc-cpuinfo',
'proc-meminfo',
'proc-modules',
'ps',
diff --git a/jc/parsers/proc.py b/jc/parsers/proc.py
index d0a8495a..0317ff53 100644
--- a/jc/parsers/proc.py
+++ b/jc/parsers/proc.py
@@ -145,7 +145,7 @@ def parse(
# signatures
buddyinfo_p = re.compile(r'^Node \d+, zone\s+\w+\s+(?:\d+\s+){11}\n')
consoles_p = re.compile(r'^\w+\s+[\-WUR]{3} \([ECBpba ]+\)\s+\d+:\d+\n')
- cpuinfo_p = re.compile(r'^processor\s+:.*\nvendor_id\s+:.*\ncpu family\s+:.*\n')
+ cpuinfo_p = re.compile(r'^processor\t+: \d+.*bogomips\t+: \d+.\d\d\n', re.DOTALL)
crypto_p = re.compile(r'^name\s+:.*\ndriver\s+:.*\nmodule\s+:.*\n')
devices_p = re.compile(r'^Character devices:\n\s+\d+ .*\n')
diskstats_p = re.compile(r'^\s*\d+\s+\d\s\w+\s(?:\d+\s){16}\d\n')
diff --git a/jc/parsers/proc_consoles.py b/jc/parsers/proc_consoles.py
index 5724a9b5..5f517f4b 100644
--- a/jc/parsers/proc_consoles.py
+++ b/jc/parsers/proc_consoles.py
@@ -1,4 +1,4 @@
-"""jc - JSON Convert `/proc/consoles` command output parser
+"""jc - JSON Convert `/proc/consoles` file parser
Usage (cli):
diff --git a/jc/parsers/proc_cpuinfo.py b/jc/parsers/proc_cpuinfo.py
new file mode 100644
index 00000000..a059eea5
--- /dev/null
+++ b/jc/parsers/proc_cpuinfo.py
@@ -0,0 +1,333 @@
+"""jc - JSON Convert `/proc/cpuinfo` file parser
+
+Usage (cli):
+
+ $ cat /proc/cpuinfo | jc --proc
+
+or
+
+ $ cat /proc/cpuinfo | jc --proc-cpuinfo
+
+Usage (module):
+
+ import jc
+ result = jc.parse('proc', proc_cpuinfo_file)
+
+or
+
+ import jc
+ result = jc.parse('proc_cpuinfo', proc_cpuinfo_file)
+
+Schema:
+
+Integer, float, and boolean ("yes"/"no") conversions are attempted. Blank
+strings are converted to `null`.
+
+"Well-known" keys like `cache size`, `address types`, `bugs`, and `flags`
+are processed into sensible data types. (see below)
+
+If this is not desired, then use the `--raw` (CLI) or `raw=True` (Module)
+option.
+
+ [
+ {
+ "processor": integer,
+ "address sizes": string,
+ "address_size_physical": integer, # in bits
+ "address_size_virtual": integer, # in bits
+ "cache size": string,
+ "cache_size_num": integer,
+ "cache_size_unit": string,
+ "flags": string,
+ "flag_list": [
+ string
+ ],
+ "bugs": string,
+ "bug_list": [
+ string
+ ],
+ "bogomips": float,
+ : string/int/float/boolean/null
+ }
+ ]
+
+Examples:
+
+ $ cat /proc/cpuinfo | jc --proc -p
+ [
+ {
+ "processor": 0,
+ "vendor_id": "GenuineIntel",
+ "cpu family": 6,
+ "model": 142,
+ "model name": "Intel(R) Core(TM) i5-8279U CPU @ 2.40GHz",
+ "stepping": 10,
+ "cpu MHz": 2400.0,
+ "cache size": "6144 KB",
+ "physical id": 0,
+ "siblings": 1,
+ "core id": 0,
+ "cpu cores": 1,
+ "apicid": 0,
+ "initial apicid": 0,
+ "fpu": true,
+ "fpu_exception": true,
+ "cpuid level": 22,
+ "wp": true,
+ "flags": "fpu vme de pse tsc msr pae mce cx8 apic sep mtrr ...",
+ "bugs": "cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass ...",
+ "bogomips": 4800.0,
+ "clflush size": 64,
+ "cache_alignment": 64,
+ "address sizes": "45 bits physical, 48 bits virtual",
+ "power management": null,
+ "address_size_physical": 45,
+ "address_size_virtual": 48,
+ "cache_size_num": 6144,
+ "cache_size_unit": "KB",
+ "flag_list": [
+ "fpu",
+ "vme",
+ "de",
+ "pse",
+ "tsc",
+ "msr",
+ "pae",
+ "mce",
+ "cx8",
+ "apic",
+ "sep",
+ "mtrr",
+ "pge",
+ "mca",
+ "cmov",
+ "pat",
+ "pse36",
+ "clflush",
+ "mmx",
+ "fxsr",
+ "sse",
+ "sse2",
+ "ss",
+ "syscall",
+ "nx",
+ "pdpe1gb",
+ "rdtscp",
+ "lm",
+ "constant_tsc",
+ "arch_perfmon",
+ "nopl",
+ "xtopology",
+ "tsc_reliable",
+ "nonstop_tsc",
+ "cpuid",
+ "pni",
+ "pclmulqdq",
+ "ssse3",
+ "fma",
+ "cx16",
+ "pcid",
+ "sse4_1",
+ "sse4_2",
+ "x2apic",
+ "movbe",
+ "popcnt",
+ "tsc_deadline_timer",
+ "aes",
+ "xsave",
+ "avx",
+ "f16c",
+ "rdrand",
+ "hypervisor",
+ "lahf_lm",
+ "abm",
+ "3dnowprefetch",
+ "cpuid_fault",
+ "invpcid_single",
+ "pti",
+ "ssbd",
+ "ibrs",
+ "ibpb",
+ "stibp",
+ "fsgsbase",
+ "tsc_adjust",
+ "bmi1",
+ "avx2",
+ "smep",
+ "bmi2",
+ "invpcid",
+ "rdseed",
+ "adx",
+ "smap",
+ "clflushopt",
+ "xsaveopt",
+ "xsavec",
+ "xgetbv1",
+ "xsaves",
+ "arat",
+ "md_clear",
+ "flush_l1d",
+ "arch_capabilities"
+ ],
+ "bug_list": [
+ "cpu_meltdown",
+ "spectre_v1",
+ "spectre_v2",
+ "spec_store_bypass",
+ "l1tf",
+ "mds",
+ "swapgs",
+ "itlb_multihit",
+ "srbds"
+ ]
+ },
+ ...
+ ]
+
+ $ proc_cpuinfo | jc --proc_cpuinfo -p -r
+ [
+ {
+ "processor": "0",
+ "vendor_id": "GenuineIntel",
+ "cpu family": "6",
+ "model": "142",
+ "model name": "Intel(R) Core(TM) i5-8279U CPU @ 2.40GHz",
+ "stepping": "10",
+ "cpu MHz": "2400.000",
+ "cache size": "6144 KB",
+ "physical id": "0",
+ "siblings": "1",
+ "core id": "0",
+ "cpu cores": "1",
+ "apicid": "0",
+ "initial apicid": "0",
+ "fpu": "yes",
+ "fpu_exception": "yes",
+ "cpuid level": "22",
+ "wp": "yes",
+ "flags": "fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge ...",
+ "bugs": "cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass ...",
+ "bogomips": "4800.00",
+ "clflush size": "64",
+ "cache_alignment": "64",
+ "address sizes": "45 bits physical, 48 bits virtual",
+ "power management": ""
+ },
+ ...
+ ]
+"""
+from typing import List, Dict
+import jc.utils
+
+
+class info():
+ """Provides parser metadata (version, author, etc.)"""
+ version = '1.0'
+ description = '`/proc/cpuinfo` file parser'
+ author = 'Kelly Brazil'
+ author_email = 'kellyjonbrazil@gmail.com'
+ compatible = ['linux']
+ hidden = True
+
+
+__version__ = info.version
+
+
+def _process(proc_data: List[Dict]) -> List[Dict]:
+ """
+ Final processing to conform to the schema.
+
+ Parameters:
+
+ proc_data: (List of Dictionaries) raw structured data to process
+
+ Returns:
+
+ List of Dictionaries. Structured to conform to the schema.
+ """
+ int_list = {'size', 'used'}
+
+ for entry in proc_data:
+ for key in entry:
+ if entry[key] == '':
+ entry[key] = None
+
+ try:
+ entry[key] = int(entry[key])
+ except Exception:
+ pass
+
+ try:
+ if isinstance(entry[key], str) and (entry[key] == 'yes' or entry[key] == 'no'):
+ entry[key] = jc.utils.convert_to_bool(entry[key])
+ except Exception:
+ pass
+
+ try:
+ if isinstance(entry[key], str) and '.' in entry[key]:
+ entry[key] = float(entry[key])
+ except Exception:
+ pass
+
+ if 'address sizes' in entry:
+ phy = int(entry['address sizes'].split()[0])
+ virt = int(entry['address sizes'].split()[3])
+ entry['address_size_physical'] = phy
+ entry['address_size_virtual'] = virt
+
+ if 'cache size' in entry:
+ cache_size_int, unit = entry['cache size'].split()
+ entry['cache_size_num'] = int(cache_size_int)
+ entry['cache_size_unit'] = unit
+
+ if 'flags' in entry:
+ flag_list = entry['flags'].split()
+ entry['flag_list'] = flag_list
+
+ if 'bugs' in entry:
+ bug_list = entry['bugs'].split()
+ entry['bug_list'] = bug_list
+
+ return proc_data
+
+
+def parse(
+ data: str,
+ raw: bool = False,
+ quiet: bool = False
+) -> List[Dict]:
+ """
+ Main text parsing function
+
+ Parameters:
+
+ data: (string) text data to parse
+ raw: (boolean) unprocessed output if True
+ quiet: (boolean) suppress warning messages if True
+
+ Returns:
+
+ List of Dictionaries. Raw or processed structured data.
+ """
+ jc.utils.compatibility(__name__, info.compatible, quiet)
+ jc.utils.input_type_check(data)
+
+ raw_output: List = []
+ output_line: Dict = {}
+
+ if jc.utils.has_data(data):
+
+ for line in filter(None, data.splitlines()):
+
+ if line.startswith('processor'):
+ if output_line:
+ raw_output.append(output_line)
+ output_line = {}
+
+ key, val = line.split(':', maxsplit=1)
+ output_line[key.strip()] = val.strip()
+
+ if output_line:
+ raw_output.append(output_line)
+
+ return raw_output if raw else _process(raw_output)
diff --git a/jc/parsers/proc_modules.py b/jc/parsers/proc_modules.py
index 59715dff..1404c66a 100644
--- a/jc/parsers/proc_modules.py
+++ b/jc/parsers/proc_modules.py
@@ -1,4 +1,4 @@
-"""jc - JSON Convert `/proc/modules` command output parser
+"""jc - JSON Convert `/proc/modules` file parser
Usage (cli):
diff --git a/man/jc.1 b/man/jc.1
index 3dc3f98f..f21b2ea9 100644
--- a/man/jc.1
+++ b/man/jc.1
@@ -407,6 +407,11 @@ PLIST file parser
\fB--proc-consoles\fP
`/proc/consoles` file parser
+.TP
+.B
+\fB--proc-cpuinfo\fP
+`/proc/cpuinfo` file parser
+
.TP
.B
\fB--proc-meminfo\fP