/***********************************************
* List Android modules according to Android.mk
* 2015, all rights reserved.
***********************************************/
#include <ctype.h>
#include <dirent.h>
#include <getopt.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define MKFILE_1 "Android.mk"
#define MKFILE_2 "NativeCode.mk"
#define SM_START "CLEAR_VARS"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
#endif
typedef struct match_table {
const char *match_string;
const char *log_file;
char cli_arg[64];
} match_table;
struct match_table match_tables[] = {
{"BUILD_PREBUILT", "./oem_modules/prebuilt.txt", {0}},
{"BUILD_SHARED_LIBRARY", "./oem_modules/shared.txt", {0}},
{"BUILD_STATIC_LIBRARY", "./oem_modules/static.txt", {0}},
{"BUILD_EXECUTABLE", "./oem_modules/binary.txt", {0}},
{"BUILD_JAVA_LIBRARY", "./oem_modules/jar.txt", {0}},
{"BUILD_PACKAGE", "./oem_modules/app.txt", {0}},
{"BUILD_HOST_SHARED_LIBRARY", "./oem_modules/host_jar.txt", {0}},
};
static char proc_name_arg[64];
static int droid_mk_count = 0;
static int nativecode_mk_count = 0;
static int my_printf(const char *fmt, ...)
{
va_list arg;
char buf[1024];
FILE *fp;
int rc;
va_start(arg, fmt);
rc = vsnprintf(buf, 1023, fmt, arg);
va_end(arg);
printf("%s", buf);
return rc;
}
static void print_usage(void)
{
const char *usage =
"Usage: %s [OPTION...]\n"
" -p, --prebuilt=PREBUILT_NAME\tlist prebuilt makefile path\n"
" -d, --so=SHARED_NAME\t\tlist shared makefile path\n"
" -s, --static=STATIC_NAME\t\tlist static makefile path\n"
" -b, --bin=BINARY\t\t\tlist binary makefile path\n"
" -j, --jar=JAR_NAME\t\t\tlist jar makefile path\n"
" -a, --apk=APP_NAME\t\t\tlist apk makefile path\n"
" -r, --jar_host=HOST_JAR_NAME\tlist jar host makefile path\n"
" -h, --help\t\t\t\tprint the usage\n\n"
"HOW-TO:\n"
"Copy this command to the Android source code "
"directory which includes the Android.mk, such as "
"<system/core>\n\n"
"For example:\n"
" ./%s\n"
" ./%s -b diag_uart_log\n\n";
my_printf(usage, proc_name_arg, proc_name_arg, proc_name_arg);
}
static void write_file_string(const char *log_file, const char *str)
{
FILE *fp;
fp = fopen(log_file, "a+");
if (fp) {
fputs(str, fp);
fclose(fp);
}
}
static bool is_local_module(char *s)
{
char *ptr;
char *tmp;
if (strstr(s, "LOCAL_PACKAGE_NAME")) {
return true;
}
tmp = s;
while (isspace(*tmp)) tmp++;
if (strstr(tmp, "LOCAL_MODULE")) {
ptr = tmp + strlen("LOCAL_MODULE");
while(isspace(*ptr)) ptr++;
if ((*ptr == ':') ||
(*ptr == '=')) {
return true;
}
return false;
}
return false;
}
static void save_module_name(char *mkfile_with_path, char *module_name,
match_table *mt, bool *manual_check)
{
char buf[256];
write_file_string(mt->log_file, module_name);
if (strlen(mt->cli_arg) > 1) {
snprintf(buf, 255, "%s\n", mkfile_with_path);
if (!strncmp(mt->cli_arg, "all", 3)) {
write_file_string(mt->log_file, buf);
} else if (!strncmp(module_name, mt->cli_arg, strlen(mt->cli_arg))) {
write_file_string(mt->log_file, buf);
}
}
if (*manual_check) {
*manual_check = false;
snprintf(buf, 255,
"###check this [%s] manually###\n", mkfile_with_path);
write_file_string(mt->log_file, buf);
}
}
static void get_all_module_names(char *mkfile_with_path)
{
FILE *fp;
int i;
char buf[256];
char module_name[256];
char *ptr;
bool pattern_match = false;
bool manual_check = false;
fp = fopen(mkfile_with_path, "r");
if (fp) {
while (fgets(buf, 255, fp)) {
if (strstr(buf, SM_START)) {
pattern_match = false;
manual_check = false;
}
if (!pattern_match) {
if (is_local_module(buf)) {
ptr = strchr(buf, '=');
ptr++;
while (isspace(*ptr)) ptr++;
snprintf(module_name, 255, "%s", ptr);
if (strchr(module_name, '$')) {
manual_check = true;
}
pattern_match = true;
}
} else if (pattern_match) {
for (i = 0; i < ARRAY_SIZE(match_tables); i++) {
if (strstr(buf, match_tables[i].match_string)) {
pattern_match = false;
save_module_name(mkfile_with_path,
module_name, &match_tables[i], &manual_check);
}
} /* end of for_loop */
} /* end of else_if */
} /* end of while */
fclose(fp);
} /* end of if (fp) */
}
static void list_modules(char *scanned_dir)
{
DIR *d;
struct dirent *de;
char buf[256];
d = opendir(scanned_dir);
if (d) {
while (NULL != (de = readdir(d))) {
if (de->d_name[0] == '.') {
continue;
}
snprintf(buf, 255, "%s/%s", scanned_dir, de->d_name);
if (de->d_type == DT_DIR) {
list_modules(buf);
} else if(!strncmp(de->d_name, MKFILE_1, strlen(MKFILE_1)) ||
!strncmp(de->d_name, MKFILE_2, strlen(MKFILE_2))) {
if (!strcasecmp(de->d_name, MKFILE_1)) {
droid_mk_count++;
} else {
nativecode_mk_count++;
}
my_printf("%s: %d found, "
"%s: %d found\r",
MKFILE_1, droid_mk_count,
MKFILE_2, nativecode_mk_count);
get_all_module_names(buf);
}
}
closedir(d);
}
}
static void rm_dir(const char *scanned_dir)
{
DIR *d;
struct dirent *de;
char buf[256];
d = opendir(scanned_dir);
if (d) {
while (NULL != (de = readdir(d))) {
if (de->d_name[0] == '.') {
continue;
}
snprintf(buf, 255, "%s/%s", scanned_dir, de->d_name);
if (de->d_type == DT_DIR) {
rm_dir(buf);
} else {
unlink(buf);
}
}
closedir(d);
}
rmdir(scanned_dir);
}
static void parse_args(int argc, char **argv)
{
char *p = NULL;
int opt = 0;
struct option long_options[] = {
{"so", required_argument, 0, 'd'},
{"static", required_argument, 0, 's'},
{"bin", required_argument, 0, 'b'},
{"apk", required_argument, 0, 'a'},
{"prebuilt", required_argument, 0, 'p'},
{"jar", required_argument, 0, 'j'},
{"jar_host", required_argument, 0, 'r'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
if (strchr(argv[0], '/')) {
p = strchr(argv[0], '/');
p++;
}
strcpy(proc_name_arg, p);
while ((opt = getopt_long(argc, argv, "p:d:s:b:j:a:r:h",
long_options, NULL)) != -1) {
switch(opt) {
case 'p': /* prebuilt */
strncpy(match_tables[0].cli_arg, optarg, 63);
break;
case 'd': /* shared */
strncpy(match_tables[1].cli_arg, optarg, 63);
break;
case 's': /* static */
strncpy(match_tables[2].cli_arg, optarg, 63);
break;
case 'b': /* binary */
strncpy(match_tables[3].cli_arg, optarg, 63);
break;
case 'j': /* jar */
strncpy(match_tables[4].cli_arg, optarg, 63);
break;
case 'a': /* application */
strncpy(match_tables[5].cli_arg, optarg, 63);
break;
case 'r': /* host jar */
strncpy(match_tables[6].cli_arg, optarg, 63);
break;
case 'h':
print_usage();
exit(0);
}
}
}
int main(int argc, char **argv)
{
rm_dir("./oem_modules");
mkdir("./oem_modules", 0777);
my_printf("\nout directory: ./oem_modules\n\n");
parse_args(argc, argv);
list_modules("./");
my_printf("\n\n");
return 0;
}