diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3dd10b0..f003768 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -74,7 +74,7 @@ add_library(CpuFeature::cpu_features ALIAS cpu_features)
# program : list_cpu_features
#
-add_executable(list_cpu_features src/list_cpu_features.c)
+add_executable(list_cpu_features src/utils/list_cpu_features.c)
target_link_libraries(list_cpu_features PRIVATE cpu_features)
add_executable(CpuFeature::list_cpu_features ALIAS list_cpu_features)
diff --git a/README.md b/README.md
index 9a3e7df..0dca3f7 100644
--- a/README.md
+++ b/README.md
@@ -121,7 +121,12 @@ family : 6 (0x06)
model : 45 (0x2D)
stepping : 7 (0x07)
uarch : INTEL_SNB
-flags : aes, avx, sse4_1, sse4_2, ssse3
+flags : aes,avx,cx16,smx,sse4_1,sse4_2,ssse3
+```
+
+```shell
+% ./build/list_cpu_features --json
+{"arch":"x86","brand":" Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz","family":6,"model":45,"stepping":7,"uarch":"INTEL_SNB","flags":["aes","avx","cx16","smx","sse4_1","sse4_2","ssse3"]}
```
diff --git a/src/list_cpu_features.c b/src/list_cpu_features.c
deleted file mode 100644
index 92b6dbc..0000000
--- a/src/list_cpu_features.c
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2017 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include
-#include
-#include
-
-#include "cpu_features_macros.h"
-#include "cpuinfo_aarch64.h"
-#include "cpuinfo_arm.h"
-#include "cpuinfo_mips.h"
-#include "cpuinfo_x86.h"
-
-// Prints a named numeric value in both decimal and hexadecimal.
-void PrintN(const char* field, int value) {
- printf("%-15s : %3d (0x%02X)\n", field, value, value);
-}
-
-// Prints a named string.
-void PrintS(const char* field, const char* value) {
- printf("%-15s : %s\n", field, value);
-}
-
-static int cmp(const void* p1, const void* p2) {
- return strcmp(*(const char* const*)p1, *(const char* const*)p2);
-}
-
-#define DEFINE_PRINT_FLAGS(HasFeature, FeatureName, FeatureType, LastEnum) \
- void PrintFlags(const FeatureType* features) { \
- size_t i; \
- const char* ptrs[LastEnum] = {0}; \
- size_t count = 0; \
- for (i = 0; i < LastEnum; ++i) { \
- if (HasFeature(features, i)) { \
- ptrs[count] = FeatureName(i); \
- ++count; \
- } \
- } \
- qsort(ptrs, count, sizeof(char*), cmp); \
- printf("%-15s : ", "flags"); \
- for (i = 0; i < count; ++i) { \
- if (i > 0) printf(", "); \
- printf("%s", ptrs[i]); \
- } \
- printf("\n"); \
- }
-
-#if defined(CPU_FEATURES_ARCH_X86)
-DEFINE_PRINT_FLAGS(GetX86FeaturesEnumValue, GetX86FeaturesEnumName, X86Features,
- X86_LAST_)
-#elif defined(CPU_FEATURES_ARCH_ARM)
-DEFINE_PRINT_FLAGS(GetArmFeaturesEnumValue, GetArmFeaturesEnumName, ArmFeatures,
- ARM_LAST_)
-#elif defined(CPU_FEATURES_ARCH_AARCH64)
-DEFINE_PRINT_FLAGS(GetAarch64FeaturesEnumValue, GetAarch64FeaturesEnumName,
- Aarch64Features, AARCH64_LAST_)
-#elif defined(CPU_FEATURES_ARCH_MIPS)
-DEFINE_PRINT_FLAGS(GetMipsFeaturesEnumValue, GetMipsFeaturesEnumName,
- MipsFeatures, MIPS_LAST_)
-#endif
-
-int main(int argc, char** argv) {
-#if defined(CPU_FEATURES_ARCH_X86)
- char brand_string[49];
- const X86Info info = GetX86Info();
- FillX86BrandString(brand_string);
- PrintS("arch", "x86");
- PrintS("brand", brand_string);
- PrintN("family", info.family);
- PrintN("model", info.model);
- PrintN("stepping", info.stepping);
- PrintS("uarch", GetX86MicroarchitectureName(GetX86Microarchitecture(&info)));
- PrintFlags(&info.features);
-#elif defined(CPU_FEATURES_ARCH_ARM)
- const ArmInfo info = GetArmInfo();
- PrintS("arch", "ARM");
- PrintN("implementer", info.implementer);
- PrintN("architecture", info.architecture);
- PrintN("variant", info.variant);
- PrintN("part", info.part);
- PrintN("revision", info.revision);
- PrintFlags(&info.features);
-#elif defined(CPU_FEATURES_ARCH_AARCH64)
- const Aarch64Info info = GetAarch64Info();
- PrintS("arch", "aarch64");
- PrintN("implementer", info.implementer);
- PrintN("variant", info.variant);
- PrintN("part", info.part);
- PrintN("revision", info.revision);
- PrintFlags(&info.features);
-#elif defined(CPU_FEATURES_ARCH_MIPS)
- const MipsInfo info = GetMipsInfo();
- PrintS("arch", "mips");
- PrintFlags(&info.features);
-#endif
- return 0;
-}
diff --git a/src/utils/list_cpu_features.c b/src/utils/list_cpu_features.c
new file mode 100644
index 0000000..1bbe394
--- /dev/null
+++ b/src/utils/list_cpu_features.c
@@ -0,0 +1,222 @@
+// Copyright 2017 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include
+#include
+#include
+
+#include "cpu_features_macros.h"
+#include "cpuinfo_aarch64.h"
+#include "cpuinfo_arm.h"
+#include "cpuinfo_mips.h"
+#include "cpuinfo_x86.h"
+
+static void PrintEscapedAscii(const char* str) {
+ putchar('"');
+ for (; str && *str; ++str) {
+ switch (*str) {
+ case '\"':
+ case '\\':
+ case '/':
+ case '\b':
+ case '\f':
+ case '\n':
+ case '\r':
+ case '\t':
+ putchar('\\');
+ }
+ putchar(*str);
+ }
+ putchar('"');
+}
+
+static void PrintVoid(void) {}
+static void PrintComma(void) { putchar(','); }
+static void PrintLineFeed(void) { putchar('\n'); }
+static void PrintOpenBrace(void) { putchar('{'); }
+static void PrintCloseBrace(void) { putchar('}'); }
+static void PrintOpenBracket(void) { putchar('['); }
+static void PrintCloseBracket(void) { putchar(']'); }
+static void PrintString(const char* field) { printf("%s", field); }
+static void PrintAlignedHeader(const char* field) { printf("%-15s : ", field); }
+static void PrintIntValue(int value) { printf("%d", value); }
+static void PrintDecHexValue(int value) {
+ printf("%3d (0x%02X)", value, value);
+}
+static void PrintJsonHeader(const char* field) {
+ PrintEscapedAscii(field);
+ putchar(':');
+}
+
+typedef struct {
+ void (*Start)(void);
+ void (*ArrayStart)(void);
+ void (*ArraySeparator)(void);
+ void (*ArrayEnd)(void);
+ void (*PrintString)(const char* value);
+ void (*PrintValue)(int value);
+ void (*EndField)(void);
+ void (*StartField)(const char* field);
+ void (*End)(void);
+} Printer;
+
+static Printer getJsonPrinter(void) {
+ return (Printer){
+ .Start = &PrintOpenBrace,
+ .ArrayStart = &PrintOpenBracket,
+ .ArraySeparator = &PrintComma,
+ .ArrayEnd = &PrintCloseBracket,
+ .PrintString = &PrintEscapedAscii,
+ .PrintValue = &PrintIntValue,
+ .EndField = &PrintComma,
+ .StartField = &PrintJsonHeader,
+ .End = &PrintCloseBrace,
+ };
+}
+
+static Printer getTextPrinter(void) {
+ return (Printer){
+ .Start = &PrintVoid,
+ .ArrayStart = &PrintVoid,
+ .ArraySeparator = &PrintComma,
+ .ArrayEnd = &PrintVoid,
+ .PrintString = &PrintString,
+ .PrintValue = &PrintDecHexValue,
+ .EndField = &PrintLineFeed,
+ .StartField = &PrintAlignedHeader,
+ .End = &PrintVoid,
+ };
+}
+
+// Prints a named numeric value in both decimal and hexadecimal.
+static void PrintN(const Printer p, const char* field, int value) {
+ p.StartField(field);
+ p.PrintValue(value);
+ p.EndField();
+}
+
+// Prints a named string.
+static void PrintS(const Printer p, const char* field, const char* value) {
+ p.StartField(field);
+ p.PrintString(value);
+ p.EndField();
+}
+
+static int cmp(const void* p1, const void* p2) {
+ return strcmp(*(const char* const*)p1, *(const char* const*)p2);
+}
+
+#define DEFINE_PRINT_FLAGS(HasFeature, FeatureName, FeatureType, LastEnum) \
+ static void PrintFlags(const Printer p, const FeatureType* features) { \
+ size_t i; \
+ const char* ptrs[LastEnum] = {0}; \
+ size_t count = 0; \
+ for (i = 0; i < LastEnum; ++i) { \
+ if (HasFeature(features, i)) { \
+ ptrs[count] = FeatureName(i); \
+ ++count; \
+ } \
+ } \
+ qsort(ptrs, count, sizeof(char*), cmp); \
+ p.StartField("flags"); \
+ p.ArrayStart(); \
+ for (i = 0; i < count; ++i) { \
+ if (i > 0) p.ArraySeparator(); \
+ p.PrintString(ptrs[i]); \
+ } \
+ p.ArrayEnd(); \
+ }
+
+#if defined(CPU_FEATURES_ARCH_X86)
+DEFINE_PRINT_FLAGS(GetX86FeaturesEnumValue, GetX86FeaturesEnumName, X86Features,
+ X86_LAST_)
+#elif defined(CPU_FEATURES_ARCH_ARM)
+DEFINE_PRINT_FLAGS(GetArmFeaturesEnumValue, GetArmFeaturesEnumName, ArmFeatures,
+ ARM_LAST_)
+#elif defined(CPU_FEATURES_ARCH_AARCH64)
+DEFINE_PRINT_FLAGS(GetAarch64FeaturesEnumValue, GetAarch64FeaturesEnumName,
+ Aarch64Features, AARCH64_LAST_)
+#elif defined(CPU_FEATURES_ARCH_MIPS)
+DEFINE_PRINT_FLAGS(GetMipsFeaturesEnumValue, GetMipsFeaturesEnumName,
+ MipsFeatures, MIPS_LAST_)
+#endif
+
+static void PrintFeatures(const Printer printer) {
+#if defined(CPU_FEATURES_ARCH_X86)
+ char brand_string[49];
+ const X86Info info = GetX86Info();
+ FillX86BrandString(brand_string);
+ PrintS(printer, "arch", "x86");
+ PrintS(printer, "brand", brand_string);
+ PrintN(printer, "family", info.family);
+ PrintN(printer, "model", info.model);
+ PrintN(printer, "stepping", info.stepping);
+ PrintS(printer, "uarch",
+ GetX86MicroarchitectureName(GetX86Microarchitecture(&info)));
+ PrintFlags(printer, &info.features);
+#elif defined(CPU_FEATURES_ARCH_ARM)
+ const ArmInfo info = GetArmInfo();
+ PrintS(printer, "arch", "ARM");
+ PrintN(printer, "implementer", info.implementer);
+ PrintN(printer, "architecture", info.architecture);
+ PrintN(printer, "variant", info.variant);
+ PrintN(printer, "part", info.part);
+ PrintN(printer, "revision", info.revision);
+ PrintFlags(printer, &info.features);
+#elif defined(CPU_FEATURES_ARCH_AARCH64)
+ const Aarch64Info info = GetAarch64Info();
+ PrintS(printer, "arch", "aarch64");
+ PrintN(printer, "implementer", info.implementer);
+ PrintN(printer, "variant", info.variant);
+ PrintN(printer, "part", info.part);
+ PrintN(printer, "revision", info.revision);
+ PrintFlags(printer, &info.features);
+#elif defined(CPU_FEATURES_ARCH_MIPS)
+ const MipsInfo info = GetMipsInfo();
+ PrintS(printer, "arch", "mips");
+ PrintFlags(printer, &info.features);
+#endif
+}
+
+static void showUsage(const char* name) {
+ printf(
+ "\n"
+ "Usage: %s [options]\n"
+ " Options:\n"
+ " -h | --help Show help message.\n"
+ " -j | --json Format output as json instead of plain text.\n"
+ "\n",
+ name);
+}
+
+int main(int argc, char** argv) {
+ Printer printer = getTextPrinter();
+ int i = 1;
+ for (; i < argc; ++i) {
+ const char* arg = argv[i];
+ if (strcmp(arg, "-j") == 0 || strcmp(arg, "--json") == 0) {
+ printer = getJsonPrinter();
+ } else {
+ showUsage(argv[0]);
+ if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0)
+ return EXIT_SUCCESS;
+ return EXIT_FAILURE;
+ }
+ }
+ printer.Start();
+ PrintFeatures(printer);
+ printer.End();
+ PrintLineFeed();
+ return EXIT_SUCCESS;
+}