/* $Id: config.c,v 1.16 2012/08/09 19:17:10 ksb Exp $ * binpack files on stdin (ksb) */ #include #include #include #include #include #include #include #include #include #include #include "machine.h" #include "config.h" #include "binpack.h" #include "shquote.h" #include "main.h" extern int errno; #if !HAVE_STRERROR extern char *sys_errlist[]; #define strerror(Me) (sys_errlist[Me]) #endif /* mkcmd call-back to remember argv's value after option procs (ksb) * And we set a binsize if you gave -N and not -b. */ static char **ppcArgv; static size_t wBaseSz; void SetCmd(int argc, char **argv) { register size_t w; auto char acMaxNum[64]; /* %ld */ extern char **environ; ppcArgv = argv; if (!fLiteral) return; /* Remove space from NCARGS for fixes argv and the environment */ if (!fGaveB) bsize = sysconf(_SC_ARG_MAX); if ((char *)0 == pcOverhead) iOverhead = sizeof(char *); for (w = 2*sizeof(char *); (char *)0 != *argv; ++argv) w += strlen(*argv)+1+sizeof(char *); for (argv = environ; (char *)0 != *argv; ++argv) w += strlen(*argv)+1+sizeof(char *); if ((char *)0 != pcSizeEnv) { /* We will add "$SizeEnv=%ld " to the command */ snprintf(acMaxNum, sizeof(acMaxNum), "%ld", bsize > w ? (long)bsize-w : bsize); wBaseSz = strlen(pcSizeEnv)+strlen(acMaxNum)+2; w += wBaseSz; } if (bsize > w) bsize -= w; else bsize = 0; bsize += wBaseSz; } /* I thought about doing some processing here and did't (ksb) */ static VEWEIGHT CWeight(VE VEElem) { return VEElem.isize; } VEWEIGHT wWasted = 0; /* Pack as many bins as we can, if this is the last call we even (ksb) * pack the patial bin at the end, otherwise we copy the left-overs * to the front of the list for the next pack session. */ static int PackSome(VE *pVE, int *pn, VEWEIGHT (*pfwW)(), VEWEIGHT wB, int fLast) { register VEWEIGHT wSize; register int bins, obins, i, j, fSpc, iScan; register char **ppc; /* this orders the elements into binpack order * and returns the number of proper bins. */ obins = bins = VEbinpack(pVE, *pn, pfwW, wB, (size_t *)0); if (!fLast && bins > 1) --bins; /* bins that fit `best' */ for (i = j = 0; j < bins; ++j) { wSize = wBaseSz; for (iScan = i; wSize + CWeight(pVE[iScan]) <= wB && iScan < *pn; ++iScan) { wSize += CWeight(pVE[iScan]); } fSpc = 0; /* Report the size in col1, or as an assignment */ if ((char *)0 != pcSizeEnv) { if ('\000' != *pcSizeEnv) { printf("%s=", pcSizeEnv); } printf("%lu", (unsigned long)wSize); fSpc = 1; } for (ppc = ppcArgv; (char *)0 != *ppc; ++ppc) { if (fSpc) putchar(' '); OutQuote(*ppc); fSpc = 1; } for (/* continue */; i < iScan; ++i) { if (fSpc) putchar(' '); OutQuote(pVE[i].pcname); fSpc = 1; } printf("\n"); if (j < bins-1) wWasted += wB - wSize; } /* skip the partially filled bin at the end */ j = 0; if (obins != bins) { wSize = wBaseSz; while (wSize + CWeight(pVE[i]) <= wB && i < *pn) { pVE[j] = pVE[i]; wSize += CWeight(pVE[i]); ++j, ++i; } } while (i < *pn) { fSpc = 0; if ((char *)0 != pcSizeEnv) { if ('\000' != *pcSizeEnv) { printf("%s=", pcSizeEnv); } printf("%lu", (unsigned long) CWeight(pVE[i])+wBaseSz); fSpc = 1; } for (ppc = ppcArgv; (char *)0 != *ppc; ++ppc) { if (fSpc) putchar(' '); OutQuote(*ppc); fSpc = 1; } if (fSpc) putchar(' '); OutQuote(pVE[i].pcname); printf("\n"); ++i, ++bins; } *pn = j; return bins; } /* Get the next filename from the input file (ksb) */ static char * NextFile(FILE *fp, int fPrint0) { register int iC, iEos, i; static char *pcMem; static int iMax; iEos = fPrint0 ? '\000' : '\n'; if ((char *)0 == pcMem || (FILE *)0 == fp) { if ((char *)0 != pcMem) { free((void *)pcMem); } iMax = 1024+4; pcMem = calloc(iMax, sizeof(char)); if ((char *)0 == pcMem) { return pcMem; } } for (i = 0; EOF != (iC = getc(fp)); ++i) { if (iMax == i+1) { iMax += 512; pcMem = realloc((void *)pcMem, iMax*sizeof(char)); if ((char *)0 == pcMem) { return pcMem; } } if (iEos == iC) { break; } pcMem[i] = iC; } pcMem[i] = '\000'; return i == 0 ? (char *)0 : pcMem; } /* Mkcmd call-back to do the work (ksb) * Fill the buffer of filenames, pack some, then refill the buffer. * On the last trip we tell the packer to include the last bits too. */ int DoPack(int fPrint0) { register char *pcBuf; auto char *pcEnd; auto int n, bins; auto VE *pVE; auto VEWEIGHT wSize, iRem; auto struct stat statbuf; pVE = (VE *)calloc(sizeof(VE), iMaxNums); if ((VE *)0 == pVE) { fprintf(stderr, "%s: calloc: no more memory\n", progname); exit(EX_OSERR); } bins = n = 0; while ((char *)0 != (pcBuf = NextFile(stdin, fPrint0))) { if (n == iMaxNums){ bins += PackSome(pVE, & n, CWeight, bsize, 0); if (n == iMaxNums) { fprintf(stderr, "%s: too many files\n", progname); exit(EX_OSERR); } } if ((char *)0 == (pVE[n].pcname = strdup(pcBuf))) { fprintf(stderr, "%s: strdup: %s\n", progname, strerror(errno)); exit(EX_OSERR); } if (fUserSize) { pcEnd = (char *)0; wSize = (VEWEIGHT)strtol(pVE[n].pcname, & pcEnd, 0); if ((char *)0 == pcEnd || pcEnd == pVE[n].pcname) { fprintf(stderr, "%s: -u: %s: cannot convert size\n", progname, pVE[n].pcname); exit(EX_DATAERR); } while (isspace(*pcEnd)) { ++pcEnd; } /* if you just gave the number use it as the payload */ if ('\000' != *pcEnd) { pVE[n].pcname = pcEnd; } } else if (fLiteral) { wSize = strlen(pcBuf)+1 + iPacking; if (0 != (iRem = (wSize % iRound))) { wSize += iRound - iRem; } wSize += iOverhead; } else if (-1 == stat(pcBuf, & statbuf)) { fprintf(stderr, "%s: stat: %s: %s\n", progname, pcBuf, strerror(errno)); continue; } else { wSize = statbuf.st_size + iPacking; if (0 != (iRem = (wSize % iRound))) { wSize += iRound - iRem; } wSize += iOverhead; } pVE[n].isize = wSize; ++n; } /* Finish whatever we have left. */ bins += PackSome(pVE, & n, CWeight, bsize, 1); if (fVerbose && --bins > 0) { fprintf(stderr, "%s: total of %lu space wasted in %d bins, ave %lu per bin %lu%%\n", progname, wWasted, bins, wWasted/bins, (100*wWasted)/(bins*bsize) ); } return 0; }