home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1998 September / PCO_0998.ISO / filesbbs / dos / sbbs_src.exe / SBBS / FILELIST / FILELIST.C next >
Encoding:
C/C++ Source or Header  |  1997-05-18  |  18.0 KB  |  658 lines

  1. /* FILELIST.C */
  2.  
  3. /* Developed 1990-1997 by Rob Swindell; PO Box 501, Yorba Linda, CA 92885 */
  4.  
  5. /* Utility to create list of files from Synchronet file directories */
  6. /* Default list format is FILES.BBS, but file size, uploader, upload date */
  7. /* and other information can be included. */
  8.  
  9. #include "sbbs.h"
  10.  
  11. #define FILELIST_VER "2.11"
  12.  
  13. #define MAX_NOTS 25
  14.  
  15. #ifdef lputs
  16. #undef lputs
  17. #endif
  18.  
  19. long lputs(char FAR16 *str)
  20. {
  21.     char tmp[256];
  22.     int i,j,k;
  23.  
  24. j=strlen(str);
  25. for(i=k=0;i<j;i++)      /* remove CRs */
  26.     if(str[i]==CR && str[i+1]==LF)
  27.         continue;
  28.     else
  29.         tmp[k++]=str[i];
  30. tmp[k]=0;
  31. return(fputs(tmp,stdout));
  32. }
  33.  
  34.  
  35. /****************************************************************************/
  36. /* Performs printf() through local assembly routines                        */
  37. /* Called from everywhere                                                   */
  38. /****************************************************************************/
  39. int lprintf(char *fmat, ...)
  40. {
  41.     va_list argptr;
  42.     char sbuf[256];
  43.     int chcount;
  44.  
  45. va_start(argptr,fmat);
  46. chcount=vsprintf(sbuf,fmat,argptr);
  47. va_end(argptr);
  48. lputs(sbuf);
  49. return(chcount);
  50. }
  51.  
  52. /****************************************************************************/
  53. /* Turns FILE    .EXT into FILE.EXT                                         */
  54. /* Called from upload                                                       */
  55. /****************************************************************************/
  56. char *unpadfname(char *filename, char *str)
  57. {
  58.     char c,d;
  59.  
  60. for(c=0,d=0;c<strlen(filename);c++)
  61.     if(filename[c]!=SP) str[d++]=filename[c];
  62. str[d]=0;
  63. return(str);
  64. }
  65.  
  66. #ifndef __FLAT__
  67. /****************************************************************************/
  68. /* This function reads files that are potentially larger than 32k.          */
  69. /* Up to one megabyte of data can be read with each call.                   */
  70. /****************************************************************************/
  71. long lread(int file, char huge *buf,long bytes)
  72. {
  73.     long count;
  74.  
  75. for(count=bytes;count>32767;count-=32767,buf+=32767)
  76.     if(read(file,(char *)buf,32767)!=32767)
  77.         return(-1L);
  78. if(read(file,(char *)buf,(int)count)!=count)
  79.     return(-1L);
  80. return(bytes);
  81. }
  82. #endif
  83. /****************************************************************************/
  84. /* Checks the disk drive for the existence of a file. Returns 1 if it       */
  85. /* exists, 0 if it doesn't.                                                 */
  86. /****************************************************************************/
  87. char fexist(char *filespec)
  88. {
  89.     struct find_t f;
  90.     uint i;
  91.  
  92. i=_dos_findfirst(filespec,_A_NORMAL,&f);
  93. #ifdef __WATCOMC__
  94. _dos_findclose(&f);
  95. #endif
  96. if(!i)
  97.     return(1);
  98. return(0);
  99. }
  100.  
  101. /****************************************************************************/
  102. /* Returns the time/date of the file in 'filespec' in time_t (unix) format  */
  103. /****************************************************************************/
  104. long fdate(char *filespec)
  105. {
  106.     int     file;
  107.     ushort    fd,ft;
  108.     struct    tm t;
  109.  
  110. if((file=nopen(filespec,O_RDONLY))==-1)
  111.     return(0);
  112. _dos_getftime(file,&fd,&ft);
  113. close(file);
  114. memset(&t,0,sizeof(t));
  115. t.tm_year=((fd&0xfe00)>>9)+80;
  116. t.tm_mon=((fd&0x01e0)>>5)-1;
  117. t.tm_mday=fd&0x1f;
  118. t.tm_hour=(ft&0xf800)>>11;
  119. t.tm_min=(ft&0x07e0)>>5;
  120. t.tm_sec=(ft&0x001f)<<1;
  121. return(mktime(&t));
  122. }
  123.  
  124. /****************************************************************************/
  125. /* Converts an ASCII Hex string into an ulong                       */
  126. /****************************************************************************/
  127. ulong ahtoul(char *str)
  128. {
  129.     ulong l,val=0;
  130.  
  131. while((l=(*str++)|0x20)!=0x20)
  132.     val=(l&0xf)+(l>>6&1)*9+val*16;
  133. return(val);
  134. }
  135.  
  136. /****************************************************************************/
  137. /* Truncates white-space chars off end of 'str' and terminates at first tab */
  138. /****************************************************************************/
  139. void truncsp(char *str)
  140. {
  141.     int c;
  142.  
  143. str[strcspn(str,"\t")]=0;
  144. c=strlen(str);
  145. while(c && (uchar)str[c-1]<=SP) c--;
  146. str[c]=0;
  147. }
  148.  
  149. void stripctrlz(char *str)
  150. {
  151.     char tmp[1024];
  152.     int i,j,k;
  153.  
  154. k=strlen(str);
  155. for(i=j=0;i<k;i++)
  156.     if(str[i]!=0x1a)
  157.         tmp[j++]=str[i];
  158. tmp[j]=0;
  159. strcpy(str,tmp);
  160. }
  161.  
  162.  
  163. /****************************************************************************/
  164. /* Puts a backslash on path strings                                         */
  165. /****************************************************************************/
  166. void backslash(char *str)
  167. {
  168.     int i;
  169.  
  170. i=strlen(str);
  171. if(i && str[i-1]!='\\') {
  172.     str[i]='\\'; str[i+1]=0; }
  173. }
  174.  
  175.  
  176. /****************************************************************************/
  177. /* Places into 'strout' CR or ETX terminated string starting at             */
  178. /* 'start' and ending at 'start'+'length' or terminator from 'strin'        */
  179. /****************************************************************************/
  180. void getrec(char *strin,int start,int length,char *strout)
  181. {
  182.     int i=0,stop;
  183.  
  184. stop=start+length;
  185. while(start<stop) {
  186.     if(strin[start]==ETX)
  187.         break;
  188.     strout[i++]=strin[start++]; }
  189. strout[i]=0;
  190. }
  191.  
  192. /****************************************************************************/
  193. /* Network open function. Opens all files DENYALL and retries LOOP_NOPEN    */
  194. /* number of times if the attempted file is already open or denying access    */
  195. /* for some other reason.    All files are opened in BINARY mode.            */
  196. /****************************************************************************/
  197. int nopen(char *str, int access)
  198. {
  199.     char logstr[256];
  200.     int file,share,count=0;
  201.  
  202. if(access==O_RDONLY) share=SH_DENYWR;
  203.     else share=SH_DENYRW;
  204. while(((file=sopen(str,O_BINARY|access,share,S_IWRITE))==-1)
  205.     && errno==EACCES && count++<LOOP_NOPEN);
  206. if(file==-1 && errno==EACCES)
  207.     lputs("\7\r\nNOPEN: ACCESS DENIED\r\n\7");
  208. return(file);
  209. }
  210.  
  211. /****************************************************************************/
  212. /* This function performs an nopen, but returns a file stream with a buffer */
  213. /* allocated.                                                                */
  214. /****************************************************************************/
  215. FILE *fnopen(int *file, char *str, int access)
  216. {
  217.     char mode[128];
  218.     FILE *stream;
  219.  
  220. if(access&O_WRONLY) access|=O_RDWR;     /* fdopen can't open WRONLY */
  221.  
  222. if(((*file)=nopen(str,access))==-1)
  223.     return(NULL);
  224.  
  225. if(access&O_APPEND) {
  226.     if(access&(O_RDONLY|O_RDWR))
  227.         strcpy(mode,"a+");
  228.     else
  229.         strcpy(mode,"a"); }
  230. else {
  231.     if(access&(O_WRONLY|O_RDWR))
  232.         strcpy(mode,"r+");
  233.     else
  234.         strcpy(mode,"r"); }
  235. stream=fdopen((*file),mode);
  236. if(stream==NULL) {
  237.     close(*file);
  238.     return(NULL); }
  239. setvbuf(stream,NULL,_IOFBF,16*1024);
  240. return(stream);
  241. }
  242.  
  243. void allocfail(uint size)
  244. {
  245. lprintf("\7Error allocating %u bytes of memory.\r\n",size);
  246. bail(1);
  247. }
  248.  
  249. void bail(int code)
  250. {
  251. exit(code);
  252. }
  253.  
  254. /****************************************************************************/
  255. /* Converts unix time format (long - time_t) into a char str MM/DD/YY        */
  256. /****************************************************************************/
  257. char *unixtodstr(time_t unix, char *str)
  258. {
  259.     struct tm *t;
  260.  
  261. if(!unix)
  262.     strcpy(str,"00/00/00");
  263. else {
  264.     t=gmtime(&unix);
  265.     sprintf(str,"%02u/%02u/%02u",t->tm_mon+1,t->tm_mday
  266.         ,t->tm_year); }
  267. return(str);
  268. }
  269.  
  270. #define ALL     (1L<<0)
  271. #define PAD     (1L<<1)
  272. #define HDR     (1L<<2)
  273. #define CDT_    (1L<<3)
  274. #define EXT     (1L<<4)
  275. #define ULN     (1L<<5)
  276. #define ULD     (1L<<6)
  277. #define DLS     (1L<<7)
  278. #define DLD     (1L<<8)
  279. #define NOD     (1L<<9)
  280. #define PLUS    (1L<<10)
  281. #define MINUS    (1L<<11)
  282. #define JST     (1L<<12)
  283. #define NOE     (1L<<13)
  284. #define DFD     (1L<<14)
  285. #define TOT     (1L<<15)
  286. #define AUTO    (1L<<16)
  287.  
  288. /*********************/
  289. /* Entry point (duh) */
  290. /*********************/
  291. int main(int argc, char **argv)
  292. {
  293.     char    *p,str[256],fname[256],ext,not[MAX_NOTS][9],nots=0;
  294.     uchar    HUGE16 *datbuf,HUGE16 *ixbbuf;
  295.     int     i,j,file,dirnum,libnum,desc_off,lines
  296.             ,omode=O_WRONLY|O_CREAT|O_TRUNC;
  297.     ulong    l,m,n,cdt,misc=0,total_cdt=0,total_files=0,datbuflen;
  298.     time_t    uld,dld;
  299.     read_cfg_text_t txt;
  300.     FILE    *in,*out=NULL;
  301.  
  302. putenv("TZ=UCT0");
  303. _fmode=O_BINARY;
  304. setvbuf(stdout,NULL,_IONBF,0);
  305.  
  306. fprintf(stderr,"\nFILELIST Version %s (%s) - Generate Synchronet File "
  307.     "Directory Lists\n"
  308.     ,FILELIST_VER
  309. #if defined(__OS2__)
  310.     ,"OS/2"
  311. #elif defined(__NT__)
  312.     ,"Win32"
  313. #elif defined(__DOS4G__)
  314.     ,"DOS4G"
  315. #elif defined(__FLAT__)
  316.     ,"DOS32"
  317. #else
  318.     ,"DOS16"
  319. #endif
  320.     );
  321.  
  322. if(argc<2) {
  323.     printf("\n   usage: FILELIST <dir_code or * for ALL> [switches] [outfile]\n");
  324.     printf("\nswitches: /LIB name All directories of specified library\n");
  325.     printf("          /NOT code Exclude specific directory\n");
  326.     printf("          /CAT      Concatenate to existing outfile\n");
  327.     printf("          /PAD      Pad filename with spaces\n");
  328.     printf("          /HDR      Include directory headers\n");
  329.     printf("          /CDT      Include credit value\n");
  330.     printf("          /TOT      Include credit totals\n");
  331.     printf("          /ULN      Include uploader's name\n");
  332.     printf("          /ULD      Include upload date\n");
  333.     printf("          /DFD      Include DOS file date\n");
  334.     printf("          /DLD      Include download date\n");
  335.     printf("          /DLS      Include total downloads\n");
  336.     printf("          /NOD      Exclude normal descriptions\n");
  337.     printf("          /NOE      Exclude normal descriptions, if extended "
  338.         "exists\n");
  339.     printf("          /EXT      Include extended descriptions\n");
  340.     printf("          /JST      Justify extended descriptions under normal\n");
  341.     printf("          /+        Include extended description indicator (+)\n");
  342.     printf("          /-        Include offline file indicator (-)\n");
  343.     printf("          /*        Short-hand for /PAD /HDR /CDT /+ /-\n");
  344.     exit(0); }
  345.  
  346. p=getenv("SBBSNODE");
  347. if(p==NULL) {
  348.     printf("\nSBBSNODE environment variable not set.\n");
  349.     printf("\nExample: SET SBBSNODE=C:\\SBBS\\NODE1\n");
  350.     exit(1); }
  351.  
  352. strcpy(node_dir,p);
  353. if(node_dir[strlen(node_dir)-1]!='\\')
  354.     strcat(node_dir,"\\");
  355.  
  356. txt.openerr="\7\nError opening %s for read.\n";
  357. txt.reading="\nReading %s...";
  358. txt.readit="\rRead %s       ";
  359. txt.allocerr="\7\nError allocating %u bytes of memory\n";
  360. txt.error="\7\nERROR: Offset %lu in %s\r\n\n";
  361.  
  362. read_node_cfg(txt);
  363. if(ctrl_dir[0]=='.') {   /* Relative path */
  364.     strcpy(str,ctrl_dir);
  365.     sprintf(ctrl_dir,"%s%s",node_dir,str); }
  366. read_main_cfg(txt);
  367. if(data_dir[0]=='.') {   /* Relative path */
  368.     strcpy(str,data_dir);
  369.     sprintf(data_dir,"%s%s",node_dir,str); }
  370. read_file_cfg(txt);
  371. printf("\n");
  372.  
  373.  
  374. dirnum=libnum=-1;
  375. if(argv[1][0]=='*')
  376.     misc|=ALL;
  377. else if(argv[1][0]!='/') {
  378.     strupr(argv[1]);
  379.     for(i=0;i<total_dirs;i++)
  380.         if(!stricmp(argv[1],dir[i]->code))
  381.             break;
  382.     if(i>=total_dirs) {
  383.         printf("\nDirectory code '%s' not found.\n",argv[1]);
  384.         exit(1); }
  385.     dirnum=i; }
  386. for(i=1;i<argc;i++) {
  387.     if(!stricmp(argv[i],"/LIB")) {
  388.         if(dirnum!=-1) {
  389.             printf("\nBoth directory code and /LIB parameters were used.\n");
  390.             exit(1); }
  391.         i++;
  392.         if(i>=argc) {
  393.             printf("\nLibrary short name must follow /LIB parameter.\n");
  394.             exit(1); }
  395.         strupr(argv[i]);
  396.         for(j=0;j<total_libs;j++)
  397.             if(!stricmp(lib[j]->sname,argv[i]))
  398.                 break;
  399.         if(j>=total_libs) {
  400.             printf("\nLibrary short name '%s' not found.\n",argv[i]);
  401.             exit(1); }
  402.         libnum=j; }
  403.     else if(!stricmp(argv[i],"/NOT")) {
  404.         if(nots>=MAX_NOTS) {
  405.             printf("\nMaximum number of /NOT options (%u) exceeded.\n"
  406.                 ,MAX_NOTS);
  407.             exit(1); }
  408.         i++;
  409.         if(i>=argc) {
  410.             printf("\nDirectory internal code must follow /NOT parameter.\n");
  411.             exit(1); }
  412.         sprintf(not[nots++],"%.8s",argv[i]); }
  413.     else if(!stricmp(argv[i],"/ALL")) {
  414.         if(dirnum!=-1) {
  415.             printf("\nBoth directory code and /ALL parameters were used.\n");
  416.             exit(1); }
  417.         if(libnum!=-1) {
  418.             printf("\nBoth library name and /ALL parameters were used.\n");
  419.             exit(1); }
  420.         misc|=ALL; }
  421.     else if(!stricmp(argv[i],"/PAD"))
  422.         misc|=PAD;
  423.     else if(!stricmp(argv[i],"/CAT"))
  424.         omode=O_WRONLY|O_CREAT|O_APPEND;
  425.     else if(!stricmp(argv[i],"/HDR"))
  426.         misc|=HDR;
  427.     else if(!stricmp(argv[i],"/CDT"))
  428.         misc|=CDT_;
  429.     else if(!stricmp(argv[i],"/TOT"))
  430.         misc|=TOT;
  431.     else if(!stricmp(argv[i],"/EXT"))
  432.         misc|=EXT;
  433.     else if(!stricmp(argv[i],"/ULN"))
  434.         misc|=ULN;
  435.     else if(!stricmp(argv[i],"/ULD"))
  436.         misc|=ULD;
  437.     else if(!stricmp(argv[i],"/DLD"))
  438.         misc|=DLD;
  439.     else if(!stricmp(argv[i],"/DFD"))
  440.         misc|=DFD;
  441.     else if(!stricmp(argv[i],"/DLS"))
  442.         misc|=DLS;
  443.     else if(!stricmp(argv[i],"/NOD"))
  444.         misc|=NOD;
  445.     else if(!stricmp(argv[i],"/JST"))
  446.         misc|=(EXT|JST);
  447.     else if(!stricmp(argv[i],"/NOE"))
  448.         misc|=(EXT|NOE);
  449.     else if(!stricmp(argv[i],"/+"))
  450.         misc|=PLUS;
  451.     else if(!stricmp(argv[i],"/-"))
  452.         misc|=MINUS;
  453.     else if(!stricmp(argv[i],"/*"))
  454.         misc|=(HDR|PAD|CDT_|PLUS|MINUS);
  455.  
  456.     else if(i!=1) {
  457.         if(argv[i][0]=='*') {
  458.             misc|=AUTO;
  459.             continue; }
  460.         if((j=nopen(argv[i],omode))==-1) {
  461.             printf("\nError opening/creating %s for output.\n",argv[i]);
  462.             exit(1); }
  463.         out=fdopen(j,"wb"); } }
  464.  
  465. if(!out && !(misc&AUTO)) {
  466.     printf("\nOutput file not specified, using FILES.BBS in each "
  467.         "directory.\n");
  468.     misc|=AUTO; }
  469.  
  470. for(i=0;i<total_dirs;i++) {
  471.     if(!(misc&ALL) && i!=dirnum && dir[i]->lib!=libnum)
  472.         continue;
  473.     for(j=0;j<nots;j++)
  474.         if(!stricmp(not[j],dir[i]->code))
  475.             break;
  476.     if(j<nots)
  477.         continue;
  478.     if(misc&AUTO && dir[i]->seqdev)     /* CD-ROM */
  479.         continue;
  480.     printf("\n%-*s %s",LEN_GSNAME,lib[dir[i]->lib]->sname,dir[i]->lname);
  481.     sprintf(str,"%s%s.IXB",dir[i]->data_dir,dir[i]->code);
  482.     if((file=nopen(str,O_RDONLY))==-1)
  483.         continue;
  484.     l=filelength(file);
  485.     if(misc&AUTO) {
  486.         sprintf(str,"%sFILES.BBS",dir[i]->path);
  487.         if((j=nopen(str,omode))==-1) {
  488.             printf("\nError opening/creating %s for output.\n",str);
  489.             exit(1); }
  490.         out=fdopen(j,"wb"); }
  491.     if(misc&HDR) {
  492.         sprintf(fname,"%-*s      %-*s       Files: %4u"
  493.             ,LEN_GSNAME,lib[dir[i]->lib]->sname
  494.             ,LEN_SLNAME,dir[i]->lname,l/F_IXBSIZE);
  495.         fprintf(out,"%s\r\n",fname);
  496.         strset(fname,'-');
  497.         fprintf(out,"%s\r\n",fname); }
  498.     if(!l) {
  499.         close(file);
  500.         if(misc&AUTO) fclose(out);
  501.         continue; }
  502.     if((ixbbuf=(char *)MALLOC(l))==NULL) {
  503.         close(file);
  504.         if(misc&AUTO) fclose(out);
  505.         printf("\7ERR_ALLOC %s %lu\n",str,l);
  506.         continue; }
  507.     if(read(file,ixbbuf,l)!=l) {
  508.         close(file);
  509.         if(misc&AUTO) fclose(out);
  510.         printf("\7ERR_READ %s %lu\n",str,l);
  511.         FREE((char *)ixbbuf);
  512.         continue; }
  513.     close(file);
  514.     sprintf(str,"%s%s.DAT",dir[i]->data_dir,dir[i]->code);
  515.     if((file=nopen(str,O_RDONLY))==-1) {
  516.         printf("\7ERR_OPEN %s %lu\n",str,O_RDONLY);
  517.         FREE((char *)ixbbuf);
  518.         if(misc&AUTO) fclose(out);
  519.         continue; }
  520.     datbuflen=filelength(file);
  521.     if((datbuf=MALLOC(datbuflen))==NULL) {
  522.         close(file);
  523.         printf("\7ERR_ALLOC %s %lu\n",str,datbuflen);
  524.         FREE((char *)ixbbuf);
  525.         if(misc&AUTO) fclose(out);
  526.         continue; }
  527.     if(lread(file,datbuf,datbuflen)!=datbuflen) {
  528.         close(file);
  529.         printf("\7ERR_READ %s %lu\n",str,datbuflen);
  530.         FREE((char *)datbuf);
  531.         FREE((char *)ixbbuf);
  532.         if(misc&AUTO) fclose(out);
  533.         continue; }
  534.     close(file);
  535.     m=0L;
  536.     while(m<l && !ferror(out)) {
  537.         for(j=0;j<12 && m<l;j++)
  538.             if(j==8)
  539.                 str[j]='.';
  540.             else
  541.                 str[j]=ixbbuf[m++]; /* Turns FILENAMEEXT into FILENAME.EXT */
  542.         str[j]=0;
  543.         unpadfname(str,fname);
  544.         fprintf(out,"%-12.12s",misc&PAD ? str : fname);
  545.         total_files++;
  546.         n=ixbbuf[m]|((long)ixbbuf[m+1]<<8)|((long)ixbbuf[m+2]<<16);
  547.         uld=(ixbbuf[m+3]|((long)ixbbuf[m+4]<<8)|((long)ixbbuf[m+5]<<16)
  548.             |((long)ixbbuf[m+6]<<24));
  549.         dld=(ixbbuf[m+7]|((long)ixbbuf[m+8]<<8)|((long)ixbbuf[m+9]<<16)
  550.             |((long)ixbbuf[m+10]<<24));
  551.         m+=11;
  552.  
  553.         if(n>=datbuflen                             /* index out of bounds */
  554.             || datbuf[n+F_DESC+LEN_FDESC]!=CR) {    /* corrupted data */
  555.             fprintf(stderr,"\n\7%s%s is corrupted!\n"
  556.                 ,dir[i]->data_dir,dir[i]->code);
  557.             exit(-1); }
  558.  
  559.  
  560.         if(misc&PLUS && datbuf[n+F_MISC]!=ETX
  561.             && (datbuf[n+F_MISC]-SP)&FM_EXTDESC)
  562.             fputc('+',out);
  563.         else
  564.             fputc(SP,out);
  565.  
  566.         desc_off=12;
  567.         if(misc&(CDT_|TOT)) {
  568.             getrec((char *)&datbuf[n],F_CDT,LEN_FCDT,str);
  569.             cdt=atol(str);
  570.             total_cdt+=cdt;
  571.             if(misc&CDT_) {
  572.                 fprintf(out,"%7lu",cdt);
  573.                 desc_off+=7; } }
  574.  
  575.         if(misc&MINUS) {
  576.             sprintf(str,"%s%s",dir[i]->path,fname);
  577.             if(!fexist(str))
  578.                 fputc('-',out);
  579.             else
  580.                 fputc(SP,out); }
  581.         else
  582.             fputc(SP,out);
  583.         desc_off++;
  584.  
  585.         if(misc&DFD) {
  586.             sprintf(str,"%s%s",dir[i]->path,fname);
  587.             fprintf(out,"%s ",unixtodstr(fdate(str),str));
  588.             desc_off+=9; }
  589.  
  590.         if(misc&ULD) {
  591.             fprintf(out,"%s ",unixtodstr(uld,str));
  592.             desc_off+=9; }
  593.  
  594.         if(misc&ULN) {
  595.             getrec((char *)&datbuf[n],F_ULER,25,str);
  596.             fprintf(out,"%-25s ",str);
  597.             desc_off+=26; }
  598.  
  599.         if(misc&DLD) {
  600.             fprintf(out,"%s ",unixtodstr(dld,str));
  601.             desc_off+=9; }
  602.  
  603.         if(misc&DLS) {
  604.             getrec((char *)&datbuf[n],F_TIMESDLED,5,str);
  605.             j=atoi(str);
  606.             fprintf(out,"%5u ",j);
  607.             desc_off+=6; }
  608.  
  609.         if(datbuf[n+F_MISC]!=ETX && (datbuf[n+F_MISC]-SP)&FM_EXTDESC)
  610.             ext=1;    /* extended description exists */
  611.         else
  612.             ext=0;    /* it doesn't */
  613.  
  614.         if(!(misc&NOD) && !(misc&NOE && ext)) {
  615.             getrec((char *)&datbuf[n],F_DESC,LEN_FDESC,str);
  616.             fprintf(out,"%s",str); }
  617.  
  618.         if(misc&EXT && ext) {                            /* Print ext desc */
  619.  
  620.             sprintf(str,"%s%s.EXB",dir[i]->data_dir,dir[i]->code);
  621.             if(!fexist(str))
  622.                 continue;
  623.             if((j=nopen(str,O_RDONLY))==-1) {
  624.                 printf("\7ERR_OPEN %s %lu\n",str,O_RDONLY);
  625.                 continue; }
  626.             if((in=fdopen(j,"rb"))==NULL) {
  627.                 close(j);
  628.                 continue; }
  629.             fseek(in,(n/F_LEN)*512L,SEEK_SET);
  630.             lines=0;
  631.             if(!(misc&NOE)) {
  632.                 fprintf(out,"\r\n");
  633.                 lines++; }
  634.             while(!feof(in) && !ferror(in)
  635.                 && ftell(in)<((n/F_LEN)+1)*512L) {
  636.                 if(!fgets(str,128,in) || !str[0])
  637.                     break;
  638.                 stripctrlz(str);
  639.                 if(lines) {
  640.                     if(misc&JST)
  641.                         fprintf(out,"%*s",desc_off,"");
  642.                     fputc(SP,out);                /* indent one character */ }
  643.                 fprintf(out,"%s",str);
  644.                 lines++; }
  645.             fclose(in); }
  646.         fprintf(out,"\r\n"); }
  647.     FREE((char *)datbuf);
  648.     FREE((char *)ixbbuf);
  649.     fprintf(out,"\r\n"); /* blank line at end of dir */
  650.     if(misc&AUTO) fclose(out); }
  651.  
  652. if(misc&TOT && !(misc&AUTO))
  653.     fprintf(out,"TOTALS\n------\n%lu credits/bytes in %lu files.\r\n"
  654.         ,total_cdt,total_files);
  655. printf("\nDone.\n");
  656. return(0);
  657. }
  658.