diff --git a/avrdude.1 b/avrdude.1
index 0b5ffa12..9a1297ec 100644
--- a/avrdude.1
+++ b/avrdude.1
@@ -19,7 +19,7 @@
 .\"
 .\" $Id$
 .\"
-.Dd DATE July 24, 2003
+.Dd DATE November 26, 2003
 .Os
 .Dt AVRDUDE 1
 .Sh NAME
@@ -387,6 +387,13 @@ field is optional and contains the format of the file to read or
 write.  See the
 .Fl f
 option for possible values.
+Note that if
+.Ar filename
+contains a colon, the
+.Ar format
+field is no longer optional since the filename part following the colon
+would otherwise be misinterpreted as
+.Ar format .
 .It Fl v
 Enable verbose output.
 .It Fl V
diff --git a/doc/avrdude.texi b/doc/avrdude.texi
index 72639642..7d76f858 100644
--- a/doc/avrdude.texi
+++ b/doc/avrdude.texi
@@ -495,6 +495,9 @@ The @var{filename} field indicates the name of the file to read or
 write.  The @var{format} field is optional and contains the format of
 the file to read or write.  See the @option{-f} option for possible
 values.
+Note that if @var{filename} contains a colon, the @var{format} field is
+no longer optional since the filename part following the colon would
+otherwise be misinterpreted as @var{format}.
 
 @item -v
 Enable verbose output.
@@ -574,11 +577,11 @@ avrdude done.  Thank you.
 @noindent
 Upload the flash memory from the ATmega128 connected to the STK500
 programmer and save it in raw binary format in the file named
-@code{diag.flash}:
+@code{c:/diag flash.bin}:
 
 @example
 @cartouche
-% avrdude -p m128 -c stk500 -U flash:r:diag.flash:r 
+% avrdude -p m128 -c stk500 -U flash:r:"c:/diag flash.bin":r 
 
 avrdude: AVR device initialized and ready to accept instructions
 
@@ -589,7 +592,7 @@ avrdude: reading flash memory:
 
 Reading | ################################################## | 100% 46.10s
 
-avrdude: writing output file "diag.flash"
+avrdude: writing output file "c:/diag flash.bin"
 
 avrdude done.  Thank you.
 
diff --git a/main.c b/main.c
index 9dba4706..c8015fb8 100644
--- a/main.c
+++ b/main.c
@@ -393,9 +393,10 @@ static void update_progress_no_tty (int percent, double etime, char *hdr)
 UPDATE * parse_op(char * s)
 {
   char buf[1024];
-  char * p;
+  char * p, * cp, c;
   UPDATE * upd;
   int i;
+  size_t fnlen;
 
   upd = (UPDATE *)malloc(sizeof(UPDATE));
   if (upd == NULL) {
@@ -457,55 +458,52 @@ UPDATE * parse_op(char * s)
 
   p++;
 
-  i = 0;
-  while ((i < (sizeof(buf)-1) && *p && (*p != ':')))
-    buf[i++] = *p++;
-  
-  if (!((*p == ':')||(*p == 0))) {
-    fprintf(stderr, "%s: invalid update specification\n", progname);
-    free(upd->memtype);
-    free(upd);
-    return NULL;
-  }
-
-  buf[i] = 0;
-
-  upd->filename = (char *)malloc(strlen(buf)+1);
-  if (upd->filename == NULL) {
-    fprintf(stderr, "%s: out of memory\n", progname);
-    free(upd->memtype);
-    free(upd);
-    return NULL;
-  }
-  strcpy(upd->filename, buf);
-
-  upd->format = FMT_AUTO;
-
-  if (*p == ':') {
-    p++;
-    switch (*p) {
+  /*
+   * Now, parse the filename component.  Instead of looking for the
+   * leftmost possible colon delimiter, we look for the rightmost one.
+   * If we found one, we do have a trailing :format specifier, and
+   * process it.  Otherwise, the remainder of the string is our file
+   * name component.  That way, the file name itself is allowed to
+   * contain a colon itself (e. g. C:/some/file.hex), except the
+   * optional format specifier becomes mandatory then.
+   */
+  cp = p;
+  p = strrchr(cp, ':');
+  if (p == NULL) {
+    upd->format = FMT_AUTO;
+    fnlen = strlen(cp);
+    upd->filename = (char *)malloc(fnlen + 1);
+  } else {
+    fnlen = p - cp;
+    upd->filename = (char *)malloc(fnlen +1);
+    c = *++p;
+    if (c && p[1])
+      /* More than one char - force failure below. */
+      c = '?';
+    switch (c) {
       case 'a': upd->format = FMT_AUTO; break;
       case 's': upd->format = FMT_SREC; break;
       case 'i': upd->format = FMT_IHEX; break;
       case 'r': upd->format = FMT_RBIN; break;
       case 'm': upd->format = FMT_IMM; break;
       default:
-        fprintf(stderr, "%s: invalid file format '%c' in update specifier\n",
-                progname, *p);
+        fprintf(stderr, "%s: invalid file format '%s' in update specifier\n",
+                progname, p);
         free(upd->memtype);
-        free(upd->filename);
         free(upd);
         return NULL;
     }
-    p++;
   }
 
-  if (*p != 0) {
-    fprintf(stderr, 
-            "%s: WARNING, extraneous data (%s) in update specifier ignored\n",
-            progname, p);
+  if (upd->filename == NULL) {
+    fprintf(stderr, "%s: out of memory\n", progname);
+    free(upd->memtype);
+    free(upd);
+    return NULL;
   }
-  
+  memcpy(upd->filename, cp, fnlen);
+  upd->filename[fnlen] = 0;
+
   return upd;
 }