Alter line of file

J

Jens

Hi All.

I am quite new to programming in C, comming from perl.
As an educational excersise I'm writing some code, which aims to change
the grub conf file menu.lst's default entry.

Consider the following code: (see code below)

If the new default entry line is longer than the original (e.g default 0,
changes to default 10, then one character of the next line is overwritten.
Is there a way of solving this progblem, without using a temp file?

Thx in advance
Jens

<code>
int alter_file(int timeout)
{
FILE *file;
regex_t *preg = malloc(sizeof(regex_t));
char *regex;
char *line;
line = (char*)malloc(sizeof(char)*257);
int ret;
regmatch_t* pmatch = (regmatch_t*)malloc(sizeof(regmatch_t));
size_t nmatch = 2;
regex = "^[[:blank:]]*default[[:blank:]]*([[:digit:]]*)";
ret = regcomp(preg,regex,REG_EXTENDED);
printf("ret %d",ret);
file = fopen("/boot/grub/menu.lst","r+");
if (file == NULL) { fprintf(stderr,"Couldn't open file for writing\n");
exit(1);}
while (fgets(line,256,file)!=NULL) {
ret = regexec(preg,line,nmatch,pmatch,0);
if (ret == 0) {
printf("end %d",pmatch[1].rm_eo+1);
fseek(file,(long)-(pmatch[1].rm_eo+1),SEEK_CUR);
fprintf(file,"%s","default 10\n");
}
}
return 0;
}
</code>
 
N

Nate Eldredge

Jens said:
Hi All.

I am quite new to programming in C, comming from perl.
As an educational excersise I'm writing some code, which aims to change
the grub conf file menu.lst's default entry.

Consider the following code: (see code below)

If the new default entry line is longer than the original (e.g default 0,
changes to default 10, then one character of the next line is overwritten.
Is there a way of solving this progblem, without using a temp file?

Not really. Few operating systems have a way to insert data into the
middle of a file, and standard C doesn't provide a mechanism to use it
even if they did.

You could read the entire rest of the file (starting at the end) and
write it back out one byte further along, then insert the new byte, but
that's way more trouble and probably less efficient.
<code>
int alter_file(int timeout)
{
FILE *file;
regex_t *preg = malloc(sizeof(regex_t));
char *regex;
char *line;
line = (char*)malloc(sizeof(char)*257);
int ret;
regmatch_t* pmatch = (regmatch_t*)malloc(sizeof(regmatch_t));
size_t nmatch = 2;
regex = "^[[:blank:]]*default[[:blank:]]*([[:digit:]]*)";
ret = regcomp(preg,regex,REG_EXTENDED);
printf("ret %d",ret);
file = fopen("/boot/grub/menu.lst","r+");
if (file == NULL) { fprintf(stderr,"Couldn't open file for writing\n");
exit(1);}
while (fgets(line,256,file)!=NULL) {
ret = regexec(preg,line,nmatch,pmatch,0);
if (ret == 0) {
printf("end %d",pmatch[1].rm_eo+1);
fseek(file,(long)-(pmatch[1].rm_eo+1),SEEK_CUR);
fprintf(file,"%s","default 10\n");
}
}
return 0;
}
</code>

Some indentation would be nice here. A decent editor will help with
that.
 
J

Jens Thoms Toerring

Jens said:
I am quite new to programming in C, comming from perl.
As an educational excersise I'm writing some code, which aims to change
the grub conf file menu.lst's default entry.
Consider the following code: (see code below)
If the new default entry line is longer than the original (e.g default 0,
changes to default 10, then one character of the next line is overwritten.
Is there a way of solving this progblem, without using a temp file?

It's not different from Perl - you can't insert something into
a file that's longer than what was at the place before (ok, with
Perl you have the '-i' option but that actually also creates a
temporary file behind your back and afterwards renames it). If
you really must avoid using a temporary file you first would
have to copy all the stuff after the place you want to insert
into to a later position in the file - just as you would
have to do it in Perl.
int alter_file(int timeout)
{
FILE *file;
regex_t *preg = malloc(sizeof(regex_t));
char *regex;
char *line;
line = (char*)malloc(sizeof(char)*257);

Unless you're actually writing C++ (but then you would have
asked in comp.lang.c++, I suppose) casting the return value of
malloc() doesn't buy you anything - it actually may keep the
compiler from complaining if you forgot to include <stdlib.h>
where malloc() is declared. Also, you should always check if
malloc() did succeed, especially if you intend to overwrite
important system files;-)

Please note that mixing variable definitions with executable
statements is only allowed if you have a (more or less) C99
compliant compiler.
regmatch_t* pmatch = (regmatch_t*)malloc(sizeof(regmatch_t));
size_t nmatch = 2;
regex = "^[[:blank:]]*default[[:blank:]]*([[:digit:]]*)";

While I won't comment otherwise on your use of the regex
library (it's off-topic here as all third-party libraries)
just the question if the shouldn't be a '+' after the se-
cond "[[:blank:]]" instead of just a '*'?

And since you assign a pointer to a non-modifiable string
to 'regex' it might be prudent to eclare it as such. i.e.

const char * regex;
ret = regcomp(preg,regex,REG_EXTENDED);
printf("ret %d",ret);
file = fopen("/boot/grub/menu.lst","r+");
if (file == NULL) { fprintf(stderr,"Couldn't open file for writing\n");
exit(1);}
while (fgets(line,256,file)!=NULL) {
ret = regexec(preg,line,nmatch,pmatch,0);
if (ret == 0) {
printf("end %d",pmatch[1].rm_eo+1);
fseek(file,(long)-(pmatch[1].rm_eo+1),SEEK_CUR);

While the '-' in after '(long)' is correct if you want
to cast the negative value of what's following it looks
defininitely strange.
fprintf(file,"%s","default 10\n");
}
}
return 0;
}
Regards, Jens
 
U

user923005

Hi All.

I am quite new to programming in C, comming from perl.
As an educational excersise I'm writing some code, which aims to change
the grub conf file menu.lst's default entry.

Consider the following code: (see code below)

If the new default entry line is longer than the original (e.g default 0,
changes to default 10, then one character of the next line is overwritten..
Is there a way of solving this progblem, without using a temp file?

Thx in advance
Jens

<code>
int alter_file(int timeout)
{
  FILE *file;
  regex_t *preg = malloc(sizeof(regex_t));
  char *regex;
  char *line;
  line = (char*)malloc(sizeof(char)*257);
  int ret;
  regmatch_t* pmatch = (regmatch_t*)malloc(sizeof(regmatch_t));
  size_t nmatch = 2;
  regex = "^[[:blank:]]*default[[:blank:]]*([[:digit:]]*)";
  ret = regcomp(preg,regex,REG_EXTENDED);
  printf("ret %d",ret);
  file = fopen("/boot/grub/menu.lst","r+");
  if (file == NULL) { fprintf(stderr,"Couldn't open file for writing\n");
exit(1);}
  while (fgets(line,256,file)!=NULL) {
  ret =  regexec(preg,line,nmatch,pmatch,0);
  if (ret == 0) {
  printf("end %d",pmatch[1].rm_eo+1);
  fseek(file,(long)-(pmatch[1].rm_eo+1),SEEK_CUR);
  fprintf(file,"%s","default 10\n");
  }
  }
  return 0;}

</code>

From the C-FAQ:
12.30: I'm trying to update a file in place, by using fopen mode "r+",
reading a certain string, and writing back a modified string,
but it's not working.

A: Be sure to call fseek before you write, both to seek back to the
beginning of the string you're trying to overwrite, and because
an fseek or fflush is always required between reading and
writing in the read/write "+" modes. Also, remember that you
can only overwrite characters with the same number of
replacement characters, and that overwriting in text mode may
truncate the file at that point, and that you may have to
preserve line lengths. See also question 19.14.

References: ISO Sec. 7.9.5.3.

19.14: How can I insert or delete a line (or record) in the middle of
a
file?

A: Short of rewriting the file, you probably can't. The usual
solution is simply to rewrite the file. (Instead of deleting
records, you might consider simply marking them as deleted, to
avoid rewriting.) Another possibility, of course, is to use a
database instead of a flat file. See also questions 12.30 and
19.13.
 
F

Flash Gordon

Gordon Burditt wrote:

You're pretty much stuck using a temporary *SOMETHING*. The grub
conf file can probably fit in memory, so you might use memory as a
temporary. If, however, the file could be larger than what you can

<snip>

<OT>
With something as important as grub.conf it is probably best to use a
temporary file in any case. Then if something disasterous goes wrong you
are more likely to still have a copy of your original file!
</OT>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,070
Latest member
BiogenixGummies

Latest Threads

Top