home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / primcuts.zip / generate_bbs_filelist / generate_filelist.c next >
Text File  |  2000-07-21  |  20KB  |  718 lines

  1. #pragma strings(readonly)
  2.  
  3. #define INCL_DOSFILEMGR
  4. #define INCL_DOSDATETIME
  5. #define INCL_DOSERRORS
  6.  
  7. #include <os2.h>
  8.  
  9. #include <stdio.h>
  10. #include <memory.h>
  11. #include <malloc.h>
  12. #include <string.h>
  13.  
  14.  
  15.  
  16. typedef struct _COMMENTLINE
  17. {
  18.    struct _COMMENTLINE *next;
  19.    char *ascii_line;
  20.    USHORT cbLength;
  21. }COMMENTLINE, *PCOMMENTLINE;
  22.  
  23. typedef struct _FILENODE
  24. {
  25.    struct _FILENODE *next;
  26.    char achName[CCHMAXPATH];
  27.    FDATE fdate;
  28.    ULONG cbFile;
  29.    PCOMMENTLINE firstcommentline;
  30. }FILENODE, *PFILENODE;
  31.  
  32. typedef struct _QUEUENODE
  33. {
  34.    struct _QUEUENODE *next;
  35.    char path[CCHMAXPATH];
  36.    char prev[256];
  37. }QUEUENODE, *PQUEUENODE;
  38.  
  39.  
  40. void syntax(char *argv0);
  41. BOOL writeFilelistHeader(HFILE hFile);
  42. BOOL writeTreeDescriptions(PSZ pszBasePath, HFILE hFile);
  43.  
  44.  
  45.  
  46. PFILENODE getFilelist(PQUEUENODE n);
  47.  
  48. void write_file_description(PCOMMENTLINE commentline, HFILE hFile, USHORT width);
  49.  
  50.  
  51. /*
  52.  * argv[1] - base directory
  53.  * argv[2] - output file
  54.  *
  55.  * options:
  56.  *    -a append to file list (default overwrite)
  57.  */
  58. int main(int argc, char *argv[])
  59. {
  60.    APIRET rc = NO_ERROR;
  61.    ULONG fsOpenFlags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS;
  62.    ULONG fsOpenMode = OPEN_FLAGS_SEQUENTIAL | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_WRITEONLY;
  63.    ULONG hFile = NULLHANDLE;
  64.    ULONG ulAction = 0;
  65.    BOOL fAppend = FALSE;
  66.  
  67.    /*
  68.     * Make sure base directory has been specified
  69.     */
  70.    if(argc < 2)
  71.    {
  72.       puts("Error: No base directory specified");
  73.       syntax(argv[0]);
  74.       return 1;
  75.    }
  76.  
  77.    /*
  78.     * Make sure output filename has been specified
  79.     */
  80.    if(argc < 3)
  81.    {
  82.       puts("Error: No file list filename specified");
  83.       syntax(argv[0]);
  84.       return 1;
  85.    }
  86.  
  87.    /*
  88.     * Check aditional parameters
  89.     */
  90.    if(argc > 2)
  91.    {
  92.       int i = 3;
  93.       for(; i < argc; i++)
  94.       {
  95.          if(argv[i][0] == '-' || argv[i][0] == '/')
  96.          {
  97.             switch(argv[i][1])
  98.             {
  99.                case 'a':
  100.                case 'A':
  101.                   fAppend = TRUE;
  102.                   puts("append");
  103.                   break;
  104.             }
  105.          }
  106.       }
  107.    }
  108.  
  109.    if(fAppend)
  110.    {
  111.       fsOpenFlags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
  112.    }
  113.  
  114.    /*
  115.     * Attempt to open output file
  116.     */
  117.    rc = DosOpen(argv[2], &hFile, &ulAction, 0UL, FILE_NORMAL, fsOpenFlags, fsOpenMode, NULL);
  118.    if(rc == NO_ERROR)
  119.    {
  120.       if(ulAction == FILE_EXISTED)
  121.       {
  122.          ULONG ibActual = 0;
  123.  
  124.          /*
  125.           * File already existed (and it wasn't replaced by DosOpen()), assume that
  126.           * the append option was used and set file pointer to the end of the file.
  127.           */
  128.          rc = DosSetFilePtr(hFile, 0L, FILE_END, &ibActual);
  129.       }
  130.       else
  131.       {
  132.          /*
  133.           * Write a file header
  134.           */
  135.          writeFilelistHeader(hFile);
  136.       }
  137.  
  138.       writeTreeDescriptions(argv[1], hFile);
  139.  
  140.       rc = DosClose(hFile);
  141.    }
  142.    return 0;
  143. }
  144.  
  145. void syntax(char *argv0)
  146. {
  147.    printf("Usage: %s <basedir> <outputfile> [options]\n", argv0);
  148.    puts("options: -a - append list to <outfilefile> (overwrite by default)");
  149.  
  150. }
  151.  
  152. BOOL writeFilelistHeader(HFILE hFile)
  153. {
  154.    BOOL fSuccess = FALSE;
  155.    APIRET rc = NO_ERROR;
  156.    char tmp[256] = "";
  157.    ULONG cbWritten = 0;
  158.    char header[] = "File list for Treadstone BBS\r\n";
  159.  
  160.    if((rc = DosWrite(hFile, header, sizeof(header), &cbWritten)) == NO_ERROR)
  161.    {
  162.       DATETIME dt = { 0 };
  163.  
  164.       if((rc = DosGetDateTime(&dt)) == NO_ERROR)
  165.       {
  166.          sprintf(tmp, "Generated on %d-%02d-%02d\r\n", dt.year, dt.month, dt.day);
  167.          if((rc = DosWrite(hFile, tmp, strlen(tmp), &cbWritten)) == NO_ERROR)
  168.          {
  169.             rc = DosWrite(hFile, "\r\n", 2UL, &cbWritten);
  170.             if(rc == NO_ERROR)
  171.             {
  172.                fSuccess = TRUE;
  173.             }
  174.          }
  175.       }
  176.    }
  177.    return fSuccess;
  178. }
  179.  
  180. BOOL writeTreeDescriptions(PSZ pszBasePath, HFILE hFile)
  181. {
  182.    APIRET rc = NO_ERROR;
  183.    ULONG ulFindMax = 32;
  184.    ULONG cbFindBuf = ulFindMax*sizeof(FILEFINDBUF3);
  185.    PFILEFINDBUF3 findbuf = malloc(cbFindBuf);
  186.    ULONG flAttribute = FILE_ARCHIVED | FILE_READONLY | FILE_DIRECTORY | MUST_HAVE_DIRECTORY;
  187.    ULONG cbBasePath = strlen(pszBasePath);
  188.    EAOP2 eaop2 = { NULL, NULL, 0UL };
  189.    PQUEUENODE node = NULL;
  190.    PQUEUENODE addnode = NULL;
  191.    PQUEUENODE tmpNode = NULL;
  192.    const char achDescription[] = ".COMMENTS";
  193.    const char achLongname[] = ".LONGNAME";
  194.    ULONG cbWritten = 0;
  195.    GEA2 *pgea2 = NULL;
  196.    PBYTE ptmp = NULL;
  197.    ULONG ulTemp = 0;
  198.  
  199.    /*
  200.     * Prepare EAOP2 structure for fetching extended attributes
  201.     */
  202.    /* GEA2 List */
  203.    eaop2.fpGEA2List = (PGEA2LIST)malloc(128);
  204.    memset(eaop2.fpGEA2List, 0, 128);
  205.    eaop2.fpGEA2List->cbList = sizeof(eaop2.fpGEA2List->cbList);
  206.  
  207.    pgea2 = &eaop2.fpGEA2List->list[0];
  208.  
  209.    /* Set up GEA2 to fetch .COMMENTS attribute */
  210.    pgea2->cbName = sizeof(achDescription)-1;
  211.    memcpy(pgea2->szName, achDescription, sizeof(achDescription));
  212.    eaop2.fpGEA2List->cbList += (sizeof(GEA2)+pgea2->cbName);
  213.  
  214.  
  215.    pgea2->oNextEntryOffset = sizeof(GEA2)+pgea2->cbName;
  216.    pgea2->oNextEntryOffset += (4-(pgea2->oNextEntryOffset%4));
  217.  
  218.    ulTemp = (PBYTE)pgea2;
  219.    ulTemp += pgea2->oNextEntryOffset;
  220.    pgea2 = (GEA2*)ulTemp;
  221.  
  222.    /* Set up GEA2 to fetch .LONGNAME attribute */
  223.    pgea2->oNextEntryOffset = 0;
  224.    pgea2->cbName = sizeof(achLongname)-1;
  225.    memcpy(pgea2->szName, achLongname, sizeof(achLongname));
  226.    eaop2.fpGEA2List->cbList += (sizeof(GEA2)+pgea2->cbName);
  227.  
  228.  
  229.    /* Allocate FEA2 List */
  230.    eaop2.fpFEA2List = (PFEA2LIST)malloc(65536);
  231.  
  232.  
  233.    /*
  234.     * Create initial node
  235.     */
  236.    node = (PQUEUENODE)malloc(sizeof(QUEUENODE));
  237.    memset(node, 0, sizeof(QUEUENODE));
  238.    node->next = NULL;
  239.    strcpy(node->path, pszBasePath);
  240.  
  241.    while(node)
  242.    {
  243.       ULONG cFilenames = ulFindMax;
  244.       HFILE hFind = HDIR_CREATE;
  245.       char area[CCHMAXPATH] = "";
  246.       char path[CCHMAXPATH] = "";
  247.       char findspec[CCHMAXPATH] = "";
  248.       PFILENODE fnode = NULL;
  249.       char achAreaName[256] = "";
  250.       PBYTE p = node->path+cbBasePath;
  251.       PFEA2 fea2desc = NULL;
  252.  
  253.       addnode = node;
  254.  
  255.       /*
  256.        * Get file list for curent directory node
  257.        */
  258.       fnode = getFilelist(node);
  259.  
  260.       /* Attempt to parse directory name */
  261.       while(*p)
  262.       {
  263.          p++;
  264.       }
  265.       while(*p != '\\')
  266.       {
  267.          if(p == (node->path+cbBasePath))
  268.          {
  269.             break;
  270.          }
  271.          p--;
  272.       }
  273.       if(*p == '\\')
  274.       {
  275.          p++;
  276.       }
  277.  
  278.       if(p > (node->path+cbBasePath))
  279.       {
  280.          /*
  281.           * Path isn't root, get file's EA:s
  282.           */
  283.          strcpy(achAreaName, p);
  284.  
  285.          eaop2.fpFEA2List->cbList = 65536;
  286.          rc = DosQueryPathInfo(node->path, FIL_QUERYEASFROMLIST, &eaop2, sizeof(EAOP2));
  287.          if(rc == NO_ERROR)
  288.          {
  289.             FEA2 *fea2 = &eaop2.fpFEA2List->list[0];
  290.  
  291.             while(1)
  292.             {
  293.                if((strcmp(fea2->szName, achLongname) == 0) && (fea2->cbValue != 0))
  294.                {
  295.                   PBYTE pValue = fea2->szName + (fea2->cbName+1);
  296.                   USHORT eaType = MAKESHORT(*pValue, *(pValue+1));
  297.  
  298.                   /*
  299.                    * Copy .LONGNAME attribute value to achAreaName
  300.                    */
  301.                   if(eaType == EAT_ASCII)
  302.                   {
  303.                      USHORT eaLen = MAKESHORT(*(pValue+2), *(pValue+3));
  304.  
  305.                      memcpy(achAreaName, (pValue+4), eaLen);
  306.                      achAreaName[eaLen] = '\0';
  307.                   }
  308.                }
  309.                else if((strcmp(fea2->szName, achDescription) == 0) && (fea2->cbValue != 0))
  310.                {
  311.                   /*
  312.                    * A .COMMENTS attribute was found for directory, write it.
  313.                    */
  314.                   fea2desc = fea2;
  315.                }
  316.  
  317.                if(fea2->oNextEntryOffset == 0)
  318.                {
  319.                   /*
  320.                    * Break out of loop if current FEA2 entry is the last in the list.
  321.                    */
  322.                   break;
  323.                }
  324.  
  325.                ulTemp = (ULONG)fea2;
  326.                ulTemp += fea2->oNextEntryOffset;
  327.                fea2 = (FEA2*)ulTemp;
  328.             }
  329.          }
  330.       }
  331.  
  332.       if(fnode)
  333.       {
  334.          /*
  335.           * Write area header
  336.           */
  337.          rc = DosWrite(hFile, "\r\n*\r\n* Area: ", 13UL, &cbWritten);
  338.          if(node->prev[0])
  339.          {
  340.             DosWrite(hFile, node->prev, strlen(node->prev), &cbWritten);
  341.             DosWrite(hFile, " -> ", 4UL, &cbWritten);
  342.          }
  343.          DosWrite(hFile, achAreaName, strlen(achAreaName), &cbWritten);
  344.          rc = DosWrite(hFile, "\r\n*\r\n", 5UL, &cbWritten);
  345.  
  346.          if(fea2desc)
  347.          {
  348.             PBYTE pValue = fea2desc->szName + (fea2desc->cbName+1);
  349.             USHORT eaType = MAKESHORT(*pValue, *(pValue+1));
  350.  
  351.             if((strcmp(fea2desc->szName, achDescription) == 0) && (fea2desc->cbValue != 0) && (eaType == EAT_MVMT))
  352.             {
  353.                USHORT codepage = MAKESHORT(*(pValue+2), *(pValue+3));   /* EAT_MVMT codepage */
  354.                USHORT entries = MAKESHORT(*(pValue+4), *(pValue+5));    /* EAT_MVMT entries  */
  355.                USHORT i = 0;
  356.                PBYTE p = pValue + 6;
  357.  
  358.                /*
  359.                 * Write .COMMENTS attribute
  360.                 */
  361.                rc = DosWrite(hFile, "\r\n", 2UL, &cbWritten);
  362.  
  363.                for(i = 0; i < entries; i++)
  364.                {
  365.                   USHORT eaLen = 0;
  366.  
  367.                   eaType = MAKESHORT(*p, *(p+1));
  368.                   p += 2;
  369.                   eaLen = MAKESHORT(*p, *(p+1));
  370.                   p += 2;
  371.  
  372.                   switch(eaType)
  373.                   {
  374.                      case EAT_ASCII:
  375.                         rc = DosWrite(hFile, "   ", 3UL, &cbWritten);
  376.                         DosWrite(hFile, p, eaLen, &cbWritten);
  377.                         rc = DosWrite(hFile, "\r\n", 2UL, &cbWritten);
  378.                         break;
  379.                   }
  380.                   p+= eaLen;
  381.                }
  382.                rc = DosWrite(hFile, "\r\n", 2UL, &cbWritten);
  383.             }
  384.          }
  385.  
  386.          /*
  387.           * Write file list
  388.           */
  389.          while(fnode)
  390.          {
  391.             char tmp[1024] = "";
  392.             PFILENODE nextNode = fnode->next;
  393.             PCOMMENTLINE commentline = fnode->firstcommentline;
  394.  
  395.             /*
  396.              * Write file information
  397.              */
  398.             sprintf(tmp, "%-16s %8d %d-%02d-%02d\r\n", fnode->achName, fnode->cbFile, 1980+fnode->fdate.year, fnode->fdate.month, fnode->fdate.day);
  399.             DosWrite(hFile, tmp, strlen(tmp), &cbWritten);
  400.  
  401.             if(fnode->firstcommentline)
  402.             {
  403.                /*
  404.                 * Write file's description
  405.                 */
  406.                write_file_description(fnode->firstcommentline, hFile, 80);
  407.             }
  408.             else
  409.             {
  410.                char achNoDescription[] = "    No description available.\r\n";
  411.                DosWrite(hFile, achNoDescription, sizeof(achNoDescription)-1, &cbWritten);
  412.             }
  413.  
  414.             /*
  415.              * free node memory
  416.              */
  417.             while(commentline)
  418.             {
  419.                PCOMMENTLINE nextLine = commentline->next;
  420.  
  421.                free(commentline->ascii_line);
  422.                free(commentline);
  423.                commentline = nextLine;
  424.             }
  425.             free(fnode);
  426.  
  427.             fnode = nextNode;
  428.          }
  429.       }
  430.       strcpy(findspec, node->path);
  431.       strcat(findspec, "\\*");
  432.  
  433.       /*
  434.        * check if directory has sub directories
  435.        */
  436.       rc = DosFindFirst(findspec, &hFind, flAttribute, findbuf, cbFindBuf, &cFilenames, FIL_STANDARD);
  437.       if(rc == NO_ERROR)
  438.       {
  439.          PFILEFINDBUF3 pfile = findbuf;
  440.  
  441.          while(cFilenames--)
  442.          {
  443.             char *pTmp = (char*)pfile;
  444.  
  445.             if(strcmp(pfile->achName, ".") != 0 && strcmp(pfile->achName, "..") != 0)
  446.             {
  447.                /*
  448.                 * Add new node
  449.                 */
  450.                tmpNode = addnode->next;
  451.                addnode->next = (PQUEUENODE)malloc(sizeof(QUEUENODE));
  452.                memset(addnode->next, 0, sizeof(QUEUENODE));
  453.                addnode = addnode->next;
  454.                addnode->next = tmpNode;
  455.  
  456.  
  457.                strcpy(addnode->path, node->path);
  458.                strcat(addnode->path, "\\");
  459.                strcat(addnode->path, pfile->achName);
  460.  
  461.                if(node->prev[0] == '\0')
  462.                {
  463.                   strcat(addnode->prev, achAreaName);
  464.                }
  465.                else
  466.                {
  467.                   strcpy(addnode->prev, node->prev);
  468.                   strcat(addnode->prev, " -> ");
  469.                   strcat(addnode->prev, achAreaName);
  470.                }
  471.             }
  472.  
  473.             /* Next file in list */
  474.             pTmp += pfile->oNextEntryOffset;
  475.             pfile = (FILEFINDBUF3*)pTmp;
  476.          }
  477.          /* Find next list of files */
  478.          cFilenames = ulFindMax;
  479.          rc = DosFindNext(hFind, findbuf, cbFindBuf, &cFilenames);
  480.       }
  481.       rc = DosFindClose(hFind);
  482.  
  483.       /* Next node in queue */
  484.       tmpNode = node;
  485.       node = node->next;
  486.       free(tmpNode);
  487.    }
  488.  
  489.    free(eaop2.fpFEA2List);
  490.    free(eaop2.fpGEA2List);
  491.  
  492.    return TRUE;
  493. }
  494.  
  495.  
  496. PFILENODE getFilelist(PQUEUENODE n)
  497. {
  498.    APIRET rc = NO_ERROR;
  499.    char filepath[CCHMAXPATH] = "";
  500.    HFILE hFind = HDIR_CREATE;
  501.    ULONG flAttribute = FILE_ARCHIVED | FILE_READONLY;
  502.    EAOP2 eaop2 = { NULL, NULL, 0UL };
  503.    PBYTE pFilename = NULL;
  504.    const ULONG ulFindMax = 64;
  505.    PFILEFINDBUF3 findbuf = calloc(ulFindMax, sizeof(FILEFINDBUF3));
  506.    ULONG cbFindBuf = ulFindMax*sizeof(FILEFINDBUF3);
  507.    ULONG cFilenames = ulFindMax;
  508.    const char achDescription[] = ".COMMENTS";
  509.  
  510.    PFILENODE filenode = NULL;
  511.    PFILENODE firstfilenode = NULL;
  512.  
  513.  
  514.    /*
  515.     * Prepare EAOP2 structure for fetching extended attributes
  516.     */
  517.    /* GEA2 */
  518.    eaop2.fpGEA2List = (PGEA2LIST)malloc(128);
  519.    memset(eaop2.fpGEA2List, 0, 128);
  520.    eaop2.fpGEA2List->cbList = sizeof(eaop2.fpGEA2List->cbList);
  521.  
  522.    eaop2.fpGEA2List->list[0].oNextEntryOffset = 0;
  523.    eaop2.fpGEA2List->list[0].cbName = sizeof(achDescription)-1;
  524.    memcpy(eaop2.fpGEA2List->list[0].szName, achDescription, sizeof(achDescription));
  525.    eaop2.fpGEA2List->cbList += (sizeof(GEA2)+eaop2.fpGEA2List->list[0].cbName);
  526.    if(eaop2.fpGEA2List->cbList % 4)
  527.    {
  528.       eaop2.fpGEA2List->cbList += (4-(eaop2.fpGEA2List->cbList%4));
  529.    }
  530.  
  531.    /* FEA2 */
  532.    eaop2.fpFEA2List = (PFEA2LIST)malloc(65536);
  533.  
  534.    /*
  535.     * Set up filespec
  536.     */
  537.    strcpy(filepath, n->path);
  538.    strcat(filepath, "\\*");
  539.  
  540.    pFilename = filepath + strlen(filepath);
  541.  
  542.    /*
  543.     * Get file list
  544.     */
  545.    rc = DosFindFirst(filepath, &hFind, flAttribute, findbuf, cbFindBuf, &cFilenames, FIL_STANDARD);
  546.    while(rc == NO_ERROR)
  547.    {
  548.       PFILEFINDBUF3 pfile = findbuf;
  549.       ULONG cbWritten = 0;
  550.  
  551.       while(cFilenames--)
  552.       {
  553.          BOOL fDescription = FALSE;
  554.          char *pTmp = (char*)pfile;
  555.          char tmp[260] = "";
  556.  
  557.          /*
  558.           * Create a new FILENODE node for current file
  559.           */
  560.          if(filenode == NULL)
  561.          {
  562.             filenode = malloc(sizeof(FILENODE));
  563.             firstfilenode = filenode;
  564.          }
  565.          else
  566.          {
  567.             filenode->next = malloc(sizeof(FILENODE));
  568.             filenode = filenode->next;
  569.          }
  570.          memset(filenode, 0, sizeof(FILENODE));
  571.  
  572.          /*
  573.           * Set node file information
  574.           */
  575.          strcpy(filenode->achName, pfile->achName);
  576.          filenode->cbFile = pfile->cbFile;
  577.          memcpy(&filenode->fdate, &pfile->fdateCreation, sizeof(FDATE));
  578.  
  579.  
  580.          strcpy(pFilename, pfile->achName);
  581.          strcpy(filepath, n->path);
  582.          strcat(filepath, "\\");
  583.          strcat(filepath, pFilename);
  584.  
  585.          /* Reset FEA2 list size */
  586.          eaop2.fpFEA2List->cbList = 65536;
  587.  
  588.          /*
  589.           * Get file's EA:s
  590.           */
  591.          rc = DosQueryPathInfo(filepath, FIL_QUERYEASFROMLIST, &eaop2, sizeof(eaop2));
  592.          if(rc == NO_ERROR)
  593.          {
  594.             FEA2 *fea2 = &eaop2.fpFEA2List->list[0];
  595.             PBYTE pValBuf = fea2->szName + (fea2->cbName+1);
  596.             USHORT eaType = MAKESHORT(*pValBuf, *(pValBuf+1));
  597.  
  598.             if((strcmp(fea2->szName, achDescription) == 0) && (fea2->cbValue != 0) && (eaType == EAT_MVMT))
  599.             {
  600.                USHORT codepage = MAKESHORT(*(pValBuf+2), *(pValBuf+3));   /* EAT_MVMT codepage */
  601.                USHORT entries = MAKESHORT(*(pValBuf+4), *(pValBuf+5));    /* EAT_MVMT entries  */
  602.                USHORT i = 0;
  603.                PBYTE p = pValBuf + 6;
  604.                PCOMMENTLINE commentline = NULL;
  605.  
  606.                /*
  607.                 * A .COMMENTS attribute was found for file
  608.                 */
  609.  
  610.                for(i = 0; i < entries; i++)
  611.                {
  612.                   USHORT eaLen = 0;
  613.  
  614.                   eaType = MAKESHORT(*p, *(p+1));
  615.                   p += 2;
  616.                   eaLen = MAKESHORT(*p, *(p+1));
  617.                   p += 2;
  618.  
  619.                   switch(eaType)
  620.                   {
  621.                      case EAT_ASCII:
  622.                         if(commentline == NULL)
  623.                         {
  624.                            commentline = filenode->firstcommentline = malloc(sizeof(COMMENTLINE));
  625.                         }
  626.                         else
  627.                         {
  628.                             commentline->next = malloc(sizeof(COMMENTLINE));
  629.                             commentline = commentline->next;
  630.                         }
  631.                         memset(commentline, 0, sizeof(COMMENTLINE));
  632.  
  633.                         commentline->cbLength = eaLen;
  634.                         commentline->ascii_line = malloc(commentline->cbLength);
  635.                         memcpy(commentline->ascii_line, p, eaLen);
  636.                         break;
  637.                   }
  638.                   p+= eaLen;
  639.                }
  640.             }
  641.          }
  642.          else
  643.          {
  644.             printf("rc = %u\n", rc);
  645.          }
  646.  
  647.          /* Next file in list */
  648.          pTmp += pfile->oNextEntryOffset;
  649.          pfile = (FILEFINDBUF3*)pTmp;
  650.       }
  651.  
  652.       cFilenames = ulFindMax;
  653.       rc = DosFindNext(hFind, findbuf, cbFindBuf, &cFilenames);
  654.    }
  655.    DosFindClose(hFind);
  656.  
  657.    free(eaop2.fpFEA2List);
  658.    free(eaop2.fpGEA2List);
  659.  
  660.    return firstfilenode;
  661. }
  662.  
  663.  
  664. /*
  665.  * Write file description in a "word wrapping" fashion.
  666.  */
  667. void write_file_description(PCOMMENTLINE commentline, HFILE hFile, USHORT width)
  668. {
  669.    while(commentline)
  670.    {
  671.       APIRET rc = NO_ERROR;
  672.       USHORT i = 0;
  673.       USHORT iStart = 0;
  674.       USHORT iScreen = 4;
  675.       PBYTE pBuf = commentline->ascii_line;
  676.       USHORT cbLen = commentline->cbLength;
  677.  
  678.       while(i < cbLen)
  679.       {
  680.          ULONG cbWritten = 0;
  681.  
  682.          if(pBuf[i] == ' ')
  683.          {
  684.             i += 1;
  685.          }
  686.  
  687.          iStart = i;
  688.  
  689.          while(iScreen < width && i < cbLen)
  690.          {
  691.             i++;
  692.             iScreen++;
  693.          }
  694.          if(i < cbLen)
  695.          {
  696.             if(pBuf[i] != ' ')
  697.             {
  698.                USHORT iTmp = i;
  699.                while(pBuf[i] != ' ')
  700.                {
  701.                   i--;
  702.                   if(i < iStart)
  703.                   {
  704.                      i = iTmp;
  705.                      break;
  706.                   }
  707.                }
  708.             }
  709.          }
  710.          rc = DosWrite(hFile, "    ", 4, &cbWritten);
  711.          rc = DosWrite(hFile, &pBuf[iStart], i-iStart, &cbWritten);
  712.          rc = DosWrite(hFile, "\r\n", 2, &cbWritten);
  713.          iScreen = 4;
  714.       }
  715.       commentline = commentline->next;
  716.    }
  717. }
  718.