Posts Tagged Code

Shell Script Version Compare (vercmp)

Here is something useful. A very short shell script to compare standard version numbers of the form ##.##.## with up to four segments. It returns the difference of the first differing segment just like strcmp.

#!/bin/sh
 
expr '(' "$1" : '\([^.]*\)' ')' '-' '(' "$2" : '\([^.]*\)' ')' '|' \
    '(' "$1.0" : '[^.]*[.]\([^.]*\)' ')' '-' '(' "$2.0" : '[^.]*[.]\([^.]*\)' ')' '|' \
    '(' "$1.0.0" : '[^.]*[.][^.]*[.]\([^.]*\)' ')' '-' '(' "$2.0.0" : '[^.]*[.][^.]*[.]\([^.]*\)' ')' '|' \
    '(' "$1.0.0.0" : '[^.]*[.][^.]*[.][^.]*[.]\([^.]*\)' ')' '-' '(' "$2.0.0.0" : '[^.]*[.][^.]*[.][^.]*[.]\([^.]*\)' ')'

Update: Added zeros to deal with unbalanced version compares

, ,

5 Comments

DMS to Decimal By Request

This is a function from my library that can be used to decode a degrees-minutes-seconds (DMS) string to a decimal degrees.
Enjoy.

/* ------------------------------
   Function: geo_dms_to_deg
     Parse a degrees-minutes-seconds (DMS) value string into a double floating
     point in degrees.
 
   Parameters:
     str     - [in]  string containing an angle in DMS
     end_ptr - [out] a pointer to the character following the last in the DMS
     packed  - [in]  boolean whether to expect the DMS to lack delimiters
     value   - [out] value in degrees
 
   Returns:
     true on success, false on failure
   ------------------------------ */
int geo_dms_to_deg( const char *str, const char **endptr, int packed, double *value ) {
  int d = -1, m = -1, s = -1, pos = 0;
  char ps[20] = "", *ps_ptr;
  float p = 0.0, fraction;
 
  if( packed ) {
    char format[64] = "";
 
    pos = strspn( str, "0123456789" );
    if( pos < 5 || pos > 7 )
      return( 0 );
 
    snprintf( format, 64, "%%%dd%%2d%%2d%%n", pos - 4 );
    if( sscanf( str, format, &d, &m, &s, &pos ) != 3 )
      return( 0 );
  } else if( sscanf( str, "%d:%d:%d.%[0123456789]%n", &d, &m, &s, ps, &pos ) == 4 ) {
    p = 0.0;
    fraction = 0.1;
    for( ps_ptr = ps; *ps_ptr != '\0'; ps_ptr++ ) {
      p += (*ps_ptr - '0')*fraction;
      fraction *= 0.1;
    }
  } else if( sscanf( str, "%d:%d:%d%n", &d, &m, &s, &pos ) == 3 ) {
    /* empty */
  } else if( sscanf( str, "%d:%d%n", &d, &m, &pos ) == 2 ) {
    s = 0;
  } else if( sscanf( str, "%d%n", &d, &pos ) == 1 ) {
    s = 0;
    m = 0;
  } else {
    return( 0 );
  }
  if (d < 0) return 0;
  if (m < 0 || m >= 60) return 0;
  if (s < 0 || s >= 60) return 0;
 
  *endptr = &str[pos];
 
  if( value )
    *value = d + m/60.0 + (p + (float)s)/3600.0;
 
  return( 1 );
}

, , , ,

No Comments

Emacs Tweaks – TAGS

Tags are an index of the definition of symbols in your source files. They allow you to quickly navigate your source files and to find what symbols exist. Originally they were designed for Vi probably because navigation is so poor there that you need navigational aids. Emacs has a number of integrated tag functions that many people just don’t know about. Many other IDEs have implemented this feature since through a series of context menu’s and hovers but fail to capture the basics that are covered so well in Emacs. However Emacs needs a little tweaking in order to take full advantage of capabilities. They are listed below.

More Productive Key Bindings
The following lisp gibberish allows you to search for the definition of the symbol under the mouse pointer and a way to search for all the uses of that symbol in your code. In Emacs you can return to the jumping point by pressing Alt-* (default key binding). I use XEmacs (which is superior) but you can put this in your .emacs file as well.

^^^^ .xemacs/init.el ^^^^

;;;;;;;;;;;;;;;;;
;; Tags setup
;;;;;;;;;;;;;;;;;

(defun tags-search-tag-at-point (tagname &optional file-list-form)
  "*Find tag whose name contains TAGNAME.
Identical to `find-tag' but does not prompt for tag when called interactively;
instead, uses tag around or before point."
  (interactive (if current-prefix-arg
		   '(nil nil)
		 (list (find-tag-tag "Search tag: ") nil)))
  (tags-search tagname file-list-form))

;; Find definition of the tag under the pointer
;; This nicely parallels M-*, which pops the tag stack.
(global-set-key '(control *) 'find-tag-at-point)

;; Find uses/calls of the tag under the pointer
;; This nicely parallels M-, , which cycles through the search results.
(global-set-key '(control ,) 'tags-search-tag-at-point)

;; Search and replace all uses of a tag
;; This nicely parallels M-%, which is the normal search and replace.
(global-set-key '(control %) 'tags-query-replace)

;; Complete the name of a symbol using the tag table
(global-set-key '(meta return) 'tag-complete-symbol)

Fancy Ways to Building Tag Files
The following is a shell script template that you can use to find which files have changed and only reindex as needed. Replace project_dir and src_dir as needed.

^^^^ make_tags.sh ^^^^

#!/bin/sh

function build_tags () {
  tag_file="$1"
  target_dir="$2"
  file_pattern="{*.[ch],Makefile}"
  if [ -e "$tag_file" ]; then
    files=`find "$target_dir" -maxdepth 1 -name '*.[ch]' -cnewer "$tag_file" -print`
    echo $files
    if [ "$files" ]; then
      etags -f "$tag_file" "$target_dir"/*.[ch]
    fi
  else
    etags -f "$tag_file" "$target_dir"/*.[ch]
  fi
}

TAGS_DIR="$HOME/project_dir/tags"

if [ ! -e "$TAGS_DIR" ]; then
  mkdir -p "$TAGS_DIR"
fi

build_tags "${TAGS_DIR}/src_dir1.tags" "$HOME/project_dir/src_dir1"
build_tags "${TAGS_DIR}/src_dir2.tags" "$HOME/project_dir/src_dir2"
build_tags "${TAGS_DIR}/usr_include.tags" "/usr/include"
build_tags "${TAGS_DIR}/usr_include_sys.tags" "/usr/include/sys"
build_tags "${TAGS_DIR}/usr_include_GL.tags" "/usr/include/GL"

# make tags for src_dir1 which depends on src_dir2
cat "${TAGS_DIR}/src_dir1.tags" "${TAGS_DIR}/src_dir2.tags" \
    "${TAGS_DIR}/usr_include.tags" "${TAGS_DIR}/usr_include_sys.tags" \
    "${TAGS_DIR}/usr_include_GL.tags" > "$HOME/project_dir/src_dir1/TAGS"

#make tags for src_dir2
cat "${TAGS_DIR}/src_dir2.tags" \
    "${TAGS_DIR}/usr_include.tags" "${TAGS_DIR}/usr_include_sys.tags" \
    "${TAGS_DIR}/usr_include_GL.tags" > "$HOME/project_dir/src_dir1/TAGS"

^^^^^^^^^^^^

, , , , , , , ,

No Comments

Bad Behavior has blocked 152 access attempts in the last 7 days.