/*

*/

include <ctype.h>

include <err.h>

include <errno.h>

include <dirent.h>

include <stdarg.h>

include <stdio.h>

include <stdlib.h>

include <string.h>

include <unistd.h>

define LEN(X) (sizeof X / sizeof X[0])

define PLEDGEORDIE(prom) if (pledge(prom, NULL) == -1) { err(1, "pledge"); }

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[])

{

ifdef OpenBSD

PLEDGEORDIE("stdio rpath cpath wpath");

endif

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;

}

Proxy Information
Original URL
gemini://si3t.ch/code/lsdesktop/lsdesktop.c
Status Code
Success (20)
Meta
application/octet-stream
Capsule Response Time
494.974373 milliseconds
Gemini-to-HTML Time
6.2659 milliseconds

This content has been proxied by September (3851b).