static void add_sub(int n, const char *string, regex_t *re, regmatch_t *pm) { if (n > (int)re->re_nsub) warnx("No subexpression %d", n); /* Subexpressions that did not match are * not an error. */ else if (pm[n].rm_so != -1 && pm[n].rm_eo != -1) addchars(string + pm[n].rm_so, pm[n].rm_eo - pm[n].rm_so); }
void doesyscmd(const char *cmd) { int p[2]; pid_t pid, cpid; char *argv[4]; int cc; int status; /* Follow gnu m4 documentation: first flush buffers. */ fflush(NULL); argv[0] = "sh"; argv[1] = "-c"; argv[2] = (char *)cmd; argv[3] = NULL; /* Just set up standard output, share stderr and stdin with m4 */ if (pipe(p) == -1) err(1, "bad pipe"); switch(cpid = fork()) { case -1: err(1, "bad fork"); /* NOTREACHED */ case 0: (void) close(p[0]); (void) dup2(p[1], 1); (void) close(p[1]); execv(_PATH_BSHELL, argv); exit(1); default: /* Read result in two stages, since m4's buffer is * pushback-only. */ (void) close(p[1]); do { char result[BUFSIZE]; cc = read(p[0], result, sizeof result); if (cc > 0) addchars(result, cc); } while (cc > 0 || (cc == -1 && errno == EINTR)); (void) close(p[0]); while ((pid = wait(&status)) != cpid && pid >= 0) continue; pbstr(getstring()); } }
/* In Gnu m4 mode, parentheses for backmatch don't work like POSIX 1003.2 * says. So we twiddle with the regexp before passing it to regcomp. */ static char * twiddle(const char *p) { /* + at start of regexp is a normal character for Gnu m4 */ if (*p == '^') { addchar(*p); p++; } if (*p == '+') { addchar('\\'); } /* This could use strcspn for speed... */ while (*p != '\0') { if (*p == '\\') { switch(p[1]) { case '(': case ')': case '|': addchar(p[1]); break; case 'w': addconstantstring("[_a-zA-Z0-9]"); break; case 'W': addconstantstring("[^_a-zA-Z0-9]"); break; case '<': addconstantstring("[[:<:]]"); break; case '>': addconstantstring("[[:>:]]"); break; default: addchars(p, 2); break; } p+=2; continue; } if (*p == '(' || *p == ')' || *p == '|') addchar('\\'); addchar(*p); p++; } return getstring(); }
/* argv[2]: string * argv[3]: regexp * argv[4]: opt rep */ void dopatsubst(const char *argv[], int argc) { if (argc <= 3) { warnx("Too few arguments to patsubst"); return; } /* special case: empty regexp */ if (argv[3][0] == '\0') { const char *s; size_t len; if (argc > 4 && argv[4]) len = strlen(argv[4]); else len = 0; for (s = argv[2]; *s != '\0'; s++) { addchars(argv[4], len); addchar(*s); } } else { int error; regex_t re; regmatch_t *pmatch; int mode = REG_EXTENDED; const char *source; size_t l = strlen(argv[3]); if (!mimic_gnu || (argv[3][0] == '^') || (l > 0 && argv[3][l-1] == '$')) mode |= REG_NEWLINE; source = mimic_gnu ? twiddle(argv[3]) : argv[3]; error = regcomp(&re, source, mode); if (error != 0) exit_regerror(error, &re, source); pmatch = xreallocarray(NULL, re.re_nsub+1, sizeof(regmatch_t), NULL); do_subst(argv[2], &re, source, argc > 4 && argv[4] != NULL ? argv[4] : "", pmatch); free(pmatch); regfree(&re); } pbstr(getstring()); }
static void do_subst(const char *string, regex_t *re, const char *source, const char *replace, regmatch_t *pm) { int error; int flags = 0; const char *last_match = NULL; while ((error = regexec(re, string, re->re_nsub+1, pm, flags)) == 0) { if (pm[0].rm_eo != 0) { if (string[pm[0].rm_eo-1] == '\n') flags = 0; else flags = REG_NOTBOL; } /* NULL length matches are special... We use the `vi-mode' * rule: don't allow a NULL-match at the last match * position. */ if (pm[0].rm_so == pm[0].rm_eo && string + pm[0].rm_so == last_match) { if (*string == '\0') return; addchar(*string); if (*string++ == '\n') flags = 0; else flags = REG_NOTBOL; continue; } last_match = string + pm[0].rm_so; addchars(string, pm[0].rm_so); add_replace(string, re, replace, pm); string += pm[0].rm_eo; } if (error != REG_NOMATCH) exit_regerror(error, re, source); pbstr(string); }
void doformat(const char *argv[], int argc) { const char *format = argv[2]; int pos = 3; int left_padded; long width; size_t l; const char *thisarg; char temp[2]; long extra; while (*format != 0) { if (*format != '%') { addchar(*format++); continue; } format++; if (*format == '%') { addchar(*format++); continue; } if (*format == 0) { addchar('%'); break; } if (*format == '*') { format++; if (pos >= argc) m4errx(1, "Format with too many format specifiers."); width = strtol(argv[pos++], NULL, 10); } else { width = strtol(format, (char **)&format, 10); } if (width < 0) { left_padded = 1; width = -width; } else { left_padded = 0; } if (*format == '.') { format++; if (*format == '*') { format++; if (pos >= argc) m4errx(1, "Format with too many format specifiers."); extra = strtol(argv[pos++], NULL, 10); } else { extra = strtol(format, (char **)&format, 10); } } else { extra = LONG_MAX; } if (pos >= argc) m4errx(1, "Format with too many format specifiers."); switch(*format) { case 's': thisarg = argv[pos++]; break; case 'c': temp[0] = strtoul(argv[pos++], NULL, 10); temp[1] = 0; thisarg = temp; break; default: m4errx(1, "Unsupported format specification: %s.", argv[2]); } format++; l = strlen(thisarg); if (l > extra) l = extra; if (!left_padded) { while (l < width--) addchar(' '); } addchars(thisarg, l); if (left_padded) { while (l < width--) addchar(' '); } } pbstr(getstring()); }
static void scan_dir(fpick_dd *dt, DIR *dp, char *select) { char full_name[PATHBUF], txt_size[64], txt_date[64], tmp_txt[64]; char *nm, *src, *dest, *dir = dt->txt_directory; memx2 mem = dt->files; struct tm *lt; struct dirent *ep; struct stat buf; int *tc; int subdir, tf, n, l = strlen(dir), cnt = 0; mem.here = 0; getmemx2(&mem, 8000); // default size dt->idx = -1; if (strcmp(dir, DIR_SEP_STR)) // Have a parent dir to move to? { // Field #0 - original name addstr(&mem, "..", 0); // Field #1 - type flag (space) + name in GUI encoding addstr(&mem, " " DIR_SEP_STR " ..", 0); // Fields #2-4 empty for all dirs // Fields #5-6 are empty strings, to keep this sorted first addchars(&mem, 0, 3 + 2); cnt++; } while ((ep = readdir(dp))) { wjstrcat(full_name, PATHBUF, dir, l, ep->d_name, NULL); // Error getting file details if (stat(full_name, &buf) < 0) continue; if (!dt->show_hidden && (ep->d_name[0] == '.')) continue; #ifdef WIN32 subdir = S_ISDIR(buf.st_mode); #else subdir = (ep->d_type == DT_DIR) || S_ISDIR(buf.st_mode); #endif tf = 'F'; // Type flag: 'D' for dir, 'F' for file if (subdir) { if (!dt->allow_dirs) continue; // Don't look at '.' or '..' if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, "..")) continue; tf = 'D'; } else if (!dt->allow_files) continue; /* Remember which row has matching name */ if (select && !strcmp(ep->d_name, select)) dt->idx = cnt; cnt++; // Field #0 - original name addstr(&mem, ep->d_name, 0); // Field #1 - type flag + name in GUI encoding addchars(&mem, tf, 1); nm = gtkuncpy(NULL, ep->d_name, 0); addstr(&mem, nm, 0); // Fields #2-4 empty for dirs if (subdir) addchars(&mem, 0, 3); else { // Field #2 - file size #ifdef WIN32 n = snprintf(tmp_txt, 64, "%I64u", (unsigned long long)buf.st_size); #else n = snprintf(tmp_txt, 64, "%llu", (unsigned long long)buf.st_size); #endif memset(txt_size, ' ', 20); dest = txt_size + 20; *dest-- = '\0'; for (src = tmp_txt + n - 1; src - tmp_txt > 2; ) { *dest-- = *src--; *dest-- = *src--; *dest-- = *src--; *dest-- = ','; } while (src - tmp_txt >= 0) *dest-- = *src--; addstr(&mem, txt_size, 0); // Field #3 - file type (extension) src = strrchr(nm, '.'); if (src && (src != nm) && src[1]) { #if GTK_MAJOR_VERSION == 1 g_strup(src = g_strdup(src + 1)); #else src = g_utf8_strup(src + 1, -1); #endif addstr(&mem, src, 0); g_free(src); } else addchars(&mem, 0, 1); // Field #4 - file modification time strcpy(txt_date, " "); // to sort failed files after dirs lt = localtime(&buf.st_mtime); /* !!! localtime() can fail and return NULL if given * "wrong" input value */ if (lt) strftime(txt_date, 60, "%Y-%m-%d %H:%M.%S", lt); addstr(&mem, txt_date, 0); } // Field #5 - case-insensitive sort key src = isort_key(nm); addstr(&mem, src, 0); g_free(src); // Field #6 - alphabetic (case-sensitive) sort key #if GTK_MAJOR_VERSION == 1 addstr(&mem, nm, 0); #else /* if GTK_MAJOR_VERSION == 2 */ src = g_utf8_collate_key(nm, -1); addstr(&mem, src, 0); g_free(src); #endif g_free(nm); } dt->cnt = cnt; /* Now add index array and mapping arrays to all this */ l = (~(unsigned)mem.here + 1) & (sizeof(int) - 1); n = cnt * COL_MAX; getmemx2(&mem, l + (n + cnt) * sizeof(int)); // Fill index array tc = dt->fcols = (void *)(mem.buf + mem.here + l); src = mem.buf; while (n-- > 0) { *tc = src - (char *)tc; tc++; src += strlen(src) + 1; } // Setup mapping array dt->fmap = tc; dt->files = mem; }
void PrintInteger(bool typeUnsigned, uint64_t argu, int base, uint64_t numbits, FormatterParams formatter, bool uppercaseDigits, char *&output, size_t &actualsize, char *end) { int64_t argi = 0; union { uint64_t *u64; signed int *i; signed char *c; signed short *s; int64_t *i64; } typepun; typepun.u64 = &argu; // cast the appropriate size to signed version switch(formatter.Length) { default: case None: case Long: argi = (int64_t)*typepun.i; break; case HalfHalf: argi = (int64_t)*typepun.c; break; case Half: argi = (int64_t)*typepun.s; break; case LongLong: argi = (int64_t)*typepun.i64; break; } bool negative = false; if(base == 10 && !typeUnsigned) { negative = argi < 0; } int digwidth = 0; int numPad0s = 0; int numPadWidth = 0; { int intwidth = 0; int digits = 0; // work out the number of decimal digits in the integer if(!negative) { uint64_t accum = argu; while(accum) { digits += 1; accum /= base; } } else { int64_t accum = argi; while(accum) { digits += 1; accum /= base; } } intwidth = digwidth = RDCMAX(1, digits); // printed int is 2 chars larger for 0x or 0b, and 1 char for 0 (octal) if(base == 16 || base == 2) intwidth += formatter.Flags & AlternateForm ? 2 : 0; if(base == 8) intwidth += formatter.Flags & AlternateForm ? 1 : 0; if(formatter.Precision != FormatterParams::NoPrecision && formatter.Precision > intwidth) numPad0s = formatter.Precision - intwidth; intwidth += numPad0s; // for decimal we can have a negative sign (or placeholder) if(base == 10) { if(negative) intwidth++; else if(formatter.Flags & (PrependPos | PrependSpace)) intwidth++; } if(formatter.Width != FormatterParams::NoWidth && formatter.Width > intwidth) numPadWidth = formatter.Width - intwidth; } // pad with spaces if necessary if((formatter.Flags & (LeftJustify | PadZeroes)) == 0 && numPadWidth > 0) addchars(output, actualsize, end, (size_t)numPadWidth, ' '); if(base == 16) { if(formatter.Flags & AlternateForm) { if(uppercaseDigits) appendstring(output, actualsize, end, "0X"); else appendstring(output, actualsize, end, "0x"); } // pad with 0s as appropriate if((formatter.Flags & (LeftJustify | PadZeroes)) == PadZeroes && numPadWidth > 0) addchars(output, actualsize, end, (size_t)numPadWidth, '0'); if(numPad0s > 0) addchars(output, actualsize, end, (size_t)numPad0s, '0'); bool left0s = true; // mask off each hex digit and print for(uint64_t i = 0; i < numbits; i += 4) { uint64_t shift = numbits - 4 - i; uint64_t mask = 0xfULL << shift; char digit = char((argu & mask) >> shift); if(digit == 0 && left0s && i + 4 < numbits) continue; left0s = false; if(digit < 10) addchar(output, actualsize, end, '0' + digit); else if(uppercaseDigits) addchar(output, actualsize, end, 'A' + digit - 10); else addchar(output, actualsize, end, 'a' + digit - 10); } } else if(base == 8)