|
|
|
/******************************************************************************
|
|
|
|
*
|
|
|
|
* Name: skproc.c
|
|
|
|
* Project: GEnesis, PCI Gigabit Ethernet Adapter
|
|
|
|
* Version: $Revision: 1.4 $
|
|
|
|
* Date: $Date: 2003/02/25 14:16:37 $
|
|
|
|
* Purpose: Funktions to display statictic data
|
|
|
|
*
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
*
|
|
|
|
* (C)Copyright 1998-2003 SysKonnect GmbH.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* Created 22-Nov-2000
|
|
|
|
* Author: Mirko Lindner (mlindner@syskonnect.de)
|
|
|
|
*
|
|
|
|
* The information in this file is provided "AS IS" without warranty.
|
|
|
|
*
|
|
|
|
******************************************************************************/
|
|
|
|
/******************************************************************************
|
|
|
|
*
|
|
|
|
* History:
|
|
|
|
*
|
|
|
|
* $Log: skproc.c,v $
|
|
|
|
* Revision 1.4 2003/02/25 14:16:37 mlindner
|
|
|
|
* Fix: Copyright statement
|
|
|
|
*
|
|
|
|
* Revision 1.3 2002/10/02 12:59:51 mlindner
|
|
|
|
* Add: Support for Yukon
|
|
|
|
* Add: Speed check and setup
|
|
|
|
* Add: Merge source for kernel 2.2.x and 2.4.x
|
|
|
|
* Add: Read sensor names directly from VPD
|
|
|
|
* Fix: Volt values
|
|
|
|
*
|
|
|
|
* Revision 1.2.2.7 2002/01/14 12:45:15 mlindner
|
|
|
|
* Fix: Editorial changes
|
|
|
|
*
|
|
|
|
* Revision 1.2.2.6 2001/12/06 15:26:07 mlindner
|
|
|
|
* Fix: Return value of proc_read
|
|
|
|
*
|
|
|
|
* Revision 1.2.2.5 2001/12/06 09:57:39 mlindner
|
|
|
|
* New ProcFs entries
|
|
|
|
*
|
|
|
|
* Revision 1.2.2.4 2001/09/05 12:16:02 mlindner
|
|
|
|
* Add: New ProcFs entries
|
|
|
|
* Fix: Counter Errors (Jumbo == to long errors)
|
|
|
|
* Fix: Kernel error compilation
|
|
|
|
* Fix: too short counters
|
|
|
|
*
|
|
|
|
* Revision 1.2.2.3 2001/06/25 07:26:26 mlindner
|
|
|
|
* Add: More error messages
|
|
|
|
*
|
|
|
|
* Revision 1.2.2.2 2001/03/15 12:50:13 mlindner
|
|
|
|
* fix: ProcFS owner protection
|
|
|
|
*
|
|
|
|
* Revision 1.2.2.1 2001/03/12 16:43:48 mlindner
|
|
|
|
* chg: 2.4 requirements for procfs
|
|
|
|
*
|
|
|
|
* Revision 1.1 2001/01/22 14:15:31 mlindner
|
|
|
|
* added ProcFs functionality
|
|
|
|
* Dual Net functionality integrated
|
|
|
|
* Rlmt networks added
|
|
|
|
*
|
|
|
|
*
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <linux/proc_fs.h>
|
|
|
|
|
|
|
|
#include "h/skdrv1st.h"
|
|
|
|
#include "h/skdrv2nd.h"
|
|
|
|
#define ZEROPAD 1 /* pad with zero */
|
|
|
|
#define SIGN 2 /* unsigned/signed long */
|
|
|
|
#define PLUS 4 /* show plus */
|
|
|
|
#define SPACE 8 /* space if plus */
|
|
|
|
#define LEFT 16 /* left justified */
|
|
|
|
#define SPECIALX 32 /* 0x */
|
|
|
|
#define LARGE 64
|
|
|
|
|
|
|
|
extern SK_AC *pACList;
|
|
|
|
extern struct net_device *SkGeRootDev;
|
|
|
|
|
|
|
|
extern char *SkNumber (char *str,
|
|
|
|
long long num,
|
|
|
|
int base,
|
|
|
|
int size,
|
|
|
|
int precision,
|
|
|
|
int type);
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* proc_read - print "summaries" entry
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* This function fills the proc entry with statistic data about
|
|
|
|
* the ethernet device.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Returns: buffer with statistic data
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int proc_read(char *buffer,
|
|
|
|
char **buffer_location,
|
|
|
|
off_t offset,
|
|
|
|
int buffer_length,
|
|
|
|
int *eof,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
int len = 0;
|
|
|
|
int t;
|
|
|
|
int i;
|
|
|
|
DEV_NET *pNet;
|
|
|
|
SK_AC *pAC;
|
|
|
|
char test_buf[100];
|
|
|
|
char sens_msg[50];
|
|
|
|
unsigned long Flags;
|
|
|
|
unsigned int Size;
|
|
|
|
struct SK_NET_DEVICE *next;
|
|
|
|
struct SK_NET_DEVICE *SkgeProcDev = SkGeRootDev;
|
|
|
|
|
|
|
|
SK_PNMI_STRUCT_DATA *pPnmiStruct;
|
|
|
|
SK_PNMI_STAT *pPnmiStat;
|
|
|
|
struct proc_dir_entry *file = (struct proc_dir_entry*) data;
|
|
|
|
|
|
|
|
while (SkgeProcDev) {
|
|
|
|
pNet = (DEV_NET*) SkgeProcDev->priv;
|
|
|
|
pAC = pNet->pAC;
|
|
|
|
next = pAC->Next;
|
|
|
|
pPnmiStruct = &pAC->PnmiStruct;
|
|
|
|
/* NetIndex in GetStruct is now required, zero is only dummy */
|
|
|
|
|
|
|
|
for (t=pAC->GIni.GIMacsFound; t > 0; t--) {
|
|
|
|
if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 1)
|
|
|
|
t--;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&pAC->SlowPathLock, Flags);
|
|
|
|
Size = SK_PNMI_STRUCT_SIZE;
|
|
|
|
SkPnmiGetStruct(pAC, pAC->IoBase,
|
|
|
|
pPnmiStruct, &Size, t-1);
|
|
|
|
spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
|
|
|
|
|
|
|
|
if (strcmp(pAC->dev[t-1]->name, file->name) == 0) {
|
|
|
|
pPnmiStat = &pPnmiStruct->Stat[0];
|
|
|
|
len = sprintf(buffer,
|
|
|
|
"\nDetailed statistic for device %s\n",
|
|
|
|
pAC->dev[t-1]->name);
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"=======================================\n");
|
|
|
|
|
|
|
|
/* Board statistics */
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"\nBoard statistics\n\n");
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"Active Port %c\n",
|
|
|
|
'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt.
|
|
|
|
Net[t-1].PrefPort]->PortNumber);
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"Preferred Port %c\n",
|
|
|
|
'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt.
|
|
|
|
Net[t-1].PrefPort]->PortNumber);
|
|
|
|
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"Bus speed (MHz) %d\n",
|
|
|
|
pPnmiStruct->BusSpeed);
|
|
|
|
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"Bus width (Bit) %d\n",
|
|
|
|
pPnmiStruct->BusWidth);
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"Hardware revision v%d.%d\n",
|
|
|
|
(pAC->GIni.GIPciHwRev >> 4) & 0x0F,
|
|
|
|
pAC->GIni.GIPciHwRev & 0x0F);
|
|
|
|
|
|
|
|
/* Print sensor informations */
|
|
|
|
for (i=0; i < pAC->I2c.MaxSens; i ++) {
|
|
|
|
/* Check type */
|
|
|
|
switch (pAC->I2c.SenTable[i].SenType) {
|
|
|
|
case 1:
|
|
|
|
strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
|
|
|
|
strcat(sens_msg, " (C)");
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"%-25s %d.%02d\n",
|
|
|
|
sens_msg,
|
|
|
|
pAC->I2c.SenTable[i].SenValue / 10,
|
|
|
|
pAC->I2c.SenTable[i].SenValue % 10);
|
|
|
|
|
|
|
|
strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
|
|
|
|
strcat(sens_msg, " (F)");
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"%-25s %d.%02d\n",
|
|
|
|
sens_msg,
|
|
|
|
((((pAC->I2c.SenTable[i].SenValue)
|
|
|
|
*10)*9)/5 + 3200)/100,
|
|
|
|
((((pAC->I2c.SenTable[i].SenValue)
|
|
|
|
*10)*9)/5 + 3200) % 10);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
|
|
|
|
strcat(sens_msg, " (V)");
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"%-25s %d.%03d\n",
|
|
|
|
sens_msg,
|
|
|
|
pAC->I2c.SenTable[i].SenValue / 1000,
|
|
|
|
pAC->I2c.SenTable[i].SenValue % 1000);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
|
|
|
|
strcat(sens_msg, " (rpm)");
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"%-25s %d\n",
|
|
|
|
sens_msg,
|
|
|
|
pAC->I2c.SenTable[i].SenValue);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Receive statistics */
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"\nReceive statistics\n\n");
|
|
|
|
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"Received bytes %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatRxOctetsOkCts,
|
|
|
|
10,0,-1,0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"Received packets %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatRxOkCts,
|
|
|
|
10,0,-1,0));
|
|
|
|
#if 0
|
|
|
|
if (pAC->GIni.GP[0].PhyType == SK_PHY_XMAC &&
|
|
|
|
pAC->HWRevision < 12) {
|
|
|
|
pPnmiStruct->InErrorsCts = pPnmiStruct->InErrorsCts -
|
|
|
|
pPnmiStat->StatRxShortsCts;
|
|
|
|
pPnmiStat->StatRxShortsCts = 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (pNet->Mtu > 1500)
|
|
|
|
pPnmiStruct->InErrorsCts = pPnmiStruct->InErrorsCts -
|
|
|
|
pPnmiStat->StatRxTooLongCts;
|
|
|
|
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"Receive errors %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStruct->InErrorsCts,
|
|
|
|
10,0,-1,0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"Receive drops %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStruct->RxNoBufCts,
|
|
|
|
10,0,-1,0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"Received multicast %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatRxMulticastOkCts,
|
|
|
|
10,0,-1,0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"Receive error types\n");
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
" length %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatRxRuntCts,
|
|
|
|
10, 0, -1, 0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
" buffer overflow %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatRxFifoOverflowCts,
|
|
|
|
10, 0, -1, 0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
" bad crc %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatRxFcsCts,
|
|
|
|
10, 0, -1, 0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
" framing %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatRxFramingCts,
|
|
|
|
10, 0, -1, 0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
" missed frames %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatRxMissedCts,
|
|
|
|
10, 0, -1, 0));
|
|
|
|
|
|
|
|
if (pNet->Mtu > 1500)
|
|
|
|
pPnmiStat->StatRxTooLongCts = 0;
|
|
|
|
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
" too long %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatRxTooLongCts,
|
|
|
|
10, 0, -1, 0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
" carrier extension %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatRxCextCts,
|
|
|
|
10, 0, -1, 0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
" too short %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatRxShortsCts,
|
|
|
|
10, 0, -1, 0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
" symbol %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatRxSymbolCts,
|
|
|
|
10, 0, -1, 0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
" LLC MAC size %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatRxIRLengthCts,
|
|
|
|
10, 0, -1, 0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
" carrier event %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatRxCarrierCts,
|
|
|
|
10, 0, -1, 0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
" jabber %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatRxJabberCts,
|
|
|
|
10, 0, -1, 0));
|
|
|
|
|
|
|
|
|
|
|
|
/*Transmit statistics */
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"\nTransmit statistics\n\n");
|
|
|
|
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"Transmited bytes %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatTxOctetsOkCts,
|
|
|
|
10,0,-1,0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"Transmited packets %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatTxOkCts,
|
|
|
|
10,0,-1,0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"Transmit errors %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatTxSingleCollisionCts,
|
|
|
|
10,0,-1,0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"Transmit dropped %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStruct->TxNoBufCts,
|
|
|
|
10,0,-1,0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"Transmit collisions %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatTxSingleCollisionCts,
|
|
|
|
10,0,-1,0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
"Transmit errors types\n");
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
" excessive collision %ld\n",
|
|
|
|
pAC->stats.tx_aborted_errors);
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
" carrier %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatTxCarrierCts,
|
|
|
|
10, 0, -1, 0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
" fifo underrun %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatTxFifoUnderrunCts,
|
|
|
|
10, 0, -1, 0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
" heartbeat %s\n",
|
|
|
|
SkNumber(test_buf, pPnmiStat->StatTxCarrierCts,
|
|
|
|
10, 0, -1, 0));
|
|
|
|
len += sprintf(buffer + len,
|
|
|
|
" window %ld\n",
|
|
|
|
pAC->stats.tx_window_errors);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SkgeProcDev = next;
|
|
|
|
}
|
|
|
|
if (offset >= len) {
|
|
|
|
*eof = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
*buffer_location = buffer + offset;
|
|
|
|
if (buffer_length >= len - offset) {
|
|
|
|
*eof = 1;
|
|
|
|
}
|
|
|
|
return (min_t(int, buffer_length, len - offset));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* SkDoDiv - convert 64bit number
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* This function "converts" a long long number.
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* remainder of division
|
|
|
|
*/
|
|
|
|
static long SkDoDiv (long long Dividend, int Divisor, long long *pErg)
|
|
|
|
{
|
|
|
|
long Rest;
|
|
|
|
long long Ergebnis;
|
|
|
|
long Akku;
|
|
|
|
|
|
|
|
|
|
|
|
Akku = Dividend >> 32;
|
|
|
|
|
|
|
|
Ergebnis = ((long long) (Akku / Divisor)) << 32;
|
|
|
|
Rest = Akku % Divisor;
|
|
|
|
|
|
|
|
Akku = Rest << 16;
|
|
|
|
Akku |= ((Dividend & 0xFFFF0000) >> 16);
|
|
|
|
|
|
|
|
|
|
|
|
Ergebnis += ((long long) (Akku / Divisor)) << 16;
|
|
|
|
Rest = Akku % Divisor;
|
|
|
|
|
|
|
|
Akku = Rest << 16;
|
|
|
|
Akku |= (Dividend & 0xFFFF);
|
|
|
|
|
|
|
|
Ergebnis += (Akku / Divisor);
|
|
|
|
Rest = Akku % Divisor;
|
|
|
|
|
|
|
|
*pErg = Ergebnis;
|
|
|
|
return (Rest);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
#define do_div(n,base) ({ \
|
|
|
|
long long __res; \
|
|
|
|
__res = ((unsigned long long) n) % (unsigned) base; \
|
|
|
|
n = ((unsigned long long) n) / (unsigned) base; \
|
|
|
|
__res; })
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* SkNumber - Print results
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* This function converts a long long number into a string.
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* number as string
|
|
|
|
*/
|
|
|
|
char * SkNumber(char * str, long long num, int base, int size, int precision
|
|
|
|
,int type)
|
|
|
|
{
|
|
|
|
char c,sign,tmp[66], *strorg = str;
|
|
|
|
const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (type & LARGE)
|
|
|
|
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
|
|
if (type & LEFT)
|
|
|
|
type &= ~ZEROPAD;
|
|
|
|
if (base < 2 || base > 36)
|
|
|
|
return 0;
|
|
|
|
c = (type & ZEROPAD) ? '0' : ' ';
|
|
|
|
sign = 0;
|
|
|
|
if (type & SIGN) {
|
|
|
|
if (num < 0) {
|
|
|
|
sign = '-';
|
|
|
|
num = -num;
|
|
|
|
size--;
|
|
|
|
} else if (type & PLUS) {
|
|
|
|
sign = '+';
|
|
|
|
size--;
|
|
|
|
} else if (type & SPACE) {
|
|
|
|
sign = ' ';
|
|
|
|
size--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (type & SPECIALX) {
|
|
|
|
if (base == 16)
|
|
|
|
size -= 2;
|
|
|
|
else if (base == 8)
|
|
|
|
size--;
|
|
|
|
}
|
|
|
|
i = 0;
|
|
|
|
if (num == 0)
|
|
|
|
tmp[i++]='0';
|
|
|
|
else while (num != 0)
|
|
|
|
tmp[i++] = digits[SkDoDiv(num,base, &num)];
|
|
|
|
|
|
|
|
if (i > precision)
|
|
|
|
precision = i;
|
|
|
|
size -= precision;
|
|
|
|
if (!(type&(ZEROPAD+LEFT)))
|
|
|
|
while(size-->0)
|
|
|
|
*str++ = ' ';
|
|
|
|
if (sign)
|
|
|
|
*str++ = sign;
|
|
|
|
if (type & SPECIALX) {
|
|
|
|
if (base==8)
|
|
|
|
*str++ = '0';
|
|
|
|
else if (base==16) {
|
|
|
|
*str++ = '0';
|
|
|
|
*str++ = digits[33];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!(type & LEFT))
|
|
|
|
while (size-- > 0)
|
|
|
|
*str++ = c;
|
|
|
|
while (i < precision--)
|
|
|
|
*str++ = '0';
|
|
|
|
while (i-- > 0)
|
|
|
|
*str++ = tmp[i];
|
|
|
|
while (size-- > 0)
|
|
|
|
*str++ = ' ';
|
|
|
|
|
|
|
|
str[0] = '\0';
|
|
|
|
|
|
|
|
return strorg;
|
|
|
|
}
|