'''Routines to guess information about files by their names

Copyright 1998-1999 by Daniel Fandrich <dan@fch.wimsey.bc.ca>

$Id: classifyfile.py,v 1.4 2002/05/14 05:32:01 dan Exp $
'''
# $Log: classifyfile.py,v $
# Revision 1.4  2002/05/14 05:32:01  dan
# Added a few more documentation files.
#
# Revision 1.3  1999/02/26 07:29:08  dan
# Fixed .* and added *.rsc to config file types.  Made dirprefix more robust.
#
# Revision 1.2  1998/07/14 22:57:03  dan
# Added __version__. Added dirprefix(). Improved lookslikedir().
# 
# Revision 1.1  1998/07/07 17:47:49  dan
# Initial revision
# 

#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2, or (at your option)
#  any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

import regex
import posixpath
from string import rfind

RCSrevision = "$Revision: 1.4 $"
__version__ = RCSrevision[11:-2]

# File names that look like configuration files
config_re = regex.compile(
		'etc/\|'	# anything in /etc/
		'app-defaults/\|'
		'config/\|'
		'/\.[^/]\|'	# any file starting with .
		'[^/]rc$\|'
		'\.rsc$\|'
		'\.cf$\|'
		'\.config$\|'
		'\.conf$\|'
		'\.ctl$\|'
		'\log$\|'
		'\.score$\|'
		'_score$\|'
		'scores$\|'
		'[uw]tmp$\|'

		# specific files from popular packages
		#  that don't match above
		'/news/mailname$\|'
		'/news/organization$\|'
		'/news/active$\|'
		'/news/moderators$\|'
		'/news/newsfeeds$\|'
		'/news/newsgroups$\|'
		'/news/nnrp.access$\|'
		'/news/passwd.nntp$\|'
		'/news/hosts.nntp$\|'
		'/news/overview.fmt$\|'
		'/news/distrib.pats$\|'
		'/news/innshellvars$\|'
		'/trn/INIT$\|'
		'/lib/aliases$\|'	# sendmail/smail
		'/smail/maps/\|'
		'/smail/methods/\|'
		'/smail/config$\|'
		'/smail/directors$\|'
		'/smail/forward$\|'
		'/smail/routers$\|'
		'/smail/transports$\|'
		'/Fontmap$\|'		# ghostscript
		'/ftpd/msgs/'
	    )

# File names and paths that ARE NOT configuration files despite
# matching one of the above patterns
not_config_re = regex.compile(
		'/samples/\|'
		'/README\|'
		'/dialog$\|'
		'/readlog$\|'
		'/rlog$\|'
		'/savelog$\|'
		'/sendlog$\|'
		'/writelog$\|'
		'\.depend$\|'
	   	'\.arc$\|'
	   	'/arc$\|'
		'\.src$\|'
	   	'/src$\|'
	   	'/irc$\|'
	   	'/brc$\|'
	   	'/lharc$\|'
		'dev/log$\|'
		'[Cc]hangelog$\|'
	   	'catalog$'
		)

def lookslikeconfigfile(fn):
	'Return true when filename looks like a configuration file'
	if config_re.search(fn) >= 0:
		if not not_config_re.search(fn) >= 0:
			return 1
	return None


# File names that look like documentation files
doc_re = regex.compile(
		'/docs?/\|'
		'/info/\|'
		'/man/\|'
		'COPYING\|'
		'Copyright\|'
		'README'
	  )

def lookslikedocfile(fn):
	'Return true when filename looks like a documentation file'
	if doc_re.search(fn) >= 0:
		return 1
	return None

def lookslikedir(fn):
	'Return true when filename looks like a directory'
	return fn[-1] == '/' or fn[-2:] == '/.' or fn[-3:] == '/..'

# pattern to match a version string like 'ver. 4.2.0'
ver_pat = (
		'\(<ver>[0-9][0-9.-]*\)' 	# version number
		'\(\(pl\(<pl>[0-9]+\)\)'	# patchlevel
		  '\|\(<suffix>[a-z]\)?\)'	# or letter suffix
	)

ver_re = []	# list of regular expressions
ver_re.append( regex.symcomp(
		'\(v\(er\(sion\)\)?\).?'	# ver with opt. period
		' *'				# whitespace
		+ ver_pat
		, regex.casefold
	))
ver_re.append( regex.symcomp(
		'('			# surrounded by parens.
		+ ver_pat +
		')'			# surrounded by parens.
		, regex.casefold
	))
ver_re.append( regex.symcomp(
		ver_pat +
		'$'			# number at end of line
		, regex.casefold
	))
ver_re.append( regex.symcomp(
		' '			# whitespace before
		+ ver_pat +
		' '			# whitespace after
		, regex.casefold
	))
ver_re.append( regex.symcomp(
		'[,(-]'			# punctuation before
			+ ver_pat +
			'[,)-]'			# punctuation after
			, regex.casefold
		))

def extractver(st):
	'''Try to extract a version number out of the given string

	e.g. 'Foobar utility ver. 1.3c' => '1.3c'
	     'Flooby utility (1.3pl25)' => '1.3.25'
	     'util-1.5b' => '1.5b'
	'''
	for re in ver_re:
		'Try all regexes to find a version number'
		if re.search(st) >= 0:
			# found a match
			ver = re.group('ver')
			if ver:
				if re.group('suffix'):
					ver = ver + re.group('suffix')
				elif re.group('pl'):
					ver = ver + '.' + re.group('pl')
				if ver[-1] == '.':
					# remove trailing period
					ver = ver[:-1]
				return ver
	return ''	# couldn't find a version number

def dirprefix(filelist):
	'''Find elements of path common to all files in list
	input: list of absolute path names
	output: directories common to all paths
	'''
	prefix = '/'
	maxmatch = len(posixpath.commonprefix(filelist))
	if maxmatch > 0 and len(filelist) >= 2:
		samplename = filelist[0]
		# Search for a file longer than maxmatch characters
		for f in filelist:
			if len(f) > maxmatch:
				break
		if len(f) <= maxmatch or f[maxmatch] != '/':
			# reduce match to include complete directory names only
			maxmatch = rfind(samplename[:maxmatch], '/')
			if maxmatch <= 0:
				maxmatch = 1	# include the initial '/', but not the last
		if samplename[0] == '/':
			# leading '/' is already part of path
			prefix = ''
		prefix = prefix + samplename[:maxmatch]
	return prefix

