| /* --COPYRIGHT--,ESD |
| * Copyright (c) 2008-2020 Texas Instruments Incorporated |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v1.0 and Eclipse Distribution License |
| * v. 1.0 which accompanies this distribution. The Eclipse Public License is |
| * available at http://www.eclipse.org/legal/epl-v10.html and the Eclipse |
| * Distribution License is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * Contributors: |
| * Texas Instruments - initial implementation |
| * --/COPYRIGHT--*/ |
| /* |
| * ======== System.c ======== |
| */ |
| |
| #include <xdc/runtime/Startup.h> |
| |
| #include <xdc/runtime/Gate.h> |
| |
| #include "package/internal/System.xdc.h" |
| #include "System__internal.h" |
| |
| #include <stdlib.h> |
| #include <stdarg.h> |
| #include <string.h> |
| #include <limits.h> |
| |
| /* |
| * ======== OUTMAX ======== |
| * The maximum length of the output of a base 8 number produced by formatNum |
| * plus 5 to accomodate the decimal point and 4 digits after the decimal |
| * point. |
| */ |
| #if ((xdc_target__bitsPerChar * xdc_target__sizeof_Ptr) > 32) \ |
| || ((xdc_target__bitsPerChar * xdc_target__sizeof_Long) > 32) |
| #define OUTMAX (((64 + 2) / 3) + 5) |
| #define PTRZPAD 16 |
| #else |
| #define OUTMAX (((32 + 2) / 3) + 5) |
| #define PTRZPAD 8 |
| #endif |
| |
| /* convenience aliases to avoid use of long System names */ |
| #define formatNum xdc_runtime_System_formatNum__I |
| typedef xdc_runtime_System_UNum UIntMax; |
| typedef xdc_runtime_System_INum IntMax; |
| |
| /* |
| * ======== vaRef ======== |
| * Return the address of a VaList (aka va_list) |
| * |
| * If va_list is an array type, taking the address of the va_list va simply |
| * returns va itself. Moreover, when such a va_list is passed to a function, |
| * C implicitly passes the address rather than the va_list array "value" |
| * itself. Taken together, this means we can "safely" cast a va_list value |
| * passed to a function as a (va_list *) when passing it on to functions |
| * expecting a (va_list *). |
| * |
| * Ignoring performance concerns, we can be squeaky clean and copy the |
| * va_list value to a local variable and pass the address of this local |
| * variable; for example: |
| * void vprint(String fmt, VaList va) |
| * { |
| * Int ret; |
| * va_list nva; |
| * va_copy(nva, va); |
| * ret = System_doPrint(NULL, (SizeT)-1, fmt, &nva, TRUE); |
| * va_end(nva); |
| * return (ret); |
| * } |
| * But this wastes stack space and CPU time to initialize a copy of something |
| * that already exists and for which we already have a legitimate reference. |
| * |
| * Of course, if va_list is not an array type, we must use the '&' operator. |
| */ |
| #if xdc_target__arraytype_VaList |
| # define vaRef(va) ((VaList *)(va)) |
| #else |
| # define vaRef(va) (&(va)) |
| #endif |
| |
| /* |
| * ======== System_Module_startup ======== |
| */ |
| Int System_Module_startup(Int stat) |
| { |
| return (Startup_DONE); |
| } |
| |
| /* |
| * ======== System_abort ======== |
| */ |
| /* REQ_TAG(SYSBIOS-1069) */ |
| Void System_abort(CString str) |
| { |
| (void)Gate_enterSystem(); |
| |
| System_SupportProxy_abort(str); |
| |
| /* REQ_TAG(SYSBIOS-899) */ |
| System_abortFxn(); |
| } |
| |
| /* |
| * ======== System_atexit ======== |
| */ |
| /* REQ_TAG(SYSBIOS-910) */ |
| Bool System_atexit(System_AtexitHandler handler) |
| { |
| IArg key; |
| Bool status = TRUE; |
| |
| key = Gate_enterSystem(); |
| |
| if (module->numAtexitHandlers < System_maxAtexitHandlers) { |
| module->atexitHandlers[module->numAtexitHandlers] = handler; |
| module->numAtexitHandlers++; |
| } |
| else { |
| status = FALSE; |
| } |
| |
| Gate_leaveSystem(key); |
| |
| return (status); |
| } |
| |
| /* |
| * ======== System_exit ======== |
| */ |
| /* REQ_TAG(SYSBIOS-1070) */ |
| Void System_exit(Int stat) |
| { |
| System_processAtExit(stat); |
| |
| /* REQ_TAG(SYSBIOS-906) */ |
| System_exitFxn(stat); |
| } |
| |
| /* |
| * ======== System_abortStd ======== |
| */ |
| /* REQ_TAG(SYSBIOS-901) */ |
| Void System_abortStd(Void) |
| { |
| abort(); |
| } |
| |
| /* |
| * ======== System_abortSpin ======== |
| */ |
| /* REQ_TAG(SYSBIOS-900) */ |
| /* LCOV_EXCL_START */ |
| Void System_abortSpin(Void) |
| { |
| /* LCOV_EXCL_STOP */ |
| for (;;) { |
| } |
| } |
| |
| /* |
| * ======== System_exitStd ======== |
| */ |
| /* REQ_TAG(SYSBIOS-908) */ |
| Void System_exitStd(Int stat) |
| { |
| exit(stat); |
| } |
| |
| /* |
| * ======== System_exitSpin ======== |
| */ |
| /* REQ_TAG(SYSBIOS-907) */ |
| /* LCOV_EXCL_START */ |
| Void System_exitSpin(Int stat) |
| { |
| /* LCOV_EXCL_STOP */ |
| for (;;) { |
| } |
| } |
| |
| /* |
| * ======== System_processAtExit ======== |
| */ |
| /* REQ_TAG(SYSBIOS-911) */ |
| Void System_processAtExit(Int stat) |
| { |
| Int i; |
| |
| (void)Gate_enterSystem(); |
| |
| for (i = module->numAtexitHandlers; i > 0; i--) { |
| (module->atexitHandlers[i - 1])(stat); |
| } |
| |
| System_SupportProxy_exit(stat); |
| } |
| |
| /* |
| * ======== System_flush ======== |
| */ |
| /* REQ_TAG(SYSBIOS-909) */ |
| Void System_flush(Void) |
| { |
| System_SupportProxy_flush(); |
| } |
| |
| |
| /* |
| * ======== System_putch ======== |
| */ |
| /* REQ_TAG(SYSBIOS-912) */ |
| Void System_putch(Char ch) |
| { |
| if (System_SupportProxy_ready() == TRUE) { |
| System_SupportProxy_putch(ch); |
| } |
| } |
| |
| /* |
| * ======== System_aprintf_va ======== |
| */ |
| Int System_aprintf_va(CString fmt, VaList va) |
| { |
| return (System_avprintf(fmt, va)); |
| } |
| |
| /* |
| * ======== System_avprintf ======== |
| * -1 indicates infinite output |
| */ |
| /* REQ_TAG(SYSBIOS-902), REQ_TAG(SYSBIOS-903) */ |
| Int System_avprintf(CString fmt, VaList va) |
| { |
| return ((System_SupportProxy_ready() == TRUE) |
| ? System_doPrint((Char *)NULL, (SizeT)-1, fmt, vaRef(va), TRUE) |
| : -1); |
| } |
| |
| /* |
| * ======== System_asprintf_va ======== |
| */ |
| Int System_asprintf_va(Char buf[], CString fmt, VaList va) |
| { |
| return (System_avsprintf(buf, fmt, va)); |
| } |
| |
| /* |
| * ======== System_avsprintf ======== |
| * -1 indicates infinite output |
| */ |
| /* REQ_TAG(SYSBIOS-902), REQ_TAG(SYSBIOS-903), REQ_TAG(SYSBIOS-904) */ |
| Int System_avsprintf(Char buf[], CString fmt, VaList va) |
| { |
| return (System_doPrint(buf, (SizeT)-1, fmt, vaRef(va), TRUE)); |
| } |
| |
| /* |
| * ======== System_printf_va ======== |
| */ |
| Int System_printf_va(CString fmt, VaList va) |
| { |
| return (System_vprintf(fmt, va)); |
| } |
| |
| /* |
| * ======== System_vprintf ======== |
| * -1 indicates infinite output |
| */ |
| /* REQ_TAG(SYSBIOS-902) */ |
| Int System_vprintf(CString fmt, VaList va) |
| { |
| return ((System_SupportProxy_ready() == TRUE) |
| ? System_doPrint((Char *)NULL, (SizeT)-1, fmt, vaRef(va), FALSE) |
| : -1); |
| } |
| |
| /* |
| * ======== System_sprintf_va ======== |
| */ |
| Int System_sprintf_va(Char buf[], CString fmt, VaList va) |
| { |
| return (System_vsprintf(buf, fmt, va)); |
| } |
| |
| /* |
| * ======== System_vsprintf ======== |
| * -1 indicates infinite output |
| */ |
| /* REQ_TAG(SYSBIOS-902), REQ_TAG(SYSBIOS-904) */ |
| Int System_vsprintf(Char buf[], CString fmt, VaList va) |
| { |
| return (System_doPrint(buf, (SizeT)-1, fmt, vaRef(va), FALSE)); |
| } |
| |
| /* |
| * ======== System_snprintf_va ======== |
| */ |
| Int System_snprintf_va(Char buf[], SizeT n, CString fmt, VaList va) |
| { |
| return (System_vsnprintf(buf, n, fmt, va)); |
| } |
| |
| /* |
| * ======== System_vsnprintf ======== |
| */ |
| /* REQ_TAG(SYSBIOS-902), REQ_TAG(SYSBIOS-904) */ |
| Int System_vsnprintf(Char buf[], SizeT n, CString fmt, VaList va) |
| { |
| return (System_doPrint(buf, n, fmt, vaRef(va), FALSE)); |
| } |
| |
| /* |
| * ======== System_doPrint ======== |
| * Internal function |
| * |
| * If buf == NULL, characters are sent to System_SupportProxy_putch(); |
| * otherwise, they are written into buf. Atmost `n` - 1 characters are written |
| * excluding '\0'. |
| * |
| * The return value is the number of characters that would have been written |
| * had `n` been sufficiently large, not counting the terminating '\0' |
| * character. |
| */ |
| Int System_doPrint(Char *buf, SizeT n, CString fmt, VaList *pva, Bool aFlag) |
| { |
| /* temp vars */ |
| Int base; |
| Char c; |
| Int res; |
| Int temp_res; |
| Char outbuf[OUTMAX]; |
| ptrdiff_t diff; |
| |
| /* vars passed to System_extendFxn. Also keep track in while loop */ |
| struct System_ParseData parse; |
| |
| parse.aFlag = aFlag; |
| |
| res = 0; |
| |
| if (fmt == (Char *)NULL) { |
| return (res); |
| } |
| |
| c = *fmt; |
| fmt++; |
| while (c != '\0') { |
| if (c != '%') { |
| System_putchar(&buf, c, &n); |
| res++; |
| } |
| else { |
| c = *fmt; |
| fmt++; |
| /* check for - flag (pad on right) */ |
| if (c == '-') { |
| parse.lJust = TRUE; |
| c = *fmt; |
| fmt++; |
| } |
| else { |
| parse.lJust = FALSE; |
| } |
| /* check for leading 0 pad */ |
| if (c == '0') { |
| parse.zpad = 1; |
| c = *fmt; |
| fmt++; |
| } |
| else { |
| parse.zpad = 0; |
| } |
| |
| /* allow optional field width/precision specification */ |
| parse.width = 0; |
| parse.precis = -1; |
| |
| /* note: dont use isdigit (very large for C30) */ |
| if (c == '*') { |
| parse.width = (parse.aFlag == TRUE) |
| ? (int)va_arg(*pva, IArg) : (int)va_arg(*pva, int); |
| c = *fmt; |
| fmt++; |
| if (parse.width < 0) { |
| parse.lJust = TRUE; |
| parse.width = -parse.width; |
| } |
| } |
| else { |
| while ((c >= '0') && (c <= '9')) { |
| parse.width = (parse.width * 10) + c - '0'; |
| c = *fmt; |
| fmt++; |
| } |
| } |
| |
| /* allow optional field precision specification */ |
| if (c == '.') { |
| parse.precis = 0; |
| c = *fmt; |
| fmt++; |
| if (c == '*') { |
| parse.precis = (parse.aFlag == TRUE) |
| ? (int)va_arg(*pva, IArg) : (int)va_arg(*pva, int); |
| if (parse.precis < 0) { |
| parse.precis = 0; |
| } |
| |
| c = *fmt; |
| fmt++; |
| } |
| else { |
| while ((c >= '0') && (c <= '9')) { |
| parse.precis = (parse.precis * 10) + c - '0'; |
| c = *fmt; |
| fmt++; |
| } |
| } |
| } |
| |
| /* setup for leading zero padding */ |
| if (parse.zpad != 0) { |
| parse.zpad = parse.width; |
| } |
| |
| /* check for presence of l flag (e.g., %ld) */ |
| if ((c == 'l') || (c == 'L')) { |
| parse.lFlag = TRUE; |
| c = *fmt; |
| fmt++; |
| } |
| else { |
| parse.lFlag = FALSE; |
| } |
| |
| parse.ptr = outbuf; |
| parse.end = outbuf + OUTMAX; |
| parse.len = 0; |
| |
| if ((c == 'd') || (c == 'i')) { |
| /* signed decimal */ |
| IntMax val = |
| (parse.aFlag == TRUE) ? (IntMax)va_arg(*pva, IArg) : |
| (parse.lFlag == TRUE) ? (IntMax)va_arg(*pva, long int) : |
| (IntMax)va_arg(*pva, int); |
| |
| if (parse.precis > parse.zpad) { |
| parse.zpad = parse.precis; |
| } |
| parse.ptr = formatNum(parse.end, (UIntMax)val, parse.zpad, -10); |
| /* We know that parse.end > parse.ptr, so it is safe to use |
| * casts and assign to UInt. All this to avoid MISRA warnings. |
| * This same comment applies to assignments to parse.len later |
| * in this function. |
| */ |
| diff = parse.end - parse.ptr; |
| parse.len = (UInt)diff; |
| } |
| else if (c == 'u' || c == 'x' || c == 'o') { |
| UIntMax val; |
| |
| base = (c == 'u') ? 10 : ((c == 'x') ? 16 : 8); |
| val = |
| (parse.aFlag == TRUE) ? (UIntMax)va_arg(*pva, IArg) : |
| (parse.lFlag == TRUE) ? (UIntMax)va_arg(*pva, unsigned long) |
| : (UIntMax)va_arg(*pva, unsigned); |
| if (parse.precis > parse.zpad) { |
| parse.zpad = parse.precis; |
| } |
| parse.ptr = formatNum(parse.end, val, parse.zpad, base); |
| diff = parse.end - parse.ptr; |
| parse.len = (UInt)diff; |
| } |
| else if (c == 'p') { |
| base = 16; |
| parse.zpad = PTRZPAD; /* ptrs are 0 padded */ |
| parse.ptr = formatNum( |
| parse.end, |
| (parse.aFlag == TRUE) ? (UIntMax)va_arg(*pva, IArg) : |
| (UIntMax)(UArg)va_arg(*pva, Ptr), parse.zpad, base); |
| parse.ptr--; |
| *(parse.ptr) = '@'; |
| diff = parse.end - parse.ptr; |
| parse.len = (UInt)diff; |
| } |
| else if (c == 'c') { |
| /* character */ |
| *parse.ptr = (parse.aFlag == TRUE) |
| ? (Char)va_arg(*pva, IArg) : (Char)va_arg(*pva, int); |
| parse.len = 1; |
| } |
| else if (c == 's') { |
| /* string */ |
| parse.ptr = (parse.aFlag == TRUE) |
| ? (String)iargToPtr(va_arg(*pva, IArg)) |
| : (String)va_arg(*pva, void *); |
| |
| /* substitute (null) for NULL pointer */ |
| if (parse.ptr == (char *)NULL) { |
| parse.ptr = "(null)"; |
| } |
| parse.len = (UInt)(strlen(parse.ptr)); |
| if ((parse.precis != -1) && ((UInt)parse.precis < parse.len)) { |
| parse.len = (UInt)parse.precis; |
| } |
| } |
| else { |
| fmt--; |
| |
| /* check if enough buffer space available */ |
| if (n > 1U) { |
| /* parse.precis should account for the buffer size. We are |
| * assuming that SIZE_MAX>=INT_MAX because it's true for |
| * the compilers we care about. A longer discussion is here: |
| * https://stackoverflow.com/questions/46508831/is-the-max-value-of-size-t-size-max-defined-relative-to-the-other-integer-type?rq=1 |
| */ |
| if ((parse.precis == -1) || ((SizeT)parse.precis >= n)) { |
| if (n < (SizeT)INT_MAX) { |
| parse.precis = (Int)n; |
| } |
| else { |
| parse.precis = INT_MAX; |
| } |
| } |
| else { |
| /* Have enough space, increment to account for '\0' */ |
| parse.precis++; |
| } |
| temp_res = System_extendFxn(&buf, &fmt, pva, &parse); |
| /* temp_res is how many were printed. We are losing here the |
| * info about how many characters would be printed, but that |
| * info is lost by calling various Text functions that don't |
| * report how many characters would be printed if there were |
| * enough space. |
| */ |
| res += temp_res; |
| n = n - (SizeT)temp_res; |
| } |
| } |
| |
| /* compute number of characters left in field */ |
| parse.width -= (Int)parse.len; |
| |
| if (parse.lJust == FALSE) { |
| /* pad with blanks on left */ |
| while (--parse.width >= 0) { |
| System_putchar(&buf, ' ', &n); |
| res++; |
| } |
| } |
| |
| /* output number, character or string */ |
| while (parse.len-- != 0U) { |
| System_putchar(&buf, *parse.ptr, &n); |
| parse.ptr++; |
| res++; |
| } |
| /* pad with blanks on right */ |
| if (parse.lJust == TRUE) { |
| while (--parse.width >= 0) { |
| System_putchar(&buf, ' ', &n); |
| res++; |
| } |
| } |
| } /* if */ |
| c = *fmt; |
| fmt++; |
| } /* while */ |
| |
| if (buf != NULL) { |
| *buf = '\0'; |
| } |
| |
| return (res); |
| } |
| |
| /* |
| * ======== formatNum ======== |
| * Internal function |
| * |
| * Format unsigned long number in specified base, returning pointer to |
| * converted output. |
| * |
| * Note: ptr points PAST end of the buffer, and is decremented as digits |
| * are converted from right to left! |
| * |
| * Note: base is negative if n is signed else n unsigned! |
| * |
| * ptr - Pointer to the end of the working buffer where the string version |
| * of the number will be placed. |
| * un - The unsigned number to be formated |
| * base - The base to format the number into. |
| */ |
| Char *formatNum(Char *ptr, UIntMax un, Int zpad, Int base) |
| { |
| Int i = 0; |
| Char sign = '\0'; |
| |
| UIntMax n; |
| n = un; |
| |
| if (base < 0) { |
| /* handle signed long case */ |
| base = -base; |
| if ((IntMax)n < 0) { |
| n = (UIntMax)(-(IntMax)n); |
| |
| /* account for sign '-': ok since zpad is signed */ |
| --zpad; |
| sign = '-'; |
| } |
| } |
| |
| /* compute digits in number from right to left */ |
| do { |
| ptr--; |
| *ptr = "0123456789abcdef"[n % (UInt)base]; |
| n = n / (UInt)base; |
| ++i; |
| } while (n != 0U); |
| |
| /* pad with leading 0s on left */ |
| while (i < zpad) { |
| ptr--; |
| *ptr = '0'; |
| ++i; |
| } |
| |
| /* add sign indicator */ |
| if (sign != '\0') { |
| ptr--; |
| *ptr = sign; |
| } |
| return (ptr); |
| } |
| |
| /* |
| * ======== System_putchar ======== |
| * Internal function |
| * |
| * Write character `c` to the buffer and, if the buffer pointer is |
| * non-NULL, update the buffer pointer. |
| * |
| * Keeps track of the number of characters written into the buffer by |
| * modifying bufsize `n`. Atmost, `n` - 1 characters are written. |
| */ |
| Void System_putchar(Char **bufp, Char c, SizeT *n) |
| { |
| /* if the size == 1, don't write so we can '\0' terminate buffer */ |
| if ((*n) > 1U) { |
| |
| /* decrement n to keep track of the number of chars written */ |
| (*n)--; |
| |
| /* |
| * If the buffer is non-NULL, use it, otherwise call the |
| * proxy's putch function (if it is ready). |
| */ |
| if (*bufp != NULL) { |
| **bufp = c; |
| (*bufp)++; |
| } |
| else if (System_SupportProxy_ready() == TRUE) { |
| System_SupportProxy_putch(c); |
| } |
| else { |
| return; |
| } |
| } |
| } |