|
|
1.1 root 1: /* cbootlib.c -- C routines for use by boot programs.
2: *
3: * La Monte H. Yarroll <[email protected]>, September 1991
4: */
5:
6: #include <string.h>
7: #include <ctype.h>
8: #include "tboot.h"
9:
10: /* puts() -- put a NUL terminated string.
11: * Takes one argument--a pointer to a NUL terminated character string.
12: * Does no error checking. Calls the assembly language routine putc().
13: */
14: void
15: puts(s)
16: register char *s;
17: {
18: while (*s != '\0') {
19: putchar(*s++);
20: }
21:
22: } /* puts() */
23:
24:
25: #define BS '\010'
26: #define DEL '\0' /* This is really what getchar() returns! */
27: #define NAK '\025'
28: /* gets() -- Read string from keyboard.
29: * Takes one argument--a pointer to a buffer big enough for the
30: * expected response.
31: * It stops reading as soon as it detects a carriage return. The CR
32: * is replaced with a NUL.
33: */
34: char *
35: gets(s)
36: char *s;
37: {
38: register char *t;
39:
40: t = s;
41:
42: while ('\r' != (*t = getchar())) {
43: if ((BS == *t) || (DEL == *t)) {
44: /* Process back space. */
45: if (t > s) {
46: t--;
47: puts("\010 \010"); /* Erase the last character. */
48: }
49: } else if (NAK == *t) {
50: /* Kill line. */
51: while (--t >= s) {
52: puts("\010 \010"); /* Erase the last character. */
53: }
54: t = s;
55: } else {
56: /* Echo the character; prepare for another. */
57: putchar(*t);
58: t++;
59: }
60: }
61: *t = '\0';
62: return(s);
63: } /* gets() */
64:
65:
66: /* Reverse string s in place.
67: * Straight from K&R.
68: */
69: void
70: reverse(s)
71: char s[];
72: {
73: int c, i, j;
74:
75: for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
76: c = s[i];
77: s[i] = s[j];
78: s[j] = c;
79: }
80: } /* reverse() */
81:
82: #define BASE10 10 /* itoa() generates base 10 numbers. */
83:
84: /* Convert n to decimal characters in s.
85: * Straight from K&R (with minor sylistic changes.)
86: */
87: void
88: itoa(n, s)
89: char s[];
90: int n;
91: {
92: int i, sign;
93:
94: if ((sign = n) < 0) { /* Record sign. */
95: n = -n; /* Make n positive. */
96: }
97:
98: i = 0;
99: do { /* Generate digits in reverse order. */
100: s[i++] = n % BASE10 + '0'; /* Get next digit. */
101:
102: } while ((n /= BASE10) > 0); /* Delete it. */
103:
104: if (sign < 0) {
105: s[i++] = '-';
106: }
107: s[i] = '\0';
108: reverse(s);
109: } /* itoa() */
110:
111:
112: #define BASE16 16
113: /* Convert n to digits in s, base base.
114: * Works for any base from 2 to 36.
115: * Modified itoa() from K&R.
116: */
117: void
118: itobase(n, s, base)
119: uint16 n;
120: char s[];
121: int base;
122: {
123: uint16 i;
124:
125: i = 0;
126: do { /* Generate digits in reverse order. */
127: s[i] = n % base + '0'; /* Get next digit. */
128: /* Adjust for the gap between '9' and 'A'. */
129: if (s[i] > '9') {
130: s[i] += ('A' - '9') - 1;
131: }
132: ++i;
133: } while ((n /= base) > 0); /* Delete it. */
134:
135: s[i] = '\0';
136: reverse(s);
137: } /* itobase() */
138:
139: /* basetoi(char *s, int base)
140: * Convert a string base "base" to an integer.
141: * Good through base 36.
142: * Loosely based on K&R's atoi().
143: */
144: uint16
145: basetoi(s, base)
146: char *s;
147: int base;
148: {
149: int i, n;
150:
151: static char convert[]="0123456789abcdefghijklmnopqrstuvwxyz";
152:
153: /* Lowercase the entire string. */
154: for(i = 0; '\0' != s[i]; ++i) {
155: if (isupper(s[i])) {
156: s[i] = tolower(s[i]);
157: }
158: }
159:
160: /* Actually do the conversion. */
161: n = 0;
162: for (i = 0; '\0' != s[i] && NULL != strchr(convert, s[i]); ++i) {
163: n = (base * n) + (strchr(convert, s[i]) - convert);
164: }
165: return(n);
166:
167: } /* basetoi() */
168:
169:
170: /* seginc(uint16 *offset,
171: * uint16 *segment,
172: * uint16 increment)
173: * Add an offset to a segment. We may adjust the segment base
174: * to make everything fit.
175: */
176: #define MAXSEG (int32)0xffff /* Top address in a segment. */
177: #define PPSIZE 16 /* Size of a paragraph--
178: * segments are PP aligned.
179: */
180:
181: void
182: seginc(offset, segment, increment)
183: uint16 *offset;
184: uint16 *segment;
185: uint16 increment;
186: {
187: /* If we won't spill over a segment boundary, just add increment
188: * to *offset.
189: */
190: if ((int32) (*offset) + (int32) increment < MAXSEG) {
191: *offset += increment;
192: } else {
193: /* Otherwise, we have to adjust the segment. */
194: *segment += (increment / PPSIZE);
195:
196: /* If offset is within PPSIZE of the end of a segment,
197: * we have to bump segment up to the next paragraph.
198: */
199: if ((int32) (*offset) + (int32) (increment % PPSIZE) < MAXSEG) {
200: *offset += (increment % PPSIZE);
201: } else {
202: *segment += 1;
203: *offset =
204: (int) (((int32) (*offset) +
205: (int32) (increment % PPSIZE))
206: - MAXSEG);
207: }
208: }
209: } /* seginc() */
210:
211:
212: /* Pad a string s on the left with character c, to length n.
213: * The old contents of s are replaced by the padded version.
214: */
215: char *
216: lpad(s, c, n)
217: char *s;
218: char c;
219: int n;
220: {
221: static char localbuf[LINESIZE];
222: register int len_s; /* length of s. */
223: register int i;
224:
225: len_s = strlen(s);
226:
227: /* We only have something to do if the string is too short. */
228: if (len_s < n) {
229: /* Is n small enough to fit in locabuf? */
230: if (n < (LINESIZE - 1)) {
231: /* Fill the padding into the local buffer. */
232: for (i = 0; i < (n - len_s); ++i) {
233: localbuf[i] = c;
234: }
235: localbuf[i] = '\0';
236:
237: /* Append the string to be padded. */
238: strcat(localbuf, s);
239: /* Copy the padded string back where it came from. */
240: strcpy(s, localbuf);
241: } else {
242: /* Too big! Do something more complicated. */
243: strcpy(s, "lpad: n is too big!");
244: }
245: }
246:
247: return(s);
248: } /* lpad() */
249:
250: #define BITS_PER_INT16 16 /* Number of bits in an int16. */
251: #define DIGITS_PER_INT16 4 /* Maximum hex digits in a 16 bit number. */
252: #define DIGITS_PER_INT8 2 /* Maximum hex digits in an 8 bit number. */
253: /*
254: * Print a 32 bit integer in hexadecimal.
255: */
256: void
257: print32(my_int)
258: uint32 my_int;
259: {
260: uint16 half;
261: char buffer[sizeof("ffff")];
262:
263: /* Convert and print the upper half. */
264: half = (uint16) ((my_int) >> BITS_PER_INT16);
265: itobase(half, buffer, BASE16);
266: lpad(buffer, '0', DIGITS_PER_INT16);
267: puts(buffer);
268:
269: /* Convert and print the lower half. */
270: half = (uint16) ((my_int << BITS_PER_INT16) >> BITS_PER_INT16);
271: itobase(half, buffer, BASE16);
272: lpad(buffer, '0', DIGITS_PER_INT16);
273: puts(buffer);
274: }
275:
276: /*
277: * Print a 16 bit integer in hexadecimal.
278: */
279: void
280: print16(my_int)
281: uint16 my_int;
282: {
283: char buffer[sizeof("ffff")];
284:
285: itobase(my_int, buffer, BASE16);
286: lpad(buffer, '0', DIGITS_PER_INT16);
287: puts(buffer);
288: }
289:
290: /*
291: * Print an 8 bit integer in hexadecimal.
292: */
293: void
294: print8(my_int)
295: uint8 my_int;
296: {
297: char buffer[sizeof("ff")];
298:
299: itobase((uint16) my_int, buffer, BASE16);
300: lpad(buffer, '0', DIGITS_PER_INT8);
301: puts(buffer);
302: }
303:
304:
305: /*
306: * Wrapper for far-far copy. Changes the segment so that the requested
307: * length does not wrap past the end of the segment.
308: *
309: * For Intel 8086 Real Mode.
310: */
311: void
312: ffcopy(to_offset, to_seg, from_offset, from_seg, length)
313: uint16 to_offset;
314: uint16 to_seg;
315: uint16 from_offset;
316: uint16 from_seg;
317: uint16 length;
318: {
319: uint16 to_move; /* Amount to move at a time. */
320: /* Algorithm:
321: * Align both segments so each offset is within a paragraph
322: * of the beginning of the segment.
323: * Move up to 1/2 a segment.
324: * Decrement length.
325: * Interate.
326: */
327:
328: while (length != 0) {
329: /* Align both segments. */
330: seg_align(&to_offset, &to_seg);
331: seg_align(&from_offset, &from_seg);
332:
333: /* Move up to 1/2 a segment. */
334: to_move = LESSER(length, MAXUINT16/2);
335:
336: _ffcopy(from_offset, from_seg, to_offset, to_seg, to_move);
337:
338: /* Decrement length. */
339: length -= to_move;
340: }
341: } /* ffcopy() */
342:
343: /*
344: * Align a far address so that its offset is within a paragraph of
345: * the start of the segment.
346: *
347: * Note that we ignore overflow in the segment, since this is exactly
348: * what happens when you offset past the end of the highest segment.
349: *
350: * WARNING: This routine is destructive to its arguments.
351: *
352: * For Intel 8086 Real Mode.
353: */
354: void
355: seg_align(offset, segment)
356: uint16 *offset;
357: uint16 *segment;
358: {
359: #define BYTE_PER_PP 16 /* Number of bytes in a paragraph. */
360: uint16 new_offset,
361: new_segment;
362:
363: new_segment = *segment + (*offset/BYTE_PER_PP);
364: new_offset = *offset % BYTE_PER_PP;
365:
366: *segment = new_segment;
367: *offset = new_offset;
368: } /* seg_align() */
369: /*
370: * wait_for_keystroke() -- wait for a specific keystroke.
371: */
372:
373: /* Location of BIOS-run timer. */
374: #define TIMER_SEG 0x0040
375: #define TIMER_OFF 0x006c
376:
377: #define MIDNIGHT (((uint32) 24) << 16)
378:
379: /*
380: * Waits delay ticks for the requested keystroke. Returns TRUE if
381: * keystroke came, FALSE if delay runs out.
382: * If key == -1, accept ANY keystroke.
383: */
384: int
385: wait_for_keystroke(delay, key)
386: int delay;
387: int key;
388: {
389: extern uint16 myds; /* My Data Segment, defined in Statup.s. */
390: uint32 end_time; /* Return when time reaches this. */
391: uint32 current_time; /* Current value of timer list. */
392: int my_key_found;
393:
394: while (iskey()) {
395: getchar(); /* Eat all pending characters. */
396: }
397:
398: /* Calculate the terminating time. */
399: ffcopy(&end_time, myds, TIMER_OFF, TIMER_SEG, sizeof(int32));
400: end_time += (int32) delay;
401:
402: /* Adjust for timer reset at midnight. */
403: if (end_time > MIDNIGHT) {
404: /* These messages are meaningless. */
405: puts("KABOOM!\r\n");
406: puts("I'm tired. Please leave me alone.\r\n");
407: end_time -= MIDNIGHT;
408: }
409:
410: /* Busy wait keystrokes and time delay. */
411:
412: my_key_found = FALSE;
413: do {
414: ffcopy(¤t_time, myds, TIMER_OFF, TIMER_SEG,sizeof(int32));
415: if (iskey()) {
416: /* The order of evaluation here is important.
417: * getchar() MUST be called to clean out the
418: * pending character.
419: */
420: if (((int) getchar() == key) || (-1 == key)) {
421: my_key_found = TRUE;
422: }
423: }
424: } while (!my_key_found && (current_time < end_time));
425:
426: return(my_key_found);
427: } /* wait_for_keystrok() */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.