12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853 |
- //###########################################################################
- //
- // FILE: ustdlib.c
- //
- // TITLE: Simple standard library functions.
- //
- //###########################################################################
- // $TI Release: F2837xD Support Library v3.05.00.00 $
- // $Release Date: Tue Jun 26 03:15:23 CDT 2018 $
- // $Copyright:
- // Copyright (C) 2013-2018 Texas Instruments Incorporated - http://www.ti.com/
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions
- // are met:
- //
- // Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- //
- // Redistributions in binary form must reproduce the above copyright
- // notice, this list of conditions and the following disclaimer in the
- // documentation and/or other materials provided with the
- // distribution.
- //
- // Neither the name of Texas Instruments Incorporated nor the names of
- // its contributors may be used to endorse or promote products derived
- // from this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- // $
- //###########################################################################
- //
- // Included Files
- //
- #include <stdint.h>
- #include <stdbool.h>
- #include "driverlib/debug.h"
- #include "utils/ustdlib.h"
- //*****************************************************************************
- //
- //! \addtogroup ustdlib_api
- //! @{
- //
- //*****************************************************************************
- //
- // Globals
- //
- //
- // A mapping from an integer between 0 and 15 to its ASCII character
- // equivalent.
- //
- static const char * const g_pcHex = "0123456789abcdef";
- //
- // Functions
- //
- //*****************************************************************************
- //
- //! Copies a certain number of characters from one string to another.
- //!
- //! \param s1 is a pointer to the destination buffer into which characters
- //! are to be copied.
- //! \param s2 is a pointer to the string from which characters are to be
- //! copied.
- //! \param n is the number of characters to copy to the destination buffer.
- //!
- //! This function copies at most \e n characters from the string pointed to
- //! by \e s2 into the buffer pointed to by \e s1. If the end of \e s2 is found
- //! before \e n characters have been copied, remaining characters in \e s1
- //! will be padded with zeroes until \e n characters have been written. Note
- //! that the destination string will only be NULL terminated if the number of
- //! characters to be copied is greater than the length of \e s2.
- //!
- //! \return Returns \e s1.
- //
- //*****************************************************************************
- char *
- ustrncpy(char * restrict s1, const char * restrict s2, size_t n)
- {
- size_t count;
- //
- // Check the arguments.
- //
- ASSERT(s1);
- ASSERT(s2);
- //
- // Start at the beginning of the source string.
- //
- count = 0;
- //
- // Copy the source string until we run out of source characters or
- // destination space.
- //
- while(n && s2[count])
- {
- s1[count] = s2[count];
- count++;
- n--;
- }
- //
- // Pad the destination if we are not yet done.
- //
- while(n)
- {
- s1[count++] = (char)0;
- n--;
- }
- //
- // Pass the destination pointer back to the caller.
- //
- return(s1);
- }
- //*****************************************************************************
- //
- //! A simple vsnprintf function supporting \%c, \%d, \%p, \%s, \%u, \%x, and
- //! \%X.
- //!
- //! \param s points to the buffer where the converted string is stored.
- //! \param n is the size of the buffer.
- //! \param format is the format string.
- //! \param arg is the list of optional arguments, which depend on the
- //! contents of the format string.
- //!
- //! This function is very similar to the C library <tt>vsnprintf()</tt>
- //! function. Only the following formatting characters are supported:
- //!
- //! - \%c to print a character
- //! - \%d or \%i to print a decimal value
- //! - \%s to print a string
- //! - \%u to print an unsigned decimal value
- //! - \%x to print a hexadecimal value using lower case letters
- //! - \%X to print a hexadecimal value using lower case letters (not upper case
- //! letters as would typically be used)
- //! - \%p to print a pointer as a hexadecimal value
- //! - \%\% to print out a \% character
- //!
- //! For \%d, \%i, \%p, \%s, \%u, \%x, and \%X, an optional number may reside
- //! between the \% and the format character, which specifies the minimum number
- //! of characters to use for that value; if preceded by a 0 then the extra
- //! characters will be filled with zeros instead of spaces. For example,
- //! ``\%8d'' will use eight characters to print the decimal value with spaces
- //! added to reach eight; ``\%08d'' will use eight characters as well but will
- //! add zeroes instead of spaces.
- //!
- //! The type of the arguments after \e format must match the requirements of
- //! the format string. For example, if an integer was passed where a string
- //! was expected, an error of some kind will most likely occur.
- //!
- //! The \e n parameter limits the number of characters that will be
- //! stored in the buffer pointed to by \e s to prevent the possibility of
- //! a buffer overflow. The buffer size should be large enough to hold the
- //! expected converted output string, including the null termination character.
- //!
- //! The function will return the number of characters that would be converted
- //! as if there were no limit on the buffer size. Therefore it is possible for
- //! the function to return a count that is greater than the specified buffer
- //! size. If this happens, it means that the output was truncated.
- //!
- //! \return Returns the number of characters that were to be stored, not
- //! including the NULL termination character, regardless of space in the
- //! buffer.
- //
- //*****************************************************************************
- int
- uvsnprintf(char * restrict s, size_t n, const char * restrict format,
- va_list arg)
- {
- unsigned long ulIdx, ulValue, ulCount, ulBase, ulNeg;
- char *pcStr, cFill;
- int iConvertCount = 0;
- //
- // Check the arguments.
- //
- ASSERT(s);
- ASSERT(n);
- ASSERT(format);
- //
- // Adjust buffer size limit to allow one space for null termination.
- //
- if(n)
- {
- n--;
- }
- //
- // Initialize the count of characters converted.
- //
- iConvertCount = 0;
- //
- // Loop while there are more characters in the format string.
- //
- while(*format)
- {
- //
- // Find the first non-% character, or the end of the string.
- //
- for(ulIdx = 0; (format[ulIdx] != '%') && (format[ulIdx] != '\0');
- ulIdx++)
- {
- }
- //
- // Write this portion of the string to the output buffer. If there are
- // more characters to write than there is space in the buffer, then
- // only write as much as will fit in the buffer.
- //
- if(ulIdx > n)
- {
- ustrncpy(s, format, n);
- s += n;
- n = 0;
- }
- else
- {
- ustrncpy(s, format, ulIdx);
- s += ulIdx;
- n -= ulIdx;
- }
- //
- // Update the conversion count. This will be the number of characters
- // that should have been written, even if there was not room in the
- // buffer.
- //
- iConvertCount += ulIdx;
- //
- // Skip the portion of the format string that was written.
- //
- format += ulIdx;
- //
- // See if the next character is a %.
- //
- if(*format == '%')
- {
- //
- // Skip the %.
- //
- format++;
- //
- // Set the digit count to zero, and the fill character to space
- // (that is, to the defaults).
- //
- ulCount = 0;
- cFill = ' ';
- //
- // It may be necessary to get back here to process more characters.
- // Goto's aren't pretty, but effective. I feel extremely dirty for
- // using not one but two of the beasts.
- //
- again:
- //
- // Determine how to handle the next character.
- //
- switch(*format++)
- {
- //
- // Handle the digit characters.
- //
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- {
- //
- // If this is a zero, and it is the first digit, then the
- // fill character is a zero instead of a space.
- //
- if((format[-1] == '0') && (ulCount == 0))
- {
- cFill = '0';
- }
- //
- // Update the digit count.
- //
- ulCount *= 10;
- ulCount += format[-1] - '0';
- //
- // Get the next character.
- //
- goto again;
- }
- //
- // Handle the %c command.
- //
- case 'c':
- {
- //
- // Get the value from the varargs.
- //
- ulValue = va_arg(arg, unsigned long);
- //
- // Copy the character to the output buffer, if there is
- // room. Update the buffer size remaining.
- //
- if(n != 0)
- {
- *s++ = (char)ulValue;
- n--;
- }
- //
- // Update the conversion count.
- //
- iConvertCount++;
- //
- // This command has been handled.
- //
- break;
- }
- //
- // Handle the %d and %i commands.
- //
- case 'd':
- case 'i':
- {
- //
- // Get the value from the varargs.
- //
- ulValue = va_arg(arg, unsigned long);
- //
- // If the value is negative, make it positive and indicate
- // that a minus sign is needed.
- //
- if((long)ulValue < 0)
- {
- //
- // Make the value positive.
- //
- ulValue = -(long)ulValue;
- //
- // Indicate that the value is negative.
- //
- ulNeg = 1;
- }
- else
- {
- //
- // Indicate that the value is positive so that a
- // negative sign isn't inserted.
- //
- ulNeg = 0;
- }
- //
- // Set the base to 10.
- //
- ulBase = 10;
- //
- // Convert the value to ASCII.
- //
- goto convert;
- }
- //
- // Handle the %s command.
- //
- case 's':
- {
- //
- // Get the string pointer from the varargs.
- //
- pcStr = va_arg(arg, char *);
- //
- // Determine the length of the string.
- //
- for(ulIdx = 0; pcStr[ulIdx] != '\0'; ulIdx++)
- {
- }
- //
- // Update the convert count to include any padding that
- // should be necessary (regardless of whether we have space
- // to write it or not).
- //
- if(ulCount > ulIdx)
- {
- iConvertCount += (ulCount - ulIdx);
- }
- //
- // Copy the string to the output buffer. Only copy as much
- // as will fit in the buffer. Update the output buffer
- // pointer and the space remaining.
- //
- if(ulIdx > n)
- {
- ustrncpy(s, pcStr, n);
- s += n;
- n = 0;
- }
- else
- {
- ustrncpy(s, pcStr, ulIdx);
- s += ulIdx;
- n -= ulIdx;
- //
- // Write any required padding spaces assuming there is
- // still space in the buffer.
- //
- if(ulCount > ulIdx)
- {
- ulCount -= ulIdx;
- if(ulCount > n)
- {
- ulCount = n;
- }
- n = -ulCount;
- while(ulCount--)
- {
- *s++ = ' ';
- }
- }
- }
- //
- // Update the conversion count. This will be the number of
- // characters that should have been written, even if there
- // was not room in the buffer.
- //
- iConvertCount += ulIdx;
- //
- // This command has been handled.
- //
- break;
- }
- //
- // Handle the %u command.
- //
- case 'u':
- {
- //
- // Get the value from the varargs.
- //
- ulValue = va_arg(arg, unsigned long);
- //
- // Set the base to 10.
- //
- ulBase = 10;
- //
- // Indicate that the value is positive so that a minus sign
- // isn't inserted.
- //
- ulNeg = 0;
- //
- // Convert the value to ASCII.
- //
- goto convert;
- }
- //
- // Handle the %x and %X commands. Note that they are treated
- // identically; that is, %X will use lower case letters for a-f
- // instead of the upper case letters is should use. We also
- // alias %p to %x.
- //
- case 'x':
- case 'X':
- case 'p':
- {
- //
- // Get the value from the varargs.
- //
- ulValue = va_arg(arg, unsigned long);
- //
- // Set the base to 16.
- //
- ulBase = 16;
- //
- // Indicate that the value is positive so that a minus sign
- // isn't inserted.
- //
- ulNeg = 0;
- //
- // Determine the number of digits in the string version of
- // the value.
- //
- convert:
- for(ulIdx = 1;
- (((ulIdx * ulBase) <= ulValue) &&
- (((ulIdx * ulBase) / ulBase) == ulIdx));
- ulIdx *= ulBase, ulCount--)
- {
- }
- //
- // If the value is negative, reduce the count of padding
- // characters needed.
- //
- if(ulNeg)
- {
- ulCount--;
- }
- //
- // If the value is negative and the value is padded with
- // zeros, then place the minus sign before the padding.
- //
- if(ulNeg && (n != 0) && (cFill == '0'))
- {
- //
- // Place the minus sign in the output buffer.
- //
- *s++ = '-';
- n--;
- //
- // Update the conversion count.
- //
- iConvertCount++;
- //
- // The minus sign has been placed, so turn off the
- // negative flag.
- //
- ulNeg = 0;
- }
- //
- // See if there are more characters in the specified field
- // width than there are in the conversion of this value.
- //
- if((ulCount > 1) && (ulCount < 65536))
- {
- //
- // Loop through the required padding characters.
- //
- for(ulCount--; ulCount; ulCount--)
- {
- //
- // Copy the character to the output buffer if there
- // is room.
- //
- if(n != 0)
- {
- *s++ = cFill;
- n--;
- }
- //
- // Update the conversion count.
- //
- iConvertCount++;
- }
- }
- //
- // If the value is negative, then place the minus sign
- // before the number.
- //
- if(ulNeg && (n != 0))
- {
- //
- // Place the minus sign in the output buffer.
- //
- *s++ = '-';
- n--;
- //
- // Update the conversion count.
- //
- iConvertCount++;
- }
- //
- // Convert the value into a string.
- //
- for(; ulIdx; ulIdx /= ulBase)
- {
- //
- // Copy the character to the output buffer if there is
- // room.
- //
- if(n != 0)
- {
- *s++ = g_pcHex[(ulValue / ulIdx) % ulBase];
- n--;
- }
- //
- // Update the conversion count.
- //
- iConvertCount++;
- }
- //
- // This command has been handled.
- //
- break;
- }
- //
- // Handle the %% command.
- //
- case '%':
- {
- //
- // Simply write a single %.
- //
- if(n != 0)
- {
- *s++ = format[-1];
- n--;
- }
- //
- // Update the conversion count.
- //
- iConvertCount++;
- //
- // This command has been handled.
- //
- break;
- }
- //
- // Handle all other commands.
- //
- default:
- {
- //
- // Indicate an error.
- //
- if(n >= 5)
- {
- ustrncpy(s, "ERROR", 5);
- s += 5;
- n -= 5;
- }
- else
- {
- ustrncpy(s, "ERROR", n);
- s += n;
- n = 0;
- }
- //
- // Update the conversion count.
- //
- iConvertCount += 5;
- //
- // This command has been handled.
- //
- break;
- }
- }
- }
- }
- //
- // Null terminate the string in the buffer.
- //
- *s = 0;
- //
- // Return the number of characters in the full converted string.
- //
- return(iConvertCount);
- }
- //*****************************************************************************
- //
- //! A simple sprintf function supporting \%c, \%d, \%p, \%s, \%u, \%x, and \%X.
- //!
- //! \param s is the buffer where the converted string is stored.
- //! \param format is the format string.
- //! \param ... are the optional arguments, which depend on the contents of the
- //! format string.
- //!
- //! This function is very similar to the C library <tt>sprintf()</tt> function.
- //! Only the following formatting characters are supported:
- //!
- //! - \%c to print a character
- //! - \%d or \%i to print a decimal value
- //! - \%s to print a string
- //! - \%u to print an unsigned decimal value
- //! - \%x to print a hexadecimal value using lower case letters
- //! - \%X to print a hexadecimal value using lower case letters (not upper case
- //! letters as would typically be used)
- //! - \%p to print a pointer as a hexadecimal value
- //! - \%\% to print out a \% character
- //!
- //! For \%d, \%i, \%p, \%s, \%u, \%x, and \%X, an optional number may reside
- //! between the \% and the format character, which specifies the minimum number
- //! of characters to use for that value; if preceded by a 0 then the extra
- //! characters will be filled with zeros instead of spaces. For example,
- //! ``\%8d'' will use eight characters to print the decimal value with spaces
- //! added to reach eight; ``\%08d'' will use eight characters as well but will
- //! add zeros instead of spaces.
- //!
- //! The type of the arguments after \e format must match the requirements of
- //! the format string. For example, if an integer was passed where a string
- //! was expected, an error of some kind will most likely occur.
- //!
- //! The caller must ensure that the buffer \e s is large enough to hold the
- //! entire converted string, including the null termination character.
- //!
- //! \return Returns the count of characters that were written to the output
- //! buffer, not including the NULL termination character.
- //
- //*****************************************************************************
- int
- usprintf(char * restrict s, const char *format, ...)
- {
- va_list arg;
- int ret;
- //
- // Start the varargs processing.
- //
- va_start(arg, format);
- //
- // Call vsnprintf to perform the conversion. Use a large number for the
- // buffer size.
- //
- ret = uvsnprintf(s, 0xffff, format, arg);
- //
- // End the varargs processing.
- //
- va_end(arg);
- //
- // Return the conversion count.
- //
- return(ret);
- }
- //*****************************************************************************
- //
- //! A simple snprintf function supporting \%c, \%d, \%p, \%s, \%u, \%x, and
- //! \%X.
- //!
- //! \param s is the buffer where the converted string is stored.
- //! \param n is the size of the buffer.
- //! \param format is the format string.
- //! \param ... are the optional arguments, which depend on the contents of the
- //! format string.
- //!
- //! This function is very similar to the C library <tt>sprintf()</tt> function.
- //! Only the following formatting characters are supported:
- //!
- //! - \%c to print a character
- //! - \%d or \%i to print a decimal value
- //! - \%s to print a string
- //! - \%u to print an unsigned decimal value
- //! - \%x to print a hexadecimal value using lower case letters
- //! - \%X to print a hexadecimal value using lower case letters (not upper case
- //! letters as would typically be used)
- //! - \%p to print a pointer as a hexadecimal value
- //! - \%\% to print out a \% character
- //!
- //! For \%d, \%i, \%p, \%s, \%u, \%x, and \%X, an optional number may reside
- //! between the \% and the format character, which specifies the minimum number
- //! of characters to use for that value; if preceded by a 0 then the extra
- //! characters will be filled with zeros instead of spaces. For example,
- //! ``\%8d'' will use eight characters to print the decimal value with spaces
- //! added to reach eight; ``\%08d'' will use eight characters as well but will
- //! add zeros instead of spaces.
- //!
- //! The type of the arguments after \e format must match the requirements of
- //! the format string. For example, if an integer was passed where a string
- //! was expected, an error of some kind will most likely occur.
- //!
- //! The function will copy at most \e n - 1 characters into the buffer
- //! \e s. One space is reserved in the buffer for the null termination
- //! character.
- //!
- //! The function will return the number of characters that would be converted
- //! as if there were no limit on the buffer size. Therefore it is possible for
- //! the function to return a count that is greater than the specified buffer
- //! size. If this happens, it means that the output was truncated.
- //!
- //! \return Returns the number of characters that were to be stored, not
- //! including the NULL termination character, regardless of space in the
- //! buffer.
- //
- //*****************************************************************************
- int
- usnprintf(char * restrict s, size_t n, const char * restrict format, ...)
- {
- va_list arg;
- int ret;
- //
- // Start the varargs processing.
- //
- va_start(arg, format);
- //
- // Call vsnprintf to perform the conversion.
- //
- ret = uvsnprintf(s, n, format, arg);
- //
- // End the varargs processing.
- //
- va_end(arg);
- //
- // Return the conversion count.
- //
- return(ret);
- }
- //
- // This array contains the number of days in a year at the beginning of each
- // month of the year, in a non-leap year.
- //
- static const time_t g_psDaysToMonth[12] =
- {
- 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
- };
- //*****************************************************************************
- //
- //! Converts from seconds to calendar date and time.
- //!
- //! \param timer is the number of seconds.
- //! \param tm is a pointer to the time structure that is filled in with the
- //! broken down date and time.
- //!
- //! This function converts a number of seconds since midnight GMT on January 1,
- //! 1970 (traditional Unix epoch) into the equivalent month, day, year, hours,
- //! minutes, and seconds representation.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- ulocaltime(time_t timer, struct tm *tm)
- {
- time_t temp, months;
- //
- // Extract the number of seconds, converting time to the number of minutes.
- //
- temp = timer / 60;
- tm->tm_sec = timer - (temp * 60);
- timer = temp;
- //
- // Extract the number of minutes, converting time to the number of hours.
- //
- temp = timer / 60;
- tm->tm_min = timer - (temp * 60);
- timer = temp;
- //
- // Extract the number of hours, converting time to the number of days.
- //
- temp = timer / 24;
- tm->tm_hour = timer - (temp * 24);
- timer = temp;
- //
- // Compute the day of the week.
- //
- tm->tm_wday = (timer + 4) % 7;
- //
- // Compute the number of leap years that have occurred since 1968, the
- // first leap year before 1970. For the beginning of a leap year, cut the
- // month loop below at March so that the leap day is classified as February
- // 29 followed by March 1, instead of March 1 followed by another March 1.
- //
- timer += 366 + 365;
- temp = timer / ((4 * 365) + 1);
- if((timer - (temp * ((4 * 365) + 1))) > (31 + 28))
- {
- temp++;
- months = 12;
- }
- else
- {
- months = 2;
- }
- //
- // Extract the year.
- //
- tm->tm_year = ((timer - temp) / 365) + 68;
- timer -= ((tm->tm_year - 68) * 365) + temp;
- //
- // Extract the month.
- //
- for(temp = 0; temp < months; temp++)
- {
- if(g_psDaysToMonth[temp] > timer)
- {
- break;
- }
- }
- tm->tm_mon = temp - 1;
- //
- // Extract the day of the month.
- //
- tm->tm_mday = timer - g_psDaysToMonth[temp - 1] + 1;
- }
- //*****************************************************************************
- //
- //! Compares two time structures and determines if one is greater than,
- //! less than, or equal to the other.
- //!
- //! \param t1 is the first time structure to compare.
- //! \param t2 is the second time structure to compare.
- //!
- //! This function compares two time structures and returns a signed number
- //! to indicate the result of the comparison. If the time represented by
- //! \e t1 is greater than the time represented by \e t2 then a positive
- //! number is returned. Likewise if \e t1 is less than \e t2 then a
- //! negative number is returned. If the two times are equal then the function
- //! returns 0.
- //!
- //! \return Returns 0 if the two times are equal, +1 if \e t1 is greater
- //! than \e t2, and -1 if \e t1 is less than \e t2.
- //
- //*****************************************************************************
- static int
- ucmptime(struct tm *t1, struct tm *t2)
- {
- //
- // Compare each field in descending significance to determine if
- // greater than, less than, or equal.
- //
- if(t1->tm_year > t2->tm_year)
- {
- return(1);
- }
- else if(t1->tm_year < t2->tm_year)
- {
- return(-1);
- }
- else if(t1->tm_mon > t2->tm_mon)
- {
- return(1);
- }
- else if(t1->tm_mon < t2->tm_mon)
- {
- return(-1);
- }
- else if(t1->tm_mday > t2->tm_mday)
- {
- return(1);
- }
- else if(t1->tm_mday < t2->tm_mday)
- {
- return(-1);
- }
- else if(t1->tm_hour > t2->tm_hour)
- {
- return(1);
- }
- else if(t1->tm_hour < t2->tm_hour)
- {
- return(-1);
- }
- else if(t1->tm_min > t2->tm_min)
- {
- return(1);
- }
- else if(t1->tm_min < t2->tm_min)
- {
- return(-1);
- }
- else if(t1->tm_sec > t2->tm_sec)
- {
- return(1);
- }
- else if(t1->tm_sec < t2->tm_sec)
- {
- return(-1);
- }
- else
- {
- //
- // Reaching this branch of the conditional means that all of the
- // fields are equal, and thus the two times are equal.
- //
- return(0);
- }
- }
- //*****************************************************************************
- //
- //! Converts calendar date and time to seconds.
- //!
- //! \param timeptr is a pointer to the time structure that is filled in with
- //! the broken down date and time.
- //!
- //! This function converts the date and time represented by the \e timeptr
- //! structure pointer to the number of seconds since midnight GMT on January 1,
- //! 1970 (traditional Unix epoch).
- //!
- //! \return Returns the calendar time and date as seconds. If the conversion
- //! was not possible then the function returns (uint32_t)(-1).
- //
- //*****************************************************************************
- time_t
- umktime(struct tm *timeptr)
- {
- struct tm sTimeGuess;
- unsigned long ulTimeGuess = 0x80000000;
- unsigned long ulAdjust = 0x40000000;
- int iSign;
- //
- // Seed the binary search with the first guess.
- //
- ulocaltime(ulTimeGuess, &sTimeGuess);
- iSign = ucmptime(timeptr, &sTimeGuess);
- //
- // While the time is not yet found, execute a binary search.
- //
- while(iSign && ulAdjust)
- {
- //
- // Adjust the time guess up or down depending on the result of the
- // last compare.
- //
- ulTimeGuess = ((iSign > 0) ? (ulTimeGuess + ulAdjust) :
- (ulTimeGuess - ulAdjust));
- ulAdjust /= 2;
- //
- // Compare the new time guess against the time pointed at by the
- // function parameters.
- //
- ulocaltime(ulTimeGuess, &sTimeGuess);
- iSign = ucmptime(timeptr, &sTimeGuess);
- }
- //
- // If the above loop was exited with iSign == 0, that means that the
- // time in seconds was found, so return that value to the caller.
- //
- if(iSign == 0)
- {
- return(ulTimeGuess);
- }
- //
- // Otherwise the time could not be converted so return an error.
- //
- else
- {
- return((unsigned long)-1);
- }
- }
- //*****************************************************************************
- //
- //! Converts a string into its numeric equivalent.
- //!
- //! \param nptr is a pointer to the string containing the integer.
- //! \param endptr is a pointer that will be set to the first character past
- //! the integer in the string.
- //! \param base is the radix to use for the conversion; can be zero to
- //! auto-select the radix or between 2 and 16 to explicitly specify the radix.
- //!
- //! This function is very similar to the C library <tt>strtoul()</tt> function.
- //! It scans a string for the first token (that is, non-white space) and
- //! converts the value at that location in the string into an integer value.
- //!
- //! \return Returns the result of the conversion.
- //
- //*****************************************************************************
- unsigned long
- ustrtoul(const char * restrict nptr, const char ** restrict endptr, int base)
- {
- unsigned long ulRet, ulDigit, ulNeg, ulValid;
- const char *pcPtr;
- //
- // Check the arguments.
- //
- ASSERT(nptr);
- ASSERT((base == 0) || ((base > 1) && (base <= 16)));
- //
- // Initially, the result is zero.
- //
- ulRet = 0;
- ulNeg = 0;
- ulValid = 0;
- //
- // Skip past any leading white space.
- //
- pcPtr = nptr;
- while((*pcPtr == ' ') || (*pcPtr == '\t'))
- {
- pcPtr++;
- }
- //
- // Take a leading + or - from the value.
- //
- if(*pcPtr == '-')
- {
- ulNeg = 1;
- pcPtr++;
- }
- else if(*pcPtr == '+')
- {
- pcPtr++;
- }
- //
- // See if the radix was not specified, or is 16, and the value starts with
- // "0x" or "0X" (to indicate a hex value).
- //
- if(((base == 0) || (base == 16)) && (*pcPtr == '0') &&
- ((pcPtr[1] == 'x') || (pcPtr[1] == 'X')))
- {
- //
- // Skip the leading "0x".
- //
- pcPtr += 2;
- //
- // Set the radix to 16.
- //
- base = 16;
- }
- //
- // See if the radix was not specified.
- //
- if(base == 0)
- {
- //
- // See if the value starts with "0".
- //
- if(*pcPtr == '0')
- {
- //
- // Values that start with "0" are assumed to be radix 8.
- //
- base = 8;
- }
- else
- {
- //
- // Otherwise, the values are assumed to be radix 10.
- //
- base = 10;
- }
- }
- //
- // Loop while there are more valid digits to consume.
- //
- while(1)
- {
- //
- // See if this character is a number.
- //
- if((*pcPtr >= '0') && (*pcPtr <= '9'))
- {
- //
- // Convert the character to its integer equivalent.
- //
- ulDigit = *pcPtr++ - '0';
- }
- //
- // Otherwise, see if this character is an upper case letter.
- //
- else if((*pcPtr >= 'A') && (*pcPtr <= 'Z'))
- {
- //
- // Convert the character to its integer equivalent.
- //
- ulDigit = *pcPtr++ - 'A' + 10;
- }
- //
- // Otherwise, see if this character is a lower case letter.
- //
- else if((*pcPtr >= 'a') && (*pcPtr <= 'z'))
- {
- //
- // Convert the character to its integer equivalent.
- //
- ulDigit = *pcPtr++ - 'a' + 10;
- }
- //
- // Otherwise, this is not a valid character.
- //
- else
- {
- //
- // Stop converting this value.
- //
- break;
- }
- //
- // See if this digit is valid for the chosen radix.
- //
- if(ulDigit >= base)
- {
- //
- // Since this was not a valid digit, move the pointer back to the
- // character that therefore should not have been consumed.
- //
- pcPtr--;
- //
- // Stop converting this value.
- //
- break;
- }
- //
- // Add this digit to the converted value.
- //
- ulRet *= base;
- ulRet += ulDigit;
- //
- // Since a digit has been added, this is now a valid result.
- //
- ulValid = 1;
- }
- //
- // Set the return string pointer to the first character not consumed.
- //
- if(endptr)
- {
- *endptr = ulValid ? pcPtr : nptr;
- }
- //
- // Return the converted value.
- //
- return(ulNeg ? (0 - ulRet) : ulRet);
- }
- //
- // An array of the value of ten raised to the power-of-two exponents. This is
- // used for converting the decimal exponent into the floating-point value of
- // 10^exp.
- //
- static const float g_pfExponents[] =
- {
- 1.0e+01,
- 1.0e+02,
- 1.0e+04,
- 1.0e+08,
- 1.0e+16,
- 1.0e+32,
- };
- //*****************************************************************************
- //
- //! Converts a string into its floating-point equivalent.
- //!
- //! \param nptr is a pointer to the string containing the floating-point
- //! value.
- //! \param endptr is a pointer that will be set to the first character past
- //! the floating-point value in the string.
- //!
- //! This function is very similar to the C library <tt>strtof()</tt> function.
- //! It scans a string for the first token (that is, non-white space) and
- //! converts the value at that location in the string into a floating-point
- //! value.
- //!
- //! \return Returns the result of the conversion.
- //
- //*****************************************************************************
- float
- ustrtof(const char *nptr, const char **endptr)
- {
- unsigned long ulNeg, ulExp, ulExpNeg, ulValid, ulIdx;
- float fRet, fDigit, fExp;
- const char *pcPtr;
- //
- // Check the arguments.
- //
- ASSERT(nptr);
- //
- // Initially, the result is zero.
- //
- fRet = 0;
- ulNeg = 0;
- ulValid = 0;
- //
- // Skip past any leading white space.
- //
- pcPtr = nptr;
- while((*pcPtr == ' ') || (*pcPtr == '\t'))
- {
- pcPtr++;
- }
- //
- // Take a leading + or - from the value.
- //
- if(*pcPtr == '-')
- {
- ulNeg = 1;
- pcPtr++;
- }
- else if(*pcPtr == '+')
- {
- pcPtr++;
- }
- //
- // Loop while there are valid digits to consume.
- //
- while((*pcPtr >= '0') && (*pcPtr <= '9'))
- {
- //
- // Add this digit to the converted value.
- //
- fRet *= 10;
- fRet += *pcPtr++ - '0';
- //
- // Since a digit has been added, this is now a valid result.
- //
- ulValid = 1;
- }
- //
- // See if the next character is a period and the character after that is a
- // digit, indicating the start of the fractional portion of the value.
- //
- if((*pcPtr == '.') && (pcPtr[1] >= '0') && (pcPtr[1] <= '9'))
- {
- //
- // Skip the period.
- //
- pcPtr++;
- //
- // Loop while there are valid fractional digits to consume.
- //
- fDigit = 0.1;
- while((*pcPtr >= '0') && (*pcPtr <= '9'))
- {
- //
- // Add this digit to the converted value.
- //
- fRet += (*pcPtr++ - '0') * fDigit;
- fDigit /= (float)10.0;
- //
- // Since a digit has been added, this is now a valid result.
- //
- ulValid = 1;
- }
- }
- //
- // See if the next character is an "e" and a valid number has been
- // converted, indicating the start of the exponent.
- //
- if(((pcPtr[0] == 'e') || (pcPtr[0] == 'E')) && (ulValid == 1) &&
- (((pcPtr[1] >= '0') && (pcPtr[1] <= '9')) ||
- (((pcPtr[1] == '+') || (pcPtr[1] == '-')) &&
- (pcPtr[2] >= '0') && (pcPtr[2] <= '9'))))
- {
- //
- // Skip the "e".
- //
- pcPtr++;
- //
- // Take a leading + or - from the exponent.
- //
- ulExpNeg = 0;
- if(*pcPtr == '-')
- {
- ulExpNeg = 1;
- pcPtr++;
- }
- else if(*pcPtr == '+')
- {
- pcPtr++;
- }
- //
- // Loop while there are valid digits in the exponent.
- //
- ulExp = 0;
- while((*pcPtr >= '0') && (*pcPtr <= '9'))
- {
- //
- // Add this digit to the converted value.
- //
- ulExp *= 10;
- ulExp += *pcPtr++ - '0';
- }
- //
- // Raise ten to the power of the exponent. Do this via binary
- // decomposition; for each binary bit set in the exponent, multiply the
- // floating-point representation by ten raised to that binary value
- // (extracted from the table above).
- //
- fExp = 1;
- for(ulIdx = 0; ulIdx < 7; ulIdx++)
- {
- if(ulExp & (1 << ulIdx))
- {
- fExp *= g_pfExponents[ulIdx];
- }
- }
- //
- // If the exponent is negative, then the exponent needs to be inverted.
- //
- if(ulExpNeg == 1)
- {
- fExp = 1 / fExp;
- }
- //
- // Multiply the result by the computed exponent value.
- //
- fRet *= fExp;
- }
- //
- // Set the return string pointer to the first character not consumed.
- //
- if(endptr)
- {
- *endptr = ulValid ? pcPtr : nptr;
- }
- //
- // Return the converted value.
- //
- return(ulNeg ? (0 - fRet) : fRet);
- }
- //*****************************************************************************
- //
- //! Returns the length of a null-terminated string.
- //!
- //! \param s is a pointer to the string whose length is to be found.
- //!
- //! This function is very similar to the C library <tt>strlen()</tt> function.
- //! It determines the length of the null-terminated string passed and returns
- //! this to the caller.
- //!
- //! This implementation assumes that single byte character strings are passed
- //! and will return incorrect values if passed some UTF-8 strings.
- //!
- //! \return Returns the length of the string pointed to by \e s.
- //
- //*****************************************************************************
- size_t
- ustrlen(const char *s)
- {
- size_t len;
- //
- // Check the arguments.
- //
- ASSERT(s);
- //
- // Initialize the length.
- //
- len = 0;
- //
- // Step through the string looking for a zero character (marking its end).
- //
- while(s[len])
- {
- //
- // Zero not found so move on to the next character.
- //
- len++;
- }
- return(len);
- }
- //*****************************************************************************
- //
- //! Finds a substring within a string.
- //!
- //! \param s1 is a pointer to the string that will be searched.
- //! \param s2 is a pointer to the substring that is to be found within
- //! \e s1.
- //!
- //! This function is very similar to the C library <tt>strstr()</tt> function.
- //! It scans a string for the first instance of a given substring and returns
- //! a pointer to that substring. If the substring cannot be found, a NULL
- //! pointer is returned.
- //!
- //! \return Returns a pointer to the first occurrence of \e s2 within
- //! \e s1 or NULL if no match is found.
- //
- //*****************************************************************************
- char *
- ustrstr(const char *s1, const char *s2)
- {
- size_t n;
- //
- // Get the length of the string to be found.
- //
- n = ustrlen(s2);
- //
- // Loop while we have not reached the end of the string.
- //
- while(*s1)
- {
- //
- // Check to see if the substring appears at this position.
- //
- if(ustrncmp(s2, s1, n) == 0)
- {
- //
- // It does so return the pointer.
- //
- return((char *)s1);
- }
- //
- // Move to the next position in the string being searched.
- //
- s1++;
- }
- //
- // We reached the end of the string without finding the substring so
- // return NULL.
- //
- return((char *)0);
- }
- //*****************************************************************************
- //
- //! Compares two strings without regard to case.
- //!
- //! \param s1 points to the first string to be compared.
- //! \param s2 points to the second string to be compared.
- //! \param n is the maximum number of characters to compare.
- //!
- //! This function is very similar to the C library <tt>strncasecmp()</tt>
- //! function. It compares at most \e n characters of two strings without
- //! regard to case. The comparison ends if a terminating NULL character is
- //! found in either string before \e n characters are compared. In this case,
- //! the shorter string is deemed the lesser.
- //!
- //! \return Returns 0 if the two strings are equal, -1 if \e s1 is less
- //! than \e s2 and 1 if \e s1 is greater than \e s2.
- //
- //*****************************************************************************
- int
- ustrncasecmp(const char *s1, const char *s2, size_t n)
- {
- char c1, c2;
- //
- // Loop while there are more characters to compare.
- //
- while(n)
- {
- //
- // If we reached a NULL in both strings, they must be equal so
- // we end the comparison and return 0
- //
- if(!*s1 && !*s2)
- {
- return(0);
- }
- //
- // Lower case the characters at the current position before we compare.
- //
- c1 = (((*s1 >= 'A') && (*s1 <= 'Z')) ? (*s1 + ('a' - 'A')) : *s1);
- c2 = (((*s2 >= 'A') && (*s2 <= 'Z')) ? (*s2 + ('a' - 'A')) : *s2);
- //
- // Compare the two characters and, if different, return the relevant
- // return code.
- //
- if(c2 < c1)
- {
- return(1);
- }
- if(c1 < c2)
- {
- return(-1);
- }
- //
- // Move on to the next character.
- //
- s1++;
- s2++;
- n--;
- }
- //
- // If we fall out, the strings must be equal for at least the first n
- // characters so return 0 to indicate this.
- //
- return(0);
- }
- //*****************************************************************************
- //
- //! Compares two strings without regard to case.
- //!
- //! \param s1 points to the first string to be compared.
- //! \param s2 points to the second string to be compared.
- //!
- //! This function is very similar to the C library <tt>strcasecmp()</tt>
- //! function. It compares two strings without regard to case. The comparison
- //! ends if a terminating NULL character is found in either string. In this
- //! case, the int16_ter string is deemed the lesser.
- //!
- //! \return Returns 0 if the two strings are equal, -1 if \e s1 is less
- //! than \e s2 and 1 if \e s1 is greater than \e s2.
- //
- //*****************************************************************************
- int
- ustrcasecmp(const char *s1, const char *s2)
- {
- //
- // Just let ustrncasecmp() handle this.
- //
- return(ustrncasecmp(s1, s2, (size_t)-1));
- }
- //*****************************************************************************
- //
- //! Compares two strings.
- //!
- //! \param s1 points to the first string to be compared.
- //! \param s2 points to the second string to be compared.
- //! \param n is the maximum number of characters to compare.
- //!
- //! This function is very similar to the C library <tt>strncmp()</tt> function.
- //! It compares at most \e n characters of two strings taking case into
- //! account. The comparison ends if a terminating NULL character is found in
- //! either string before \e n characters are compared. In this case, the
- //! int16_ter string is deemed the lesser.
- //!
- //! \return Returns 0 if the two strings are equal, -1 if \e s1 is less
- //! than \e s2 and 1 if \e s1 is greater than \e s2.
- //
- //*****************************************************************************
- int
- ustrncmp(const char *s1, const char *s2, size_t n)
- {
- //
- // Loop while there are more characters.
- //
- while(n)
- {
- //
- // If we reached a NULL in both strings, they must be equal so we end
- // the comparison and return 0
- //
- if(!*s1 && !*s2)
- {
- return(0);
- }
- //
- // Compare the two characters and, if different, return the relevant
- // return code.
- //
- if(*s2 < *s1)
- {
- return(1);
- }
- if(*s1 < *s2)
- {
- return(-1);
- }
- //
- // Move on to the next character.
- //
- s1++;
- s2++;
- n--;
- }
- //
- // If we fall out, the strings must be equal for at least the first n
- // characters so return 0 to indicate this.
- //
- return(0);
- }
- //*****************************************************************************
- //
- //! Compares two strings.
- //!
- //! \param s1 points to the first string to be compared.
- //! \param s2 points to the second string to be compared.
- //!
- //! This function is very similar to the C library <tt>strcmp()</tt>
- //! function. It compares two strings, taking case into account. The
- //! comparison ends if a terminating NULL character is found in either string.
- //! In this case, the int16_ter string is deemed the lesser.
- //!
- //! \return Returns 0 if the two strings are equal, -1 if \e s1 is less
- //! than \e s2 and 1 if \e s1 is greater than \e s2.
- //
- //*****************************************************************************
- int
- ustrcmp(const char *s1, const char *s2)
- {
- //
- // Pass this on to ustrncmp.
- //
- return(ustrncmp(s1, s2, (size_t)-1));
- }
- //
- // Random Number Generator Seed Value
- //
- static unsigned int g_iRandomSeed = 1;
- //*****************************************************************************
- //
- //! Set the random number generator seed.
- //!
- //! \param seed is the new seed value to use for the random number
- //! generator.
- //!
- //! This function is very similar to the C library <tt>srand()</tt> function.
- //! It will set the seed value used in the <tt>urand()</tt> function.
- //!
- //! \return None
- //
- //*****************************************************************************
- void
- usrand(unsigned int seed)
- {
- g_iRandomSeed = seed;
- }
- //*****************************************************************************
- //
- //! Generate a new (pseudo) random number
- //!
- //! This function is very similar to the C library <tt>rand()</tt> function.
- //! It will generate a pseudo-random number sequence based on the seed value.
- //!
- //! \return A pseudo-random number will be returned.
- //
- //*****************************************************************************
- int
- urand(void)
- {
- //
- // Generate a new pseudo-random number with a linear congruence random
- // number generator. This new random number becomes the seed for the next
- // random number.
- //
- g_iRandomSeed = (g_iRandomSeed * 1664525) + 1013904223;
- //
- // Return the new random number.
- //
- return((int)g_iRandomSeed);
- }
- //*****************************************************************************
- //
- // Close the Doxygen group.
- //! @}
- //
- //*****************************************************************************
- //
- // End of file
- //
|