netwerk/streamconv/converters/ParseFTPList.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial