diff --git a/README.md b/README.md index 980d4c3..c1d8102 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ By default, each time you save a `bindzone` file, the script will look for the D Patterns -------- -In order to be detected, the DNS serial number must match the following pattern: +In order to be detected, the DNS serial number must match one the following pattern: * `YYYYMMDDXX ; serial` - `YYYY` is the year (4 digits); @@ -38,8 +38,65 @@ In order to be detected, the DNS serial number must match the following pattern: - the word `serial` is not case-sensitive; - there can be any number of blanks on each sides of the semicolon. +* `XX ; serial` + - `XX` is any non-negative number (1 or more digits); + - the word `serial` is not case-sensitive; + - there can be any number of blanks on each sides of the semicolon. + Configuration ------------- -You can turn off the automatic serial update by setting `let g:dnsserial_auto_update = 0` in your vimrc. +You can set several configuration variables in your vimrc: + +* `g:dnsserial_auto_update`: Defines whether or not the serial is updated when the zone file is saved (default is 1, set it to 0 to disable). +* `g:dnsserial_custom_patterns`: List of customs patterns that will be added to the default ones. Order matters, the first matching patters will be used. Customs patterns will be tested before the default ones. +* `g:dnsserial_patterns`: List of default patterns. It is not advised to change it. + + +Custom patterns +--------------- + +A pattern is defined by a dictionary with two keys: `regex` and `matching`. + +**regex** + +Contains the regular expression that will be used to search the document for the serial number. All the components of the serial number must be captured with parenthesis. + +**matching** + +This is a list of every components of the serial number. Each component is defined by a dictionary. The `type` key must be present and contain one of the allowed types. Depending on the type, several additional keys might be defined. Authorized types and their options are: + +* `raw`: Raw string. +* `integer`: An integer that will be incremented. +- `offset` (int): set the offset by which the integer is incremented. Default is 1. +- `padding` (int): Force the integer to be 0-padded on the associated number of digits. +- `date_reset` (bool): If set to 1 and a the serial contains a `date`, the integer will be reseted to 0 if the date is updated. Default is 0. +* `date`: A formated date that will be updated to the current one. +- `fmt` (string, mandatory) : the date format according to the `strftime()` specifications. See `:help strftime` for more details. + +**examples** + +A simple pattern matching a serial defined as an integer and followed by a comment starting by the word `serial` is: + +```json +{ + 'regex': '\(\d\+\)\s*;\s*\cserial', + 'matching': [ + {'type': 'integer'} + ] +} +``` + +The same example, but having the serial number starting by the current date (YYYYMMDD) and the integer padded on two digits: + + +```json +{ + 'regex': '\(\d\{8}\)\(\d\+\)\s*;\s*\cserial', + 'matching': [ + {'type': 'date', 'fmt': '%Y%m%d'}, + {'type': 'integer', 'padding': 2, 'date_reset': 1} + ] +} +``` diff --git a/autoload/dnsserial.vim b/autoload/dnsserial.vim index c72b448..15cca4c 100644 --- a/autoload/dnsserial.vim +++ b/autoload/dnsserial.vim @@ -12,28 +12,59 @@ " See the License for the specific language governing permissions and " limitations under the License. -function! s:IncrementSerial(old_date, old_nb) - let curr_date = strftime("%Y%m%d") - if a:old_date ==? curr_date - let curr_nb = a:old_nb + 1 - if curr_nb < 10 - let curr_nb = "0".curr_nb + +function! s:HasDateChanged(pattern, old_matchlist) + let i = 0 + for matching in a:pattern.matching + if matching.type ==? 'date' + let old_date = a:old_matchlist[i] + let new_date = strftime(matching.fmt) + if old_date !=? new_date + return 1 + endif endif - else - let curr_nb = "01" + let i += 1 + endfor + return 0 +endfunction + +function! s:GetNewValue(matching, old_value, date_changed) + if a:matching.type ==? 'date' + return strftime(a:matching.fmt) + elseif a:matching.type ==? 'integer' + let nb = a:old_value + get(a:matching, 'offset', 1) + if a:date_changed && get(a:matching, 'date_reset', 0) + let nb = 0 + endif + return printf('%0' . get(a:matching, 'padding', 1) . 'd', nb) endif - return curr_date.curr_nb + return a:old_value +endfunction + +function! s:GetNewSerial(pattern, old_matchlist) + let date_changed = s:HasDateChanged(a:pattern, a:old_matchlist) + let new_serial = [] + let i = 0 + for matching in a:pattern.matching + let new_value = s:GetNewValue(matching, a:old_matchlist[i], date_changed) + call add(new_serial, new_value) + let i += 1 + endfor + return join(new_serial, '') endfunction function! dnsserial#DNSSerialUpdate() - let pattern = '\(\d\{8}\)\(\d\+\)\s*;\s*\cserial' - if search(pattern) == 0 - echom "No serial found." - return 0 - endif - let old_pattern = matchlist(getline('.'), pattern) - let old_serial = old_pattern[1].old_pattern[2] - let new_serial = s:IncrementSerial(old_pattern[1], old_pattern[2]) - execute "s/".old_serial."/".new_serial."/" - echom "Serial updated to ".new_serial."." + let patterns = g:dnsserial_custom_patterns + g:dnsserial_patterns + for pattern in patterns + if search(pattern.regex) != 0 + let offset = len(pattern.matching) + let old_matchlist = matchlist(getline('.'), pattern.regex)[1:offset] + let old_serial = join(old_matchlist, '') + let new_serial = s:GetNewSerial(pattern, old_matchlist) + execute "s/" . old_serial . "/" . new_serial . "/" + echom "Serial updated to " . new_serial . "." + return 0 + endif + endfor + echom "No serial found." endfunction diff --git a/plugin/dnsserial.vim b/plugin/dnsserial.vim index 0607bde..7de4233 100644 --- a/plugin/dnsserial.vim +++ b/plugin/dnsserial.vim @@ -12,4 +12,28 @@ " See the License for the specific language governing permissions and " limitations under the License. + +if !exists('g:dnsserial_custom_patterns') + let g:dnsserial_custom_patterns = [] +endif + +if !exists('g:dnsserial_patterns') + let g:dnsserial_patterns = [ + \{ + \'regex': '\(\d\{8}\)\(\d\+\)\s*;\s*\cserial', + \'matching': [ + \{'type': 'date', 'fmt': '%Y%m%d'}, + \{'type': 'integer', 'padding': 2, 'date_reset': 1} + \] + \}, + \{ + \'regex': '\(\d\+\)\s*;\s*\cserial', + \'matching': [ + \{'type': 'integer'} + \] + \}, + \] +endif + + command! DNSSerialUpdate call dnsserial#DNSSerialUpdate()