summaryrefslogtreecommitdiff
path: root/mysys/default_modify.c
blob: c0589f54132ff200d4a1f28d2f3cc459f578dcec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/*
  Add/remove option to the option file section.

  SYNOPSYS
    modify_defaults_file()
    file_location     The location of configuration file to edit
    option            option to look for
    option value      The value of the option we would like to set
    section_name      the name of the section
    remove_option     This is true if we want to remove the option.
                      False otherwise.
  IMPLEMENTATION
    We open the option file first, then read the file line-by-line,
    looking for the section we need. At the same time we put these lines
    into a buffer. Then we look for the option within this section and
    change/remove it. In the end we get a buffer with modified version of the
    file. Then we write it to the file, truncate it if needed and close it.

  RETURN
    0 - ok
    1 - some error has occured. Probably due to the lack of resourses
    2 - cannot open the file
*/

#include "my_global.h"
#include "mysys_priv.h"
#include "m_string.h"
#include <my_dir.h>

#define BUFF_SIZE 1024

#ifdef __WIN__
#define NEWLINE "\r\n"
#define NEWLINE_LEN 2
#else
#define NEWLINE "\n"
#define NEWLINE_LEN 1
#endif

uint modify_defaults_file(const char *file_location, const char *option,
			  const char *option_value,
			  const char *section_name, int remove_option)
{
  FILE *cnf_file;
  struct stat file_stat;
  char linebuff[BUFF_SIZE], tmp[BUFF_SIZE], *tmp_ptr, *src_ptr, *dst_ptr,
       *file_buffer;
  uint optlen, optval_len, sect_len;
  my_bool in_section= FALSE;
  DBUG_ENTER("modify_defaults_file");

  optlen= strlen(option);
  optval_len= strlen(option_value);
  sect_len= strlen(section_name);

  if (!(cnf_file= my_fopen(file_location, O_RDWR | O_BINARY, MYF(0))))
    DBUG_RETURN(2);

  /* my_fstat doesn't use the flag parameter */
  if (my_fstat(fileno(cnf_file), &file_stat, MYF(0)))
    goto err;

  /*
    Reserve space to read the contents of the file and some more
    for the option we want to add.
  */
  if (!(file_buffer= (char*) my_malloc(sizeof(char)*
				       (file_stat.st_size +
					/* option name len */
					optlen +
					/* reserve space for newline */
					NEWLINE_LEN +
					/* reserve for '=' char */
					1 +           
					/* option value len */
					optval_len), MYF(MY_WME))))
    goto malloc_err;

  for (dst_ptr= file_buffer, tmp_ptr= 0;
       fgets(linebuff, BUFF_SIZE, cnf_file); )
  {
    /* Skip over whitespaces */
    for (src_ptr= linebuff; my_isspace(&my_charset_latin1, *src_ptr);
	 src_ptr++)
    {}

    if (in_section && !strncmp(src_ptr, option, optlen) &&
	(*(src_ptr + optlen) == '=' ||
	 my_isspace(&my_charset_latin1, *(src_ptr + optlen)) ||
	 *(src_ptr + optlen) == '\0'))
    {
      /* The option under modifying was found in this section. Apply new. */
      if (!remove_option)
	dst_ptr= strmov(dst_ptr, tmp);
      tmp_ptr= 0; /* To mark that we have already applied this */
    }
    else
    {
      /* If going to new group and we have option to apply, do it now */
      if (tmp_ptr && *src_ptr == '[')
      {
	dst_ptr= strmov(dst_ptr, tmp);
	tmp_ptr= 0;
      }
      dst_ptr= strmov(dst_ptr, linebuff);
    }
    /* Look for a section */
    if (*src_ptr == '[')
    {
      /* Copy the line to the buffer */
      if (!strncmp(++src_ptr, section_name, sect_len))
      {
	src_ptr+= sect_len;
	/* Skip over whitespaces. They are allowed after section name */
	for (; my_isspace(&my_charset_latin1, *src_ptr); src_ptr++)
	{}

	if (*src_ptr != ']')
	  continue; /* Missing closing parenthesis. Assume this was no group */
	
        in_section= TRUE;
        /* add option */
        if (!remove_option)
        {
          tmp_ptr= strmov(tmp, option);
          if (*option_value)
          {
	    *tmp_ptr++= '=';
            tmp_ptr= strmov(tmp_ptr, option_value);
          }
          /* add a newline */
	  strmov(tmp_ptr, NEWLINE);
        }
      }
      else
        in_section= FALSE; /* mark that this section is of no interest to us */
    }
  }
  /* File ended. New option still remains to apply at the end */
  if (tmp_ptr)
  {
    if (*(dst_ptr - 1) != '\n')
      *dst_ptr++= '\n';
    dst_ptr= strmov(dst_ptr, tmp);    
  }

  if (my_chsize(fileno(cnf_file), (my_off_t) (dst_ptr - file_buffer), 0,
		MYF(MY_WME)) ||
      my_fseek(cnf_file, 0, MY_SEEK_SET, MYF(0)) ||
      my_fwrite(cnf_file, file_buffer, (uint) (dst_ptr - file_buffer),
		MYF(MY_NABP)) ||
      my_fclose(cnf_file, MYF(MY_WME)))
     goto err;

  my_free(file_buffer, MYF(0));

  DBUG_RETURN(0);

err:
  my_free(file_buffer, MYF(0));
malloc_err:
  my_fclose(cnf_file, MYF(0));
  DBUG_RETURN(1); /* out of resources */
}