├── Makefile ├── lc_manual.png ├── README.md ├── LICENSE.md └── lc.c /Makefile: -------------------------------------------------------------------------------- 1 | lc: lc.c 2 | $(CC) $(CFLAGS) -o $@ $< 3 | -------------------------------------------------------------------------------- /lc_manual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gdm85/lc/HEAD/lc_manual.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a port of 'lc' (List files in categories and columns) from MWC (Mark Williams Company) [Coherent UNIX](https://en.wikipedia.org/wiki/Coherent_(operating_system)). 2 | 3 | You can find the original source tarball here: http://www.nesssoftware.com/home/mwc/source.php 4 | 5 | The original source file is `COHERENT/romana/relic/d/bin/lc.c` in the archive. 6 | 7 | ## Manual 8 | 9 | The original manual page: 10 | ![lc manual page](./lc_manual.png) 11 | 12 | ## Differences from original 13 | 14 | I added support of symlinks (`-l` command-line option). 15 | 16 | ## License 17 | 18 | Released with the original [LICENSE](./LICENSE.md). 19 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # License 2 | 3 | Copyright © 1977-1995 by Robert Swartz. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | 9 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | 11 | Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 12 | 13 | This software is provided by the copyright holders and contributors "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the copyright holder or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. 14 | -------------------------------------------------------------------------------- /lc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * List files in categories (and columns) 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define WIDTH 79 /* Default line width */ 15 | #define GAP 1 /* Minimum gap between columns */ 16 | #define INDENT1 4 /* Indent for multiple directories */ 17 | #define INDENT2 4 /* Indent for files in a category */ 18 | #define NFNAME 400 /* Maximum a filename can expand to */ 19 | 20 | // from source/4.2.x/usr/include/kernel/dir.h 21 | //# define DIRSIZ 14 22 | #define DIRSIZ MAXNAMLEN 23 | 24 | int oneflag; /* One per line */ 25 | int aflag; /* Do all entries, including `.' and `..' */ 26 | int bflag; /* Do block special */ 27 | int cflag; /* Do character special */ 28 | int dflag; /* Do directories */ 29 | int fflag; /* Do regular files */ 30 | int lflag; /* Do symlinks */ 31 | int mflag; /* Do multiplexor files */ 32 | int pflag; /* Do pipes */ 33 | int allflag = 1; /* Do all types */ 34 | int ndir; 35 | int printed = 0; /* Set when we have printed something */ 36 | int maxwidth; /* Maximum width of a filename */ 37 | int lwidth = WIDTH-INDENT2; 38 | 39 | struct stat sb; 40 | char obuf[BUFSIZ]; 41 | char fname[NFNAME]; 42 | 43 | typedef struct ENTRY { 44 | struct ENTRY *e_fp; 45 | char e_name[DIRSIZ]; 46 | } ENTRY; 47 | 48 | ENTRY *files, *links, *dirs, *blocks, *chars, *pipes, *mults; 49 | 50 | void usage(); 51 | void prtype(ENTRY *list, char *type); 52 | void addlist(ENTRY **lpp, ENTRY *ep); 53 | void clearlist(ENTRY **lpp); 54 | int doentry(char *dirname, struct dirent *dp); 55 | void prnames(); 56 | int lcdir(char *dname); 57 | int lc(char *name); 58 | 59 | 60 | /* 61 | * Print a line with possible indent. 62 | */ 63 | /* VARARGS */ 64 | #define prindent(...) \ 65 | if (ndir > 1) \ 66 | printf("%*s", INDENT1, ""); \ 67 | printf(__VA_ARGS__); \ 68 | printed = 1; 69 | 70 | #define prindent_empty() \ 71 | if (ndir > 1) \ 72 | printf("%*s", INDENT1, ""); \ 73 | printed = 1; 74 | 75 | int main(int argc, char *argv[]) 76 | { 77 | register char *ap; 78 | register int i; 79 | register int estat = 0; 80 | 81 | while (argc>1 && *argv[1]=='-') { 82 | for (ap = &argv[1][1]; *ap!='\0'; ap++) 83 | switch (*ap) { 84 | case 'f': 85 | fflag = 1; 86 | allflag = 0; 87 | break; 88 | 89 | case 'd': 90 | dflag = 1; 91 | allflag = 0; 92 | break; 93 | 94 | case 'l': 95 | lflag = 1; 96 | allflag = 0; 97 | break; 98 | 99 | case 'm': 100 | mflag = 1; 101 | allflag = 0; 102 | break; 103 | 104 | case 'b': 105 | bflag = 1; 106 | allflag = 0; 107 | break; 108 | 109 | case 'c': 110 | cflag = 1; 111 | allflag = 0; 112 | break; 113 | 114 | case 'p': 115 | pflag = 1; 116 | allflag = 0; 117 | break; 118 | 119 | case '1': 120 | oneflag = 1; 121 | break; 122 | 123 | case 'a': 124 | aflag = 1; 125 | break; 126 | 127 | default: 128 | usage(); 129 | } 130 | argv++; 131 | argc--; 132 | } 133 | if (allflag) 134 | fflag = dflag = cflag = bflag = mflag = lflag = pflag = 1; 135 | setbuf(stdout, obuf); 136 | if (argc < 2) { 137 | ndir = 1; 138 | estat = lc("."); 139 | } else { 140 | if (argc > 2) 141 | lwidth -= INDENT1; 142 | ndir = argc-1; 143 | for (i=1; i 1) { 217 | if (printed) 218 | putchar('\n'); 219 | printf("%s:\n", dname); 220 | } 221 | printed = 0; 222 | if (!(fd = opendir(dname))) { 223 | fprintf(stderr, "Cannot open directory `%s'\n", dname); 224 | return 1; 225 | } 226 | errno = 0; 227 | while ((dp = readdir(fd)) != NULL) { 228 | if (dp->d_ino == 0) { 229 | errno = 0; 230 | continue; 231 | } 232 | doentry(dname, dp); 233 | errno = 0; 234 | } 235 | int rd_errno = errno; 236 | closedir(fd); 237 | prnames(); 238 | if (rd_errno) { 239 | fprintf(stderr, "%s: directory read error: %s\n", dname, strerror(rd_errno)); 240 | return (1); 241 | } 242 | return (0); 243 | } 244 | 245 | /* 246 | * Do a stat on one filename in the 247 | * indicated directory. 248 | * and then sort into the appropriate table. 249 | */ 250 | int doentry(dirname, dp) 251 | char *dirname; 252 | struct dirent *dp; 253 | { 254 | int width = 0; 255 | 256 | { 257 | register char *p = dp->d_name; 258 | 259 | if (!aflag 260 | && *p++=='.' && (*p=='\0' || (*p++=='.' && *p=='\0'))) 261 | return (0); 262 | } { 263 | register char *p1, *p2; 264 | register unsigned n = DIRSIZ; 265 | 266 | p1 = fname; 267 | p2 = dirname; 268 | while (*p1++ = *p2++) 269 | ; 270 | p1--; 271 | if (*p1 != '/') 272 | *p1++ = '/'; 273 | p2 = dp->d_name; 274 | do { 275 | if (*p2 == '\0') 276 | break; 277 | width++; 278 | *p1++ = *p2++; 279 | } while (--n); 280 | *p1 = '\0'; 281 | } 282 | if (width > maxwidth) 283 | maxwidth = width; 284 | if (stat(fname, &sb) < 0) { 285 | prindent("%.*s: cannot stat\n", DIRSIZ, dp->d_name); 286 | return (1); 287 | } { 288 | register ENTRY *ep; 289 | register ENTRY **list; 290 | 291 | if ((ep = (ENTRY *)malloc(sizeof (ENTRY))) == NULL) { 292 | fprintf(stderr, "Out of memory\n"); 293 | exit (1); 294 | } 295 | strncpy(ep->e_name, dp->d_name, DIRSIZ); 296 | switch (sb.st_mode & S_IFMT) { 297 | case S_IFREG: 298 | list = &files; 299 | break; 300 | 301 | case S_IFLNK: 302 | list = &links; 303 | break; 304 | 305 | case S_IFDIR: 306 | list = &dirs; 307 | break; 308 | 309 | case S_IFBLK: 310 | list = &blocks; 311 | break; 312 | 313 | case S_IFCHR: 314 | list = &chars; 315 | break; 316 | 317 | case S_IFSOCK: 318 | list = &mults; 319 | break; 320 | 321 | case S_IFIFO: 322 | list = &pipes; 323 | break; 324 | 325 | default: 326 | prindent("%.*s: unknown file type\n", DIRSIZ, 327 | dp->d_name); 328 | return (1); 329 | } 330 | addlist(list, ep); 331 | } 332 | return (0); 333 | } 334 | 335 | /* 336 | * Add an entry to the list. 337 | * Sort the list at insertion time 338 | * into lexicographic order. 339 | */ 340 | void addlist(lpp, ep) 341 | ENTRY **lpp; 342 | ENTRY *ep; 343 | { 344 | register ENTRY *rp; 345 | register ENTRY *pp; 346 | 347 | for (pp=NULL, rp=*lpp; rp!=NULL; pp=rp, rp=rp->e_fp) 348 | if (strncmp(ep->e_name, rp->e_name, DIRSIZ) <= 0) 349 | break; 350 | if (pp == NULL) { 351 | ep->e_fp = *lpp; 352 | *lpp = ep; 353 | } else { 354 | ep->e_fp = pp->e_fp; 355 | pp->e_fp = ep; 356 | } 357 | } 358 | 359 | /* 360 | * Clear out the list, a pointer to which is 361 | * the argument. 362 | */ 363 | void clearlist(lpp) 364 | ENTRY **lpp; 365 | { 366 | register ENTRY *rp, *op; 367 | 368 | rp = *lpp; 369 | while (rp != NULL) { 370 | op = rp; 371 | rp = rp->e_fp; 372 | free(op); 373 | } 374 | *lpp = NULL; 375 | } 376 | 377 | /* 378 | * Print out the appropriate names. 379 | */ 380 | void prnames() 381 | { 382 | if (dflag) 383 | prtype(dirs, "Directories"); 384 | if (fflag) 385 | prtype(files, "Files"); 386 | if (lflag) 387 | prtype(links, "Symlinks"); 388 | if (cflag) 389 | prtype(chars, "Character special files"); 390 | if (bflag) 391 | prtype(blocks, "Block special files"); 392 | if (pflag) 393 | prtype(pipes, "Pipes"); 394 | if (mflag) 395 | prtype(mults, "Multiplexed files"); 396 | } 397 | 398 | /* 399 | * Print out one type of files 400 | */ 401 | void prtype(list, type) 402 | ENTRY *list; 403 | char *type; 404 | { 405 | register char *cp; 406 | register ENTRY *ep; 407 | register int n; 408 | register int i; 409 | int npl; 410 | 411 | if (list == NULL) 412 | return; 413 | if (printed) 414 | putchar('\n'); 415 | if(!oneflag) 416 | prindent("%s:\n", type); 417 | if (oneflag) 418 | npl = 1; 419 | else 420 | npl = lwidth/(maxwidth+GAP); 421 | ep = list; 422 | i = 0; 423 | for (ep = list; ep != NULL; ep = ep->e_fp) { 424 | if (!oneflag && (i == 0)) { 425 | printf("%*s", INDENT2, ""); 426 | prindent_empty(); 427 | } 428 | n = DIRSIZ; 429 | for (cp=ep->e_name; *cp!='\0' && n; n--) 430 | putchar(*cp++); 431 | if (++i!=npl && ep->e_fp!=NULL) { 432 | n -= DIRSIZ-GAP-maxwidth; 433 | while (n-- > 0) 434 | putchar(' '); 435 | } else { 436 | i = 0; 437 | putchar('\n'); 438 | } 439 | } 440 | } 441 | 442 | void usage() 443 | { 444 | fprintf(stderr, "Usage: lc [-afdcbpl] [-1] [name ...]\n"); 445 | exit(1); 446 | } 447 | --------------------------------------------------------------------------------