Сайт | Скачать | Видео | Wiki

Автор Тема: Построитель меню JWM на C  (Прочитано 29628 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн DdShurick

  • Это Риччи
  • Активный участник
  • Ветеран
  • ****
  • Сообщений: 8635
  • Репутация: +187/-2
  • Автор темы
  • Старый чайник
Построитель меню JWM на C
« : 02 Февраль 2016, 15:19:49 »
https://github.com/rodonx/menu

Очень упрощённый аналог ls, вводит список файлов *.desktop
Код
#include <stdio.h>
#include <dirent.h>
#include <string.h>

int main() {
    DIR *dir;
    struct dirent *entry;

    dir = opendir("/usr/share/applications");
    if (!dir) {
        perror("diropen");
    }

    while ((entry = readdir(dir)) != NULL) {
if ( strstr(entry->d_name, ".desktop")!=0 ) {
        printf(entry->d_name);
        printf("\n");
}
    }

    closedir(dir);
}
Думаю приспособить для fixmenus.
« Последнее редактирование: 26 Сентябрь 2019, 11:07:24 от sfs »
Моноблок Lenovo IdeaCentre c200 (Intel Atom D525, Intel GMA 3150, 2 Gb RAM) Richy64
Nettop Acer Aspire Revo R3610 (Atom N330, nVidia GeForce 9400, 3 Gb RAM) Richy64

Оффлайн sfs

  • Администратор
  • Ветеран
  • *****
  • Сообщений: 33965
  • Репутация: +231/-0
    • PuppyRus-A
Построитель меню JWM
« Ответ #1 : 02 Февраль 2016, 15:29:53 »
На выходе получается ускорение по сравнению с sh ? Смысл в этом?

Оффлайн DdShurick

  • Это Риччи
  • Активный участник
  • Ветеран
  • ****
  • Сообщений: 8635
  • Репутация: +187/-2
  • Автор темы
  • Старый чайник
Построитель меню JWM
« Ответ #2 : 02 Февраль 2016, 17:53:08 »
На выходе получается ускорение по сравнению с sh ?
Должно
Смысл в этом?
Расти над самим собой.
Моноблок Lenovo IdeaCentre c200 (Intel Atom D525, Intel GMA 3150, 2 Gb RAM) Richy64
Nettop Acer Aspire Revo R3610 (Atom N330, nVidia GeForce 9400, 3 Gb RAM) Richy64

Оффлайн dim-kut

  • Активный участник
  • Ветеран
  • ****
  • Сообщений: 1021
  • Репутация: +41/-0
Построитель меню JWM
« Ответ #3 : 02 Февраль 2016, 18:02:00 »
На выходе получается ускорение по сравнению с sh ?
Должно
Должно, но на современных компах мы можем этого не заметить.
Смысл в этом?
Расти над самим собой.
+1
Engineering is the art of making what you want from things you can get.

Оффлайн DdShurick

  • Это Риччи
  • Активный участник
  • Ветеран
  • ****
  • Сообщений: 8635
  • Репутация: +187/-2
  • Автор темы
  • Старый чайник
Построитель меню JWM
« Ответ #4 : 03 Февраль 2016, 10:20:57 »
 Научил lsapplications понимать Categories:
Код
# ./lsapplications1 
Категория?
# ./lsapplications1 Network
Linux-Firewall.desktop
Pure_FTPd-FTP-server.desktop
gpptp.desktop
mtr-traceroute.desktop
pnethood.desktop
tsclient.desktop
wifi.desktop
CMake.desktop
Осталось сделать вывод в нужном формате.
Моноблок Lenovo IdeaCentre c200 (Intel Atom D525, Intel GMA 3150, 2 Gb RAM) Richy64
Nettop Acer Aspire Revo R3610 (Atom N330, nVidia GeForce 9400, 3 Gb RAM) Richy64

Оффлайн DdShurick

  • Это Риччи
  • Активный участник
  • Ветеран
  • ****
  • Сообщений: 8635
  • Репутация: +187/-2
  • Автор темы
  • Старый чайник
Построитель меню JWM
« Ответ #5 : 04 Февраль 2016, 18:23:26 »
 Я забуксовал. Этот вариант:
Код
#include <stdio.h>
#include <dirent.h>
#include <string.h>

DIR *dir;
FILE *fp;
char buf[64], str[1024];
char *name, *icon, *exec;
char *appdir="/usr/share/applications/";

struct dirent *entry;

int main(int argc, char *argv[]) {
if (argc<2) {
printf("Категория? %s","\n");
return 0;
}
    dir = opendir(appdir);
    if (!dir) {
        perror("diropen");
    }
printf("<JWM>%s","\n");
    while ((entry = readdir(dir))!=0) {
if (strstr(entry->d_name,".desktop")!=0 ) {
buf[0]=0;
strcat(buf,appdir);
strcat(buf,entry->d_name);
        fp=fopen(buf,"r");
        while (fgets(str,sizeof(str),fp)!=0) {
if (strstr(str,argv[1])!=0) {
while (fgets(str,sizeof(str),fp)!=0) {
name=strstr(str,"Name");
// *strchr(strchr(name, '=') + 1, '\n') = 0;
// name=("%s\n", strchr(name, '=') + 1);
}
while (fgets(str,sizeof(str),fp)!=0) {
icon=strstr(str,"Icon");
}
while (fgets(str,sizeof(str),fp)!=0) {
exec=strstr(str,"Exec");
}
printf("\t<Program %s%s%s %s%s%s%s%s%s","label=\"",name,"\"","icon\"",icon,"\">",exec,"</Program>","\n");
}

}
        fclose(fp);
}

    }
    closedir(dir);
    printf("<JWM>%s","\n");
}
генерирует подменю заданной категории но не полностью, без icon и exec. Не желает брать переменные.
Код
<JWM>
<Program label="Name=Partview view partition sizes
" icon"(null)">(null)</Program>
<Program label="Name=Xfdiff-cut
" icon"(null)">(null)</Program>
<Program label="Name=gFnRename
" icon"(null)">(null)</Program>
<Program label="Name=Gcolor2
" icon"(null)">(null)</Program>
<Program label="Name=Сохранить настройки в sfs
" icon"(null)">(null)</Program>
<Program label="ies=GTK;GNOME;Application;Utility;
" icon"(null)">(null)</Program>
<Program label="Name=PTM Timer
" icon"(null)">(null)</Program>
<Program label="Name=puppyPDF convert file to PDF
" icon"(null)">(null)</Program>
<Program label="(null)" icon"(null)">(null)</Program>
<Program label="Name=ePDFView PDF viewer
" icon"(null)">(null)</Program>
<Program label="Name=mtPaint-snapshot screen capture
" icon"(null)">(null)</Program>
<JWM>
Закомментированный код убирает "Name=" но вызывает сегментацию. Что делать  ???
Моноблок Lenovo IdeaCentre c200 (Intel Atom D525, Intel GMA 3150, 2 Gb RAM) Richy64
Nettop Acer Aspire Revo R3610 (Atom N330, nVidia GeForce 9400, 3 Gb RAM) Richy64

Оффлайн ander

  • Активный участник
  • Старожил
  • ****
  • Сообщений: 300
  • Репутация: +16/-0
Построитель меню JWM
« Ответ #6 : 04 Февраль 2016, 23:15:40 »
Код
*strchr(strchr(name, '=') + 1, '\n') = 0;
Еще скобок не хватает:
Код
*(strchr(strchr(name, '=') + 1, '\n')) = 0;
без них эта конструкция пытается записать ноль даже сразу и не соображу куда, но явно не по возвращаемому функцией указателю, скорее по адресу самой функции, где она в памяти располагается.

А конструкция
Код
name=("%s\n", strchr(name, '=') + 1);
вообще непонятная.  Может тут sprintf предполагался?

А переменные равны null, все правильно.
Смотрите, что получается.  Начался while (fgets(str,sizeof(str),fp)!=0) {}, он же переберет все строки, для каждой выполняя name=strstr(str,"Name");.  Тут, видимо, повезло и "Name" нашлось в последней строке, поэтому name установлен. А последующие while не выполняются вовсе, поскольку fgets() читать больше нечего, файл-то уже кончился.  Вот icon и exec никуда и не указывают.

Оффлайн DdShurick

  • Это Риччи
  • Активный участник
  • Ветеран
  • ****
  • Сообщений: 8635
  • Репутация: +187/-2
  • Автор темы
  • Старый чайник
Построитель меню JWM
« Ответ #7 : 05 Февраль 2016, 09:25:45 »
Код
*strchr(strchr(name, '=') + 1, '\n') = 0;
Еще скобок не хватает:
Код
*(strchr(strchr(name, '=') + 1, '\n')) = 0;
без них эта конструкция пытается записать ноль даже сразу и не соображу куда, но явно не по возвращаемому функцией указателю, скорее по адресу самой функции, где она в памяти располагается.
А конструкция
Код
name=("%s\n", strchr(name, '=') + 1);
вообще непонятная.  Может тут sprintf предполагался?
Эту конструкцию я "честно стырил" на одном из форумов. В первоисточнике было printf. Можно сделать
Код
name=strchr(name, '=') + 1;
но тогда строка "ломается" и всё равно "ошибка сегментации".
А последующие while не выполняются вовсе, поскольку fgets() читать больше нечего, файл-то уже кончился.  Вот icon и exec никуда и не указывают.
Это понятно, но как заставить fgets перечитать файл?
Моноблок Lenovo IdeaCentre c200 (Intel Atom D525, Intel GMA 3150, 2 Gb RAM) Richy64
Nettop Acer Aspire Revo R3610 (Atom N330, nVidia GeForce 9400, 3 Gb RAM) Richy64

Оффлайн ander

  • Активный участник
  • Старожил
  • ****
  • Сообщений: 300
  • Репутация: +16/-0
Построитель меню JWM
« Ответ #8 : 05 Февраль 2016, 11:35:42 »
Перечитать можно сделав rewind или fseek, но логичнее было бы все поиски делать в одном цикле.  И тут еще один прикол - все эти name - это просто указатели на ячейку памяти, строк они не содержат.  Если они указывают куда-то, где располагается массив str и в этом массиве действительно есть строка по этому адресу, то все нормально, можно прочитать эту строку через name.  Но ведь на следующем проходе цикла while массив str будет содержать уже другие данные, а name указывает на прежнее место, то есть напечатав его значение, вы увидите совсем не то, что на предыдущем проходе, хотя сам name и не изменялся.
В C вообще часто нужно четко представлять, как байты в памяти располагаются и указатели на них указывают.

Оффлайн k0l0p0k

  • Ветеран
  • *****
  • Сообщений: 1611
  • Репутация: +27/-1
Построитель меню JWM
« Ответ #9 : 05 Февраль 2016, 11:43:15 »
Цитата
Это понятно, но как заставить fgets перечитать файл?

1)см выше :) . rewind или fseek
2)костыльнее - закрыть файл, открыть заново
3)считать строки в массив и  работать уже с массивом
ну или файл в память считать, массив все равно нужен будет - указатели на строки хранить.
...
« Последнее редактирование: 05 Февраль 2016, 11:48:39 от k0l0p0k »
1.пень G2020,8Gb,Radeon RX460 (Debian+openBox+LXPanel)
2.нетбук  Samsung N145 (Debian+openBox+LXPanel, ddr01)

Оффлайн ander

  • Активный участник
  • Старожил
  • ****
  • Сообщений: 300
  • Репутация: +16/-0
Построитель меню JWM
« Ответ #10 : 05 Февраль 2016, 13:52:34 »
примерно так.  Не оптимально, повторения в функцию надо вынести, но работает.
Код
#include <stdio.h>
#include <dirent.h>
#include <string.h>

DIR *dir;
FILE *fp;
char buf[64], str[1024], namestr[64], iconstr[64], execstr[64];
char *tpoint, *lf;
int category_found;
char *appdir="/usr/share/applications/";
        
struct dirent *entry;

int main(int argc, char *argv[]) {
        if (argc<2) {
                printf("Категория?\n");
                return 0;
        }
    dir = opendir(appdir);
    if (!dir) {
        perror("diropen");
    }
    namestr[64]=iconstr[64]=execstr[64]=0; /* чтоб в любом случае в конце строки был */
        printf("<JWM>\n");
    while ((entry = readdir(dir))!=0) {
                if (strstr(entry->d_name,".desktop")!=0 ) {
                        buf[0]=0;
                        strcat(buf,appdir);
                        strcat(buf,entry->d_name);
                fp=fopen(buf,"r");
                category_found=0;
                while (fgets(str,sizeof(str),fp)!=0) {
                                if ( (lf=strchr(str, '\n'))!=0 ) *lf=0;  /* убрали перевод строки, чтобы не болтался*/
                                if (strstr(str,argv[1])!=0) category_found=1;
                                else if ((tpoint=strstr(str,"Name="))!=0) strncpy(namestr, strchr(tpoint, '=')+1, sizeof(namestr)-1); /* найденную строку сохранили */
                                else if ((tpoint=strstr(str,"Icon"))!=0) strncpy(iconstr, strchr(tpoint, '=')+1, sizeof(iconstr)-1);
                                else if ((tpoint=strstr(str,"Exec"))!=0) strncpy(execstr, strchr(tpoint, '=')+1, sizeof(execstr)-1);
                        }
                        if (category_found) printf("\t<Program label=\"%s\" icon\"%s\">%s</Program>\n", namestr, iconstr, execstr);
                        fclose(fp);
                }
    }
    closedir(dir);
    printf("<JWM>\n");
    return 0;
}
Чего-то отступы при вставке сбиваются, с табуляцией видимо проблемы.  Но принцип в общем то понятен, я думаю.
« Последнее редактирование: 05 Февраль 2016, 14:02:15 от ander »

Оффлайн DdShurick

  • Это Риччи
  • Активный участник
  • Ветеран
  • ****
  • Сообщений: 8635
  • Репутация: +187/-2
  • Автор темы
  • Старый чайник
Построитель меню JWM
« Ответ #11 : 05 Февраль 2016, 14:02:05 »
 Благодарю! Сейчас буду допиливать.
Моноблок Lenovo IdeaCentre c200 (Intel Atom D525, Intel GMA 3150, 2 Gb RAM) Richy64
Nettop Acer Aspire Revo R3610 (Atom N330, nVidia GeForce 9400, 3 Gb RAM) Richy64

Оффлайн k0l0p0k

  • Ветеран
  • *****
  • Сообщений: 1611
  • Репутация: +27/-1
Построитель меню JWM
« Ответ #12 : 05 Февраль 2016, 14:56:38 »
не возникнет ли проблем если длинна найденных строк превысит 64 ?
1.пень G2020,8Gb,Radeon RX460 (Debian+openBox+LXPanel)
2.нетбук  Samsung N145 (Debian+openBox+LXPanel, ddr01)

Оффлайн DdShurick

  • Это Риччи
  • Активный участник
  • Ветеран
  • ****
  • Сообщений: 8635
  • Репутация: +187/-2
  • Автор темы
  • Старый чайник
Построитель меню JWM
« Ответ #13 : 05 Февраль 2016, 15:05:11 »
не возникнет ли проблем если длинна найденных строк превысит 64 ?
Обрежет строку, но серьёзных проблем не будет, длинные строки могут быть label= и icon=, в exec - нет.
Моноблок Lenovo IdeaCentre c200 (Intel Atom D525, Intel GMA 3150, 2 Gb RAM) Richy64
Nettop Acer Aspire Revo R3610 (Atom N330, nVidia GeForce 9400, 3 Gb RAM) Richy64

Оффлайн DdShurick

  • Это Риччи
  • Активный участник
  • Ветеран
  • ****
  • Сообщений: 8635
  • Репутация: +187/-2
  • Автор темы
  • Старый чайник
Построитель меню JWM
« Ответ #14 : 06 Февраль 2016, 09:58:01 »
 Возникли проблемы. Например, при обработке файла Alsamixer-sound-mixer.desktop
Код
[Desktop Entry]
Encoding=UTF-8
Type=Application
Name=AlsaMixer -  аудио-микшер
Exec=xterm -e alsamixer

Icon=mini-sound.xpm
Categories=AudioVideo;

#MimeType=
Terminal=false
#GenericName=
#Comment=
#NoDisplay=
#Hidden=
#OnlyShowIn=
#NotShowIn=
#TryExec=
#Path=
#StartupNotify=true
#StartupWMClass=
В нём есть закомментированные строки с непрописанными параметрами в которых встречаются "Exec" и "Name". Программа запоминает последнее, пустое, значение. В результате получаем
Код
<JWM>
<Program label="" icon="mini-sound.xpm"></Program>
</JWM>
Если в цикл добавить строку
Код
while (fgets(str,sizeof(str),fp)!=0) {
if (str[1]=='#') continue;
она вырежет все закомментированные строки, но проблема "последнего значения" остаётся. Например GenericName, Name, Name[ru], Name[de] получим последнее, немецкое название, а надо Name[ru], которое никак не вставляется в код.
Моноблок Lenovo IdeaCentre c200 (Intel Atom D525, Intel GMA 3150, 2 Gb RAM) Richy64
Nettop Acer Aspire Revo R3610 (Atom N330, nVidia GeForce 9400, 3 Gb RAM) Richy64