Console input in 32-bit Protected mode - c

I am currently working on my OS. I've started building it since a-day before yesterday. My OS is command-based.
This is my Kernel.c(The main file):
#include "include/screen.h"
#include "include/kb.h"
#include "include/string.h"
#include "data/userdata.c"
kmain()
{
clearScreen();
print("Halcyon OS 1.05 Beta ");
while (1)
{
print("\nhalcyon#halcyon ~\n$ ");
string ch = readStr();
if(strEql(ch,"cmd")!=0)
{
print("\nYou are already in cmd\n");
}
else if(strEql(ch,"clear")!=0)
{
clearScreen();
}
else if(strEql(ch,"help")!=0)
{
print("Halcyon help.");
}
else if(strEql(ch,"")!=0)
{
continue;
}
else
{
print("\nNo command found:");print(ch);
break;
}
}// end while loop!
}
And here is kb.h (I've made it for keyboard support.):
#ifndef KB_H
#define KB_H
#include "screen.h"
#include "system.h"
#include "types.h"
string readStr()
{
char buff;
string buffstr;
uint8 i = 0;
uint8 reading = 1;
while(reading)
{
if(inportb(0x64) & 0x1)
{
switch(inportb(0x60))
{
/*case 1:
printch('(char)27); Escape button
buffstr[i] = (char)27;
i++;
break;*/
case 2:
printch('1');
buffstr[i] = '1';
i++;
break;
case 3:
printch('2');
buffstr[i] = '2';
i++;
break;
case 4:
printch('3');
buffstr[i] = '3';
i++;
break;
case 5:
printch('4');
buffstr[i] = '4';
i++;
break;
case 6:
printch('5');
buffstr[i] = '5';
i++;
break;
case 7:
printch('6');
buffstr[i] = '6';
i++;
break;
case 8:
printch('7');
buffstr[i] = '7';
i++;
break;
case 9:
printch('8');
buffstr[i] = '8';
i++;
break;
case 10:
printch('9');
buffstr[i] = '9';
i++;
break;
case 11:
printch('0');
buffstr[i] = '0';
i++;
break;
case 12:
printch('-');
buffstr[i] = '-';
i++;
break;
case 13:
printch('=');
buffstr[i] = '=';
i++;
break;
case 14:
printch('\b');
i--;
buffstr[i] = 0;
break;
/* case 15:
printch('\t'); Tab button
buffstr[i] = '\t';
i++;
break;*/
case 16:
printch('q');
buffstr[i] = 'q';
i++;
break;
case 17:
printch('w');
buffstr[i] = 'w';
i++;
break;
case 18:
printch('e');
buffstr[i] = 'e';
i++;
break;
case 19:
printch('r');
buffstr[i] = 'r';
i++;
break;
case 20:
printch('t');
buffstr[i] = 't';
i++;
break;
case 21:
printch('y');
buffstr[i] = 'y';
i++;
break;
case 22:
printch('u');
buffstr[i] = 'u';
i++;
break;
case 23:
printch('i');
buffstr[i] = 'i';
i++;
break;
case 24:
printch('o');
buffstr[i] = 'o';
i++;
break;
case 25:
printch('p');
buffstr[i] = 'p';
i++;
break;
case 26:
printch('[');
buffstr[i] = '[';
i++;
break;
case 27:
printch(']');
buffstr[i] = ']';
i++;
break;
case 28:
// printch('\n');
// buffstr[i] = '\n';
i++;
reading = 0;
break;
/* case 29:
printch('q'); Left Control
buffstr[i] = 'q';
i++;
break;*/
case 30:
printch('a');
buffstr[i] = 'a';
i++;
break;
case 31:
printch('s');
buffstr[i] = 's';
i++;
break;
case 32:
printch('d');
buffstr[i] = 'd';
i++;
break;
case 33:
printch('f');
buffstr[i] = 'f';
i++;
break;
case 34:
printch('g');
buffstr[i] = 'g';
i++;
break;
case 35:
printch('h');
buffstr[i] = 'h';
i++;
break;
case 36:
printch('j');
buffstr[i] = 'j';
i++;
break;
case 37:
printch('k');
buffstr[i] = 'k';
i++;
break;
case 38:
printch('l');
buffstr[i] = 'l';
i++;
break;
case 39:
printch(';');
buffstr[i] = ';';
i++;
break;
case 40:
printch((char)44); // Single quote (')
buffstr[i] = (char)44;
i++;
break;
case 41:
printch((char)44); // Back tick (`)
buffstr[i] = (char)44;
i++;
break;
/* case 42: Left shift
printch('q');
buffstr[i] = 'q';
i++;
break;
case 43: \ (< for somekeyboards)
printch((char)92);
buffstr[i] = 'q';
i++;
break;*/
case 44:
printch('z');
buffstr[i] = 'z';
i++;
break;
case 45:
printch('x');
buffstr[i] = 'x';
i++;
break;
case 46:
printch('c');
buffstr[i] = 'c';
i++;
break;
case 47:
printch('v');
buffstr[i] = 'v';
i++;
break;
case 48:
printch('b');
buffstr[i] = 'b';
i++;
break;
case 49:
printch('n');
buffstr[i] = 'n';
i++;
break;
case 50:
printch('m');
buffstr[i] = 'm';
i++;
break;
case 51:
printch(',');
buffstr[i] = ',';
i++;
break;
case 52:
printch('.');
buffstr[i] = '.';
i++;
break;
case 53:
printch('/');
buffstr[i] = '/';
i++;
break;
case 54:
printch('.');
buffstr[i] = '.';
i++;
break;
case 55:
printch('/');
buffstr[i] = '/';
i++;
break;
/*case 56:
printch(' '); Right shift
buffstr[i] = ' ';
i++;
break;*/
case 57:
printch(' ');
buffstr[i] = ' ';
i++;
break;
}
}
}
buffstr[i] = 0;
return buffstr;
}
#endif
And at last the string.h(This has function to compare two strings.):
#ifndef STRING_H
#define STRING_H
#include "types.h"
uint16 strlength(string ch)
{
uint16 i = 1;
while(ch[i++]);
return --i;
}
uint8 strEql(string ch1,string ch2)
{
uint8 result = 1;
uint8 size = strlength(ch1);
if(size != strlength(ch2)) result =0;
else
{
uint8 i = 0;
for(i;i<=size;i++)
{
if(ch1[i] != ch2[i]) result = 0;
}
}
return result;
}
#endif
But the problem is that even if enter the correct command like 'cmd', it only sometimes says 'No command found: cm' and sometimes it works! It goes sometimes correct and says: 'You're already in cmd!'
Also, it is recognizing it as 'cm' not 'cmd'.
And if I write in kernel.c: "print("Hello");" then it will print: 'Hell' not 'Hello'! It misses the last character.
I don't know what's wrong with my program.
I use gcc to compile it, platform is Linux Ubuntu. The sometimes work and sometimes not. But if I compile my kernel with Windows the command never works.
Please help! Any help will be greatly appreciated.

Your string length function is wrong:
uint16 strlength(string ch)
{
uint16 i = 1;
while(ch[i++]);
return --i;
}
Assuming the string is "cmd", then you start and check if the second character, m, is null, then the third, then finally the fourth is null. i starts off with 1 and increases up to 3, and finally gets decremented to 2.
Also it would fail on zero length strings.
The consequence is, that you are not printing enough in your print function.
unit16 strlength(string ch) {
unit16 l = 0;
while (ch[l]) {
++l;
}
return l;
}
To find out why the comparison fails I'd need to know what type string actually is.
If it's a char *, then this is actually undefined behaviour, as your writing into some random memory.
If it's a char [N] then out won't work either, because that array decays to a pointer on return. And that pointer points to a local variable with automatic storage, so it is no longer valid after function return.
OK, it's a pointer. Pointers point to memory, where you then store the actual data. To have this working you need
Memory to store the data to
Set the pointer to point to that memory.
Normally one would allocate memory via malloc, but in the context of operating system development you'd first have to implement that yourself.
You cold use a buffer with automatic storage (on the stack) in the caller:
char buffer[20];
size_t num_read = read_into(buffer, 20);
// pass the pointer to the memory for the data plus the maximal characters this buffer can hold.
size_t read_into (char * buffer, size_t max) {
// read up to Max characters into the
// buffer, don't forget to count the 0 at the end.
}
Judging from the rest of your code, you seem to be fairly new to C programming. While writing an operating system kernel is a fun task, you'll have more fun doing it when you understand the basics first.
Since you're writing to random memory locations with those uninitialised char * you don't know where you store the data. This could be "normal", free memory. Then everything will work as expected. But you could also write to memory mapped device information or even your own code, making it impossible to predict what might happen.

Related

switch/case not recognizing certain char inputs

I am creating a program for an online coding course which takes a poker hand and calculates the odds of the hand winning. I am currently in the early stages, writing the functions necessary to advance to the next part of the assignment. I have isolated my issues to one function, card_from_letters.
I created my-test-main.c to test card_from_letters. It creates two chars, representing the suit and value of a poker card. It then creates the struct testCard2.
A card_t struct has two components: an unsigned int for value, and an enumerated type for suit between SPADES and CLUBS. I cannot change the struct card_t.
int main(void) {
char sui = 'c';
char val = 'Q';
card_t testCard2 = card_from_letters(val, sui);
printf("last test! My card %c%c is value %d, and suit %d!\n", val, sui, testCard2.value, testCard2.suit);
}
This is my function card_from_letters:
card_t card_from_letters(char value_let, char suit_let) {
card_t temp;
assert(suit_let == 'd' ||'h' || 'c' || 's');
assert((value_let >= '2' && value_let <= '9') || (value_let = '0' || 'K' || 'Q' || 'J' || 'A'));
switch (value_let) {
case '2': temp.value = 2; break;
case '3': temp.value = 3; break;
case '4': temp.value = 4; break;
case '5': temp.value = 5; break;
case '6': temp.value = 6; break;
case '7': temp.value = 7; break;
case '8': temp.value = 8; break;
case '9': temp.value = 9; break;
case '0': temp.value = 10; break;
case 'K': temp.value = 13; break;
case 'Q': temp.value = 12; break;
case 'J': temp.value = 11; break;
case 'A': temp.value = 14; break;
}
switch (suit_let) {
case 's': temp.suit = SPADES; break;
case 'h': temp.suit = HEARTS; break;
case 'd': temp.suit = DIAMONDS; break;
case 'c': temp.suit = CLUBS; break;
}
return temp;
}
When val is set between '2' and '9', I am able to run card_from_letters with no problem. When I run my-test-main.c as it is here through gdb, the execution arrow makes it to switch (value_let), but then skips all cases and enters switch (suit_let), where it returns the correct suit. What am I missing here? How come card_from_letters works for chars 2 to 9, but not 0 to A?

Convert phone number from alphabetic to numeric form

I'm doing an exercise from KNKings book "C Programming: A modern approach" which involves converting a phone number in alphabetic form, entered by the user, into numeric form. When the program encounters non-alphabetic characters (digits or punctuations, for example), it should leave them unchanged. I may assume that the user only enters upper-case letters.
However, my program seems to produce garbage, to say the least.
#include <stdio.h>
#define MAX_SIZE 50
int main(void)
{
char alphabetic[MAX_SIZE], ch;
int num_elements = 0;
printf("Enter phone number: ");
int i;
for (i = 0; i < MAX_SIZE && ((ch = getchar()) != '\n'); i++){
alphabetic[i] = ch;
num_elements++;
}
for (i = 0; i <= num_elements; i++){
switch (alphabetic[i]){
case 'A': case 'B': case 'C': alphabetic[i] = '2'; break;
case 'D': case 'E': case 'F': alphabetic[i] = '3'; break;
case 'G': case 'H': case 'I': alphabetic[i] = '4'; break;
case 'J': case 'K': case 'L': alphabetic[i] = '5'; break;
case 'M': case 'N': case 'O': alphabetic[i] = '6'; break;
case 'P': case 'R': case 'S': alphabetic[i] = '7'; break;
case 'T': case 'U': case 'V': alphabetic[i] = '8'; break;
case 'W': case 'X': case 'Y': alphabetic[i] = '9'; break;
default: break;
}
}
printf("%s\n", alphabetic);
return 0;
}
In particular, I enter: COLLECT-800.
It outputs something like this: u░#■   ║k ╩
What did I do wrong?
You have the right idea, but there are two things missing in your program:
Most importantly, the null terminator at the end of the string. After your for loop in which you read the number, add the line:
alphabetic[i] = '\0';
If the user enters lowercase letters, they are ignored in the switch statement. To get around this, include <ctype.h> and change the switch quantity from alphabetic[i] to toupper(alphabetic[i]). Calling toupper on an already upper case letter is benign.
You're not putting a null-terminator anywhere so it's undefined behavior when you read the string regardless of whether you modified it afterwards. Put this line:
alphabetic[num_elements] = 0;
After your for (i = 0; i < MAX_SIZE &&... loop.
Personally, I wouldn't do the getchar loop and instead read in the string like this:
scanf("%49s", alphabetic); // reads in a string up to 50 characters
for (i = 0; alphabetic[i]; i++) { ...

unexpected output from switch statement in c program [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I'm getting output of a - 0000520 when I input a while i should get 0001010 as per the code I've assigned. Also the default runs every time (tested using a printf statement) for unexplained reason. My code is here:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int splitWord(char* word, int count);
int sunCode(char letter);
int main()
{
char inputString[100];
char splitStrings[10][10];
int i, j, count;
printf("Enter the message.\n");
fgets(inputString, 100, stdin);
j = count = 0;
for (i = 0; i <= (strlen(inputString)); i++) {
if (inputString[i] == ' ' || inputString[i] == '\0') {
splitStrings[count][j] = '\0';
count++;
j = 0;
}
else {
splitStrings[count][j] = inputString[i];
j++;
}
}
printf("\nOriginal String is: %s\n", inputString);
for (i = 0; i < count; i++) {
/*for(j=0;j<=strlen(splitStrings[i]);j++){
printf("%s",splitStrings[i][j]);
}*/
splitWord(splitStrings[i], count);
}
return 0;
}
int splitWord(char* word, int count)
{
int i;
int strLength = strlen(word);
for (i = 0; i <= strLength; i++) {
sunCode(word[i]);
// printf("%c\n",word[i]);
}
return 0;
}
int sunCode(char letter)
{
char letr = tolower(letter);
int code = 0;
switch (letr) {
case '0':
code = 0000000;
break;
case '1':
code = 0000001;
break;
case '2':
code = 0000010;
break;
case '3':
code = 0000011;
break;
case '4':
code = 0000100;
break;
case '5':
code = 0000101;
break;
case '6':
code = 0000110;
break;
case '7':
code = 0000111;
break;
case '8':
code = 0001000;
break;
case '9':
code = 0001001;
break;
case 'a':
code = 0001010;
break;
case 'b':
code = 0001011;
break;
case 'c':
code = 0001100;
break;
case 'd':
code = 0001101;
break;
case 'e':
code = 0001110;
break;
case 'f':
code = 0001111;
break;
case 'g':
code = 0010000;
break;
case 'h':
code = 0010001;
break;
case 'i':
code = 0010010;
break;
case 'j':
code = 0010011;
break;
case 'k':
code = 0010100;
break;
case 'l':
code = 0010101;
break;
case 'm':
code = 0010110;
break;
case 'n':
code = 0010111;
break;
case 'o':
code = 0011000;
break;
case 'p':
code = 0011001;
break;
case 'q':
code = 0011010;
break;
case 'r':
code = 0011011;
break;
case 's':
code = 0011100;
break;
case 't':
code = 0011101;
break;
case 'u':
code = 0011110;
break;
case 'v':
code = 0011111;
break;
case 'w':
code = -010000;
break;
case 'x':
code = 010001;
break;
case 'y':
code = 010010;
break;
case 'z':
code = 010011;
break;
case ' ':
code = 45;
printf("\nis space\n");
break;
default:
break;
}
printf("%c - %07d\n", letr, code);
}
I tried to see if it's giving ASCII values (it isn't)
the letter is being passed properly in the sunCode function (it is)
I do not understand why it is behaving like this, verified the syntax and conditions of switch too.
I am using gcc 7.3.0 on Ubuntu.
Leading zeros indicate that the number is expressed in octal, or base 8; thus, 010 = 8.
https://stackoverflow.com/a/1661378/10479742
0001010 in octal is 520 in decimal, and that's why you get that result. Either remove leading zeros, or change code to string.

LC-3 to Hexadecimal

This program takes the input
1283
5105
and prints out the following, I was wondering how to do it the opposite way around so to take the LC-3 instruction as the input and display it in Hexadecimal as I've been stuck on that for quite awhile. Any help would be great !
`add r1,r2,r3
and r0,r4,r5`
 
#include<stdio.h>
#include<string.h>
#include<ctype.h>
int main(int arga, char *argb[]){
int str; //string
int firstReg=0;
int secondReg=0;
int opCode=0;
int reg=0; //register
char hexa[7]; //hexadecimal value
FILE *fp;
fp = fopen(argb[1],"r");
// Statement 1
while((fscanf(fp,"%s",hexa))!=EOF){
int x =0;
str = 0;
// Statement 2
for (;x<=3;x++){
switch(hexa[x]){
case '0': str = str|0;
break;
case '1': str = str|1;
break;
case '2': str = str|2;
break;
case '3': str = str|3;
break;
case '4': str = str|4;
break;
case '5': str = str|5;
break;
case '6': str = str|6;
break;
case '7': str = str|7;
break;
case '8': str = str|8;
break;
case '9': str = str|9;
break;
case 'a': str = str|10;
break;
case 'b': str = str|11;
break;
case 'c': str = str|12;
break;
case 'd': str = str|13;
break;
case 'e': str = str|14;
break;
case 'f': str = str|15;
break;
default: printf("\nInvalid hexadecimal digit %c ",hexa[x]); return 0;
}
if(x != 3){
str = str <<4;
}
}
opCode = str&(15<<12);
opCode = opCode>>12;
// Statement 3
if(opCode == 5){
printf("and");
reg= str&(7<<9);
reg= reg>>9;
printf(" r%d",reg);
firstReg =str & (7<<6);
firstReg= firstReg>>6;
printf(", r%d",firstReg);
secondReg = str &(7);
printf(", r%d",secondReg);
printf("\n");
}
// Statement 4
if(opCode == 1) {
printf("add");
reg= str&(7<<9);
reg= reg>>9;
printf(" r%d",reg);
firstReg =str & (7<<6);
firstReg= firstReg>>6;
printf(", r%d",firstReg);
secondReg = str &(7);
printf(", r%d",secondReg);
printf("\n");
}
}
fclose(fp);
return 0;
}

Unprinted characters attaching to string

I'm working on an encryption program for a class in C. I use modulo 27 math to perform the encryption. I add each encrypted character to an array but I've noticed that unprinted characters are also being added to my string at the end. I realized this when I checked the word count of the encrypted text and it contained more characters than the original text that was encrypted. Can anyone explain why this is happening? This is taking into account the newline at the end of the texts.
Plaintext = THE RED GOOSE FLIES AT MIDNIGHT STOP - wc is 37
Ciphertext = ACBVKWNOGMMMPQHNI XL QBJXDPNVIQVSNZN - wc is 40
//Go through each character of the plaintext
for (i = 0; i < size; i++)
{
//Convert the characters to an integer
PlainNums[i] = charInt(plaintext[i]);
KeyNums[i] = charInt(key[i]);
//Add the int from plain text and the key together
CipherNums[i] = PlainNums[i] + KeyNums[i];
if (CipherNums[i] > 27) //Wrap around if the number exceeds 27
{
CipherNums[i] -= 27;
}
CipherNums[i] = CipherNums[i] % 27; //Use modulo 27 math to generate a new integer
cipherText[i] = IntChar(CipherNums[i]);
}
int charInt(char c)
{
switch (c)
{
case 'A': return 0;
case 'B': return 1;
case 'C': return 2;
case 'D': return 3;
case 'E': return 4;
case 'F': return 5;
case 'G': return 6;
case 'H': return 7;
case 'I': return 8;
case 'J': return 9;
case 'K': return 10;
case 'L': return 11;
case 'M': return 12;
case 'N': return 13;
case 'O': return 14;
case 'P': return 15;
case 'Q': return 16;
case 'R': return 17;
case 'S': return 18;
case 'T': return 19;
case 'U': return 20;
case 'V': return 21;
case 'W': return 22;
case 'X': return 23;
case 'Y': return 24;
case 'Z': return 25;
case ' ': return 26;
default: return -1;
}
}
char IntChar(int n)
{
switch(n)
{
case 0: return 'A';
case 1: return 'B';
case 2: return 'C';
case 3: return 'D';
case 4: return 'E';
case 5: return 'F';
case 6: return 'G';
case 7: return 'H';
case 8: return 'I';
case 9: return 'J';
case 10: return 'K';
case 11: return 'L';
case 12: return 'M';
case 13: return 'N';
case 14: return 'O';
case 15: return 'P';
case 16: return 'Q';
case 17: return 'R';
case 18: return 'S';
case 19: return 'T';
case 20: return 'U';
case 21: return 'V';
case 22: return 'W';
case 23: return 'X';
case 24: return 'Y';
case 25: return 'Z';
case 26: return ' ';
default: return '!'; //error
}
}
Try adding cipherText[size] = '\0'; at the end of the loop to make sure the encoded string only contain the encoded data.
Initialize the cipherText before for loop using memset in your code like the following way.
memset(cipherText,0,sizeof(cipherText));
for (i = 0; i < size; i++)
{
//Convert the characters to an integer
PlainNums[i] = charInt(plaintext[i]);
//....
// rest of the code
You must need to include<string.h.
And it works.

Resources