1 /* 2 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <getopt.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 12 #include <Architecture.h> 13 #include <Path.h> 14 #include <PathFinder.h> 15 #include <StringList.h> 16 17 18 extern const char* __progname; 19 const char* kCommandName = __progname; 20 21 22 static const char* kUsage = 23 "Usage: %s [ <options> ] [ <path> ]\n" 24 "Prints the architecture currently set via the PATH environment variable,\n" 25 "when no arguments are given. When <path> is specified, the architecture\n" 26 "associated with that path is printed. The options allow to print the\n" 27 "primary architecture or the secondary architectures.\n" 28 "\n" 29 "Options:\n" 30 " -h, --help\n" 31 " Print this usage info.\n" 32 " -p, --primary\n" 33 " Print the primary architecture.\n" 34 " -s, --secondary\n" 35 " Print all secondary architectures for which support is installed.\n" 36 ; 37 38 39 static void 40 print_usage_and_exit(bool error) 41 { 42 fprintf(error ? stderr : stdout, kUsage, kCommandName); 43 exit(error ? 1 : 0); 44 } 45 46 47 static BString 48 get_current_architecture() 49 { 50 // get the system installation location path 51 BPath systemPath; 52 if (find_directory(B_SYSTEM_DIRECTORY, &systemPath) != B_OK) 53 return BString(); 54 55 // get all architectures 56 BStringList architectures; 57 get_architectures(architectures); 58 if (architectures.CountStrings() < 2) 59 return BString(); 60 61 // get the system bin directory for each architecture 62 BStringList binDirectories; 63 BPathFinder pathFinder(systemPath.Path()); 64 int32 architectureCount = architectures.CountStrings(); 65 for (int32 i = 0; i < architectureCount; i++) { 66 BPath path; 67 if (pathFinder.FindPath(architectures.StringAt(i), 68 B_FIND_PATH_BIN_DIRECTORY, NULL, 0, path) != B_OK 69 || !binDirectories.Add(path.Path())) { 70 return BString(); 71 } 72 } 73 74 // Get and split the PATH environmental variable value. The first system 75 // bin path we encounter implies the architecture. 76 char* pathVariableValue = getenv("PATH"); 77 BStringList paths; 78 if (pathVariableValue != NULL 79 && BString(pathVariableValue).Split(":", true, paths)) { 80 int32 count = paths.CountStrings(); 81 for (int32 i = 0; i < count; i++) { 82 // normalize the path, but skip a relative one 83 BPath path; 84 if (paths.StringAt(i)[0] != '/' 85 || path.SetTo(paths.StringAt(i), NULL, true) != B_OK) { 86 continue; 87 } 88 89 int32 index = binDirectories.IndexOf(path.Path()); 90 if (index >= 0) 91 return architectures.StringAt(index); 92 } 93 } 94 95 return BString(); 96 } 97 98 99 int 100 main(int argc, const char* const* argv) 101 { 102 bool printPrimary = false; 103 bool printSecondary = false; 104 105 while (true) { 106 static struct option sLongOptions[] = { 107 { "help", no_argument, 0, 'h' }, 108 { "primary", no_argument, 0, 'p' }, 109 { "secondary", no_argument, 0, 's' }, 110 { 0, 0, 0, 0 } 111 }; 112 113 opterr = 0; // don't print errors 114 int c = getopt_long(argc, (char**)argv, "+hps", 115 sLongOptions, NULL); 116 if (c == -1) 117 break; 118 119 switch (c) { 120 case 'h': 121 print_usage_and_exit(false); 122 break; 123 124 case 'p': 125 printPrimary = true; 126 break; 127 128 case 's': 129 printSecondary = true; 130 break; 131 132 default: 133 print_usage_and_exit(true); 134 break; 135 } 136 } 137 138 // The remaining argument is the optional path. 139 const char* path = optind < argc ? argv[optind++] : NULL; 140 if (optind < argc) 141 print_usage_and_exit(true); 142 143 // only one of path, printPrimary, printSecondary may be specified 144 if (int(path != NULL) + int(printPrimary) + int(printSecondary) > 1) 145 print_usage_and_exit(true); 146 147 if (path != NULL) { 148 // architecture for given path 149 printf("%s\n", guess_architecture_for_path(path)); 150 } else if (printPrimary) { 151 // primary architecture 152 printf("%s\n", get_primary_architecture()); 153 } else if (printSecondary) { 154 // secondary architectures 155 BStringList architectures; 156 get_secondary_architectures(architectures); 157 int32 count = architectures.CountStrings(); 158 for (int32 i = 0; i < count; i++) 159 printf("%s\n", architectures.StringAt(i).String()); 160 } else { 161 // current architecture as implied by PATH 162 BString architecture = get_current_architecture(); 163 printf("%s\n", 164 architecture.IsEmpty() 165 ? get_primary_architecture() : architecture.String()); 166 } 167 168 return 0; 169 } 170