diff --git a/doc/AstraKernelManual.pdf b/doc/AstraKernelManual.pdf index 1ac6c25..2f5fe47 100644 Binary files a/doc/AstraKernelManual.pdf and b/doc/AstraKernelManual.pdf differ diff --git a/doc/contents/datetime.tex b/doc/contents/datetime.tex index 4c9b793..b7615dd 100644 --- a/doc/contents/datetime.tex +++ b/doc/contents/datetime.tex @@ -2,7 +2,7 @@ \section{Timekeeping API} Provide calendar dates and clock time based on the on-chip RTC. -\subsection*{Overview} +\paragraph{Overview} \begin{itemize} \item Reads a 32-bit seconds-since-1970 counter (RTC register at `0x101e8000`). \item Exposes two APIs: @@ -35,30 +35,30 @@ \subsection*{Data Structure} Data Register(\textbf{RTCDR}). This is a 32 bit register, and therefore \underline{subject to the Year 2038 Problem}. -\subsection{API: \texttt{uint32\_t getdate(dateval *date\_struct)}} +\subsection{\texttt{uint32\_t getdate(dateval *date\_struct)}} Populate the provided \texttt{*date\_struct} with the current date in days, months, and years. -\subsubsection*{Parameters} +\paragraph{Parameters} \begin{itemize} \item \texttt{date\_struct} pointer to a \texttt{dateval} structure; if \texttt{NULL}, only the raw \textbf{RTC} counter is returned. \end{itemize} -\subsubsection*{Return Value} +\paragraph{Return Value} \begin{itemize} \item Returns number of seconds since epoch (\texttt{RTCDR}) as read from the hardware register. \end{itemize} -\subsection{API: \texttt{uint32\_t gettime(timeval *time\_struct)}} +\subsection{\texttt{uint32\_t gettime(timeval *time\_struct)}} Populate \texttt{*time\_struct} with the current click time in hours, minutes, and seconds. -\subsubsection*{Parameters} +\paragraph{Parameters} \begin{itemize} \item \texttt{time\_struct} pointer to a \texttt{timeval} structure; if \texttt{NULL}, only the raw \textbf{RTC} counter is returned. \end{itemize} -\subsubsection*{Return Value} +\paragraph{Return Value} \begin{itemize} \item Returns number of seconds since epoch (\texttt{RTCDR}) as read from the hardware register. \end{itemize} diff --git a/doc/contents/puts.tex b/doc/contents/print.tex similarity index 65% rename from doc/contents/puts.tex rename to doc/contents/print.tex index d79b522..4922e59 100644 --- a/doc/contents/puts.tex +++ b/doc/contents/print.tex @@ -1,10 +1,11 @@ % ------------------------------------------------ -% *** Section 2: I/O API *** +% *** Section 2: I/O \& Time Services *** % ------------------------------------------------ \newpage \chapter{I/O \& Time Services} -\section{UART Device Driver} +\section{UART Output API} + \subsubsection{Registers \& Constants} \begin{itemize} \item \textbf{UART0\_DR} (Data Register), \texttt{0x101f1000} @@ -12,22 +13,25 @@ \subsubsection{Registers \& Constants} \item \textbf{UART\_FR\_TXFF}, \textbf{UART\_FR\_RXFE} \end{itemize} -\subsection{API: \texttt{printf(char *s, ...)}} +\subsection{\texttt{printf(char *s, ...)}} + +\paragraph{Description} Sends a null-terminated format string over UART. If an incorrect datatype is given for a format specifier, \underline{the behavior is undefined}. If a format specifier is given without a matching argument, it is simply skipped when the string is outputted. The following format specifiers are supported: +\paragraph{Supported Format Specifiers} \begin{itemize} - \item \textbf{\%c}: Expects a single character. - \item \textbf{\%s}: Expects a null-terminated string. - \item \textbf{\%d}: For 32-bit signed integers in the range \texttt{-2147483648} to \texttt{2147483647}. - \item \textbf{\%ld}: For 64-bit signed integers in the range \texttt{-9223372036854775808} to \texttt{9223372036854775807}, excluding the range specified above, for \textbf{\%d}. - \item \textbf{\%lu}: For 64-bit unsigned integers in the range \texttt{2147483648} to \texttt{18446744073709551615}. - \item \textbf{\%x} and \textbf{\%X}: For 32-bit unsigned integers in the range \texttt{0} to \texttt{2147483647}, where the case of \texttt{x} determines the case of the hexadecimal digits (\texttt{a-f} or \texttt{A-F}). - \item \textbf{\%lx} and \textbf{\%lX}: For 64-bit unsigned integers printed in hexadecimal format. Has the same range as \textbf{\%lu}. The case of \texttt{x} determines the case of the hexadecimal digits (\texttt{a-f} or \texttt{A-F}). - \item \textbf{\%\%}: Outputs a '\%'. - \item \textbf{\%}: Outputs (null). This is a special case where the format specifier is not followed by any character, and it simply outputs nothing. + \item \texttt{\%c}: Expects a single character. + \item \texttt{\%s}: Expects a null-terminated string. + \item \texttt{\%d}: For 32-bit signed integers in the range \texttt{-2147483648} to \texttt{2147483647}. + \item \texttt{\%ld}: For 64-bit signed integers in the range \texttt{-9223372036854775808} to \texttt{9223372036854775807}, excluding the range specified above, for \textbf{\%d}. + \item \texttt{\%lu}: For 64-bit unsigned integers in the range \texttt{2147483648} to \texttt{18446744073709551615}. + \item \texttt{\%x}, \texttt{\%X}: For 32-bit unsigned integers in the range \texttt{0} to \texttt{2147483647}, where the case of \texttt{x} determines the case of the hexadecimal digits (\texttt{a-f} or \texttt{A-F}). + \item \texttt{\%lx}, \texttt{\%lX}: For 64-bit unsigned integers printed in hexadecimal format. Has the same range as \textbf{\%lu}. The case of \texttt{x} determines the case of the hexadecimal digits (\texttt{a-f} or \texttt{A-F}). + \item \texttt{\%\%}: Outputs a literal \texttt{\%}. + \item \texttt{\%}: If the format specifier is not followed by a valid character, prints \texttt{(null)}. \end{itemize} \begin{flushleft} @@ -35,7 +39,7 @@ \subsection{API: \texttt{printf(char *s, ...)}} range \texttt{-2147483648} to \texttt{2147483647} are passed as 32 bit integers and any integers not part of this range are passed as 64 bit integers \underline{by default}. If desired, integers of this range can be cast as \texttt{long long} or \texttt{unsigned long long} -for use with the format specifiers prefixed by \textbf{l}(ell). +for use with the format specifiers prefixed by the character \texttt{l}. \end{flushleft} \subsection*{Examples} diff --git a/doc/contents/string.tex b/doc/contents/string.tex new file mode 100644 index 0000000..03ecdf3 --- /dev/null +++ b/doc/contents/string.tex @@ -0,0 +1,71 @@ +\newpage +\section{String Manipulation API} +\subsection{\texttt{strcmp(const char *str\_1, const char *str\_2)}} + +\paragraph{Purpose} +Compares two null-terminated strings, character by character. + +\paragraph{Overview} +This function compares the characters of two strings (\texttt{ASCII values}), +\texttt{str\_1} and \texttt{str\_2}, one by one. It returns: + +\paragraph{Return Values} +\begin{itemize} + \item 0 if both strings are equal, + \item -1 if the first differing character in \texttt{str\_1} is less than that in \texttt{str\_2}, + \item 1 if the first differing character in \texttt{str\_1} is greater than that in \texttt{str\_2}. +\end{itemize} + +\paragraph{Behavior} +The comparison stops at the first difference or the null terminator. +Case sensitivity is observed. Behavior is undefined if either pointer is not a +valid null-terminated string. + +\subsection*{Examples} +\begin{lstlisting}[language=C, caption=String Comparison Example] + int result = strcmp("abc", "abc"); // Expect 0 + printf("Expect 0 -> %d\n", result); + + result = strcmp("abc", "abd"); // Expect -1 + printf("Expect -1 -> %d\n", result); + + result = strcmp("abc", "ABC"); // Expect 1 + printf("Expect 1 -> %d\n", result); +\end{lstlisting} + +\begin{note} +In the future, we could returning the difference between the first differing +characters, which would allow for more detailed comparisons. This would enable +users to understand how far apart the strings are in terms of character values. +\end{note} + +\subsection{\texttt{strlen(const char *str)}} + +\paragraph{Purpose} +Calculates the length of a null-terminated string. + +\paragraph{Overview} +This function counts the number of characters in a null-terminated string, +excluding the null terminator itself. It returns the length of the string as an +unsigned integer. This function uses pointer arithmetic to traverse the string, +performing mathematical operations directly on the pointer values. + +\paragraph{Return Values} +\begin{itemize} + \item The number of characters in the string, not including the null terminator. + \item 0 if the string is empty (i.e., the first character is the null terminator). +\end{itemize} + +\paragraph{Behavior} +The function iterates through the input string until the null terminator is found, returning +the number of characters preceding it. If the input pointer is not a valid +null-terminated string, the behavior is undefined. + +\subsection*{Examples} +\begin{lstlisting}[language=C, caption=String Length Example] + size_t result = strlen("abc"); // Expect 3 + printf("Expect len 3 -> %d\n", result); + + result = strlen(""); // Expect 0 + printf("Expect len 0 -> %d\n", result); +\end{lstlisting} diff --git a/doc/front/preface.tex b/doc/front/preface.tex index f6ce80f..21967a9 100644 --- a/doc/front/preface.tex +++ b/doc/front/preface.tex @@ -41,7 +41,7 @@ \section*{Preface} \addcontentsline{toc}{section}{About This Project} \section*{About This Project} -\subsection*{Resources} +\paragraph{Resources} To guide my learning and support development of AstraKernel, I am using the following resources, which are particularly valuable for foundational and practical understanding of OS design: @@ -50,26 +50,28 @@ \subsection*{Resources} \item \textbf{The Little Book About OS Development} by Erik Helin and Adam Renberg \end{itemize} -\subsection*{Acknowledgments \& Contributions} +\paragraph{Contributions} AstraKernel is an open source project, and I encourage contributions from anyone interested in improving, extending the kernel or simply experiment with it. I also encourage anyone to improve this documentation, as it is a work in progress. If you would like to contribute, please feel free to open an issue or pull request on the GitHub repository. +\\ \begin{info} You can join the Matrix Server \url{https://matrix.to/#/#sandboxscience:matrix.org} for general SandBox Science discussion as well as project-specific discussion such as AstraKernel development. \end{info} -\noindent +\paragraph{Acknowledgments} Specially thanks to the following individuals for their contributions: \begin{itemize} - \item \textbf{shade5144} (\url{https://github.com/shade5144}) for contributing the initial version of the \texttt{printf} - function as well as the documentation for it. + \item \textbf{shade5144} (\url{https://github.com/shade5144}) for contributing + the initial version of the \texttt{printf} and \texttt{datetime} function as + well as the documentation for them. \end{itemize} -\subsection*{Disclaimer} +\paragraph{Disclaimer} AstraKernel is currently in its early stages of development and is not intended for production use. It is primarily an educational and experimental project. The code is provided as-is, diff --git a/doc/main.tex b/doc/main.tex index c96288d..f862c0c 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -18,7 +18,8 @@ % % *** Main Content *** % % ----------------------------------------------------- \input{contents/introduction} -\input{contents/puts} +\input{contents/print} +\input{contents/string} \input{contents/datetime} \end{document} \ No newline at end of file diff --git a/include/string.h b/include/string.h new file mode 100644 index 0000000..216201d --- /dev/null +++ b/include/string.h @@ -0,0 +1,18 @@ +#ifndef STRING_H +#define STRING_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + int strcmp(const char *str_1, const char *str_2); + size_t strlen(const char *str); + +#ifdef __cplusplus +} +#endif + +#endif // STRING_H diff --git a/kernel/kernel.c b/kernel/kernel.c index f014545..f452f83 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -4,6 +4,7 @@ #include "datetime.h" #include "printf.h" #include "clear.h" +#include "string.h" static const char *banner[] = { "========================================\r\n", @@ -53,37 +54,50 @@ void kernel_main(void) switch (input_buffer[0]) { - case 'h': // Check for help command - printf("\nHelp:\n 'q' to exit\n 'h' for help\n 'c' to clear screen\n 't' to print current time\n 'd' to print current date\r\n"); - break; - case 'e': // TODO: This is for testing purposes. Remove once not needed - printf("%ld %ld %ld\n", 0, -9223372036854775808, 9223372036854775807); - printf("%d %d\n", 2147483647, -2147483648); - printf("%x %lx %lX %X\n", 2147483647, 2147483649, 2147483648, 1234); - printf("%lX %x %lx\n", 0x123456789abcdef0, 1234, 9223372036854775809); - printf("Name: %c\n", 'b'); - printf("Hello %s\n", "World"); - printf("100%%\n"); - break; - case 'q': // Check for exit command - printf("Exiting...\r\n"); - is_running = false; - break; - case 'c': // Check for clear screen command - clear(); - break; - - case 't': // Check for time command - gettime(&time_struct); - printf("Current time(GMT): %d:%d:%d\n", time_struct.hrs, time_struct.mins, time_struct.secs); - break; - case 'd': // Check for date command - getdate(&date_struct); - printf("Current date(MM-DD-YYYY): %d-%d-%d\n", date_struct.month, date_struct.day, date_struct.year); - break; - default: - printf("Unknown command. Type 'h' for help.\r\n"); - break; + case 'h': // Check for help command + printf("\nHelp:\n 'q' to exit\n 'h' for help\n 'c' to clear screen\n 't' to print current time\n 'd' to print current date\r\n"); + break; + case 'e': + int result = strcmp("abc", "abc"); // Expect 0 + printf("Expect 0 -> %d\n", result); + + result = strcmp("abc", "abd"); // Expect -1 + printf("Expect -1 -> %d\n", result); + + result = strcmp("abc", "ABC"); // Expect 1 + printf("Expect 1 -> %d\n", result); + + result = strcmp("ABC", "abc"); // Expect -1 + printf("Expect -1 -> %d\n", result); + + result = strcmp("\x01\x02\x03", "\x01\x02\x03"); // Expect 0 + printf("Expect 0 -> %d\n", result); + + result = strcmp("\x01\x02\x03", "\x01\x02\x04"); // Expect -1 + printf("Expect -1 -> %d\n", result); + + result = strcmp("\x01\x02\x04", "\x01\x02\x03"); // Expect 1 + printf("Expect 1 -> %d\n", result); + break; + case 'q': // Check for exit command + printf("Exiting...\r\n"); + is_running = false; + break; + case 'c': // Check for clear screen command + clear(); + break; + + case 't': // Check for time command + gettime(&time_struct); + printf("Current time(GMT): %d:%d:%d\n", time_struct.hrs, time_struct.mins, time_struct.secs); + break; + case 'd': // Check for date command + getdate(&date_struct); + printf("Current date(MM-DD-YYYY): %d-%d-%d\n", date_struct.month, date_struct.day, date_struct.year); + break; + default: + printf("Unknown command. Type 'h' for help.\r\n"); + break; } } } diff --git a/user/string.c b/user/string.c new file mode 100644 index 0000000..9ff0224 --- /dev/null +++ b/user/string.c @@ -0,0 +1,45 @@ +#include "string.h" + +/** + * @brief Compares two null-terminated strings lexicographically. + * + * @param str_1 Pointer to the first string to compare. + * @param str_2 Pointer to the second string to compare. + * + * @return int 0 if strings are equal, -1 if `str_1` < `str_2`, 1 if `str_1` > `str_2`. + */ +int strcmp(const char *str_1, const char *str_2) +{ + unsigned char ch1, ch2; + do + { + ch1 = *str_1++; + ch2 = *str_2++; + + if (ch1 != ch2) + { + // NOTE: If needed in the future, can return the difference between + // the strings rather than just -1 or 1 + return ch1 < ch2 ? -1 : 1; + } + + } while (ch1); + + return 0; +} + +/** + * @brief Calculates the length of a null-terminated string. + * + * @param str Pointer to the null-terminated string to be measured. + * @return The number of characters in the string, excluding the null terminator. + */ +size_t strlen(const char *str) +{ + const char *s = str; + while (*s) + { + ++s; + } + return s - str; +}