<commit_before>/*
Copyright 2014 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cups

/*
#cgo LDFLAGS: -lcups
#include <cups/cups.h>
#include <stddef.h> // size_t
#include <stdlib.h> // malloc, free
#include <string.h> // memset
#include <time.h>   // time_t
*/
import "C"
import (
	"crypto/md5"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"reflect"
	"unsafe"
)

type ppdCache struct {
	c_http  *C.http_t
	m       map[string]*ppdCacheEntry
	request chan ppdRequest
	q       chan bool
}

type ppdRequest struct {
	printerName string
	response    chan ppdResponse
}

type ppdResponse struct {
	filename string
	hash     string
	err      error
}

func newPPDCache(c_http *C.http_t) *ppdCache {
	m := make(map[string]*ppdCacheEntry)
	pc := ppdCache{c_http, m, make(chan ppdRequest), make(chan bool)}
	go pc.servePPDs()
	return &pc
}

func (pc *ppdCache) quit() {
	pc.q <- true
	<-pc.q
	for printerName, pce := range pc.m {
		pce.free()
		delete(pc.m, printerName)
	}
}

func (pc *ppdCache) getPPD(printerName string) (string, error) {
	ch := make(chan ppdResponse)
	request := ppdRequest{printerName, ch}
	pc.request <- request
	response := <-ch

	if response.err != nil {
		return "", response.err
	}
	ppd, err := ioutil.ReadFile(response.filename)
	if err != nil {
		return "", err
	}

	return string(ppd), nil
}

func (pc *ppdCache) getPPDHash(printerName string) (string, error) {
	ch := make(chan ppdResponse)
	request := ppdRequest{printerName, ch}
	pc.request <- request
	response := <-ch
	return response.hash, response.err
}

func (pc *ppdCache) getPrinterNames() ([]string, error) {
	var c_dests *C.cups_dest_t
	c_num_dests := C.cupsGetDests2(pc.c_http, &c_dests)
	if c_num_dests < 0 {
		text := fmt.Sprintf("CUPS failed to call cupsGetDests2(): %d %s",
			int(C.cupsLastError()), C.GoString(C.cupsLastErrorString()))
		return nil, errors.New(text)
	}
	defer C.cupsFreeDests(c_num_dests, c_dests)

	num_dests := int(c_num_dests)
	hdr := reflect.SliceHeader{
		Data: uintptr(unsafe.Pointer(c_dests)),
		Len:  num_dests,
		Cap:  num_dests,
	}
	dests := *(*[]C.cups_dest_t)(unsafe.Pointer(&hdr))

	names := make([]string, 0, num_dests)
	for _, dest := range dests {
		names = append(names, C.GoString(dest.name))
	}

	return names, nil
}

func (pc *ppdCache) servePPDs() {
	// Prime the cache.
	printerNames, err := pc.getPrinterNames()
	if err != nil {
		log.Fatal(err)
	}
	for _, printerName := range printerNames {
		pce, err := createPPDCacheEntry(printerName)
		if err != nil {
			log.Fatal(err)
		}
		pce.refreshPPDCacheEntry(pc.c_http)
		pc.m[printerName] = pce
	}

	for {
		select {
		case r := <-pc.request:
			pce, exists := pc.m[r.printerName]
			if !exists {
				pce, err = createPPDCacheEntry(r.printerName)
				if err != nil {
					r.response <- ppdResponse{"", "", err}
				}
			}
			if err := pce.refreshPPDCacheEntry(pc.c_http); err != nil {
				r.response <- ppdResponse{"", "", err}
			}
			r.response <- ppdResponse{C.GoString(pce.buffer), pce.hash, nil}

		case <-pc.q:
			pc.q <- true
			return
		}
	}
}

// Holds persistent data needed for calling C.cupsGetPPD3.
type ppdCacheEntry struct {
	name    *C.char
	modtime C.time_t
	buffer  *C.char
	bufsize C.size_t
	hash    string
}

// Creates an instance of ppdCache with the name field set, all else empty.
// Don't forget to call C.free() for the name and buffer fields with
// ppdCacheEntry.free()!
func createPPDCacheEntry(name string) (*ppdCacheEntry, error) {<commit_msg>Remove unnecessary cache prime (and cupsGetDests2() call) from ppdCache.<commit_after>/*
Copyright 2014 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cups

/*
#cgo LDFLAGS: -lcups
#include <cups/cups.h>
#include <stddef.h> // size_t
#include <stdlib.h> // malloc, free
#include <string.h> // memset
#include <time.h>   // time_t
*/
import "C"
import (
	"crypto/md5"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"unsafe"
)

type ppdCache struct {
	c_http  *C.http_t
	m       map[string]*ppdCacheEntry
	request chan ppdRequest
	q       chan bool
}

type ppdRequest struct {
	printerName string
	response    chan ppdResponse
}

type ppdResponse struct {
	filename string
	hash     string
	err      error
}

func newPPDCache(c_http *C.http_t) *ppdCache {
	m := make(map[string]*ppdCacheEntry)
	pc := ppdCache{c_http, m, make(chan ppdRequest), make(chan bool)}
	go pc.servePPDs()
	return &pc
}

func (pc *ppdCache) quit() {
	pc.q <- true
	<-pc.q
	for printerName, pce := range pc.m {
		pce.free()
		delete(pc.m, printerName)
	}
}

func (pc *ppdCache) getPPD(printerName string) (string, error) {
	ch := make(chan ppdResponse)
	request := ppdRequest{printerName, ch}
	pc.request <- request
	response := <-ch

	if response.err != nil {
		return "", response.err
	}
	ppd, err := ioutil.ReadFile(response.filename)
	if err != nil {
		return "", err
	}

	return string(ppd), nil
}

func (pc *ppdCache) getPPDHash(printerName string) (string, error) {
	ch := make(chan ppdResponse)
	request := ppdRequest{printerName, ch}
	pc.request <- request
	response := <-ch
	return response.hash, response.err
}

func (pc *ppdCache) servePPDs() {
	for {
		select {
		case r := <-pc.request:
			var err error
			pce, exists := pc.m[r.printerName]
			if !exists {
				pce, err = createPPDCacheEntry(r.printerName)
				if err != nil {
					r.response <- ppdResponse{"", "", err}
					continue
				}
			}
			if err = pce.refreshPPDCacheEntry(pc.c_http); err != nil {
				r.response <- ppdResponse{"", "", err}
				continue
			}
			r.response <- ppdResponse{C.GoString(pce.buffer), pce.hash, nil}

		case <-pc.q:
			pc.q <- true
			return
		}
	}
}

// Holds persistent data needed for calling C.cupsGetPPD3.
type ppdCacheEntry struct {
	name    *C.char
	modtime C.time_t
	buffer  *C.char
	bufsize C.size_t
	hash    string
}

// Creates an instance of ppdCache with the name field set, all else empty.
// Don't forget to call C.free() for the name and buffer fields with
// ppdCacheEntry.free()!
func createPPDCacheEntry(name string) (*ppdCacheEntry, error) {
{'fraction_non_alphanumeric': 0.12572891480585976, 'fraction_numerical': 0.003555681979803726, 'mean_word_length': 3.5930764206401045, 'pattern_counts': {'":': 0, '<': 38, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4570212', 'n_tokens_mistral': 2741, 'n_tokens_neox': 2553, 'n_words': 740}