cookutils view fix-desktop-file @ rev 769

Add fix-desktop-file: check and fix errors, warnings and apply hints in .desktop files
author Aleksej Bobylev <al.bobylev@gmail.com>
date Sat Nov 07 16:00:41 2015 +0200 (2015-11-07)
parents
children e177315d46eb
line source
1 #!/bin/sh
2 #
3 # Description:
4 # -----------
5 # There is a utility that allows you to check a lot of mistakes in the
6 # '.desktop' files: `desktop-file-validate`.
7 # This utility, `fix-desktop-file`, allows you to correct most errors
8 # automatically.
9 #
10 # Using:
11 # -----
12 # fix-desktop-file /path/to/desktop-file.desktop
13 # All the changes are made at the place with the replacement of the original
14 # file.
15 #
16 # License:
17 # -------
18 # `fix-desktop-file` is a part of Cookutils suite for SliTaz GNU/Linux
19 # and distributed under the same license as the Cookutils.
20 #
21 # Useful links:
22 # ------------
23 # * <http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.1.html>
24 # * <http://standards.freedesktop.org/menu-spec/menu-spec-1.0.html>
25 #
26 # Author:
27 # ------
28 # Aleksej Bobylev <al.bobylev@gmail.com>, November 2015.
31 desktop="$1"
33 busybox awk '
34 BEGIN {
35 FS = "=";
36 in_section = 0;
37 Name = "";
38 Comment = "";
39 Icon = "";
40 }
42 function handle_cats(x, y, yy) {
43 split(y, yy, ";");
44 for(i in yy) {
45 if (cats[x] && ! cats[yy[i]]) {
46 printf "%s;", yy[i];
47 cats[yy[i]] = "printed";
48 }
49 }
50 }
52 in_section == 1 {
53 # remove Version and deprecated keys
54 if ($0 ~ /^(Version|Protocols|Extensions|BinaryPattern|MapNotify|Patterns|DefaultApp|MiniIcon|TerminalOptions|Encoding|SwallowTitle|SwallowExec|SortOrder|FilePattern|MultipleArgs)[[:space:]]*=/)
55 next;
57 # process Icon
58 if ($0 ~ /^Icon[[:space:]]*=/) {
59 if (Icon) next; # Icon already printed
60 Icon = gensub(/^[^=]+=[[:space:]]*/, "", "");
61 # remove icon extension for non-absolute path
62 if ($0 ~ /^Icon[[:space:]]*=[^\/]*$/)
63 sub(/\.(png|xpm|svg)$/, "");
64 }
66 # fix boolean values
67 if ($0 ~ /^(NoDisplay|Hidden|DBusActivatable|Terminal|StartupNotify)[[:space:]]*=/) {
68 sub(/0/, "false"); sub(/False/, "false");
69 sub(/1/, "true"); sub(/True/, "true");
70 }
72 # process Name
73 if ($0 ~ /^Name[[:space:]]*=/) {
74 if (Name) next; # Name already printed
75 Name = gensub(/^[^=]+=[[:space:]]*/, "", "");
76 print;
77 for (i in name) {
78 if (name[i] &&
79 name[i] != Name) { # skip redundant
80 printf "Name[%s]=%s\n", i, name[i];
81 }
82 }
83 next;
84 }
86 # process localized Names
87 if ($0 ~ /^Name\[[^\]+\][[:space:]]*=/) {
88 locale = gensub(/^[^\[]*\[([^\]+)\].*$/, "\\1", "");
89 value = gensub(/^[^=]*=[[:space:]]*(.*)$/, "\\1", "");
90 if (name[locale]) next; # Name[locale] already printed
91 name[locale] = value;
92 if (Name &&
93 Name != value) { # skip redundant
94 name[locale] = value;
95 print;
96 }
97 if (comment[locale] && # print pending Comment[xx]
98 tolower(comment[locale]) != tolower(name[locale]))
99 printf "Comment[%s]=%s\n", locale, comment[locale];
100 next;
101 }
103 # process Comment
104 if ($0 ~ /^Comment[[:space:]]*=/) {
105 if (Comment) next; # Comment already printed
106 Comment = gensub(/^[^=]+=[[:space:]]*/, "", "");
107 if (Comment == Name) {
108 printf "%s (*)\n", $0; # Forgive redundant Comment: Comment[xx] required it
109 } else {
110 print;
111 }
112 for (i in comment) {
113 if (comment[i] &&
114 tolower(comment[i]) != tolower(Comment) &&
115 tolower(comment[i]) != tolower(name[i])) { # skip redundant
116 printf "Comment[%s]=%s\n", i, comment[i];
117 }
118 }
119 next;
120 }
122 # process localized Comments
123 if ($0 ~ /^Comment\[[^\]+\][[:space:]]*=/) {
124 locale = gensub(/^[^\[]*\[([^\]+)\].*$/, "\\1", "");
125 locomm = gensub(/^[^=]*=[[:space:]]*(.*)$/, "\\1", "");
126 if (comment[locale]) next; # Comment[locale] already printed
127 comment[locale] = locomm;
128 if (Comment && # pending until Comment appear
129 name[locale] && # pending until Name[xx] appear
130 tolower(locomm) != tolower(Comment) &&
131 tolower(locomm) != tolower(name[locale])) { # skip redundant
132 comment[locale] = locomm;
133 print;
134 }
135 next;
136 }
138 # process Categories list
139 if ($0 ~ /^Categories[[:space:]]*=/) {
140 value = gensub(/^[^=]*=[[:space:]]*(.*)$/, "\\1", "");
141 split(value, categories, ";");
142 printf "Categories=";
143 for (i in categories) {
144 # skip empty (;;), Application(s), and repeated categories
145 if (categories[i] &&
146 categories[i] != "Application" &&
147 categories[i] != "Applications" &&
148 ! cats[categories[i]]) {
149 if (categories[i] == "Terminal") categories[i] = "ConsoleOnly" # Mistake
150 if (categories[i] == "Multimedia") categories[i] = "AudioVideo" # Mistake
151 gsub(/ /, "", categories[i]);
152 printf "%s;", categories[i];
153 cats[categories[i]] = "printed";
154 }
155 }
156 # add main category if needed (http://standards.freedesktop.org/menu-spec/latest/apas02.html)
157 handle_cats("Audio", "AudioVideo");
158 handle_cats("Video", "AudioVideo");
159 handle_cats("Building", "Development");
160 handle_cats("Debugger", "Development");
161 handle_cats("IDE", "Development");
162 handle_cats("GUIDesigner", "Development");
163 handle_cats("Profiling", "Development");
164 handle_cats("RevisionControl", "Development");
165 handle_cats("Translation", "Development");
166 handle_cats("Calendar", "Office");
167 handle_cats("ContactManagement", "Office");
168 handle_cats("Chart", "Office");
169 handle_cats("Finance", "Office");
170 handle_cats("FlowChart", "Office");
171 handle_cats("PDA", "Office");
172 handle_cats("Presentation", "Office");
173 handle_cats("Spreadsheet", "Office");
174 handle_cats("WordProcessor", "Office");
175 handle_cats("2DGraphics", "Graphics");
176 handle_cats("VectorGraphics", "Graphics;2DGraphics");
177 handle_cats("RasterGraphics", "Graphics;2DGraphics");
178 handle_cats("3DGraphics", "Graphics");
179 handle_cats("Scanning", "Graphics");
180 handle_cats("OCR", "Graphics;Scanning");
181 handle_cats("TextTools", "Utility");
182 handle_cats("DesktopSettings", "Settings");
183 handle_cats("HardwareSettings", "Settings");
184 handle_cats("Printing", "HardwareSettings;Settings");
185 handle_cats("PackageManager", "Settings");
186 handle_cats("Dialup", "Network");
187 handle_cats("InstantMessaging", "Network");
188 handle_cats("Chat", "Network");
189 handle_cats("IRCClient", "Network");
190 handle_cats("Feed", "Network");
191 handle_cats("FileTransfer", "Network");
192 handle_cats("News", "Network");
193 handle_cats("P2P", "Network");
194 handle_cats("RemoteAccess", "Network");
195 handle_cats("Telephony", "Network");
196 handle_cats("TelephonyTools", "Utility");
197 handle_cats("VideoConference", "Network");
198 handle_cats("WebBrowser", "Network");
199 handle_cats("Midi", "AudioVideo;Audio");
200 handle_cats("Mixer", "AudioVideo;Audio");
201 handle_cats("Sequencer", "AudioVideo;Audio");
202 handle_cats("Tuner", "AudioVideo;Audio");
203 handle_cats("TV", "AudioVideo;Video");
204 handle_cats("DiscBurning", "AudioVideo");
205 handle_cats("ActionGame", "Game");
206 handle_cats("AdventureGame", "Game");
207 handle_cats("ArcadeGame", "Game");
208 handle_cats("BoardGame", "Game");
209 handle_cats("BlocksGame", "Game");
210 handle_cats("CardGame", "Game");
211 handle_cats("KidsGame", "Game");
212 handle_cats("LogicGame", "Game");
213 handle_cats("RolePlaying", "Game");
214 handle_cats("Shooter", "Game");
215 handle_cats("Simulation", "Game");
216 handle_cats("SportsGame", "Game");
217 handle_cats("StrategyGame", "Game");
218 handle_cats("Archiving", "Utility");
219 handle_cats("Compression", "Utility;Archiving");
220 handle_cats("FileManager", "System;FileTools");
221 handle_cats("TerminalEmulator", "System");
222 handle_cats("Filesystem", "System");
223 handle_cats("Calculator", "Utility");
224 handle_cats("Clock", "Utility");
225 handle_cats("TextEditor", "Utility");
226 handle_cats("KDE", "Qt");
227 handle_cats("GNOME", "GTK");
228 handle_cats("XFCE", "GTK");
230 printf "\n";
231 next;
232 }
234 # process MimeType list
235 if ($0 ~ /^MimeType[[:space:]]*=/) {
236 value = gensub(/^[^=]*=[[:space:]]*(.*)$/, "\\1", "");
237 value = gensub(/x-directory\/gnome-default-handler/, "inode/directory", "g", value);
238 value = gensub(/x-directory\/normal/, "inode/directory", "g", value);
239 gsub(/ /, "", value);
240 split(value, mimetype, ";");
241 printf "MimeType=";
242 for (i in mimetype) {
243 # skip empty (;;), and repeated mimetypes
244 if (mimetype[i] &&
245 ! mimes[mimetype[i]]) {
246 printf "%s;", mimetype[i];
247 mimes[mimetype[i]] = "printed";
248 }
249 }
250 printf "\n";
251 next;
252 }
254 # process Keywords
255 if ($0 ~ /^Keywords[[:space:]]*=/) {
256 value = gensub(/^[^=]*=[[:space:]]*(.*)$/, "\\1", "");
257 split(value, keywords, ";");
258 printf "Keywords=";
259 for (i in keywords) {
260 # skip empty (;;), and repeated keywords
261 if (keywords[i] &&
262 ! keys[keywords[i]]) {
263 printf "%s;", keywords[i];
264 keys[keywords[i]] = "printed";
265 }
266 }
267 printf "\n";
268 delete keys;
269 next;
270 }
272 # process localized Keywords
273 if ($0 ~ /^Keywords\[[^\]+\][[:space:]]*=/) {
274 locale = gensub(/^[^\[]*\[([^\]+)\].*$/, "\\1", "");
275 lokeys = gensub(/^[^=]*=[[:space:]]*(.*)$/, "\\1", "");
276 split(lokeys, keywords, ";");
277 printf "Keywords[%s]=", locale;
278 for (i in keywords) {
279 # skip empty (;;), and repeated keywords
280 if (keywords[i] &&
281 ! keys[keywords[i]]) {
282 printf "%s;", keywords[i];
283 keys[keywords[i]] = "printed";
284 }
285 }
286 printf "\n";
287 delete keys;
288 next;
289 }
291 }
293 /^\[/ {
294 in_section = 0;
295 }
296 /^\[Desktop Entry\]/ {
297 in_section = 1;
298 }
299 {
300 print;
301 }
302 ' "$desktop" > "$desktop.$$"
304 mv -f "$desktop.$$" "$desktop"