📄 file.c
字号:
/* * This file contains the file i/o stuff. These functions get stuff from * from the outside world into a form for TDE. The form TDE uses is a * double linked list. Each node in the list points to the prev and * the next nodes, if they exist. Also in each node is a pointer to a * line of text, a line length variable, and a node type indicator. In * earlier versions of TDE, a '\n' was used to terminate a line of text. * In this version, we must keep an accurate count of characters in * each line of text, as no character is used to terminate the line. * * Each file must contain at least one node. That node is called the * EOF node. The EOF node terminates the double linked list for each * file. The EOF node has a NULL pointer in the line field, a NULL * pointer in the next field, and an EOF in the len field. Here's * a crude picture of the double linked list structure: * * Regular node EOF node * -------- -------- * | prev | ---> pointer to prev node | prev | ---> unknown * | line | ---> "Hello world" | line | ---> NULL * | len | ---> 11 | len | ---> EOF * | type | ---> DIRTY | syntax flags | type | ---> 0 * | next | ---> pointer to next node | next | ---> NULL * -------- -------- * * Implicitly, I am assuming that EOF is defined as (-1) in stdio.h. * * jmh 980701: I've added a top of file marker, so now each file contains * at least two nodes and the first line in the file becomes * line_list->next rather than just line_list, which is the * zeroth line and remains constant. It also causes changes in * other files, which are not documented. * * The load_file function is probably more complicated than expected, but * I was trying to read chunks of text that match the disk cluster size * and/or some multiple of the cache in the disk controller. * * jmh 021101: tried to simplify it. Instead of reading into two buffers and * and swapping the residue between them, read into one buffer * and copy the residue into the other. I also read multiple * binary lines at once. * * * New editor name: TDE, the Thomson-Davis Editor. * Author: Frank Davis * Date: June 5, 1991, version 1.0 * Date: July 29, 1991, version 1.1 * Date: October 5, 1991, version 1.2 * Date: January 20, 1992, version 1.3 * Date: February 17, 1992, version 1.4 * Date: April 1, 1992, version 1.5 * Date: June 5, 1992, version 2.0 * Date: October 31, 1992, version 2.1 * Date: April 1, 1993, version 2.2 * Date: June 5, 1993, version 3.0 * Date: August 29, 1993, version 3.1 * Date: November 13, 1993, version 3.2 * Date: June 5, 1994, version 4.0 * Date: December 5, 1998, version 5.0 (jmh) * * This code is released into the public domain, Frank Davis. * You may distribute it freely. */#include "tdestr.h" /* tde types */#include "common.h"#include "define.h"#include "tdefunc.h"static char file_buf[READ_LENGTH]; /* jmh 021102: file buffer */static char *cmd_title; /* jmh 030331: for -c */char wksp_file[PATH_MAX]; /* jmh 020802: for -w */int wksp_loaded; /* jmh 020911: for AutoSaveWorkspace */extern char init_wd[PATH_MAX]; /* defined in main.c */extern char *line_in; /* defined in config.c */extern int make_window; /* defined in window.c */#if defined( __WIN32__ )extern HANDLE conin; /* defined in win32/console.c */#endifextern int auto_reload; /* defined in utils.c */extern TDE_WIN *results_window; /* defined in findrep.c */extern file_infos *results_file;extern file_infos *search_file;extern long found_rline;static void write_history( FILE *, HISTORY * ); /* added by jmh 021029 */static void read_history( FILE *, HISTORY * ); /* ditto *//* * Name: write_file * Purpose: To write text to a file * way. * Date: June 5, 1991 * Passed: name: name of disk file or device * open_mode: fopen flags to be used in open * file: pointer to file structure to write * start: first node to write * end: last node to write * block: write a file or a marked block * Returns: OK, or ERROR if anything went wrong * * jmh: August 27, 1997 - if name is empty (ie. "") then write to stdout. * This allows TDE to be used in a pipe. * jmh 021103: fixed writing the first/last line of a stream block with tabs * (but if inside a tab, it will write the tab, not the spaces). */int write_file( char *name, int open_mode, file_infos *file, long start, long end, int block ){FILE *fp; /* file to be written */text_ptr p;char *z = "\x1a";register int rc;int bc;int ec;int len;int write_z;int write_eol;long number;line_list_ptr ll;char *open_string;char *eol;size_t eol_count;int tabs;int tab_size; if (block == LINE || block == BOX || block == STREAM) { if (g_status.marked_file == NULL) return( ERROR ); file = g_status.marked_file; } write_z = mode.control_z; switch (open_mode) { case APPEND : open_string = "ab"; break; case OVERWRITE : default : open_string = "wb"; break; } switch (file->crlf) { case BINARY : eol_count = 0; eol = ""; write_z = FALSE; break; case CRLF : eol_count = 2; eol = "\r\n"; break; case LF : eol_count = 1; eol = "\n"; break; default : eol_count = 0; eol = ""; assert( FALSE ); } rc = OK; if (*name == '\0') { fp = stdout;#if !defined( __UNIX__ ) setmode( fileno( stdout ), O_BINARY );#endif } else if ((fp = fopen( name, open_string )) == NULL || CEH_ERROR) rc = ERROR; if (rc == OK) { ll = file->line_list->next; for (number = 1; number < start && ll->len != EOF; number++) ll = ll->next; ec = bc = len = 0; if (block == BOX || block == STREAM) { bc = file->block_bc; ec = file->block_ec; len = ec + 1 - bc; if (block == STREAM && start == end && ec != -1) block = BOX; } tabs = file->inflate_tabs; tab_size = file->ptab_size; if (block == BOX) { p = g_status.line_buff; for (; start <= end && rc == OK; start++) { load_box_buff( p, ll, bc, ec, ' ', tabs, tab_size ); if (fwrite( p, sizeof( char ), len, fp ) < (unsigned)len || CEH_ERROR) rc = ERROR; if ((rc != ERROR && fwrite( eol, sizeof( char ), eol_count, fp ) < eol_count) || CEH_ERROR) rc = ERROR; ll = ll->next; if (ll == NULL) rc = ERROR; } } else { for (number = start; number <= end && rc == OK; number++) { p = ll->line; len = ll->len; if (block == STREAM) { if (number == start) { if (tabs) bc = entab_adjust_rcol( (text_ptr)p, len, bc, tab_size ); if (bc > len) bc = len; p += bc; len -= bc; } else if (number == end && ec != -1) { if (tabs) ec = entab_adjust_rcol( (text_ptr)p, len, ec, tab_size ); ++ec; if (ec < len) len = ec; } } if (fwrite( p, sizeof( char ), len, fp ) < (unsigned)len || CEH_ERROR) rc = ERROR; /* * if a Control-Z is already at EOF, don't write another one. */ write_eol = TRUE; if (number == end) { if (file->crlf != BINARY) { if (len > 0 && *(p + len - 1) == '\x1a') { write_eol = FALSE; write_z = FALSE; } } } if ((write_eol == TRUE && rc != ERROR && fwrite( eol, sizeof( char ), eol_count, fp ) < eol_count) || CEH_ERROR) rc = ERROR; ll = ll->next; if (ll == NULL) rc = ERROR; } } if (rc != ERROR && write_z) { if (fwrite( z, sizeof( char ), 1, fp ) < 1 || CEH_ERROR) rc = ERROR; } g_status.copied = FALSE; if (!CEH_ERROR) { if (fclose( fp ) != 0) rc = ERROR; } } return( rc );}/* * Name: hw_save * Purpose: To save text to a file * Date: November 11, 1989 * Passed: name: name of disk file * file: pointer to file structure * start: first character in text buffer * end: last character (+1) in text buffer * block: type of block defined * Returns: OK, or ERROR if anything went wrong */int hw_save( char *name, file_infos *file, long start, long end, int block ){ return( write_file( name, OVERWRITE, file, start, end, block ) );}/* * Name: hw_append * Purpose: To append text to a file. * Date: November 11, 1989 * Passed: name: name of disk file * file: pointer to file structure * start: first character in text buffer * end: last character (+1) in text buffer * block: type of defined block * Returns: OK, or ERROR if anything went wrong */int hw_append( char *name, file_infos *file, long start, long end, int block ){ return( write_file( name, APPEND, file, start, end, block ) );}/* * Name: load_file * Purpose: To load a file into the array of text pointers. * Date: December 1, 1992 * Passed: name: name of disk file * fp: pointer to file structure * file_mode: BINARY or TEXT * bin_len: if opened in BINARY mode, length of node line * insert: NULL for new file, pointer to line to insert file * Returns: OK, or ERROR if anything went wrong * * jmh: August 27, 1997 - if name is empty (ie. "") then read from stdin. * This allows TDE to be used in a pipe. * January 24, 1998 - added insert line pointer to allow a file to be * inserted into another file. * jmh 990428: if input is redirected, and output is not, set read-only mode. * jmh 990501: don't set mode.trailing = FALSE when loading BINARY (it's taken * care of separately). * jmh 020822: removed UNIX' forced text mode for files starting with "#!" */int load_file( char *name, file_infos *fp, int *file_mode, int bin_len, line_list_ptr insert ){FILE *stream; /* stream to read */int rc;line_list_ptr ll;line_list_ptr temp_ll;char *s, *e;int len;int t1, t2;int crlf;int prompt_line; /* * initialize the counters and pointers */ rc = OK; prompt_line = g_display.end_line; ll = (insert == NULL) ? fp->line_list : insert; if (*name == '\0') { stream = stdin;#if !defined( __UNIX__ ) setmode( fileno( stdin ), O_BINARY );#endif } else if ((stream = fopen( name, "rb" )) == NULL || CEH_ERROR) { /* * file not found or error loading file */ combine_strings( line_out, main7a, name, main7b ); error( INFO, prompt_line, line_out ); rc = ERROR; } if (rc == OK) { if (*file_mode == BINARY) { crlf = BINARY; if (bin_len < 0 || bin_len > READ_LENGTH) bin_len = DEFAULT_BIN_LENGTH; assert( bin_len < MAX_LINE_LENGTH ); t2 = (READ_LENGTH / bin_len) * bin_len; if (t2 == 0) /* READ_LENGTH is smaller than MAX_LINE_LENGTH */ t2 = bin_len; while (rc == OK) { t1 = fread( file_buf, sizeof(char), t2, stream ); if (ferror( stream ) || CEH_ERROR) { combine_strings( line_out, main9, name, "'" ); error( WARNING, prompt_line, line_out ); rc = ERROR; break; } if (t1 == 0) break; s = file_buf; do { if (t1 < bin_len) /* will only occur on the last line */ bin_len = t1; temp_ll = new_line_text( (text_ptr)s, bin_len, 0, &rc); if (rc != ERROR) { insert_node( fp, ll, temp_ll ); ll = temp_ll; } else { rc = show_file_2big( name, prompt_line ); break; } s += bin_len; t1 -= bin_len; } while (t1 != 0); } } else { crlf = LF; len = 0; while (rc == OK) { t1 = fread( file_buf, 1, READ_LENGTH, stream ); if (ferror( stream ) || CEH_ERROR) { combine_strings( line_out, main9, name, "'" ); error( WARNING, prompt_line, line_out ); rc = ERROR; break; } if (t1 == 0) break; s = file_buf; do { e = memchr( s, '\n', t1 ); if (e == NULL) { if (len + t1 <= READ_LENGTH) { memcpy( g_status.line_buff + len, s, t1 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -