modify upstream makefile to allow hardening build flags to apply
[debian/yforth] / block.c
1 /* yForth? - A Forth interpreter written in ANSI C
2  * Copyright (C) 2012 Luca Padovani
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  * ------------------------------------------------------------------------
17  * Module name:     block.c
18  * Abstract:        Block word set implementation
19  */
20
21 #include <stdio.h>
22 #include <malloc.h>
23 #include "yforth.h"
24 #include "core.h"
25 #include "block.h"
26
27 /**************************************************************************/
28 /* VARIABLES **************************************************************/
29 /**************************************************************************/
30
31 UCell _b_l_k;
32 UCell current_block;
33
34 FILE *block_file;                   /* FILE used to implement blocks */
35
36 struct _block_data *block_data;
37 struct _block_buffer *block_buffer;
38
39 static int block_clock;             /* Used to select the next block to
40                                        deallocate. Based on the "clock
41                                        algorithm
42                                     */
43
44 /**************************************************************************/
45 /* WORDS ******************************************************************/
46 /**************************************************************************/
47
48 void _block() {
49         register UCell u = (UCell) *sp;
50         register int b = search_block(u);
51         if (b < 0) b = allocate_block(u, 1);
52         current_block = b;
53         sp[0] = (Cell) &block_buffer[b].buffer;
54 }
55
56 void _buffer() {
57         register UCell u = (UCell) *sp;
58         register int b = search_block(u);
59         if (b < 0) b = allocate_block(u, 0);
60         current_block = b;
61         sp[0] = (Cell) &block_buffer[b].buffer;
62 }
63
64 void _flush() {
65         register int i;
66         _save_buffers();
67         for (i = 0; i < NUM_BLOCKS; i++) block_data[i].block_no = 0;
68 }
69
70 void _load() {
71         register UCell block_no = (UCell) *sp;
72         save_input_specification();
73         _block();
74         _input_buffer = (Char *) *sp++;
75         _in_input_buffer = BLOCK_SIZE;
76         _to_in = 0;
77         _b_l_k = block_no;
78         _interpret();
79         restore_input_specification();
80 }
81
82 void _save_buffers() {
83         register int i;
84         for (i = 0; i < NUM_BLOCKS; i++) if (block_data[i].dirty) save_block(i);
85 }
86
87 void _update() {
88         block_data[current_block].dirty = 1;
89 }
90
91 /**************************************************************************/
92 /* AUXILIARY FUNCTIONS ****************************************************/
93 /**************************************************************************/
94
95 int search_block(UCell block_no) {
96         register int i;
97         for (i = 0; i < NUM_BLOCKS && block_data[i].block_no != block_no; i++) ;
98         return (i < NUM_BLOCKS ? i : -1);
99 }
100
101 int allocate_block(UCell block_no, int load) {
102         register int i;
103         register int b = search_block(0);
104         if (b < 0) {
105         if (block_data[block_clock].dirty) save_block(block_clock);
106         b = block_clock;
107         block_clock = (block_clock + 1) % NUM_BLOCKS;
108         }
109         if (load) load_block(block_no, b);
110     return (b);
111 }
112
113 void load_block(UCell block_no, int b) {
114         block_data[b].block_no = block_no;
115         block_data[b].dirty = 0;
116         fseek(block_file, ((long) (block_no - 1)) * BLOCK_SIZE, SEEK_SET);
117         fread(&block_buffer[b].buffer, BLOCK_SIZE, 1, block_file);
118 }
119
120 void save_block(int b) {
121         fseek(block_file, ((long) (block_data[b].block_no - 1)) * BLOCK_SIZE, SEEK_SET);
122         fwrite(&block_buffer[b].buffer, BLOCK_SIZE, 1, block_file);
123         block_data[b].dirty = 0;
124 }
125
126 int open_block_file(char *name) {
127         block_file = fopen(name, "r+b");
128         if (!block_file) block_file = fopen(name, "r+b");
129         if (block_file) {
130                 block_data = (struct _block_data *) malloc(NUM_BLOCKS * sizeof(struct _block_data));
131                 block_buffer = (struct _block_buffer *) malloc(NUM_BLOCKS * sizeof(struct _block_buffer));
132                 if (block_data && block_buffer) {
133                         int i;
134                         for (i = 0; i < NUM_BLOCKS; i++) block_data[i].block_no = 0;
135                 } else block_file = NULL;
136         }
137         return (block_file ? 0 : -1);
138 }
139
140 void close_block_file() {
141         if (block_file) {
142                 _save_buffers();
143                 fclose(block_file);
144         }
145 }