~ubuntu-branches/ubuntu/natty/geany/natty

« back to all changes in this revision

Viewing changes to src/utils.c

  • Committer: Bazaar Package Importer
  • Author(s): Chow Loong Jin
  • Date: 2010-08-07 03:23:12 UTC
  • mfrom: (1.4.3 upstream)
  • mto: This revision was merged to the branch mainline in revision 22.
  • Revision ID: james.westby@ubuntu.com-20100807032312-ot70ac9d50cn79we
Tags: upstream-0.19
ImportĀ upstreamĀ versionĀ 0.19

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 *      along with this program; if not, write to the Free Software
19
19
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
20
 *
21
 
 * $Id: utils.c 4630 2010-01-31 21:54:47Z eht16 $
 
21
 * $Id: utils.c 4884 2010-05-08 13:10:33Z eht16 $
22
22
 */
23
23
 
24
24
/*
139
139
                }
140
140
                else if (buffer[i] == 0x0d)
141
141
                {
142
 
                        if (i >= (size-1))
 
142
                        if (i >= (size - 1))
143
143
                        {
144
144
                                /* Last char, CR */
145
145
                                cr++;
146
146
                        }
147
147
                        else
148
148
                        {
149
 
                                if (buffer[i+1] != 0x0a)
 
149
                                if (buffer[i + 1] != 0x0a)
150
150
                                {
151
151
                                        /* CR */
152
152
                                        cr++;
214
214
 
215
215
 
216
216
/**
217
 
 *  Write the given @a text into a file with @a filename.
 
217
 *  Writes the given @a text into a file with @a filename.
218
218
 *  If the file doesn't exist, it will be created.
219
219
 *  If it already exists, it will be overwritten.
220
220
 *
221
221
 *  @param filename The filename of the file to write, in locale encoding.
222
222
 *  @param text The text to write into the file.
223
223
 *
224
 
 *  @return 0 if the directory was successfully created, otherwise the @c errno of the
 
224
 *  @return 0 if the file was successfully written, otherwise the @c errno of the
225
225
 *          failed operation is returned.
226
226
 **/
227
227
gint utils_write_file(const gchar *filename, const gchar *text)
292
292
        else
293
293
                cur = &sel[size - 1];
294
294
 
295
 
        cur--; /* Skip past the > */
296
 
        while (cur > begin)
297
 
        {
298
 
                if (*cur == '<') break;
299
 
                else if (! check_tag && *cur == '>') break;
 
295
        /* Skip to the character before the closing brace */
 
296
        while (cur > begin)
 
297
        {
 
298
                if (*cur == '>')
 
299
                        break;
 
300
                --cur;
 
301
        }
 
302
        --cur;
 
303
        /* skip whitespace */
 
304
        while (cur > begin && isspace(*cur))
 
305
                cur--;
 
306
        if (*cur == '/')
 
307
                return NULL; /* we found a short tag which doesn't need to be closed */
 
308
        while (cur > begin)
 
309
        {
 
310
                if (*cur == '<')
 
311
                        break;
 
312
                else if (! check_tag && *cur == '>')
 
313
                        break;
300
314
                --cur;
301
315
        }
302
316
 
508
522
 
509
523
 
510
524
/**
511
 
 *  Remove the extension from @a filename and return the result in a newly allocated string.
 
525
 *  Removes the extension from @a filename and return the result in a newly allocated string.
512
526
 *
513
527
 *  @param filename The filename to operate on.
514
528
 *
641
655
                        {
642
656
                                for (j = 1; (j < needle_length); j++)
643
657
                                {
644
 
                                        if (haystack[i+j] == needle[j])
 
658
                                        if (haystack[i + j] == needle[j])
645
659
                                        {
646
660
                                                if (pos == -1)
647
661
                                                        pos = i;
660
674
 
661
675
 
662
676
/**
663
 
 *  This is a convenience function to retrieve a formatted date/time string from strftime().
 
677
 *  Retrieves a formatted date/time string from strftime().
664
678
 *  This function should be preferred to directly calling strftime() since this function
665
679
 *  works on UTF-8 encoded strings.
666
680
 *
729
743
 
730
744
 
731
745
/**
732
 
 *  Convenience function for g_key_file_get_integer() to add a default value argument.
 
746
 *  Wraps g_key_file_get_integer() to add a default value argument.
733
747
 *
734
748
 *  @param config A GKeyFile object.
735
749
 *  @param section The group name to look in for the key.
760
774
 
761
775
 
762
776
/**
763
 
 *  Convenience function for g_key_file_get_boolean() to add a default value argument.
 
777
 *  Wraps g_key_file_get_boolean() to add a default value argument.
764
778
 *
765
779
 *  @param config A GKeyFile object.
766
780
 *  @param section The group name to look in for the key.
791
805
 
792
806
 
793
807
/**
794
 
 *  Convenience function for g_key_file_get_string() to add a default value argument.
 
808
 *  Wraps g_key_file_get_string() to add a default value argument.
795
809
 *
796
810
 *  @param config A GKeyFile object.
797
811
 *  @param section The group name to look in for the key.
806
820
                                                                const gchar *default_value)
807
821
{
808
822
        gchar *tmp;
809
 
        GError *error = NULL;
810
823
 
811
824
        if (G_UNLIKELY(config == NULL))
812
825
                return g_strdup(default_value);
813
826
 
814
 
        tmp = g_key_file_get_string(config, section, key, &error);
815
 
        if (G_UNLIKELY(error))
 
827
        tmp = g_key_file_get_string(config, section, key, NULL);
 
828
        if (G_UNLIKELY(!tmp))
816
829
        {
817
 
                g_error_free(error);
818
830
                return g_strdup(default_value);
819
831
        }
820
832
        return tmp;
913
925
                {
914
926
                        f = fmt_tenths;
915
927
                        ++u;
916
 
                        frac = ((((gint)(val % 1024)) * 10) + (1024/2)) / 1024;
 
928
                        frac = ((((gint)(val % 1024)) * 10) + (1024 / 2)) / 1024;
917
929
                        val /= 1024;
918
930
                }
919
931
                if (frac >= 10)
1047
1059
 
1048
1060
 
1049
1061
/* Contributed by Stefan Oltmanns, thanks.
1050
 
 * Replaces \\, \r, \n, \t and \uXXX by their real counterparts */
1051
 
gboolean utils_str_replace_escape(gchar *string)
 
1062
 * Replaces \\, \r, \n, \t and \uXXX by their real counterparts.
 
1063
 * keep_backslash is used for regex strings to leave '\\' and '\?' in place */
 
1064
gboolean utils_str_replace_escape(gchar *string, gboolean keep_backslash)
1052
1065
{
1053
1066
        gsize i, j, len;
1054
1067
        guint unicodechar;
1068
1081
                        switch (string[i])
1069
1082
                        {
1070
1083
                                case '\\':
 
1084
                                        if (keep_backslash)
 
1085
                                                string[j++] = '\\';
1071
1086
                                        string[j] = '\\';
1072
1087
                                        break;
1073
1088
                                case 'n':
1086
1101
                                        {
1087
1102
                                                return FALSE;
1088
1103
                                        }
1089
 
                                        if (isdigit(string[i-1])) string[j] = string[i-1]-48;
1090
 
                                        else if (isxdigit(string[i-1])) string[j] = tolower(string[i-1])-87;
 
1104
                                        if (isdigit(string[i - 1])) string[j] = string[i - 1] - 48;
 
1105
                                        else if (isxdigit(string[i - 1])) string[j] = tolower(string[i - 1])-87;
1091
1106
                                        else return FALSE;
1092
1107
                                        string[j] <<= 4;
1093
 
                                        if (isdigit(string[i])) string[j] |= string[i]-48;
 
1108
                                        if (isdigit(string[i])) string[j] |= string[i] - 48;
1094
1109
                                        else if (isxdigit(string[i])) string[j] |= tolower(string[i])-87;
1095
1110
                                        else return FALSE;
1096
1111
                                        break;
1097
1112
#endif
1098
1113
                                case 'u':
 
1114
                                {
1099
1115
                                        i += 2;
1100
1116
                                        if (i >= strlen(string))
1101
1117
                                        {
1102
1118
                                                return FALSE;
1103
1119
                                        }
1104
 
                                        if (isdigit(string[i-1])) unicodechar = string[i-1]-48;
1105
 
                                        else if (isxdigit(string[i-1])) unicodechar = tolower(string[i-1])-87;
 
1120
                                        if (isdigit(string[i - 1])) unicodechar = string[i - 1] - 48;
 
1121
                                        else if (isxdigit(string[i - 1])) unicodechar = tolower(string[i - 1])-87;
1106
1122
                                        else return FALSE;
1107
1123
                                        unicodechar <<= 4;
1108
 
                                        if (isdigit(string[i])) unicodechar |= string[i]-48;
 
1124
                                        if (isdigit(string[i])) unicodechar |= string[i] - 48;
1109
1125
                                        else if (isxdigit(string[i])) unicodechar |= tolower(string[i])-87;
1110
1126
                                        else return FALSE;
1111
 
                                        if (((i+2) < strlen(string)) && (isdigit(string[i+1]) || isxdigit(string[i+1]))
1112
 
                                                && (isdigit(string[i+2]) || isxdigit(string[i+2])))
1113
 
                                        {
1114
 
                                                i += 2;
1115
 
                                                unicodechar <<= 8;
1116
 
                                                if (isdigit(string[i-1])) unicodechar |= ((string[i-1]-48)<<4);
1117
 
                                                else unicodechar |= ((tolower(string[i-1])-87) << 4);
1118
 
                                                if (isdigit(string[i])) unicodechar |= string[i]-48;
1119
 
                                                else unicodechar |= tolower(string[i])-87;
1120
 
                                        }
1121
 
                                        if (((i+2) < strlen(string)) && (isdigit(string[i+1]) || isxdigit(string[i+1]))
1122
 
                                                && (isdigit(string[i+2]) || isxdigit(string[i+2])))
1123
 
                                        {
1124
 
                                                i += 2;
1125
 
                                                unicodechar <<= 8;
1126
 
                                                if (isdigit(string[i-1])) unicodechar |= ((string[i-1]-48) << 4);
1127
 
                                                else unicodechar |= ((tolower(string[i-1])-87) << 4);
1128
 
                                                if (isdigit(string[i])) unicodechar |= string[i]-48;
1129
 
                                                else unicodechar |= tolower(string[i])-87;
1130
 
                                        }
1131
 
                                        if(unicodechar < 0x80)
 
1127
                                        if (((i + 2) < strlen(string)) && (isdigit(string[i + 1]) || isxdigit(string[i + 1]))
 
1128
                                                && (isdigit(string[i + 2]) || isxdigit(string[i + 2])))
 
1129
                                        {
 
1130
                                                i += 2;
 
1131
                                                unicodechar <<= 8;
 
1132
                                                if (isdigit(string[i - 1])) unicodechar |= ((string[i - 1] - 48) << 4);
 
1133
                                                else unicodechar |= ((tolower(string[i - 1])-87) << 4);
 
1134
                                                if (isdigit(string[i])) unicodechar |= string[i] - 48;
 
1135
                                                else unicodechar |= tolower(string[i])-87;
 
1136
                                        }
 
1137
                                        if (((i + 2) < strlen(string)) && (isdigit(string[i + 1]) || isxdigit(string[i + 1]))
 
1138
                                                && (isdigit(string[i + 2]) || isxdigit(string[i + 2])))
 
1139
                                        {
 
1140
                                                i += 2;
 
1141
                                                unicodechar <<= 8;
 
1142
                                                if (isdigit(string[i - 1])) unicodechar |= ((string[i - 1] - 48) << 4);
 
1143
                                                else unicodechar |= ((tolower(string[i - 1])-87) << 4);
 
1144
                                                if (isdigit(string[i])) unicodechar |= string[i] - 48;
 
1145
                                                else unicodechar |= tolower(string[i])-87;
 
1146
                                        }
 
1147
                                        if (unicodechar < 0x80)
1132
1148
                                        {
1133
1149
                                                string[j] = unicodechar;
1134
1150
                                        }
1135
1151
                                        else if (unicodechar < 0x800)
1136
1152
                                        {
1137
 
                                                string[j] = (unsigned char) ((unicodechar >> 6)| 0xC0);
 
1153
                                                string[j] = (unsigned char) ((unicodechar >> 6) | 0xC0);
1138
1154
                                                j++;
1139
 
                                                string[j] = (unsigned char) ((unicodechar & 0x3F)| 0x80);
 
1155
                                                string[j] = (unsigned char) ((unicodechar & 0x3F) | 0x80);
1140
1156
                                        }
1141
1157
                                        else if (unicodechar < 0x10000)
1142
1158
                                        {
1161
1177
                                                return FALSE;
1162
1178
                                        }
1163
1179
                                        break;
 
1180
                                }
1164
1181
                                default:
1165
 
                                        return FALSE;
 
1182
                                        /* unnecessary escapes are allowed */
 
1183
                                        if (keep_backslash)
 
1184
                                                string[j++] = '\\';
 
1185
                                        string[j] = string[i];
1166
1186
                        }
1167
1187
                }
1168
1188
                else
1316
1336
 
1317
1337
 
1318
1338
/**
1319
 
 *  Create a directory if it doesn't already exist.
1320
 
 *  Create intermediate parent directories as needed, too.
 
1339
 *  Creates a directory if it doesn't already exist.
 
1340
 *  Creates intermediate parent directories as needed, too.
1321
1341
 *  The permissions of the created directory are set 0700.
1322
1342
 *
1323
1343
 *  @param path The path of the directory to create, in locale encoding.
1342
1362
 
1343
1363
 
1344
1364
/**
1345
 
 *  Gets a sorted list of files from the specified directory.
1346
 
 *  Locale encoding is expected for path and used for the file list. The list and the data
1347
 
 *  in the list should be freed after use.
1348
 
 *
1349
 
 *  @param path The path of the directory to scan, in locale encoding.
1350
 
 *  @param length The location to store the number of non-@c NULL data items in the list,
1351
 
 *                unless @c NULL.
1352
 
 *  @param error The is the location for storing a possible error, or @c NULL.
1353
 
 *
1354
 
 *  @return A newly allocated list or @c NULL if no files found. The list and its data should be
1355
 
 *          freed when no longer needed.
 
1365
 * Gets a list of files from the specified directory.
 
1366
 * Locale encoding is expected for @a path and used for the file list. The list and the data
 
1367
 * in the list should be freed after use, e.g.:
 
1368
 * @code
 
1369
 * g_slist_foreach(list, (GFunc) g_free, NULL);
 
1370
 * g_slist_free(list); @endcode
 
1371
 *
 
1372
 * @note If you don't need a list you should use the foreach_dir() macro instead -
 
1373
 * it's more efficient.
 
1374
 *
 
1375
 * @param path The path of the directory to scan, in locale encoding.
 
1376
 * @param full_path Whether to include the full path for each filename in the list. Obviously this
 
1377
 * will use more memory.
 
1378
 * @param sort Whether to sort alphabetically (UTF-8 safe).
 
1379
 * @param error The location for storing a possible error, or @c NULL.
 
1380
 *
 
1381
 * @return A newly allocated list or @c NULL if no files were found. The list and its data should be
 
1382
 * freed when no longer needed.
 
1383
 * @see utils_get_file_list().
1356
1384
 **/
1357
 
GSList *utils_get_file_list(const gchar *path, guint *length, GError **error)
 
1385
GSList *utils_get_file_list_full(const gchar *path, gboolean full_path, gboolean sort, GError **error)
1358
1386
{
1359
1387
        GSList *list = NULL;
1360
 
        guint len = 0;
1361
1388
        GDir *dir;
 
1389
        const gchar *filename;
1362
1390
 
1363
1391
        if (error)
1364
1392
                *error = NULL;
1365
 
        if (length)
1366
 
                *length = 0;
1367
1393
        g_return_val_if_fail(path != NULL, NULL);
1368
1394
 
1369
1395
        dir = g_dir_open(path, 0, error);
1370
1396
        if (dir == NULL)
1371
1397
                return NULL;
1372
1398
 
1373
 
        while (1)
 
1399
        foreach_dir(filename, dir)
1374
1400
        {
1375
 
                const gchar *filename = g_dir_read_name(dir);
1376
 
                if (filename == NULL)
1377
 
                        break;
1378
 
 
1379
 
                list = g_slist_append(list, g_strdup(filename));
1380
 
                len++;
 
1401
                list = g_slist_append(list, full_path ?
 
1402
                        g_build_path(G_DIR_SEPARATOR_S, path, filename, NULL) : g_strdup(filename));
1381
1403
        }
1382
1404
        g_dir_close(dir);
1383
1405
        /* sorting last is quicker than on insertion */
1384
 
        list = g_slist_sort(list, (GCompareFunc) utils_str_casecmp);
 
1406
        if (sort)
 
1407
                list = g_slist_sort(list, (GCompareFunc) utils_str_casecmp);
 
1408
        return list;
 
1409
}
 
1410
 
 
1411
 
 
1412
/**
 
1413
 * Gets a sorted list of files from the specified directory.
 
1414
 * Locale encoding is expected for @a path and used for the file list. The list and the data
 
1415
 * in the list should be freed after use, e.g.:
 
1416
 * @code
 
1417
 * g_slist_foreach(list, (GFunc) g_free, NULL);
 
1418
 * g_slist_free(list); @endcode
 
1419
 *
 
1420
 * @param path The path of the directory to scan, in locale encoding.
 
1421
 * @param length The location to store the number of non-@c NULL data items in the list,
 
1422
 *               unless @c NULL.
 
1423
 * @param error The location for storing a possible error, or @c NULL.
 
1424
 *
 
1425
 * @return A newly allocated list or @c NULL if no files were found. The list and its data should be
 
1426
 *         freed when no longer needed.
 
1427
 * @see utils_get_file_list_full().
 
1428
 **/
 
1429
GSList *utils_get_file_list(const gchar *path, guint *length, GError **error)
 
1430
{
 
1431
        GSList *list = utils_get_file_list_full(path, FALSE, TRUE, error);
1385
1432
 
1386
1433
        if (length)
1387
 
                *length = len;
 
1434
                *length = g_slist_length(list);
1388
1435
        return list;
1389
1436
}
1390
1437
 
1455
1502
 * @param needle The string which should be replaced.
1456
1503
 * @param replace The replacement for @a needle.
1457
1504
 *
1458
 
 * @return amount of replacements done
 
1505
 * @return Number of replacements made.
1459
1506
 **/
1460
1507
guint utils_string_replace_all(GString *haystack, const gchar *needle, const gchar *replace)
1461
1508
{
1464
1511
 
1465
1512
 
1466
1513
/**
1467
 
 * Convenience function to replace only the first occurrence of @a needle in @a haystack
 
1514
 * Replaces only the first occurrence of @a needle in @a haystack
1468
1515
 * with @a replace.
1469
1516
 * For details, see utils_string_replace_all().
1470
1517
 *
1472
1519
 * @param needle The string which should be replaced.
1473
1520
 * @param replace The replacement for @a needle.
1474
1521
 *
1475
 
 * @return amount of replacements done
 
1522
 * @return Number of replacements made.
1476
1523
 *
1477
1524
 *  @since 0.16
1478
1525
 */
1516
1563
 
1517
1564
 
1518
1565
/**
1519
 
 *  This is a wrapper function for g_spawn_sync() and internally calls this function on Unix-like
 
1566
 *  Wraps g_spawn_sync() and internally calls this function on Unix-like
1520
1567
 *  systems. On Win32 platforms, it uses the Windows API.
1521
1568
 *
1522
1569
 *  @param dir The child's current working directory, or @a NULL to inherit parent's.
1564
1611
 
1565
1612
 
1566
1613
/**
1567
 
 *  This is a wrapper function for g_spawn_async() and internally calls this function on Unix-like
 
1614
 *  Wraps g_spawn_async() and internally calls this function on Unix-like
1568
1615
 *  systems. On Win32 platforms, it uses the Windows API.
1569
1616
 *
1570
1617
 *  @param dir The child's current working directory, or @a NULL to inherit parent's.
1767
1814
}
1768
1815
 
1769
1816
 
1770
 
/* @warning Doesn't include null terminating character. */
1771
 
#define foreach_str(char_ptr, string) \
1772
 
        for (char_ptr = string; *char_ptr; char_ptr++)
1773
 
 
1774
1817
/**
1775
 
 *  Replace or remove characters from a string in place.
 
1818
 *  Removes characters from a string, in place.
1776
1819
 *
1777
1820
 *  @param string String to search.
1778
1821
 *  @param chars Characters to remove.
1801
1844
}
1802
1845
 
1803
1846
 
 
1847
static void utils_slist_remove_next(GSList *node)
 
1848
{
 
1849
        GSList *old = node->next;
 
1850
 
 
1851
        g_return_if_fail(old);
 
1852
 
 
1853
        node->next = old->next;
 
1854
        g_slist_free_1(old);
 
1855
}
 
1856
 
 
1857
 
 
1858
/* Gets list of sorted filenames with no path and no duplicates from user and system config */
 
1859
GSList *utils_get_config_files(const gchar *subdir)
 
1860
{
 
1861
        gchar *path = g_build_path(G_DIR_SEPARATOR_S, app->configdir, subdir, NULL);
 
1862
        GSList *list = utils_get_file_list_full(path, FALSE, FALSE, NULL);
 
1863
        GSList *syslist, *node;
 
1864
 
 
1865
        if (!list)
 
1866
        {
 
1867
                utils_mkdir(path, FALSE);
 
1868
        }
 
1869
        setptr(path, g_build_path(G_DIR_SEPARATOR_S, app->datadir, subdir, NULL));
 
1870
        syslist = utils_get_file_list_full(path, FALSE, FALSE, NULL);
 
1871
        /* merge lists */
 
1872
        list = g_slist_concat(list, syslist);
 
1873
 
 
1874
        list = g_slist_sort(list, (GCompareFunc) utils_str_casecmp);
 
1875
        /* remove duplicates (next to each other after sorting) */
 
1876
        foreach_slist(node, list)
 
1877
        {
 
1878
                if (node->next && utils_str_equal(node->next->data, node->data))
 
1879
                {
 
1880
                        g_free(node->next->data);
 
1881
                        utils_slist_remove_next(node);
 
1882
                }
 
1883
        }
 
1884
        g_free(path);
 
1885
        return list;
 
1886
}
 
1887
 
 
1888
 
 
1889
/* Suffix can be NULL or a string which should be appended to the Help URL like
 
1890
 * an anchor link, e.g. "#some_anchor". */
 
1891
gchar *utils_get_help_url(const gchar *suffix)
 
1892
{
 
1893
        gint skip;
 
1894
        gchar *uri;
 
1895
 
 
1896
#ifdef G_OS_WIN32
 
1897
        skip = 8;
 
1898
        uri = g_strconcat("file:///", app->docdir, "/Manual.html", NULL);
 
1899
        g_strdelimit(uri, "\\", '/'); /* replace '\\' by '/' */
 
1900
#else
 
1901
        skip = 7;
 
1902
        uri = g_strconcat("file://", app->docdir, "index.html", NULL);
 
1903
#endif
 
1904
 
 
1905
        if (! g_file_test(uri + skip, G_FILE_TEST_IS_REGULAR))
 
1906
        {       /* fall back to online documentation if it is not found on the hard disk */
 
1907
                g_free(uri);
 
1908
                uri = g_strconcat(GEANY_HOMEPAGE, "manual/", VERSION, "/index.html", NULL);
 
1909
        }
 
1910
 
 
1911
        if (suffix != NULL)
 
1912
        {
 
1913
                setptr(uri, g_strconcat(uri, suffix, NULL));
 
1914
        }
 
1915
 
 
1916
        return uri;
 
1917
}
 
1918
 
 
1919
 
 
1920
static gboolean str_in_array(const gchar **haystack, const gchar *needle)
 
1921
{
 
1922
        const gchar **p;
 
1923
 
 
1924
        for (p = haystack; *p != NULL; ++p)
 
1925
        {
 
1926
                if (utils_str_equal(*p, needle))
 
1927
                        return TRUE;
 
1928
        }
 
1929
        return FALSE;
 
1930
}
 
1931
 
 
1932
 
 
1933
/**
 
1934
 * Copies the current environment into a new array.
 
1935
 * @a exclude_vars is a @c NULL-terminated array of variable names which should be not copied.
 
1936
 * All further arguments are key, value pairs of variables which should be added to
 
1937
 * the environment.
 
1938
 *
 
1939
 * The argument list must be @c NULL-terminated.
 
1940
 *
 
1941
 * @param exclude_vars @c NULL-terminated array of variable names to exclude.
 
1942
 * @param first_varname Name of the first variable to copy into the new array.
 
1943
 * @param ... Key-value pairs of variable names and values, @c NULL-terminated.
 
1944
 *
 
1945
 * @return The new environment array.
 
1946
 **/
 
1947
gchar **utils_copy_environment(const gchar **exclude_vars, const gchar *first_varname, ...)
 
1948
{
 
1949
        gchar **result;
 
1950
        gchar **p;
 
1951
        gchar **env;
 
1952
        va_list args;
 
1953
        const gchar *key, *value;
 
1954
        guint n, o;
 
1955
 
 
1956
        /* get all the environ variables */
 
1957
        env = g_listenv();
 
1958
 
 
1959
        /* count the additional variables */
 
1960
        va_start(args, first_varname);
 
1961
        for (o = 1; va_arg(args, gchar*) != NULL; o++);
 
1962
        va_end(args);
 
1963
        /* the passed arguments should be even (key, value pairs) */
 
1964
        g_return_val_if_fail(o % 2 == 0, NULL);
 
1965
 
 
1966
        o /= 2;
 
1967
 
 
1968
        /* create an array large enough to hold the new environment */
 
1969
        n = g_strv_length(env);
 
1970
        /* 'n + o + 1' could leak a little bit when exclude_vars is set */
 
1971
        result = g_new(gchar *, n + o + 1);
 
1972
 
 
1973
        /* copy the environment */
 
1974
        for (n = 0, p = env; *p != NULL; ++p)
 
1975
        {
 
1976
                /* copy the variable */
 
1977
                value = g_getenv(*p);
 
1978
                if (G_LIKELY(value != NULL))
 
1979
                {
 
1980
                        /* skip excluded variables */
 
1981
                        if (exclude_vars != NULL && str_in_array(exclude_vars, *p))
 
1982
                                continue;
 
1983
 
 
1984
                        result[n++] = g_strconcat(*p, "=", value, NULL);
 
1985
                }
 
1986
        }
 
1987
        g_strfreev(env);
 
1988
 
 
1989
        /* now add additional variables */
 
1990
        va_start(args, first_varname);
 
1991
        key = first_varname;
 
1992
        value = va_arg(args, gchar*);
 
1993
        while (key != NULL)
 
1994
        {
 
1995
                result[n++] = g_strconcat(key, "=", value, NULL);
 
1996
 
 
1997
                key = va_arg(args, gchar*);
 
1998
                if (key == NULL)
 
1999
                        break;
 
2000
                value = va_arg(args, gchar*);
 
2001
        }
 
2002
        va_end(args);
 
2003
 
 
2004
        result[n] = NULL;
 
2005
 
 
2006
        return result;
 
2007
}
 
2008
 
 
2009