~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to cmd-line-utils/readline/histfile.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* histfile.c - functions to manipulate the history file. */
 
2
 
 
3
/* Copyright (C) 1989-2003 Free Software Foundation, Inc.
 
4
 
 
5
   This file contains the GNU History Library (the Library), a set of
 
6
   routines for managing the text of previously typed lines.
 
7
 
 
8
   The Library is free software; you can redistribute it and/or modify
 
9
   it under the terms of the GNU General Public License as published by
 
10
   the Free Software Foundation; either version 2, or (at your option)
 
11
   any later version.
 
12
 
 
13
   The Library is distributed in the hope that it will be useful, but
 
14
   WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
   General Public License for more details.
 
17
 
 
18
   The GNU General Public License is often shipped with GNU software, and
 
19
   is generally kept in a file called COPYING or LICENSE.  If you do not
 
20
   have a copy of the license, write to the Free Software Foundation,
 
21
   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
 
22
 
 
23
/* The goal is to make the implementation transparent, so that you
 
24
   don't have to know what data types are used, just what functions
 
25
   you can call.  I think I have done that. */
 
26
 
 
27
#define READLINE_LIBRARY
 
28
 
 
29
#if defined (__TANDEM)
 
30
#  include <floss.h>
 
31
#endif
 
32
 
 
33
#if defined (HAVE_CONFIG_H)
 
34
#  include "config_readline.h"
 
35
#endif
 
36
 
 
37
#include <stdio.h>
 
38
 
 
39
#include <sys/types.h>
 
40
#if ! defined (_MINIX) && defined (HAVE_SYS_FILE_H)
 
41
#  include <sys/file.h>
 
42
#endif
 
43
#include "posixstat.h"
 
44
#include <fcntl.h>
 
45
 
 
46
#if defined (HAVE_STDLIB_H)
 
47
#  include <stdlib.h>
 
48
#else
 
49
#  include "ansi_stdlib.h"
 
50
#endif /* HAVE_STDLIB_H */
 
51
 
 
52
#if defined (HAVE_UNISTD_H)
 
53
#  include <unistd.h>
 
54
#endif
 
55
 
 
56
#if defined (__EMX__) || defined (__CYGWIN__)
 
57
#  undef HAVE_MMAP
 
58
#endif
 
59
 
 
60
#ifdef HISTORY_USE_MMAP
 
61
#  include <sys/mman.h>
 
62
 
 
63
#  ifdef MAP_FILE
 
64
#    define MAP_RFLAGS  (MAP_FILE|MAP_PRIVATE)
 
65
#    define MAP_WFLAGS  (MAP_FILE|MAP_SHARED)
 
66
#  else
 
67
#    define MAP_RFLAGS  MAP_PRIVATE
 
68
#    define MAP_WFLAGS  MAP_SHARED
 
69
#  endif
 
70
 
 
71
#  ifndef MAP_FAILED
 
72
#    define MAP_FAILED  ((void *)-1)
 
73
#  endif
 
74
 
 
75
#endif /* HISTORY_USE_MMAP */
 
76
 
 
77
/* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment
 
78
   on win 95/98/nt), we want to open files with O_BINARY mode so that there
 
79
   is no \n -> \r\n conversion performed.  On other systems, we don't want to
 
80
   mess around with O_BINARY at all, so we ensure that it's defined to 0. */
 
81
#if defined (__EMX__) || defined (__CYGWIN__)
 
82
#  ifndef O_BINARY
 
83
#    define O_BINARY 0
 
84
#  endif
 
85
#else /* !__EMX__ && !__CYGWIN__ */
 
86
#  undef O_BINARY
 
87
#  define O_BINARY 0
 
88
#endif /* !__EMX__ && !__CYGWIN__ */
 
89
 
 
90
#include <errno.h>
 
91
#if !defined (errno)
 
92
extern int errno;
 
93
#endif /* !errno */
 
94
 
 
95
#include "history.h"
 
96
#include "histlib.h"
 
97
 
 
98
#include "rlshell.h"
 
99
#include "xmalloc.h"
 
100
 
 
101
/* If non-zero, we write timestamps to the history file in history_do_write() */
 
102
int history_write_timestamps = 0;
 
103
 
 
104
/* Does S look like the beginning of a history timestamp entry?  Placeholder
 
105
   for more extensive tests. */
 
106
#define HIST_TIMESTAMP_START(s)         (*(s) == history_comment_char)
 
107
 
 
108
/* Return the string that should be used in the place of this
 
109
   filename.  This only matters when you don't specify the
 
110
   filename to read_history (), or write_history (). */
 
111
static char *
 
112
history_filename (filename)
 
113
     const char *filename;
 
114
{
 
115
  char *return_val;
 
116
  const char *home;
 
117
  int home_len;
 
118
 
 
119
  return_val = filename ? savestring (filename) : (char *)NULL;
 
120
 
 
121
  if (return_val)
 
122
    return (return_val);
 
123
  
 
124
  home = sh_get_env_value ("HOME");
 
125
 
 
126
  if (home == 0)
 
127
    {
 
128
      home = ".";
 
129
      home_len = 1;
 
130
    }
 
131
  else
 
132
    home_len = strlen (home);
 
133
 
 
134
  return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */
 
135
  strcpy (return_val, home);
 
136
  return_val[home_len] = '/';
 
137
#if defined (__MSDOS__)
 
138
  strcpy (return_val + home_len + 1, "_history");
 
139
#else
 
140
  strcpy (return_val + home_len + 1, ".history");
 
141
#endif
 
142
 
 
143
  return (return_val);
 
144
}
 
145
 
 
146
/* Add the contents of FILENAME to the history list, a line at a time.
 
147
   If FILENAME is NULL, then read from ~/.history.  Returns 0 if
 
148
   successful, or errno if not. */
 
149
int
 
150
read_history (filename)
 
151
     const char *filename;
 
152
{
 
153
  return (read_history_range (filename, 0, -1));
 
154
}
 
155
 
 
156
/* Read a range of lines from FILENAME, adding them to the history list.
 
157
   Start reading at the FROM'th line and end at the TO'th.  If FROM
 
158
   is zero, start at the beginning.  If TO is less than FROM, read
 
159
   until the end of the file.  If FILENAME is NULL, then read from
 
160
   ~/.history.  Returns 0 if successful, or errno if not. */
 
161
int
 
162
read_history_range (filename, from, to)
 
163
     const char *filename;
 
164
     int from, to;
 
165
{
 
166
  register char *line_start, *line_end, *p;
 
167
  char *input, *buffer, *bufend, *last_ts;
 
168
  int file, current_line, chars_read;
 
169
  struct stat finfo;
 
170
  size_t file_size;
 
171
#if defined (EFBIG)
 
172
  int overflow_errno = EFBIG;
 
173
#elif defined (EOVERFLOW)
 
174
  int overflow_errno = EOVERFLOW;
 
175
#else
 
176
  int overflow_errno = EIO;
 
177
#endif
 
178
 
 
179
  buffer = last_ts = (char *)NULL;
 
180
  input = history_filename (filename);
 
181
  file = open (input, O_RDONLY|O_BINARY, 0666);
 
182
 
 
183
  if ((file < 0) || (fstat (file, &finfo) == -1))
 
184
    goto error_and_exit;
 
185
 
 
186
  file_size = (size_t)finfo.st_size;
 
187
 
 
188
  /* check for overflow on very large files */
 
189
  if ((sizeof(off_t) > sizeof(size_t) && finfo.st_size > (off_t)(size_t)~0) ||  
 
190
    file_size + 1 < file_size)
 
191
    {
 
192
      errno = overflow_errno;
 
193
      goto error_and_exit;
 
194
    }
 
195
 
 
196
#ifdef HISTORY_USE_MMAP
 
197
  /* We map read/write and private so we can change newlines to NULs without
 
198
     affecting the underlying object. */
 
199
  buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0);
 
200
  if ((void *)buffer == MAP_FAILED)
 
201
    {
 
202
      errno = overflow_errno;
 
203
      goto error_and_exit;
 
204
    }
 
205
  chars_read = file_size;
 
206
#else
 
207
  buffer = (char *)malloc (file_size + 1);
 
208
  if (buffer == 0)
 
209
    {
 
210
      errno = overflow_errno;
 
211
      goto error_and_exit;
 
212
    }
 
213
 
 
214
  chars_read = read (file, buffer, file_size);
 
215
#endif
 
216
  if (chars_read < 0)
 
217
    {
 
218
  error_and_exit:
 
219
      if (errno != 0)
 
220
        chars_read = errno;
 
221
      else
 
222
        chars_read = EIO;
 
223
      if (file >= 0)
 
224
        close (file);
 
225
 
 
226
      FREE (input);
 
227
#ifndef HISTORY_USE_MMAP
 
228
      FREE (buffer);
 
229
#endif
 
230
 
 
231
      return (chars_read);
 
232
    }
 
233
 
 
234
  close (file);
 
235
 
 
236
  /* Set TO to larger than end of file if negative. */
 
237
  if (to < 0)
 
238
    to = chars_read;
 
239
 
 
240
  /* Start at beginning of file, work to end. */
 
241
  bufend = buffer + chars_read;
 
242
  current_line = 0;
 
243
 
 
244
  /* Skip lines until we are at FROM. */
 
245
  for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
 
246
    if (*line_end == '\n')
 
247
      {
 
248
        p = line_end + 1;
 
249
        /* If we see something we think is a timestamp, continue with this
 
250
           line.  We should check more extensively here... */
 
251
        if (HIST_TIMESTAMP_START(p) == 0)
 
252
          current_line++;
 
253
        line_start = p;
 
254
      }
 
255
 
 
256
  /* If there are lines left to gobble, then gobble them now. */
 
257
  for (line_end = line_start; line_end < bufend; line_end++)
 
258
    if (*line_end == '\n')
 
259
      {
 
260
        /* Change to allow Windows-like \r\n end of line delimiter. */
 
261
        if (line_end > line_start && line_end[-1] == '\r')
 
262
          line_end[-1] = '\0';
 
263
        else
 
264
          *line_end = '\0';
 
265
 
 
266
        if (*line_start)
 
267
          {
 
268
            if (HIST_TIMESTAMP_START(line_start) == 0)
 
269
              {
 
270
                add_history (line_start);
 
271
                if (last_ts)
 
272
                  {
 
273
                    add_history_time (last_ts);
 
274
                    last_ts = NULL;
 
275
                  }
 
276
              }
 
277
            else
 
278
              {
 
279
                last_ts = line_start;
 
280
                current_line--;
 
281
              }
 
282
          }
 
283
 
 
284
        current_line++;
 
285
 
 
286
        if (current_line >= to)
 
287
          break;
 
288
 
 
289
        line_start = line_end + 1;
 
290
      }
 
291
 
 
292
  FREE (input);
 
293
#ifndef HISTORY_USE_MMAP
 
294
  FREE (buffer);
 
295
#else
 
296
  munmap (buffer, file_size);
 
297
#endif
 
298
 
 
299
  return (0);
 
300
}
 
301
 
 
302
/* Truncate the history file FNAME, leaving only LINES trailing lines.
 
303
   If FNAME is NULL, then use ~/.history.  Returns 0 on success, errno
 
304
   on failure. */
 
305
int
 
306
history_truncate_file (fname, lines)
 
307
     const char *fname;
 
308
     int lines;
 
309
{
 
310
  char *buffer, *filename, *bp, *bp1;           /* bp1 == bp+1 */
 
311
  int file, chars_read, rv;
 
312
  struct stat finfo;
 
313
  size_t file_size;
 
314
  size_t bytes_written;
 
315
 
 
316
  buffer = (char *)NULL;
 
317
  filename = history_filename (fname);
 
318
  file = open (filename, O_RDONLY|O_BINARY, 0666);
 
319
  rv = 0;
 
320
 
 
321
  /* Don't try to truncate non-regular files. */
 
322
  if (file == -1 || fstat (file, &finfo) == -1)
 
323
    {
 
324
      rv = errno;
 
325
      if (file != -1)
 
326
        close (file);
 
327
      goto truncate_exit;
 
328
    }
 
329
 
 
330
  if (S_ISREG (finfo.st_mode) == 0)
 
331
    {
 
332
      close (file);
 
333
#ifdef EFTYPE
 
334
      rv = EFTYPE;
 
335
#else
 
336
      rv = EINVAL;
 
337
#endif
 
338
      goto truncate_exit;
 
339
    }
 
340
 
 
341
  file_size = (size_t)finfo.st_size;
 
342
 
 
343
  /* check for overflow on very large files */
 
344
  if ((sizeof(off_t) > sizeof(size_t) && finfo.st_size > (off_t)(size_t)~0) ||  
 
345
    file_size + 1 < file_size)
 
346
    {
 
347
      close (file);
 
348
#if defined (EFBIG)
 
349
      rv = errno = EFBIG;
 
350
#elif defined (EOVERFLOW)
 
351
      rv = errno = EOVERFLOW;
 
352
#else
 
353
      rv = errno = EINVAL;
 
354
#endif
 
355
      goto truncate_exit;
 
356
    }
 
357
 
 
358
  buffer = (char *)malloc (file_size + 1);
 
359
  if (buffer == 0)
 
360
    {
 
361
      close (file);
 
362
      goto truncate_exit;
 
363
    }
 
364
 
 
365
  chars_read = read (file, buffer, file_size);
 
366
  close (file);
 
367
 
 
368
  if (chars_read <= 0)
 
369
    {
 
370
      rv = (chars_read < 0) ? errno : 0;
 
371
      goto truncate_exit;
 
372
    }
 
373
 
 
374
  /* Count backwards from the end of buffer until we have passed
 
375
     LINES lines.  bp1 is set funny initially.  But since bp[1] can't
 
376
     be a comment character (since it's off the end) and *bp can't be
 
377
     both a newline and the history comment character, it should be OK. */
 
378
  for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--)
 
379
    {
 
380
      if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
 
381
        lines--;
 
382
      bp1 = bp;
 
383
    }
 
384
 
 
385
  /* If this is the first line, then the file contains exactly the
 
386
     number of lines we want to truncate to, so we don't need to do
 
387
     anything.  It's the first line if we don't find a newline between
 
388
     the current value of i and 0.  Otherwise, write from the start of
 
389
     this line until the end of the buffer. */
 
390
  for ( ; bp > buffer; bp--)
 
391
    {
 
392
      if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
 
393
        {
 
394
          bp++;
 
395
          break;
 
396
        }
 
397
      bp1 = bp;
 
398
    }
 
399
 
 
400
  /* Write only if there are more lines in the file than we want to
 
401
     truncate to. */
 
402
  if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
 
403
    {
 
404
      bytes_written= write (file, bp, chars_read - (bp - buffer));
 
405
 
 
406
#if defined (__BEOS__)
 
407
      /* BeOS ignores O_TRUNC. */
 
408
      ftruncate (file, chars_read - (bp - buffer));
 
409
#endif
 
410
 
 
411
      close (file);
 
412
    }
 
413
 
 
414
 truncate_exit:
 
415
 
 
416
  FREE (buffer);
 
417
 
 
418
  free (filename);
 
419
  return rv;
 
420
}
 
421
 
 
422
/* Workhorse function for writing history.  Writes NELEMENT entries
 
423
   from the history list to FILENAME.  OVERWRITE is non-zero if you
 
424
   wish to replace FILENAME with the entries. */
 
425
static int
 
426
history_do_write (filename, nelements, overwrite)
 
427
     const char *filename;
 
428
     int nelements, overwrite;
 
429
{
 
430
  register int i;
 
431
  char *output;
 
432
  int file, mode, rv;
 
433
#ifdef HISTORY_USE_MMAP
 
434
  size_t cursize;
 
435
 
 
436
  mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY;
 
437
#else
 
438
  mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
 
439
#endif
 
440
  output = history_filename (filename);
 
441
  rv = 0;
 
442
 
 
443
  if ((file = open (output, mode, 0600)) == -1)
 
444
    {
 
445
      FREE (output);
 
446
      return (errno);
 
447
    }
 
448
 
 
449
#ifdef HISTORY_USE_MMAP
 
450
  cursize = overwrite ? 0 : lseek (file, 0, SEEK_END);
 
451
#endif
 
452
 
 
453
  if (nelements > history_length)
 
454
    nelements = history_length;
 
455
 
 
456
  /* Build a buffer of all the lines to write, and write them in one syscall.
 
457
     Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
 
458
  {
 
459
    HIST_ENTRY **the_history;   /* local */
 
460
    register int j;
 
461
    int buffer_size;
 
462
    char *buffer;
 
463
 
 
464
    the_history = history_list ();
 
465
    /* Calculate the total number of bytes to write. */
 
466
    for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
 
467
#if 0
 
468
      buffer_size += 2 + HISTENT_BYTES (the_history[i]);
 
469
#else
 
470
      {
 
471
        if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
 
472
          buffer_size += strlen (the_history[i]->timestamp) + 1;
 
473
        buffer_size += strlen (the_history[i]->line) + 1;
 
474
      }
 
475
#endif
 
476
 
 
477
    /* Allocate the buffer, and fill it. */
 
478
#ifdef HISTORY_USE_MMAP
 
479
    if (ftruncate (file, buffer_size+cursize) == -1)
 
480
      goto mmap_error;
 
481
    buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize);
 
482
    if ((void *)buffer == MAP_FAILED)
 
483
      {
 
484
mmap_error:
 
485
        rv = errno;
 
486
        FREE (output);
 
487
        close (file);
 
488
        return rv;
 
489
      }
 
490
#else    
 
491
    buffer = (char *)malloc (buffer_size);
 
492
    if (buffer == 0)
 
493
      {
 
494
        rv = errno;
 
495
        FREE (output);
 
496
        close (file);
 
497
        return rv;
 
498
      }
 
499
#endif
 
500
 
 
501
    for (j = 0, i = history_length - nelements; i < history_length; i++)
 
502
      {
 
503
        if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
 
504
          {
 
505
            strcpy (buffer + j, the_history[i]->timestamp);
 
506
            j += strlen (the_history[i]->timestamp);
 
507
            buffer[j++] = '\n';
 
508
          }
 
509
        strcpy (buffer + j, the_history[i]->line);
 
510
        j += strlen (the_history[i]->line);
 
511
        buffer[j++] = '\n';
 
512
      }
 
513
 
 
514
#ifdef HISTORY_USE_MMAP
 
515
    if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0)
 
516
      rv = errno;
 
517
#else
 
518
    if (write (file, buffer, buffer_size) < 0)
 
519
      rv = errno;
 
520
    free (buffer);
 
521
#endif
 
522
  }
 
523
 
 
524
  close (file);
 
525
 
 
526
  FREE (output);
 
527
 
 
528
  return (rv);
 
529
}
 
530
 
 
531
/* Append NELEMENT entries to FILENAME.  The entries appended are from
 
532
   the end of the list minus NELEMENTs up to the end of the list. */
 
533
int
 
534
append_history (nelements, filename)
 
535
     int nelements;
 
536
     const char *filename;
 
537
{
 
538
  return (history_do_write (filename, nelements, HISTORY_APPEND));
 
539
}
 
540
 
 
541
/* Overwrite FILENAME with the current history.  If FILENAME is NULL,
 
542
   then write the history list to ~/.history.  Values returned
 
543
   are as in read_history ().*/
 
544
int
 
545
write_history (filename)
 
546
     const char *filename;
 
547
{
 
548
  return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
 
549
}