Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
263 dpurdie 1
/*
2
	CPP V5 -- system module.
3
 
4
	Source:  sys.c
5
	Started: October 7, 1985
6
	Version:
7
		May 26, 1988
8
		August 1, 1989
9
			Stamp out the extra newline bug in sysnlput().
10
 
11
	Written by Edward K. Ream.
12
	This software is in the public domain.
13
 
14
	See the read.me file for disclaimer and other information.
15
*/
16
 
17
#include "cpp.h"
18
 
19
#if defined(MICRO_SOFT) || defined(__WATCOMC__)
20
#include <fcntl.h>
21
#include <sys\types.h>
22
#include <sys\stat.h>
23
#include <io.h>
24
#include <time.h>
25
#endif
26
 
27
#if defined(TURBOC)
28
#include <fcntl.h>
29
#include <sys\stat.h>
30
#include <io.h>
31
#include <conio.h>
32
#include <time.h>
33
#endif
34
 
35
/*
36
	Define the format of a file node.
37
	The node contains all information pertaining to the file.
38
	The fil_name and f_line are used to update preprocessor globals.
39
*/
40
typedef enum { NULL_STAT,
41
	CLOSED_STAT, INPUT_STAT, OUTPUT_STAT, LOCAL_STAT, EOF_STAT
42
} en_stat;
43
 
44
static struct FN {
45
	struct FN * f_next;	/* pointer to next node		*/
46
	char *	fil_name;	/* file name			*/
47
	int	f_line;		/* line number			*/
48
	char *	f_buffer;	/* file buffer			*/
49
	int	f_bufsize;	/* size of file buffer: bytes	*/
50
	int	f_handle;	/* handle to file.		*/
51
	char *  f_bufp;		/* pointer into file buffer	*/
52
	int	f_bufc;		/* characters in buffer		*/
53
	en_stat	f_type;		/* status of file		*/
54
	int	f_lastc;	/* restart character		*/
55
};
56
#define FN_SIZE (sizeof(struct FN))
57
 
58
static struct FN * in_list   = NULL;	/* List of input nodes.		*/
59
static struct FN * outn_list = NULL;	/* List of output nodes.	*/
60
 
61
/*
62
	The following global variables are copies of the fields in FN.
63
	Global variables are used as an efficiency measure.
64
*/
65
static char *	s_ip = NULL;    /* Copy of f_bufp for input file.	*/
66
static int	s_ic = 0;    	/* Copy of f_bufc for input file.	*/
67
static char *	s_op = NULL;	/* Copy of f_bufp for output file.	*/
68
static int	s_oc = 0;	/* Copy of f_bufc for output file.	*/
69
 
70
#define MAX_INLEVEL 20	/* Max depth of nested #includes.	*/
71
#define IBUF_SIZE 2048	/* Size of each input buffer.		*/
72
#define OBUF_SIZE 2048	/* Size of the output buffer.		*/
73
 
74
/*
75
	Define "pushed back" characters used by sysn1().
76
*/
77
static int	push_back = -1;		/* Used by macro logic.		*/
78
static int	file_put_back = -1;	/* Used by non-macro logic.	*/
79
 
80
/*
81
	Define variables used by time and date routines.
82
*/
83
static	long ltime;
84
static	struct tm *newtime;
85
static char time_buf [30];
86
static char date_buf [30];
87
 
88
/*
89
	Declare static functions in this module.
90
*/
91
static void	raw_close	(int);
92
static int	raw_creat	(char *);
93
static int	raw_open	(char *);
94
static int	raw_read	(int, char *, int);
95
static int	raw_write	(int, char *, int);
96
static int	syscstat	(void);
97
static void	sysn1		(void);
98
static struct FN *sys_new	(int);
99
static void	sys_release	(void);
100
 
101
/*
102
	Close a file opened with raw_open() or raw_creat().
103
*/
104
static void
105
raw_close(handle)
106
int handle;
107
{
108
	TRACEP("raw_close", printf("(handle: %d)\n", handle));
109
 
110
	close (handle);
111
}
112
 
113
/*
114
	Open the file for writing only.
115
	Return a handle (int) or ERROR.
116
*/
117
static int
118
raw_creat(name)
119
char *name;
120
{
121
 
122
	TRACEP("raw_creat", printf("(%s)\n", name));
123
 
124
	chmod(name, S_IREAD | S_IWRITE);
125
//	return creat(name, S_IREAD | S_IWRITE);
126
        return open(name, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE);
127
}
128
 
129
 
130
/*
131
	Open the file for reading only.
132
	Return a handle (int) or ERROR.
133
*/
134
static int
135
raw_open(name)
136
char *name;
137
{
138
	TRACEP("raw_open", printf("(%s)\n", name));
139
 
140
	return open(name, O_RDONLY | O_BINARY);
141
}
142
 
143
/*
144
	Read n bytes from the file described by handle into buffer[].
145
	Return the number of bytes read.
146
*/
147
static int
148
raw_read(handle, buffer, n)
149
int handle;
150
char *buffer;
151
int n;
152
{
153
	int result;
154
 
155
	TRACEP("raw_read", printf("(handle: %d, buffer: %lx, n: %d)\n",
156
		handle, buffer, n));
157
 
158
	result = read (handle, buffer, n);
159
 
160
	TRACEP("raw_read", printf("returns %d\n", result));
161
	return result;
162
}
163
 
164
/*
165
	Write n bytes from buffer[] to the file described by handle.
166
	Return the number of bytes written.
167
*/
168
static int
169
raw_write(handle, buffer, n)
170
int handle;
171
char *buffer;
172
int n;
173
{
174
	TRACEP("raw_write", printf("(handle: %dx, buffer: %lx, n: %d)\n",
175
		handle, buffer, n));
176
 
177
	return write (handle, buffer, n);	
178
}
179
 
180
/*
181
	Close all files and exit.
182
 
183
	Do not call fatal() or sysabort() from inside
184
	sysiclose(), sysoclose(), or sys_release().
185
*/
186
void
187
sysabort()
188
{
189
	/* Close the output file. */
190
	if (outn_list != NULL) {
191
		sysoclose();
192
	}
193
 
194
	/* Close all input files. */
195
	while(in_list != NULL) {
196
		sysiclose();
197
	}
198
	sysend();
199
	exit(BAD_EXIT);
200
}		
201
 
202
/*
203
	Put a non-newline to the output file.
204
	This is the second most called routine after sysnext().
205
*/
206
void
207
syscput(c)
208
char c;
209
{
210
	struct FN * fnp;
211
 
212
	*s_op++ = c;
213
	s_oc++;
214
	if (s_oc == OBUF_SIZE) {
215
 
216
		fnp = outn_list;
217
		if (raw_write(fnp->f_handle, fnp->f_buffer, OBUF_SIZE) != 
218
			OBUF_SIZE) {
219
			error("Disk full.");
220
			return;
221
		}
222
 
223
		s_oc = 0;
224
		s_op = fnp -> f_buffer;
225
	}
226
}
227
 
228
/*
229
	Open a file for output.  Only one such file may be open at a time.
230
 
231
	Return TRUE if all went well.
232
*/
233
bool
234
syscreat(name)
235
register char * name;
236
{
237
	register struct FN * fnp;
238
	int handle;
239
 
240
	TRACEP("syscreat", printf("(%s)\n", name));
241
 
242
	fnp = outn_list;
243
	if (fnp == NULL) {
244
		/* Allocate node for output file. */
245
		fnp = outn_list  = sys_new(OBUF_SIZE);
246
	}
247
	else if (fnp -> f_type != CLOSED_STAT) {
248
		syserr("syscreat: Can't happen.");
249
	}
250
 
251
	/* Actually open the file. */
252
        if (str_eq(name, "--"))
253
                handle = fileno(stdout);
254
        else handle = raw_creat(name);
255
	if (handle == ERROR) {
256
		return FALSE;
257
	}
258
	fnp -> f_handle = handle;
259
	fnp -> f_type = OUTPUT_STAT;
260
 
261
	/* The output buffer is empty. */
262
	s_oc = 0;
263
	s_op = fnp -> f_buffer;
264
 
265
	return TRUE;
266
}
267
 
268
/*
269
	Return 0 if no character is ready from the keyboard.
270
	Otherwise, return the character itself.
271
*/
272
static int
273
syscstat()
274
{
275
	if (kbhit()) {
276
		return fgetchar() & 0x7f;
277
	}
278
	else {
279
		return 0;
280
	}
281
}
282
 
283
/*
284
	Get console status and pause if the user has hit control S.
285
	Abort if user has hit control C.
286
*/
287
 
288
#define CONTROL_C 3
289
 
290
void
291
syscsts()
292
{
293
	int c;
294
 
295
	c = syscstat();
296
	if (c == CONTROL_C) {
297
		printf("\nCompilation aborted by operator.\n");
298
		sysabort();
299
	}
300
}
301
 
302
/*
303
	Return the print string of the current date.
304
*/
305
char *
306
sysdate()
307
{
308
	char *p;
309
 
310
	time(&ltime);	
311
	newtime = localtime(&ltime);
312
	p = asctime(newtime);
313
	if (strlen(p) != 25) {
314
		return "";
315
	}
316
	else {
317
		strcpy(date_buf, "\"");
318
		p[11] = '\0';
319
		strcat(date_buf, p);
320
		p[24] = '\0';
321
		strcat(date_buf, p + 20);
322
		strcat(date_buf, "\"");
323
 
324
		TRACEPN("sysdate", printf("returns: %s\n", date_buf));
325
		return date_buf;
326
	}
327
}
328
 
329
/*
330
	Shut down the system.  This routine is called just before doing an
331
	exit().  Do any last minute things here.
332
*/
333
void
334
sysend()
335
{
336
	TICK("sysend");
337
}
338
 
339
/*
340
	Push c back into the file input stream, not the macro input stream.
341
*/
342
void
343
sys_fpb(c)
344
int c;
345
{
346
	file_put_back = c;
347
}
348
 
349
/*
350
	Close the current input file and pop back one level.
351
*/
352
void
353
sysiclose()
354
{
355
	register struct FN * fnp;
356
 
357
	TICK("sysiclose");
358
 
359
#ifdef DEBUG
360
	if (t_inlevel < 0) {
361
		syserr("sysiclose: Bad t_inlevel.");
362
	}
363
#endif
364
 
365
	/* Close the current input file. */
366
	fnp = in_list;	
367
	raw_close(fnp -> f_handle);
368
 
369
	/* Release the current node. */
370
	sys_release();
371
	if (t_inlevel > 0 && in_list == NULL) {
372
		syserr("sysiclose: NULL in_list.");
373
	}
374
 
375
	/* Pop back one level. */
376
	if (in_list != NULL) {
377
		if (t_inlevel < 0) {
378
			syserr("sysiclose: Unexpected in_list.");
379
		}
380
		fnp = in_list;
381
		s_ic = fnp -> f_bufc;
382
		s_ip = fnp -> f_bufp;
383
		t_file = fnp -> fil_name;
384
		t_line = fnp -> f_line;
385
	}
386
	t_inlevel--;
387
 
388
	if (t_inlevel == -1) {
389
		ch = END_FILE;
390
		TRACEPN("sysiclose", printf("restarts. ch=END_FILE\n"));
391
	}
392
	else {
393
		ch = (unsigned char) fnp -> f_lastc;
394
		TRACEPN("sysiclose", printf("retarts. ch=lastc: %s\n",
395
			pr_ch(ch)));
396
	}
397
 
398
	TRACEP("sysiclose", printf("exit: t_inlevel=%d\n", t_inlevel));
399
}
400
 
401
/*
402
	Allocate space for a new file node and file buffer.
403
	Fill in all other fields to neutral values.
404
*/
405
static struct FN *
406
sys_new(buf_size)
407
int buf_size;
408
{
409
	register struct FN * fnp;
410
 
411
	TRACEP("sys_new", printf("(buf_size: %d)\n", buf_size));
412
 
413
	fnp		 = (struct FN *) m_alloc(sizeof(struct FN));
414
	fnp -> f_buffer	 = (char *)      m_alloc(buf_size);
415
	fnp -> f_bufsize = buf_size;
416
 
417
	fnp -> f_next	= NULL;
418
	fnp -> fil_name	= NULL;
419
	fnp -> f_bufp	= fnp -> f_buffer;
420
	fnp -> f_bufc	= 0;
421
	fnp -> f_type	= CLOSED_STAT;
422
 
423
	TRACEPN("sys_new", printf("returns %lx\n", fnp));
424
	return fnp;
425
}
426
 
427
/*
428
	Set the global variable ch to the next character from the input stream.
429
	This is the most often called routine in the whole program.
430
*/
431
void
432
sysnext()
433
{
434
	for(;;) {
435
		sysn1();
436
 
437
		/* Intercept backslash newline combinations here. */
438
		if (ch == '\\') {
439
 
440
			/* 3/3/89 */
441
			sysn1();
442
			while (ch == '\r') {
443
				sysn1();
444
			}
445
 
446
			if (ch == '\n') {
447
				t_line++;
448
				continue;
449
			}
450
			else {
451
				push_back = ch;
452
				ch = '\\';
453
				return;
454
			}
455
		}
456
		/* Filter out all carriage returns. */
457
		else if (ch != '\r') {
458
			return;
459
		}
460
	}
461
}
462
 
463
static void
464
sysn1()
465
{
466
	register int n;
467
	register struct FN * fnp;
468
 
469
	/* Priority 1: A pushed back character. */
470
	if (push_back != -1) {
471
		ch = push_back;
472
		TRACEP("sysnext", printf("pushback: %s\n", pr_ch(ch)));
473
		push_back = -1;
474
		return;
475
	}
476
 
477
	/* Priority 2:  The rescan buffer. */
478
	if (m_flag) {
479
		ch = *p_rescan++;
480
		if (ch) {
481
			TRACEP("sysnext", printf("rescan ch: %s\n",
482
				pr_ch(ch)));
483
			return;
484
		}
485
		m_flag = FALSE;
486
 
487
		/*
488
			Priority 2A:  The trailing character.
489
			This is NOT part of the rescan buffer.
490
		*/
491
		if (file_put_back != -1) {
492
			ch = file_put_back;
493
			TRACEP("sysnext", printf("fpb ch: %s\n",
494
				pr_ch(ch)));
495
			file_put_back = -1;
496
			return;
497
		}
498
		/* FALL THROUGH. */
499
	}
500
 
501
	/* Priority 3:  The current file. */
502
	if (s_ic > 0) {
503
		s_ic--;
504
		ch = *s_ip++;
505
		TRACEP("sysnext_v", printf("ch: %s\n", pr_ch(ch)));
506
		return;
507
	}
508
 
509
	/* A file or local buffer is empty. */
510
	fnp = in_list;
511
	switch(fnp -> f_type) {
512
 
513
	case EOF_STAT:
514
		/* Continue returning END_FILE until the file is closed. */
515
		ch = END_FILE;
516
		return;
517
 
518
	case INPUT_STAT:
519
		n = raw_read(fnp->f_handle, fnp->f_buffer, IBUF_SIZE);
520
		if (n > 0) {
521
			s_ic  = n;
522
			s_ip = fnp -> f_buffer;
523
			s_ic--;
524
			ch = *s_ip++;
525
		}
526
		else {
527
			fnp -> f_type = EOF_STAT;
528
			ch = END_FILE;
529
		}
530
		return;
531
 
532
	default:
533
		TRACEP("sysn1",
534
			printf("in_list = %lx, in_list -> f_type = %d\n",
535
				in_list, in_list -> f_type));
536
 
537
		syserr("sysn1: Bad f_type field.");
538
	}
539
}
540
 
541
/*
542
	Put a newline to the output file.
543
*/
544
void
545
sysnlput()
546
{
547
	STAT("sysnlput");
548
 
549
	/* 8/1/89 ----- file is open for text, not binary.
550
	syscput('\r');
551
	----- */
552
 
553
	syscput('\n');
554
 
555
	/* Give user a chance to stop. */
556
	syscsts();
557
}
558
 
559
/*
560
	Close the output file(s).
561
*/
562
void
563
sysoclose()
564
{
565
	register struct FN * fnp;
566
 
567
	TICK("sysoclose");
568
 
569
	fnp = outn_list;
570
	if (fnp != NULL && fnp -> f_type != CLOSED_STAT) {
571
		syscput(END_FILE);
572
		raw_write(fnp -> f_handle, fnp -> f_buffer, s_oc);
573
                if (fnp->f_handle != fileno(stdout))
574
		    raw_close(fnp -> f_handle);
575
		fnp -> f_type = CLOSED_STAT;
576
	}
577
}
578
 
579
/*
580
	Open a file for input.
581
	Return TRUE if all went well.
582
*/
583
bool
584
sysopen(name)
585
char *name;
586
{
587
	struct FN * fnp;
588
	int handle;
589
 
590
	TRACEP("sysopen", printf("(%s); old t_inlevel = %d\n",
591
		name, t_inlevel));
592
 
593
	if (m_flag == TRUE) {
594
		m_flag = FALSE;
595
		error("Macro expansion truncated following #include.");
596
	}
597
 
598
	/* Save information about the current level on the stack. */
599
	if (t_inlevel != -1) {
600
		if (in_list == NULL) {
601
			syserr("sysopen: Can't happen.");
602
		}
603
		fnp = in_list;
604
		fnp -> f_line = t_line;
605
		fnp -> f_bufc = s_ic;
606
		fnp -> f_bufp = s_ip;
607
		fnp -> f_lastc = (int) ch;
608
	}
609
 
610
	/* Enter a new level. */
611
	if (t_inlevel >= MAX_INLEVEL) {
612
		fatal("include files nested too deeply");
613
	}
614
	else {
615
		t_inlevel++;
616
	}
617
 
618
	/* Create a new file node and link to the front of the list. */
619
 
620
	TRACEP("sysopen", printf("set up new file: call sys_new\n"));
621
 
622
	fnp	      = sys_new(IBUF_SIZE);
623
	fnp -> f_next = in_list;
624
	fnp -> f_type = INPUT_STAT;
625
	in_list       = fnp;
626
 
627
	/* Actually open the file. */
628
 
629
	handle = raw_open(name);
630
	if (handle == ERROR) {
631
 
632
		/* Deallocate the node. */
633
		TRACEP("sysopen", printf("file open %s fails\n", name));
634
		sys_release();
635
		t_inlevel--;
636
		return FALSE;
637
	}
638
	else {
639
		fnp -> f_handle = handle;
640
	}
641
 
642
	/* Set the global variables. */
643
	t_file = str_alloc(name);
644
	t_line = 1;
645
	fnp -> fil_name = t_file;
646
 
647
	/* Put the first character of the file into ch. */
648
	s_ic = 0;
649
	s_ip = fnp -> f_buffer;
650
	sysnext();
651
 
652
	TRACEP("sysopen", printf("exit: t_inlevel=%d, in_list=%lx\n",
653
						t_inlevel, (long)in_list));
654
	return TRUE;
655
}
656
 
657
/*
658
	Push back c so that sysnext() will return it next.
659
*/
660
void
661
syspushback(c)
662
int c;
663
{
664
	push_back = c;
665
}
666
 
667
/*
668
	Remove one node from the input list.
669
*/
670
static void
671
sys_release()
672
{
673
	register struct FN * fnp;
674
 
675
	TICK("sys_release");
676
 
677
#ifdef DEBUG
678
	if (in_list == NULL) {
679
		syserr("sys_release: Can't happen.");
680
	}
681
#endif
682
 
683
	/* Remove the node from the input list. */
684
	fnp     = in_list;
685
	in_list = fnp -> f_next;
686
	fnp -> f_type = CLOSED_STAT;
687
 
688
	/* Deallocate the node. */
689
	if (fnp -> f_buffer != NULL) {
690
		m_free(fnp -> f_buffer);
691
	}
692
	m_free(fnp);
693
 
694
	/* Reset the global variables from the next node. */
695
	if (in_list == NULL) {
696
		s_ic = 0;
697
	}
698
	else {
699
		fnp = in_list;
700
		s_ic = fnp -> f_bufc;
701
		s_ip = fnp -> f_bufp;
702
	}
703
}
704
 
705
/*
706
	Put one string to the output file.
707
*/
708
void
709
syssput(s)
710
register char * s;
711
{
712
	TRACEP("syssput", printf("(%s)\n", s));
713
 
714
	while (*s) {
715
		syscput(*s++);
716
	}
717
}
718
 
719
/*
720
	Return a print string of the current time.
721
*/
722
char *
723
systime()
724
{
725
	char *p;
726
 
727
	time(&ltime);	
728
	newtime = localtime(&ltime);
729
	p = asctime(newtime);
730
	if (strlen(p) != 25) {
731
		return "\"\"";
732
	}
733
	else {
734
		strcpy(time_buf, "\"");
735
		*(p+19) = '\0';
736
		strcat(time_buf, p+11);
737
		strcat(time_buf, "\"");
738
		TRACEPN("systime", printf("returns: %s\n", time_buf));
739
		return time_buf;
740
	}
741
}