Settings.c 18.2 KB
Newer Older
Hisham Muhammad's avatar
Hisham Muhammad committed
1
2
/*
htop - Settings.c
Hisham Muhammad's avatar
Hisham Muhammad committed
3
(C) 2004-2011 Hisham H. Muhammad
Hisham Muhammad's avatar
Hisham Muhammad committed
4
5
6
7
8
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/

#include "Settings.h"
9
#include "Platform.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
10

David Hunt's avatar
David Hunt committed
11
#include "StringUtils.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
12
#include "Vector.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
13
#include "CRT.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
14

Hisham Muhammad's avatar
Hisham Muhammad committed
15
16
17
18
19
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

Hisham Muhammad's avatar
Hisham Muhammad committed
20
21
22
#define DEFAULT_DELAY 15

/*{
Hisham Muhammad's avatar
Hisham Muhammad committed
23
#include "Process.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
24
#include <stdbool.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
25

26
27
28
29
30
31
typedef struct {
   const char* name;
   const char* columns;
   const char* sortKey;
} ScreenDefaults;

Hisham Muhammad's avatar
Hisham Muhammad committed
32
33
34
35
36
typedef struct {
   int len;
   char** names;
   int* modes;
} MeterColumnSettings;
37

38
39
40
41
42
43
44
45
46
typedef struct {
   char* name;
   ProcessField* fields;
   int flags;
   int direction;
   ProcessField sortKey;
   bool treeView;
} ScreenSettings;

Hisham Muhammad's avatar
Hisham Muhammad committed
47
typedef struct Settings_ {
Hisham Muhammad's avatar
Hisham Muhammad committed
48
49
   char* filename;
   
50
   MeterColumnSettings meterColumns[2];
Hisham Muhammad's avatar
Hisham Muhammad committed
51

52
53
54
55
   ScreenSettings** screens;
   unsigned int nScreens;
   unsigned int ssIndex;
   ScreenSettings* ss;
56

Hisham Muhammad's avatar
Hisham Muhammad committed
57
58
   int colorScheme;
   int delay;
Hisham Muhammad's avatar
Hisham Muhammad committed
59

60
   int cpuCount;
Hisham Muhammad's avatar
Hisham Muhammad committed
61
62
63

   bool countCPUsFromZero;
   bool detailedCPUTime;
64
   bool showProgramPath;
Hisham Muhammad's avatar
Hisham Muhammad committed
65
66
67
68
69
70
71
72
73
74
75
   bool hideThreads;
   bool shadowOtherUsers;
   bool showThreadNames;
   bool hideKernelThreads;
   bool hideUserlandThreads;
   bool highlightBaseName;
   bool highlightMegabytes;
   bool highlightThreads;
   bool updateProcessNames;
   bool accountGuestInCPUMeter;
   bool headerMargin;
Hisham Muhammad's avatar
Hisham Muhammad committed
76
   bool screenTabs;
Hisham Muhammad's avatar
Hisham Muhammad committed
77

Hisham Muhammad's avatar
Hisham Muhammad committed
78
   bool changed;
Hisham Muhammad's avatar
Hisham Muhammad committed
79
80
} Settings;

Hisham Muhammad's avatar
Hisham Muhammad committed
81
82
83
84
#ifndef Settings_cpuId
#define Settings_cpuId(settings, cpu) ((settings)->countCPUsFromZero ? (cpu) : (cpu)+1)
#endif

Hisham Muhammad's avatar
Hisham Muhammad committed
85
86
}*/

87
88
89
90
91
92
93
94
95
static void writeList(FILE* fd, char** list, int len) {
   const char* sep = "";
   for (int i = 0; i < len; i++) {
      fprintf(fd, "%s%s", sep, list[i]);
      sep = " ";
   }
   fprintf(fd, "\n");
}

96
97
98
99
/*

static char** readQuotedList(char* line) {
   int n = 0;
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
   char** list = xCalloc(sizeof(char*), 1);
   int start = 0;
   for (;;) {
      while (line[start] && line[start] == ' ') {
         start++;
      }
      if (line[start] != '"') {
         break;
      }
      start++;
      int close = start;
      while (line[close] && line[close] != '"') {
         close++;
      }
      int len = close - start;
      char* item = xMalloc(len + 1);
      strncpy(item, line + start, len);
      item[len] = '\0';
118
119
120
      list[n] = item;
      n++;
      list = xRealloc(list, sizeof(char*) * (n + 1));
121
122
      start = close + 1;
   }
123
   list[n] = NULL;
124
125
126
   return list;
}

127
static void writeQuotedList(FILE* fd, char** list) {
128
   const char* sep = "";
129
   for (int i = 0; list[i]; i++) {
130
131
132
133
134
135
      fprintf(fd, "%s\"%s\"", sep, list[i]);
      sep = " ";
   }
   fprintf(fd, "\n");
}

136
137
*/

Hisham Muhammad's avatar
Hisham Muhammad committed
138
void Settings_delete(Settings* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
139
   free(this->filename);
140
141
142
143
144
145
146
147
148
149
   for (unsigned int i = 0; i < (sizeof(this->meterColumns)/sizeof(MeterColumnSettings)); i++) {
      String_freeArray(this->meterColumns[i].names);
      free(this->meterColumns[i].modes);
   }
   if (this->screens) {
      for (unsigned int i = 0; this->screens[i]; i++) {
         free(this->screens[i]->name);
         free(this->screens[i]->fields);
      }
      free(this->screens);
Hisham Muhammad's avatar
Hisham Muhammad committed
150
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
151
152
153
   free(this);
}

154
static void Settings_readMeters(Settings* this, char* line, int side) {
Hisham Muhammad's avatar
Hisham Muhammad committed
155
   char* trim = String_trim(line);
156
157
   int nIds;
   char** ids = String_split(trim, ' ', &nIds);
Hisham Muhammad's avatar
Hisham Muhammad committed
158
   free(trim);
159
   this->meterColumns[side].names = ids;
Hisham Muhammad's avatar
Hisham Muhammad committed
160
161
}

162
static void Settings_readMeterModes(Settings* this, char* line, int side) {
Hisham Muhammad's avatar
Hisham Muhammad committed
163
   char* trim = String_trim(line);
164
165
   int nIds;
   char** ids = String_split(trim, ' ', &nIds);
Hisham Muhammad's avatar
Hisham Muhammad committed
166
   free(trim);
Hisham Muhammad's avatar
Hisham Muhammad committed
167
   int len = 0;
168
   for (int i = 0; ids[i]; i++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
169
170
      len++;
   }
171
   this->meterColumns[side].len = len;
Hisham's avatar
Hisham committed
172
   int* modes = xCalloc(len, sizeof(int));
Hisham Muhammad's avatar
Hisham Muhammad committed
173
174
   for (int i = 0; i < len; i++) {
      modes[i] = atoi(ids[i]);
Hisham Muhammad's avatar
Hisham Muhammad committed
175
176
   }
   String_freeArray(ids);
177
   this->meterColumns[side].modes = modes;
Hisham Muhammad's avatar
Hisham Muhammad committed
178
179
}

180
static void Settings_defaultMeters(Settings* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
181
   int sizes[] = { 3, 3 };
182
   if (this->cpuCount > 4) {
Hisham Muhammad's avatar
Hisham Muhammad committed
183
184
185
      sizes[1]++;
   }
   for (int i = 0; i < 2; i++) {
186
187
188
      this->meterColumns[i].names = xCalloc(sizes[i] + 1, sizeof(char*));
      this->meterColumns[i].modes = xCalloc(sizes[i], sizeof(int));
      this->meterColumns[i].len = sizes[i];
Hisham Muhammad's avatar
Hisham Muhammad committed
189
190
191
   }
   
   int r = 0;
192
   if (this->cpuCount > 8) {
193
194
195
196
      this->meterColumns[0].names[0] = xStrdup("LeftCPUs2");
      this->meterColumns[0].modes[0] = BAR_METERMODE;
      this->meterColumns[1].names[r] = xStrdup("RightCPUs2");
      this->meterColumns[1].modes[r++] = BAR_METERMODE;
197
   } else if (this->cpuCount > 4) {
198
199
200
201
      this->meterColumns[0].names[0] = xStrdup("LeftCPUs");
      this->meterColumns[0].modes[0] = BAR_METERMODE;
      this->meterColumns[1].names[r] = xStrdup("RightCPUs");
      this->meterColumns[1].modes[r++] = BAR_METERMODE;
202
   } else {
203
204
      this->meterColumns[0].names[0] = xStrdup("AllCPUs");
      this->meterColumns[0].modes[0] = BAR_METERMODE;
Hisham Muhammad's avatar
Hisham Muhammad committed
205
   }
206
207
208
209
   this->meterColumns[0].names[1] = xStrdup("Memory");
   this->meterColumns[0].modes[1] = BAR_METERMODE;
   this->meterColumns[0].names[2] = xStrdup("Swap");
   this->meterColumns[0].modes[2] = BAR_METERMODE;
Hisham Muhammad's avatar
Hisham Muhammad committed
210
   
211
212
213
214
215
216
   this->meterColumns[1].names[r] = xStrdup("Tasks");
   this->meterColumns[1].modes[r++] = TEXT_METERMODE;
   this->meterColumns[1].names[r] = xStrdup("LoadAverage");
   this->meterColumns[1].modes[r++] = TEXT_METERMODE;
   this->meterColumns[1].names[r] = xStrdup("Uptime");
   this->meterColumns[1].modes[r++] = TEXT_METERMODE;
Hisham Muhammad's avatar
Hisham Muhammad committed
217
218
}

Hisham Muhammad's avatar
Hisham Muhammad committed
219
static const char* toFieldName(int i) {
220
221
222
   if (i < 0 || i > LAST_PROCESSFIELD) {
      return "";
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
223
224
225
   return Process_fields[i].name;
}

226
227
228
229
static int toFieldIndex(const char* str) {
   if (isdigit(str[0])) {
      // This "+1" is for compatibility with the older enum format.
      int id = atoi(str) + 1;
Hisham Muhammad's avatar
Hisham Muhammad committed
230
      if (id < Platform_numberOfFields && toFieldName(id)) {
231
232
233
234
         return id;
      }
   } else {
      for (int p = 1; p < LAST_PROCESSFIELD; p++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
235
236
         const char* pName = toFieldName(p);
         if (pName && strcmp(pName, str) == 0) {
237
238
239
240
241
            return p;
         }
      }
   }
   return -1;
242
243
}

Hisham Muhammad's avatar
Hisham Muhammad committed
244
245
246
247
248
249
250
static void readFields(ProcessField* fields, int* flags, const char* line) {
   char* trim = String_trim(line);
   int nIds;
   char** ids = String_split(trim, ' ', &nIds);
   free(trim);
   int i, j;
   *flags = 0;
251
   for (j = 0, i = 0; i < Platform_numberOfFields && ids[i]; i++) {
252
253
254
255
      int idx = toFieldIndex(ids[i]);
      if (idx != -1) {
         fields[j] = idx;
         *flags |= Process_fields[idx].flags;
Hisham Muhammad's avatar
Hisham Muhammad committed
256
257
         j++;
      }
258
   }
Hisham's avatar
Hisham committed
259
   fields[j] = NULL_PROCESSFIELD;
Hisham Muhammad's avatar
Hisham Muhammad committed
260
   String_freeArray(ids);
261
262
}

263
ScreenSettings* Settings_newScreen(Settings* this, const char* name, const char* line) {
264
265
266
267
268
269
270
   ScreenSettings* ss = xCalloc(sizeof(ScreenSettings), 1);
   ss->name = xStrdup(name);
   ss->fields = xCalloc(Platform_numberOfFields+1, sizeof(ProcessField));
   ss->flags = 0;
   ss->direction = 1;
   ss->treeView = 0;
   readFields(ss->fields, &(ss->flags), line);
Hisham Muhammad's avatar
Hisham Muhammad committed
271
   ss->sortKey = ss->fields[0];
272
273
274
275
   this->screens[this->nScreens] = ss;
   this->nScreens++;
   this->screens = xRealloc(this->screens, sizeof(ScreenSettings*) * (this->nScreens + 1));
   this->screens[this->nScreens] = NULL;
276
   return ss;
277
278
279
}

static void Settings_defaultScreens(Settings* this) {
280
281
282
   for (unsigned int i = 0; i < Platform_numberOfDefaultScreens; i++) {
      ScreenDefaults* defaults = &Platform_defaultScreens[i];
      Settings_newScreen(this, defaults->name, defaults->columns);
283
      this->screens[i]->sortKey = toFieldIndex(defaults->sortKey);
284
   }
285
286
}

287
static bool Settings_read(Settings* this, const char* fileName) {
288
   FILE* fd;
289
290
   
   CRT_dropPrivileges();
291
   fd = fopen(fileName, "r");
292
   CRT_restorePrivileges();
293
   if (!fd)
Hisham Muhammad's avatar
Hisham Muhammad committed
294
      return false;
295
   
296
297
   bool didReadMeters = false;
   bool didReadFields = false;
298
299
300
   ProcessField* legacyFields = xCalloc(Platform_numberOfFields+1, sizeof(ProcessField));
   int legacyFlags;
   bool legacyFieldsRead = false;
301
302
303
304
305
   for (;;) {
      char* line = String_readLine(fd);
      if (!line) {
         break;
      }
306
      int nOptions;
307
308
      char** option = String_split(line, '=', &nOptions);
      free (line);
309
310
311
312
      if (nOptions < 2) {
         String_freeArray(option);
         continue;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
313
      if (String_eq(option[0], "fields")) {
314
315
         readFields(legacyFields, &legacyFlags, option[1]);
         legacyFieldsRead = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
316
      } else if (String_eq(option[0], "hide_threads")) {
Hisham Muhammad's avatar
Hisham Muhammad committed
317
         this->hideThreads = atoi(option[1]);
Hisham Muhammad's avatar
Hisham Muhammad committed
318
      } else if (String_eq(option[0], "hide_kernel_threads")) {
Hisham Muhammad's avatar
Hisham Muhammad committed
319
         this->hideKernelThreads = atoi(option[1]);
Hisham Muhammad's avatar
Hisham Muhammad committed
320
      } else if (String_eq(option[0], "hide_userland_threads")) {
Hisham Muhammad's avatar
Hisham Muhammad committed
321
         this->hideUserlandThreads = atoi(option[1]);
Hisham Muhammad's avatar
Hisham Muhammad committed
322
      } else if (String_eq(option[0], "shadow_other_users")) {
Hisham Muhammad's avatar
Hisham Muhammad committed
323
         this->shadowOtherUsers = atoi(option[1]);
Hisham Muhammad's avatar
Hisham Muhammad committed
324
      } else if (String_eq(option[0], "show_thread_names")) {
Hisham Muhammad's avatar
Hisham Muhammad committed
325
         this->showThreadNames = atoi(option[1]);
326
327
      } else if (String_eq(option[0], "show_program_path")) {
         this->showProgramPath = atoi(option[1]);
Hisham Muhammad's avatar
Hisham Muhammad committed
328
      } else if (String_eq(option[0], "highlight_base_name")) {
Hisham Muhammad's avatar
Hisham Muhammad committed
329
         this->highlightBaseName = atoi(option[1]);
Hisham Muhammad's avatar
Hisham Muhammad committed
330
      } else if (String_eq(option[0], "highlight_megabytes")) {
Hisham Muhammad's avatar
Hisham Muhammad committed
331
         this->highlightMegabytes = atoi(option[1]);
332
      } else if (String_eq(option[0], "highlight_threads")) {
Hisham Muhammad's avatar
Hisham Muhammad committed
333
         this->highlightThreads = atoi(option[1]);
Hisham Muhammad's avatar
Hisham Muhammad committed
334
      } else if (String_eq(option[0], "header_margin")) {
Hisham Muhammad's avatar
Hisham Muhammad committed
335
         this->headerMargin = atoi(option[1]);
Hisham Muhammad's avatar
Hisham Muhammad committed
336
337
      } else if (String_eq(option[0], "screen_tabs")) {
         this->screenTabs = atoi(option[1]);
338
      } else if (String_eq(option[0], "expand_system_time")) {
339
         // Compatibility option.
Hisham Muhammad's avatar
Hisham Muhammad committed
340
         this->detailedCPUTime = atoi(option[1]);
341
      } else if (String_eq(option[0], "detailed_cpu_time")) {
Hisham Muhammad's avatar
Hisham Muhammad committed
342
         this->detailedCPUTime = atoi(option[1]);
343
      } else if (String_eq(option[0], "cpu_count_from_zero")) {
Hisham Muhammad's avatar
Hisham Muhammad committed
344
         this->countCPUsFromZero = atoi(option[1]);
345
      } else if (String_eq(option[0], "update_process_names")) {
Hisham Muhammad's avatar
Hisham Muhammad committed
346
         this->updateProcessNames = atoi(option[1]);
347
      } else if (String_eq(option[0], "account_guest_in_cpu_meter")) {
Hisham Muhammad's avatar
Hisham Muhammad committed
348
         this->accountGuestInCPUMeter = atoi(option[1]);
Hisham Muhammad's avatar
Hisham Muhammad committed
349
350
351
352
      } else if (String_eq(option[0], "delay")) {
         this->delay = atoi(option[1]);
      } else if (String_eq(option[0], "color_scheme")) {
         this->colorScheme = atoi(option[1]);
353
         if (this->colorScheme < 0 || this->colorScheme >= LAST_COLORSCHEME) this->colorScheme = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
354
      } else if (String_eq(option[0], "left_meters")) {
Hisham Muhammad's avatar
Hisham Muhammad committed
355
         Settings_readMeters(this, option[1], 0);
356
         didReadMeters = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
357
      } else if (String_eq(option[0], "right_meters")) {
Hisham Muhammad's avatar
Hisham Muhammad committed
358
         Settings_readMeters(this, option[1], 1);
359
         didReadMeters = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
360
      } else if (String_eq(option[0], "left_meter_modes")) {
Hisham Muhammad's avatar
Hisham Muhammad committed
361
         Settings_readMeterModes(this, option[1], 0);
362
         didReadMeters = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
363
      } else if (String_eq(option[0], "right_meter_modes")) {
Hisham Muhammad's avatar
Hisham Muhammad committed
364
         Settings_readMeterModes(this, option[1], 1);
365
         didReadMeters = true;
366
      } else if (strncmp(option[0], "screen:", 7) == 0) {
367
         Settings_newScreen(this, option[0] + 7, option[1]);
368
         didReadFields = true;
369
370
371
372
373
374
375
376
377
378
379
380
      } else if (String_eq(option[0], ".tree_view")) {
         if (this->nScreens > 0) {
            this->screens[this->nScreens - 1]->treeView = atoi(option[1]);
         }
      } else if (String_eq(option[0], ".sort_direction")) {
         if (this->nScreens > 0) {
            this->screens[this->nScreens - 1]->direction = atoi(option[1]);
         }
      } else if (String_eq(option[0], ".sort_key")) {
         if (this->nScreens > 0) {
            this->screens[this->nScreens - 1]->sortKey = toFieldIndex(option[1]);
         }
Hisham Muhammad's avatar
Hisham Muhammad committed
381
382
383
384
      }
      String_freeArray(option);
   }
   fclose(fd);
385
   if (this->nScreens == 0) {
386
      Settings_defaultScreens(this);
387
      if (legacyFieldsRead) {
388
         didReadFields = true;
389
390
391
392
         free(this->screens[0]->fields);
         this->screens[0]->fields = legacyFields;
         this->screens[0]->flags = legacyFlags;
      }
393
   }
394
   if (!didReadMeters) {
395
      Settings_defaultMeters(this);
Hisham Muhammad's avatar
Hisham Muhammad committed
396
   }
397
   return didReadFields;
Hisham Muhammad's avatar
Hisham Muhammad committed
398
399
}

400
static void writeFields(FILE* fd, ProcessField* fields, bool byName) {
401
   const char* sep = "";
Hisham Muhammad's avatar
Hisham Muhammad committed
402
   for (int i = 0; fields[i]; i++) {
403
      if (byName) {
Hisham Muhammad's avatar
Hisham Muhammad committed
404
         fprintf(fd, "%s%s", sep, toFieldName(fields[i]));
405
406
407
408
      } else {
         // This " - 1" is for compatibility with the older enum format.
         fprintf(fd, "%s%d", sep, (int) fields[i] - 1);
      }
409
      sep = " ";
Hisham Muhammad's avatar
Hisham Muhammad committed
410
411
412
413
   }
   fprintf(fd, "\n");
}

414
415
static void writeMeters(Settings* this, FILE* fd, int side) {
   writeList(fd, this->meterColumns[side].names, this->meterColumns[side].len);
Hisham Muhammad's avatar
Hisham Muhammad committed
416
417
}

418
static void writeMeterModes(Settings* this, FILE* fd, int side) {
419
   const char* sep = "";
420
421
   for (int i = 0; i < this->meterColumns[side].len; i++) {
      fprintf(fd, "%s%d", sep, this->meterColumns[side].modes[i]);
422
      sep = " ";
Hisham Muhammad's avatar
Hisham Muhammad committed
423
424
425
426
   }
   fprintf(fd, "\n");
}

Hisham Muhammad's avatar
Hisham Muhammad committed
427
428
bool Settings_write(Settings* this) {
   FILE* fd;
429

430
   CRT_dropPrivileges();
Hisham Muhammad's avatar
Hisham Muhammad committed
431
   fd = fopen(this->filename, "w");
432
433
   CRT_restorePrivileges();

Hisham Muhammad's avatar
Hisham Muhammad committed
434
435
436
   if (fd == NULL) {
      return false;
   }
437
   fprintf(fd, "# Beware! This file is rewritten by htop when settings are changed in the interface.\n");
Hisham Muhammad's avatar
Hisham Muhammad committed
438
   fprintf(fd, "# The parser is also very primitive, and not human-friendly.\n");
439
   fprintf(fd, "fields="); writeFields(fd, this->screens[0]->fields, false);
Hisham Muhammad's avatar
Hisham Muhammad committed
440
441
442
443
444
   fprintf(fd, "hide_threads=%d\n", (int) this->hideThreads);
   fprintf(fd, "hide_kernel_threads=%d\n", (int) this->hideKernelThreads);
   fprintf(fd, "hide_userland_threads=%d\n", (int) this->hideUserlandThreads);
   fprintf(fd, "shadow_other_users=%d\n", (int) this->shadowOtherUsers);
   fprintf(fd, "show_thread_names=%d\n", (int) this->showThreadNames);
445
   fprintf(fd, "show_program_path=%d\n", (int) this->showProgramPath);
Hisham Muhammad's avatar
Hisham Muhammad committed
446
447
448
449
   fprintf(fd, "highlight_base_name=%d\n", (int) this->highlightBaseName);
   fprintf(fd, "highlight_megabytes=%d\n", (int) this->highlightMegabytes);
   fprintf(fd, "highlight_threads=%d\n", (int) this->highlightThreads);
   fprintf(fd, "header_margin=%d\n", (int) this->headerMargin);
Hisham Muhammad's avatar
Hisham Muhammad committed
450
   fprintf(fd, "screen_tabs=%d\n", (int) this->screenTabs);
Hisham Muhammad's avatar
Hisham Muhammad committed
451
452
453
454
   fprintf(fd, "detailed_cpu_time=%d\n", (int) this->detailedCPUTime);
   fprintf(fd, "cpu_count_from_zero=%d\n", (int) this->countCPUsFromZero);
   fprintf(fd, "update_process_names=%d\n", (int) this->updateProcessNames);
   fprintf(fd, "account_guest_in_cpu_meter=%d\n", (int) this->accountGuestInCPUMeter);
Hisham Muhammad's avatar
Hisham Muhammad committed
455
456
   fprintf(fd, "color_scheme=%d\n", (int) this->colorScheme);
   fprintf(fd, "delay=%d\n", (int) this->delay);
Hisham Muhammad's avatar
Hisham Muhammad committed
457
458
459
460
   fprintf(fd, "left_meters="); writeMeters(this, fd, 0);
   fprintf(fd, "left_meter_modes="); writeMeterModes(this, fd, 0);
   fprintf(fd, "right_meters="); writeMeters(this, fd, 1);
   fprintf(fd, "right_meter_modes="); writeMeterModes(this, fd, 1);
461
462
463
464
465
466
467

   // Legacy compatibility with older versions of htop
   fprintf(fd, "tree_view=%d\n", (int) this->screens[0]->treeView);
   // This "-1" is for compatibility with the older enum format.
   fprintf(fd, "sort_key=%d\n", (int) this->screens[0]->sortKey-1);
   fprintf(fd, "sort_direction=%d\n", (int) this->screens[0]->direction);

468
469
470
471
472
473
   if (this->screens && this->screens[0]) {
      for (unsigned int i = 0; i < this->nScreens; i++) {
         ScreenSettings* ss = this->screens[i];
         fprintf(fd, "screen:%s=", ss->name);
         writeFields(fd, ss->fields, true);
         fprintf(fd, ".tree_view=%d\n", (int) ss->treeView);
Hisham Muhammad's avatar
Hisham Muhammad committed
474
         fprintf(fd, ".sort_key=%s\n", toFieldName(ss->sortKey));
475
476
         fprintf(fd, ".sort_direction=%d\n", (int) ss->direction);
      }
477
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
478
479
480
   fclose(fd);
   return true;
}
481

Hisham Muhammad's avatar
Hisham Muhammad committed
482
483
Settings* Settings_new(int cpuCount) {
  
Hisham's avatar
Hisham committed
484
   Settings* this = xCalloc(1, sizeof(Settings));
Hisham Muhammad's avatar
Hisham Muhammad committed
485
486
487
488
489
490
491
492
493
494
495

   this->hideThreads = false;
   this->shadowOtherUsers = false;
   this->showThreadNames = false;
   this->hideKernelThreads = false;
   this->hideUserlandThreads = false;
   this->highlightBaseName = false;
   this->highlightMegabytes = false;
   this->detailedCPUTime = false;
   this->countCPUsFromZero = false;
   this->updateProcessNames = false;
496
   this->cpuCount = cpuCount;
497
   this->showProgramPath = true;
Hisham's avatar
Hisham committed
498
   this->highlightThreads = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
499
   
500
501
   this->screens = xCalloc(sizeof(ScreenSettings*), 1);
   this->nScreens = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
502

503
504
505
   char* legacyDotfile = NULL;
   char* rcfile = getenv("HTOPRC");
   if (rcfile) {
Hisham's avatar
Hisham committed
506
      this->filename = xStrdup(rcfile);
507
508
509
510
511
512
513
   } else {
      const char* home = getenv("HOME");
      if (!home) home = "";
      const char* xdgConfigHome = getenv("XDG_CONFIG_HOME");
      char* configDir = NULL;
      char* htopDir = NULL;
      if (xdgConfigHome) {
Hisham Muhammad's avatar
Hisham Muhammad committed
514
         this->filename = String_cat(xdgConfigHome, "/htop/htoprc");
Hisham's avatar
Hisham committed
515
         configDir = xStrdup(xdgConfigHome);
516
517
         htopDir = String_cat(xdgConfigHome, "/htop");
      } else {
Hisham Muhammad's avatar
Hisham Muhammad committed
518
         this->filename = String_cat(home, "/.config/htop/htoprc");
519
520
521
522
         configDir = String_cat(home, "/.config");
         htopDir = String_cat(home, "/.config/htop");
      }
      legacyDotfile = String_cat(home, "/.htoprc");
523
524
      
      CRT_dropPrivileges();
525
526
      (void) mkdir(configDir, 0700);
      (void) mkdir(htopDir, 0700);
527
528
      free(htopDir);
      free(configDir);
529
      struct stat st;
530
531
      int err = lstat(legacyDotfile, &st);
      if (err || S_ISLNK(st.st_mode)) {
532
533
534
         free(legacyDotfile);
         legacyDotfile = NULL;
      }
535
      CRT_restorePrivileges();
536
   }
537
538
539
   this->colorScheme = 0;
   this->changed = false;
   this->delay = DEFAULT_DELAY;
540
541
542
543
   bool ok = false;
   if (legacyDotfile) {
      ok = Settings_read(this, legacyDotfile);
      if (ok) {
544
545
546
547
         // Transition to new location and delete old configuration file
         if (Settings_write(this))
            unlink(legacyDotfile);
      }
548
549
550
551
552
553
      free(legacyDotfile);
   }
   if (!ok) {
      ok = Settings_read(this, this->filename);
   }
   if (!ok) {
554
555
556
      this->changed = true;
      // TODO: how to get SYSCONFDIR correctly through Autoconf?
      char* systemSettings = String_cat(SYSCONFDIR, "/htoprc");
557
      ok = Settings_read(this, systemSettings);
558
559
      free(systemSettings);
   }
560
561
   if (!ok) {
      Settings_defaultMeters(this);
562
      Settings_defaultScreens(this);
563
564
565
566
      this->hideKernelThreads = true;
      this->highlightMegabytes = true;
      this->highlightThreads = true;
      this->headerMargin = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
567
      this->screenTabs = true;
568
   }
569
570
571
572

   this->ssIndex = 0;
   this->ss = this->screens[this->ssIndex];

573
574
   return this;
}
Hisham Muhammad's avatar
Hisham Muhammad committed
575

576
void ScreenSettings_invertSortOrder(ScreenSettings* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
577
578
579
580
581
   if (this->direction == 1)
      this->direction = -1;
   else
      this->direction = 1;
}