// SPDX-License-Identifier: MPL-2.0 #include "std/stdlib.h" #include "devs/apic/lapic.h" #include "memory/ring.h" #include "cpu/serial.h" sh_bool are_rings_buffer_setup=SH_FALSE; sh_ring_RING_BUFFER_HEADER *ring_buffer_array=SH_NULLPTR; sh_SPIN_LOCK serial_lock=SH_LOCK(); SH_STATUS sh_print_setup_ring_buffers_per_ap(sh_conf_BOOT_CONFIG *boot_config) { if (are_rings_buffer_setup==SH_TRUE || ring_buffer_array!=SH_NULLPTR || boot_config==SH_NULLPTR) return SH_STATUS_UNAVAILABLE; sh_uint64 cpu_count=0; sh_lapic_DEVICE **lapic_dev_array=sh_lapic_get_by_apic_id_array(); sh_uint64 max_lapic_id=sh_lapic_get_max_apic_id(); for (sh_iter64 i=0;ilog_ring_size/cpu_count; if (log_ring_size_ap<4) log_ring_size_ap=4; for (sh_iter64 i=0;iper_cpu->bytes_outputed); if (!text_to_flush) return SH_STATUS_ERROR_NULLPTR_RETURNED; sh_spin_lock(&serial_lock); SH_STATUS status=sh_ring_read_bytes(&ring_buffer_array[sh_smp_gs_base()->per_cpu->cpu_id],sh_smp_gs_base()->per_cpu->bytes_outputed,text_to_flush); if (sh_status_error(status)) { sh_spin_unlock(&serial_lock); return status; } sh_log_string(text_to_flush); sh_spin_unlock(&serial_lock); sh_free(text_to_flush); return SH_STATUS_SUCCESS; } SH_STATUS sh_print_byte(sh_uint8 byte) { if (!are_rings_buffer_setup) { sh_log_byte(byte); return SH_STATUS_SUCCESS; } else { SH_STATUS status=sh_ring_write_byte(&ring_buffer_array[sh_smp_gs_base()->per_cpu->cpu_id],byte); if (sh_status_error(status)) return status; sh_smp_gs_base()->per_cpu->bytes_outputed++; return SH_STATUS_SUCCESS; } } SH_STATUS sh_print_int8(sh_int8 n) { return sh_print_int64((sh_int64)n); } SH_STATUS sh_print_int16(sh_int16 n) { return sh_print_int64((sh_int64)n); } SH_STATUS sh_print_int32(sh_int32 n) { return sh_print_int64((sh_int64)n); } SH_STATUS sh_print_int64(sh_int64 n) { sh_uint64 absolute_val; if (n<0) { sh_print_byte('-'); absolute_val=(sh_uint64)(-(n+1))+1; } else { absolute_val=(sh_uint64)n; } return sh_print_uint64(absolute_val); } SH_STATUS sh_print_uint8(sh_uint8 n) { return sh_print_uint64((sh_uint64)n); } SH_STATUS sh_print_uint16(sh_uint16 n) { return sh_print_uint64((sh_uint64)n); } SH_STATUS sh_print_uint32(sh_uint32 n) { return sh_print_uint64((sh_uint64)n); } SH_STATUS sh_print_uint64(sh_uint64 n) { char buf[20]; sh_uint32 i=0; if (n==0) { sh_print_byte('0'); return SH_STATUS_SUCCESS; } while (n>0) { buf[i++]='0'+(sh_int8)(n%10); n/=10; } while (i--) { sh_print_byte((sh_uint8)buf[i]); } return SH_STATUS_SUCCESS; } SH_STATUS sh_print_uint8_hex(sh_uint8 n) { return sh_print_uint64_hex((sh_uint64)n); } SH_STATUS sh_print_uint16_hex(sh_uint16 n) { return sh_print_uint64_hex((sh_uint64)n); } SH_STATUS sh_print_uint32_hex(sh_uint32 n) { return sh_print_uint64_hex((sh_uint64)n); } SH_STATUS sh_print_uint64_hex(sh_uint64 n) { char buf[16]; sh_uint32 i=0; const char hex_digits[]="0123456789ABCDEF"; if (n==0) { sh_print_byte('0'); return SH_STATUS_SUCCESS; } while (n>0) { buf[i++]=hex_digits[n & 0xF]; n>>=4; } while (i--) { sh_print_byte((sh_uint8)buf[i]); } return SH_STATUS_SUCCESS; } SH_STATUS sh_print_uint64_hex_fixed(sh_uint64 n) { const char hex_digits[]="0123456789ABCDEF"; for (sh_int8 i=15;i>=0;i--) { sh_uint8 nibble=(sh_uint8)((n>>(i*4))&0xF); sh_print_byte((sh_uint8)hex_digits[nibble]); } return SH_STATUS_SUCCESS; } SH_STATUS sh_print_double(double value) { if (value<0) { sh_print_byte('-'); value=-value; } sh_uint64 integer_part=(sh_uint64)value; double fractional_part=value-(double)integer_part; SH_STATUS status=sh_print_uint64(integer_part); if (status!=SH_STATUS_SUCCESS) return status; sh_print_byte('.'); for (sh_iter64 i=0;i<6;i++) { fractional_part*=10.0; sh_uint64 digit=(sh_uint64)fractional_part; sh_print_byte('0'+(sh_uint8)digit); fractional_part-=(double)digit; } return SH_STATUS_SUCCESS; } SH_STATUS sh_print(sh_log_OUTPUT_TYPE output_type,char *text) { if (text==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER; sh_tsc_TSC_VALUE tsc_value=sh_tsc_get_kernel_current_tsc(); if (!sh_log_output_type_valid(output_type)) return SH_STATUS_INVALID_PARAMETER; if (output_typeper_cpu->bytes_outputed=0; sh_asm_cli(); char *intro="[Shelter:"; while (*intro) { sh_print_byte((sh_uint8)*intro++); } sh_print_uint64(sh_smp_gs_base()->per_cpu->cpu_id); sh_print_byte('@'); char* type=SH_NULLPTR; if (output_type==SH_DEBUG) { type="Debug] "; } else if (output_type==SH_LOG) { type="Log] "; } else if (output_type==SH_WARNING) { type="Warning] "; } else if (output_type==SH_ERROR) { type="Error] "; } else if (output_type==SH_CRITICAL) { type="Critical] "; } else if (output_type==SH_FATAL) { type="Fatal] "; } else if (output_type==SH_TEST) { type="Test] "; } else if (output_type==SH_FAULT) { type="Fault] "; } while (*type) { sh_print_byte((sh_uint8)*type++); } sh_print_uint64(tsc_value); char *transition=" : "; while (*transition) { sh_print_byte((sh_uint8)*transition++); } while (*text) { sh_print_byte((sh_uint8)*text++); } SH_STATUS status=sh_print_flush(); if (sh_status_error(status)) return status; sh_asm_sti(); return SH_STATUS_SUCCESS; } SH_STATUS sh_printf(sh_log_OUTPUT_TYPE output_type,char* format,...) { if (format==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER; sh_tsc_TSC_VALUE tsc_value=sh_tsc_get_kernel_current_tsc(); if (!sh_log_output_type_valid(output_type)) return SH_STATUS_INVALID_PARAMETER; if (output_typeper_cpu->bytes_outputed=0; sh_asm_cli(); char *intro="[Shelter:"; while (*intro) { sh_print_byte((sh_uint8)*intro++); } sh_print_uint64(sh_smp_gs_base()->per_cpu->cpu_id); sh_print_byte('@'); char* type=SH_NULLPTR; if (output_type==SH_DEBUG) { type="Debug] "; } else if (output_type==SH_LOG) { type="Log] "; } else if (output_type==SH_WARNING) { type="Warning] "; } else if (output_type==SH_ERROR) { type="Error] "; } else if (output_type==SH_CRITICAL) { type="Critical] "; } else if (output_type==SH_FATAL) { type="Fatal] "; } else if (output_type==SH_TEST) { type="Test] "; } else if (output_type==SH_FAULT) { type="Fault] "; } while (*type) { sh_print_byte((sh_uint8)*type++); } sh_print_uint64(tsc_value); char *transition=" : "; while (*transition) { sh_print_byte((sh_uint8)*transition++); } va_list args; va_start(args,format); for (const char *p=format;*p!='\0';p++) { if (*p!='%') { sh_print_byte((sh_uint8)*p); continue; } p++; switch (*p) { case 's': { char *s=va_arg(args,char *); while (*s) { sh_print_byte((sh_uint8)*s++); } break; } case 'd': { double s=va_arg(args,double); sh_print_double(s); break; } case '1': { if (p[1]=='u') { sh_print_uint8((sh_uint8)va_arg(args,int)); p++; } else if (p[1]=='s') { sh_print_int8((sh_int8)va_arg(args,int)); p++; } else if (p[1]=='U') { sh_print_uint8_hex((sh_uint8)va_arg(args,int)); p++; } break; } case '2': { if (p[1]=='u') { sh_print_uint16((sh_uint16)va_arg(args,int)); p++; } else if (p[1]=='s') { sh_print_int16((sh_int16)va_arg(args,int)); p++; } else if (p[1]=='U') { sh_print_uint16_hex((sh_uint16)va_arg(args,int)); p++; } break; } case '4': { if (p[1]=='u') { sh_print_uint32((sh_uint32)va_arg(args,int)); p++; } else if (p[1]=='s') { sh_print_int32((sh_int32)va_arg(args,int)); p++; } else if (p[1]=='U') { sh_print_uint32_hex((sh_uint32)va_arg(args,int)); p++; } break; } case '8': { if (p[1]=='u') { sh_print_uint64(va_arg(args,unsigned long long)); p++; } else if (p[1]=='s') { sh_print_int64(va_arg(args,long long)); p++; } else if (p[1]=='U') { sh_print_uint64_hex(va_arg(args,unsigned long long)); p++; } break; } case 'x': { sh_uint64 x=va_arg(args,sh_uint64); sh_print_uint64_hex_fixed(x); break; } case 'c': { sh_print_byte((sh_uint8)va_arg(args,int)); break; } case '%': { sh_print_byte('%'); break; } default: sh_print_byte((sh_uint8)*p); break; } } va_end(args); SH_STATUS status=sh_print_flush(); if (sh_status_error(status)) return status; sh_asm_sti(); return SH_STATUS_SUCCESS; } SH_STATUS sh_print_ibyte(sh_uint8 byte); SH_STATUS sh_print_iint8(sh_int8 n); SH_STATUS sh_print_iint16(sh_int16 n); SH_STATUS sh_print_iint32(sh_int32 n); SH_STATUS sh_print_iint64(sh_int64 n); SH_STATUS sh_print_iuint8(sh_uint8 n); SH_STATUS sh_print_iuint16(sh_uint16 n); SH_STATUS sh_print_iuint32(sh_uint32 n); SH_STATUS sh_print_iuint64(sh_uint64 n); SH_STATUS sh_print_iuint8_hex(sh_uint8 n); SH_STATUS sh_print_iuint16_hex(sh_uint16 n); SH_STATUS sh_print_iuint32_hex(sh_uint32 n); SH_STATUS sh_print_iuint64_hex(sh_uint64 n); SH_STATUS sh_print_iuint64_hex_fixed(sh_uint64 n); SH_STATUS sh_print_idouble(double value); SH_STATUS sh_print_ibyte(sh_uint8 byte) { sh_serial_send_byte(byte); return SH_STATUS_SUCCESS; } SH_STATUS sh_print_iint8(sh_int8 n) { return sh_print_iint64((sh_int64)n); } SH_STATUS sh_print_iint16(sh_int16 n) { return sh_print_iint64((sh_int64)n); } SH_STATUS sh_print_iint32(sh_int32 n) { return sh_print_iint64((sh_int64)n); } SH_STATUS sh_print_iint64(sh_int64 n) { sh_uint64 absolute_val; if (n<0) { sh_print_ibyte('-'); absolute_val=(sh_uint64)(-(n+1))+1; } else { absolute_val=(sh_uint64)n; } return sh_print_iuint64(absolute_val); } SH_STATUS sh_print_iuint8(sh_uint8 n) { return sh_print_iuint64((sh_uint64)n); } SH_STATUS sh_print_iuint16(sh_uint16 n) { return sh_print_iuint64((sh_uint64)n); } SH_STATUS sh_print_iuint32(sh_uint32 n) { return sh_print_iuint64((sh_uint64)n); } SH_STATUS sh_print_iuint64(sh_uint64 n) { char buf[20]; sh_uint32 i=0; if (n==0) { sh_print_ibyte('0'); return SH_STATUS_SUCCESS; } while (n>0) { buf[i++]='0'+(sh_int8)(n%10); n/=10; } while (i--) { sh_print_ibyte((sh_uint8)buf[i]); } return SH_STATUS_SUCCESS; } SH_STATUS sh_print_iuint8_hex(sh_uint8 n) { return sh_print_iuint64_hex((sh_uint64)n); } SH_STATUS sh_print_iuint16_hex(sh_uint16 n) { return sh_print_iuint64_hex((sh_uint64)n); } SH_STATUS sh_print_iuint32_hex(sh_uint32 n) { return sh_print_iuint64_hex((sh_uint64)n); } SH_STATUS sh_print_iuint64_hex(sh_uint64 n) { char buf[16]; sh_uint32 i=0; const char hex_digits[]="0123456789ABCDEF"; if (n==0) { sh_print_ibyte('0'); return SH_STATUS_SUCCESS; } while (n>0) { buf[i++]=hex_digits[n & 0xF]; n>>=4; } while (i--) { sh_print_ibyte((sh_uint8)buf[i]); } return SH_STATUS_SUCCESS; } SH_STATUS sh_print_iuint64_hex_fixed(sh_uint64 n) { const char hex_digits[]="0123456789ABCDEF"; for (sh_int8 i=15;i>=0;i--) { sh_uint8 nibble=(sh_uint8)((n>>(i*4))&0xF); sh_print_ibyte((sh_uint8)hex_digits[nibble]); } return SH_STATUS_SUCCESS; } SH_STATUS sh_print_idouble(double value) { if (value<0) { sh_print_ibyte('-'); value=-value; } sh_uint64 integer_part=(sh_uint64)value; double fractional_part=value-(double)integer_part; SH_STATUS status=sh_print_iuint64(integer_part); if (status!=SH_STATUS_SUCCESS) return status; sh_print_ibyte('.'); for (sh_iter64 i=0;i<6;i++) { fractional_part*=10.0; sh_uint64 digit=(sh_uint64)fractional_part; sh_print_ibyte('0'+(sh_uint8)digit); fractional_part-=(double)digit; } return SH_STATUS_SUCCESS; } SH_STATUS sh_iprint(sh_log_OUTPUT_TYPE output_type,char *text) { if (text==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER; sh_tsc_TSC_VALUE tsc_value=sh_tsc_get_kernel_current_tsc(); if (!sh_log_output_type_valid(output_type)) return SH_STATUS_INVALID_PARAMETER; if (output_typelapic_id) was_locked_by_me=SH_TRUE; if (!was_locked_by_me) { sh_spin_lock(&serial_lock); } char *intro="[Shelter:"; while (*intro) { sh_print_ibyte((sh_uint8)*intro++); } sh_print_iuint64(sh_smp_gs_base()->per_cpu->cpu_id); sh_print_ibyte('@'); char* type=SH_NULLPTR; if (output_type==SH_DEBUG) { type="Debug] "; } else if (output_type==SH_LOG) { type="Log] "; } else if (output_type==SH_WARNING) { type="Warning] "; } else if (output_type==SH_ERROR) { type="Error] "; } else if (output_type==SH_CRITICAL) { type="Critical] "; } else if (output_type==SH_FATAL) { type="Fatal] "; } else if (output_type==SH_TEST) { type="Test] "; } else if (output_type==SH_FAULT) { type="Fault] "; } while (*type) { sh_print_ibyte((sh_uint8)*type++); } sh_print_iuint64(tsc_value); char *transition=" : "; while (*transition) { sh_print_ibyte((sh_uint8)*transition++); } while (*text) { sh_print_ibyte((sh_uint8)*text++); } if (!was_locked_by_me) sh_spin_unlock(&serial_lock); return SH_STATUS_SUCCESS; } SH_STATUS sh_iprintf(sh_log_OUTPUT_TYPE output_type,char* format,...) { if (format==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER; sh_tsc_TSC_VALUE tsc_value=sh_tsc_get_kernel_current_tsc(); if (!sh_log_output_type_valid(output_type)) return SH_STATUS_INVALID_PARAMETER; if (output_typelapic_id) was_locked_by_me=SH_TRUE; if (!was_locked_by_me) { sh_spin_lock(&serial_lock); } char *intro="[Shelter:"; while (*intro) { sh_print_ibyte((sh_uint8)*intro++); } sh_print_iuint64(sh_smp_gs_base()->per_cpu->cpu_id); sh_print_ibyte('@'); char* type=SH_NULLPTR; if (output_type==SH_DEBUG) { type="Debug] "; } else if (output_type==SH_LOG) { type="Log] "; } else if (output_type==SH_WARNING) { type="Warning] "; } else if (output_type==SH_ERROR) { type="Error] "; } else if (output_type==SH_CRITICAL) { type="Critical] "; } else if (output_type==SH_FATAL) { type="Fatal] "; } else if (output_type==SH_TEST) { type="Test] "; } else if (output_type==SH_FAULT) { type="Fault] "; } while (*type) { sh_print_ibyte((sh_uint8)*type++); } sh_print_iuint64(tsc_value); char *transition=" : "; while (*transition) { sh_print_ibyte((sh_uint8)*transition++); } va_list args; va_start(args,format); for (const char *p=format;*p!='\0';p++) { if (*p!='%') { sh_print_ibyte((sh_uint8)*p); continue; } p++; switch (*p) { case 's': { char *s=va_arg(args,char *); while (*s) { sh_print_ibyte((sh_uint8)*s++); } break; } case 'd': { double s=va_arg(args,double); sh_print_idouble(s); break; } case '1': { if (p[1]=='u') { sh_print_iuint8((sh_uint8)va_arg(args,int)); p++; } else if (p[1]=='s') { sh_print_iint8((sh_int8)va_arg(args,int)); p++; } else if (p[1]=='U') { sh_print_iuint8_hex((sh_uint8)va_arg(args,int)); p++; } break; } case '2': { if (p[1]=='u') { sh_print_iuint16((sh_uint16)va_arg(args,int)); p++; } else if (p[1]=='s') { sh_print_iint16((sh_int16)va_arg(args,int)); p++; } else if (p[1]=='U') { sh_print_iuint16_hex((sh_uint16)va_arg(args,int)); p++; } break; } case '4': { if (p[1]=='u') { sh_print_iuint32((sh_uint32)va_arg(args,int)); p++; } else if (p[1]=='s') { sh_print_iint32((sh_int32)va_arg(args,int)); p++; } else if (p[1]=='U') { sh_print_iuint32_hex((sh_uint32)va_arg(args,int)); p++; } break; } case '8': { if (p[1]=='u') { sh_print_iuint64(va_arg(args,unsigned long long)); p++; } else if (p[1]=='s') { sh_print_iint64(va_arg(args,long long)); p++; } else if (p[1]=='U') { sh_print_iuint64_hex(va_arg(args,unsigned long long)); p++; } break; } case 'x': { sh_uint64 x=va_arg(args,sh_uint64); sh_print_iuint64_hex_fixed(x); break; } case 'c': { sh_print_ibyte((sh_uint8)va_arg(args,int)); break; } case '%': { sh_print_ibyte('%'); break; } default: sh_print_ibyte((sh_uint8)*p); break; } } va_end(args); if (!was_locked_by_me) sh_spin_unlock(&serial_lock); return SH_STATUS_SUCCESS; } typedef struct sh_sprint_WRITER { sh_uint8 *out; sh_uint8 *end; } sh_sprint_WRITER; static inline SH_STATUS sh_sprint_byte(sh_sprint_WRITER *w,sh_uint8 c) { if(w->out>=w->end) return SH_STATUS_TOO_MUCH_DATA; *w->out++=c; return SH_STATUS_SUCCESS; } SH_STATUS sh_sprint_int8(sh_sprint_WRITER *w,sh_int8 n); SH_STATUS sh_sprint_int16(sh_sprint_WRITER *w,sh_int16 n); SH_STATUS sh_sprint_int32(sh_sprint_WRITER *w,sh_int32 n); SH_STATUS sh_sprint_int64(sh_sprint_WRITER *w,sh_int64 n); SH_STATUS sh_sprint_uint8(sh_sprint_WRITER *w,sh_uint8 n); SH_STATUS sh_sprint_uint16(sh_sprint_WRITER *w,sh_uint16 n); SH_STATUS sh_sprint_uint32(sh_sprint_WRITER *w,sh_uint32 n); SH_STATUS sh_sprint_uint64(sh_sprint_WRITER *w,sh_uint64 n); SH_STATUS sh_sprint_uint8_hex(sh_sprint_WRITER *w,sh_uint8 n); SH_STATUS sh_sprint_uint16_hex(sh_sprint_WRITER *w,sh_uint16 n); SH_STATUS sh_sprint_uint32_hex(sh_sprint_WRITER *w,sh_uint32 n); SH_STATUS sh_sprint_uint64_hex(sh_sprint_WRITER *w,sh_uint64 n); SH_STATUS sh_sprint_uint64_hex_fixed(sh_sprint_WRITER *w,sh_uint64 n); SH_STATUS sh_sprint_double(sh_sprint_WRITER *w,double value); SH_STATUS sh_sprint_int8(sh_sprint_WRITER *w,sh_int8 n) { return sh_sprint_int64(w,(sh_int64)n); } SH_STATUS sh_sprint_int16(sh_sprint_WRITER *w,sh_int16 n) { return sh_sprint_int64(w,(sh_int64)n); } SH_STATUS sh_sprint_int32(sh_sprint_WRITER *w,sh_int32 n) { return sh_sprint_int64(w,(sh_int64)n); } SH_STATUS sh_sprint_int64(sh_sprint_WRITER *w,sh_int64 n) { sh_uint64 absolute_val; if (n<0) { SH_STATUS status=sh_sprint_byte(w,'-'); if (sh_status_error(status)) return status; absolute_val=(sh_uint64)(-(n+1))+1; } else { absolute_val=(sh_uint64)n; } return sh_sprint_uint64(w,absolute_val); } SH_STATUS sh_sprint_uint8(sh_sprint_WRITER *w,sh_uint8 n) { return sh_sprint_uint64(w,(sh_int64)n); } SH_STATUS sh_sprint_uint16(sh_sprint_WRITER *w,sh_uint16 n) { return sh_sprint_uint64(w,(sh_int64)n); } SH_STATUS sh_sprint_uint32(sh_sprint_WRITER *w,sh_uint32 n) { return sh_sprint_uint64(w,(sh_int64)n); } SH_STATUS sh_sprint_uint64(sh_sprint_WRITER *w,sh_uint64 n) { char buf[20]; sh_uint32 i=0; if (n==0) return sh_sprint_byte(w,'0'); while (n>0) { buf[i++]='0'+(sh_int8)(n%10); n/=10; } while (i--) { SH_STATUS status=sh_sprint_byte(w,(sh_uint8)buf[i]); if (sh_status_error(status)) return status; } return SH_STATUS_SUCCESS; } SH_STATUS sh_sprint_uint8_hex(sh_sprint_WRITER *w,sh_uint8 n) { return sh_sprint_uint64_hex(w,(sh_uint64)n); } SH_STATUS sh_sprint_uint16_hex(sh_sprint_WRITER *w,sh_uint16 n) { return sh_sprint_uint64_hex(w,(sh_uint64)n); } SH_STATUS sh_sprint_uint32_hex(sh_sprint_WRITER *w,sh_uint32 n) { return sh_sprint_uint64_hex(w,(sh_uint64)n); } SH_STATUS sh_sprint_uint64_hex(sh_sprint_WRITER *w,sh_uint64 n) { char buf[16]; sh_uint32 i=0; const char hex_digits[]="0123456789ABCDEF"; if (n==0) return sh_sprint_byte(w,'0'); while (n>0) { buf[i++]=hex_digits[n & 0xF]; n>>=4; } while (i--) { SH_STATUS status=sh_sprint_byte(w,(sh_uint8)buf[i]); if (sh_status_error(status)) return status; } return SH_STATUS_SUCCESS; } SH_STATUS sh_sprint_uint64_hex_fixed(sh_sprint_WRITER *w,sh_uint64 n) { const char hex[]="0123456789ABCDEF"; for (sh_int8 i=15;i>=0;i--) { char c=hex[(n>>(i*4))&0xF]; SH_STATUS status=sh_sprint_byte(w,(sh_uint8)c); if (sh_status_error(status)) return status; } return SH_STATUS_SUCCESS; } SH_STATUS sh_sprint_double(sh_sprint_WRITER *w,double value) { SH_STATUS status; if(value<0) { status=sh_sprint_byte(w,'-'); if (sh_status_error(status)) return status; value= -value; } sh_uint64 int_part=(sh_uint64)value; double frac=value-(double)int_part; status=sh_sprint_uint64(w,int_part); if (sh_status_error(status)) return status; status=sh_sprint_byte(w,'.'); if (sh_status_error(status)) return status; for(sh_iter64 i=0;i<6;i++) { frac*=10.0; sh_uint64 d=(sh_uint64)frac; status=sh_sprint_byte(w,(sh_uint8)'0'+(sh_uint8)d); if (sh_status_error(status)) return status; frac-=(double)d; } return SH_STATUS_SUCCESS; } SH_STATUS sh_sprintf(char *output_string,sh_uint64 output_len,char *format,...) { if (format==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER; sh_asm_cli(); sh_sprint_WRITER w={ .out=(sh_uint8*)output_string, .end=(sh_uint8*)output_string+output_len }; va_list args; va_start(args,format); for (const char *p=format;*p!='\0';p++) { if (*p!='%') { sh_sprint_byte(&w,(sh_uint8)*p); continue; } p++; switch (*p) { case 's': { char *s=va_arg(args,char *); while (*s) { sh_sprint_byte(&w,(sh_uint8)*s++); } break; } case 'd': { double s=va_arg(args,double); sh_sprint_double(&w,s); break; } case '1': { if (p[1]=='u') { sh_sprint_uint8(&w,(sh_uint8)va_arg(args,int)); p++; } else if (p[1]=='s') { sh_sprint_int8(&w,(sh_int8)va_arg(args,int)); p++; } else if (p[1]=='U') { sh_sprint_uint8_hex(&w,(sh_uint8)va_arg(args,int)); p++; } break; } case '2': { if (p[1]=='u') { sh_sprint_uint16(&w,(sh_uint16)va_arg(args,int)); p++; } else if (p[1]=='s') { sh_sprint_int16(&w,(sh_int16)va_arg(args,int)); p++; } else if (p[1]=='U') { sh_sprint_uint16_hex(&w,(sh_uint16)va_arg(args,int)); p++; } break; } case '4': { if (p[1]=='u') { sh_sprint_uint32(&w,(sh_uint32)va_arg(args,int)); p++; } else if (p[1]=='s') { sh_sprint_int32(&w,(sh_int32)va_arg(args,int)); p++; } else if (p[1]=='U') { sh_sprint_uint32_hex(&w,(sh_uint32)va_arg(args,int)); p++; } break; } case '8': { if (p[1]=='u') { sh_sprint_uint64(&w,va_arg(args,unsigned long long)); p++; } else if (p[1]=='s') { sh_sprint_int64(&w,va_arg(args,long long)); p++; } else if (p[1]=='U') { sh_sprint_uint64_hex(&w,va_arg(args,unsigned long long)); p++; } break; } case 'x': { sh_uint64 x=va_arg(args,sh_uint64); sh_sprint_uint64_hex_fixed(&w,x); break; } case 'c': { sh_sprint_byte(&w,(sh_uint8)va_arg(args,int)); break; } case '%': { sh_sprint_byte(&w,'%'); break; } default: sh_sprint_byte(&w,(sh_uint8)*p); break; } } va_end(args); SH_STATUS status=sh_sprint_byte(&w,'\0'); if (sh_status_error(status)) { output_string[output_len-1]='\0'; } sh_asm_sti(); return SH_STATUS_SUCCESS; }