LCOV - code coverage report
Current view: directory - netwerk/streamconv/converters - ParseFTPList.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 807 378 46.8 %
Date: 2012-06-02 Functions: 2 2 100.0 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org Code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Cyrus Patel <cyp@fb14.uni-mainz.de>.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2002
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Doug Turner <dougt@netscape.com>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include <stdlib.h>
      40                 : #include <string.h>
      41                 : #include <ctype.h>
      42                 : #include "plstr.h"
      43                 : #include "nsDebug.h"
      44                 : 
      45                 : #include "ParseFTPList.h"
      46                 : 
      47                 : /* ==================================================================== */
      48                 : 
      49               7 : static inline int ParsingFailed(struct list_state *state)
      50                 : {
      51               7 :   if (state->parsed_one || state->lstyle) /* junk if we fail to parse */
      52               4 :     return '?';      /* this time but had previously parsed successfully */
      53               3 :   return '"';        /* its part of a comment or error message */
      54                 : }
      55                 : 
      56              49 : int ParseFTPList(const char *line, struct list_state *state,
      57                 :                  struct list_result *result )
      58                 : {
      59                 :   unsigned int carry_buf_len; /* copy of state->carry_buf_len */
      60                 :   unsigned int linelen, pos;
      61                 :   const char *p;
      62                 : 
      63              49 :   if (!line || !state || !result)
      64               0 :     return 0;
      65                 : 
      66              49 :   memset( result, 0, sizeof(*result) );
      67              49 :   if (state->magic != ((void *)ParseFTPList))
      68                 :   {
      69              17 :     memset( state, 0, sizeof(*state) );
      70              17 :     state->magic = ((void *)ParseFTPList);
      71                 :   }
      72              49 :   state->numlines++;
      73                 : 
      74                 :   /* carry buffer is only valid from one line to the next */
      75              49 :   carry_buf_len = state->carry_buf_len;
      76              49 :   state->carry_buf_len = 0;
      77                 : 
      78              49 :   linelen = 0;
      79                 : 
      80                 :   /* strip leading whitespace */
      81              98 :   while (*line == ' ' || *line == '\t')
      82               0 :     line++;
      83                 :     
      84                 :   /* line is terminated at first '\0' or '\n' */
      85              49 :   p = line;
      86            2755 :   while (*p && *p != '\n')
      87            2657 :     p++;
      88              49 :   linelen = p - line;
      89                 : 
      90              49 :   if (linelen > 0 && *p == '\n' && *(p-1) == '\r')
      91               0 :     linelen--;
      92                 : 
      93                 :   /* DON'T strip trailing whitespace. */
      94                 : 
      95              49 :   if (linelen > 0)
      96                 :   {
      97                 :     static const char *month_names = "JanFebMarAprMayJunJulAugSepOctNovDec";
      98                 :     const char *tokens[16]; /* 16 is more than enough */
      99                 :     unsigned int toklen[(sizeof(tokens)/sizeof(tokens[0]))];
     100                 :     unsigned int linelen_sans_wsp;  // line length sans whitespace
     101              49 :     unsigned int numtoks = 0;
     102              49 :     unsigned int tokmarker = 0; /* extra info for lstyle handler */
     103              49 :     unsigned int month_num = 0;
     104                 :     char tbuf[4];
     105              49 :     int lstyle = 0;
     106                 : 
     107              49 :     if (carry_buf_len) /* VMS long filename carryover buffer */
     108                 :     {
     109               0 :       tokens[0] = state->carry_buf;
     110               0 :       toklen[0] = carry_buf_len;
     111               0 :       numtoks++;
     112                 :     }
     113                 : 
     114              49 :     pos = 0;
     115             434 :     while (pos < linelen && numtoks < (sizeof(tokens)/sizeof(tokens[0])) )
     116                 :     {
     117            3671 :       while (pos < linelen && 
     118            1996 :             (line[pos] == ' ' || line[pos] == '\t' || line[pos] == '\r'))
     119            1003 :         pos++;
     120             336 :       if (pos < linelen)
     121                 :       {
     122             329 :         tokens[numtoks] = &line[pos];
     123            7389 :         while (pos < linelen && 
     124            5121 :            (line[pos] != ' ' && line[pos] != '\t' && line[pos] != '\r'))
     125            1610 :           pos++;
     126             329 :         if (tokens[numtoks] != &line[pos])
     127                 :         {
     128             329 :           toklen[numtoks] = (&line[pos] - tokens[numtoks]);
     129             329 :           numtoks++;  
     130                 :         }
     131                 :       }
     132                 :     }    
     133                 : 
     134              49 :     if (!numtoks)
     135               1 :       return ParsingFailed(state);
     136                 : 
     137              48 :     linelen_sans_wsp = &(tokens[numtoks-1][toklen[numtoks-1]]) - tokens[0];
     138              48 :     if (numtoks == (sizeof(tokens)/sizeof(tokens[0])) )
     139                 :     {
     140               2 :       pos = linelen;
     141               4 :       while (pos > 0 && (line[pos-1] == ' ' || line[pos-1] == '\t'))
     142               0 :         pos--;
     143               2 :       linelen_sans_wsp = pos;
     144                 :     }
     145                 : 
     146                 :     /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
     147                 : 
     148                 : #if defined(SUPPORT_EPLF)
     149                 :     /* EPLF handling must come somewhere before /bin/dls handling. */
     150              48 :     if (!lstyle && (!state->lstyle || state->lstyle == 'E'))
     151                 :     {
     152              18 :       if (*line == '+' && linelen > 4 && numtoks >= 2)
     153                 :       {
     154               0 :         pos = 1;
     155               0 :         while (pos < (linelen-1))
     156                 :         {
     157               0 :           p = &line[pos++];
     158               0 :           if (*p == '/') 
     159               0 :             result->fe_type = 'd'; /* its a dir */
     160               0 :           else if (*p == 'r')
     161               0 :             result->fe_type = 'f'; /* its a file */
     162               0 :           else if (*p == 'm')
     163                 :           {
     164               0 :             if (isdigit(line[pos]))
     165                 :             {
     166               0 :               while (pos < linelen && isdigit(line[pos]))
     167               0 :                 pos++;
     168               0 :               if (pos < linelen && line[pos] == ',')
     169                 :               {
     170                 :                 PRTime t;
     171                 :                 PRTime seconds;
     172               0 :                 PR_sscanf(p+1, "%llu", &seconds);
     173               0 :                 LL_MUL(t, seconds, PR_USEC_PER_SEC);
     174               0 :                 PR_ExplodeTime(t, PR_LocalTimeParameters, &(result->fe_time) );
     175                 :               }
     176                 :             }
     177                 :           }
     178               0 :           else if (*p == 's')
     179                 :           {
     180               0 :             if (isdigit(line[pos]))
     181                 :             {
     182               0 :               while (pos < linelen && isdigit(line[pos]))
     183               0 :                 pos++;
     184               0 :               if (pos < linelen && line[pos] == ',' &&
     185                 :                  ((&line[pos]) - (p+1)) < int(sizeof(result->fe_size)-1) )
     186                 :               {
     187               0 :                 memcpy( result->fe_size, p+1, (unsigned)(&line[pos] - (p+1)) );
     188               0 :                 result->fe_size[(&line[pos] - (p+1))] = '\0';
     189                 :               }
     190                 :             }
     191                 :           }
     192               0 :           else if (isalpha(*p)) /* 'i'/'up' or unknown "fact" (property) */
     193                 :           {
     194               0 :             while (pos < linelen && *++p != ',')
     195               0 :               pos++;
     196                 :           }
     197               0 :           else if (*p != '\t' || (p+1) != tokens[1])
     198                 :           {
     199               0 :             break; /* its not EPLF after all */
     200                 :           }
     201                 :           else
     202                 :           {
     203               0 :             state->parsed_one = 1;
     204               0 :             state->lstyle = lstyle = 'E';
     205                 : 
     206               0 :             p = &(line[linelen_sans_wsp]);
     207               0 :             result->fe_fname = tokens[1];
     208               0 :             result->fe_fnlen = p - tokens[1];
     209                 : 
     210               0 :             if (!result->fe_type) /* access denied */
     211                 :             {
     212               0 :               result->fe_type = 'f'; /* is assuming 'f'ile correct? */
     213               0 :               return '?';            /* NO! junk it. */
     214                 :             }
     215               0 :             return result->fe_type;
     216                 :           }
     217               0 :           if (pos >= (linelen-1) || line[pos] != ',')
     218               0 :             break;
     219               0 :           pos++;
     220                 :         } /* while (pos < linelen) */
     221               0 :         memset( result, 0, sizeof(*result) );
     222                 :       } /* if (*line == '+' && linelen > 4 && numtoks >= 2) */
     223                 :     } /* if (!lstyle && (!state->lstyle || state->lstyle == 'E')) */
     224                 : #endif /* SUPPORT_EPLF */
     225                 : 
     226                 :     /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
     227                 : 
     228                 : #if defined(SUPPORT_VMS)
     229              48 :     if (!lstyle && (!state->lstyle || state->lstyle == 'V'))
     230                 :     {                          /* try VMS Multinet/UCX/CMS server */
     231                 :       /*
     232                 :        * Legal characters in a VMS file/dir spec are [A-Z0-9$.-_~].
     233                 :        * '$' cannot begin a filename and `-' cannot be used as the first 
     234                 :        * or last character. '.' is only valid as a directory separator 
     235                 :        * and <file>.<type> separator. A canonical filename spec might look 
     236                 :        * like this: DISK$VOL:[DIR1.DIR2.DIR3]FILE.TYPE;123
     237                 :        * All VMS FTP servers LIST in uppercase.
     238                 :        *
     239                 :        * We need to be picky about this in order to support
     240                 :        * multi-line listings correctly.
     241                 :       */
     242              23 :       if (!state->parsed_one &&
     243               0 :           (numtoks == 1 || (numtoks == 2 && toklen[0] == 9 &&
     244               0 :                             memcmp(tokens[0], "Directory", 9)==0 )))
     245                 :       {
     246                 :         /* If no dirstyle has been detected yet, and this line is a 
     247                 :          * VMS list's dirname, then turn on VMS dirstyle.
     248                 :          * eg "ACA:[ANONYMOUS]", "DISK$FTP:[ANONYMOUS]", "SYS$ANONFTP:" 
     249                 :         */
     250               0 :         p = tokens[0];
     251               0 :         pos = toklen[0];
     252               0 :         if (numtoks == 2)
     253                 :         {
     254               0 :           p = tokens[1];
     255               0 :           pos = toklen[1];
     256                 :         }
     257               0 :         pos--;
     258               0 :         if (pos >= 3)
     259                 :         {
     260               0 :           while (pos > 0 && p[pos] != '[')
     261                 :           {
     262               0 :             pos--;
     263               0 :             if (p[pos] == '-' || p[pos] == '$')
     264                 :             {
     265               0 :               if (pos == 0 || p[pos-1] == '[' || p[pos-1] == '.' ||
     266               0 :                   (p[pos] == '-' && (p[pos+1] == ']' || p[pos+1] == '.')))
     267               0 :                 break;
     268                 :             }
     269               0 :             else if (p[pos] != '.' && p[pos] != '~' && 
     270               0 :                      !isdigit(p[pos]) && !isalpha(p[pos]))
     271               0 :               break;
     272               0 :             else if (isalpha(p[pos]) && p[pos] != toupper(p[pos]))
     273               0 :               break;
     274                 :           }
     275               0 :           if (pos > 0)
     276                 :           {
     277               0 :             pos--;
     278               0 :             if (p[pos] != ':' || p[pos+1] != '[')
     279               0 :               pos = 0;
     280                 :           }
     281                 :         }
     282               0 :         if (pos > 0 && p[pos] == ':')
     283                 :         {
     284               0 :           while (pos > 0)
     285                 :           {
     286               0 :             pos--;
     287               0 :             if (p[pos] != '$' && p[pos] != '_' && p[pos] != '-' &&
     288               0 :                 p[pos] != '~' && !isdigit(p[pos]) && !isalpha(p[pos]))
     289               0 :               break;
     290               0 :             else if (isalpha(p[pos]) && p[pos] != toupper(p[pos]))
     291               0 :               break;
     292                 :           }
     293               0 :           if (pos == 0)
     294                 :           {  
     295               0 :             state->lstyle = 'V';
     296               0 :             return '?'; /* its junk */
     297                 :           }
     298                 :         }
     299                 :         /* fallthrough */ 
     300                 :       }
     301              23 :       else if ((tokens[0][toklen[0]-1]) != ';')
     302                 :       {
     303              21 :         if (numtoks == 1 && (state->lstyle == 'V' && !carry_buf_len))
     304               0 :           lstyle = 'V';
     305              21 :         else if (numtoks < 4)
     306                 :           ;
     307              21 :         else if (toklen[1] >= 10 && memcmp(tokens[1], "%RMS-E-PRV", 10) == 0)
     308               0 :           lstyle = 'V';
     309              42 :         else if ((&line[linelen] - tokens[1]) >= 22 &&
     310              21 :                   memcmp(tokens[1], "insufficient privilege", 22) == 0)
     311               0 :           lstyle = 'V';
     312              21 :         else if (numtoks != 4 && numtoks != 6)
     313                 :           ;
     314              10 :         else if (numtoks == 6 && (
     315               0 :                  toklen[5] < 4 || *tokens[5] != '(' ||        /* perms */
     316               0 :                            (tokens[5][toklen[5]-1]) != ')'  ))
     317                 :           ;
     318              82 :         else if (  (toklen[2] == 10 || toklen[2] == 11) &&      
     319               6 :                         (tokens[2][toklen[2]-5]) == '-' &&
     320               6 :                         (tokens[2][toklen[2]-9]) == '-' &&
     321              24 :         (((toklen[3]==4 || toklen[3]==5 || toklen[3]==7 || toklen[3]==8) &&
     322               0 :                         (tokens[3][toklen[3]-3]) == ':' ) ||
     323              12 :          ((toklen[3]==10 || toklen[3]==11 ) &&
     324               6 :                         (tokens[3][toklen[3]-3]) == '.' )
     325                 :         ) &&  /* time in [H]H:MM[:SS[.CC]] format */
     326               6 :                                     isdigit(*tokens[1]) && /* size */
     327               6 :                                     isdigit(*tokens[2]) && /* date */
     328               6 :                                     isdigit(*tokens[3])    /* time */
     329                 :                 )
     330                 :         {
     331               6 :           lstyle = 'V';
     332                 :         }
     333              21 :         if (lstyle == 'V')
     334                 :         {
     335                 :           /* 
     336                 :           * MultiNet FTP:
     337                 :           *   LOGIN.COM;2                 1   4-NOV-1994 04:09 [ANONYMOUS] (RWE,RWE,,)
     338                 :           *   PUB.DIR;1                   1  27-JAN-1994 14:46 [ANONYMOUS] (RWE,RWE,RE,RWE)
     339                 :           *   README.FTP;1        %RMS-E-PRV, insufficient privilege or file protection violation
     340                 :           *   ROUSSOS.DIR;1               1  27-JAN-1994 14:48 [CS,ROUSSOS] (RWE,RWE,RE,R)
     341                 :           *   S67-50903.JPG;1           328  22-SEP-1998 16:19 [ANONYMOUS] (RWED,RWED,,)
     342                 :           * UCX FTP: 
     343                 :           *   CII-MANUAL.TEX;1  213/216  29-JAN-1996 03:33:12  [ANONYMOU,ANONYMOUS] (RWED,RWED,,)
     344                 :           * CMU/VMS-IP FTP
     345                 :           *   [VMSSERV.FILES]ALARM.DIR;1 1/3 5-MAR-1993 18:09
     346                 :           * TCPware FTP
     347                 :           *   FOO.BAR;1 4 5-MAR-1993 18:09:01.12
     348                 :           * Long filename example:
     349                 :           *   THIS-IS-A-LONG-VMS-FILENAME.AND-THIS-IS-A-LONG-VMS-FILETYPE\r\n
     350                 :           *                    213[/nnn]  29-JAN-1996 03:33[:nn]  [ANONYMOU,ANONYMOUS] (RWED,RWED,,)
     351                 :           */
     352               6 :           tokmarker = 0;
     353               6 :           p = tokens[0];
     354               6 :           pos = 0;
     355               6 :           if (*p == '[' && toklen[0] >= 4) /* CMU style */
     356                 :           {
     357               6 :             if (p[1] != ']') 
     358                 :             {
     359               6 :               p++;
     360               6 :               pos++;
     361                 :             }
     362              48 :             while (lstyle && pos < toklen[0] && *p != ']')
     363                 :             {
     364             102 :               if (*p != '$' && *p != '.' && *p != '_' && *p != '-' &&
     365              66 :                   *p != '~' && !isdigit(*p) && !isalpha(*p))              
     366               0 :                 lstyle = 0;
     367              36 :               pos++;
     368              36 :               p++;
     369                 :             }
     370               6 :             if (lstyle && pos < (toklen[0]-1))
     371                 :             {
     372                 :               /* ']' was found and there is at least one character after it */
     373               4 :               NS_ASSERTION(*p == ']', "unexpected state");
     374               4 :               pos++;
     375               4 :               p++;
     376               4 :               tokmarker = pos; /* length of leading "[DIR1.DIR2.etc]" */
     377                 :             } else {
     378                 :               /* not a CMU style listing */
     379               2 :               lstyle = 0;
     380                 :             }
     381                 :           }
     382              15 :           while (lstyle && pos < toklen[0] && *p != ';')
     383                 :           {
     384               9 :             if (*p != '$' && *p != '.' && *p != '_' && *p != '-' &&
     385               6 :                 *p != '~' && !isdigit(*p) && !isalpha(*p))
     386               0 :               lstyle = 0;
     387               3 :             else if (isalpha(*p) && *p != toupper(*p))
     388               0 :               lstyle = 0;
     389               3 :             p++;
     390               3 :             pos++;
     391                 :           }
     392               6 :           if (lstyle && *p == ';')
     393                 :           {
     394               3 :             if (pos == 0 || pos == (toklen[0]-1))
     395               0 :               lstyle = 0;
     396               7 :             for (pos++;lstyle && pos < toklen[0];pos++)
     397                 :             {
     398               4 :               if (!isdigit(tokens[0][pos]))
     399               1 :                 lstyle = 0;
     400                 :             }
     401                 :           }
     402               6 :           pos = (p - tokens[0]); /* => fnlength sans ";####" */
     403               6 :           pos -= tokmarker;      /* => fnlength sans "[DIR1.DIR2.etc]" */
     404               6 :           p = &(tokens[0][tokmarker]); /* offset of basename */
     405                 : 
     406               6 :           if (!lstyle || pos == 0 || pos > 80) /* VMS filenames can't be longer than that */
     407                 :           {
     408               4 :             lstyle = 0;
     409                 :           }
     410               2 :           else if (numtoks == 1)
     411                 :           { 
     412                 :             /* if VMS has been detected and there is only one token and that 
     413                 :              * token was a VMS filename then this is a multiline VMS LIST entry.
     414                 :             */
     415               0 :             if (pos >= (sizeof(state->carry_buf)-1))
     416               0 :               pos = (sizeof(state->carry_buf)-1); /* shouldn't happen */
     417               0 :             memcpy( state->carry_buf, p, pos );
     418               0 :             state->carry_buf_len = pos;
     419               0 :             return '?'; /* tell caller to treat as junk */
     420                 :           }
     421               2 :           else if (isdigit(*tokens[1])) /* not no-privs message */
     422                 :           {
     423               4 :             for (pos = 0; lstyle && pos < (toklen[1]); pos++)
     424                 :             {
     425               2 :               if (!isdigit((tokens[1][pos])) && (tokens[1][pos]) != '/')
     426               0 :                 lstyle = 0;
     427                 :             }
     428               2 :             if (lstyle && numtoks > 4) /* Multinet or UCX but not CMU */
     429                 :             {
     430               0 :               for (pos = 1; lstyle && pos < (toklen[5]-1); pos++)
     431                 :               {
     432               0 :                 p = &(tokens[5][pos]);
     433               0 :                 if (*p!='R' && *p!='W' && *p!='E' && *p!='D' && *p!=',')
     434               0 :                   lstyle = 0;
     435                 :               }
     436                 :             }
     437                 :           }
     438                 :         } /* passed initial tests */
     439                 :       } /* else if ((tokens[0][toklen[0]-1]) != ';') */    
     440                 : 
     441              23 :       if (lstyle == 'V')
     442                 :       {
     443               2 :         state->parsed_one = 1;
     444               2 :         state->lstyle = lstyle;
     445                 : 
     446               2 :         if (isdigit(*tokens[1]))  /* not permission denied etc */
     447                 :         {
     448                 :           /* strip leading directory name */
     449               2 :           if (*tokens[0] == '[') /* CMU server */
     450                 :           {
     451               2 :             pos = toklen[0]-1;
     452               2 :             p = tokens[0]+1;
     453              16 :             while (*p != ']')
     454                 :             {
     455              12 :               p++;
     456              12 :               pos--;
     457                 :             }
     458               2 :             toklen[0] = --pos;
     459               2 :             tokens[0] = ++p;
     460                 :           }
     461               2 :           pos = 0;
     462               6 :           while (pos < toklen[0] && (tokens[0][pos]) != ';')
     463               2 :             pos++;
     464                 :        
     465               2 :           result->fe_cinfs = 1;
     466               2 :           result->fe_type = 'f';
     467               2 :           result->fe_fname = tokens[0];
     468               2 :           result->fe_fnlen = pos;
     469                 : 
     470               2 :           if (pos > 4)
     471                 :           {
     472               0 :             p = &(tokens[0][pos-4]);
     473               0 :             if (p[0] == '.' && p[1] == 'D' && p[2] == 'I' && p[3] == 'R')
     474                 :             {
     475               0 :               result->fe_fnlen -= 4;
     476               0 :               result->fe_type = 'd';
     477                 :             }
     478                 :           }
     479                 : 
     480               2 :           if (result->fe_type != 'd')
     481                 :           {
     482                 :             /* #### or used/allocated form. If used/allocated form, then
     483                 :              * 'used' is the size in bytes if and only if 'used'<=allocated.
     484                 :              * If 'used' is size in bytes then it can be > 2^32
     485                 :              * If 'used' is not size in bytes then it is size in blocks.
     486                 :             */
     487               2 :             pos = 0;
     488               6 :             while (pos < toklen[1] && (tokens[1][pos]) != '/')
     489               2 :               pos++;
     490                 :             
     491                 : /*
     492                 :  * I've never seen size come back in bytes, its always in blocks, and 
     493                 :  * the following test fails. So, always perform the "size in blocks".
     494                 :  * I'm leaving the "size in bytes" code if'd out in case we ever need
     495                 :  * to re-instate it.
     496                 : */
     497                 : #if 0
     498                 :             if (pos < toklen[1] && ( (pos<<1) > (toklen[1]-1) ||
     499                 :                  (strtoul(tokens[1], (char **)0, 10) > 
     500                 :                   strtoul(tokens[1]+pos+1, (char **)0, 10))        ))
     501                 :             {                                   /* size is in bytes */
     502                 :               if (pos > (sizeof(result->fe_size)-1))
     503                 :                 pos = sizeof(result->fe_size)-1;
     504                 :               memcpy( result->fe_size, tokens[1], pos );
     505                 :               result->fe_size[pos] = '\0';
     506                 :             }
     507                 :             else /* size is in blocks */
     508                 : #endif
     509                 :             {
     510                 :               /* size requires multiplication by blocksize. 
     511                 :                *
     512                 :                * We could assume blocksize is 512 (like Lynx does) and
     513                 :                * shift by 9, but that might not be right. Even if it 
     514                 :                * were, doing that wouldn't reflect what the file's 
     515                 :                * real size was. The sanest thing to do is not use the
     516                 :                * LISTing's filesize, so we won't (like ftpmirror).
     517                 :                *
     518                 :                * ulltoa(((unsigned long long)fsz)<<9, result->fe_size, 10);
     519                 :                *
     520                 :                * A block is always 512 bytes on OpenVMS, compute size.
     521                 :                * So its rounded up to the next block, so what, its better
     522                 :                * than not showing the size at all.
     523                 :                * A block is always 512 bytes on OpenVMS, compute size.
     524                 :                * So its rounded up to the next block, so what, its better
     525                 :                * than not showing the size at all.
     526                 :               */
     527                 :               PRUint64 fsz, factor;
     528               2 :               LL_UI2L(fsz, strtoul(tokens[1], (char **)0, 10));
     529               2 :               LL_UI2L(factor, 512);
     530               2 :               LL_MUL(fsz, fsz, factor);
     531                 :               PR_snprintf(result->fe_size, sizeof(result->fe_size), 
     532               2 :                           "%lld", fsz);
     533                 :             } 
     534                 : 
     535                 :           } /* if (result->fe_type != 'd') */
     536                 : 
     537               2 :           p = tokens[2] + 2;
     538               2 :           if (*p == '-')
     539               0 :             p++;
     540               2 :           tbuf[0] = p[0];
     541               2 :           tbuf[1] = tolower(p[1]);
     542               2 :           tbuf[2] = tolower(p[2]);
     543               2 :           month_num = 0;
     544               6 :           for (pos = 0; pos < (12*3); pos+=3)
     545                 :           {
     546              10 :             if (tbuf[0] == month_names[pos+0] && 
     547               2 :                 tbuf[1] == month_names[pos+1] && 
     548               2 :                 tbuf[2] == month_names[pos+2])
     549               2 :               break;
     550               4 :             month_num++;
     551                 :           }
     552               2 :           if (month_num >= 12)
     553               0 :             month_num = 0;
     554               2 :           result->fe_time.tm_month = month_num;
     555               2 :           result->fe_time.tm_mday = atoi(tokens[2]);
     556               2 :           result->fe_time.tm_year = atoi(p+4); // NSPR wants year as XXXX
     557                 : 
     558               2 :           p = tokens[3] + 2;
     559               2 :           if (*p == ':')
     560               2 :             p++;
     561               2 :           if (p[2] == ':')
     562               2 :             result->fe_time.tm_sec = atoi(p+3);
     563               2 :           result->fe_time.tm_hour = atoi(tokens[3]);
     564               2 :           result->fe_time.tm_min  = atoi(p);
     565                 :       
     566               2 :           return result->fe_type;
     567                 : 
     568                 :         } /* if (isdigit(*tokens[1])) */
     569                 : 
     570               0 :         return '?'; /* junk */
     571                 : 
     572                 :       } /* if (lstyle == 'V') */
     573                 :     } /* if (!lstyle && (!state->lstyle || state->lstyle == 'V')) */
     574                 : #endif
     575                 : 
     576                 :     /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
     577                 : 
     578                 : #if defined(SUPPORT_CMS)
     579                 :     /* Virtual Machine/Conversational Monitor System (IBM Mainframe) */
     580              46 :     if (!lstyle && (!state->lstyle || state->lstyle == 'C'))  /* VM/CMS */
     581                 :     {
     582                 :       /* LISTing according to mirror.pl
     583                 :        * Filename FileType  Fm Format Lrecl  Records Blocks Date      Time
     584                 :        * LASTING  GLOBALV   A1 V      41     21     1       9/16/91   15:10:32
     585                 :        * J43401   NETLOG    A0 V      77     1      1       9/12/91   12:36:04
     586                 :        * PROFILE  EXEC      A1 V      17     3      1       9/12/91   12:39:07
     587                 :        * DIRUNIX  SCRIPT    A1 V      77     1216   17      1/04/93   20:30:47
     588                 :        * MAIL     PROFILE   A2 F      80     1      1       10/14/92  16:12:27
     589                 :        * BADY2K   TEXT      A0 V      1      1      1       1/03/102  10:11:12
     590                 :        * AUTHORS            A1 DIR    -      -      -       9/20/99   10:31:11
     591                 :        *
     592                 :        * LISTing from vm.marist.edu and vm.sc.edu
     593                 :        * 220-FTPSERVE IBM VM Level 420 at VM.MARIST.EDU, 04:58:12 EDT WEDNESDAY 2002-07-10
     594                 :        * AUTHORS           DIR        -          -          - 1999-09-20 10:31:11 -
     595                 :        * HARRINGTON        DIR        -          -          - 1997-02-12 15:33:28 -
     596                 :        * PICS              DIR        -          -          - 2000-10-12 15:43:23 -
     597                 :        * SYSFILE           DIR        -          -          - 2000-07-20 17:48:01 -
     598                 :        * WELCNVT  EXEC     V         72          9          1 1999-09-20 17:16:18 -
     599                 :        * WELCOME  EREADME  F         80         21          1 1999-12-27 16:19:00 -
     600                 :        * WELCOME  README   V         82         21          1 1999-12-27 16:19:04 -
     601                 :        * README   ANONYMOU V         71         26          1 1997-04-02 12:33:20 TCP291
     602                 :        * README   ANONYOLD V         71         15          1 1995-08-25 16:04:27 TCP291
     603                 :       */
     604              17 :       if (numtoks >= 7 && (toklen[0]+toklen[1]) <= 16)
     605                 :       {
     606              57 :         for (pos = 1; !lstyle && (pos+5) < numtoks; pos++)
     607                 :         {
     608              47 :           p = tokens[pos];
     609              94 :           if ((toklen[pos] == 1 && (*p == 'F' || *p == 'V')) ||
     610              47 :               (toklen[pos] == 3 && *p == 'D' && p[1] == 'I' && p[2] == 'R'))
     611                 :           {
     612               0 :             if (toklen[pos+5] == 8 && (tokens[pos+5][2]) == ':' &&
     613               0 :                                       (tokens[pos+5][5]) == ':'   )
     614                 :             {
     615               0 :               p = tokens[pos+4];
     616               0 :               if ((toklen[pos+4] == 10 && p[4] == '-' && p[7] == '-') ||
     617               0 :                   (toklen[pos+4] >= 7 && toklen[pos+4] <= 9 && 
     618               0 :                             p[((p[1]!='/')?(2):(1))] == '/' && 
     619               0 :                             p[((p[1]!='/')?(5):(4))] == '/'))
     620                 :                /* Y2K bugs possible ("7/06/102" or "13/02/101") */
     621                 :               {
     622               0 :                 if ( (*tokens[pos+1] == '-' &&
     623               0 :                       *tokens[pos+2] == '-' &&
     624               0 :                       *tokens[pos+3] == '-')  ||
     625               0 :                       (isdigit(*tokens[pos+1]) &&
     626               0 :                        isdigit(*tokens[pos+2]) &&
     627               0 :                        isdigit(*tokens[pos+3])) )
     628                 :                 {
     629               0 :                   lstyle = 'C';
     630               0 :                   tokmarker = pos;
     631                 :                 }
     632                 :               }
     633                 :             }
     634                 :           }
     635                 :         } /* for (pos = 1; !lstyle && (pos+5) < numtoks; pos++) */
     636                 :       } /* if (numtoks >= 7) */
     637                 : 
     638                 :       /* extra checking if first pass */
     639              17 :       if (lstyle && !state->lstyle) 
     640                 :       {
     641               0 :         for (pos = 0, p = tokens[0]; lstyle && pos < toklen[0]; pos++, p++)
     642                 :         {  
     643               0 :           if (isalpha(*p) && toupper(*p) != *p)
     644               0 :             lstyle = 0;
     645                 :         } 
     646               0 :         for (pos = tokmarker+1; pos <= tokmarker+3; pos++)
     647                 :         {
     648               0 :           if (!(toklen[pos] == 1 && *tokens[pos] == '-'))
     649                 :           {
     650               0 :             for (p = tokens[pos]; lstyle && p<(tokens[pos]+toklen[pos]); p++)
     651                 :             {
     652               0 :               if (!isdigit(*p))
     653               0 :                 lstyle = 0;
     654                 :             }
     655                 :           }
     656                 :         }
     657               0 :         for (pos = 0, p = tokens[tokmarker+4]; 
     658               0 :              lstyle && pos < toklen[tokmarker+4]; pos++, p++)
     659                 :         {
     660               0 :           if (*p == '/')
     661                 :           { 
     662                 :             /* There may be Y2K bugs in the date. Don't simplify to
     663                 :              * pos != (len-3) && pos != (len-6) like time is done.
     664                 :             */             
     665               0 :             if ((tokens[tokmarker+4][1]) == '/')
     666                 :             {
     667               0 :               if (pos != 1 && pos != 4)
     668               0 :                 lstyle = 0;
     669                 :             }
     670               0 :             else if (pos != 2 && pos != 5)
     671               0 :               lstyle = 0;
     672                 :           }
     673               0 :           else if (*p != '-' && !isdigit(*p))
     674               0 :             lstyle = 0;
     675               0 :           else if (*p == '-' && pos != 4 && pos != 7)
     676               0 :             lstyle = 0;
     677                 :         }
     678               0 :         for (pos = 0, p = tokens[tokmarker+5]; 
     679               0 :              lstyle && pos < toklen[tokmarker+5]; pos++, p++)
     680                 :         {
     681               0 :           if (*p != ':' && !isdigit(*p))
     682               0 :             lstyle = 0;
     683               0 :           else if (*p == ':' && pos != (toklen[tokmarker+5]-3)
     684               0 :                              && pos != (toklen[tokmarker+5]-6))
     685               0 :             lstyle = 0;
     686                 :         }
     687                 :       } /* initial if() */
     688                 : 
     689              17 :       if (lstyle == 'C')
     690                 :       {
     691               0 :         state->parsed_one = 1;
     692               0 :         state->lstyle = lstyle;
     693                 : 
     694               0 :         p = tokens[tokmarker+4];
     695               0 :         if (toklen[tokmarker+4] == 10) /* newstyle: YYYY-MM-DD format */
     696                 :         {
     697               0 :           result->fe_time.tm_year = atoi(p+0) - 1900;
     698               0 :           result->fe_time.tm_month  = atoi(p+5) - 1;
     699               0 :           result->fe_time.tm_mday = atoi(p+8);
     700                 :         }
     701                 :         else /* oldstyle: [M]M/DD/YY format */
     702                 :         {
     703               0 :           pos = toklen[tokmarker+4];
     704               0 :           result->fe_time.tm_month  = atoi(p) - 1;
     705               0 :           result->fe_time.tm_mday = atoi((p+pos)-5);
     706               0 :           result->fe_time.tm_year = atoi((p+pos)-2);
     707               0 :           if (result->fe_time.tm_year < 70)
     708               0 :             result->fe_time.tm_year += 100;
     709                 :         }
     710                 : 
     711               0 :         p = tokens[tokmarker+5];
     712               0 :         pos = toklen[tokmarker+5];
     713               0 :         result->fe_time.tm_hour  = atoi(p);
     714               0 :         result->fe_time.tm_min = atoi((p+pos)-5);
     715               0 :         result->fe_time.tm_sec = atoi((p+pos)-2);
     716                 : 
     717               0 :         result->fe_cinfs = 1;
     718               0 :         result->fe_fname = tokens[0];
     719               0 :         result->fe_fnlen = toklen[0];
     720               0 :         result->fe_type  = 'f';
     721                 : 
     722               0 :         p = tokens[tokmarker];
     723               0 :         if (toklen[tokmarker] == 3 && *p=='D' && p[1]=='I' && p[2]=='R')
     724               0 :           result->fe_type  = 'd';
     725                 : 
     726               0 :         if ((/*newstyle*/ toklen[tokmarker+4] == 10 && tokmarker > 1) ||
     727               0 :             (/*oldstyle*/ toklen[tokmarker+4] != 10 && tokmarker > 2))
     728                 :         {                            /* have a filetype column */
     729                 :           char *dot;
     730               0 :           p = &(tokens[0][toklen[0]]);
     731               0 :           memcpy( &dot, &p, sizeof(dot) ); /* NASTY! */
     732               0 :           *dot++ = '.';
     733               0 :           p = tokens[1];
     734               0 :           for (pos = 0; pos < toklen[1]; pos++)
     735               0 :             *dot++ = *p++;
     736               0 :           result->fe_fnlen += 1 + toklen[1];
     737                 :         }
     738                 : 
     739                 :         /* oldstyle LISTING: 
     740                 :          * files/dirs not on the 'A' minidisk are not RETRievable/CHDIRable 
     741                 :         if (toklen[tokmarker+4] != 10 && *tokens[tokmarker-1] != 'A')
     742                 :           return '?';
     743                 :         */
     744                 :         
     745                 :         /* VM/CMS LISTings have no usable filesize field. 
     746                 :          * Have to use the 'SIZE' command for that.
     747                 :         */
     748               0 :         return result->fe_type;
     749                 : 
     750                 :       } /* if (lstyle == 'C' && (!state->lstyle || state->lstyle == lstyle)) */
     751                 :     } /* VM/CMS */
     752                 : #endif
     753                 : 
     754                 :     /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
     755                 : 
     756                 : #if defined(SUPPORT_DOS) /* WinNT DOS dirstyle */
     757              46 :     if (!lstyle && (!state->lstyle || state->lstyle == 'W'))
     758                 :     {
     759                 :       /*
     760                 :        * "10-23-00  01:27PM       <DIR>          veronist"
     761                 :        * "06-15-00  07:37AM       <DIR>          zoe"
     762                 :        * "07-14-00  01:35PM              2094926 canprankdesk.tif"
     763                 :        * "07-21-00  01:19PM                95077 Jon Kauffman Enjoys the Good Life.jpg"
     764                 :        * "07-21-00  01:19PM                52275 Name Plate.jpg"
     765                 :        * "07-14-00  01:38PM              2250540 Valentineoffprank-HiRes.jpg"
     766                 :       */
     767              51 :       if ((numtoks >= 4) && toklen[0] == 8 && toklen[1] == 7 && 
     768              22 :           (*tokens[2] == '<' || isdigit(*tokens[2])) )
     769                 :       {
     770              16 :         p = tokens[0];
     771              96 :         if ( isdigit(p[0]) && isdigit(p[1]) && p[2]=='-' && 
     772              48 :              isdigit(p[3]) && isdigit(p[4]) && p[5]=='-' &&
     773              32 :              isdigit(p[6]) && isdigit(p[7]) )
     774                 :         {
     775              16 :           p = tokens[1];
     776              80 :           if ( isdigit(p[0]) && isdigit(p[1]) && p[2]==':' && 
     777              32 :                isdigit(p[3]) && isdigit(p[4]) && 
     778              32 :                (p[5]=='A' || p[5]=='P') && p[6]=='M')
     779                 :           {
     780              16 :             lstyle = 'W';
     781              16 :             if (!state->lstyle)
     782                 :             {            
     783               4 :               p = tokens[2];
     784                 :               /* <DIR> or <JUNCTION> */
     785               4 :               if (*p != '<' || p[toklen[2]-1] != '>')
     786                 :               {
     787               8 :                 for (pos = 1; (lstyle && pos < toklen[2]); pos++)
     788                 :                 {
     789               6 :                   if (!isdigit(*++p))
     790               0 :                     lstyle = 0;
     791                 :                 }
     792                 :               }
     793                 :             }
     794                 :           }
     795                 :         }
     796                 :       }
     797                 : 
     798              29 :       if (lstyle == 'W')
     799                 :       {
     800              16 :         state->parsed_one = 1;
     801              16 :         state->lstyle = lstyle;
     802                 : 
     803              16 :         p = &(line[linelen]); /* line end */
     804              16 :         result->fe_cinfs = 1;
     805              16 :         result->fe_fname = tokens[3];
     806              16 :         result->fe_fnlen = p - tokens[3];
     807              16 :         result->fe_type = 'd';
     808                 : 
     809              16 :         if (*tokens[2] != '<') /* not <DIR> or <JUNCTION> */
     810                 :         {
     811                 :           // try to handle correctly spaces at the beginning of the filename
     812                 :           // filesize (token[2]) must end at offset 38
     813               6 :           if (tokens[2] + toklen[2] - line == 38) {
     814               4 :             result->fe_fname = &(line[39]);
     815               4 :             result->fe_fnlen = p - result->fe_fname;
     816                 :           }
     817               6 :           result->fe_type = 'f';
     818               6 :           pos = toklen[2];
     819              12 :           while (pos > (sizeof(result->fe_size)-1))
     820               0 :             pos = (sizeof(result->fe_size)-1);
     821               6 :           memcpy( result->fe_size, tokens[2], pos );
     822               6 :           result->fe_size[pos] = '\0';
     823                 :         }
     824                 :         else {
     825                 :           // try to handle correctly spaces at the beginning of the filename
     826                 :           // token[2] must begin at offset 24, the length is 5 or 10
     827                 :           // token[3] must begin at offset 39 or higher
     828              16 :           if (tokens[2] - line == 24 && (toklen[2] == 5 || toklen[2] == 10) &&
     829               6 :               tokens[3] - line >= 39) {
     830               4 :             result->fe_fname = &(line[39]);
     831               4 :             result->fe_fnlen = p - result->fe_fname;
     832                 :           }
     833                 : 
     834              10 :           if ((tokens[2][1]) != 'D') /* not <DIR> */
     835                 :           {
     836               5 :             result->fe_type = '?'; /* unknown until junc for sure */
     837               5 :             if (result->fe_fnlen > 4)
     838                 :             {
     839               5 :               p = result->fe_fname;
     840              51 :               for (pos = result->fe_fnlen - 4; pos > 0; pos--)
     841                 :               {
     842              61 :                 if (p[0] == ' ' && p[3] == ' ' && p[2] == '>' &&
     843              10 :                     (p[1] == '=' || p[1] == '-'))
     844                 :                 {
     845               5 :                   result->fe_type = 'l';
     846               5 :                   result->fe_fnlen = p - result->fe_fname;
     847               5 :                   result->fe_lname = p + 4;
     848               5 :                   result->fe_lnlen = &(line[linelen]) 
     849               5 :                                      - result->fe_lname;
     850               5 :                   break;
     851                 :                 }
     852              46 :                 p++;
     853                 :               }
     854                 :             }
     855                 :           }
     856                 :         }
     857                 : 
     858              16 :         result->fe_time.tm_month = atoi(tokens[0]+0);
     859              16 :         if (result->fe_time.tm_month != 0)
     860                 :         {
     861              16 :           result->fe_time.tm_month--;
     862              16 :           result->fe_time.tm_mday = atoi(tokens[0]+3);
     863              16 :           result->fe_time.tm_year = atoi(tokens[0]+6);
     864                 :           /* if year has only two digits then assume that
     865                 :                00-79 is 2000-2079
     866                 :                80-99 is 1980-1999 */
     867              16 :           if (result->fe_time.tm_year < 80)
     868              15 :             result->fe_time.tm_year += 2000;
     869               1 :           else if (result->fe_time.tm_year < 100)
     870               1 :             result->fe_time.tm_year += 1900;
     871                 :         }
     872                 : 
     873              16 :         result->fe_time.tm_hour = atoi(tokens[1]+0);
     874              16 :         result->fe_time.tm_min = atoi(tokens[1]+3);
     875              16 :         if ((tokens[1][5]) == 'P' && result->fe_time.tm_hour < 12)
     876               0 :           result->fe_time.tm_hour += 12;
     877                 : 
     878                 :         /* the caller should do this (if dropping "." and ".." is desired)
     879                 :         if (result->fe_type == 'd' && result->fe_fname[0] == '.' &&
     880                 :             (result->fe_fnlen == 1 || (result->fe_fnlen == 2 &&
     881                 :                                       result->fe_fname[1] == '.')))
     882                 :           return '?';
     883                 :         */
     884                 : 
     885              16 :         return result->fe_type;  
     886                 :       } /* if (lstyle == 'W' && (!state->lstyle || state->lstyle == lstyle)) */
     887                 :     } /* if (!lstyle && (!state->lstyle || state->lstyle == 'W')) */
     888                 : #endif
     889                 : 
     890                 :     /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
     891                 : 
     892                 : #if defined(SUPPORT_OS2)
     893              30 :     if (!lstyle && (!state->lstyle || state->lstyle == 'O')) /* OS/2 test */
     894                 :     {
     895                 :       /* 220 server IBM TCP/IP for OS/2 - FTP Server ver 23:04:36 on Jan 15 1997 ready.
     896                 :       * fixed position, space padded columns. I have only a vague idea 
     897                 :       * of what the contents between col 18 and 34 might be: All I can infer
     898                 :       * is that there may be attribute flags in there and there may be 
     899                 :       * a " DIR" in there.
     900                 :       *
     901                 :       *          1         2         3         4         5         6
     902                 :       *0123456789012345678901234567890123456789012345678901234567890123456789
     903                 :       *----- size -------|??????????????? MM-DD-YY|  HH:MM| nnnnnnnnn....
     904                 :       *                 0  DIR            04-11-95   16:26  .
     905                 :       *                 0  DIR            04-11-95   16:26  ..
     906                 :       *                 0  DIR            04-11-95   16:26  ADDRESS
     907                 :       *               612  RHSA           07-28-95   16:45  air_tra1.bag
     908                 :       *               195  A              08-09-95   10:23  Alfa1.bag
     909                 :       *                 0  RHS   DIR      04-11-95   16:26  ATTACH
     910                 :       *               372  A              08-09-95   10:26  Aussie_1.bag
     911                 :       *            310992                 06-28-94   09:56  INSTALL.EXE
     912                 :       *                            1         2         3         4
     913                 :       *                  01234567890123456789012345678901234567890123456789
     914                 :       * dirlist from the mirror.pl project, col positions from Mozilla.
     915                 :       */
     916              13 :       p = &(line[toklen[0]]);
     917                 :       /* \s(\d\d-\d\d-\d\d)\s+(\d\d:\d\d)\s */
     918              13 :       if (numtoks >= 4 && toklen[0] <= 18 && isdigit(*tokens[0]) &&
     919               0 :          (linelen - toklen[0]) >= (53-18)                        &&
     920               0 :          p[18-18] == ' ' && p[34-18] == ' '                      &&
     921               0 :          p[37-18] == '-' && p[40-18] == '-' && p[43-18] == ' '   &&
     922               0 :          p[45-18] == ' ' && p[48-18] == ':' && p[51-18] == ' '   &&
     923               0 :          isdigit(p[35-18]) && isdigit(p[36-18])                  &&
     924               0 :          isdigit(p[38-18]) && isdigit(p[39-18])                  &&
     925               0 :          isdigit(p[41-18]) && isdigit(p[42-18])                  &&
     926               0 :          isdigit(p[46-18]) && isdigit(p[47-18])                  &&
     927               0 :          isdigit(p[49-18]) && isdigit(p[50-18])
     928                 :       )
     929                 :       {
     930               0 :         lstyle = 'O'; /* OS/2 */
     931               0 :         if (!state->lstyle)
     932                 :         {            
     933               0 :           for (pos = 1; lstyle && pos < toklen[0]; pos++)
     934                 :           {
     935               0 :             if (!isdigit(tokens[0][pos]))
     936               0 :               lstyle = 0;
     937                 :           }
     938                 :         }
     939                 :       }
     940                 : 
     941              13 :       if (lstyle == 'O')
     942                 :       {
     943               0 :         state->parsed_one = 1;
     944               0 :         state->lstyle = lstyle;
     945                 : 
     946               0 :         p = &(line[toklen[0]]);
     947                 : 
     948               0 :         result->fe_cinfs = 1;
     949               0 :         result->fe_fname = &p[53-18];
     950               0 :         result->fe_fnlen = (&(line[linelen_sans_wsp]))
     951               0 :                            - (result->fe_fname);
     952               0 :         result->fe_type = 'f';
     953                 : 
     954                 :         /* I don't have a real listing to determine exact pos, so scan. */
     955               0 :         for (pos = (18-18); pos < ((35-18)-4); pos++)
     956                 :         {
     957               0 :           if (p[pos+0] == ' ' && p[pos+1] == 'D' && 
     958               0 :               p[pos+2] == 'I' && p[pos+3] == 'R')
     959                 :           {
     960               0 :             result->fe_type = 'd';
     961               0 :             break;
     962                 :           }
     963                 :         }
     964                 :     
     965               0 :         if (result->fe_type != 'd')
     966                 :         {
     967               0 :           pos = toklen[0];
     968               0 :           if (pos > (sizeof(result->fe_size)-1))
     969               0 :             pos = (sizeof(result->fe_size)-1);
     970               0 :           memcpy( result->fe_size, tokens[0], pos );
     971               0 :           result->fe_size[pos] = '\0';
     972                 :         }  
     973                 :     
     974               0 :         result->fe_time.tm_month = atoi(&p[35-18]) - 1;
     975               0 :         result->fe_time.tm_mday = atoi(&p[38-18]);
     976               0 :         result->fe_time.tm_year = atoi(&p[41-18]);
     977               0 :         if (result->fe_time.tm_year < 80)
     978               0 :           result->fe_time.tm_year += 100;
     979               0 :         result->fe_time.tm_hour = atoi(&p[46-18]);
     980               0 :         result->fe_time.tm_min = atoi(&p[49-18]);
     981                 :    
     982                 :         /* the caller should do this (if dropping "." and ".." is desired)
     983                 :         if (result->fe_type == 'd' && result->fe_fname[0] == '.' &&
     984                 :             (result->fe_fnlen == 1 || (result->fe_fnlen == 2 &&
     985                 :                                       result->fe_fname[1] == '.')))
     986                 :           return '?';
     987                 :         */
     988                 : 
     989               0 :         return result->fe_type;
     990                 :       } /* if (lstyle == 'O') */
     991                 : 
     992                 :     } /* if (!lstyle && (!state->lstyle || state->lstyle == 'O')) */
     993                 : #endif
     994                 : 
     995                 :     /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
     996                 :     
     997                 : #if defined(SUPPORT_LSL)
     998              30 :     if (!lstyle && (!state->lstyle || state->lstyle == 'U')) /* /bin/ls & co. */
     999                 :     {
    1000                 :       /* UNIX-style listing, without inum and without blocks
    1001                 :        * "-rw-r--r--   1 root     other        531 Jan 29 03:26 README"
    1002                 :        * "dr-xr-xr-x   2 root     other        512 Apr  8  1994 etc"
    1003                 :        * "dr-xr-xr-x   2 root     512 Apr  8  1994 etc"
    1004                 :        * "lrwxrwxrwx   1 root     other          7 Jan 25 00:17 bin -> usr/bin"
    1005                 :        * Also produced by Microsoft's FTP servers for Windows:
    1006                 :        * "----------   1 owner    group         1803128 Jul 10 10:18 ls-lR.Z"
    1007                 :        * "d---------   1 owner    group               0 May  9 19:45 Softlib"
    1008                 :        * Also WFTPD for MSDOS:
    1009                 :        * "-rwxrwxrwx   1 noone    nogroup      322 Aug 19  1996 message.ftp"
    1010                 :        * Hellsoft for NetWare:
    1011                 :        * "d[RWCEMFA] supervisor            512       Jan 16 18:53    login"
    1012                 :        * "-[RWCEMFA] rhesus             214059       Oct 20 15:27    cx.exe"
    1013                 :        * Newer Hellsoft for NetWare: (netlab2.usu.edu)
    1014                 :        * - [RWCEAFMS] NFAUUser               192 Apr 27 15:21 HEADER.html
    1015                 :        * d [RWCEAFMS] jrd                    512 Jul 11 03:01 allupdates
    1016                 :        * Also NetPresenz for the Mac:
    1017                 :        * "-------r--         326  1391972  1392298 Nov 22  1995 MegaPhone.sit"
    1018                 :        * "drwxrwxr-x               folder        2 May 10  1996 network"
    1019                 :        * Protected directory:
    1020                 :        * "drwx-wx-wt  2 root  wheel  512 Jul  1 02:15 incoming"
    1021                 :        * uid/gid instead of username/groupname:
    1022                 :        * "drwxr-xr-x  2 0  0  512 May 28 22:17 etc"
    1023                 :       */
    1024                 :     
    1025              26 :       bool is_old_Hellsoft = false;
    1026                 :     
    1027              26 :       if (numtoks >= 6)
    1028                 :       {
    1029                 :         /* there are two perm formats (Hellsoft/NetWare and *IX strmode(3)).
    1030                 :          * Scan for size column only if the perm format is one or the other.
    1031                 :          */
    1032              24 :         if (toklen[0] == 1 || (tokens[0][1]) == '[')
    1033                 :         {
    1034               8 :           if (*tokens[0] == 'd' || *tokens[0] == '-')
    1035                 :           {
    1036               4 :             pos = toklen[0]-1;
    1037               4 :             p = tokens[0] + 1;
    1038               4 :             if (pos == 0)
    1039                 :             {
    1040               2 :               p = tokens[1];
    1041               2 :               pos = toklen[1];
    1042                 :             }
    1043              24 :             if ((pos == 9 || pos == 10)        && 
    1044               4 :                 (*p == '[' && p[pos-1] == ']') &&
    1045               4 :                 (p[1] == 'R' || p[1] == '-')   &&
    1046               4 :                 (p[2] == 'W' || p[2] == '-')   &&
    1047               4 :                 (p[3] == 'C' || p[3] == '-')   &&
    1048               4 :                 (p[4] == 'E' || p[4] == '-'))
    1049                 :             {
    1050                 :               /* rest is FMA[S] or AFM[S] */
    1051               4 :               lstyle = 'U'; /* very likely one of the NetWare servers */
    1052               4 :               if (toklen[0] == 10)
    1053               2 :                 is_old_Hellsoft = true;
    1054                 :             }
    1055                 :           }
    1056                 :         }
    1057              40 :         else if ((toklen[0] == 10 || toklen[0] == 11) 
    1058              20 :                    && strchr("-bcdlpsw?DFam", *tokens[0]))
    1059                 :         {
    1060              20 :           p = &(tokens[0][1]);
    1061             148 :           if ((p[0] == 'r' || p[0] == '-') &&
    1062              20 :               (p[1] == 'w' || p[1] == '-') &&
    1063              20 :               (p[3] == 'r' || p[3] == '-') &&
    1064              32 :               (p[4] == 'w' || p[4] == '-') &&
    1065              20 :               (p[6] == 'r' || p[6] == '-') &&
    1066              36 :               (p[7] == 'w' || p[7] == '-'))
    1067                 :             /* 'x'/p[9] can be S|s|x|-|T|t or implementation specific */
    1068                 :           {
    1069              20 :             lstyle = 'U'; /* very likely /bin/ls */
    1070                 :           }
    1071                 :         }
    1072                 :       }
    1073              26 :       if (lstyle == 'U') /* first token checks out */
    1074                 :       {
    1075              24 :         lstyle = 0;
    1076              67 :         for (pos = (numtoks-5); !lstyle && pos > 1; pos--)
    1077                 :         {
    1078                 :           /* scan for: (\d+)\s+([A-Z][a-z][a-z])\s+
    1079                 :            *  (\d\d\d\d|\d\:\d\d|\d\d\:\d\d|\d\:\d\d\:\d\d|\d\d\:\d\d\:\d\d)
    1080                 :            *  \s+(.+)$
    1081                 :           */
    1082             517 :           if (isdigit(*tokens[pos]) /* size */
    1083                 :               /* (\w\w\w) */
    1084              98 :            && toklen[pos+1] == 3 && isalpha(*tokens[pos+1]) &&
    1085              48 :               isalpha(tokens[pos+1][1]) && isalpha(tokens[pos+1][2])
    1086                 :               /* (\d|\d\d) */
    1087              24 :            && isdigit(*tokens[pos+2]) &&
    1088              24 :                 (toklen[pos+2] == 1 || 
    1089              24 :                   (toklen[pos+2] == 2 && isdigit(tokens[pos+2][1])))
    1090              48 :            && toklen[pos+3] >= 4 && isdigit(*tokens[pos+3]) 
    1091                 :               /* (\d\:\d\d\:\d\d|\d\d\:\d\d\:\d\d) */
    1092              24 :            && (toklen[pos+3] <= 5 || (
    1093               0 :                (toklen[pos+3] == 7 || toklen[pos+3] == 8) &&
    1094               0 :                (tokens[pos+3][toklen[pos+3]-3]) == ':'))
    1095              24 :            && isdigit(tokens[pos+3][toklen[pos+3]-2])
    1096              24 :            && isdigit(tokens[pos+3][toklen[pos+3]-1])
    1097                 :            && (
    1098                 :               /* (\d\d\d\d) */
    1099              32 :                  ((toklen[pos+3] == 4 || toklen[pos+3] == 5) &&
    1100              24 :                   isdigit(tokens[pos+3][1]) &&
    1101              24 :                   isdigit(tokens[pos+3][2])  )
    1102                 :               /* (\d\:\d\d|\d\:\d\d\:\d\d) */
    1103              16 :               || ((toklen[pos+3] == 4 || toklen[pos+3] == 7) && 
    1104               0 :                   (tokens[pos+3][1]) == ':' &&
    1105               0 :                   isdigit(tokens[pos+3][2]) && isdigit(tokens[pos+3][3]))
    1106                 :               /* (\d\d\:\d\d|\d\d\:\d\d\:\d\d) */
    1107               8 :               || ((toklen[pos+3] == 5 || toklen[pos+3] == 8) && 
    1108              16 :                   isdigit(tokens[pos+3][1]) && (tokens[pos+3][2]) == ':' &&
    1109              16 :                   isdigit(tokens[pos+3][3]) && isdigit(tokens[pos+3][4])) 
    1110                 :               )
    1111                 :            )
    1112                 :           {
    1113              24 :             lstyle = 'U'; /* assume /bin/ls or variant format */
    1114              24 :             tokmarker = pos;
    1115                 : 
    1116                 :             /* check that size is numeric */
    1117              24 :             p = tokens[tokmarker];
    1118                 :             unsigned int i;
    1119              81 :             for (i = 0; i < toklen[tokmarker]; i++)
    1120                 :             {
    1121              57 :               if (!isdigit(*p++))
    1122                 :               {
    1123               0 :                 lstyle = 0;
    1124               0 :                 break;
    1125                 :               }
    1126                 :             }
    1127              24 :             if (lstyle)
    1128                 :             {
    1129              24 :               month_num = 0;
    1130              24 :               p = tokens[tokmarker+1];
    1131              36 :               for (i = 0; i < (12*3); i+=3)
    1132                 :               {
    1133              84 :                 if (p[0] == month_names[i+0] && 
    1134              24 :                     p[1] == month_names[i+1] && 
    1135              24 :                     p[2] == month_names[i+2])
    1136              24 :                   break;
    1137              12 :                 month_num++;
    1138                 :               }
    1139              24 :               if (month_num >= 12)
    1140               0 :                 lstyle = 0;
    1141                 :             }
    1142                 :           } /* relative position test */
    1143                 :         } /* for (pos = (numtoks-5); !lstyle && pos > 1; pos--) */
    1144                 :       } /* if (lstyle == 'U') */
    1145                 : 
    1146              26 :       if (lstyle == 'U')
    1147                 :       {
    1148              24 :         state->parsed_one = 1;
    1149              24 :         state->lstyle = lstyle;
    1150                 :     
    1151              24 :         result->fe_cinfs = 0;
    1152              24 :         result->fe_type = '?';
    1153              24 :         if (*tokens[0] == 'd' || *tokens[0] == 'l')
    1154               5 :           result->fe_type = *tokens[0];
    1155              19 :         else if (*tokens[0] == 'D')
    1156               0 :           result->fe_type = 'd';
    1157              19 :         else if (*tokens[0] == '-' || *tokens[0] == 'F')
    1158              19 :           result->fe_type = 'f'; /* (hopefully a regular file) */
    1159                 : 
    1160              24 :         if (result->fe_type != 'd')
    1161                 :         {
    1162              22 :           pos = toklen[tokmarker];
    1163              22 :           if (pos > (sizeof(result->fe_size)-1))
    1164               0 :             pos = (sizeof(result->fe_size)-1);
    1165              22 :           memcpy( result->fe_size, tokens[tokmarker], pos );
    1166              22 :           result->fe_size[pos] = '\0';
    1167                 :         }
    1168                 : 
    1169              24 :         result->fe_time.tm_month  = month_num;
    1170              24 :         result->fe_time.tm_mday = atoi(tokens[tokmarker+2]);
    1171              24 :         if (result->fe_time.tm_mday == 0)
    1172               0 :           result->fe_time.tm_mday++;
    1173                 : 
    1174              24 :         p = tokens[tokmarker+3];
    1175              24 :         pos = (unsigned int)atoi(p);
    1176              24 :         if (p[1] == ':') /* one digit hour */
    1177               0 :           p--;
    1178              24 :         if (p[2] != ':') /* year */
    1179                 :         {
    1180              16 :           result->fe_time.tm_year = pos;
    1181                 :         }
    1182                 :         else
    1183                 :         {
    1184               8 :           result->fe_time.tm_hour = pos;
    1185               8 :           result->fe_time.tm_min  = atoi(p+3);
    1186               8 :           if (p[5] == ':')
    1187               0 :             result->fe_time.tm_sec = atoi(p+6);
    1188                 :        
    1189               8 :           if (!state->now_time)
    1190                 :           {
    1191               2 :             state->now_time = PR_Now();
    1192               2 :             PR_ExplodeTime((state->now_time), PR_LocalTimeParameters, &(state->now_tm) );
    1193                 :           }
    1194                 : 
    1195               8 :           result->fe_time.tm_year = state->now_tm.tm_year;
    1196               8 :           if ( (( state->now_tm.tm_month << 5) + state->now_tm.tm_mday) <
    1197                 :                ((result->fe_time.tm_month << 5) + result->fe_time.tm_mday) )
    1198               0 :             result->fe_time.tm_year--;
    1199                 :        
    1200                 :         } /* time/year */
    1201                 :         
    1202                 :         // The length of the whole date string should be 12. On AIX the length
    1203                 :         // is only 11 when the year is present in the date string and there is
    1204                 :         // 1 padding space at the end of the string. In both cases the filename
    1205                 :         // starts at offset 13 from the start of the date string.
    1206                 :         // Don't care about leading spaces when the date string has different
    1207                 :         // format or when old Hellsoft output was detected.
    1208                 :         {
    1209              24 :           const char *date_start = tokens[tokmarker+1];
    1210              24 :           const char *date_end = tokens[tokmarker+3] + toklen[tokmarker+3];
    1211              26 :           if (!is_old_Hellsoft && ((date_end - date_start) == 12 ||
    1212               2 :               ((date_end - date_start) == 11 && date_end[1] == ' ')))
    1213              22 :             result->fe_fname = date_start + 13;
    1214                 :           else
    1215               2 :             result->fe_fname = tokens[tokmarker+4];
    1216                 :         }
    1217                 : 
    1218              24 :         result->fe_fnlen = (&(line[linelen]))
    1219              24 :                            - (result->fe_fname);
    1220                 : 
    1221              24 :         if (result->fe_type == 'l' && result->fe_fnlen > 4)
    1222                 :         {
    1223                 :           /* First try to use result->fe_size to find " -> " sequence.
    1224                 :              This can give proper result for cases like "aaa -> bbb -> ccc". */
    1225               3 :           PRUint32 fe_size = atoi(result->fe_size);
    1226                 : 
    1227               6 :           if (result->fe_fnlen > (fe_size + 4) &&
    1228               3 :               PL_strncmp(result->fe_fname + result->fe_fnlen - fe_size - 4 , " -> ", 4) == 0)
    1229                 :           {
    1230               2 :             result->fe_lname = result->fe_fname + (result->fe_fnlen - fe_size);
    1231               2 :             result->fe_lnlen = (&(line[linelen])) - (result->fe_lname);
    1232               2 :             result->fe_fnlen -= fe_size + 4;
    1233                 :           }
    1234                 :           else
    1235                 :           {
    1236                 :             /* Search for sequence " -> " from the end for case when there are
    1237                 :                more occurrences. F.e. if ftpd returns "a -> b -> c" assume
    1238                 :                "a -> b" as a name. Powerusers can remove unnecessary parts
    1239                 :                manually but there is no way to follow the link when some
    1240                 :                essential part is missing. */
    1241               1 :             p = result->fe_fname + (result->fe_fnlen - 5);
    1242               7 :             for (pos = (result->fe_fnlen - 5); pos > 0; pos--)
    1243                 :             {
    1244               7 :               if (PL_strncmp(p, " -> ", 4) == 0)
    1245                 :               {
    1246               1 :                 result->fe_lname = p + 4;
    1247               1 :                 result->fe_lnlen = (&(line[linelen]))
    1248               1 :                                  - (result->fe_lname);
    1249               1 :                 result->fe_fnlen = pos;
    1250               1 :                 break;
    1251                 :               }
    1252               6 :               p--;
    1253                 :             }
    1254                 :           }
    1255                 :         }
    1256                 : 
    1257                 : #if defined(SUPPORT_LSLF) /* some (very rare) servers return ls -lF */
    1258                 :         if (result->fe_fnlen > 1)
    1259                 :         {
    1260                 :           p = result->fe_fname[result->fe_fnlen-1];
    1261                 :           pos = result->fe_type;
    1262                 :           if (pos == 'd') { 
    1263                 :              if (*p == '/') result->fe_fnlen--; /* directory */
    1264                 :           } else if (pos == 'l') { 
    1265                 :              if (*p == '@') result->fe_fnlen--; /* symlink */
    1266                 :           } else if (pos == 'f') { 
    1267                 :              if (*p == '*') result->fe_fnlen--; /* executable */
    1268                 :           } else if (*p == '=' || *p == '%' || *p == '|') {
    1269                 :             result->fe_fnlen--; /* socket, whiteout, fifo */
    1270                 :           }
    1271                 :         }
    1272                 : #endif
    1273                 :      
    1274                 :         /* the caller should do this (if dropping "." and ".." is desired)
    1275                 :         if (result->fe_type == 'd' && result->fe_fname[0] == '.' &&
    1276                 :             (result->fe_fnlen == 1 || (result->fe_fnlen == 2 &&
    1277                 :                                       result->fe_fname[1] == '.')))
    1278                 :           return '?';
    1279                 :         */
    1280                 : 
    1281              24 :         return result->fe_type;  
    1282                 : 
    1283                 :       } /* if (lstyle == 'U') */
    1284                 : 
    1285                 :     } /* if (!lstyle && (!state->lstyle || state->lstyle == 'U')) */
    1286                 : #endif
    1287                 : 
    1288                 :     /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
    1289                 : 
    1290                 : #if defined(SUPPORT_W16) /* 16bit Windows */
    1291               6 :     if (!lstyle && (!state->lstyle || state->lstyle == 'w'))
    1292                 :     {       /* old SuperTCP suite FTP server for Win3.1 */
    1293                 :             /* old NetManage Chameleon TCP/IP suite FTP server for Win3.1 */
    1294                 :       /*
    1295                 :       * SuperTCP dirlist from the mirror.pl project
    1296                 :       * mon/day/year separator may be '/' or '-'.
    1297                 :       * .               <DIR>           11-16-94        17:16
    1298                 :       * ..              <DIR>           11-16-94        17:16
    1299                 :       * INSTALL         <DIR>           11-16-94        17:17
    1300                 :       * CMT             <DIR>           11-21-94        10:17
    1301                 :       * DESIGN1.DOC          11264      05-11-95        14:20
    1302                 :       * README.TXT            1045      05-10-95        11:01
    1303                 :       * WPKIT1.EXE          960338      06-21-95        17:01
    1304                 :       * CMT.CSV                  0      07-06-95        14:56
    1305                 :       *
    1306                 :       * Chameleon dirlist guessed from lynx
    1307                 :       * .               <DIR>      Nov 16 1994 17:16   
    1308                 :       * ..              <DIR>      Nov 16 1994 17:16   
    1309                 :       * INSTALL         <DIR>      Nov 16 1994 17:17
    1310                 :       * CMT             <DIR>      Nov 21 1994 10:17
    1311                 :       * DESIGN1.DOC     11264      May 11 1995 14:20   A
    1312                 :       * README.TXT       1045      May 10 1995 11:01
    1313                 :       * WPKIT1.EXE     960338      Jun 21 1995 17:01   R
    1314                 :       * CMT.CSV             0      Jul 06 1995 14:56   RHA
    1315                 :       */
    1316               6 :       if (numtoks >= 4 && toklen[0] < 13 && 
    1317               4 :           ((toklen[1] == 5 && *tokens[1] == '<') || isdigit(*tokens[1])) )
    1318                 :       {
    1319               6 :         if (numtoks == 4
    1320               4 :          && (toklen[2] == 8 || toklen[2] == 9)
    1321               0 :          && (((tokens[2][2]) == '/' && (tokens[2][5]) == '/') ||
    1322               0 :              ((tokens[2][2]) == '-' && (tokens[2][5]) == '-'))
    1323               0 :          && (toklen[3] == 4 || toklen[3] == 5)
    1324               0 :          && (tokens[3][toklen[3]-3]) == ':'
    1325               0 :          && isdigit(tokens[2][0]) && isdigit(tokens[2][1])
    1326               0 :          && isdigit(tokens[2][3]) && isdigit(tokens[2][4])
    1327               0 :          && isdigit(tokens[2][6]) && isdigit(tokens[2][7])
    1328               0 :          && (toklen[2] < 9 || isdigit(tokens[2][8]))
    1329               0 :          && isdigit(tokens[3][toklen[3]-1]) && isdigit(tokens[3][toklen[3]-2])
    1330               0 :          && isdigit(tokens[3][toklen[3]-4]) && isdigit(*tokens[3]) 
    1331                 :          )
    1332                 :         {
    1333               0 :           lstyle = 'w';
    1334                 :         }
    1335               2 :         else if ((numtoks == 6 || numtoks == 7)
    1336               0 :          && toklen[2] == 3 && toklen[3] == 2
    1337               0 :          && toklen[4] == 4 && toklen[5] == 5
    1338               0 :          && (tokens[5][2]) == ':'
    1339               0 :          && isalpha(tokens[2][0]) && isalpha(tokens[2][1])
    1340               0 :          &&                          isalpha(tokens[2][2])
    1341               0 :          && isdigit(tokens[3][0]) && isdigit(tokens[3][1])
    1342               0 :          && isdigit(tokens[4][0]) && isdigit(tokens[4][1])
    1343               0 :          && isdigit(tokens[4][2]) && isdigit(tokens[4][3])
    1344               0 :          && isdigit(tokens[5][0]) && isdigit(tokens[5][1])
    1345               0 :          && isdigit(tokens[5][3]) && isdigit(tokens[5][4])
    1346                 :          /* could also check that (&(tokens[5][5]) - tokens[2]) == 17 */
    1347                 :         )
    1348                 :         {
    1349               0 :           lstyle = 'w';
    1350                 :         }
    1351               2 :         if (lstyle && state->lstyle != lstyle) /* first time */
    1352                 :         {
    1353               0 :           p = tokens[1];   
    1354               0 :           if (toklen[1] != 5 || p[0] != '<' || p[1] != 'D' || 
    1355               0 :                  p[2] != 'I' || p[3] != 'R' || p[4] != '>')
    1356                 :           {
    1357               0 :             for (pos = 0; lstyle && pos < toklen[1]; pos++)
    1358                 :             {
    1359               0 :               if (!isdigit(*p++))
    1360               0 :                 lstyle = 0;
    1361                 :             }
    1362                 :           } /* not <DIR> */
    1363                 :         } /* if (first time) */
    1364                 :       } /* if (numtoks == ...) */
    1365                 : 
    1366               2 :       if (lstyle == 'w')
    1367                 :       {
    1368               0 :         state->parsed_one = 1;
    1369               0 :         state->lstyle = lstyle;
    1370                 : 
    1371               0 :         result->fe_cinfs = 1;
    1372               0 :         result->fe_fname = tokens[0];
    1373               0 :         result->fe_fnlen = toklen[0];
    1374               0 :         result->fe_type = 'd';
    1375                 : 
    1376               0 :         p = tokens[1];
    1377               0 :         if (isdigit(*p))
    1378                 :         {
    1379               0 :           result->fe_type = 'f';
    1380               0 :           pos = toklen[1];
    1381               0 :           if (pos > (sizeof(result->fe_size)-1))
    1382               0 :             pos = sizeof(result->fe_size)-1;
    1383               0 :           memcpy( result->fe_size, p, pos );
    1384               0 :           result->fe_size[pos] = '\0';
    1385                 :         }
    1386                 : 
    1387               0 :         p = tokens[2];
    1388               0 :         if (toklen[2] == 3) /* Chameleon */
    1389                 :         {
    1390               0 :           tbuf[0] = toupper(p[0]);
    1391               0 :           tbuf[1] = tolower(p[1]);
    1392               0 :           tbuf[2] = tolower(p[2]);
    1393               0 :           for (pos = 0; pos < (12*3); pos+=3)
    1394                 :           {
    1395               0 :             if (tbuf[0] == month_names[pos+0] &&
    1396               0 :                 tbuf[1] == month_names[pos+1] && 
    1397               0 :                 tbuf[2] == month_names[pos+2])
    1398                 :             {
    1399               0 :               result->fe_time.tm_month = pos/3;
    1400               0 :               result->fe_time.tm_mday = atoi(tokens[3]);
    1401               0 :               result->fe_time.tm_year = atoi(tokens[4]) - 1900;
    1402               0 :               break;
    1403                 :             }
    1404                 :           }          
    1405               0 :           pos = 5; /* Chameleon toknum of date field */
    1406                 :         }
    1407                 :         else
    1408                 :         {
    1409               0 :           result->fe_time.tm_month = atoi(p+0)-1;
    1410               0 :           result->fe_time.tm_mday = atoi(p+3);
    1411               0 :           result->fe_time.tm_year = atoi(p+6);
    1412               0 :           if (result->fe_time.tm_year < 80) /* SuperTCP */
    1413               0 :             result->fe_time.tm_year += 100;
    1414                 : 
    1415               0 :           pos = 3; /* SuperTCP toknum of date field */
    1416                 :         }
    1417                 : 
    1418               0 :         result->fe_time.tm_hour = atoi(tokens[pos]);
    1419               0 :         result->fe_time.tm_min = atoi(&(tokens[pos][toklen[pos]-2]));
    1420                 : 
    1421                 :         /* the caller should do this (if dropping "." and ".." is desired)
    1422                 :         if (result->fe_type == 'd' && result->fe_fname[0] == '.' &&
    1423                 :             (result->fe_fnlen == 1 || (result->fe_fnlen == 2 &&
    1424                 :                                       result->fe_fname[1] == '.')))
    1425                 :           return '?';
    1426                 :         */
    1427                 : 
    1428               0 :         return result->fe_type;
    1429                 :       } /* (lstyle == 'w') */
    1430                 : 
    1431                 :     } /* if (!lstyle && (!state->lstyle || state->lstyle == 'w'))  */
    1432                 : #endif
    1433                 : 
    1434                 :     /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
    1435                 : 
    1436                 : #if defined(SUPPORT_DLS) /* dls -dtR */
    1437              12 :     if (!lstyle && 
    1438               6 :        (state->lstyle == 'D' || (!state->lstyle && state->numlines == 1)))
    1439                 :        /* /bin/dls lines have to be immediately recognizable (first line) */
    1440                 :     {
    1441                 :       /* I haven't seen an FTP server that delivers a /bin/dls listing,
    1442                 :        * but can infer the format from the lynx and mirror.pl projects.
    1443                 :        * Both formats are supported.
    1444                 :        *
    1445                 :        * Lynx says:
    1446                 :        * README              763  Information about this server\0
    1447                 :        * bin/                  -  \0
    1448                 :        * etc/                  =  \0
    1449                 :        * ls-lR                 0  \0
    1450                 :        * ls-lR.Z               3  \0
    1451                 :        * pub/                  =  Public area\0
    1452                 :        * usr/                  -  \0
    1453                 :        * morgan               14  -> ../real/morgan\0
    1454                 :        * TIMIT.mostlikely.Z\0
    1455                 :        *                   79215  \0
    1456                 :        *
    1457                 :        * mirror.pl says:
    1458                 :        * filename:  ^(\S*)\s+
    1459                 :        * size:      (\-|\=|\d+)\s+
    1460                 :        * month/day: ((\w\w\w\s+\d+|\d+\s+\w\w\w)\s+
    1461                 :        * time/year: (\d+:\d+|\d\d\d\d))\s+
    1462                 :        * rest:      (.+) 
    1463                 :        *
    1464                 :        * README              763  Jul 11 21:05  Information about this server
    1465                 :        * bin/                  -  Apr 28  1994
    1466                 :        * etc/                  =  11 Jul 21:04
    1467                 :        * ls-lR                 0   6 Aug 17:14
    1468                 :        * ls-lR.Z               3  05 Sep 1994
    1469                 :        * pub/                  =  Jul 11 21:04  Public area
    1470                 :        * usr/                  -  Sep  7 09:39
    1471                 :        * morgan               14  Apr 18 09:39  -> ../real/morgan
    1472                 :        * TIMIT.mostlikely.Z
    1473                 :        *                   79215  Jul 11 21:04
    1474                 :       */
    1475               1 :       if (!state->lstyle && line[linelen-1] == ':' && 
    1476               0 :           linelen >= 2 && toklen[numtoks-1] != 1)
    1477                 :       { 
    1478                 :         /* code in mirror.pl suggests that a listing may be preceded
    1479                 :          * by a PWD line in the form "/some/dir/names/here:"
    1480                 :          * but does not necessarily begin with '/'. *sigh*
    1481                 :         */
    1482               0 :         pos = 0;
    1483               0 :         p = line;
    1484               0 :         while (pos < (linelen-1))
    1485                 :         {
    1486                 :           /* illegal (or extremely unusual) chars in a dirspec */
    1487               0 :           if (*p == '<' || *p == '|' || *p == '>' ||
    1488                 :               *p == '?' || *p == '*' || *p == '\\')
    1489               0 :             break;
    1490               0 :           if (*p == '/' && pos < (linelen-2) && p[1] == '/')
    1491               0 :             break;
    1492               0 :           pos++;
    1493               0 :           p++;
    1494                 :         }
    1495               0 :         if (pos == (linelen-1))
    1496                 :         {
    1497               0 :           state->lstyle = 'D';
    1498               0 :           return '?';
    1499                 :         }
    1500                 :       }
    1501                 : 
    1502               1 :       if (!lstyle && numtoks >= 2)
    1503                 :       {
    1504               1 :         pos = 22; /* pos of (\d+|-|=) if this is not part of a multiline */
    1505               1 :         if (state->lstyle && carry_buf_len) /* first is from previous line */
    1506               0 :           pos = toklen[1]-1; /* and is 'as-is' (may contain whitespace) */
    1507                 : 
    1508               1 :         if (linelen > pos)
    1509                 :         {
    1510               1 :           p = &line[pos];
    1511               2 :           if ((*p == '-' || *p == '=' || isdigit(*p)) &&
    1512                 :               ((linelen == (pos+1)) || 
    1513               1 :                (linelen >= (pos+3) && p[1] == ' ' && p[2] == ' ')) )
    1514                 :           {
    1515               0 :             tokmarker = 1;
    1516               0 :             if (!carry_buf_len)
    1517                 :             {
    1518               0 :               pos = 1;
    1519               0 :               while (pos < numtoks && (tokens[pos]+toklen[pos]) < (&line[23]))
    1520               0 :                 pos++;
    1521               0 :               tokmarker = 0;
    1522               0 :               if ((tokens[pos]+toklen[pos]) == (&line[23]))
    1523               0 :                 tokmarker = pos;
    1524                 :             }
    1525               0 :             if (tokmarker)  
    1526                 :             {
    1527               0 :               lstyle = 'D';
    1528               0 :               if (*tokens[tokmarker] == '-' || *tokens[tokmarker] == '=')
    1529                 :               {
    1530               0 :                 if (toklen[tokmarker] != 1 ||
    1531               0 :                    (tokens[tokmarker-1][toklen[tokmarker-1]-1]) != '/')
    1532               0 :                   lstyle = 0;
    1533                 :               }              
    1534                 :               else
    1535                 :               {
    1536               0 :                 for (pos = 0; lstyle && pos < toklen[tokmarker]; pos++) 
    1537                 :                 {
    1538               0 :                   if (!isdigit(tokens[tokmarker][pos]))
    1539               0 :                     lstyle = 0; 
    1540                 :                 }
    1541                 :               }
    1542               0 :               if (lstyle && !state->lstyle) /* first time */
    1543                 :               {
    1544                 :                 /* scan for illegal (or incredibly unusual) chars in fname */
    1545               0 :                 for (p = tokens[0]; lstyle &&
    1546               0 :                      p < &(tokens[tokmarker-1][toklen[tokmarker-1]]); p++)
    1547                 :                 {
    1548               0 :                   if (*p == '<' || *p == '|' || *p == '>' || 
    1549                 :                       *p == '?' || *p == '*' || *p == '/' || *p == '\\')
    1550               0 :                     lstyle = 0;
    1551                 :                 }
    1552                 :               }
    1553                 : 
    1554                 :             } /* size token found */
    1555                 :           } /* expected chars behind expected size token */
    1556                 :         } /* if (linelen > pos) */
    1557                 :       } /* if (!lstyle && numtoks >= 2) */
    1558                 : 
    1559               1 :       if (!lstyle && state->lstyle == 'D' && !carry_buf_len)
    1560                 :       {
    1561                 :         /* the filename of a multi-line entry can be identified
    1562                 :          * correctly only if dls format had been previously established.
    1563                 :          * This should always be true because there should be entries
    1564                 :          * for '.' and/or '..' and/or CWD that precede the rest of the
    1565                 :          * listing.
    1566                 :         */
    1567               0 :         pos = linelen;
    1568               0 :         if (pos > (sizeof(state->carry_buf)-1))
    1569               0 :           pos = sizeof(state->carry_buf)-1;
    1570               0 :         memcpy( state->carry_buf, line, pos );
    1571               0 :         state->carry_buf_len = pos;
    1572               0 :         return '?';
    1573                 :       }
    1574                 : 
    1575               1 :       if (lstyle == 'D')
    1576                 :       {
    1577               0 :         state->parsed_one = 1;
    1578               0 :         state->lstyle = lstyle;
    1579                 : 
    1580               0 :         p = &(tokens[tokmarker-1][toklen[tokmarker-1]]);
    1581               0 :         result->fe_fname = tokens[0];
    1582               0 :         result->fe_fnlen = p - tokens[0];
    1583               0 :         result->fe_type  = 'f';
    1584                 : 
    1585               0 :         if (result->fe_fname[result->fe_fnlen-1] == '/')
    1586                 :         {
    1587               0 :           if (result->fe_lnlen == 1)
    1588               0 :             result->fe_type = '?';
    1589                 :           else
    1590                 :           {
    1591               0 :             result->fe_fnlen--;
    1592               0 :             result->fe_type  = 'd';
    1593                 :           }
    1594                 :         }
    1595               0 :         else if (isdigit(*tokens[tokmarker]))
    1596                 :         {
    1597               0 :           pos = toklen[tokmarker];
    1598               0 :           if (pos > (sizeof(result->fe_size)-1))
    1599               0 :             pos = sizeof(result->fe_size)-1;
    1600               0 :           memcpy( result->fe_size, tokens[tokmarker], pos );
    1601               0 :           result->fe_size[pos] = '\0';
    1602                 :         }
    1603                 : 
    1604               0 :         if ((tokmarker+3) < numtoks && 
    1605               0 :               (&(tokens[numtoks-1][toklen[numtoks-1]]) - 
    1606               0 :                tokens[tokmarker+1]) >= (1+1+3+1+4) )
    1607                 :         {
    1608               0 :           pos = (tokmarker+3);
    1609               0 :           p = tokens[pos];
    1610               0 :           pos = toklen[pos];
    1611                 : 
    1612               0 :           if ((pos == 4 || pos == 5)
    1613               0 :           &&  isdigit(*p) && isdigit(p[pos-1]) && isdigit(p[pos-2])
    1614               0 :           &&  ((pos == 5 && p[2] == ':') ||  
    1615               0 :                (pos == 4 && (isdigit(p[1]) || p[1] == ':')))
    1616                 :              )
    1617                 :           {
    1618               0 :             month_num = tokmarker+1; /* assumed position of month field */
    1619               0 :             pos = tokmarker+2;       /* assumed position of mday field */
    1620               0 :             if (isdigit(*tokens[month_num])) /* positions are reversed */
    1621                 :             {
    1622               0 :               month_num++;
    1623               0 :               pos--;
    1624                 :             }
    1625               0 :             p = tokens[month_num];
    1626               0 :             if (isdigit(*tokens[pos]) 
    1627               0 :             && (toklen[pos] == 1 || 
    1628               0 :                   (toklen[pos] == 2 && isdigit(tokens[pos][1])))
    1629               0 :             && toklen[month_num] == 3
    1630               0 :             && isalpha(*p) && isalpha(p[1]) && isalpha(p[2])  )
    1631                 :             {
    1632               0 :               pos = atoi(tokens[pos]);
    1633               0 :               if (pos > 0 && pos <= 31)
    1634                 :               {
    1635               0 :                 result->fe_time.tm_mday = pos;
    1636               0 :                 month_num = 1;
    1637               0 :                 for (pos = 0; pos < (12*3); pos+=3)
    1638                 :                 {
    1639               0 :                   if (p[0] == month_names[pos+0] &&
    1640               0 :                       p[1] == month_names[pos+1] &&
    1641               0 :                       p[2] == month_names[pos+2])
    1642               0 :                     break;
    1643               0 :                   month_num++;
    1644                 :                 }
    1645               0 :                 if (month_num > 12)
    1646               0 :                   result->fe_time.tm_mday = 0;
    1647                 :                 else
    1648               0 :                   result->fe_time.tm_month = month_num - 1;
    1649                 :               }
    1650                 :             }
    1651               0 :             if (result->fe_time.tm_mday)
    1652                 :             {
    1653               0 :               tokmarker += 3; /* skip mday/mon/yrtime (to find " -> ") */
    1654               0 :               p = tokens[tokmarker];
    1655                 : 
    1656               0 :               pos = atoi(p);
    1657               0 :               if (pos > 24)
    1658               0 :                 result->fe_time.tm_year = pos-1900;
    1659                 :               else
    1660                 :               {
    1661               0 :                 if (p[1] == ':')
    1662               0 :                   p--;
    1663               0 :                 result->fe_time.tm_hour = pos;
    1664               0 :                 result->fe_time.tm_min = atoi(p+3);
    1665               0 :                 if (!state->now_time)
    1666                 :                 {
    1667               0 :                   state->now_time = PR_Now();
    1668               0 :                   PR_ExplodeTime((state->now_time), PR_LocalTimeParameters, &(state->now_tm) );
    1669                 :                 }
    1670               0 :                 result->fe_time.tm_year = state->now_tm.tm_year;
    1671               0 :                 if ( (( state->now_tm.tm_month  << 4) + state->now_tm.tm_mday) <
    1672                 :                      ((result->fe_time.tm_month << 4) + result->fe_time.tm_mday) )
    1673               0 :                   result->fe_time.tm_year--;
    1674                 :               } /* got year or time */
    1675                 :             } /* got month/mday */
    1676                 :           } /* may have year or time */
    1677                 :         } /* enough remaining to possibly have date/time */
    1678                 : 
    1679               0 :         if (numtoks > (tokmarker+2))
    1680                 :         {
    1681               0 :           pos = tokmarker+1;
    1682               0 :           p = tokens[pos];
    1683               0 :           if (toklen[pos] == 2 && *p == '-' && p[1] == '>')
    1684                 :           {
    1685               0 :             p = &(tokens[numtoks-1][toklen[numtoks-1]]);
    1686               0 :             result->fe_type  = 'l';
    1687               0 :             result->fe_lname = tokens[pos+1];
    1688               0 :             result->fe_lnlen = p - result->fe_lname;
    1689               0 :             if (result->fe_lnlen > 1 &&
    1690               0 :                 result->fe_lname[result->fe_lnlen-1] == '/')
    1691               0 :               result->fe_lnlen--;
    1692                 :           }
    1693                 :         } /* if (numtoks > (tokmarker+2)) */
    1694                 : 
    1695                 :         /* the caller should do this (if dropping "." and ".." is desired)
    1696                 :         if (result->fe_type == 'd' && result->fe_fname[0] == '.' &&
    1697                 :             (result->fe_fnlen == 1 || (result->fe_fnlen == 2 &&
    1698                 :                                       result->fe_fname[1] == '.')))
    1699                 :           return '?';
    1700                 :         */
    1701                 : 
    1702               0 :         return result->fe_type;
    1703                 : 
    1704                 :       } /* if (lstyle == 'D') */
    1705                 :     } /* if (!lstyle && (!state->lstyle || state->lstyle == 'D')) */
    1706                 : #endif
    1707                 : 
    1708                 :     /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
    1709                 : 
    1710                 :   } /* if (linelen > 0) */
    1711                 : 
    1712               6 :   return ParsingFailed(state);
    1713                 : }
    1714                 : 
    1715                 : /* ==================================================================== */
    1716                 : /* standalone testing                                                   */
    1717                 : /* ==================================================================== */
    1718                 : #if 0
    1719                 : 
    1720                 : #include <stdio.h>
    1721                 : 
    1722                 : static int do_it(FILE *outfile, 
    1723                 :                  char *line, size_t linelen, struct list_state *state,
    1724                 :                  char **cmnt_buf, unsigned int *cmnt_buf_sz,
    1725                 :                  char **list_buf, unsigned int *list_buf_sz )
    1726                 : {
    1727                 :   struct list_result result;
    1728                 :   char *p;
    1729                 :   int rc;
    1730                 : 
    1731                 :   rc = ParseFTPList( line, state, &result );
    1732                 : 
    1733                 :   if (!outfile)
    1734                 :   {
    1735                 :     outfile = stdout;
    1736                 :     if (rc == '?')
    1737                 :       fprintf(outfile, "junk: %.*s\n", (int)linelen, line );
    1738                 :     else if (rc == '"')
    1739                 :       fprintf(outfile, "cmnt: %.*s\n", (int)linelen, line );
    1740                 :     else
    1741                 :       fprintf(outfile, 
    1742                 :               "list: %02u-%02u-%02u  %02u:%02u%cM %20s %.*s%s%.*s\n",
    1743                 :               (result.fe_time.tm_mday ? (result.fe_time.tm_month + 1) : 0),
    1744                 :               result.fe_time.tm_mday,
    1745                 :               (result.fe_time.tm_mday ? (result.fe_time.tm_year % 100) : 0),
    1746                 :               result.fe_time.tm_hour - 
    1747                 :                 ((result.fe_time.tm_hour > 12)?(12):(0)),
    1748                 :               result.fe_time.tm_min,
    1749                 :               ((result.fe_time.tm_hour >= 12) ? 'P' : 'A'),
    1750                 :               (rc == 'd' ? "<DIR>         " : 
    1751                 :               (rc == 'l' ? "<JUNCTION>    " : result.fe_size)),
    1752                 :               (int)result.fe_fnlen, result.fe_fname,
    1753                 :               ((rc == 'l' && result.fe_lnlen) ? " -> " : ""),
    1754                 :               (int)((rc == 'l' && result.fe_lnlen) ? result.fe_lnlen : 0),
    1755                 :               ((rc == 'l' && result.fe_lnlen) ? result.fe_lname : "") );
    1756                 :   }
    1757                 :   else if (rc != '?') /* NOT junk */
    1758                 :   { 
    1759                 :     char **bufp = list_buf;
    1760                 :     unsigned int *bufz = list_buf_sz;
    1761                 :     
    1762                 :     if (rc == '"') /* comment - make it a 'result' */
    1763                 :     {
    1764                 :       memset( &result, 0, sizeof(result));
    1765                 :       result.fe_fname = line;
    1766                 :       result.fe_fnlen = linelen;
    1767                 :       result.fe_type = 'f';
    1768                 :       if (line[linelen-1] == '/')
    1769                 :       {
    1770                 :         result.fe_type = 'd';
    1771                 :         result.fe_fnlen--; 
    1772                 :       }
    1773                 :       bufp = cmnt_buf;
    1774                 :       bufz = cmnt_buf_sz;
    1775                 :       rc = result.fe_type;
    1776                 :     }  
    1777                 : 
    1778                 :     linelen = 80 + result.fe_fnlen + result.fe_lnlen;
    1779                 :     p = (char *)realloc( *bufp, *bufz + linelen );
    1780                 :     if (!p)
    1781                 :       return -1;
    1782                 :     sprintf( &p[*bufz], 
    1783                 :              "%02u-%02u-%04u  %02u:%02u:%02u %20s %.*s%s%.*s\n",
    1784                 :               (result.fe_time.tm_mday ? (result.fe_time.tm_month + 1) : 0),
    1785                 :               result.fe_time.tm_mday,
    1786                 :               (result.fe_time.tm_mday ? (result.fe_time.tm_year + 1900) : 0),
    1787                 :               result.fe_time.tm_hour,
    1788                 :               result.fe_time.tm_min,
    1789                 :               result.fe_time.tm_sec,
    1790                 :               (rc == 'd' ? "<DIR>         " : 
    1791                 :               (rc == 'l' ? "<JUNCTION>    " : result.fe_size)),
    1792                 :               (int)result.fe_fnlen, result.fe_fname,
    1793                 :               ((rc == 'l' && result.fe_lnlen) ? " -> " : ""),
    1794                 :               (int)((rc == 'l' && result.fe_lnlen) ? result.fe_lnlen : 0),
    1795                 :               ((rc == 'l' && result.fe_lnlen) ? result.fe_lname : "") );
    1796                 :     linelen = strlen(&p[*bufz]);
    1797                 :     *bufp = p;
    1798                 :     *bufz = *bufz + linelen;
    1799                 :   }
    1800                 :   return 0;
    1801                 : }
    1802                 : 
    1803                 : int main(int argc, char *argv[])
    1804                 : {
    1805                 :   FILE *infile = (FILE *)0;
    1806                 :   FILE *outfile = (FILE *)0;
    1807                 :   int need_close_in = 0;
    1808                 :   int need_close_out = 0;
    1809                 : 
    1810                 :   if (argc > 1)
    1811                 :   {
    1812                 :     infile = stdin;
    1813                 :     if (strcmp(argv[1], "-") == 0)
    1814                 :       need_close_in = 0;
    1815                 :     else if ((infile = fopen(argv[1], "r")) != ((FILE *)0))
    1816                 :       need_close_in = 1;
    1817                 :     else
    1818                 :       fprintf(stderr, "Unable to open input file '%s'\n", argv[1]);
    1819                 :   }
    1820                 :   if (infile && argc > 2)
    1821                 :   {
    1822                 :     outfile = stdout;
    1823                 :     if (strcmp(argv[2], "-") == 0)
    1824                 :       need_close_out = 0;
    1825                 :     else if ((outfile = fopen(argv[2], "w")) != ((FILE *)0))
    1826                 :       need_close_out = 1;
    1827                 :     else
    1828                 :     {
    1829                 :       fprintf(stderr, "Unable to open output file '%s'\n", argv[2]);
    1830                 :       fclose(infile);
    1831                 :       infile = (FILE *)0;
    1832                 :     }
    1833                 :   }
    1834                 : 
    1835                 :   if (!infile)
    1836                 :   {
    1837                 :     char *appname = &(argv[0][strlen(argv[0])]);
    1838                 :     while (appname > argv[0])
    1839                 :     {
    1840                 :       appname--;
    1841                 :       if (*appname == '/' || *appname == '\\' || *appname == ':')
    1842                 :       {
    1843                 :         appname++;
    1844                 :         break;
    1845                 :       } 
    1846                 :     }
    1847                 :     fprintf(stderr, 
    1848                 :         "Usage: %s <inputfilename> [<outputfilename>]\n"
    1849                 :         "\nIf an outout file is specified the results will be"
    1850                 :         "\nbe post-processed, and only the file entries will appear"
    1851                 :         "\n(or all comments if there are no file entries)."
    1852                 :         "\nNot specifying an output file causes %s to run in \"debug\""
    1853                 :         "\nmode, ie results are printed as lines are parsed."
    1854                 :         "\nIf a filename is a single dash ('-'), stdin/stdout is used."
    1855                 :         "\n", appname, appname );
    1856                 :   }
    1857                 :   else
    1858                 :   {
    1859                 :     char *cmnt_buf = (char *)0;
    1860                 :     unsigned int cmnt_buf_sz = 0;
    1861                 :     char *list_buf = (char *)0;
    1862                 :     unsigned int list_buf_sz = 0;
    1863                 : 
    1864                 :     struct list_state state;
    1865                 :     char line[512];
    1866                 : 
    1867                 :     memset( &state, 0, sizeof(state) );
    1868                 :     while (fgets(line, sizeof(line), infile))
    1869                 :     {
    1870                 :       size_t linelen = strlen(line);
    1871                 :       if (linelen < (sizeof(line)-1))
    1872                 :       {
    1873                 :         if (linelen > 0 && line[linelen-1] == '\n')
    1874                 :           linelen--;
    1875                 :         if (do_it( outfile, line, linelen, &state, 
    1876                 :                    &cmnt_buf, &cmnt_buf_sz, &list_buf, &list_buf_sz) != 0)
    1877                 :         {
    1878                 :           fprintf(stderr, "Insufficient memory. Listing may be incomplete.\n"); 
    1879                 :           break;
    1880                 :         }
    1881                 :       }
    1882                 :       else
    1883                 :       {
    1884                 :         /* no '\n' found. drop this and everything up to the next '\n' */
    1885                 :         fprintf(stderr, "drop: %.*s", (int)linelen, line );
    1886                 :         while (linelen == sizeof(line))
    1887                 :         {
    1888                 :           if (!fgets(line, sizeof(line), infile))
    1889                 :             break;
    1890                 :           linelen = 0;
    1891                 :           while (linelen < sizeof(line) && line[linelen] != '\n')
    1892                 :             linelen++;
    1893                 :           fprintf(stderr, "%.*s", (int)linelen, line );
    1894                 :         }  
    1895                 :         fprintf(stderr, "\n");
    1896                 :       }
    1897                 :     }
    1898                 :     if (outfile)
    1899                 :     {
    1900                 :       if (list_buf)
    1901                 :         fwrite( list_buf, 1, list_buf_sz, outfile );
    1902                 :       else if (cmnt_buf)
    1903                 :         fwrite( cmnt_buf, 1, cmnt_buf_sz, outfile );
    1904                 :     }
    1905                 :     if (list_buf) 
    1906                 :       free(list_buf);
    1907                 :     if (cmnt_buf)
    1908                 :       free(cmnt_buf);
    1909                 : 
    1910                 :     if (need_close_in)
    1911                 :       fclose(infile);
    1912                 :     if (outfile && need_close_out)
    1913                 :       fclose(outfile);
    1914                 :   }
    1915                 : 
    1916                 :   return 0;
    1917                 : }
    1918                 : #endif

Generated by: LCOV version 1.7