/*
Application-Name command
*/
int efclose(FILE *stream);
FILE * efopen(const char *path, const char *mode);
int endswith(const char *str, const char *end);
size_t esnprintf(char *str, size_t size, const char *fmt, ...);
char * estrdup(const char *s);
int filter_desktop(const struct dirent *d);
char * get_desktop_item(const char *f, const char *item);
void print_name(const char *f);
void print_exec(const char *f);
void print_category(const char *f);
void trim(char **str);
int startswith(const char *str, const char *start);
static const char *categories[][2] = {
{ "Graphics", "Graphics" },
{ "Development", "Development" },
{ "Settings", "Settings" },
{ "System", "System" },
{ "Utility", "Utility" },
{ "Game", "Game" },
{ "Network", "Network" },
{ "Office", "Office" },
{ "Audio", "Multimedia" },
{ "Video", "Multimedia" },
};
static const char *misc = "Misc";
int
efclose(FILE *stream)
{
int ret = 0;
ret = fclose(stream);
if (ferror(stream)) {
err(1,"closefile");
}
return ret;
}
FILE *
efopen(const char *path, const char *mode)
{
FILE *f = NULL;
if ((f = fopen(path, mode)) == NULL)
err(1, "%s: %s", "Fail to open", path);
return f;
}
size_t
esnprintf(char *str, size_t size, const char *fmt, ...)
{
va_list ap;
size_t ret = 0;
va_start(ap, fmt);
ret = vsnprintf(str, size, fmt, ap);
if (ret < 0) {
err(1,"vsnprintf:");
} else if (ret >= size) {
err(1,"vsnprintf: Output truncated");
}
va_end(ap);
return ret;
}
char *
estrdup(const char *s)
{
char *p = strdup(s);
if (p == NULL)
err(1, "strdup");
return p;
}
int
startswith(const char *str, const char *start)
{
size_t str_len = strlen(str);
size_t start_len = strlen(start);
int ret = 0;
if ((str_len >= start_len) &&
(strncmp(str, start, start_len) == 0)) {
ret = 1;
}
return ret;
}
int
endswith(const char *str, const char *end)
{
size_t str_len = strlen(str);
size_t end_len = strlen(end);
int ret = 0;
if ((str_len >= end_len) &&
(strcmp(str + (str_len -end_len), end) == 0)) {
ret = 1;
}
return ret;
}
char *
get_desktop_item(const char *f, const char *item)
{
char *match = NULL;
char *tmp = NULL;
char *line = NULL;
size_t linesize = 0;
ssize_t linelen;
FILE *fp;
fp = efopen(f, "r");
while ((linelen = getline(&line, &linesize, fp)) != -1) {
if (startswith(line, item)) {
tmp = strsep(&line, "=");
trim(&line);
match = estrdup(line);
break;
}
}
free(tmp);
if (ferror(fp)) {
err(1, "getline");
}
efclose(fp);
return match;
}
void
print_name(const char *f)
{
char *res = NULL;
char l[3] = {'\0'};
char namel[10] = {'\0'};
const char *lang = getenv("LANG");
strncpy(l, lang, 2);
esnprintf(namel, sizeof(namel), "Name[%s]=", l);
res = get_desktop_item(f, namel);
if (res == NULL) {
res = get_desktop_item(f, "Name=");
}
printf("%s", res);
free(res);
}
void
print_category(const char *f)
{
char *res = NULL;
res = get_desktop_item(f, "Categories=");
if (res != NULL) {
for (size_t k = 0; k < LEN(categories); k++) {
if (strstr(res, categories[k][0]) != NULL) {
printf("%s", categories[k][1]);
break;
}
}
} else {
printf("%s", misc);
}
free(res);
}
void
print_exec(const char *f)
{
char *res = NULL;
char *tmp = NULL;
/* remove %f and stuff */
res = get_desktop_item(f, "Exec=");
tmp = strsep(&res, "%");
printf("%s", tmp);
free(tmp);
}
int
filter_desktop(const struct dirent *d)
{
int ret = 0;
const char *homedir = getenv("HOME");
char exclude[BUFSIZ] = {'\0'};
char *line = NULL;
FILE *fp;
size_t linesize = 0;
ssize_t linelen;
/* exclude list is in ~/.config/lsdesktop.exclude */
esnprintf(exclude, sizeof(exclude), "%s/.config/lsdesktop.exclude", homedir);
if (endswith(d->d_name, ".desktop")) {
ret = 1;
if (access(exclude, F_OK ) != -1 ) {
fp = efopen(exclude, "r");
while ((linelen = getline(&line, &linesize, fp)) != -1) {
trim(&line);
if (strcmp(d->d_name, line) == 0) {
ret = 0;
break;
}
}
free(line);
if (ferror(fp)) {
err(1, "getline");
}
efclose(fp);
}
}
return ret;
}
/* return a trimmed copy of str */
/* trim(&str); */
void
trim(char **str)
{
size_t begin = 0;
size_t end = strlen(*str);
while (isspace((*str)[begin])) {
begin++;
}
while (isspace((*str)[end-1])) {
end--;
}
for (size_t i = begin, j=0; i < end; i++, j++) {
(*str)[j] = (*str)[i];
}
(*str)[end - begin] = '\0';
}
int
main (int argc, char *argv[])
{
PLEDGEORDIE("stdio rpath cpath wpath");
int n = 0;
char *sep = "|";
char *item = NULL;
char homedirapp[BUFSIZ] = {'\0'};
char desktop[BUFSIZ] = {'\0'};
const char *homedir = getenv("HOME");
struct dirent **namelist;
if (argc == 2) {
if (strcmp(argv[1], "-h") == 0) {
printf("usage: %s [-h|-s]\n", argv[0]);
printf(" -h: show this message\n");
printf(" -s: set separator string between name and command\n\n");
printf("every filename listed in ~/.config/lsdesktop.exclude"
" will be ignored (one per line)\n");
exit(0);
}
} else if (argc == 3) {
sep = argv[2];
}
esnprintf(homedirapp, sizeof(homedirapp), "%s/.local/share/applications", homedir);
/* .desktop files directories */
const char *dfd[] = {
"/usr/local/share/applications",
"/usr/share/applications",
homedirapp
};
for (size_t i = 0; i < LEN(dfd); i++) {
if ((n = scandir(dfd[i], &namelist, filter_desktop, NULL)) < 0) {
warn("scandir:%s", dfd[i]);
} else {
for(int j = 0; j < n; j++) {
esnprintf(desktop, sizeof(desktop), "%s/%s",
dfd[i], namelist[j]->d_name);
print_category(desktop);
printf("%s", sep);
print_name(desktop);
printf("%s", sep);
print_exec(desktop);
printf("\n");
free(namelist[j]);
}
free(namelist);
}
}
return 0;
}
application/octet-stream
This content has been proxied by September (3851b).