1 /*- 2 * Copyright (c) 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 #ifndef lint 36 __COPYRIGHT("@(#) Copyright (c) 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"); 38 #endif /* not lint */ 39 40 #ifndef lint 41 #if 0 42 static char sccsid[] = "@(#)rs.c 8.1 (Berkeley) 6/6/93"; 43 #else 44 __RCSID("$NetBSD: rs.c,v 1.4 1997/10/19 14:22:16 lukem Exp $"); 45 #endif 46 #endif /* not lint */ 47 48 /* 49 * rs - reshape a data array 50 * Author: John Kunze, Office of Comp. Affairs, UCB 51 * BEWARE: lots of unfinished edges 52 */ 53 54 #include <ctype.h> 55 #include <err.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 60 long flags; 61 #define TRANSPOSE 000001 62 #define MTRANSPOSE 000002 63 #define ONEPERLINE 000004 64 #define ONEISEPONLY 000010 65 #define ONEOSEPONLY 000020 66 #define NOTRIMENDCOL 000040 67 #define SQUEEZE 000100 68 #define SHAPEONLY 000200 69 #define DETAILSHAPE 000400 70 #define RIGHTADJUST 001000 71 #define NULLPAD 002000 72 #define RECYCLE 004000 73 #define SKIPPRINT 010000 74 #define ICOLBOUNDS 020000 75 #define OCOLBOUNDS 040000 76 #define ONEPERCHAR 0100000 77 #define NOARGS 0200000 78 79 short *colwidths; 80 short *cord; 81 short *icbd; 82 short *ocbd; 83 int nelem; 84 char **elem; 85 char **endelem; 86 char *curline; 87 int allocsize = BUFSIZ; 88 int curlen; 89 int irows, icols; 90 int orows, ocols; 91 int maxlen; 92 int skip; 93 int propgutter; 94 char isep = ' ', osep = ' '; 95 int owidth = 80, gutter = 2; 96 97 void usage __P((char *, char *)); 98 void getargs __P((int, char *[])); 99 void getfile __P((void)); 100 int getline __P((void)); 101 char *getlist __P((short **, char *)); 102 char *getnum __P((int *, char *, int)); 103 char **getptrs __P((char **)); 104 int main __P((int, char **)); 105 void prepfile __P((void)); 106 void prints __P((char *, int)); 107 void putfile __P((void)); 108 109 #define INCR(ep) do { \ 110 if (++ep >= endelem) \ 111 ep = getptrs(ep); \ 112 } while(0) 113 114 int 115 main(argc, argv) 116 int argc; 117 char *argv[]; 118 { 119 getargs(argc, argv); 120 getfile(); 121 if (flags & SHAPEONLY) { 122 printf("%d %d\n", irows, icols); 123 exit(0); 124 } 125 prepfile(); 126 putfile(); 127 exit(0); 128 } 129 130 void 131 getfile() 132 { 133 char *p; 134 char *endp; 135 char **ep = 0; 136 int multisep = (flags & ONEISEPONLY ? 0 : 1); 137 int nullpad = flags & NULLPAD; 138 char **padto; 139 140 while (skip--) { 141 getline(); 142 if (flags & SKIPPRINT) 143 puts(curline); 144 } 145 getline(); 146 if (flags & NOARGS && curlen < owidth) 147 flags |= ONEPERLINE; 148 if (flags & ONEPERLINE) 149 icols = 1; 150 else /* count cols on first line */ 151 for (p = curline, endp = curline + curlen; p < endp; p++) { 152 if (*p == isep && multisep) 153 continue; 154 icols++; 155 while (*p && *p != isep) 156 p++; 157 } 158 ep = getptrs(elem); 159 p = curline; 160 do { 161 if (flags & ONEPERLINE) { 162 *ep = curline; 163 INCR(ep); /* prepare for next entry */ 164 if (maxlen < curlen) 165 maxlen = curlen; 166 irows++; 167 continue; 168 } 169 for (p = curline, endp = curline + curlen; p < endp; p++) { 170 if (*p == isep && multisep) 171 continue; /* eat up column separators */ 172 if (*p == isep) /* must be an empty column */ 173 *ep = ""; 174 else /* store column entry */ 175 *ep = p; 176 while (p < endp && *p != isep) 177 p++; /* find end of entry */ 178 *p = '\0'; /* mark end of entry */ 179 if (maxlen < p - *ep) /* update maxlen */ 180 maxlen = p - *ep; 181 INCR(ep); /* prepare for next entry */ 182 } 183 irows++; /* update row count */ 184 if (nullpad) { /* pad missing entries */ 185 padto = elem + irows * icols; 186 while (ep < padto) { 187 *ep = ""; 188 INCR(ep); 189 } 190 } 191 } while (getline() != EOF); 192 *ep = 0; /* mark end of pointers */ 193 nelem = ep - elem; 194 } 195 196 void 197 putfile() 198 { 199 char **ep; 200 int i, j, n; 201 202 ep = elem; 203 if (flags & TRANSPOSE) { 204 for (i = 0; i < orows; i++) { 205 for (j = i; j < nelem; j += orows) 206 prints(ep[j], (j - i) / orows); 207 putchar('\n'); 208 } 209 } else { 210 for (n = 0, i = 0; i < orows && n < nelem; i++) { 211 for (j = 0; j < ocols; j++) { 212 if (n++ >= nelem) 213 break; 214 prints(*ep++, j); 215 } 216 putchar('\n'); 217 } 218 } 219 } 220 221 void 222 prints(s, col) 223 char *s; 224 int col; 225 { 226 int n; 227 char *p = s; 228 229 while (*p) 230 p++; 231 n = (flags & ONEOSEPONLY ? 1 : colwidths[col] - (p - s)); 232 if (flags & RIGHTADJUST) 233 while (n-- > 0) 234 putchar(osep); 235 for (p = s; *p; p++) 236 putchar(*p); 237 while (n-- > 0) 238 putchar(osep); 239 } 240 241 void 242 usage(msg, s) 243 char *msg, *s; 244 { 245 warnx(msg, s); 246 fprintf(stderr, 247 "Usage: rs [ -[csCS][x][kKgGw][N]tTeEnyjhHm ] [ rows [ cols ] ]\n"); 248 exit(1); 249 } 250 251 void 252 prepfile() 253 { 254 char **ep; 255 int i; 256 int j; 257 char **lp; 258 int colw; 259 int max = 0; 260 int n; 261 262 ep = NULL; 263 if (!nelem) 264 exit(0); 265 gutter += maxlen * propgutter / 100.0; 266 colw = maxlen + gutter; 267 if (flags & MTRANSPOSE) { 268 orows = icols; 269 ocols = irows; 270 } 271 else if (orows == 0 && ocols == 0) { /* decide rows and cols */ 272 ocols = owidth / colw; 273 if (ocols == 0) { 274 warnx("Display width %d is less than column width %d\n", owidth, colw); 275 ocols = 1; 276 } 277 if (ocols > nelem) 278 ocols = nelem; 279 orows = nelem / ocols + (nelem % ocols ? 1 : 0); 280 } 281 else if (orows == 0) /* decide on rows */ 282 orows = nelem / ocols + (nelem % ocols ? 1 : 0); 283 else if (ocols == 0) /* decide on cols */ 284 ocols = nelem / orows + (nelem % orows ? 1 : 0); 285 lp = elem + orows * ocols; 286 while (lp > endelem) { 287 getptrs(elem + nelem); 288 lp = elem + orows * ocols; 289 } 290 if (flags & RECYCLE) { 291 for (ep = elem + nelem; ep < lp; ep++) 292 *ep = *(ep - nelem); 293 nelem = lp - elem; 294 } 295 if (!(colwidths = (short *) malloc(ocols * sizeof(short)))) 296 errx(1, "malloc: No gutter space"); 297 if (flags & SQUEEZE) { 298 if (flags & TRANSPOSE) 299 for (ep = elem, i = 0; i < ocols; i++) { 300 for (j = 0; j < orows; j++) 301 if ((n = strlen(*ep++)) > max) 302 max = n; 303 colwidths[i] = max + gutter; 304 } 305 else 306 for (i = 0; i < ocols; i++) { 307 for (j = i; j < nelem; j += ocols) 308 if ((n = strlen(ep[j])) > max) 309 max = n; 310 colwidths[i] = max + gutter; 311 } 312 } 313 /* for (i = 0; i < orows; i++) { 314 for (j = i; j < nelem; j += orows) 315 prints(ep[j], (j - i) / orows); 316 putchar('\n'); 317 } 318 else 319 for (i = 0; i < orows; i++) { 320 for (j = 0; j < ocols; j++) 321 prints(*ep++, j); 322 putchar('\n'); 323 }*/ 324 else 325 for (i = 0; i < ocols; i++) 326 colwidths[i] = colw; 327 if (!(flags & NOTRIMENDCOL)) { 328 if (flags & RIGHTADJUST) 329 colwidths[0] -= gutter; 330 else 331 colwidths[ocols - 1] = 0; 332 } 333 n = orows * ocols; 334 if (n > nelem && (flags & RECYCLE)) 335 nelem = n; 336 /*for (i = 0; i < ocols; i++) 337 fprintf(stderr, "%d ",colwidths[i]); 338 fprintf(stderr, "is colwidths, nelem %d\n", nelem);*/ 339 } 340 341 #define BSIZE 2048 342 char ibuf[BSIZE]; /* two screenfuls should do */ 343 344 int 345 getline() /* get line; maintain curline, curlen; manage storage */ 346 { 347 static int putlength; 348 static char *endblock = ibuf + BSIZE; 349 char *p; 350 int c, i; 351 352 if (!irows) { 353 curline = ibuf; 354 putlength = flags & DETAILSHAPE; 355 } 356 else if (skip <= 0) { /* don't waste storage */ 357 curline += curlen + 1; 358 if (putlength) /* print length, recycle storage */ 359 printf(" %d line %d\n", curlen, irows); 360 } 361 if (!putlength && endblock - curline < BUFSIZ) { /* need storage */ 362 /*ww = endblock-curline; tt += ww;*/ 363 /*printf("#wasted %d total %d\n",ww,tt);*/ 364 if (!(curline = (char *) malloc(BSIZE))) 365 errx(1, "File too large"); 366 endblock = curline + BSIZE; 367 /*printf("#endb %d curline %d\n",endblock,curline);*/ 368 } 369 for (p = curline, i = 1; i < BUFSIZ; *p++ = c, i++) 370 if ((c = getchar()) == EOF || c == '\n') 371 break; 372 *p = '\0'; 373 curlen = i - 1; 374 return(c); 375 } 376 377 char ** 378 getptrs(sp) 379 char **sp; 380 { 381 char **p; 382 383 allocsize += allocsize; 384 p = (char **)realloc(elem, allocsize * sizeof(char *)); 385 if (p == (char **)0) 386 err(1, "no memory"); 387 388 sp += (p - elem); 389 endelem = (elem = p) + allocsize; 390 return(sp); 391 } 392 393 void 394 getargs(ac, av) 395 int ac; 396 char *av[]; 397 { 398 char *p; 399 400 if (ac == 1) { 401 flags |= NOARGS | TRANSPOSE; 402 } 403 while (--ac && **++av == '-') 404 for (p = *av+1; *p; p++) 405 switch (*p) { 406 case 'T': 407 flags |= MTRANSPOSE; 408 case 't': 409 flags |= TRANSPOSE; 410 break; 411 case 'c': /* input col. separator */ 412 flags |= ONEISEPONLY; 413 case 's': /* one or more allowed */ 414 if (p[1]) 415 isep = *++p; 416 else 417 isep = '\t'; /* default is ^I */ 418 break; 419 case 'C': 420 flags |= ONEOSEPONLY; 421 case 'S': 422 if (p[1]) 423 osep = *++p; 424 else 425 osep = '\t'; /* default is ^I */ 426 break; 427 case 'w': /* window width, default 80 */ 428 p = getnum(&owidth, p, 0); 429 if (owidth <= 0) 430 usage("Width must be a positive integer", ""); 431 break; 432 case 'K': /* skip N lines */ 433 flags |= SKIPPRINT; 434 case 'k': /* skip, do not print */ 435 p = getnum(&skip, p, 0); 436 if (!skip) 437 skip = 1; 438 break; 439 case 'm': 440 flags |= NOTRIMENDCOL; 441 break; 442 case 'g': /* gutter space */ 443 p = getnum(&gutter, p, 0); 444 break; 445 case 'G': 446 p = getnum(&propgutter, p, 0); 447 break; 448 case 'e': /* each line is an entry */ 449 flags |= ONEPERLINE; 450 break; 451 case 'E': 452 flags |= ONEPERCHAR; 453 break; 454 case 'j': /* right adjust */ 455 flags |= RIGHTADJUST; 456 break; 457 case 'n': /* null padding for missing values */ 458 flags |= NULLPAD; 459 break; 460 case 'y': 461 flags |= RECYCLE; 462 break; 463 case 'H': /* print shape only */ 464 flags |= DETAILSHAPE; 465 case 'h': 466 flags |= SHAPEONLY; 467 break; 468 case 'z': /* squeeze col width */ 469 flags |= SQUEEZE; 470 break; 471 /*case 'p': 472 ipagespace = atoi(++p); (default is 1) 473 break;*/ 474 case 'o': /* col order */ 475 p = getlist(&cord, p); 476 break; 477 case 'b': 478 flags |= ICOLBOUNDS; 479 p = getlist(&icbd, p); 480 break; 481 case 'B': 482 flags |= OCOLBOUNDS; 483 p = getlist(&ocbd, p); 484 break; 485 default: 486 usage("Bad flag: %.1s", p); 487 } 488 /*if (!osep) 489 osep = isep;*/ 490 switch (ac) { 491 /*case 3: 492 opages = atoi(av[2]);*/ 493 case 2: 494 ocols = atoi(av[1]); 495 case 1: 496 orows = atoi(av[0]); 497 case 0: 498 break; 499 default: 500 usage("Too many arguments.", ""); 501 } 502 } 503 504 char * 505 getlist(list, p) 506 short **list; 507 char *p; 508 { 509 int count = 1; 510 char *t; 511 512 for (t = p + 1; *t; t++) { 513 if (!isdigit(*t)) 514 usage("Option %.1s requires a list of unsigned numbers separated by commas", t); 515 count++; 516 while (*t && isdigit(*t)) 517 t++; 518 if (*t != ',') 519 break; 520 } 521 if (!(*list = (short *) malloc(count * sizeof(short)))) 522 errx(1, "No list space"); 523 count = 0; 524 for (t = p + 1; *t; t++) { 525 (*list)[count++] = atoi(t); 526 printf("++ %d ", (*list)[count-1]); 527 fflush(stdout); 528 while (*t && isdigit(*t)) 529 t++; 530 if (*t != ',') 531 break; 532 } 533 (*list)[count] = 0; 534 return(t - 1); 535 } 536 537 char * 538 getnum(num, p, strict) /* num = number p points to; if (strict) complain */ 539 int *num, strict; /* returns pointer to end of num */ 540 char *p; 541 { 542 char *t = p; 543 544 if (!isdigit(*++t)) { 545 if (strict || *t == '-' || *t == '+') 546 usage("Option %.1s requires an unsigned integer", p); 547 *num = 0; 548 return(p); 549 } 550 *num = atoi(t); 551 while (*++t) 552 if (!isdigit(*t)) 553 break; 554 return(--t); 555 } 556