URI: 
       tconfigfile.c - vaccinewars - be a doctor and try to vaccinate the world
  HTML git clone git://src.adamsgaard.dk/vaccinewars
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tconfigfile.c (7670B)
       ---
            1 /************************************************************************
            2  * configfile.c   Functions for dealing with dopewars config files      *
            3  * Copyright (C)  2002-2004  Ben Webb                                   *
            4  *                Email: benwebb@users.sf.net                           *
            5  *                WWW: https://dopewars.sourceforge.io/                 *
            6  *                                                                      *
            7  * This program is free software; you can redistribute it and/or        *
            8  * modify it under the terms of the GNU General Public License          *
            9  * as published by the Free Software Foundation; either version 2       *
           10  * of the License, or (at your option) any later version.               *
           11  *                                                                      *
           12  * This program is distributed in the hope that it will be useful,      *
           13  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
           14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
           15  * GNU General Public License for more details.                         *
           16  *                                                                      *
           17  * You should have received a copy of the GNU General Public License    *
           18  * along with this program; if not, write to the Free Software          *
           19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,               *
           20  *                   MA  02111-1307, USA.                               *
           21  ************************************************************************/
           22 
           23 #ifdef HAVE_CONFIG_H
           24 #include <config.h>
           25 #endif
           26 
           27 #include <string.h>             /* For memcmp etc. */
           28 #include <stdio.h>              /* For fgetc etc. */
           29 #include <stdlib.h>             /* For atoi */
           30 #include <errno.h>              /* For errno */
           31 #include <ctype.h>              /* For isprint */
           32 #include <glib.h>
           33 
           34 #include "configfile.h"
           35 #include "convert.h"            /* For Converter */
           36 #include "dopewars.h"           /* For struct GLOBALS etc. */
           37 #include "nls.h"                /* For _ function */
           38 #include "error.h"              /* For ErrStrFromErrno */
           39 
           40 gchar *LocalCfgEncoding = NULL;
           41 
           42 /*
           43  * Prints the given string to a file, converting control characters
           44  * and escaping other special characters.
           45  */
           46 static void PrintEscaped(FILE *fp, gchar *str)
           47 {
           48   guint i;
           49 
           50   for (i = 0; i < strlen(str); i++) {
           51     int ch = (int)(guchar)str[i];
           52     switch(ch) {
           53     case '"':
           54     case '\'':
           55     case '\\':
           56       fputc('\\', fp);
           57       fputc(ch, fp);
           58       break;
           59     case '\n':
           60       fputs("\\n", fp);
           61       break;
           62     case '\t':
           63       fputs("\\t", fp);
           64       break;
           65     case '\r':
           66       fputs("\\r", fp);
           67       break;
           68     case '\b':
           69       fputs("\\b", fp);
           70       break;
           71     case '\f':
           72       fputs("\\f", fp);
           73       break;
           74     default:
           75       if (isascii(ch) && isprint(ch)) {
           76         fputc(ch, fp);
           77       } else {
           78         fprintf(fp, "\\%o", ch);
           79       }
           80     }
           81   }
           82 }
           83 
           84 /*
           85  * Writes a single configuration file variable (identified by GlobalIndex
           86  * and StructIndex) to the specified file, in a format suitable for reading
           87  * back in (via. ParseNextConfig and friends).
           88  */
           89 static void WriteConfigValue(FILE *fp, Converter *conv, int GlobalIndex,
           90                              int StructIndex)
           91 {
           92   gchar *GlobalName;
           93 
           94   if (Globals[GlobalIndex].NameStruct[0]) {
           95     GlobalName =
           96         g_strdup_printf("%s[%d].%s", Globals[GlobalIndex].NameStruct,
           97                         StructIndex, Globals[GlobalIndex].Name);
           98   } else {
           99     GlobalName = Globals[GlobalIndex].Name;
          100   }
          101 
          102   if (Globals[GlobalIndex].IntVal) {
          103     fprintf(fp, "%s = %d\n", GlobalName,
          104             *GetGlobalInt(GlobalIndex, StructIndex));
          105   } else if (Globals[GlobalIndex].BoolVal) {
          106     fprintf(fp, "%s = %s\n", GlobalName,
          107             *GetGlobalBoolean(GlobalIndex, StructIndex) ?
          108             "TRUE" : "FALSE");
          109   } else if (Globals[GlobalIndex].PriceVal) {
          110     gchar *prstr = pricetostr(*GetGlobalPrice(GlobalIndex, StructIndex));
          111 
          112     fprintf(fp, "%s = %s\n", GlobalName, prstr);
          113     g_free(prstr);
          114   } else if (Globals[GlobalIndex].StringVal) {
          115     gchar *convstr;
          116 
          117     fprintf(fp, "%s = \"", GlobalName);
          118     convstr = Conv_ToExternal(conv,
          119                               *GetGlobalString(GlobalIndex, StructIndex), -1);
          120     PrintEscaped(fp, convstr);
          121     g_free(convstr);
          122     fputs("\"\n", fp);
          123   } else if (Globals[GlobalIndex].StringList) {
          124     int i;
          125     gchar *convstr;
          126 
          127     fprintf(fp, "%s = { ", GlobalName);
          128     for (i = 0; i < *Globals[GlobalIndex].MaxIndex; i++) {
          129       if (i > 0)
          130         fputs(", ", fp);
          131       fputc('"', fp);
          132       convstr = Conv_ToExternal(conv,
          133                                 (*Globals[GlobalIndex].StringList)[i], -1);
          134       PrintEscaped(fp, convstr);
          135       g_free(convstr);
          136       fputc('"', fp);
          137     }
          138     fputs(" }\n", fp);
          139   }
          140 
          141   if (Globals[GlobalIndex].NameStruct[0])
          142     g_free(GlobalName);
          143 }
          144 
          145 
          146 static void ReadFileToString(FILE *fp, gchar *str, int matchlen)
          147 {
          148   int len, mpos, ch;
          149   gchar *match;
          150   GString *file;
          151 
          152   file = g_string_new("");
          153   len = strlen(str);
          154   if (matchlen > 0) {
          155     len = MIN(len, matchlen);
          156   }
          157   match = g_new(gchar, len);
          158   mpos = 0;
          159 
          160   while (mpos < len && (ch = fgetc(fp)) != EOF) {
          161     g_string_append_c(file, ch);
          162     match[mpos++] = ch;
          163     if (ch != str[mpos - 1]) {
          164       int start;
          165       gboolean shortmatch = FALSE;
          166 
          167       for (start = 1; start < mpos; start++) {
          168         if (memcmp(str, &match[start], mpos - start) == 0) {
          169           mpos -= start;
          170           memmove(match, &match[start], mpos);
          171           shortmatch = TRUE;
          172           break;
          173         }
          174       }
          175       if (!shortmatch)
          176         mpos = 0;
          177     }
          178   }
          179   g_string_truncate(file, file->len - mpos);
          180 
          181   g_free(match);
          182 
          183   rewind(fp);
          184   ftruncate(fileno(fp), 0);
          185   fputs(file->str, fp);
          186 
          187   fputs(str, fp);
          188 
          189   g_string_free(file, TRUE);
          190 }
          191 
          192 /*
          193  * Writes all of the configuration file variables that have changed
          194  * (together with their values) to the given file.
          195  */
          196 static void WriteConfigFile(FILE *fp, gboolean ForceUTF8)
          197 {
          198   int i, j;
          199   Converter *conv = Conv_New();
          200 
          201   if (ForceUTF8 && !IsConfigFileUTF8()) {
          202     g_free(LocalCfgEncoding);
          203     LocalCfgEncoding = g_strdup("UTF-8");
          204     fputs("encoding \"UTF-8\"\n", fp);
          205   }
          206 
          207   if (LocalCfgEncoding && LocalCfgEncoding[0]) {
          208     Conv_SetCodeset(conv, LocalCfgEncoding);
          209   }
          210 
          211   for (i = 0; i < NUMGLOB; i++) {
          212     if (Globals[i].Modified) {
          213       if (Globals[i].NameStruct[0]) {
          214         for (j = 1; j <= *Globals[i].MaxIndex; j++) {
          215           WriteConfigValue(fp, conv, i, j);
          216         }
          217       } else {
          218         WriteConfigValue(fp, conv, i, 0);
          219       }
          220     }
          221   }
          222   Conv_Free(conv);
          223 }
          224 
          225 gboolean UpdateConfigFile(const gchar *cfgfile, gboolean ForceUTF8)
          226 {
          227   FILE *fp;
          228   gchar *defaultfile;
          229   static gchar *header =
          230       "\n### Everything from here on is written automatically by\n"
          231       "### the dopewars program; you can edit it manually, but any\n"
          232       "### formatting (comments, etc.) will be lost at the next rewrite.\n\n";
          233 
          234   defaultfile = GetLocalConfigFile();
          235   if (!cfgfile || !cfgfile[0]) {
          236     cfgfile = defaultfile;
          237     if (!cfgfile) {
          238       g_warning(_("Could not determine local config file to write to"));
          239       return FALSE;
          240     }
          241   }
          242 
          243   fp = fopen(cfgfile, "r+");
          244   if (!fp) {
          245     fp = fopen(cfgfile, "w+");
          246   }
          247 
          248   if (!fp) {
          249     gchar *errstr = ErrStrFromErrno(errno);
          250     g_warning(_("Could not open file %s: %s"), cfgfile, errstr);
          251     g_free(errstr);
          252     g_free(defaultfile);
          253     return FALSE;
          254   }
          255 
          256   ReadFileToString(fp, header, 50);
          257   WriteConfigFile(fp, ForceUTF8);
          258 
          259   fclose(fp);
          260   g_free(defaultfile);
          261   return TRUE;
          262 }
          263 
          264 gboolean IsConfigFileUTF8(void)
          265 {
          266   return (LocalCfgEncoding && strcmp(LocalCfgEncoding, "UTF-8") == 0);
          267 }