OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-7.1/] [readline/] [histfile.c] - Blame information for rev 856

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 227 jeremybenn
/* 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.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 (file_size != finfo.st_size || file_size + 1 < file_size)
190
    {
191
      errno = overflow_errno;
192
      goto error_and_exit;
193
    }
194
 
195
#ifdef HISTORY_USE_MMAP
196
  /* We map read/write and private so we can change newlines to NULs without
197
     affecting the underlying object. */
198
  buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0);
199
  if ((void *)buffer == MAP_FAILED)
200
    {
201
      errno = overflow_errno;
202
      goto error_and_exit;
203
    }
204
  chars_read = file_size;
205
#else
206
  buffer = (char *)malloc (file_size + 1);
207
  if (buffer == 0)
208
    {
209
      errno = overflow_errno;
210
      goto error_and_exit;
211
    }
212
 
213
  chars_read = read (file, buffer, file_size);
214
#endif
215
  if (chars_read < 0)
216
    {
217
  error_and_exit:
218
      if (errno != 0)
219
        chars_read = errno;
220
      else
221
        chars_read = EIO;
222
      if (file >= 0)
223
        close (file);
224
 
225
      FREE (input);
226
#ifndef HISTORY_USE_MMAP
227
      FREE (buffer);
228
#endif
229
 
230
      return (chars_read);
231
    }
232
 
233
  close (file);
234
 
235
  /* Set TO to larger than end of file if negative. */
236
  if (to < 0)
237
    to = chars_read;
238
 
239
  /* Start at beginning of file, work to end. */
240
  bufend = buffer + chars_read;
241
  current_line = 0;
242
 
243
  /* Skip lines until we are at FROM. */
244
  for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
245
    if (*line_end == '\n')
246
      {
247
        p = line_end + 1;
248
        /* If we see something we think is a timestamp, continue with this
249
           line.  We should check more extensively here... */
250
        if (HIST_TIMESTAMP_START(p) == 0)
251
          current_line++;
252
        line_start = p;
253
      }
254
 
255
  /* If there are lines left to gobble, then gobble them now. */
256
  for (line_end = line_start; line_end < bufend; line_end++)
257
    if (*line_end == '\n')
258
      {
259
        if (line_end - 1 >= line_start && *(line_end - 1) == '\r')
260
          *(line_end - 1) = '\0';
261
        else
262
          *line_end = '\0';
263
 
264
        if (*line_start)
265
          {
266
            if (HIST_TIMESTAMP_START(line_start) == 0)
267
              {
268
                add_history (line_start);
269
                if (last_ts)
270
                  {
271
                    add_history_time (last_ts);
272
                    last_ts = NULL;
273
                  }
274
              }
275
            else
276
              {
277
                last_ts = line_start;
278
                current_line--;
279
              }
280
          }
281
 
282
        current_line++;
283
 
284
        if (current_line >= to)
285
          break;
286
 
287
        line_start = line_end + 1;
288
      }
289
 
290
  FREE (input);
291
#ifndef HISTORY_USE_MMAP
292
  FREE (buffer);
293
#else
294
  munmap (buffer, file_size);
295
#endif
296
 
297
  return (0);
298
}
299
 
300
/* Truncate the history file FNAME, leaving only LINES trailing lines.
301
   If FNAME is NULL, then use ~/.history.  Returns 0 on success, errno
302
   on failure. */
303
int
304
history_truncate_file (fname, lines)
305
     const char *fname;
306
     int lines;
307
{
308
  char *buffer, *filename, *bp, *bp1;           /* bp1 == bp+1 */
309
  int file, chars_read, rv;
310
  struct stat finfo;
311
  size_t file_size;
312
 
313
  buffer = (char *)NULL;
314
  filename = history_filename (fname);
315
  file = open (filename, O_RDONLY|O_BINARY, 0666);
316
  rv = 0;
317
 
318
  /* Don't try to truncate non-regular files. */
319
  if (file == -1 || fstat (file, &finfo) == -1)
320
    {
321
      rv = errno;
322
      if (file != -1)
323
        close (file);
324
      goto truncate_exit;
325
    }
326
 
327
  if (S_ISREG (finfo.st_mode) == 0)
328
    {
329
      close (file);
330
#ifdef EFTYPE
331
      rv = EFTYPE;
332
#else
333
      rv = EINVAL;
334
#endif
335
      goto truncate_exit;
336
    }
337
 
338
  file_size = (size_t)finfo.st_size;
339
 
340
  /* check for overflow on very large files */
341
  if (file_size != finfo.st_size || file_size + 1 < file_size)
342
    {
343
      close (file);
344
#if defined (EFBIG)
345
      rv = errno = EFBIG;
346
#elif defined (EOVERFLOW)
347
      rv = errno = EOVERFLOW;
348
#else
349
      rv = errno = EINVAL;
350
#endif
351
      goto truncate_exit;
352
    }
353
 
354
  buffer = (char *)malloc (file_size + 1);
355
  if (buffer == 0)
356
    {
357
      close (file);
358
      goto truncate_exit;
359
    }
360
 
361
  chars_read = read (file, buffer, file_size);
362
  close (file);
363
 
364
  if (chars_read <= 0)
365
    {
366
      rv = (chars_read < 0) ? errno : 0;
367
      goto truncate_exit;
368
    }
369
 
370
  /* Count backwards from the end of buffer until we have passed
371
     LINES lines.  bp1 is set funny initially.  But since bp[1] can't
372
     be a comment character (since it's off the end) and *bp can't be
373
     both a newline and the history comment character, it should be OK. */
374
  for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--)
375
    {
376
      if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
377
        lines--;
378
      bp1 = bp;
379
    }
380
 
381
  /* If this is the first line, then the file contains exactly the
382
     number of lines we want to truncate to, so we don't need to do
383
     anything.  It's the first line if we don't find a newline between
384
     the current value of i and 0.  Otherwise, write from the start of
385
     this line until the end of the buffer. */
386
  for ( ; bp > buffer; bp--)
387
    {
388
      if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
389
        {
390
          bp++;
391
          break;
392
        }
393
      bp1 = bp;
394
    }
395
 
396
  /* Write only if there are more lines in the file than we want to
397
     truncate to. */
398
  if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
399
    {
400
      write (file, bp, chars_read - (bp - buffer));
401
 
402
#if defined (__BEOS__)
403
      /* BeOS ignores O_TRUNC. */
404
      ftruncate (file, chars_read - (bp - buffer));
405
#endif
406
 
407
      close (file);
408
    }
409
 
410
 truncate_exit:
411
 
412
  FREE (buffer);
413
 
414
  free (filename);
415
  return rv;
416
}
417
 
418
/* Workhorse function for writing history.  Writes NELEMENT entries
419
   from the history list to FILENAME.  OVERWRITE is non-zero if you
420
   wish to replace FILENAME with the entries. */
421
static int
422
history_do_write (filename, nelements, overwrite)
423
     const char *filename;
424
     int nelements, overwrite;
425
{
426
  register int i;
427
  char *output;
428
  int file, mode, rv;
429
#ifdef HISTORY_USE_MMAP
430
  size_t cursize;
431
 
432
  mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY;
433
#else
434
  mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
435
#endif
436
  output = history_filename (filename);
437
  rv = 0;
438
 
439
  if ((file = open (output, mode, 0600)) == -1)
440
    {
441
      FREE (output);
442
      return (errno);
443
    }
444
 
445
#ifdef HISTORY_USE_MMAP
446
  cursize = overwrite ? 0 : lseek (file, 0, SEEK_END);
447
#endif
448
 
449
  if (nelements > history_length)
450
    nelements = history_length;
451
 
452
  /* Build a buffer of all the lines to write, and write them in one syscall.
453
     Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
454
  {
455
    HIST_ENTRY **the_history;   /* local */
456
    register int j;
457
    int buffer_size;
458
    char *buffer;
459
 
460
    the_history = history_list ();
461
    /* Calculate the total number of bytes to write. */
462
    for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
463
#if 0
464
      buffer_size += 2 + HISTENT_BYTES (the_history[i]);
465
#else
466
      {
467
        if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
468
          buffer_size += strlen (the_history[i]->timestamp) + 1;
469
        buffer_size += strlen (the_history[i]->line) + 1;
470
      }
471
#endif
472
 
473
    /* Allocate the buffer, and fill it. */
474
#ifdef HISTORY_USE_MMAP
475
    if (ftruncate (file, buffer_size+cursize) == -1)
476
      goto mmap_error;
477
    buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize);
478
    if ((void *)buffer == MAP_FAILED)
479
      {
480
mmap_error:
481
        rv = errno;
482
        FREE (output);
483
        close (file);
484
        return rv;
485
      }
486
#else    
487
    buffer = (char *)malloc (buffer_size);
488
    if (buffer == 0)
489
      {
490
        rv = errno;
491
        FREE (output);
492
        close (file);
493
        return rv;
494
      }
495
#endif
496
 
497
    for (j = 0, i = history_length - nelements; i < history_length; i++)
498
      {
499
        if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
500
          {
501
            strcpy (buffer + j, the_history[i]->timestamp);
502
            j += strlen (the_history[i]->timestamp);
503
            buffer[j++] = '\n';
504
          }
505
        strcpy (buffer + j, the_history[i]->line);
506
        j += strlen (the_history[i]->line);
507
        buffer[j++] = '\n';
508
      }
509
 
510
#ifdef HISTORY_USE_MMAP
511
    if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0)
512
      rv = errno;
513
#else
514
    if (write (file, buffer, buffer_size) < 0)
515
      rv = errno;
516
    free (buffer);
517
#endif
518
  }
519
 
520
  close (file);
521
 
522
  FREE (output);
523
 
524
  return (rv);
525
}
526
 
527
/* Append NELEMENT entries to FILENAME.  The entries appended are from
528
   the end of the list minus NELEMENTs up to the end of the list. */
529
int
530
append_history (nelements, filename)
531
     int nelements;
532
     const char *filename;
533
{
534
  return (history_do_write (filename, nelements, HISTORY_APPEND));
535
}
536
 
537
/* Overwrite FILENAME with the current history.  If FILENAME is NULL,
538
   then write the history list to ~/.history.  Values returned
539
   are as in read_history ().*/
540
int
541
write_history (filename)
542
     const char *filename;
543
{
544
  return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
545
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.